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"]),