@mikeargento/bitgraph-player 0.3.0 → 0.4.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.
- package/README.md +40 -0
- package/SPEC.md +5 -2
- package/dist/__tests__/check.test.d.ts +2 -0
- package/dist/__tests__/check.test.d.ts.map +1 -0
- package/dist/__tests__/check.test.js +358 -0
- package/dist/__tests__/check.test.js.map +1 -0
- package/dist/check.d.ts +156 -0
- package/dist/check.d.ts.map +1 -0
- package/dist/check.js +640 -0
- package/dist/check.js.map +1 -0
- package/dist/cli.js +84 -15
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/verdict.d.ts +1 -1
- package/dist/verdict.js +1 -1
- package/dist-web/verify.html +159 -0
- package/package.json +8 -3
- package/src/__tests__/check.test.ts +417 -0
- package/src/__tests__/fixtures/export-random-043/ethereum-anchors/anchor-after-witness.json +6 -0
- package/src/__tests__/fixtures/export-random-043/ethereum-anchors/anchor-after.json +43 -0
- package/src/__tests__/fixtures/export-random-043/ethereum-anchors/anchor-before-witness.json +6 -0
- package/src/__tests__/fixtures/export-random-043/ethereum-anchors/anchor-before.json +47 -0
- package/src/__tests__/fixtures/export-random-043/proof.json +38 -0
- package/src/__tests__/fixtures/export-random-043/random-043.txt +1 -0
- package/src/check.ts +873 -0
- package/src/cli.ts +82 -16
- package/src/index.ts +3 -0
- package/src/verdict.ts +1 -1
package/README.md
CHANGED
|
@@ -25,6 +25,33 @@ folders the BitGraph Folder writes). Exit codes: `0` TRUE, `1` FALSE,
|
|
|
25
25
|
`2` UNDETERMINED, `3` error. `--out file` writes the verdict to a file;
|
|
26
26
|
`--summary` prints a bundle reconnaissance to stderr.
|
|
27
27
|
|
|
28
|
+
## Check a bundle
|
|
29
|
+
|
|
30
|
+
bitgraph-play check "BitGraph (photo.jpg)/"
|
|
31
|
+
bitgraph-play check proof.json photo.jpg --json
|
|
32
|
+
|
|
33
|
+
No rule needed. `check` reads an export (a folder or archive, or a
|
|
34
|
+
proof.json beside the file it records) and says, offline, what the bundle
|
|
35
|
+
establishes about each recording in it: that the file in hand hashes to
|
|
36
|
+
the recorded digest, that the Ed25519 signature and slot binding verify,
|
|
37
|
+
that the AWS Nitro attestation validates to the AWS root and binds this
|
|
38
|
+
exact proof, that the attested PCR0 is a published BitGraph enclave
|
|
39
|
+
measurement, and, from block headers in the bundle, which Ethereum blocks
|
|
40
|
+
the recording sits between. Every line is TRUE, FALSE, or UNDETERMINED:
|
|
41
|
+
FALSE only when evidence in hand contradicts the recording (an edited
|
|
42
|
+
signature, a block header that does not hash to its anchor), UNDETERMINED
|
|
43
|
+
when the evidence does not decide (the file is not in the bundle, a
|
|
44
|
+
witness is missing). Absence is never a verdict. The report ends with what
|
|
45
|
+
no offline check can establish, stated rather than implied. `--json`
|
|
46
|
+
prints the `bitgraph-check/1` report; exit codes match evaluation.
|
|
47
|
+
|
|
48
|
+
The same check runs in a browser: `verify.html`, built from this package,
|
|
49
|
+
ships inside the BitGraph Folder, beside Recordings. Open it and choose or
|
|
50
|
+
drop a recording folder, offline, and it renders the same report from the
|
|
51
|
+
same code. It is not hosted anywhere: the site's own drop box checks a file
|
|
52
|
+
against the public ledger, and a second box that could only say
|
|
53
|
+
"self-consistent" would be two boxes with different meanings.
|
|
54
|
+
|
|
28
55
|
## Start a rule
|
|
29
56
|
|
|
30
57
|
bitgraph-play init po.pdf delivery.jpg approval.pdf --out rule.json
|
|
@@ -123,6 +150,19 @@ const verdict = buildVerdict(rule, ruleSha256Hex, resolutions, evaluation, audit
|
|
|
123
150
|
process.stdout.write(serializeVerdict(verdict));
|
|
124
151
|
```
|
|
125
152
|
|
|
153
|
+
`check` is exported the same way, in two halves that the CLI and the
|
|
154
|
+
browser page share:
|
|
155
|
+
|
|
156
|
+
```ts
|
|
157
|
+
import { ingestBundle, ingestEntries } from "@mikeargento/bitgraph-audit";
|
|
158
|
+
import { checkIngest, renderCheckText } from "@mikeargento/bitgraph-player";
|
|
159
|
+
|
|
160
|
+
const report = await checkIngest(await ingestBundle("BitGraph (photo.jpg)/"));
|
|
161
|
+
// or, from bytes already in hand (a browser drop):
|
|
162
|
+
// await checkIngest(await ingestEntries([{ path: "proof.json", open: () => bytes }]));
|
|
163
|
+
process.stdout.write(renderCheckText(report));
|
|
164
|
+
```
|
|
165
|
+
|
|
126
166
|
## License
|
|
127
167
|
|
|
128
168
|
MIT. Verification and evaluation are permissionless by design.
|
package/SPEC.md
CHANGED
|
@@ -238,9 +238,12 @@ bundle contents MUST be byte-identical.
|
|
|
238
238
|
Diagnostics go to stderr. Stdout carries verdict bytes only.
|
|
239
239
|
|
|
240
240
|
These requirements govern evaluation invocations. A command-line Player
|
|
241
|
-
MAY offer authoring conveniences (such as rule scaffolding)
|
|
241
|
+
MAY offer authoring conveniences (such as rule scaffolding) and reading
|
|
242
|
+
conveniences (such as a bundle check that reports, in the three values,
|
|
243
|
+
what a bundle establishes about the recordings it holds) as distinct
|
|
242
244
|
subcommands; those are outside this specification and MUST NOT change
|
|
243
|
-
the behavior of evaluation invocations.
|
|
245
|
+
the behavior of evaluation invocations. The reference implementation's
|
|
246
|
+
`check` subcommand uses the same exit-code mapping as evaluation.
|
|
244
247
|
|
|
245
248
|
## 9. Format 2: trustedKeys and signedBy
|
|
246
249
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/check.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
// Copyright (c) 2024-2026 Mike Argento. Licensed under the MIT License. See LICENSE.
|
|
2
|
+
/**
|
|
3
|
+
* `check` tests.
|
|
4
|
+
*
|
|
5
|
+
* The real fixture is a genuine export from the production ledger: a
|
|
6
|
+
* 685-byte random text file, its proof (real Ed25519 signature, real AWS
|
|
7
|
+
* Nitro attestation, enclave v5 measurement), both bounding anchors, and
|
|
8
|
+
* both block-header witnesses. Copied verbatim from a BitGraph Folder
|
|
9
|
+
* export; read-only here, no ledger writes, no network.
|
|
10
|
+
*
|
|
11
|
+
* The parity test is the one that matters most: the same bundle ingested
|
|
12
|
+
* from disk (the CLI's path) and from memory (the browser page's path)
|
|
13
|
+
* must produce byte-identical reports, or the two fronts have drifted.
|
|
14
|
+
*/
|
|
15
|
+
import { describe, it, before, after } from "node:test";
|
|
16
|
+
import * as assert from "node:assert/strict";
|
|
17
|
+
import { spawnSync } from "node:child_process";
|
|
18
|
+
import { cp, mkdtemp, readFile, rm, writeFile, readdir } from "node:fs/promises";
|
|
19
|
+
import { tmpdir } from "node:os";
|
|
20
|
+
import { join, relative } from "node:path";
|
|
21
|
+
import { fileURLToPath } from "node:url";
|
|
22
|
+
import { ingestBundle, ingestEntries } from "@mikeargento/bitgraph-audit";
|
|
23
|
+
import { buildCheckReport, checkIngest, renderCheckText, serializeCheckReport, KNOWN_ENCLAVE_MEASUREMENTS } from "../check.js";
|
|
24
|
+
import { PLAYER_VERSION } from "../verdict.js";
|
|
25
|
+
import { digestFor, makeAudit } from "./fixtures.js";
|
|
26
|
+
const FIXTURE = fileURLToPath(new URL("../../src/__tests__/fixtures/export-random-043", import.meta.url));
|
|
27
|
+
const CLI_PATH = fileURLToPath(new URL("../cli.js", import.meta.url));
|
|
28
|
+
async function walk(root, rel = "") {
|
|
29
|
+
const out = [];
|
|
30
|
+
const dir = rel === "" ? root : join(root, rel);
|
|
31
|
+
for (const entry of await readdir(dir, { withFileTypes: true })) {
|
|
32
|
+
const r = rel === "" ? entry.name : `${rel}/${entry.name}`;
|
|
33
|
+
if (entry.isDirectory())
|
|
34
|
+
out.push(...(await walk(root, r)));
|
|
35
|
+
else if (entry.isFile())
|
|
36
|
+
out.push(r);
|
|
37
|
+
}
|
|
38
|
+
return out;
|
|
39
|
+
}
|
|
40
|
+
async function memoryEntriesOf(root) {
|
|
41
|
+
const paths = await walk(root);
|
|
42
|
+
return paths.map((p) => ({
|
|
43
|
+
path: p,
|
|
44
|
+
open: () => readFile(join(root, ...p.split("/"))).then((b) => new Uint8Array(b)),
|
|
45
|
+
}));
|
|
46
|
+
}
|
|
47
|
+
/** Fill the audit sections makeAudit leaves empty so buildCheckReport can run over synthetic input. */
|
|
48
|
+
function complete(audit, overrides = {}) {
|
|
49
|
+
const a = audit;
|
|
50
|
+
return {
|
|
51
|
+
...audit,
|
|
52
|
+
anomalies: { anomalies: [], divergences: [], boundaryEntryPoints: [] },
|
|
53
|
+
authorities: { groups: [], anomalies: [], sharedSignersAcrossEpochs: [] },
|
|
54
|
+
anchors: { anchors: [], metadataOnlyProofHashes: [], findings: [] },
|
|
55
|
+
witnesses: { outcomes: [], findings: [] },
|
|
56
|
+
attestations: {
|
|
57
|
+
records: [],
|
|
58
|
+
findings: [],
|
|
59
|
+
counts: {
|
|
60
|
+
proofsWithDeclaredMeasurement: 0,
|
|
61
|
+
proofsWithDocument: 0,
|
|
62
|
+
documentsValidated: 0,
|
|
63
|
+
documentsFailed: 0,
|
|
64
|
+
pcr0Matches: 0,
|
|
65
|
+
pcr0Mismatches: 0,
|
|
66
|
+
userDataBound: 0,
|
|
67
|
+
userDataUnbound: 0,
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
...(a["temporal"] !== undefined ? {} : {}),
|
|
71
|
+
...overrides,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
describe("check: real export fixture (disk)", () => {
|
|
75
|
+
let report;
|
|
76
|
+
before(async () => {
|
|
77
|
+
report = await checkIngest(await ingestBundle(FIXTURE));
|
|
78
|
+
});
|
|
79
|
+
it("is TRUE end to end: file, signature, attestation, enclave, both anchors, both witnesses", () => {
|
|
80
|
+
assert.equal(report.check, "bitgraph-check/1");
|
|
81
|
+
assert.equal(report.result, "TRUE");
|
|
82
|
+
assert.equal(report.recordings.length, 1);
|
|
83
|
+
assert.equal(report.anchors.length, 2);
|
|
84
|
+
const rec = report.recordings[0];
|
|
85
|
+
assert.equal(rec.result, "TRUE");
|
|
86
|
+
assert.equal(rec.filePath, "random-043.txt");
|
|
87
|
+
assert.deepEqual(rec.lines.map((l) => [l.name, l.result]), [
|
|
88
|
+
["file", "TRUE"],
|
|
89
|
+
["signature", "TRUE"],
|
|
90
|
+
["attestation", "TRUE"],
|
|
91
|
+
["enclave", "TRUE"],
|
|
92
|
+
]);
|
|
93
|
+
for (const anchor of report.anchors) {
|
|
94
|
+
assert.equal(anchor.result, "TRUE");
|
|
95
|
+
assert.deepEqual(anchor.lines.map((l) => [l.name, l.result]), [
|
|
96
|
+
["signature", "TRUE"],
|
|
97
|
+
["witness", "TRUE"],
|
|
98
|
+
]);
|
|
99
|
+
}
|
|
100
|
+
assert.equal(report.contradictions.length, 0);
|
|
101
|
+
});
|
|
102
|
+
it("brackets the recording between the two verified block headers", () => {
|
|
103
|
+
const b = report.recordings[0].bounds;
|
|
104
|
+
assert.equal(b.status, "bracketed");
|
|
105
|
+
assert.equal(b.notBefore?.blockNumber, "25735831");
|
|
106
|
+
assert.equal(b.notAfter?.blockNumber, "25735832");
|
|
107
|
+
assert.match(b.detail, /after Ethereum block 25735831 and before block 25735832/);
|
|
108
|
+
});
|
|
109
|
+
it("orders anchors by causal position, not file name", () => {
|
|
110
|
+
assert.deepEqual(report.anchors.map((a) => a.blockNumber), ["25735831", "25735832"]);
|
|
111
|
+
assert.equal(report.anchors[0].witnessPath, "ethereum-anchors/anchor-before-witness.json");
|
|
112
|
+
});
|
|
113
|
+
it("names the excerpt gaps as notes, never as verdicts", () => {
|
|
114
|
+
assert.ok(report.notes.some((n) => /causal positions? between the earliest and latest recording/.test(n)));
|
|
115
|
+
assert.ok(report.notes.some((n) => /link(s)? to a predecessor that is not in this bundle/.test(n)));
|
|
116
|
+
assert.equal(report.contradictions.length, 0);
|
|
117
|
+
});
|
|
118
|
+
it("states what it cannot check", () => {
|
|
119
|
+
assert.ok(report.notChecked.some((n) => /canonical/.test(n)));
|
|
120
|
+
assert.ok(report.notChecked.some((n) => /ledger/.test(n)));
|
|
121
|
+
assert.equal(report.network, "none");
|
|
122
|
+
assert.equal(report.evaluator.version, PLAYER_VERSION);
|
|
123
|
+
});
|
|
124
|
+
it("recognizes the enclave v5 measurement from PINS.md", () => {
|
|
125
|
+
const enclave = report.recordings[0].lines.find((l) => l.name === "enclave");
|
|
126
|
+
assert.match(enclave.detail, /enclave v5/);
|
|
127
|
+
assert.equal(KNOWN_ENCLAVE_MEASUREMENTS.length, 4);
|
|
128
|
+
});
|
|
129
|
+
it("serializes deterministically: no timestamps, no machine paths", async () => {
|
|
130
|
+
const again = await checkIngest(await ingestBundle(FIXTURE));
|
|
131
|
+
assert.equal(serializeCheckReport(again), serializeCheckReport(report));
|
|
132
|
+
const bytes = serializeCheckReport(report);
|
|
133
|
+
assert.ok(!bytes.includes(FIXTURE), "report must not contain the machine path");
|
|
134
|
+
assert.ok(!bytes.includes("startedAt"));
|
|
135
|
+
assert.ok(renderCheckText(report).startsWith("TRUE: this file was recorded at position 1576"));
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
describe("check: disk and memory ingest produce byte-identical reports (the no-drift guarantee)", () => {
|
|
139
|
+
it("ingestEntries over the same files equals ingestBundle over the directory", async () => {
|
|
140
|
+
const fromDisk = await checkIngest(await ingestBundle(FIXTURE));
|
|
141
|
+
const fromMemory = await checkIngest(await ingestEntries(await memoryEntriesOf(FIXTURE)));
|
|
142
|
+
assert.equal(serializeCheckReport(fromMemory), serializeCheckReport(fromDisk));
|
|
143
|
+
assert.equal(fromMemory.result, "TRUE");
|
|
144
|
+
});
|
|
145
|
+
it("memory ingest tolerates any supply order (entries are sorted by path)", async () => {
|
|
146
|
+
const entries = await memoryEntriesOf(FIXTURE);
|
|
147
|
+
const reversed = [...entries].reverse();
|
|
148
|
+
const a = await checkIngest(await ingestEntries(entries));
|
|
149
|
+
const b = await checkIngest(await ingestEntries(reversed));
|
|
150
|
+
assert.equal(serializeCheckReport(a), serializeCheckReport(b));
|
|
151
|
+
});
|
|
152
|
+
it("memory ingest accepts whole bytes, promises, and chunk streams alike", async () => {
|
|
153
|
+
const paths = await walk(FIXTURE);
|
|
154
|
+
const entries = [];
|
|
155
|
+
for (const [i, p] of paths.entries()) {
|
|
156
|
+
const bytes = new Uint8Array(await readFile(join(FIXTURE, ...p.split("/"))));
|
|
157
|
+
const open = i % 3 === 0
|
|
158
|
+
? () => bytes
|
|
159
|
+
: i % 3 === 1
|
|
160
|
+
? () => Promise.resolve(bytes)
|
|
161
|
+
: () => (async function* () {
|
|
162
|
+
const half = Math.floor(bytes.length / 2);
|
|
163
|
+
yield bytes.subarray(0, half);
|
|
164
|
+
yield bytes.subarray(half);
|
|
165
|
+
})();
|
|
166
|
+
entries.push({ path: p, open });
|
|
167
|
+
}
|
|
168
|
+
const report = await checkIngest(await ingestEntries(entries));
|
|
169
|
+
assert.equal(report.result, "TRUE");
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
describe("check: what evidence in hand contradicts, and what it merely leaves open", () => {
|
|
173
|
+
let dir;
|
|
174
|
+
before(async () => {
|
|
175
|
+
dir = await mkdtemp(join(tmpdir(), "bitgraph-check-"));
|
|
176
|
+
});
|
|
177
|
+
after(async () => {
|
|
178
|
+
await rm(dir, { recursive: true, force: true });
|
|
179
|
+
});
|
|
180
|
+
async function copyFixture(name) {
|
|
181
|
+
const dest = join(dir, name);
|
|
182
|
+
await cp(FIXTURE, dest, { recursive: true });
|
|
183
|
+
return dest;
|
|
184
|
+
}
|
|
185
|
+
it("an edited file is UNDETERMINED (not FALSE) with a note naming it: absence is not a verdict", async () => {
|
|
186
|
+
const d = await copyFixture("edited");
|
|
187
|
+
const p = join(d, "random-043.txt");
|
|
188
|
+
await writeFile(p, Buffer.concat([await readFile(p), Buffer.from("x")]));
|
|
189
|
+
const report = await checkIngest(await ingestBundle(d));
|
|
190
|
+
assert.equal(report.result, "UNDETERMINED");
|
|
191
|
+
const file = report.recordings[0].lines.find((l) => l.name === "file");
|
|
192
|
+
assert.equal(file.result, "UNDETERMINED");
|
|
193
|
+
assert.ok(report.notes.some((n) => /random-043\.txt/.test(n) && /bytes differ/.test(n)));
|
|
194
|
+
// Everything else about the recording still holds.
|
|
195
|
+
assert.equal(report.recordings[0].lines.find((l) => l.name === "signature").result, "TRUE");
|
|
196
|
+
assert.equal(report.recordings[0].lines.find((l) => l.name === "attestation").result, "TRUE");
|
|
197
|
+
});
|
|
198
|
+
it("a tampered signature is FALSE", async () => {
|
|
199
|
+
const d = await copyFixture("badsig");
|
|
200
|
+
const p = join(d, "proof.json");
|
|
201
|
+
const proof = JSON.parse(await readFile(p, "utf8"));
|
|
202
|
+
const sig = Buffer.from(proof.signer.signatureB64, "base64");
|
|
203
|
+
sig[0] = sig[0] ^ 1;
|
|
204
|
+
proof.signer.signatureB64 = sig.toString("base64");
|
|
205
|
+
await writeFile(p, JSON.stringify(proof));
|
|
206
|
+
const report = await checkIngest(await ingestBundle(d));
|
|
207
|
+
assert.equal(report.result, "FALSE");
|
|
208
|
+
assert.equal(report.recordings[0].lines.find((l) => l.name === "signature").result, "FALSE");
|
|
209
|
+
assert.match(report.summary, /^FALSE/);
|
|
210
|
+
});
|
|
211
|
+
it("a tampered block header is FALSE on that anchor, and the bound it gave is withdrawn", async () => {
|
|
212
|
+
const d = await copyFixture("badwitness");
|
|
213
|
+
const p = join(d, "ethereum-anchors", "anchor-after-witness.json");
|
|
214
|
+
const w = JSON.parse(await readFile(p, "utf8"));
|
|
215
|
+
const h = w.headerRlpHex;
|
|
216
|
+
w.headerRlpHex = h.slice(0, -2) + (h.slice(-2) === "00" ? "11" : "00");
|
|
217
|
+
await writeFile(p, JSON.stringify(w));
|
|
218
|
+
const report = await checkIngest(await ingestBundle(d));
|
|
219
|
+
assert.equal(report.result, "FALSE");
|
|
220
|
+
const after = report.anchors.find((a) => a.blockNumber === "25735832");
|
|
221
|
+
assert.equal(after.lines.find((l) => l.name === "witness").result, "FALSE");
|
|
222
|
+
assert.equal(report.recordings[0].result, "TRUE", "the recording itself is still sound");
|
|
223
|
+
assert.equal(report.recordings[0].bounds.status, "lower-bounded");
|
|
224
|
+
});
|
|
225
|
+
it("proof plus file with no anchors is TRUE and unanchored", async () => {
|
|
226
|
+
const entries = ["proof.json", "random-043.txt"].map((name) => ({
|
|
227
|
+
path: name,
|
|
228
|
+
open: () => readFile(join(FIXTURE, name)).then((b) => new Uint8Array(b)),
|
|
229
|
+
}));
|
|
230
|
+
const report = await checkIngest(await ingestEntries(entries));
|
|
231
|
+
assert.equal(report.result, "TRUE");
|
|
232
|
+
assert.equal(report.recordings[0].bounds.status, "unanchored");
|
|
233
|
+
assert.equal(report.anchors.length, 0);
|
|
234
|
+
assert.match(report.summary, /with no Ethereum bound in this bundle/);
|
|
235
|
+
});
|
|
236
|
+
it("proof alone (no file) is UNDETERMINED: signature and attestation hold, binding to bytes does not", async () => {
|
|
237
|
+
const entries = [
|
|
238
|
+
{ path: "proof.json", open: () => readFile(join(FIXTURE, "proof.json")).then((b) => new Uint8Array(b)) },
|
|
239
|
+
];
|
|
240
|
+
const report = await checkIngest(await ingestEntries(entries));
|
|
241
|
+
assert.equal(report.result, "UNDETERMINED");
|
|
242
|
+
const rec = report.recordings[0];
|
|
243
|
+
assert.equal(rec.lines.find((l) => l.name === "file").result, "UNDETERMINED");
|
|
244
|
+
assert.equal(rec.lines.find((l) => l.name === "signature").result, "TRUE");
|
|
245
|
+
assert.equal(rec.filePath, undefined);
|
|
246
|
+
});
|
|
247
|
+
it("without WebCrypto the attestation is UNDETERMINED with the reason, never FALSE", async () => {
|
|
248
|
+
const report = await checkIngest(await ingestBundle(FIXTURE), { webCryptoAvailable: false });
|
|
249
|
+
const rec = report.recordings[0];
|
|
250
|
+
assert.equal(rec.lines.find((l) => l.name === "attestation").result, "UNDETERMINED");
|
|
251
|
+
assert.match(rec.lines.find((l) => l.name === "attestation").detail, /WebCrypto/);
|
|
252
|
+
assert.equal(rec.lines.find((l) => l.name === "enclave").result, "UNDETERMINED");
|
|
253
|
+
assert.equal(report.result, "UNDETERMINED");
|
|
254
|
+
});
|
|
255
|
+
it("an empty bundle is UNDETERMINED and says so", async () => {
|
|
256
|
+
const report = await checkIngest(await ingestEntries([]));
|
|
257
|
+
assert.equal(report.result, "UNDETERMINED");
|
|
258
|
+
assert.match(report.summary, /no BitGraph proofs were found/);
|
|
259
|
+
});
|
|
260
|
+
});
|
|
261
|
+
describe("check: synthetic audit shapes", () => {
|
|
262
|
+
it("an unknown PCR0 is UNDETERMINED (outside this verifier's knowledge), never FALSE", () => {
|
|
263
|
+
const audit = complete(makeAudit({
|
|
264
|
+
proofs: [{ name: "a", digestB64: digestFor("a"), epochId: "E", counter: "5", slotCounter: "4" }],
|
|
265
|
+
partitions: [{ epochId: "E", members: ["a"] }],
|
|
266
|
+
}));
|
|
267
|
+
audit.attestations.records.push({
|
|
268
|
+
proofHash: "proofhash-a",
|
|
269
|
+
declaredMeasurementPresent: true,
|
|
270
|
+
declaredMeasurement: "ff".repeat(48),
|
|
271
|
+
documentPresent: true,
|
|
272
|
+
attestationFormat: "aws-nitro",
|
|
273
|
+
documentValidated: true,
|
|
274
|
+
checks: [],
|
|
275
|
+
attestedPcr0: "ff".repeat(48),
|
|
276
|
+
pcr0MatchesDeclared: true,
|
|
277
|
+
userDataBoundToProof: true,
|
|
278
|
+
});
|
|
279
|
+
const report = buildCheckReport(audit);
|
|
280
|
+
const rec = report.recordings[0];
|
|
281
|
+
assert.equal(rec.lines.find((l) => l.name === "attestation").result, "TRUE");
|
|
282
|
+
const enclave = rec.lines.find((l) => l.name === "enclave");
|
|
283
|
+
assert.equal(enclave.result, "UNDETERMINED");
|
|
284
|
+
assert.match(enclave.detail, /not among the BitGraph enclave measurements this verifier knows/);
|
|
285
|
+
assert.equal(report.result, "UNDETERMINED");
|
|
286
|
+
});
|
|
287
|
+
it("an attestation bound to some other proof is FALSE", () => {
|
|
288
|
+
const audit = complete(makeAudit({
|
|
289
|
+
proofs: [{ name: "a", digestB64: digestFor("a"), epochId: "E", counter: "5" }],
|
|
290
|
+
partitions: [{ epochId: "E", members: ["a"] }],
|
|
291
|
+
}));
|
|
292
|
+
audit.attestations.records.push({
|
|
293
|
+
proofHash: "proofhash-a",
|
|
294
|
+
declaredMeasurementPresent: true,
|
|
295
|
+
documentPresent: true,
|
|
296
|
+
documentValidated: true,
|
|
297
|
+
checks: [],
|
|
298
|
+
attestedPcr0: KNOWN_ENCLAVE_MEASUREMENTS[3].pcr0,
|
|
299
|
+
pcr0MatchesDeclared: true,
|
|
300
|
+
userDataBoundToProof: false,
|
|
301
|
+
});
|
|
302
|
+
const report = buildCheckReport(audit);
|
|
303
|
+
assert.equal(report.recordings[0].lines.find((l) => l.name === "attestation").result, "FALSE");
|
|
304
|
+
assert.equal(report.result, "FALSE");
|
|
305
|
+
});
|
|
306
|
+
it("structural contradictions surface as FALSE while excerpt gaps stay notes", () => {
|
|
307
|
+
const audit = complete(makeAudit({
|
|
308
|
+
proofs: [
|
|
309
|
+
{ name: "a", digestB64: digestFor("a"), epochId: "E", counter: "5" },
|
|
310
|
+
{ name: "b", digestB64: digestFor("b"), epochId: "E", counter: "5" },
|
|
311
|
+
],
|
|
312
|
+
partitions: [{ epochId: "E", members: ["a", "b"] }],
|
|
313
|
+
}));
|
|
314
|
+
audit.anomalies.anomalies.push({ code: "unexplained-counter-positions", proofHashes: [], message: "gap", details: { count: "3", ranges: [], positions: [], truncated: false } }, { code: "chain-break-missing", proofHashes: ["proofhash-a"], message: "missing pred", details: {} }, { code: "counter-collision", proofHashes: ["proofhash-a", "proofhash-b"], message: "two commits at position 5" });
|
|
315
|
+
const report = buildCheckReport(audit);
|
|
316
|
+
assert.equal(report.contradictions.length, 1);
|
|
317
|
+
assert.match(report.contradictions[0].detail, /^counter-collision/);
|
|
318
|
+
assert.ok(report.notes.some((n) => /3 causal positions/.test(n)));
|
|
319
|
+
assert.equal(report.result, "FALSE");
|
|
320
|
+
});
|
|
321
|
+
});
|
|
322
|
+
describe("check: CLI", () => {
|
|
323
|
+
it("prints the human report and exits 0 on the real fixture", () => {
|
|
324
|
+
const r = spawnSync(process.execPath, [CLI_PATH, "check", FIXTURE], { encoding: "utf8" });
|
|
325
|
+
assert.equal(r.status, 0, r.stderr);
|
|
326
|
+
assert.match(r.stdout, /^TRUE: this file was recorded at position 1576/);
|
|
327
|
+
assert.match(r.stdout, /Result: TRUE/);
|
|
328
|
+
});
|
|
329
|
+
it("--json prints the bitgraph-check/1 report", () => {
|
|
330
|
+
const r = spawnSync(process.execPath, [CLI_PATH, "check", FIXTURE, "--json"], { encoding: "utf8" });
|
|
331
|
+
assert.equal(r.status, 0, r.stderr);
|
|
332
|
+
const parsed = JSON.parse(r.stdout);
|
|
333
|
+
assert.equal(parsed.check, "bitgraph-check/1");
|
|
334
|
+
assert.equal(parsed.result, "TRUE");
|
|
335
|
+
});
|
|
336
|
+
it("accepts a list of files and ingests them in memory", () => {
|
|
337
|
+
const r = spawnSync(process.execPath, [CLI_PATH, "check", join(FIXTURE, "proof.json"), join(FIXTURE, "random-043.txt")], { encoding: "utf8" });
|
|
338
|
+
assert.equal(r.status, 0, r.stderr);
|
|
339
|
+
assert.match(r.stdout, /no Ethereum bound in this bundle/);
|
|
340
|
+
});
|
|
341
|
+
it("exits 2 for UNDETERMINED (proof alone) and 3 for a missing path", () => {
|
|
342
|
+
const u = spawnSync(process.execPath, [CLI_PATH, "check", join(FIXTURE, "proof.json")], { encoding: "utf8" });
|
|
343
|
+
assert.equal(u.status, 2, u.stderr);
|
|
344
|
+
const e = spawnSync(process.execPath, [CLI_PATH, "check", join(FIXTURE, "does-not-exist")], { encoding: "utf8" });
|
|
345
|
+
assert.equal(e.status, 3);
|
|
346
|
+
assert.match(e.stderr, /cannot read bundle/);
|
|
347
|
+
});
|
|
348
|
+
it("evaluate and init reject --json (it belongs to check only)", () => {
|
|
349
|
+
const r = spawnSync(process.execPath, [CLI_PATH, "init", join(FIXTURE, "random-043.txt"), "--json"], { encoding: "utf8" });
|
|
350
|
+
assert.equal(r.status, 3);
|
|
351
|
+
assert.match(r.stderr, /usage:/);
|
|
352
|
+
});
|
|
353
|
+
it("the relative path helper is unused by the report (paths are bundle-relative only)", () => {
|
|
354
|
+
// Guard against a future report field leaking absolute paths.
|
|
355
|
+
assert.equal(relative(FIXTURE, join(FIXTURE, "proof.json")), "proof.json");
|
|
356
|
+
});
|
|
357
|
+
});
|
|
358
|
+
//# sourceMappingURL=check.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check.test.js","sourceRoot":"","sources":["../../src/__tests__/check.test.ts"],"names":[],"mappings":"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"}
|
package/dist/check.d.ts
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `check`: what a bundle establishes about the recordings it holds, said
|
|
3
|
+
* plainly, offline, in the Player's three values.
|
|
4
|
+
*
|
|
5
|
+
* This is a SPEC section 8 convenience: a distinct subcommand that never
|
|
6
|
+
* touches evaluation semantics. It asks no rule-author question ("was A
|
|
7
|
+
* before B"); it asks the reader's question ("is this recording sound, and
|
|
8
|
+
* what bounds it"), over the audit pipeline's canonical interpretation of
|
|
9
|
+
* the bundle, and answers per line with TRUE, FALSE, or UNDETERMINED.
|
|
10
|
+
*
|
|
11
|
+
* The vocabulary, and the line it lives or dies on:
|
|
12
|
+
*
|
|
13
|
+
* TRUE evidence in hand establishes the property.
|
|
14
|
+
* FALSE evidence in hand CONTRADICTS the property: bytes that do
|
|
15
|
+
* not hash to the digest they sit beside, a signature that
|
|
16
|
+
* fails, an attestation whose user_data is not this proof, a
|
|
17
|
+
* block header that does not hash to its anchor's block hash,
|
|
18
|
+
* two recordings that cannot both be right.
|
|
19
|
+
* UNDETERMINED the evidence does not decide. Missing bytes, a missing
|
|
20
|
+
* witness, an environment that cannot run a check, a
|
|
21
|
+
* measurement this verifier does not know. Absence is never
|
|
22
|
+
* a verdict, and this command never degrades a failed or
|
|
23
|
+
* missing check into a FALSE (project rule: a failed read is
|
|
24
|
+
* never a verdict).
|
|
25
|
+
*
|
|
26
|
+
* The overall result is the strong-Kleene `all` over every line the report
|
|
27
|
+
* emits: each recording's lines, each anchor's lines, and each structural
|
|
28
|
+
* contradiction. Ethereum BOUNDS are reported descriptively per recording
|
|
29
|
+
* and never enter the conjunction: a bundle without an anchor has an
|
|
30
|
+
* unbounded recording, not an unsound one. A witness that is PRESENT and
|
|
31
|
+
* fails is a contradiction and does enter.
|
|
32
|
+
*
|
|
33
|
+
* Excerpt honesty. A single export is an excerpt of a chain: its recording
|
|
34
|
+
* links to a predecessor that is not in the bundle, and the counter
|
|
35
|
+
* positions between its anchors are absent. The audit reports those as
|
|
36
|
+
* anomalies because it is built to audit whole epochs; here they are
|
|
37
|
+
* expected and are reported as notes, never as verdicts. Real
|
|
38
|
+
* contradictions (collisions, forks, malformed links, signer changes)
|
|
39
|
+
* still surface as FALSE.
|
|
40
|
+
*
|
|
41
|
+
* Enclave identity. An attestation proves that SOME AWS Nitro enclave
|
|
42
|
+
* running code with the attested PCR0 signed this proof's key. Whether
|
|
43
|
+
* that PCR0 is a published BitGraph enclave measurement is a fact this
|
|
44
|
+
* verifier carries as DECLARED knowledge (KNOWN_ENCLAVE_MEASUREMENTS, from
|
|
45
|
+
* server/commit-service/reproducible-build/PINS.md). A measurement outside
|
|
46
|
+
* that list is UNDETERMINED, never FALSE: it is beyond what this build of
|
|
47
|
+
* the verifier knows, which is exactly how an offline verifier should age.
|
|
48
|
+
*
|
|
49
|
+
* Determinism. The report contains no wall-clock time, no machine path, and
|
|
50
|
+
* no run-local value; bundle-relative entry paths are bundle content and
|
|
51
|
+
* are allowed. Same bundle bytes, same report bytes.
|
|
52
|
+
*/
|
|
53
|
+
import type { AuditResult, IngestResult } from "@mikeargento/bitgraph-audit";
|
|
54
|
+
import type { ThreeValued } from "./types.js";
|
|
55
|
+
/**
|
|
56
|
+
* Published BitGraph enclave PCR0 measurements, per PINS.md, oldest first.
|
|
57
|
+
* Each remains correct for proofs minted during its own period; a proof
|
|
58
|
+
* carries its own measurement, so nothing here needs to be "current" for
|
|
59
|
+
* an old proof to check. Lowercase hex, exactly as attestations report.
|
|
60
|
+
*/
|
|
61
|
+
export declare const KNOWN_ENCLAVE_MEASUREMENTS: ReadonlyArray<{
|
|
62
|
+
pcr0: string;
|
|
63
|
+
label: string;
|
|
64
|
+
period: string;
|
|
65
|
+
}>;
|
|
66
|
+
/** One checked property, three-valued, with a plain-language reason. */
|
|
67
|
+
export interface CheckLine {
|
|
68
|
+
name: "file" | "signature" | "attestation" | "enclave" | "witness" | "contradiction";
|
|
69
|
+
result: ThreeValued;
|
|
70
|
+
detail: string;
|
|
71
|
+
}
|
|
72
|
+
/** A verified Ethereum bound on a recording, from a witness in the bundle. */
|
|
73
|
+
export interface CheckBound {
|
|
74
|
+
blockNumber?: string;
|
|
75
|
+
blockHash: string;
|
|
76
|
+
/** Unix seconds from the verified block header. */
|
|
77
|
+
timestamp: number;
|
|
78
|
+
anchorProofHash: string;
|
|
79
|
+
evidence: "chain-link" | "counter-order";
|
|
80
|
+
weaker: boolean;
|
|
81
|
+
}
|
|
82
|
+
export interface CheckBounds {
|
|
83
|
+
status: "bracketed" | "lower-bounded" | "upper-bounded" | "unanchored";
|
|
84
|
+
notBefore?: CheckBound;
|
|
85
|
+
notAfter?: CheckBound;
|
|
86
|
+
detail: string;
|
|
87
|
+
}
|
|
88
|
+
/** A non-anchor recording in the bundle. */
|
|
89
|
+
export interface CheckRecording {
|
|
90
|
+
proofHash: string;
|
|
91
|
+
digestB64: string;
|
|
92
|
+
epochId?: string;
|
|
93
|
+
chainId: string;
|
|
94
|
+
counter?: string;
|
|
95
|
+
slotCounter?: string;
|
|
96
|
+
publicKeyB64?: string;
|
|
97
|
+
/** Bundle-relative path of the matched artifact, when its bytes were present. */
|
|
98
|
+
filePath?: string;
|
|
99
|
+
lines: CheckLine[];
|
|
100
|
+
/** Kleene all over `lines`. */
|
|
101
|
+
result: ThreeValued;
|
|
102
|
+
bounds: CheckBounds;
|
|
103
|
+
}
|
|
104
|
+
/** An Ethereum anchor recording in the bundle. */
|
|
105
|
+
export interface CheckAnchor {
|
|
106
|
+
proofHash: string;
|
|
107
|
+
epochId?: string;
|
|
108
|
+
chainId: string;
|
|
109
|
+
counter?: string;
|
|
110
|
+
blockNumber?: string;
|
|
111
|
+
blockHash?: string;
|
|
112
|
+
/** Bundle-relative path of the witness file, when one matched this anchor. */
|
|
113
|
+
witnessPath?: string;
|
|
114
|
+
lines: CheckLine[];
|
|
115
|
+
result: ThreeValued;
|
|
116
|
+
}
|
|
117
|
+
export interface CheckReport {
|
|
118
|
+
check: "bitgraph-check/1";
|
|
119
|
+
result: ThreeValued;
|
|
120
|
+
/** One-sentence plain-language conclusion, deterministic. */
|
|
121
|
+
summary: string;
|
|
122
|
+
recordings: CheckRecording[];
|
|
123
|
+
anchors: CheckAnchor[];
|
|
124
|
+
/** Structural findings the bundle contradicts itself on. Every entry is FALSE. */
|
|
125
|
+
contradictions: CheckLine[];
|
|
126
|
+
/** Informational: excerpt gaps, unmatched files, duplicates. Never verdicts. */
|
|
127
|
+
notes: string[];
|
|
128
|
+
/** What no offline check can establish, stated rather than implied. */
|
|
129
|
+
notChecked: string[];
|
|
130
|
+
evaluator: {
|
|
131
|
+
name: "bitgraph-player";
|
|
132
|
+
version: string;
|
|
133
|
+
audit: string;
|
|
134
|
+
};
|
|
135
|
+
network: "none";
|
|
136
|
+
}
|
|
137
|
+
export interface CheckOptions {
|
|
138
|
+
/**
|
|
139
|
+
* False when the environment cannot run the attestation's ECDSA P-384
|
|
140
|
+
* verification (no WebCrypto). Attestation lines are then UNDETERMINED
|
|
141
|
+
* with that reason instead of a false FALSE. Defaults to true.
|
|
142
|
+
*/
|
|
143
|
+
webCryptoAvailable?: boolean;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Check an already-ingested bundle: runs the audit's pure tail (no
|
|
147
|
+
* filesystem, no network) and builds the report. Both the CLI and the
|
|
148
|
+
* browser page call this, so they cannot drift.
|
|
149
|
+
*/
|
|
150
|
+
export declare function checkIngest(ingest: IngestResult, options?: CheckOptions): Promise<CheckReport>;
|
|
151
|
+
/** The pure report builder over an AuditResult. */
|
|
152
|
+
export declare function buildCheckReport(audit: AuditResult, options?: CheckOptions): CheckReport;
|
|
153
|
+
export declare function renderCheckText(report: CheckReport): string;
|
|
154
|
+
/** Deterministic JSON bytes for the report: two-space indent, one trailing newline. */
|
|
155
|
+
export declare function serializeCheckReport(report: CheckReport): string;
|
|
156
|
+
//# sourceMappingURL=check.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../src/check.ts"],"names":[],"mappings":"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"}
|