Integrate Node 24 security pin policy repair

Co-Authored-By: Paperclip <noreply@paperclip.ing>

* codex/runner-cursor-acp:
  fix(ci): accept exact Node 24 security image pins
This commit is contained in:
DottaandPaperclip committed 2026-09-28 17:53:54 -05:00
commit ac785ba09f
3 files changed
+24 -1

No files matched your search

+2 -1
View File
@@ -1,6 +1,7 @@
import fs from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { isNode24ImageTag } from "./node-image-policy.mjs";
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
const expectedEngine = ">=24.11.0";
@@ -48,7 +49,7 @@ walk(repoRoot, (filePath) => {
if (!path.basename(filePath).startsWith("Dockerfile")) return;
const source = fs.readFileSync(filePath, "utf8");
for (const match of source.matchAll(/^\s*FROM\s+node:([^\s]+)/gm)) {
if (!match[1].startsWith("24-")) failures.push(`${relative(filePath)}: Node base image must use the Node 24 major, found node:${match[1]}`);
if (!isNode24ImageTag(match[1])) failures.push(`${relative(filePath)}: Node base image must use the Node 24 major, found node:${match[1]}`);
}
for (const match of source.matchAll(/^\s*ARG\s+NODE_(?:MAJOR|VERSION)=([^\s]+)/gm)) {
if (match[1] !== "24") failures.push(`${relative(filePath)}: Node build argument must be 24, found ${match[1]}`);
+5
View File
@@ -0,0 +1,5 @@
// Accept the existing major tags and exact patch pins, with a required image variant.
// A digest, when present, must be a complete SHA-256 pin.
export function isNode24ImageTag(tag) {
return /^24(?:\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*))?-[a-z0-9][a-z0-9._-]*(?:@sha256:[a-f0-9]{64})?$/.test(tag);
}
+17
View File
@@ -2,6 +2,23 @@ import assert from "node:assert/strict";
import { createHash } from "node:crypto";
import test from "node:test";
import { standardImageDigest, resolveStandardImageDigest } from "./standard-image-contract.mjs";
import { isNode24ImageTag } from "./node-image-policy.mjs";
test("Node image policy accepts Node 24 major tags and exact security pins", () => {
for (const tag of ["24-trixie-slim", "24-bookworm-slim", "24-alpine3.23", "24.21.0-bookworm",
`24.21.0-bookworm@sha256:${"a".repeat(64)}`, `24-bookworm@sha256:${"0".repeat(64)}`]) {
assert.equal(isNode24ImageTag(tag), true, tag);
}
});
test("Node image policy rejects other majors, partial versions and malformed pins", () => {
for (const tag of ["240-bookworm", "25.21.0-bookworm", "v24.21.0-bookworm", "latest",
"24.21-bookworm", "24.21.0", "24.21.0-", "24..21.0-bookworm", "24.021.0-bookworm",
"24.21.0-bookworm@sha256:short", `24.21.0-bookworm@@sha256:${"a".repeat(64)}`,
`24.21.0-bookworm@sha256:${"a".repeat(64)}junk`, "${NODE_VERSION}-bookworm", "24-$(whoami)"]) {
assert.equal(isNode24ImageTag(tag), false, tag);
}
});
const descriptor = architecture => ({ platform: { os: "linux", architecture }, digest: `sha256:${"a".repeat(64)}`, size: 100 });
const index = manifests => Buffer.from(JSON.stringify({ schemaVersion: 2, mediaType: "application/vnd.oci.image.index.v1+json", manifests }));
test("signs the exact registry bytes, including both supported platforms", () => {