fix(core): Make DataCaptureConfigSummary.kms_key_id optional - #6346
Conversation
DescribeEndpoint omits DataCaptureConfig.KmsKeyId when data capture is enabled without a customer-managed KMS key, but the service model marks it as required, so codegen emitted DataCaptureConfigSummary.kms_key_id as a required field. As a result Endpoint.get() raised a pydantic ValidationError for any endpoint with data capture enabled and no KMS key. Register the member in REQUIRED_TO_OPTIONAL_OVERRIDES so codegen keeps it optional, and update the generated shape to match. Add unit tests for the codegen override, the shape, and Endpoint.get(). Fixes aws#5738
|
Claude finished @lucasjia-aws's task in 44s —— View job Review: PR #6346 — Make
|
|
unit tests failing , can you check. |
|
The sagemaker-serve unit failure (test_model_builder_methods.py::test_is_mms_version_none) is a pre-existing flaky test unrelated to this PR: ModelBuilder(model=Mock()) without a role calls resolve_and_validate_role at construction, which hits the real IAM SimulatePrincipalPolicy API in CI and got Throttling ... Rate exceeded. This PR only touches sagemaker-core shapes/codegen, the same test passed on py311 and py312 in the same build, and #6314/#6312 hit the same throttling on other tests in this file, we should fix it separately by mocking resolve_and_validate_role in the serve unit-test conftest. |
mohamedzeidan2021
left a comment
There was a problem hiding this comment.
Approving, and the codegen question is handled correctly — which was the main thing I wanted to check.
shapes.py is generated, so a hand-edit alone would have been silently reverted on the next codegen run. This PR also registers the member in REQUIRED_TO_OPTIONAL_OVERRIDES, which shapes_extractor.py consumes. I ran the real generator into a temp dir: with the fix it emits kms_key_id: Optional[StrPipeVar] = Unassigned(), with constants.py reverted it emits kms_key_id: StrPipeVar, and the regenerated shapes.py has no delta against the committed one for this shape. Both halves are covered in the right direction — reverting shapes.py fails 2 of the 3 new tests, reverting constants.py fails the codegen test, and test_other_members_stay_required guards against a blanket override.
Worth recording for the history: the botocore model actually marks KmsKeyId as required (confirmed in both the installed botocore and the repo's tracked sample/.../service-2.json), so codegen was faithful and the model is what's wrong. The fix is still correct, for reasons independent of that: DataCaptureConfigSummary is output-only (I computed reachability across all operations), required on an output shape isn't a wire guarantee since botocore only validates input and the response parser never enforces it, the input DataCaptureConfig doesn't require the CMK and documents it as optional, and ModelPackageSecurityConfig: ["KmsKeyId"] is already in the override map for exactly this defect.
Reproduced the issue's ValidationError ... data_capture_config.kms_key_id Field required verbatim and its absence. Adversarial matrix clean (omitted / present / "" / explicit None / unicode / whole config omitted). No production readers of the field, field order and keyword-only construction unchanged, model_dump() identical when the key is present, and Unassigned.__bool__ is False so if cfg.kms_key_id: doesn't surprise callers. 3716 passed / 23 skipped.
Two follow-ups, neither blocking:
- The generator derives required-ness from the model's
requiredlist for output shapes generally, so 329 output-only structures (62 of them*Summary) carry the same latentEndpoint.get()failure —EndpointSummary,ClusterSummary,AutoMLJobSummaryamong them. The override map closes one at a time; teaching the generator to treat output-only members as Optional would close the class. The KMS pattern specifically is now fully closed (only two shapes ever declared a requiredKms*member). shapes.pyhas drifted from its generator independently of this PR — regenerating today also reordersConflictException/InstancePreferenceand rewrites several docstrings. Present at the merge base, so not this PR's doing, but it argues for a CI "codegen is reproducible" check.
Issue
Fixes #5738
Description
Endpoint.get()fails with a pydanticValidationError(data_capture_config.kms_key_id Field required) on any endpoint that has data capture enabled without a customer-managed KMS key.Root cause
The SageMaker service model (
service-2.json, also current botocore) listsKmsKeyIdinDataCaptureConfigSummary.required, butDescribeEndpointomitsKmsKeyIdwhen no customer-managed KMS key is configured (S3 default encryption is used). sagemaker-core codegen follows the service model, soDataCaptureConfigSummary.kms_key_idwas generated as a requiredStrPipeVar. The input shapeDataCaptureConfigalready treats it as optional.Fix
Add
"DataCaptureConfigSummary": ["KmsKeyId"]toREQUIRED_TO_OPTIONAL_OVERRIDESinsagemaker-core/src/sagemaker/core/tools/constants.py, the existing mechanism for members the model marks required but the API can omit (same pattern asModelPackageSecurityConfig.KmsKeyId). This keeps the fix across future shape regenerations. Update the generatedDataCaptureConfigSummaryinshapes.pytokms_key_id: Optional[StrPipeVar] = Unassigned(); runningShapesExtractoragainst the bundled service model produces exactly this definition. The change only relaxes validation, so all previously valid inputs still validate.Testing
tests/unit/tools/test_shapes_extractor.py: codegen emitskms_key_idas optional via the override, and the other four members stay required.tests/unit/generated/test_shapes.py:DataCaptureConfigSummaryvalidates with and withoutkms_key_id, andEndpoint.get()(mocked client) parses aDescribeEndpointresponse with noKmsKeyId.tests/unit/tools/test_api_coverage.pyfails identically on unmodified master (394 vs 391 operations) and is unrelated to this change.This is V3-only: V2 does not validate DescribeEndpoint responses against generated pydantic shapes, so no V2 fix is needed.