Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ const EXPECTED_LITERAL_SITES = {
validatePackagedProof: { digests: 2, permissionTuples: 2, stepNames: 106, workflowNames: 2 },
validatePluginAndDraftWorkflows: { stepNames: 32, workflowNames: 13 },
validatePluginRelease: { permissionTuples: 1, stepNames: 17, workflowNames: 6 },
validatePostPublish: { stepNames: 38, workflowNames: 1 },
validatePostPublish: { stepNames: 40, workflowNames: 1 },
validateReleaseArtifactRerunSafety: { workflowNames: 13 },
validateReleaseCellUploadOwnership: { workflowNames: 18 },
validateReleaseCoordinator: { stepNames: 24, workflowNames: 11 },
Expand Down
34 changes: 32 additions & 2 deletions .github/scripts/check-workflow-policy.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4937,6 +4937,33 @@ function validatePostPublish(workflows, violations, graph) {
add(violations, closeoutInput.type === "string", `${file} ${event} pre_publish_closeout_artifact must be a string`);
}
const job = object(object(workflow.jobs).smoke);
const closeoutHarnessName = "Stage caller-bound closeout harness";
const closeoutHarness = namedStep(job, closeoutHarnessName);
add(
violations,
closeoutHarness?.id === "closeout-harness"
&& closeoutHarness?.shell === "bash"
&& closeoutHarness?.if === undefined
&& closeoutHarness?.["continue-on-error"] === undefined,
`${file} must stage the caller-bound closeout harness fail closed`,
);
requireStepRun(violations, file, job, closeoutHarnessName, [
`printf '%s' "$GITHUB_SHA" | grep -Eq '^[0-9a-f]{40}$'`,
'git archive "$GITHUB_SHA"',
".github/scripts/install-codestory-marketplace-proof.mjs",
".github/scripts/marketplace-delivery-identity.mjs",
".github/scripts/check-packaged-agent-proof.py",
".github/scripts/packaged_agent_proof",
'| tar -x -C "$harness_root"',
'echo "helper=$harness_root/.github/scripts/install-codestory-marketplace-proof.mjs" >> "$GITHUB_OUTPUT"',
'echo "proof=$harness_root/.github/scripts/check-packaged-agent-proof.py" >> "$GITHUB_OUTPUT"',
]);
add(
violations,
stepIndex(job, closeoutHarnessName)
< stepIndex(job, "Bind this smoke to the published release"),
`${file} must stage the closeout harness immediately after the tag checkout`,
);
const pythonSetup = namedStep(job, "Install pinned Python");
add(
violations,
Expand Down Expand Up @@ -5296,6 +5323,7 @@ function validatePostPublish(workflows, violations, graph) {
// The install arguments arrive as variables, so the command text no longer says which delivery
// state produced them. Each variable is bound back to the step that resolved it.
requireStepEnv(violations, file, job, resolveStepName, {
CLOSEOUT_HELPER: "${{ steps.closeout-harness.outputs.helper }}",
MARKETPLACE_REVISION: "${{ steps.delivery.outputs.marketplace_revision }}",
MARKETPLACE_SOURCE: "${{ steps.delivery.outputs.marketplace_source }}",
LOCAL_FIXTURE: "${{ steps.delivery.outputs.local_fixture }}",
Expand Down Expand Up @@ -5359,7 +5387,7 @@ function validatePostPublish(workflows, violations, graph) {
);
const installedRun = executableRunText(String(installed?.run ?? ""));
for (const fragment of [
"python .github/scripts/check-packaged-agent-proof.py",
'python "$PROOF_HELPER"',
'--archive "$ASSET_ARCHIVE"',
"--plugin-handoff",
"--engine-policy accelerated",
Expand Down Expand Up @@ -5389,6 +5417,7 @@ function validatePostPublish(workflows, violations, graph) {
CATALOG_DELIVERY_STATE: "${{ steps.delivery.outputs.state }}",
DELIVERED_INSTALLER: "${{ steps.delivery.outputs.installer }}",
EXPECTED_BACKEND: "${{ matrix.backend }}",
PROOF_HELPER: "${{ steps.closeout-harness.outputs.proof }}",
});
add(
violations,
Expand All @@ -5402,6 +5431,7 @@ function validatePostPublish(workflows, violations, graph) {
"INSTALLED_ATTESTATION",
"INSTALLED_PLUGIN_DATA",
"INSTALLED_PLUGIN_ROOT",
"PROOF_HELPER",
"RELEASE_VERSION",
]),
`${file} installed runtime restart proof must bind only the reviewed package, install, delivery, and backend identities`,
Expand All @@ -5415,7 +5445,7 @@ function validatePostPublish(workflows, violations, graph) {
add(
violations,
occurrenceCount(installedRun, "common=(") === 1
&& occurrenceCount(installedCommon, "python .github/scripts/check-packaged-agent-proof.py") === 1
&& occurrenceCount(installedCommon, 'python "$PROOF_HELPER"') === 1
&& [
'--archive "$ASSET_ARCHIVE"',
'--checksum-file "$ASSET_CHECKSUM"',
Expand Down
21 changes: 17 additions & 4 deletions .github/scripts/check-workflow-policy.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -3140,7 +3140,7 @@ test("exact proof policy rejects trigger and identity downgrades", async (t) =>
["source manual SHA equality", sourceFile, workflow => {
sourceResolver(workflow).run = sourceResolver(workflow).run
.replace('test "$GITHUB_SHA" = "$EXPECTED_HEAD_SHA"', 'test -n "$GITHUB_SHA"');
}, /GITHUB_SHA.*EXPECTED_HEAD_SHA/u],
}, /GITHUB_SHA.*EXPECTED_HEAD_SHA|trusted resolver script contract/u],
["source manual SHA short-circuit", sourceFile, workflow => {
sourceResolver(workflow).run = sourceResolver(workflow).run
.replace(
Expand Down Expand Up @@ -3177,7 +3177,7 @@ test("exact proof policy rejects trigger and identity downgrades", async (t) =>
["platform manual SHA equality", packagedCoordinatorFile, workflow => {
packagedResolver(workflow).run = packagedResolver(workflow).run
.replace('test "$GITHUB_SHA" = "$INPUT_HEAD_SHA"', 'test -n "$GITHUB_SHA"');
}, /GITHUB_SHA.*INPUT_HEAD_SHA/u],
}, /GITHUB_SHA.*INPUT_HEAD_SHA|trusted resolver script contract/u],
["platform manual SHA short-circuit", packagedCoordinatorFile, workflow => {
packagedResolver(workflow).run = packagedResolver(workflow).run
.replace(
Expand Down Expand Up @@ -3213,7 +3213,7 @@ test("exact proof policy rejects trigger and identity downgrades", async (t) =>
["integration live dev SHA equality", packagedCoordinatorFile, workflow => {
packagedResolver(workflow).run = packagedResolver(workflow).run
.replace('test "$GITHUB_SHA" = "$dev_head"', 'test -n "$GITHUB_SHA"');
}, /GITHUB_SHA.*dev_head/u],
}, /GITHUB_SHA.*dev_head|trusted resolver script contract/u],
["hosted-only integration scope removed", packagedCoordinatorFile, workflow => {
workflow.on.workflow_dispatch.inputs.scope.options
= workflow.on.workflow_dispatch.inputs.scope.options.filter(scope => scope !== "none");
Expand Down Expand Up @@ -4102,7 +4102,7 @@ test("release freeze policy pins live PR base and support ancestry revalidation"
"JSON.parse('{}')",
)],
["release base lookup stops using the live integration ref", value =>
value.replace(
value.replaceAll(
"`repos/${repository}/git/ref/heads/dev/codestory-next`",
"`repos/${repository}/git/commits/${pr.base.sha}`",
)],
Expand Down Expand Up @@ -5957,6 +5957,19 @@ test("post-publish proof uses an immutable real Codex marketplace install", asyn
({ name }) => name === "Prove the catalog-resolved published runtime",
);
const mutations = [
["caller-bound closeout harness is removed", workflow => {
workflow.jobs.smoke.steps = workflow.jobs.smoke.steps.filter(
({ name }) => name !== "Stage caller-bound closeout harness",
);
}, /stage the caller-bound closeout harness/u],
["install step returns to the release-tag harness", workflow => {
installStep(workflow).env.CLOSEOUT_HELPER =
"${{ github.workspace }}/.github/scripts/install-codestory-marketplace-proof.mjs";
}, /must bind CLOSEOUT_HELPER/u],
["runtime proof returns to the release-tag harness", workflow => {
proofStep(workflow).env.PROOF_HELPER =
"${{ github.workspace }}/.github/scripts/check-packaged-agent-proof.py";
}, /must bind PROOF_HELPER/u],
["Codex CLI pin drifts", workflow => {
workflow.env.CODEX_CLI_VERSION = "latest";
}, /pin the Codex CLI/u],
Expand Down
25 changes: 19 additions & 6 deletions .github/scripts/install-codestory-marketplace-proof.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -55,18 +55,24 @@ export function commandPlan(
if (/[\r\n"]/u.test(value)) fail("Codex command arguments must be single-line");
return `"${value.replaceAll("%", "%%")}"`;
};
const commandLine = [executable, ...args].map(quote).join(" ");
return {
command: comspec,
commandArgs: ["/d", "/s", "/c", [executable, ...args].map(quote).join(" ")],
// With /s, cmd.exe removes the first and last quotes from the command
// string. Keep an outer pair so the quoted shim path survives intact,
// and stop Node from escaping that raw cmd.exe command string again.
commandArgs: ["/d", "/s", "/c", `"${commandLine}"`],
spawnOptions: { windowsVerbatimArguments: true },
};
}
return { command: executable, commandArgs: args };
}

function run(executable, args, options = {}) {
const { command, commandArgs } = commandPlan(executable, args);
const { command, commandArgs, spawnOptions = {} } = commandPlan(executable, args);
const result = spawnSync(command, commandArgs, {
...options,
...spawnOptions,
encoding: "utf8",
});
if (result.status !== 0) {
Expand All @@ -92,12 +98,19 @@ function filesUnder(root, relative = "") {
});
}

function directoryDigest(root) {
export function directoryDigest(root) {
const digest = createHash("sha256");
const files = filesUnder(root).sort();
const files = filesUnder(root)
.map((relative) => ({
relative,
normalized: relative.split(path.sep).join("/"),
}))
.sort((left, right) => Buffer.compare(
Buffer.from(left.normalized),
Buffer.from(right.normalized),
));
if (files.length === 0) fail("installed plugin package is empty");
for (const relative of files) {
const normalized = relative.split(path.sep).join("/");
for (const { relative, normalized } of files) {
const name = Buffer.from(normalized);
const payload = readFileSync(path.join(root, relative));
const nameLength = Buffer.alloc(8);
Expand Down
42 changes: 40 additions & 2 deletions .github/scripts/install-codestory-marketplace-proof.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,29 @@ import process from "node:process";
import test from "node:test";
import { fileURLToPath, pathToFileURL } from "node:url";

import { commandPlan } from "./install-codestory-marketplace-proof.mjs";
import {
commandPlan,
directoryDigest,
} from "./install-codestory-marketplace-proof.mjs";

const scriptRoot = path.dirname(fileURLToPath(import.meta.url));
const repositoryRoot = path.resolve(scriptRoot, "..", "..");
const helper = path.join(scriptRoot, "install-codestory-marketplace-proof.mjs");
const codexVersion = "0.144.5";
const orderingContractDigest =
"9c8a732ad11364c4eb6a36b16fd856f5b63e31ab01ad41e5782bdafdbf7dd34d";

test("plugin directory digest sorts normalized paths bytewise", () => {
const root = mkdtempSync(path.join(tmpdir(), "codestory-directory-contract-"));
try {
mkdirSync(path.join(root, "a"));
writeFileSync(path.join(root, "a", "child.txt"), "nested");
writeFileSync(path.join(root, "a0.txt"), "flat");
assert.equal(directoryDigest(root), orderingContractDigest);
} finally {
rmSync(root, { recursive: true, force: true });
}
});

test("Windows invokes native executables directly and wraps only command shims", () => {
const comspec = "C:\\Windows\\System32\\cmd.exe";
Expand All @@ -45,12 +62,33 @@ test("Windows invokes native executables directly and wraps only command shims",
"/d",
"/s",
"/c",
'"C:\\tools\\codex.cmd" "plugin" "list" "--json"',
'""C:\\tools\\codex.cmd" "plugin" "list" "--json""',
],
spawnOptions: { windowsVerbatimArguments: true },
},
);
});

test("Windows executes a command shim whose path and arguments contain spaces", {
skip: process.platform !== "win32",
}, () => {
const root = mkdtempSync(path.join(tmpdir(), "codestory command shim "));
try {
const shim = path.join(root, "shim directory", "probe.cmd");
mkdirSync(path.dirname(shim), { recursive: true });
writeFileSync(shim, "@echo off\r\necho [%~1][%~2]\r\n");
const plan = commandPlan(shim, ["first", "two words"]);
const result = spawnSync(plan.command, plan.commandArgs, {
...plan.spawnOptions,
encoding: "utf8",
});
assert.equal(result.status, 0, result.stderr);
assert.equal(result.stdout.trim(), "[first][two words]");
} finally {
rmSync(root, { recursive: true, force: true });
}
});

function run(executable, args, options = {}) {
const result = spawnSync(executable, args, {
...options,
Expand Down
10 changes: 7 additions & 3 deletions .github/scripts/packaged_agent_proof/installation_support.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,18 @@
def directory_contract_sha256(root: Path) -> str:
require(root.is_dir(), f"plugin package root does not exist: {root}")
digest = hashlib.sha256()
files = sorted(path for path in root.rglob("*") if path.is_file())
files = [
(path.relative_to(root).as_posix().encode("utf-8"), path)
for path in root.rglob("*")
if path.is_file()
]
files.sort(key=lambda entry: entry[0])
require(files, "plugin package root is empty")
for path in files:
for relative, path in files:
require(
not path.is_symlink(),
f"installed plugin package contains a symlink: {path}",
)
relative = path.relative_to(root).as_posix().encode("utf-8")
payload = path.read_bytes()
digest.update(len(relative).to_bytes(8, "little"))
digest.update(relative)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@

from .foundation import REPOSITORY_ROOT, ProofFailure, require
from .installed_identity import installed_plugin_identity
from .installation_support import directory_contract_sha256
from .marketplace_installation import (
DEFERRED_INSTALLATION_SOURCE,
LIVE_INSTALLATION_SOURCE,
Expand All @@ -42,6 +43,21 @@
_MARKER_FILENAME = ".codestory-marketplace-fixture.json"
_MARKER_PURPOSE = "codestory-candidate-pinned-marketplace-fixture"
_PLUGIN_ID = f"codestory@{_MARKETPLACE_NAME}"
_ORDERING_CONTRACT_DIGEST = (
"9c8a732ad11364c4eb6a36b16fd856f5b63e31ab01ad41e5782bdafdbf7dd34d"
)


def _run_directory_contract_ordering_self_test() -> None:
with tempfile.TemporaryDirectory(prefix="codestory-directory-contract-") as raw:
root = Path(raw)
(root / "a").mkdir()
(root / "a" / "child.txt").write_text("nested", encoding="utf-8")
(root / "a0.txt").write_text("flat", encoding="utf-8")
require(
directory_contract_sha256(root) == _ORDERING_CONTRACT_DIGEST,
"plugin directory digest does not sort normalized paths bytewise",
)


def _git(repository: Path, *arguments: str) -> str:
Expand Down Expand Up @@ -609,6 +625,7 @@ def _run_shared_identity_self_tests() -> None:


def run_marketplace_delivery_self_tests() -> None:
_run_directory_contract_ordering_self_test()
_run_codex_config_serialization_self_test()
manifest = _manifest()
with tempfile.TemporaryDirectory(prefix="codestory-marketplace-delivery-") as raw:
Expand Down
8 changes: 7 additions & 1 deletion .github/scripts/release-driver-receipt.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,13 @@ function validateGroupValue(group, value) {
sha(row.commit, `${group} commit`);
sha(row.tree, `${group} tree`);
} else if (group === "pull-requests") {
positiveInteger(row.release_pr, "pull-requests release_pr");
if (row.release_pr == null || row.release_pr === 0) {
if (row.bind !== "next_head") {
fail("pull-requests without release_pr must bind next_head");
}
} else {
positiveInteger(row.release_pr, "pull-requests release_pr");
}
if (
!Array.isArray(row.integrated_support_prs)
|| !row.integrated_support_prs.every(number =>
Expand Down
3 changes: 2 additions & 1 deletion .github/scripts/release-driver-receipt.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ function preFreezeReceipt() {
let receipt = initReceipt("0.17.0");
receipt = record(receipt, "calibration-source", { commit: C, tree: C_TREE });
receipt = record(receipt, "pull-requests", {
release_pr: 1873,
release_pr: null,
bind: "next_head",
integrated_support_prs: [1869, 1871],
});
receipt = record(
Expand Down
4 changes: 2 additions & 2 deletions .github/scripts/release-freeze-acceptance-jobs.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
{
"schema": "codestory.release-freeze-acceptance-jobs/v2",
"workflow": ".github/workflows/source-proof.yml",
"workflow_context_sha256": "81c20037a04bf19fb5a0ac043cea491186613ae55335c88b86150011191254a4",
"workflow_context_sha256": "c2c807e4ea1e830e07fdbee2ab52a47f2e765be694e3e3cb6e681840c7893250",
"jobs": {
"resolve": "16e028133665257ebd2260770752587cb339dc58dbf87004065ac1a9f754fa65",
"resolve": "d5f548a981f92e6597233ca50b7184627b79515e89911e214244fcb4a29f378f",
"freeze-hostile-mutations": "ebc27d28a1c087f848be090d2a2a458acee0177f06048c4d357e0724cf38be1a",
"freeze-windows-native-probe": "e4570bb9d0ae34da43965d49c02b34276b43ad6b6e2a492435dedb1f254e454a",
"freeze-acceptance": "19e8ad21de3c35d03b4630c44f6b88d1d3d813d48c28aa9176cb4b75bb596371"
Expand Down
Loading
Loading