Fix/SageMaker client construction - #6120
Conversation
… singleton pinning
Remove the temporary SAGEMAKER_ENDPOINT / SAGEMAKER_RUNTIME_ENDPOINT /
SAGEMAKER_STAGE overrides and the custom botocore service-model loader from
SageMakerClient. These were internal beta/gamma testing shims (marked
"# TODO: Remove post-launch") added while the generic Job APIs were not yet in
public botocore. Those APIs (CreateJob/DescribeJob/ListJobs) now ship in public
botocore, so the standard session.client("sagemaker", ...) path is used and the
env-driven endpoint redirection is no longer read by the SDK.
Also fix SingletonMeta so SageMakerClient is keyed by (session, region) instead
of by class alone. Previously the first instance was pinned process-wide, so a
later call with a different session/region silently reused the original client.
Parameterless SageMakerClient() calls still share a single instance.
Harden the container-driver env logger to mask values that look like AWS
credential material (access key IDs, session tokens) even when the key name
contains none of SENSITIVE_KEYWORDS.
…logging The startup env logger masked only by key name, so a sensitive value under a key name without a SENSITIVE_KEYWORDS substring was logged verbatim. Add value-based detection for AWS credential material (access key IDs, session tokens) so such values are masked regardless of key name.
|
Claude finished @lucasjia-aws's task in 2m 51s —— View job Claude review — Fix/aml 509849
I reviewed the four changed files. The change splits into two independent concerns: (1) masking credential-shaped values in container env logging, and (2) reworking
🟠
|
Make SageMakerClient._singleton_key tolerant of extra constructor arguments by accepting *args/**kwargs, so callers passing additional keywords (such as the legacy service_name=) no longer raise a TypeError during key computation on cache-hit paths. Document why id(session) is a stable cache key: the cached instance retains the session reference, preventing garbage collection and id reuse while the entry lives. Add unit tests for the singleton keying and reset(): distinct instance per (session, region), reuse across repeated no-arg calls, reuse for an identical session/region, and reset() clearing all keyed entries for the class. Rework the env-logging test assertion to compare the logged arguments exactly instead of a URL substring check, removing the CodeQL incomplete-URL-sanitization finding on the test file.
|
Claude finished @lucasjia-aws's task in 1m 31s —— View job Claude review — Fix/aml 509849 (re-review after sync)
Thanks for the updates — the two items I flagged as most important last round are resolved:
🟢 CodeQL alert (
|
| SENSITIVE_KEYWORDS = ["SECRET", "PASSWORD", "KEY", "TOKEN", "PRIVATE", "CREDS", "CREDENTIALS"] | ||
| HIDDEN_VALUE = "******" | ||
|
|
||
| SENSITIVE_VALUE_PATTERNS = [ |
There was a problem hiding this comment.
Env-log masking gap — the container-driver startup logger masks by key name only, so a credential-shaped value under an innocuous key name would be logged in clear text.
The PR is doing regex against some known patterns, but credentials may/may not match that regex.
I wonder what's the best practice to filter out credentials from logs. I would suggest to explore if there any official AWS guidance on this.
There was a problem hiding this comment.
Revert the (session, region) singleton keying introduced earlier in this PR. The security concern behind Finding 3 (a poisoned endpoint being pinned) is already resolved by removing the SAGEMAKER_ENDPOINT override in Finding 1, so there is no attacker-controlled endpoint left to pin. Per team design, the SDK operates with a single session/region per process, so a class-keyed singleton is the intended behavior. Restores the original SingletonMeta, SageMakerClient.reset(), and drops the singleton keying unit tests. Finding 1 (endpoint override removal) and Finding 5 (env-log value masking) are unchanged.
|
Claude finished @lucasjia-aws's task in 7m 54s —— View job Claude review — Fix/aml 509849 (re-review after rework)
The PR changed shape since my last pass. The per- 🟠 Removing the sample-model loader may break the
|
Removing the custom sample-model loader makes the control-plane client a
stock session.client("sagemaker"), so the generic Job APIs must be present
in the resolved botocore. CreateJob/DescribeJob/ListJobs first ship in
botocore 1.43.20; the previous floor (boto3>=1.42.2) allowed botocore
versions without them, which would regress Job.create()/get()/get_all()
at runtime.
Raise the pin to boto3>=1.43.20 (which requires botocore>=1.43.20) to
guarantee the Job APIs are available.
|
Claude finished @lucasjia-aws's task in 2m 16s —— View job Claude review — Fix/aml 509849 (re-review after boto3 floor bump)
The new commit ( 🟢 Job-API concern — addressed, with one thing to confirm at runtime
What I was able to verify from the checked-out repo:
What I couldn't verify in this environment: botocore isn't installed here and web fetch is disabled, so I can't independently confirm import boto3; boto3.Session().client("sagemaker", region_name="us-west-2").create_jobshould not raise. If that holds at 🟡 Minor — the now-unused
|
|
Re: Claude review Fixed. Other notes acknowledged: dict-nested value masking is an intentional scope boundary; the CodeQL alert is a false positive (strict tuple-equality assertion, no URL sanitization). |
| dependencies = [ | ||
| # Add your dependencies here (Include lower and upper bounds as applicable) | ||
| "boto3>=1.42.2,<2.0.0", | ||
| "boto3>=1.43.20,<2.0.0", |
Remove the value-based masking added earlier in this PR for the container -driver env logger. The behavior it targeted was raised as a forensic signal rather than a vulnerability, and comprehensive credential masking in logs is handled by the platform-side CloudWatch Logs data protection policies. Restores environment.py (sagemaker-train and the sagemaker-core mirror) and its tests to their original state.
|
Claude finished @lucasjia-aws's task in 1m 30s —— View job Claude review — Fix/aml 509849 (re-review after sync)
The PR narrowed since the last pass. The env-log value-masking change was reverted ( ✅
|
Description
This PR simplifies SageMaker client construction and includes a couple of small robustness improvements.
Simplify control-plane client construction.
SageMakerClientpreviously loaded a custom botocore service model (from a bundledsample/directory) as a temporary measure to expose the generic Job APIs before they were available upstream. Those Job APIs (CreateJob/DescribeJob/ListJobs) now ship in the public botocore, so this temporary loader is no longer needed. The client now uses the standardsession.client("sagemaker", ...)path, which is simpler and behaves consistently with the other clients in the constructor.Bump the boto3 floor to
>=1.43.20. Since the client now relies on the public botocore for the Job APIs, the minimum boto3 version is raised to the first release where those operations are available (botocore>=1.43.20), so theJob.create()/Job.get()/Job.get_all()paths resolve correctly on a clean install. This is compatible with the package's existing Python>=3.10requirement.Testing
session.client("sagemaker")exposescreate_job/describe_job/list_jobsat the pinned botocore floor.sagemaker-coreunit tests pass.By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.