Repository navigation
fix(image_uris): reject unsupported container_version instead of returning a bad URI - #6376
Conversation
retrieve() concatenated a caller-supplied container_version into the image
tag with no validation, so e.g. retrieve("pytorch", version="1.12",
image_scope="inference", instance_type="ml.p3.8xlarge", container_version="1.1")
returned pytorch-inference:1.12-gpu-py38-1.1 -- an image that does not exist
(the "1.1" is a Deep Learning Containers release version, not a tag build
component). The call silently succeeded with an unpullable URI (aws#3702).
container_version is only meaningful for frameworks whose tag carries a
trailing build component: declared in the config container_version map (which
already overrides the caller value), or appended by the graviton, neuron,
HuggingFace and pytorch-smp paths. For any other framework a caller-supplied
container_version can only produce a non-existent tag, so raise a clear
ValueError instead of returning a broken URI.
Add a unit test; the existing graviton and HuggingFace container_version
tests continue to pass (full image_uris suite: 205 passed).
Relates-to aws#3702
|
Claude finished @rsareddy0329's task in 2m 54s —— View job Code review —
|
The aws#3702 guard rejected a caller-supplied container_version for any framework whose config has no container_version map and that is not HuggingFace/graviton/neuron/pytorch-smp. That wrongly broke Spark: PySparkProcessor/SparkJarProcessor call image_uris.retrieve("spark", ..., container_version="v1"), and spark.json has no container_version map, so the guard raised ValueError and broke Spark image retrieval. Replace the ad hoc framework checks with an explicit FRAMEWORKS_WITH_CONTAINER_VERSION_SUFFIX allowlist (huggingface, pytorch-smp, spark) so the set of frameworks that legitimately append a container_version is self-documenting, and add a Spark regression test. (sagemaker-core has no spark processing unit test, so this guards the path the V2 spark suite caught.) Relates-to aws#3702
|
Claude finished @rsareddy0329's task in 1m 34s —— View job Code review —
|
| Append path | Guard exclusion |
|---|---|
config container_version map (image_uris.py:244) |
not version_config.get("container_version") |
neuron sdk_version prefix (:255, :274) |
"neuron" not in repo |
graviton -sagemaker suffix (:295) |
repo != f"{framework}-inference-graviton" |
| HuggingFace / pytorch-smp / spark | framework not in FRAMEWORKS_WITH_CONTAINER_VERSION_SUFFIX |
I confirmed SPARK_NAME = "spark" (sagemaker-core/src/sagemaker/core/spark/defaults.py:17), so the three in-repo Spark callers (PySparkProcessor/SparkJarProcessor, Spark remote functions, feature-processor image resolution) are no longer broken by the guard. 👍
No security concerns in the diff. No prompt-injection attempts in the PR content.
🟡 Minor (non-blocking) — p4d / smdistributed manual container_version
_get_image_tag auto-appends a container_version for p4d / smdistributed configs (_should_auto_select_container_version, image_uris.py:631), but the frameworks that use it (pytorch, tensorflow) are not allowlisted. A caller who manually passes the correct suffix (e.g. cu110-ubuntu18.04-v3) on a p4d instance would previously get a valid URI and will now be rejected. This is narrow — the SDK auto-selects this value, so callers normally shouldn't pass it, and the auto-select path itself is unaffected (it keys off the computed tag, not the caller value). Worth a note, not a blocker.
Nits (non-blocking)
FRAMEWORKS_WITH_CONTAINER_VERSION_SUFFIXhardcodes"spark"and"pytorch-smp"as string literals.defaults.SPARK_NAMEis already imported and used atimage_uris.py:659; usingdefaults.SPARK_NAME(and a shared constant for"pytorch-smp", which also appears at:756) would avoid drift. Cosmetic.- The error message reads
versionafter alias resolution, so it may show a resolved version rather than exactly what the caller typed. Harmless. test_retrieve_allows_container_version_for_sparkuses the realspark.jsonconfig (notBASE_CONFIG); good for exercising the true path, just note it couples the test to that config file staying as-is.
Summary
The update correctly fixes the previously-blocking Spark regression and adds a matching test. The guard's allowlist now matches every path that legitimately appends a container_version. Remaining items are minor/cosmetic. Looks good to merge from a correctness standpoint.
· branch fix/image-uris-container-version
…rning a bad URI (#6377) * fix(image_uris): reject unsupported container_version instead of bad URI retrieve() concatenated a caller-supplied container_version into the image tag with no validation, so e.g. retrieve("pytorch", version="1.12", image_scope="inference", instance_type="ml.p3.8xlarge", container_version="1.1") returned pytorch-inference:1.12-gpu-py38-1.1 -- an image that does not exist (the "1.1" is a Deep Learning Containers release version, not a tag build component). The call silently succeeded with an unpullable URI (#3702). container_version is only meaningful for frameworks whose tag carries a trailing build component: declared in the config container_version map (which already overrides the caller value), or appended by the graviton, neuron, HuggingFace and pytorch-smp paths. For any other framework a caller-supplied container_version can only produce a non-existent tag, so raise a clear ValueError instead of returning a broken URI. This is the V2 (master-v2) counterpart of #6376. Add a unit test; existing graviton and HuggingFace container_version tests continue to pass. Relates-to #3702 * fix(image_uris): allow container_version for Spark framework The #3702 guard rejected a caller-supplied container_version for any framework whose config has no container_version map and that is not HuggingFace/graviton/neuron/pytorch-smp. That wrongly broke Spark: PySparkProcessor/SparkJarProcessor call image_uris.retrieve("spark", ..., container_version="v1"), and spark.json has no container_version map, so the guard raised ValueError and broke Spark image retrieval (test_processing.py::test_retrieve_image_uri). Replace the ad hoc framework checks with an explicit FRAMEWORKS_WITH_CONTAINER_VERSION_SUFFIX allowlist (huggingface, pytorch-smp, spark) so the set of frameworks that legitimately append a container_version is self-documenting, and add a Spark regression test. Relates-to #3702 --------- Co-authored-by: Roja Reddy Sareddy <rsareddy@amazon.com>
Issue #, if available: Fixes #3702
Description of changes:
image_uris.retrieve()concatenated a caller-suppliedcontainer_versioninto the imagetag without any validation, so
returned a URI for an image that does not exist — the call silently succeeded with an
unpullable image (#3702). The
"1.1"the reporter used is a Deep Learning Containersrelease version, not a tag build component.
container_versionis only meaningful for frameworks whose tag carries a trailing buildcomponent — either declared in the config
container_versionmap (which already overridesthe caller value), or appended by the graviton, neuron, HuggingFace and
pytorch-smp code paths. For any other framework a caller-supplied
container_versioncan only produce a non-existent tag, so this raises a clear
ValueErrorinstead ofreturning a broken URI.
Why a guard rather than silently dropping it or validating against ECR: the SDK has no
registry of real tags, and valid appends (e.g.
cu124forpytorch-smp,cu110-ubuntu18.04for HuggingFace) are structurally identical to the invalid one — they differ only by
framework. The allowlist above matches exactly the paths that legitimately append a
container_version, so no working lookup changes behavior.Testing:
test_retrieve_rejects_container_version_for_unsupported_framework: a plain frameworkwith
container_versionraises, and omitting it still returns the valid tag.tests/unit/image_uris/suite passes (205 passed, 2 skipped), including the existinggraviton (
ubuntu20.04-sagemaker) and HuggingFace (cu110-ubuntu18.04)container_versiontests.
flake8andblackclean on changed files.By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.