@mikeargento/bitgraph 1.1.1 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/dist/__tests__/audit-memory-ingest.test.js +15 -0
  2. package/dist/__tests__/audit-memory-ingest.test.js.map +1 -1
  3. package/dist/__tests__/fuse-placement.test.d.ts +2 -0
  4. package/dist/__tests__/fuse-placement.test.d.ts.map +1 -0
  5. package/dist/__tests__/fuse-placement.test.js +31 -0
  6. package/dist/__tests__/fuse-placement.test.js.map +1 -0
  7. package/dist/__tests__/fuse-roundtrip.test.d.ts +2 -0
  8. package/dist/__tests__/fuse-roundtrip.test.d.ts.map +1 -0
  9. package/dist/__tests__/fuse-roundtrip.test.js +172 -0
  10. package/dist/__tests__/fuse-roundtrip.test.js.map +1 -0
  11. package/dist/__tests__/fuse-sdk.test.d.ts +2 -0
  12. package/dist/__tests__/fuse-sdk.test.d.ts.map +1 -0
  13. package/dist/__tests__/fuse-sdk.test.js +117 -0
  14. package/dist/__tests__/fuse-sdk.test.js.map +1 -0
  15. package/dist/__tests__/fuse-vectors.test.d.ts +2 -0
  16. package/dist/__tests__/fuse-vectors.test.d.ts.map +1 -0
  17. package/dist/__tests__/fuse-vectors.test.js +175 -0
  18. package/dist/__tests__/fuse-vectors.test.js.map +1 -0
  19. package/dist/__tests__/fuse-verify.test.d.ts +2 -0
  20. package/dist/__tests__/fuse-verify.test.d.ts.map +1 -0
  21. package/dist/__tests__/fuse-verify.test.js +250 -0
  22. package/dist/__tests__/fuse-verify.test.js.map +1 -0
  23. package/dist/fuse-cli.d.ts +3 -0
  24. package/dist/fuse-cli.d.ts.map +1 -0
  25. package/dist/fuse-cli.js +210 -0
  26. package/dist/fuse-cli.js.map +1 -0
  27. package/dist/fuse.d.ts +92 -0
  28. package/dist/fuse.d.ts.map +1 -0
  29. package/dist/fuse.js +304 -0
  30. package/dist/fuse.js.map +1 -0
  31. package/dist/index.d.ts +2 -0
  32. package/dist/index.d.ts.map +1 -1
  33. package/dist/index.js +4 -0
  34. package/dist/index.js.map +1 -1
  35. package/package.json +12 -7
  36. package/src/__tests__/audit-memory-ingest.test.ts +16 -0
  37. package/src/__tests__/fuse-placement.test.ts +32 -0
  38. package/src/__tests__/fuse-roundtrip.test.ts +174 -0
  39. package/src/__tests__/fuse-sdk.test.ts +142 -0
  40. package/src/__tests__/fuse-vectors.test.ts +218 -0
  41. package/src/__tests__/fuse-verify.test.ts +278 -0
  42. package/src/fuse-cli.ts +187 -0
  43. package/src/fuse.ts +390 -0
  44. package/src/index.ts +6 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fuse.js","sourceRoot":"","sources":["../src/fuse.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -15,6 +15,8 @@ export { computeProofHash } from "@mikeargento/bitgraph-verify";
15
15
  export { canonicalize, canonicalizeToString, constantTimeEqual } from "@mikeargento/bitgraph-verify";
16
16
  export type { HostCapabilities } from "./host.js";
17
17
  export { Constructor } from "./constructor.js";
18
+ export { fuse, builderFor, FuseError, digestFromBase64, placementForBytes, fusedNamesFor } from "./fuse.js";
19
+ export type { FuseBuilder, BuilderInput, FuseOptions, FuseResult, FuseTransport, FuseErrorCode } from "./fuse.js";
18
20
  export { parsePolicy, hashPolicy, createPolicyBinding, validateAction, } from "./policy.js";
19
21
  export type { PolicyDocument, PolicyRules, ActionValidationResult, } from "./policy.js";
20
22
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA;;;;;;;;;GASG;AAGH,YAAY,EACV,aAAa,EACb,cAAc,EACd,kBAAkB,EAClB,UAAU,EACV,eAAe,EACf,WAAW,EACX,aAAa,EACb,cAAc,EACd,aAAa,EACb,oBAAoB,EACpB,qBAAqB,EACrB,cAAc,GACf,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,MAAM,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAC3E,YAAY,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,EAAE,YAAY,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAGrG,YAAY,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAGlD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAG/C,OAAO,EACL,WAAW,EACX,UAAU,EACV,mBAAmB,EACnB,cAAc,GACf,MAAM,aAAa,CAAC;AACrB,YAAY,EACV,cAAc,EACd,WAAW,EACX,sBAAsB,GACvB,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA;;;;;;;;;GASG;AAGH,YAAY,EACV,aAAa,EACb,cAAc,EACd,kBAAkB,EAClB,UAAU,EACV,eAAe,EACf,WAAW,EACX,aAAa,EACb,cAAc,EACd,aAAa,EACb,oBAAoB,EACpB,qBAAqB,EACrB,cAAc,GACf,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,MAAM,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAC3E,YAAY,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,EAAE,YAAY,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAGrG,YAAY,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAGlD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAK/C,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC5G,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAGlH,OAAO,EACL,WAAW,EACX,UAAU,EACV,mBAAmB,EACnB,cAAc,GACf,MAAM,aAAa,CAAC;AACrB,YAAY,EACV,cAAc,EACd,WAAW,EACX,sBAAsB,GACvB,MAAM,aAAa,CAAC"}
package/dist/index.js CHANGED
@@ -4,6 +4,10 @@ export { computeProofHash } from "@mikeargento/bitgraph-verify";
4
4
  export { canonicalize, canonicalizeToString, constantTimeEqual } from "@mikeargento/bitgraph-verify";
5
5
  // Constructor (write path)
6
6
  export { Constructor } from "./constructor.js";
7
+ // The producer profile over the primitive (working name Fuse): allocate a
8
+ // slot, write a commitment to it into the artifact, hash, commit under the
9
+ // same slot. The resulting proof is ordinary bitgraph/1.
10
+ export { fuse, builderFor, FuseError, digestFromBase64, placementForBytes, fusedNamesFor } from "./fuse.js";
7
11
  // Policy parsing, hashing, and validation
8
12
  export { parsePolicy, hashPolicy, createPolicyBinding, validateAction, } from "./policy.js";
9
13
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,gEAAgE;AA4BhE,OAAO,EAAE,MAAM,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAE3E,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,EAAE,YAAY,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAKrG,2BAA2B;AAC3B,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C,0CAA0C;AAC1C,OAAO,EACL,WAAW,EACX,UAAU,EACV,mBAAmB,EACnB,cAAc,GACf,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,gEAAgE;AA4BhE,OAAO,EAAE,MAAM,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAE3E,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,EAAE,YAAY,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAKrG,2BAA2B;AAC3B,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C,0EAA0E;AAC1E,2EAA2E;AAC3E,yDAAyD;AACzD,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAG5G,0CAA0C;AAC1C,OAAO,EACL,WAAW,EACX,UAAU,EACV,mBAAmB,EACnB,cAAc,GACf,MAAM,aAAa,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mikeargento/bitgraph",
3
- "version": "1.1.1",
3
+ "version": "1.3.0",
4
4
  "license": "SEE LICENSE IN LICENSE",
5
5
  "description": "Portable cryptographic proof of construction for digital artifacts.",
6
6
  "type": "module",
@@ -17,21 +17,23 @@
17
17
  "src",
18
18
  "README.md",
19
19
  "LICENSE",
20
- "NOTICE"
20
+ "NOTICE",
21
+ "!src/__tests__/fuse-fixtures"
21
22
  ],
22
23
  "scripts": {
23
24
  "build": "npm run build --workspace=packages/verify && npm run build --workspace=packages/audit && npm run build --workspace=packages/player && npm run build --workspace=packages/mcp && tsc",
24
25
  "typecheck": "npm run build --workspace=packages/verify && npm run build --workspace=packages/audit && npm run typecheck --workspace=packages/mcp && tsc --noEmit",
25
- "test:core": "npm run build && node --test dist/__tests__/canonical.test.js dist/__tests__/constructor.test.js dist/__tests__/verifier.test.js dist/__tests__/proof-integrity.test.js dist/__tests__/audit-ingest.test.js dist/__tests__/audit-tiers.test.js dist/__tests__/audit-reconstruct.test.js dist/__tests__/audit-anomalies.test.js dist/__tests__/audit-anchors.test.js dist/__tests__/audit-witness.test.js dist/__tests__/audit-temporal.test.js dist/__tests__/audit-attestation.test.js dist/__tests__/audit-report.test.js dist/__tests__/audit-cli.test.js dist/__tests__/audit-property.test.js dist/__tests__/audit-real-fixtures.test.js dist/__tests__/audit-dependencies.test.js dist/__tests__/audit-bench-smoke.test.js dist/__tests__/audit-roundtrip.test.js dist/__tests__/audit-real-live.test.js dist/__tests__/chain-hash-anchor.test.js dist/__tests__/audit-boundary.test.js dist/__tests__/audit-witness-real.test.js dist/__tests__/audit-memory-ingest.test.js",
26
- "test": "npm run test:core"
26
+ "test:core": "npm run build && node --test dist/__tests__/canonical.test.js dist/__tests__/constructor.test.js dist/__tests__/verifier.test.js dist/__tests__/proof-integrity.test.js dist/__tests__/audit-ingest.test.js dist/__tests__/audit-tiers.test.js dist/__tests__/audit-reconstruct.test.js dist/__tests__/audit-anomalies.test.js dist/__tests__/audit-anchors.test.js dist/__tests__/audit-witness.test.js dist/__tests__/audit-temporal.test.js dist/__tests__/audit-attestation.test.js dist/__tests__/audit-report.test.js dist/__tests__/audit-cli.test.js dist/__tests__/audit-property.test.js dist/__tests__/audit-real-fixtures.test.js dist/__tests__/audit-dependencies.test.js dist/__tests__/audit-bench-smoke.test.js dist/__tests__/audit-roundtrip.test.js dist/__tests__/audit-real-live.test.js dist/__tests__/chain-hash-anchor.test.js dist/__tests__/audit-boundary.test.js dist/__tests__/audit-witness-real.test.js dist/__tests__/audit-memory-ingest.test.js dist/__tests__/fuse-vectors.test.js dist/__tests__/fuse-roundtrip.test.js dist/__tests__/fuse-verify.test.js dist/__tests__/fuse-sdk.test.js dist/__tests__/fuse-placement.test.js",
27
+ "test": "npm run test:core",
28
+ "prepack": "npm run build"
27
29
  },
28
30
  "dependencies": {
29
- "@mikeargento/bitgraph-verify": "^1.0.0",
31
+ "@mikeargento/bitgraph-verify": "^1.4.0",
30
32
  "@noble/ed25519": "^2.1.0",
31
33
  "@noble/hashes": "^1.4.0"
32
34
  },
33
35
  "devDependencies": {
34
- "@mikeargento/bitgraph-audit": "^0.1.0",
36
+ "@mikeargento/bitgraph-audit": "^0.4.0",
35
37
  "@types/node": "^20.0.0",
36
38
  "typescript": "^5.4.0"
37
39
  },
@@ -41,5 +43,8 @@
41
43
  "packages/mcp",
42
44
  "packages/player",
43
45
  "packages/titles"
44
- ]
46
+ ],
47
+ "bin": {
48
+ "bitgraph-fuse": "./dist/fuse-cli.js"
49
+ }
45
50
  }
@@ -138,3 +138,19 @@ describe("audit: ingestEntries mirrors ingestBundle over the same files", () =>
138
138
  assert.ok(viaMemory.verification.verified > 0);
139
139
  });
140
140
  });
141
+
142
+ describe("audit: a bitgraph-fuse/1 Frame is a proof carrier", () => {
143
+ it("ingestEntries reads the nested proof out of a Frame and does not index the Frame as an artifact", async () => {
144
+ const fix = fileURLToPath(new URL("../../src/__tests__/fuse-fixtures/", import.meta.url)); // compiled tests run from dist/__tests__/
145
+ const frame = new Uint8Array(await readFile(join(fix, "trailer.bitgraph-fuse.json")));
146
+ const fused = new Uint8Array(await readFile(join(fix, "fused-trailer.bin")));
147
+ const ingest = await ingestEntries([
148
+ { path: "photo.bitgraph-fuse.json", open: () => frame },
149
+ { path: "photo.bin", open: () => fused },
150
+ ]);
151
+ assert.equal(ingest.proofs.length, 1);
152
+ assert.equal((ingest.proofs[0]!.proof.attribution as { name?: string } | undefined)?.name, "bitgraph-fuse/1");
153
+ assert.ok(!ingest.artifacts.some((a) => a.paths.includes("photo.bitgraph-fuse.json")), "the Frame is not an artifact candidate");
154
+ assert.ok(ingest.artifacts.some((a) => a.paths.includes("photo.bin") && a.matchedProofHashes.length === 1), "the fused bytes match the nested proof");
155
+ });
156
+ });
@@ -0,0 +1,32 @@
1
+ // Copyright (c) Mike Argento. All rights reserved. See LICENSE.
2
+ import { describe, it } from "node:test";
3
+ import * as assert from "node:assert/strict";
4
+ import { placementForBytes, fusedNamesFor } from "../fuse.js";
5
+
6
+ const bytes = (...b: number[]) => new Uint8Array([...b, ...new Array(24).fill(0)]);
7
+
8
+ describe("placementForBytes: decided from the bytes, never the name", () => {
9
+ it("formats that ignore trailing data take trailer/1", () => {
10
+ assert.equal(placementForBytes(bytes(0xff, 0xd8, 0xff, 0xe0)), "trailer/1", "JPEG");
11
+ assert.equal(placementForBytes(bytes(0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a)), "trailer/1", "PNG");
12
+ assert.equal(placementForBytes(bytes(0x47, 0x49, 0x46, 0x38, 0x39, 0x61)), "trailer/1", "GIF");
13
+ assert.equal(placementForBytes(bytes(0x49, 0x49, 0x2a, 0x00)), "trailer/1", "TIFF, DNG, CR2");
14
+ assert.equal(placementForBytes(bytes(0x4d, 0x4d, 0x00, 0x2a)), "trailer/1", "TIFF big-endian, NEF");
15
+ assert.equal(placementForBytes(bytes(0x42, 0x4d)), "trailer/1", "BMP");
16
+ assert.equal(placementForBytes(bytes(0x52, 0x49, 0x46, 0x46, 0, 0, 0, 0, 0x57, 0x45, 0x42, 0x50)), "trailer/1", "RIFF WebP");
17
+ });
18
+ it("everything else takes container/1", () => {
19
+ assert.equal(placementForBytes(new TextEncoder().encode("%PDF-1.7\n")), "container/1", "PDF");
20
+ assert.equal(placementForBytes(bytes(0x50, 0x4b, 0x03, 0x04)), "container/1", "ZIP, Office, EPUB");
21
+ assert.equal(placementForBytes(bytes(0, 0, 0, 0x18, 0x66, 0x74, 0x79, 0x70)), "container/1", "ISO base media");
22
+ assert.equal(placementForBytes(bytes(0x1a, 0x45, 0xdf, 0xa3)), "container/1", "Matroska");
23
+ assert.equal(placementForBytes(bytes(0x49, 0x44, 0x33)), "container/1", "MP3");
24
+ assert.equal(placementForBytes(new TextEncoder().encode("# markdown\n")), "container/1", "text");
25
+ assert.equal(placementForBytes(new Uint8Array(0)), "container/1", "empty");
26
+ });
27
+ it("names keep the extension for trailers and use .tar for containers", () => {
28
+ assert.deepEqual(fusedNamesFor("IMG_0001.jpg", "trailer/1"), { fusedName: "IMG_0001.fused.jpg", frameName: "IMG_0001.jpg.bitgraph-fuse.json" });
29
+ assert.deepEqual(fusedNamesFor("contract.pdf", "container/1"), { fusedName: "contract.fused.tar", frameName: "contract.pdf.bitgraph-fuse.json" });
30
+ assert.deepEqual(fusedNamesFor("README", "container/1"), { fusedName: "README.fused.tar", frameName: "README.bitgraph-fuse.json" });
31
+ });
32
+ });
@@ -0,0 +1,174 @@
1
+ // Copyright (c) Mike Argento. All rights reserved. See LICENSE.
2
+
3
+ /**
4
+ * BitGraph Fuse: reconstruction round trips (spec 15.3). A placement enters
5
+ * the registry only with this test passing: original plus proof rebuilds
6
+ * bytes whose hash equals the artifact digest, from fixed vectors.
7
+ */
8
+
9
+ import { describe, test } from "node:test";
10
+ import * as assert from "node:assert/strict";
11
+ import { readFileSync } from "node:fs";
12
+ import { fileURLToPath } from "node:url";
13
+ import { sha256 } from "@noble/hashes/sha256";
14
+ import { PLACEMENTS, getPlacement, computeSlotCommitment, bytesToBase64, buildFrame, parseFrame, readFrameMarker, readFuseAttribution, fuseAttribution } from "@mikeargento/bitgraph-verify";
15
+ import type { BitGraphProof } from "@mikeargento/bitgraph-verify";
16
+
17
+ const FIX = fileURLToPath(new URL("../../src/__tests__/fuse-fixtures/", import.meta.url));
18
+ const bytes = (name: string) => new Uint8Array(readFileSync(FIX + name));
19
+ const proofOf = (name: string) => JSON.parse(readFileSync(FIX + name, "utf8")) as BitGraphProof;
20
+
21
+ describe("registry", () => {
22
+ test("fixed order and ids", () => {
23
+ assert.deepEqual(PLACEMENTS.map((p) => p.id), ["trailer/1", "container/1", "produced/1"]);
24
+ assert.deepEqual(PLACEMENTS.map((p) => p.byteExact), [true, true, false]);
25
+ assert.equal(getPlacement("xmp/9"), undefined);
26
+ assert.equal(getPlacement(""), undefined);
27
+ });
28
+ });
29
+
30
+ describe("trailer/1", () => {
31
+ const p = getPlacement("trailer/1")!;
32
+ test("original + proof rebuilds the committed bytes", () => {
33
+ const proof = proofOf("trailer.proof.json");
34
+ const rebuilt = p.build({ original: bytes("original.txt"), commitment: computeSlotCommitment(proof.slotAllocation!) });
35
+ assert.deepEqual(rebuilt, bytes("fused-trailer.bin"));
36
+ assert.equal(bytesToBase64(sha256(rebuilt)), proof.artifact.digestB64);
37
+ });
38
+ test("locate returns the commitment and the exact original prefix", () => {
39
+ const proof = proofOf("trailer.proof.json");
40
+ const l = p.locate(bytes("fused-trailer.bin"))!;
41
+ assert.deepEqual(l.commitment, computeSlotCommitment(proof.slotAllocation!));
42
+ assert.deepEqual(l.originalBytes, bytes("original.txt"));
43
+ assert.equal(l.originDigest, undefined, "trailer/1 writes no origin digest");
44
+ });
45
+ test("locate refuses short input, wrong magic, non-zero reserved bytes", () => {
46
+ assert.equal(p.locate(new Uint8Array(47)), null);
47
+ const f = bytes("fused-trailer.bin");
48
+ const magic = f.slice(); magic[magic.length - 48] = 0x58;
49
+ assert.equal(p.locate(magic), null);
50
+ const reserved = f.slice(); reserved[reserved.length - 40] = 1;
51
+ assert.equal(p.locate(reserved), null);
52
+ assert.equal(p.locate(bytes("original.txt")), null, "an unfused file has no trailer");
53
+ });
54
+ test("build refuses a bad commitment length and a missing original", () => {
55
+ assert.throws(() => p.build({ commitment: new Uint8Array(32) }), /original/);
56
+ assert.throws(() => p.build({ original: new Uint8Array(1), commitment: new Uint8Array(31) }), /32 bytes/);
57
+ });
58
+ });
59
+
60
+ describe("container/1", () => {
61
+ const p = getPlacement("container/1")!;
62
+ test("original + proof rebuilds the committed archive byte for byte, twice", () => {
63
+ const proof = proofOf("container.proof.json");
64
+ const c = computeSlotCommitment(proof.slotAllocation!);
65
+ const a = p.build({ original: bytes("image.png"), commitment: c });
66
+ const b = p.build({ original: bytes("image.png"), commitment: c });
67
+ assert.deepEqual(a, b, "deterministic");
68
+ assert.deepEqual(a, bytes("fused-container.tar"));
69
+ assert.equal(bytesToBase64(sha256(a)), proof.artifact.digestB64);
70
+ });
71
+ test("locate returns commitment, origin digest and the original bytes", () => {
72
+ const proof = proofOf("container.proof.json");
73
+ const l = p.locate(bytes("fused-container.tar"))!;
74
+ assert.deepEqual(l.commitment, computeSlotCommitment(proof.slotAllocation!));
75
+ assert.deepEqual(l.originDigest, sha256(bytes("image.png")));
76
+ assert.deepEqual(l.originalBytes, bytes("image.png"));
77
+ });
78
+ test("locate refuses any deviation from the fixed layout", () => {
79
+ const f = bytes("fused-container.tar");
80
+ const mtime = f.slice(); mtime[136] = 0x31; // manifest header mtime
81
+ assert.equal(p.locate(mtime), null, "non-zero mtime");
82
+ const uid = f.slice(); uid[108] = 0x31;
83
+ assert.equal(p.locate(uid), null, "uid");
84
+ const truncated = f.subarray(0, f.length - 512);
85
+ assert.equal(p.locate(truncated), null, "missing end block");
86
+ const extra = new Uint8Array(f.length + 512); extra.set(f);
87
+ assert.equal(p.locate(extra), null, "extra trailing block");
88
+ // Swap entry order: rebuild with the original first is not this placement.
89
+ const swapped = f.slice(); swapped[0] = 0x78; // corrupt the manifest name
90
+ assert.equal(p.locate(swapped), null, "wrong entry name");
91
+ assert.equal(p.locate(bytes("image.png")), null, "not a tar");
92
+ assert.equal(p.locate(bytes("fused-trailer.bin")), null);
93
+ });
94
+ test("an archive with a wrong manifest origin does not locate", () => {
95
+ const proof = proofOf("container.proof.json");
96
+ const c = computeSlotCommitment(proof.slotAllocation!);
97
+ const lying = p.build({ original: bytes("image.png"), originDigest: sha256(bytes("original.txt")), commitment: c });
98
+ // build accepts a caller-supplied origin digest; locate returns what is written,
99
+ // and the verifier compares it against the marker and the original's hash.
100
+ const l = p.locate(lying)!;
101
+ assert.deepEqual(l.originDigest, sha256(bytes("original.txt")));
102
+ assert.notDeepEqual(l.originDigest, sha256(l.originalBytes!));
103
+ });
104
+ });
105
+
106
+ describe("produced/1", () => {
107
+ const p = getPlacement("produced/1")!;
108
+ test("build and locate agree, with and without an origin", () => {
109
+ for (const [name, proofName] of [["produced-origin.json", "produced-origin.proof.json"], ["produced-bare.json", "produced-bare.proof.json"]] as const) {
110
+ const proof = proofOf(proofName);
111
+ const l = p.locate(bytes(name))!;
112
+ assert.deepEqual(l.commitment, computeSlotCommitment(proof.slotAllocation!));
113
+ assert.equal(bytesToBase64(sha256(bytes(name))), proof.artifact.digestB64);
114
+ }
115
+ assert.equal(p.locate(bytes("original.txt")), null);
116
+ assert.throws(() => p.build({ original: new Uint8Array(1), commitment: new Uint8Array(32) }), /no original/);
117
+ });
118
+ });
119
+
120
+ describe("legacy files that carry a nonce line", () => {
121
+ test("a file with a 'nonce:' line and no trailer, container or payload locates nothing", () => {
122
+ // ~/BitGraph holds recordings whose bytes begin with a test label and a line
123
+ // "nonce: <hex>" (the proto pattern, minted 2026-06-27 and 2026-08-06). That
124
+ // line is content, not a commitment: every registered placement must miss.
125
+ const legacy = new TextEncoder().encode("BitGraph test subject folder-02 file-02\nnonce: e317096692576a308263bc283d66b42e\nuoJjpYb8igrEhhSlczKKTKDyw6guO2iU5iHdBRF+mPELQqBfjrO2WZYrSWyHEuKK\n");
126
+ for (const p of PLACEMENTS) assert.equal(p.locate(legacy), null, p.id);
127
+ });
128
+ });
129
+
130
+ describe("attribution and Frame", () => {
131
+ test("fused attribution carries placement in title and origin in message (standard base64)", () => {
132
+ const origin = sha256(bytes("original.txt"));
133
+ const a = fuseAttribution("trailer/1", origin);
134
+ assert.deepEqual(a, { name: "bitgraph-fuse/1", title: "trailer/1", message: bytesToBase64(origin) });
135
+ assert.deepEqual(fuseAttribution("produced/1"), { name: "bitgraph-fuse/1", title: "produced/1" });
136
+ const proof = proofOf("trailer.proof.json");
137
+ const m = readFuseAttribution(proof)!;
138
+ assert.equal(m.placement, "trailer/1");
139
+ assert.equal(m.placementSource, "attribution");
140
+ assert.equal(m.source, "attribution");
141
+ assert.deepEqual(m.originDigest, origin);
142
+ assert.equal(m.originSource, "attribution");
143
+ const bare = readFuseAttribution(proofOf("trailer-undeclared.proof.json"))!;
144
+ assert.equal(bare.originDigest, undefined);
145
+ assert.equal(bare.originSource, undefined);
146
+ assert.equal(readFuseAttribution(proofOf("recorded.proof.json")), null, "an ordinary proof has no marker");
147
+ });
148
+ test("a Frame parses regardless of outer formatting and the nested proof is untouched", () => {
149
+ const text = readFileSync(FIX + "trailer.bitgraph-fuse.json", "utf8");
150
+ const a = parseFrame(text)!;
151
+ const b = parseFrame(JSON.stringify(JSON.parse(text)))!;
152
+ assert.deepEqual(a, b);
153
+ assert.equal(a.manifest.placement, "trailer/1");
154
+ assert.deepEqual(a.proof, proofOf("trailer.proof.json"));
155
+ const marker = readFrameMarker(a);
156
+ assert.equal(marker.source, "manifest");
157
+ assert.equal(marker.placementSource, "manifest");
158
+ assert.deepEqual(marker.originDigest, sha256(bytes("original.txt")));
159
+ const undeclared = parseFrame({ type: "bitgraph-fuse/1", manifest: { artifact: { algorithm: "sha256", digest: "00".repeat(32) }, fusedFile: null }, proof: proofOf("trailer.proof.json") })!;
160
+ assert.equal(readFrameMarker(undeclared).placement, null, "a manifest may leave the placement undeclared");
161
+ assert.equal(parseFrame(proofOf("trailer.proof.json")), null, "a bare proof is not a Frame");
162
+ assert.equal(parseFrame("{not json"), null);
163
+ assert.equal(parseFrame({ type: "bitgraph-fuse/1", manifest: { placement: "trailer/1", artifact: { algorithm: "sha256", digest: "zz" }, fusedFile: null }, proof: {} }), null);
164
+ });
165
+ test("a Frame is never proof-shaped", () => {
166
+ const f = JSON.parse(readFileSync(FIX + "produced-origin.bitgraph-fuse.json", "utf8")) as Record<string, unknown>;
167
+ assert.equal(f.version, undefined);
168
+ assert.equal(f.artifact, undefined);
169
+ assert.equal(f.signer, undefined);
170
+ assert.equal(f.type, "bitgraph-fuse/1");
171
+ assert.ok(f.fusePayload, "Form C frames carry the parsed payload view");
172
+ assert.throws(() => buildFrame({ proof: proofOf("produced-origin.proof.json"), placement: "produced/1", artifactDigest: new Uint8Array(32), fusedFile: null, fusePayload: new Uint8Array([1]) }), /canonical/);
173
+ });
174
+ });
@@ -0,0 +1,142 @@
1
+ // Copyright (c) Mike Argento. All rights reserved. See LICENSE.
2
+
3
+ /**
4
+ * fuse() against a fake transport built from real fixture proofs (minted
5
+ * through the local enclave harness). Every refusal path runs.
6
+ */
7
+
8
+ import { describe, test } from "node:test";
9
+ import * as assert from "node:assert/strict";
10
+ import { readFileSync } from "node:fs";
11
+ import { fileURLToPath } from "node:url";
12
+ import { fuse, builderFor, FuseError } from "../fuse.js";
13
+ import type { BitGraphProof, SlotAllocation } from "../fuse.js";
14
+
15
+ const FIX = fileURLToPath(new URL("../../src/__tests__/fuse-fixtures/", import.meta.url));
16
+ const bytes = (name: string) => new Uint8Array(readFileSync(FIX + name));
17
+ const proofOf = (name: string) => JSON.parse(readFileSync(FIX + name, "utf8")) as BitGraphProof;
18
+
19
+ interface Call { path: string; body: unknown }
20
+
21
+ /** A transport that hands out `slot` and answers the commit with `answer`. */
22
+ function fakeTransport(slot: SlotAllocation, answer: (calls: Call[], body: unknown) => { status: number; json: unknown }, lookup?: (calls: Call[]) => { status: number; json: unknown }) {
23
+ const calls: Call[] = [];
24
+ const f: typeof fetch = async (input, init) => {
25
+ const url = String(input);
26
+ const path = url.replace(/^https?:\/\/[^/]+/, "");
27
+ const body = init?.body ? JSON.parse(String(init.body)) : undefined;
28
+ calls.push({ path, body });
29
+ const reply = (r: { status: number; json: unknown }) => new Response(JSON.stringify(r.json), { status: r.status, headers: { "Content-Type": "application/json" } });
30
+ if (path === "/api/fuse/allocate") return reply({ status: 200, json: { slotId: slot.nonceB64, slot, chainId: "bitgraph:main" } });
31
+ if (path === "/api/fuse/commit") return reply(answer(calls, body));
32
+ if (path.startsWith("/api/proofs/")) return reply(lookup ? lookup(calls) : { status: 200, json: { proofs: [] } });
33
+ return reply({ status: 404, json: { error: "no route" } });
34
+ };
35
+ return { calls, transport: { baseUrl: "https://example.test", fetch: f, recoveryAttempts: 2, recoveryDelayMs: 1 } };
36
+ }
37
+
38
+ describe("fuse(): the four beats", () => {
39
+ test("trailer/1 over an existing original: allocate, fuse, hash, fill; Frame carries the unchanged proof", async () => {
40
+ const proof = proofOf("trailer.proof.json");
41
+ const { calls, transport } = fakeTransport(proof.slotAllocation!, () => ({ status: 200, json: { proof } }));
42
+ const original = bytes("original.txt");
43
+ const r = await fuse(builderFor("trailer/1", original), { placement: "trailer/1", original, fusedFile: "photo.jpg", transport });
44
+ assert.equal(r.artifactDigestB64, proof.artifact.digestB64);
45
+ assert.deepEqual(r.proof, proof);
46
+ assert.equal(r.frame.type, "bitgraph-fuse/1");
47
+ assert.equal(r.frame.manifest.placement, "trailer/1");
48
+ assert.equal(r.frame.manifest.fusedFile, "photo.jpg");
49
+ assert.deepEqual(r.frame.proof, proof);
50
+ assert.equal(r.recovered, false);
51
+ assert.equal(r.verification.category, "FUSED_DIRECT");
52
+ assert.equal(r.fusedBytes, undefined, "byte-exact placements evaporate by default");
53
+ // The commit carried the placement and origin in the attribution, and named the slot.
54
+ const commit = calls.find((c) => c.path === "/api/fuse/commit")!.body as Record<string, unknown>;
55
+ assert.equal(commit.slotId, proof.slotAllocation!.nonceB64);
56
+ assert.deepEqual(commit.attribution, { name: "bitgraph-fuse/1", title: "trailer/1", message: r.originDigestB64 });
57
+ assert.deepEqual(commit.digests, [{ digestB64: proof.artifact.digestB64, hashAlg: "sha256" }]);
58
+ assert.equal(commit.chainId, "bitgraph:main");
59
+ // The raw nonce appears in no error and nowhere but the slot field it must ride in.
60
+ assert.ok(!JSON.stringify(commit.attribution).includes(proof.slotAllocation!.nonceB64));
61
+ });
62
+
63
+ test("produced/1 keeps its bytes and its payload view in the Frame", async () => {
64
+ const proof = proofOf("produced-origin.proof.json");
65
+ const { transport } = fakeTransport(proof.slotAllocation!, () => ({ status: 200, json: [proof] }));
66
+ const originDigest = new Uint8Array(Buffer.from(proof.attribution!.message!, "base64"));
67
+ const r = await fuse(builderFor("produced/1"), { placement: "produced/1", originDigest, transport });
68
+ assert.ok(r.fusedBytes, "Form C keeps the fused bytes");
69
+ assert.deepEqual(r.fusedBytes, bytes("produced-origin.json"));
70
+ assert.ok(r.frame.fusePayload);
71
+ assert.equal(r.frame.fusePayload!.type, "bitgraph-fuse/1");
72
+ });
73
+
74
+ test("a builder that drops the commitment is refused BEFORE any commit; the slot is left to expire", async () => {
75
+ const proof = proofOf("trailer.proof.json");
76
+ const { calls, transport } = fakeTransport(proof.slotAllocation!, () => ({ status: 200, json: { proof } }));
77
+ await assert.rejects(
78
+ fuse(() => bytes("original.txt"), { placement: "trailer/1", original: bytes("original.txt"), transport }),
79
+ (e: FuseError) => e.code === "commitment-missing",
80
+ );
81
+ assert.equal(calls.filter((c) => c.path === "/api/fuse/commit").length, 0, "no commit was attempted");
82
+ });
83
+
84
+ test("a proof under a different slot is never labelled fused", async () => {
85
+ const proof = proofOf("trailer.proof.json");
86
+ const other = proofOf("trailer-undeclared.proof.json");
87
+ const { transport } = fakeTransport(proof.slotAllocation!, () => ({ status: 200, json: { proof: other } }));
88
+ await assert.rejects(
89
+ fuse(builderFor("trailer/1", bytes("original.txt")), { placement: "trailer/1", original: bytes("original.txt"), transport }),
90
+ (e: FuseError) => e.code === "slot-mismatch",
91
+ );
92
+ });
93
+
94
+ test("409 slot-unavailable: the proof is read back by digest and matched on slotHashB64; nothing is re-allocated", async () => {
95
+ const proof = proofOf("trailer.proof.json");
96
+ const decoy = proofOf("trailer-undeclared.proof.json");
97
+ const { calls, transport } = fakeTransport(
98
+ proof.slotAllocation!,
99
+ () => ({ status: 409, json: { error: "gone", code: "slot-unavailable" } }),
100
+ () => ({ status: 200, json: { proofs: [{ proof: decoy }, { proof }] } }),
101
+ );
102
+ const r = await fuse(builderFor("trailer/1", bytes("original.txt")), { placement: "trailer/1", original: bytes("original.txt"), transport });
103
+ assert.equal(r.recovered, true);
104
+ assert.deepEqual(r.proof, proof);
105
+ assert.equal(calls.filter((c) => c.path === "/api/fuse/allocate").length, 1, "allocated exactly once");
106
+ });
107
+
108
+ test("409 with no matching proof on the ledger is reported as slot-unavailable, not retried into a new slot", async () => {
109
+ const proof = proofOf("trailer.proof.json");
110
+ const { calls, transport } = fakeTransport(proof.slotAllocation!, () => ({ status: 409, json: { error: "gone", code: "slot-unavailable" } }));
111
+ await assert.rejects(
112
+ fuse(builderFor("trailer/1", bytes("original.txt")), { placement: "trailer/1", original: bytes("original.txt"), transport }),
113
+ (e: FuseError) => e.code === "slot-unavailable" && !e.message.includes(proof.slotAllocation!.nonceB64),
114
+ );
115
+ assert.equal(calls.filter((c) => c.path === "/api/fuse/allocate").length, 1);
116
+ });
117
+
118
+ test("tee-restarting on commit: read back first, then report; a network failure after send does the same", async () => {
119
+ const proof = proofOf("trailer.proof.json");
120
+ const a = fakeTransport(proof.slotAllocation!, () => ({ status: 503, json: { error: "restarting", code: "tee-restarting" } }), () => ({ status: 200, json: { proofs: [{ proof }] } }));
121
+ const r = await fuse(builderFor("trailer/1", bytes("original.txt")), { placement: "trailer/1", original: bytes("original.txt"), transport: a.transport });
122
+ assert.equal(r.recovered, true);
123
+ const b = fakeTransport(proof.slotAllocation!, () => ({ status: 503, json: { error: "restarting", code: "tee-restarting" } }));
124
+ await assert.rejects(fuse(builderFor("trailer/1", bytes("original.txt")), { placement: "trailer/1", original: bytes("original.txt"), transport: b.transport }), (e: FuseError) => e.code === "tee-restarting");
125
+ });
126
+
127
+ test("bad inputs are refused before any request", async () => {
128
+ const proof = proofOf("trailer.proof.json");
129
+ const { calls, transport } = fakeTransport(proof.slotAllocation!, () => ({ status: 200, json: { proof } }));
130
+ await assert.rejects(fuse(builderFor("trailer/1", bytes("original.txt")), { placement: "xmp/9" as never, original: bytes("original.txt"), transport }), (e: FuseError) => e.code === "bad-placement");
131
+ await assert.rejects(fuse(builderFor("trailer/1"), { placement: "trailer/1", transport }), (e: FuseError) => e.code === "bad-input");
132
+ await assert.rejects(fuse(builderFor("produced/1"), { placement: "produced/1", original: bytes("original.txt"), transport }), (e: FuseError) => e.code === "bad-input");
133
+ assert.equal(calls.length, 0);
134
+ assert.throws(() => builderFor("nope/1" as never), (e: FuseError) => e.code === "bad-placement");
135
+ });
136
+
137
+ test("a slot off the anchored chain is refused", async () => {
138
+ const proof = proofOf("trailer.proof.json");
139
+ const { transport } = fakeTransport({ ...proof.slotAllocation!, chainId: "global" }, () => ({ status: 200, json: { proof } }));
140
+ await assert.rejects(fuse(builderFor("trailer/1", bytes("original.txt")), { placement: "trailer/1", original: bytes("original.txt"), transport }), (e: FuseError) => e.code === "allocate-failed" && /anchored chain/.test(e.message));
141
+ });
142
+ });