fix(continuity): hash exact remote receipt bytes
This commit is contained in:
parent
6a05fe6ba2
commit
e2887513b2
3 changed files with 18 additions and 8 deletions
|
|
@ -30,8 +30,8 @@
|
|||
"any failed gate leaves the development lane unfinished"
|
||||
],
|
||||
"source_sha256": {
|
||||
"finalizer": "a1f51515cc3c175f83a487f499ddd26ec13aec17d063d4416efe714780a02517",
|
||||
"tests": "39e70be546c54c1e315bd5d8447947b79fb1a0b67416cc2acd0f0a7027075bd0"
|
||||
"finalizer": "7216ec32244d4b5c6956908b8f72a6c3cd207cddcc4f527ca90272e9de1a672d",
|
||||
"tests": "9e9297d2ec0b72aadd54c0781d537d986afd8d384ef739b1aac9c1714dfb2f57"
|
||||
},
|
||||
"runtime_sha256": {
|
||||
"bootstrap": "cbf5be03e5156a11f3ae11d0baf2f9daa2c8b4e58c8a405de22bcadff024c282",
|
||||
|
|
@ -39,7 +39,7 @@
|
|||
"publish_policy": "10bc53c439479c67f5b59685a29e221e0db2baab48ceb26c8369ca75c1427330"
|
||||
},
|
||||
"verification": {
|
||||
"finalizer_node_tests": "PASS_100_9_OF_9",
|
||||
"finalizer_node_tests": "PASS_100_10_OF_10",
|
||||
"continuity_guard_self_test": "PASS_100",
|
||||
"source_and_runtime_syntax": "PASS_100",
|
||||
"environment_audit": {
|
||||
|
|
|
|||
|
|
@ -138,18 +138,23 @@ export function isJsonRecordName(name) {
|
|||
}
|
||||
|
||||
function run(file, args, options = {}) {
|
||||
return execFileSync(file, args, {
|
||||
const output = execFileSync(file, args, {
|
||||
cwd: options.cwd,
|
||||
encoding: "utf8",
|
||||
stdio: options.stdio || ["ignore", "pipe", "pipe"],
|
||||
maxBuffer: 16 * 1024 * 1024,
|
||||
}).trim();
|
||||
});
|
||||
return options.trim === false ? output : output.trim();
|
||||
}
|
||||
|
||||
function git(worktree, args) {
|
||||
return run("/usr/bin/git", ["-C", worktree, ...args]);
|
||||
}
|
||||
|
||||
function gitRaw(worktree, args) {
|
||||
return run("/usr/bin/git", ["-C", worktree, ...args], { trim: false });
|
||||
}
|
||||
|
||||
function guard(guardScript, args) {
|
||||
const output = run(process.execPath, [guardScript, ...args]);
|
||||
return output ? JSON.parse(output) : null;
|
||||
|
|
@ -159,7 +164,7 @@ function readJson(filePath) {
|
|||
return JSON.parse(fs.readFileSync(filePath, "utf8"));
|
||||
}
|
||||
|
||||
function sha256(value) {
|
||||
export function sha256(value) {
|
||||
return crypto.createHash("sha256").update(value).digest("hex");
|
||||
}
|
||||
|
||||
|
|
@ -214,7 +219,7 @@ function verifyWorktree(worktree, receipts) {
|
|||
const branch = normalizeBranch(git(root, ["branch", "--show-current"]));
|
||||
const receiptEvidence = receipts.map((receipt) => {
|
||||
const relative = normalizeReceipt(receipt);
|
||||
const content = git(root, ["show", `HEAD:${relative}`]);
|
||||
const content = gitRaw(root, ["show", `HEAD:${relative}`]);
|
||||
if (!content) throw new Error(`RECEIPT_NOT_COMMITTED:${relative}`);
|
||||
return {
|
||||
path: relative,
|
||||
|
|
@ -321,7 +326,7 @@ function pushAndReadBack(worktree, repository, branch, head, receipts) {
|
|||
if (cloneHead !== head) throw new Error(`FRESH_CLONE_HEAD_MISMATCH:${cloneHead}`);
|
||||
git(clone, ["fsck", "--full"]);
|
||||
for (const receipt of receipts) {
|
||||
const remoteContent = git(clone, ["show", `HEAD:${receipt.path}`]);
|
||||
const remoteContent = gitRaw(clone, ["show", `HEAD:${receipt.path}`]);
|
||||
if (sha256(Buffer.from(remoteContent)) !== receipt.sha256) {
|
||||
throw new Error(`REMOTE_RECEIPT_MISMATCH:${receipt.path}`);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import {
|
|||
parseArgs,
|
||||
safeCacheRelative,
|
||||
selfTest,
|
||||
sha256,
|
||||
} from "./finalize-development.mjs";
|
||||
|
||||
test("the finalizer accepts only the registered Fifth Domain code channel", () => {
|
||||
|
|
@ -83,3 +84,7 @@ test("macOS AppleDouble sidecars are never parsed as JSON records", () => {
|
|||
assert.equal(isJsonRecordName("._lease.json"), false);
|
||||
assert.equal(isJsonRecordName("lease.txt"), false);
|
||||
});
|
||||
|
||||
test("receipt hashes preserve exact trailing bytes", () => {
|
||||
assert.notEqual(sha256(Buffer.from("{}")), sha256(Buffer.from("{}\n")));
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue