@suveren/gateway 0.18.2 → 0.19.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/bin/suveren-gateway.js +5 -1
- package/dist/control-plane/index.mjs +4 -0
- package/dist/mcp-server/chunk-ZRRZFGRL.mjs +2412 -0
- package/dist/mcp-server/http.mjs +385 -674
- package/dist/mcp-server/report-verify-cli.mjs +64 -7
- package/dist/ui/assets/index-DeQPO4Sj.js +111 -0
- package/dist/ui/assets/index-kObsFuwK.css +1 -0
- package/dist/ui/index.html +2 -2
- package/package.json +1 -1
- package/profiles/index.json +2 -1
- package/profiles/reporting/0.2.profile.json +98 -0
- package/dist/mcp-server/chunk-QOKPECVY.mjs +0 -751
- package/dist/ui/assets/index-Bfi-G4qJ.css +0 -1
- package/dist/ui/assets/index-D0uXCqQB.js +0 -111
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
isExportBundle,
|
|
3
3
|
verifyExportBundle
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-ZRRZFGRL.mjs";
|
|
5
5
|
|
|
6
6
|
// bin/report-verify-cli.ts
|
|
7
7
|
import { readFileSync } from "fs";
|
|
@@ -19,6 +19,12 @@ function extractProofBundle(html) {
|
|
|
19
19
|
} catch (err) {
|
|
20
20
|
throw new Error(`Could not parse the embedded proof bundle: ${err instanceof Error ? err.message : String(err)}`);
|
|
21
21
|
}
|
|
22
|
+
const o = parsed;
|
|
23
|
+
if (o && o.format === "suveren-report-export" && o.version === 1) {
|
|
24
|
+
throw new Error(
|
|
25
|
+
"This file was exported by an older gateway (format version 1): it does not carry what the checker needs to compare the values the page SHOWS with the signed data. Export the report again with a current gateway."
|
|
26
|
+
);
|
|
27
|
+
}
|
|
22
28
|
if (!isExportBundle(parsed)) {
|
|
23
29
|
throw new Error('The embedded proof bundle is not in the expected "suveren-report-export" format.');
|
|
24
30
|
}
|
|
@@ -46,8 +52,8 @@ function parseArgs(argv) {
|
|
|
46
52
|
var HELP_TEXT = `Usage: suveren-gateway verify-report <file> [--key <hex>] [--online]
|
|
47
53
|
|
|
48
54
|
Verifies an "Export with proof" report file OFFLINE: every ticket signature,
|
|
49
|
-
every mandate attestation signature,
|
|
50
|
-
|
|
55
|
+
every mandate attestation signature, every reference the report makes to a
|
|
56
|
+
ticket, approval, mandate, or case \u2014 and every VALUE the page shows.
|
|
51
57
|
|
|
52
58
|
--key <hex> Require the embedded Authority Server key to match this exact
|
|
53
59
|
value \u2014 a fingerprint you already trust (e.g. read aloud over
|
|
@@ -61,6 +67,27 @@ confirm the embedded key against something you trust independently of this
|
|
|
61
67
|
file; with neither, the file's internal consistency is checked but the key
|
|
62
68
|
itself is not.
|
|
63
69
|
|
|
70
|
+
What the page shows is checked in two steps:
|
|
71
|
+
1. The visible page must be exactly what the embedded proof data draws \u2014
|
|
72
|
+
the checker re-draws the whole file and compares it byte for byte. Any
|
|
73
|
+
edit to the page (a number, a time, a style, an added box) fails. Keep
|
|
74
|
+
the file as downloaded: re-saving it from a browser changes it. A file
|
|
75
|
+
drawn by a different gateway version may not re-draw identically; check
|
|
76
|
+
it with that version.
|
|
77
|
+
2. Every value in every green box is checked against its source:
|
|
78
|
+
checked against signature ticket fields (action, time, profile,
|
|
79
|
+
execution context), mandate limits (via
|
|
80
|
+
the recomputed bounds hash), commitment
|
|
81
|
+
mode, owners, intent (via its hash)
|
|
82
|
+
recomputed wait_s, a case's duration_s, metrics \u2014
|
|
83
|
+
recomputed from the file's own values
|
|
84
|
+
not checkable offline approval times and approver (local
|
|
85
|
+
archive), records and a case's start email
|
|
86
|
+
(connector database), the refusals metric
|
|
87
|
+
Values that cannot be checked offline are listed per box under "Not
|
|
88
|
+
checkable offline" and do NOT fail the check \u2014 but they are never
|
|
89
|
+
reported as signed.
|
|
90
|
+
|
|
64
91
|
References the report itself shows as "not verifiable" (e.g. the AI named a
|
|
65
92
|
ticket that does not exist) are listed under "Not verifiable (as shown in the
|
|
66
93
|
report)" and do NOT fail the check \u2014 the file is honest about them. Every
|
|
@@ -69,10 +96,12 @@ ticket (and mandate) in the file, or the check fails.
|
|
|
69
96
|
|
|
70
97
|
Exit codes:
|
|
71
98
|
0 every signature is valid, every reference shown as verified is backed,
|
|
72
|
-
|
|
99
|
+
every value checked against a signature or recomputed matches, AND the
|
|
100
|
+
embedded key was confirmed
|
|
73
101
|
1 something is invalid \u2014 a bad signature, a reference shown as verified
|
|
74
|
-
with no valid ticket behind it,
|
|
75
|
-
|
|
102
|
+
with no valid ticket behind it, a value on the page that differs from
|
|
103
|
+
the signed data or does not recompute, an edited page, or a key that
|
|
104
|
+
does not match --key/--online
|
|
76
105
|
2 everything else is valid, but the embedded key was NOT checked (no --key
|
|
77
106
|
or --online given) \u2014 confirm it yourself before trusting this file
|
|
78
107
|
`;
|
|
@@ -143,7 +172,8 @@ function printSummary(bundle, result) {
|
|
|
143
172
|
console.log(` - ${e.elementId}${e.ticketIds.length ? ` (${e.ticketIds.join(", ")})` : ""}${note}`);
|
|
144
173
|
}
|
|
145
174
|
}
|
|
146
|
-
|
|
175
|
+
printBoxes(result);
|
|
176
|
+
const invalidAuth = result.authorizations.filter((a) => !a.attestationValid || a.boundsHashMatches === false || a.boundsValuesProven === false);
|
|
147
177
|
if (invalidAuth.length > 0) {
|
|
148
178
|
console.log(` Mandates: ${result.authorizations.length - invalidAuth.length}/${result.authorizations.length} valid \u2014 INVALID:`);
|
|
149
179
|
for (const a of invalidAuth) console.log(` - ${a.authorizationId}: ${a.error ?? "invalid"}`);
|
|
@@ -159,6 +189,33 @@ function printSummary(bundle, result) {
|
|
|
159
189
|
console.log(` Key not confirmed \u2014 compare this fingerprint with ${bundle.authorityServer.url}/api/as/pubkey or pass --online.`);
|
|
160
190
|
}
|
|
161
191
|
}
|
|
192
|
+
function printBoxes(result) {
|
|
193
|
+
if (result.document.state === "match") console.log(" Page: exactly what the signed data draws.");
|
|
194
|
+
else if (result.document.state === "mismatch") console.log(` INVALID \u2014 page: ${result.document.error}`);
|
|
195
|
+
for (const e of result.drawnErrors) console.log(` INVALID \u2014 ${e}`);
|
|
196
|
+
const bad = result.boxes.filter((b) => b.mismatches.length > 0);
|
|
197
|
+
const ok = result.boxes.filter((b) => b.mismatches.length === 0);
|
|
198
|
+
const fully = ok.filter((b) => b.notCheckable.length === 0);
|
|
199
|
+
console.log(` Boxes: ${fully.length} fully checked \xB7 ${ok.length - fully.length} partly not checkable offline \xB7 ${bad.length} MISMATCH.`);
|
|
200
|
+
for (const b of ok) {
|
|
201
|
+
const parts = [];
|
|
202
|
+
if (b.signed.length > 0) parts.push(`checked against signature: ${[...new Set(b.signed)].join(", ")}`);
|
|
203
|
+
if (b.recomputed.length > 0) parts.push(`recomputed: ${b.recomputed.map((r) => `${r.field} (from ${r.inputs.join(" + ")})`).join(", ")}`);
|
|
204
|
+
if (parts.length > 0) console.log(` - ${b.elementId}: ${parts.join(" \xB7 ")}`);
|
|
205
|
+
}
|
|
206
|
+
if (bad.length > 0) {
|
|
207
|
+
console.log(` INVALID \u2014 ${bad.length} box(es) show a value that differs from its source:`);
|
|
208
|
+
for (const b of bad) for (const m of b.mismatches) console.log(` - ${b.elementId}: ${m}`);
|
|
209
|
+
}
|
|
210
|
+
const unbackable = result.boxes.filter((b) => b.notCheckable.length > 0);
|
|
211
|
+
if (unbackable.length > 0) {
|
|
212
|
+
console.log(" Not checkable offline (shown in the report, not backed by a signature \u2014 does not fail the check):");
|
|
213
|
+
for (const b of unbackable) {
|
|
214
|
+
console.log(` - ${b.elementId}: ${b.notCheckable.map((n) => `${n.field} (${n.source})`).join(", ")}`);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
console.log(" Coverage panel: from the connector database \u2014 not checkable offline.");
|
|
218
|
+
}
|
|
162
219
|
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
163
220
|
runVerifyReportCli(process.argv.slice(2)).then((code) => {
|
|
164
221
|
process.exitCode = code;
|