Skip to content

Commit d296e96

Browse files
fix(ci): bound the release evidence subprocess capture (#1748)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
1 parent 070a0cf commit d296e96

2 files changed

Lines changed: 22 additions & 0 deletions

File tree

scripts/verify-release-evidence.test.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import assert from "node:assert/strict";
2+
import { readFileSync } from "node:fs";
23
import { describe, it } from "node:test";
34

45
import {
@@ -164,6 +165,18 @@ void describe("release evidence manifest", () => {
164165
});
165166
});
166167

168+
void describe("subprocess capture", () => {
169+
void it("bounds every captured subprocess above Node's 1 MiB default", () => {
170+
// A cosign attestation carries the whole SPDX SBOM base64-encoded. Under the default cap the
171+
// capture raises ENOBUFS, which failed a release after the images were already tagged.
172+
const source = readFileSync(new URL("./verify-release-evidence.ts", import.meta.url), "utf8");
173+
assert.match(source, /maxBuffer: CAPTURE_LIMIT_BYTES/);
174+
const limit = /const CAPTURE_LIMIT_BYTES = (\d+) \* 1024 \* 1024;/.exec(source);
175+
assert.ok(limit, "CAPTURE_LIMIT_BYTES must be declared in MiB");
176+
assert.ok(Number(limit[1]) >= 64, "an SBOM attestation needs far more than the 1 MiB default");
177+
});
178+
});
179+
167180
void describe("release evidence bindings", () => {
168181
void it("binds license and OCI index evidence to the immutable subject", () => {
169182
const amd64 = subject("linux/amd64");

scripts/verify-release-evidence.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,10 +182,19 @@ export function validateManifest(
182182
return { schemaVersion: 1, subjects };
183183
}
184184

185+
/**
186+
* Node caps a captured subprocess at 1 MiB and raises ENOBUFS past it. A `cosign verify-attestation`
187+
* envelope carries the whole SPDX SBOM base64-encoded, so the webapp's exceeds that cap and failed a
188+
* release mid-verification. The bound belongs here rather than at a call site: every capture in this
189+
* file reads an SBOM, an attestation or an image index, and none of them has a useful size limit.
190+
*/
191+
const CAPTURE_LIMIT_BYTES = 256 * 1024 * 1024;
192+
185193
function command(commandName: string, args: string[], capture = false): string {
186194
const result = spawnSync(commandName, args, {
187195
encoding: "utf8",
188196
stdio: capture ? "pipe" : "inherit",
197+
maxBuffer: CAPTURE_LIMIT_BYTES,
189198
});
190199
if (result.error) throw result.error;
191200
if (result.status !== 0) {

0 commit comments

Comments
 (0)