Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/managed-images.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -811,6 +811,9 @@ jobs:
DOCKER_CONFIG="$anonymous_config" docker pull \
--platform "$platform" \
"$cohort_reference"
# The classic Docker image store cannot retain two platform
# variants under one multi-platform digest reference.
docker image rm "$cohort_reference"
done
done < <(jq -c '.[]' "$cohort_manifests")
Expand Down
15 changes: 15 additions & 0 deletions test/helpers/managed-image-publication-barrier.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ export function runManagedImagePromotion(script: string, failCohortAgent = ""):
const root = fs.mkdtempSync(path.join(os.tmpdir(), "nemoclaw-managed-promotion-"));
const bin = path.join(root, "bin");
const calls = path.join(root, "docker-calls");
const pulledReferences = path.join(root, "docker-pulled-references");
const candidateSet = path.join(root, "candidate-set.json");
const contracts = path.join(root, "managed-image-contracts");
const digest = `sha256:${"f".repeat(64)}`;
Expand All @@ -163,6 +164,19 @@ export function runManagedImagePromotion(script: string, failCohortAgent = ""):
`#!/usr/bin/env bash
set -euo pipefail
printf '%s\\n' "$*" >> "$DOCKER_CALLS"
if [ "$1" = "pull" ]; then
reference="\${@: -1}"
if grep -Fxq "$reference" "$DOCKER_PULLED_REFERENCES" 2>/dev/null; then
printf 'cannot overwrite digest %s\\n' "\${reference##*@}" >&2
exit 92
fi
printf '%s\\n' "$reference" >> "$DOCKER_PULLED_REFERENCES"
elif [ "$1" = "image" ] && [ "$2" = "rm" ]; then
reference="$3"
remaining="\${DOCKER_PULLED_REFERENCES}.remaining"
grep -Fvx "$reference" "$DOCKER_PULLED_REFERENCES" > "$remaining" || true
mv "$remaining" "$DOCKER_PULLED_REFERENCES"
fi
if [ -n "\${FAIL_COHORT_AGENT:-}" ] &&
[[ "$*" == *"imagetools create"* ]] &&
[[ "$*" == *"/\${FAIL_COHORT_AGENT}-sandbox:cohort-"* ]]; then
Expand All @@ -189,6 +203,7 @@ fi
...process.env,
CANDIDATE_SET: candidateSet,
DOCKER_CALLS: calls,
DOCKER_PULLED_REFERENCES: pulledReferences,
FAIL_COHORT_AGENT: failCohortAgent,
GITHUB_REPOSITORY: repository,
GITHUB_RUN_ATTEMPT: runAttempt,
Expand Down
32 changes: 32 additions & 0 deletions test/managed-image-publication-workflow.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -572,6 +572,38 @@ describe("complete managed-image publication workflow", () => {
expect(runPublicationBarrier(barrier.run ?? "").status).toBe(0);
});

it("removes each anonymously pulled digest reference before the next platform pull", () => {
const promotion = required(
step(
managedPromoter(readWorkflow("managed-images.yaml")),
"Promote validated multi-platform managed image cohort",
).run,
"managed image promotion script is missing",
);
const result = runManagedImagePromotion(promotion);
const collision = runManagedImagePromotion(
promotion.replace('docker image rm "$cohort_reference"', ":"),
);
const digest = `sha256:${"f".repeat(64)}`;
const anonymousPullCalls = result.calls.filter(
(call) => call.startsWith("pull --platform") || call.startsWith("image rm"),
);
const expectedCalls = [...publicationAgents].sort().flatMap((agent) => {
const reference = `ghcr.io/nvidia/nemoclaw/${agent}-sandbox@${digest}`;
return [
`pull --platform linux/amd64 ${reference}`,
`image rm ${reference}`,
`pull --platform linux/arm64 ${reference}`,
`image rm ${reference}`,
];
});

expect(collision.status).toBe(92);
expect(collision.stderr).toContain(`cannot overwrite digest ${digest}`);
expect(result.status, result.stderr).toBe(0);
expect(anonymousPullCalls).toEqual(expectedCalls);
});

it("stages all multi-platform cohort aliases before moving the sole root pointer (#7744)", () => {
const promotion = required(
step(
Expand Down
Loading