fix(genbi): keep managed runtime readiness read-only

This commit is contained in:
Jax Liu
2026-09-07 13:02:23 +08:00
parent e8ddcaaea6
commit 99da1da319
5 changed files with 90 additions and 22 deletions
+2 -1
View File
@@ -46,7 +46,8 @@ jobs:
curl --fail --location --proto '=https' --tlsv1.2 -o release/python.tar.gz 'https://github.com/astral-sh/python-build-standalone/releases/download/20260901/cpython-3.11.16%2B20260901-aarch64-apple-darwin-install_only.tar.gz'
test "$(shasum -a 256 release/python.tar.gz | awk '{print $1}')" = 50424fa409e8ae84b82a3052522f64695b47dff2158b70bb7358e0ebd6c085c9
/usr/bin/tar -tzf release/python.tar.gz | python -c "import json,sys; paths=[p.strip() for p in sys.stdin if any(x in p.upper() for x in ('LICENSE','COPYING','NOTICE'))]; print(json.dumps({'schema':1,'archiveSha256':'50424fa409e8ae84b82a3052522f64695b47dff2158b70bb7358e0ebd6c085c9','bundledLicenseEvidence':[{'path':p,'declaredLicense':'REVIEW_REQUIRED'} for p in paths]},indent=2))" > release/pbs-license-inventory.json
/usr/bin/tar -xzf release/python.tar.gz -C release/runtime
/usr/bin/tar -xpzf release/python.tar.gz -C release/runtime
/bin/chmod 700 release/runtime
release/runtime/python/bin/python3.11 -m venv release/runtime/venv
python - <<'PY'
import json, pathlib
+25 -5
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env node
/** Non-publishing reproducibility probe for the exact managed PBS input. */
import { createHash } from "node:crypto";
import { chmod, mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
import { chmod, lstat, mkdtemp, readFile, readdir, readlink, realpath, rm, writeFile } from "node:fs/promises";
import { execFile } from "node:child_process";
import { promisify } from "node:util";
import os from "node:os";
@@ -9,13 +9,33 @@ import path from "node:path";
import { fileURLToPath } from "node:url";
const run = promisify(execFile); const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
const input = JSON.parse(await readFile(path.join(root, "managed-wren", "release-inputs.json"), "utf8")).python;
const temp = await mkdtemp(path.join(os.tmpdir(), "genbi-pbs-probe-"));
const digest = (value) => createHash("sha256").update(value).digest("hex");
function contained(root, target) { const relative = path.relative(root, target); return relative === "" || (!relative.startsWith("..") && !path.isAbsolute(relative)); }
async function treeDigest(root) {
const entries = [];
const visit = async (directory) => {
for (const name of (await readdir(directory)).sort()) {
if (name === "__pycache__") continue;
const target = path.join(directory, name); const metadata = await lstat(target); const mode = (metadata.mode & 0o777).toString(8);
if (metadata.isSymbolicLink()) { const canonical = await realpath(target); if (!contained(root, canonical)) throw new Error("PBS link escapes tree"); entries.push(path.relative(root, target) + "\0" + mode + "\0link\0" + await readlink(target)); }
else if (metadata.isDirectory()) await visit(target); else if (metadata.isFile()) entries.push(path.relative(root, target) + "\0" + mode + "\0file\0" + digest(await readFile(target))); else throw new Error("unsupported PBS tree entry");
}
};
await visit(root); return digest(entries.join("\n"));
}
async function extractWithUmask(archive, target, umask) {
await run("/bin/sh", ["-c", "umask \"$1\"; exec /usr/bin/tar -xpzf \"$2\" -C \"$3\"", "managed-wren-pbs", umask, archive, target]);
}
const temp = await realpath(await mkdtemp(path.join(os.tmpdir(), "genbi-pbs-probe-")));
try {
const archive = path.join(temp, input.filename); await run("/usr/bin/curl", ["--fail", "--location", "--proto", "=https", "--tlsv1.2", "-o", archive, input.url]);
if (createHash("sha256").update(await readFile(archive)).digest("hex") !== input.sha256) throw new Error("PBS hash mismatch");
const staging = path.join(temp, "staging"), final = path.join(temp, "final"); await run("/bin/mkdir", [staging]); await run("/usr/bin/tar", ["-xzf", archive, "-C", staging]);
if (digest(await readFile(archive)) !== input.sha256) throw new Error("PBS hash mismatch");
const staging = path.join(temp, "staging-022"), alternate = path.join(temp, "staging-077"), final = path.join(temp, "final"); await run("/bin/mkdir", [staging]); await run("/bin/mkdir", [alternate]);
await extractWithUmask(archive, staging, "022"); await extractWithUmask(archive, alternate, "077"); await chmod(staging, 0o700); await chmod(alternate, 0o700);
const pythonTreeSha256 = await treeDigest(path.join(staging, "python"));
if (pythonTreeSha256 !== await treeDigest(path.join(alternate, "python"))) throw new Error("PBS tree digest depends on umask");
await run(path.join(staging, "python", "bin", "python3.11"), ["-m", "venv", "--copies", path.join(staging, "venv")]); await run("/bin/mv", [staging, final]);
const config = path.join(final, "venv", "pyvenv.cfg"); const text = (await readFile(config, "utf8")).split(staging).join(final); if (text.includes(staging)) throw new Error("staging reference remains"); await writeFile(config, text, { mode: 0o600 });
const launcher = path.join(final, "venv", "bin", "wren-probe"); await writeFile(launcher, `#!${path.join(final, "venv", "bin", "python")}\nimport sys; print(sys.executable)\n`, { mode: 0o700 }); await chmod(launcher, 0o700);
const { stdout } = await run(launcher, []); if (stdout.trim() !== path.join(final, "venv", "bin", "python")) throw new Error("promoted launcher mismatch"); console.log(`ok sha256=${input.sha256}`);
const { stdout } = await run(launcher, []); if (stdout.trim() !== path.join(final, "venv", "bin", "python")) throw new Error("promoted launcher mismatch"); console.log(`ok sha256=${input.sha256} pythonTreeSha256=${pythonTreeSha256}`);
} finally { if (path.basename(temp).startsWith("genbi-pbs-probe-")) await rm(temp, { recursive: true, force: true }); }
+8 -13
View File
@@ -144,7 +144,7 @@ import { NativeSessionService } from "./native-sessions.js";
import { NativeArtifactService } from "./native-artifacts.js";
import { RuntimeHost } from "./runtime-host/local.js";
import { runtimeNotReady } from "./runtime-host/policy.js";
import { ManagedWrenRuntimeError, provisionManagedWrenRuntime, resolveManagedWrenRuntime } from "./managed-wren-runtime.js";
import { managedWrenReadinessFailure, resolveManagedWrenRuntime } from "./managed-wren-runtime.js";
import { assertNativeExecutableIdentity, assertNativeRuntimeSpec, attestNativeExecutable, buildNativeChildEnvironment, buildNativeRuntimeSpec, resolveNativeExecutable } from "./native-runtime-spec.js";
import type { NativeExecutableIdentity } from "./native-runtime-spec.js";
import { initializeNativeSessionStateBase, legacyInteractiveWorkspace, validateLegacyInteractiveWorkspace } from "./native-session-workspace.js";
@@ -581,23 +581,18 @@ async function main(): Promise<void> {
// This is the sole production composition of the Phase-1 policy. Browser
// requests never reach this selection or its executable/policy inputs.
const managedCodexRuntimeProbe = async () => {
try {
const record = await provisionManagedWrenRuntime({ packageRoot });
// Provisioning is only one Codex readiness input. This phase must not
// enable the local PTY as a production Codex adapter before the future
// app-server capability/identity contract is certified.
void record;
return {
readiness: runtimeNotReady("codex-app-server", "unprovisioned", "codex_app_server_unprovisioned"),
diagnostic: { phase: "provisioning" as const },
};
} catch (error) {
const code = error instanceof ManagedWrenRuntimeError ? error.code : "codex_wren_runtime_unprovisioned";
const code = managedWrenReadinessFailure({ packageRoot });
if (code !== undefined) {
return {
readiness: runtimeNotReady("codex-app-server", "unprovisioned", code),
diagnostic: { phase: "provisioning" as const },
};
}
// A verified runtime alone does not enable the future app-server adapter.
return {
readiness: runtimeNotReady("codex-app-server", "unprovisioned", "codex_app_server_unprovisioned"),
diagnostic: { phase: "provisioning" as const },
};
};
const nativeRuntimeHost = new RuntimeHost({
selected: "local",
+16 -2
View File
@@ -38,7 +38,7 @@ const managedWrenManifestSchema = z.object({
if (new Set(value.wheels.map((wheel) => wheel.filename)).size !== value.wheels.length) context.addIssue({ code: "custom", message: "duplicate wheel filename" });
if (value.wheels[0]?.distribution !== "wrenai" || value.wheels[0].version !== value.compatibility.wren) context.addIssue({ code: "custom", message: "wrenai must be the first exact wheel" });
const approved = value.activation === "approved";
if (approved !== (value.licenseApproval.state === "approved") || (approved && (!value.licenseApproval.evidence || value.runtime.pythonTreeSha256 === "staged" || value.runtime.packageTreeSha256 === "staged" || value.runtime.closureSha256 === "staged"))) {
if (approved !== (value.licenseApproval.state === "approved") || (approved && (!value.licenseApproval.evidence || value.runtime.pythonTreeSha256 === "staged" || value.runtime.packageTreeSha256 === "staged" || value.runtime.sitePackagesTreeSha256 === "staged" || value.runtime.closureSha256 === "staged"))) {
context.addIssue({ code: "custom", message: "activation requires approved licence evidence and attested digests" });
}
});
@@ -309,6 +309,20 @@ export function resolveManagedWrenRuntime(options: { readonly packageRoot?: stri
return Object.freeze({ version: "1", shim: launcher, launcher, venv_python: interpreter, tool_root: path.join(generation, "venv"), site_packages: path.dirname(packagePath), source_root: packagePath, interpreter: python, interpreter_root: path.dirname(path.dirname(python)), manifest_digest: digest, generation_root: generation, closure_digest: actualClosure, package_digest: actualPackage });
}
/**
* Readiness is deliberately resolve-only: checking any RuntimeHost backend
* must neither create the GenBI runtime root nor fetch/install managed bytes.
* An explicit future first-use path may call the exported provisioner below.
*/
export function managedWrenReadinessFailure(options: { readonly packageRoot?: string; readonly runtimeRoot?: string } = {}): ManagedWrenFailureCode | undefined {
try {
resolveManagedWrenRuntime(options);
return undefined;
} catch (error) {
return error instanceof ManagedWrenRuntimeError ? error.code : "codex_wren_runtime_unprovisioned";
}
}
/**
* Provision is intentionally unavailable for a staged manifest. A release can
* only turn this on after the protected licence approval job writes an approved
@@ -352,7 +366,7 @@ export async function provisionManagedWrenRuntime(options: { readonly packageRoo
// Fetching any other URL, index, or dependency resolver is intentionally absent.
const archive = path.join(staging, manifest.runtime.pythonArchivePath); const download = async (url: string, target: string, expected: string) => { const response = await fetch(url); if (!response.ok) throw new Error("download"); const bytes = Buffer.from(await response.arrayBuffer()); if (sha256(bytes) !== expected) throw new Error("digest"); writeFileSync(target, bytes, { mode: 0o600, flag: "wx" }); };
await download(manifest.python.mirror.url, archive, manifest.python.mirror.sha256);
assertSafeArchive(archive); execFileSync("/usr/bin/tar", ["-xzf", archive, "-C", staging], { stdio: "ignore" });
assertSafeArchive(archive); execFileSync("/usr/bin/tar", ["-xpzf", archive, "-C", staging], { stdio: "ignore" }); chmodSync(staging, 0o700);
const python = path.join(staging, manifest.python.interpreterPath); regularExecutable(staging, python, "codex_wren_interpreter_mismatch");
const wheels = path.join(staging, "wheels"); mkdirSync(wheels, { mode: 0o700 });
for (const wheel of manifest.wheels) await download(wheel.url, path.join(wheels, wheel.filename), wheel.sha256);
+39 -1
View File
@@ -4,7 +4,9 @@ import { createHash } from "node:crypto";
import { tmpdir } from "node:os";
import path from "node:path";
import { afterEach, describe, expect, it, vi } from "vitest";
import { ManagedWrenRuntimeError, cleanupManagedWrenGenerations, managedWrenClosureDigest, managedWrenTreeDigest, manifestDigest, provisionManagedWrenRuntime, readManagedWrenManifest, resolveManagedWrenRuntime } from "../server/managed-wren-runtime.js";
import { ManagedWrenRuntimeError, cleanupManagedWrenGenerations, managedWrenClosureDigest, managedWrenReadinessFailure, managedWrenTreeDigest, manifestDigest, provisionManagedWrenRuntime, readManagedWrenManifest, resolveManagedWrenRuntime } from "../server/managed-wren-runtime.js";
import { RuntimeHost } from "../server/runtime-host/local.js";
import { runtimeNotReady } from "../server/runtime-host/policy.js";
const roots: string[] = [];
const digest = (value: string | Uint8Array) => createHash("sha256").update(value).digest("hex");
@@ -124,6 +126,42 @@ describe("managed Wren runtime", () => {
}
});
it("rejects every staged attestation placeholder in an approved manifest", () => {
const value = fixture(); const manifestPath = path.join(value.packageRoot, "managed-wren", "manifest.json");
for (const field of ["pythonTreeSha256", "packageTreeSha256", "sitePackagesTreeSha256", "closureSha256"] as const) {
const changed = JSON.parse(JSON.stringify(value.manifest)); changed.runtime[field] = "staged"; writeFileSync(manifestPath, JSON.stringify(changed));
try { readManagedWrenManifest(value.packageRoot); throw new Error("approved staged digest was accepted"); } catch (error) { expect(error).toMatchObject({ code: "codex_wren_manifest_invalid" }); }
}
});
it("keeps production RuntimeHost composition resolve-only across local, Codex, and Claude probes", async () => {
const value = provisionFixture(); rmSync(value.runtimeRoot, { recursive: true, force: true });
const fetch = vi.fn(); vi.stubGlobal("fetch", fetch);
const localAvailable = vi.fn(() => true);
const host = new RuntimeHost({
selected: "local",
deployment: "development",
localAvailable,
vendorProbes: {
"codex-app-server": async () => {
const code = managedWrenReadinessFailure({ packageRoot: value.packageRoot, runtimeRoot: value.runtimeRoot });
return { readiness: runtimeNotReady("codex-app-server", "unprovisioned", code ?? "codex_app_server_unprovisioned"), diagnostic: { phase: "provisioning" as const } };
},
},
});
await expect(host.probe()).resolves.toMatchObject({
selectedReadiness: { state: "ready" },
backends: {
"codex-app-server": { state: "unprovisioned", code: "codex_wren_runtime_unprovisioned" },
"claude-sandbox-runtime": { state: "unprovisioned", code: "claude_sandbox_runtime_unprovisioned" },
},
});
expect(localAvailable).toHaveBeenCalledTimes(1); expect(fetch).not.toHaveBeenCalled(); expect(existsSync(value.runtimeRoot)).toBe(false);
const productionComposition = readFileSync(path.resolve("server", "bin.ts"), "utf8");
expect(productionComposition).toContain("managedWrenReadinessFailure({ packageRoot })");
expect(productionComposition).not.toContain("provisionManagedWrenRuntime");
});
it("provisions deterministic fixture assets offline and then reuses the immutable generation", async () => {
const value = provisionFixture(); value.installFetch();
const first = await provisionManagedWrenRuntime({ packageRoot: value.packageRoot, runtimeRoot: value.runtimeRoot });