From 7bbd2e9b3faa7a6eb1fca89130365f31fc2ad11f Mon Sep 17 00:00:00 2001 From: Alix-007 Date: Fri, 17 Jul 2026 15:10:17 +0800 Subject: [PATCH] fix(docker): bound attestation registry inspection (#109325) --- scripts/verify-docker-attestations.d.mts | 6 +++++ scripts/verify-docker-attestations.mjs | 8 ++++-- .../verify-docker-attestations.test.ts | 27 +++++++++++++++++++ 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/scripts/verify-docker-attestations.d.mts b/scripts/verify-docker-attestations.d.mts index 906ac124aa4..540c2056834 100644 --- a/scripts/verify-docker-attestations.d.mts +++ b/scripts/verify-docker-attestations.d.mts @@ -15,6 +15,12 @@ export function parsePlatform(value: unknown): { * Collects missing/mismatched attestation errors for required image platforms. */ export function collectDockerAttestationErrors(params: unknown): string[]; +export function inspectRaw( + imageRef: unknown, + params?: { + execFileSyncImpl?: (command: string, args: string[], options: unknown) => string; + }, +): string; export function parseArgs(argv: unknown): { help: boolean; imageRefs: unknown[]; diff --git a/scripts/verify-docker-attestations.mjs b/scripts/verify-docker-attestations.mjs index e0aa245b671..32f48fc966a 100644 --- a/scripts/verify-docker-attestations.mjs +++ b/scripts/verify-docker-attestations.mjs @@ -7,6 +7,7 @@ import process from "node:process"; const ATTESTATION_REFERENCE_TYPE = "attestation-manifest"; const EXPECTED_ATTESTATION_ARTIFACT_TYPE = "application/vnd.docker.attestation.manifest.v1+json"; const REQUIRED_PREDICATES = ["https://spdx.dev/Document", "https://slsa.dev/provenance/v1"]; +const DOCKER_INSPECT_TIMEOUT_MS = 120_000; /** * Rewrites an image reference to use the provided digest. @@ -124,11 +125,14 @@ export function collectDockerAttestationErrors(params) { return errors; } -function inspectRaw(imageRef) { - return execFileSync("docker", ["buildx", "imagetools", "inspect", "--raw", imageRef], { +export function inspectRaw(imageRef, params = {}) { + const execFileSyncImpl = params.execFileSyncImpl ?? execFileSync; + return execFileSyncImpl("docker", ["buildx", "imagetools", "inspect", "--raw", imageRef], { encoding: "utf8", + killSignal: "SIGKILL", maxBuffer: 20 * 1024 * 1024, stdio: ["ignore", "pipe", "pipe"], + timeout: DOCKER_INSPECT_TIMEOUT_MS, }); } diff --git a/test/scripts/verify-docker-attestations.test.ts b/test/scripts/verify-docker-attestations.test.ts index 1a829975a9e..706c8b104dc 100644 --- a/test/scripts/verify-docker-attestations.test.ts +++ b/test/scripts/verify-docker-attestations.test.ts @@ -3,6 +3,7 @@ import { describe, expect, it } from "vitest"; import { collectDockerAttestationErrors, imageRefForDigest, + inspectRaw, parseArgs, parsePlatform, } from "../../scripts/verify-docker-attestations.mjs"; @@ -54,6 +55,32 @@ function createAttestation( } describe("verify-docker-attestations", () => { + it("bounds docker manifest inspection calls", () => { + const calls: unknown[] = []; + const imageRef = "ghcr.io/openclaw/openclaw:test"; + const output = inspectRaw(imageRef, { + execFileSyncImpl(command: string, args: string[], options: unknown) { + calls.push({ args, command, options }); + return "{}"; + }, + }); + + expect(output).toBe("{}"); + expect(calls).toStrictEqual([ + { + args: ["buildx", "imagetools", "inspect", "--raw", imageRef], + command: "docker", + options: { + encoding: "utf8", + killSignal: "SIGKILL", + maxBuffer: 20 * 1024 * 1024, + stdio: ["ignore", "pipe", "pipe"], + timeout: 120_000, + }, + }, + ]); + }); + it("parses required platforms and image refs", () => { expect( parseArgs(["--platform", "linux/amd64", "--platform", "linux/arm64", "ghcr.io/openclaw/app"]),