fix: harden runtime config snapshot publication

This commit is contained in:
2026-08-11 10:50:21 +02:00
parent 971315aa80
commit e9613767c5
5 changed files with 280 additions and 101 deletions
+11 -19
View File
@@ -306,6 +306,12 @@ export class ThtRunner {
return new Promise((resolve) => {
const env: NodeJS.ProcessEnv = { ...process.env };
delete env.THT_DATA_ROOT;
// Handoff variables are backend-owned capabilities, never inherited from an
// operator shell or forwarded request environment.
delete env.THT_RUNTIME_CONFIG_MANIFEST_SHA256;
delete env.THT_CONFIG_FD;
delete env.THT_CONFIG_MANIFEST_FD;
delete env.THT_CONFIG_MANIFEST_SHA256;
clearPrincipalEnvironment(env);
if (this.cfg.dataRoot !== undefined) env.THT_DATA_ROOT = this.cfg.dataRoot;
if (this.principal) Object.assign(env, principalEnvironment(this.principal));
@@ -321,41 +327,27 @@ export class ThtRunner {
env.THT_SSL_CA = ca;
}
let snapshotFd: number | undefined;
let canonicalFd: number | undefined;
let manifestFd: number | undefined;
let ch;
try {
snapshotFd = workspaceConfigPath && this.runtimeSnapshots.has(workspaceConfigPath)
? this.openTrustedRuntimeSnapshot(workspaceConfigPath) : undefined;
const lease = workspaceConfigPath ? this.runtimeLeases.get(workspaceConfigPath) : undefined;
// Registry leases retain the verified config bytes in fd 3 and the separately
// published manifest in fd 4. The argv remains the canonical -c pathname for
// diagnostics/compatibility; the harness never trusts that pathname for bytes.
canonicalFd = snapshotFd === undefined && lease
? openSync(lease.path, fsConstants.O_RDONLY | fsConstants.O_NOFOLLOW) : undefined;
manifestFd = lease
? openSync(lease.manifestPath, fsConstants.O_RDONLY | fsConstants.O_NOFOLLOW) : undefined;
if (lease) {
env.THT_CONFIG_FD = "3";
env.THT_CONFIG_MANIFEST_FD = "4";
env.THT_CONFIG_MANIFEST_SHA256 = lease.manifestSha256;
}
const handoffFd = snapshotFd ?? canonicalFd;
// Runtime leases use the canonical path plus an authenticated manifest digest.
// FD 3/4 remain reserved for the maintenance writer/root ABI.
if (lease) env.THT_RUNTIME_CONFIG_MANIFEST_SHA256 = lease.manifestSha256;
ch = spawn(
this.cfg.thtBin,
snapshotFd === undefined ? this.buildArgv(args, workspaceConfigPath) : [...args, "-c", "/dev/fd/3"],
{
cwd: this.cfg.harnessDir,
env,
...(handoffFd === undefined ? {} : {
stdio: ["ignore", "pipe", "pipe", handoffFd, ...(manifestFd === undefined ? [] : [manifestFd])],
...(snapshotFd === undefined ? {} : {
stdio: ["ignore", "pipe", "pipe", snapshotFd],
}),
},
);
} finally {
if (snapshotFd !== undefined) closeSync(snapshotFd);
if (canonicalFd !== undefined) closeSync(canonicalFd);
if (manifestFd !== undefined) closeSync(manifestFd);
}
let stdout = "";
let stderr = "";