@sanning/proof 0.19.0 → 0.20.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 +30 -29
- package/dist/agent-record.d.ts +62 -0
- package/dist/agent-record.js +527 -0
- package/dist/agent-schemas.generated.d.ts +15 -0
- package/dist/agent-schemas.generated.js +5759 -0
- package/dist/case-file.d.ts +32 -89
- package/dist/case-file.js +41 -93
- package/dist/case.d.ts +343 -810
- package/dist/case.js +693 -1151
- package/dist/chain.d.ts +19 -47
- package/dist/chain.js +78 -205
- package/dist/claims.d.ts +211 -0
- package/dist/claims.js +1081 -0
- package/dist/cli.d.ts +45 -68
- package/dist/cli.js +618 -1022
- package/dist/compose.js +23 -65
- package/dist/crypto.d.ts +7 -8
- package/dist/crypto.js +60 -147
- package/dist/declaration.d.ts +68 -194
- package/dist/declaration.js +175 -518
- package/dist/environment.d.ts +9 -30
- package/dist/environment.js +17 -66
- package/dist/evidence.d.ts +119 -160
- package/dist/evidence.js +744 -1103
- package/dist/exit-codes.d.ts +11 -27
- package/dist/exit-codes.js +24 -59
- package/dist/file-match.d.ts +33 -79
- package/dist/file-match.js +33 -69
- package/dist/grading.d.ts +98 -135
- package/dist/grading.js +224 -380
- package/dist/handoff.d.ts +62 -160
- package/dist/handoff.js +153 -393
- package/dist/index.d.ts +14 -10
- package/dist/index.js +60 -167
- package/dist/json-schema.d.ts +29 -0
- package/dist/json-schema.js +298 -0
- package/dist/merkle.js +16 -28
- package/dist/message-parts.d.ts +56 -212
- package/dist/message-parts.js +142 -502
- package/dist/side-content.d.ts +11 -22
- package/dist/side-content.js +22 -65
- package/dist/types.d.ts +17 -0
- package/dist/types.js +19 -5
- package/dist/verifier.d.ts +40 -114
- package/dist/verifier.js +196 -535
- package/dist/witness-cache.d.ts +24 -45
- package/dist/witness-cache.js +38 -81
- package/dist/witness-lookup.d.ts +36 -57
- package/dist/witness-lookup.js +89 -139
- package/dist/zip-reader.d.ts +18 -33
- package/dist/zip-reader.js +19 -34
- package/package.json +11 -3
- package/src/agent-record.ts +608 -0
- package/src/agent-schemas.generated.ts +5764 -0
- package/src/case-file.ts +45 -109
- package/src/case.ts +848 -1322
- package/src/chain.ts +85 -224
- package/src/claims.ts +1253 -0
- package/src/cli.ts +714 -1176
- package/src/compose.ts +33 -79
- package/src/crypto.ts +60 -147
- package/src/declaration.ts +219 -656
- package/src/environment.ts +17 -65
- package/src/evidence.ts +958 -1381
- package/src/exit-codes.ts +24 -63
- package/src/file-match.ts +40 -89
- package/src/grading.ts +287 -421
- package/src/handoff.ts +175 -427
- package/src/index.ts +132 -177
- package/src/json-schema.ts +295 -0
- package/src/merkle.ts +16 -28
- package/src/message-parts.ts +155 -533
- package/src/side-content.ts +25 -68
- package/src/types.ts +55 -36
- package/src/verifier.ts +202 -526
- package/src/witness-cache.ts +45 -94
- package/src/witness-lookup.ts +107 -177
- package/src/zip-reader.ts +20 -38
- package/vectors/README.md +52 -34
- package/vectors/agent-record.json +2175 -0
- package/vectors/case-file-index.json +1 -1
- package/vectors/case-split.json +2 -2
- package/vectors/chain-reading.json +3 -3
- package/vectors/file-match.json +285 -148
- package/vectors/jcs-reader.json +6 -6
- package/vectors/pack-grading.json +102 -25
- package/vectors/sandbox-evidence.json +597 -580
- package/vectors/stamp-on-chain.json +18 -18
- package/vectors/witness-cache.json +49 -49
- package/dist/agent-proof.d.ts +0 -28
- package/dist/agent-proof.js +0 -226
- package/dist/run-adapters.d.ts +0 -10
- package/dist/run-adapters.js +0 -35
- package/dist/run.d.ts +0 -209
- package/dist/run.js +0 -1405
- package/src/agent-proof.ts +0 -264
- package/src/run-adapters.ts +0 -44
- package/src/run.ts +0 -1598
package/dist/agent-proof.js
DELETED
|
@@ -1,226 +0,0 @@
|
|
|
1
|
-
// Agent inclusion proof verification (`sanning.agent.proof/v1`).
|
|
2
|
-
//
|
|
3
|
-
// The `sanning.agent.proof/v1` bundle is the agent's ~1.4 KB self-contained
|
|
4
|
-
// inclusion proof: a signed checkpoint envelope (sanning.agent/v1, INLINE payload)
|
|
5
|
-
// plus a single leaf object and its RFC 9162 audit path. Verifying it is the
|
|
6
|
-
// inverse of `sanningd proof`. The CLI sniffs `spec_version` and routes here so
|
|
7
|
-
// ONE verifier covers both the agent (this) and the anchor SDK (evidence.ts).
|
|
8
|
-
//
|
|
9
|
-
// Algorithm:
|
|
10
|
-
// 1. Verify the checkpoint envelope (signature + inline payload_hash bind).
|
|
11
|
-
// 2. leaf_hash = SHA-256(0x00 || JCS(leaf)).
|
|
12
|
-
// 3. Walk audit_path with leaf_index + leaf_count (from the checkpoint
|
|
13
|
-
// payload) to reconstruct the root.
|
|
14
|
-
// 4. Confirm the reconstructed root == checkpoint_envelope.payload.merkle_root.
|
|
15
|
-
// 5. (optional) Re-fetch checkpoint_tx_id from a gateway and byte-compare.
|
|
16
|
-
import { hexToBytes, utf8 } from "./crypto.js";
|
|
17
|
-
import { safeInteger } from "./grading.js";
|
|
18
|
-
import { leafHash, verifyInclusion } from "./merkle.js";
|
|
19
|
-
import { MAX_CANONICAL_DEPTH, exceedsDepth, jcs, jcsParse, verifyEnvelope } from "./verifier.js";
|
|
20
|
-
export const AGENT_PROOF_SPEC_VERSION = "sanning.agent.proof/v1";
|
|
21
|
-
/** The sentence `agent_proof.py` writes when the proof's own fields are not usable. */
|
|
22
|
-
const MALFORMED_PROOF = "merkle_root / audit_path / leaf_index malformed";
|
|
23
|
-
function toHex(bytes) {
|
|
24
|
-
let out = "";
|
|
25
|
-
for (const x of bytes)
|
|
26
|
-
out += x.toString(16).padStart(2, "0");
|
|
27
|
-
return out;
|
|
28
|
-
}
|
|
29
|
-
export function isAgentProofSpec(specVersion) {
|
|
30
|
-
if (typeof specVersion !== "string")
|
|
31
|
-
return false;
|
|
32
|
-
return specVersion === AGENT_PROOF_SPEC_VERSION || specVersion.startsWith(`${AGENT_PROOF_SPEC_VERSION}.`);
|
|
33
|
-
}
|
|
34
|
-
export async function verifyAgentProof(bundle, options = {}) {
|
|
35
|
-
const fail = (error) => ({
|
|
36
|
-
status: "malformed",
|
|
37
|
-
checkpointOk: false,
|
|
38
|
-
inclusionOk: false,
|
|
39
|
-
onChainOk: null,
|
|
40
|
-
onChainChecked: false,
|
|
41
|
-
leafIndex: -1,
|
|
42
|
-
leafCount: null,
|
|
43
|
-
checkpointTxId: null,
|
|
44
|
-
errors: [error],
|
|
45
|
-
});
|
|
46
|
-
if (bundle === null || typeof bundle !== "object" || Array.isArray(bundle)) {
|
|
47
|
-
return fail("bundle is not a JSON object");
|
|
48
|
-
}
|
|
49
|
-
// Bound nesting before any canonicalization (checkpoint envelope + Merkle
|
|
50
|
-
// leaves are canonicalized recursively) — a fixed shared limit keeps this a
|
|
51
|
-
// `malformed` verdict in every kernel. See MAX_CANONICAL_DEPTH.
|
|
52
|
-
if (exceedsDepth(bundle, MAX_CANONICAL_DEPTH)) {
|
|
53
|
-
return fail(`bundle nesting exceeds the ${MAX_CANONICAL_DEPTH}-level canonicalization depth bound`);
|
|
54
|
-
}
|
|
55
|
-
const b = bundle;
|
|
56
|
-
if (!isAgentProofSpec(b.spec_version)) {
|
|
57
|
-
// An absent one reads `null`, as in `agent_proof.py` (`dict.get` gives
|
|
58
|
-
// None); `JSON.stringify(undefined)` would write the word `undefined`.
|
|
59
|
-
return fail(`unsupported bundle spec_version: ${JSON.stringify(b.spec_version ?? null)}`);
|
|
60
|
-
}
|
|
61
|
-
if (b.checkpoint_envelope === null || typeof b.checkpoint_envelope !== "object") {
|
|
62
|
-
return fail("bundle missing checkpoint_envelope");
|
|
63
|
-
}
|
|
64
|
-
if (b.leaf === null || typeof b.leaf !== "object") {
|
|
65
|
-
return fail("bundle missing leaf");
|
|
66
|
-
}
|
|
67
|
-
if (!Array.isArray(b.audit_path)) {
|
|
68
|
-
return fail(MALFORMED_PROOF);
|
|
69
|
-
}
|
|
70
|
-
const errors = [];
|
|
71
|
-
// Step 1: verify the checkpoint envelope (inline payload — no payloadBytes).
|
|
72
|
-
let checkpointOk = false;
|
|
73
|
-
let merkleRoot;
|
|
74
|
-
let leafCount;
|
|
75
|
-
try {
|
|
76
|
-
const res = await verifyEnvelope(b.checkpoint_envelope);
|
|
77
|
-
checkpointOk = res.ok && res.payloadHashOk === true;
|
|
78
|
-
if (!res.signatureOk)
|
|
79
|
-
errors.push("checkpoint envelope signature failed");
|
|
80
|
-
if (res.payloadHashOk !== true)
|
|
81
|
-
errors.push("checkpoint envelope payload binding failed");
|
|
82
|
-
// A malformed skeleton field (proof#95) fails the envelope with a valid
|
|
83
|
-
// signature and binding; name it rather than fail with no reason.
|
|
84
|
-
for (const m of res.errors)
|
|
85
|
-
if (m.startsWith("malformed "))
|
|
86
|
-
errors.push(`checkpoint envelope ${m}`);
|
|
87
|
-
const payload = (b.checkpoint_envelope.payload ?? {});
|
|
88
|
-
if (typeof payload.merkle_root === "string")
|
|
89
|
-
merkleRoot = payload.merkle_root;
|
|
90
|
-
// `leaf_count` and `leaf_index` are read BY VALUE, the rule every
|
|
91
|
-
// inclusion reader in both kernels follows (evidence-bundle A38): `3.0` is
|
|
92
|
-
// 3, and a fraction, a value past 2**53 - 1, a string or a boolean is not
|
|
93
|
-
// an integer. `agent_proof.py` reads them through `_safe_integer`.
|
|
94
|
-
leafCount = safeInteger(payload.leaf_count) ?? undefined;
|
|
95
|
-
if (merkleRoot === undefined)
|
|
96
|
-
errors.push("checkpoint payload missing merkle_root");
|
|
97
|
-
if (leafCount === undefined)
|
|
98
|
-
errors.push("checkpoint payload leaf_count is not an integer");
|
|
99
|
-
}
|
|
100
|
-
catch {
|
|
101
|
-
// The sentence `agent_proof.py` writes for the same failure. The thrown
|
|
102
|
-
// text is the host's, and a public result carries the kernel's words only
|
|
103
|
-
// (proof#150).
|
|
104
|
-
errors.push("checkpoint envelope verification failed");
|
|
105
|
-
}
|
|
106
|
-
// Steps 2-4: leaf hash, audit-path walk, root match.
|
|
107
|
-
let inclusionOk = false;
|
|
108
|
-
if (merkleRoot !== undefined && leafCount !== undefined) {
|
|
109
|
-
let lh;
|
|
110
|
-
try {
|
|
111
|
-
lh = await leafHash(utf8(jcs(b.leaf)));
|
|
112
|
-
}
|
|
113
|
-
catch {
|
|
114
|
-
errors.push("leaf is not JCS-canonicalizable");
|
|
115
|
-
}
|
|
116
|
-
const leafIndex = safeInteger(b.leaf_index);
|
|
117
|
-
if (lh !== undefined && leafIndex === null) {
|
|
118
|
-
// `agent_proof.py` refuses a leaf_index that is not an integer with this
|
|
119
|
-
// sentence. Without the check a string, `null` or `1.5` reaches the walk
|
|
120
|
-
// and reads as a failed inclusion proof instead (proof#150).
|
|
121
|
-
errors.push(MALFORMED_PROOF);
|
|
122
|
-
}
|
|
123
|
-
else if (lh !== undefined) {
|
|
124
|
-
try {
|
|
125
|
-
inclusionOk = await verifyInclusion(lh, leafIndex, leafCount, b.audit_path.map((h) => hexToBytes(h)), hexToBytes(merkleRoot));
|
|
126
|
-
if (!inclusionOk)
|
|
127
|
-
errors.push("audit_path does not reconstruct merkle_root");
|
|
128
|
-
}
|
|
129
|
-
catch {
|
|
130
|
-
// `agent_proof.py`'s sentence for the same failure; the thrown text is
|
|
131
|
-
// the host's (proof#150).
|
|
132
|
-
errors.push(MALFORMED_PROOF);
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
// Step 5: optional on-chain re-fetch.
|
|
137
|
-
const gateways = options.gateways ?? [];
|
|
138
|
-
const onChainChecked = gateways.length > 0;
|
|
139
|
-
let onChainOk = null;
|
|
140
|
-
let gatewayUnavailable = false;
|
|
141
|
-
if (onChainChecked) {
|
|
142
|
-
const fetchImpl = options.fetchImpl ?? globalThis.fetch;
|
|
143
|
-
if (typeof fetchImpl !== "function") {
|
|
144
|
-
gatewayUnavailable = true;
|
|
145
|
-
errors.push("on-chain re-fetch requested but no fetch implementation is available");
|
|
146
|
-
}
|
|
147
|
-
else {
|
|
148
|
-
const outcome = await refetch(b.checkpoint_envelope, b.checkpoint_tx_id, gateways, fetchImpl);
|
|
149
|
-
onChainOk = outcome.ok;
|
|
150
|
-
if (outcome.unavailable)
|
|
151
|
-
gatewayUnavailable = true;
|
|
152
|
-
if (outcome.error)
|
|
153
|
-
errors.push(outcome.error);
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
let status;
|
|
157
|
-
if (!checkpointOk || !inclusionOk || onChainOk === false) {
|
|
158
|
-
status = "failed";
|
|
159
|
-
}
|
|
160
|
-
else if (gatewayUnavailable) {
|
|
161
|
-
status = "partial";
|
|
162
|
-
}
|
|
163
|
-
else {
|
|
164
|
-
status = "verified";
|
|
165
|
-
}
|
|
166
|
-
return {
|
|
167
|
-
status,
|
|
168
|
-
checkpointOk,
|
|
169
|
-
inclusionOk,
|
|
170
|
-
onChainOk,
|
|
171
|
-
onChainChecked,
|
|
172
|
-
// Read by value, as the walk above read it: a `2.5` or `1e+21` index is
|
|
173
|
-
// reported as no index, never printed beside a verdict that refused it.
|
|
174
|
-
leafIndex: safeInteger(b.leaf_index) ?? -1,
|
|
175
|
-
leafCount: leafCount ?? null,
|
|
176
|
-
checkpointTxId: typeof b.checkpoint_tx_id === "string" ? b.checkpoint_tx_id : null,
|
|
177
|
-
errors,
|
|
178
|
-
};
|
|
179
|
-
}
|
|
180
|
-
async function refetch(envelope, txId, gateways, fetchImpl) {
|
|
181
|
-
let expectedHex;
|
|
182
|
-
try {
|
|
183
|
-
expectedHex = toHex(utf8(jcs(envelope)));
|
|
184
|
-
}
|
|
185
|
-
catch {
|
|
186
|
-
return { ok: false, unavailable: false, error: "checkpoint envelope is not JCS-canonicalizable" };
|
|
187
|
-
}
|
|
188
|
-
let anyReachable = false;
|
|
189
|
-
for (const gw of gateways) {
|
|
190
|
-
const url = `${gw.replace(/\/+$/, "")}/${txId}`;
|
|
191
|
-
try {
|
|
192
|
-
const resp = await fetchImpl(url);
|
|
193
|
-
if (!resp.ok)
|
|
194
|
-
continue;
|
|
195
|
-
anyReachable = true;
|
|
196
|
-
const onChain = new Uint8Array(await resp.arrayBuffer());
|
|
197
|
-
if (toHex(onChain) === expectedHex)
|
|
198
|
-
return { ok: true, unavailable: false };
|
|
199
|
-
try {
|
|
200
|
-
// `jcsParse`, matching `_probe_gateway` in
|
|
201
|
-
// `src/sanning_proof/evidence.py`. These bytes arrive from a gateway or
|
|
202
|
-
// a CDN in front of one, so a lenient decoder is reachable without any
|
|
203
|
-
// party building a pack: a CDN serving the envelope with a byte-order
|
|
204
|
-
// mark split this probe from the one in `evidence.ts`, and two honest
|
|
205
|
-
// readers of ONE transaction disagreed (proof#140 gate 5).
|
|
206
|
-
const parsed = jcsParse(onChain);
|
|
207
|
-
if (toHex(utf8(jcs(parsed))) === expectedHex)
|
|
208
|
-
return { ok: true, unavailable: false };
|
|
209
|
-
}
|
|
210
|
-
catch {
|
|
211
|
-
// fall through
|
|
212
|
-
}
|
|
213
|
-
return {
|
|
214
|
-
ok: false,
|
|
215
|
-
unavailable: false,
|
|
216
|
-
error: `on-chain bytes at ${txId} do not match the checkpoint envelope`,
|
|
217
|
-
};
|
|
218
|
-
}
|
|
219
|
-
catch {
|
|
220
|
-
// try next gateway
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
if (anyReachable)
|
|
224
|
-
return { ok: false, unavailable: false, error: `checkpoint ${txId} mismatched on every gateway` };
|
|
225
|
-
return { ok: null, unavailable: true, error: `checkpoint ${txId} unreachable on all gateways` };
|
|
226
|
-
}
|
package/dist/run-adapters.d.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { type EnclaveAdapter } from "./run.js";
|
|
2
|
-
/** Import a module by name. A parameter so a test can watch what is asked for. */
|
|
3
|
-
export type Importer = (name: string) => Promise<unknown>;
|
|
4
|
-
/**
|
|
5
|
-
* The adapters this environment holds, loaded from `ADAPTER_MODULES` and
|
|
6
|
-
* nothing else. A module counts only when it exports the provider it was
|
|
7
|
-
* loaded for as `provider`, a `check` function, and the failure kinds it
|
|
8
|
-
* declares as `kinds` (`declaredKinds`).
|
|
9
|
-
*/
|
|
10
|
-
export declare function loadInstalledAdapters(importer?: Importer): Promise<Map<string, EnclaveAdapter>>;
|
package/dist/run-adapters.js
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
// Loading the enclave attestation adapters a reader has installed. Kept out of
|
|
2
|
-
// `index.ts` on purpose: it imports packages by name, which a browser bundle
|
|
3
|
-
// cannot resolve, and only the command line needs it. `run.ts` imports nothing.
|
|
4
|
-
//
|
|
5
|
-
// The packages are named by `ADAPTER_MODULES` and by nothing else: a provider
|
|
6
|
-
// id read from a pack is never turned into a module name.
|
|
7
|
-
import { ADAPTER_MODULES, declaredKinds } from "./run.js";
|
|
8
|
-
const dynamicImport = (name) => import(/* @vite-ignore */ name);
|
|
9
|
-
/**
|
|
10
|
-
* The adapters this environment holds, loaded from `ADAPTER_MODULES` and
|
|
11
|
-
* nothing else. A module counts only when it exports the provider it was
|
|
12
|
-
* loaded for as `provider`, a `check` function, and the failure kinds it
|
|
13
|
-
* declares as `kinds` (`declaredKinds`).
|
|
14
|
-
*/
|
|
15
|
-
export async function loadInstalledAdapters(importer = dynamicImport) {
|
|
16
|
-
const found = new Map();
|
|
17
|
-
for (const [provider, name] of Object.entries(ADAPTER_MODULES)) {
|
|
18
|
-
let module;
|
|
19
|
-
try {
|
|
20
|
-
module = await importer(name);
|
|
21
|
-
}
|
|
22
|
-
catch {
|
|
23
|
-
continue;
|
|
24
|
-
}
|
|
25
|
-
const m = module;
|
|
26
|
-
if (m !== null &&
|
|
27
|
-
typeof m === "object" &&
|
|
28
|
-
m.provider === provider &&
|
|
29
|
-
typeof m.check === "function" &&
|
|
30
|
-
declaredKinds(m) !== null) {
|
|
31
|
-
found.set(provider, m);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
return found;
|
|
35
|
-
}
|
package/dist/run.d.ts
DELETED
|
@@ -1,209 +0,0 @@
|
|
|
1
|
-
import { type SideContentMap } from "./side-content.js";
|
|
2
|
-
export declare const ATTESTATION_VERSION = "sanning.enclave-attestation/v1";
|
|
3
|
-
export declare const BINDING_VERSION = "sanning.run-binding/v1";
|
|
4
|
-
export declare const POLICY_VERSION = "sanning.enclave-policy/v1";
|
|
5
|
-
export declare const MANIFEST_VERSION = "sanning.run-manifest/v1";
|
|
6
|
-
export declare const RUN_OPENED = "runner.run_opened";
|
|
7
|
-
export declare const RUN_CLOSED = "runner.run_closed";
|
|
8
|
-
export declare const PROVIDER_GCP = "gcp-confidential-space";
|
|
9
|
-
export declare const PROVIDER_FLARE = "flare-fcc";
|
|
10
|
-
/**
|
|
11
|
-
* The fixed table: provider id to the package that answers for it. A provider
|
|
12
|
-
* id read from a pack is looked up HERE and nowhere else, so a pack naming `os`
|
|
13
|
-
* or `../x` loads nothing.
|
|
14
|
-
*/
|
|
15
|
-
export declare const ADAPTER_MODULES: Readonly<Record<string, string>>;
|
|
16
|
-
/** Printed after an enclave line whose token was checked. Never a state. */
|
|
17
|
-
export declare const REVOCATION_SENTENCE: string;
|
|
18
|
-
export declare const ENCLAVE_STATES: readonly ["confirmed", "differs", "not_checked"];
|
|
19
|
-
export declare const RUN_ACCOUNT_STATES: readonly ["closed", "differs", "not_closed"];
|
|
20
|
-
/** Why an enclave line reads `not_checked`. */
|
|
21
|
-
export declare const ENCLAVE_NOT_CHECKED_KINDS: readonly ["no_adapter", "no_attestation", "unknown_version", "no_policy", "policy_unreadable", "adapter_failed", "no_opening_record"];
|
|
22
|
-
/** The provider-neutral checks that make a line `differs`, in line order. */
|
|
23
|
-
export declare const ENCLAVE_DIFFERS_KINDS: readonly ["attestation_malformed", "subject_key_not_signer", "manifest_not_content", "binding_other_run", "binding_other_manifest", "binding_other_keys", "signed_at_outside_tolerance", "manifest_content_mismatch", "manifest_unreadable", "case_hash_differs", "agent_record_under_runner_key"];
|
|
24
|
-
/** The kinds an adapter may answer with; any other reads `adapter_failed`. */
|
|
25
|
-
export declare const ENCLAVE_NOTE_KINDS: readonly ["no_issue_time", "manifest_withheld", "stamp_unwitnessed"];
|
|
26
|
-
/**
|
|
27
|
-
* Every kind and note the kernel itself names. An adapter declares its own
|
|
28
|
-
* failure kinds (its `kinds`, section 9); none of them may be one of these, so
|
|
29
|
-
* an adapter can never speak for a neutral check.
|
|
30
|
-
*/
|
|
31
|
-
export declare const NEUTRAL_KINDS: ReadonlySet<string>;
|
|
32
|
-
export declare const ACCOUNT_FINDING_KINDS: readonly ["record_not_listed", "listed_record_absent", "more_than_one_closing_record", "closing_malformed"];
|
|
33
|
-
/**
|
|
34
|
-
* Why the online line (`flare-fcc` only, section 8) reads `not_checked`:
|
|
35
|
-
* nothing was decided. `adapter_failed` is the kernel's.
|
|
36
|
-
*/
|
|
37
|
-
export declare const ONLINE_NOT_CHECKED_KINDS: readonly ["adapter_failed", "evidence_not_confirmed", "no_contracts", "manifest_withheld", "manifest_unreadable", "chain_unavailable", "not_final"];
|
|
38
|
-
/** Why the online line reads `differs`: the chain answered, and it does not match. */
|
|
39
|
-
export declare const ONLINE_DIFFERS_KINDS: readonly ["instruction_count", "instruction_other_extension", "instruction_other_machine", "instruction_other_operation", "instruction_other_message", "transaction_failed", "log_malformed", "run_opened_differs", "run_opened_count", "machine_not_production", "machine_other_extension", "code_not_supported", "call_reverted"];
|
|
40
|
-
export declare const ACCOUNT_NOTE_KINDS: readonly ["agent_key_unknown", "runner_record_under_agent_key", "runner_record_bytes_withheld", "payload_hashes_absent", "unacknowledged_record_absent"];
|
|
41
|
-
/**
|
|
42
|
-
* Whether `s`, the text between a host's brackets, is an IPv6 address as the
|
|
43
|
-
* WHATWG URL Standard's IPv6 parser accepts one (RFC 4291 text form), in
|
|
44
|
-
* lowercase. A step for step port of the parser, the twin of Python's
|
|
45
|
-
* `is_ipv6_text` and the runner's `run.IsPlaneOrigin`.
|
|
46
|
-
*/
|
|
47
|
-
export declare function isIpv6Text(s: string): boolean;
|
|
48
|
-
/** The object does not read under the one spelling. The message is the reason. */
|
|
49
|
-
export declare class AttestationRefused extends Error {
|
|
50
|
-
}
|
|
51
|
-
/** `attestation_version` is a string this reader does not know. */
|
|
52
|
-
export declare class UnknownAttestationVersion extends AttestationRefused {
|
|
53
|
-
}
|
|
54
|
-
/** `sanning.run-binding/v1`, read strictly from the evidence. */
|
|
55
|
-
export interface Binding {
|
|
56
|
-
runId: string;
|
|
57
|
-
manifestHash: string;
|
|
58
|
-
runnerPublicKey: string;
|
|
59
|
-
agentPublicKey: string;
|
|
60
|
-
credentialPublicKey: string;
|
|
61
|
-
caseHash: string;
|
|
62
|
-
/**
|
|
63
|
-
* The plane's origin the runner claimed the run from (section 4). Carried,
|
|
64
|
-
* not compared: the plane refuses a claim whose binding names another plane.
|
|
65
|
-
*/
|
|
66
|
-
plane: string;
|
|
67
|
-
request: Readonly<Record<string, unknown>>;
|
|
68
|
-
}
|
|
69
|
-
/** `sanning.enclave-attestation/v1`, read strictly. */
|
|
70
|
-
export interface Attestation {
|
|
71
|
-
runnerPublicKey: string;
|
|
72
|
-
agentPublicKey: string;
|
|
73
|
-
manifestHash: string;
|
|
74
|
-
runId: string;
|
|
75
|
-
provider: string;
|
|
76
|
-
evidence: Readonly<Record<string, unknown>>;
|
|
77
|
-
/** The binding the evidence carries, for a registered provider; else null. */
|
|
78
|
-
binding: Binding | null;
|
|
79
|
-
}
|
|
80
|
-
/**
|
|
81
|
-
* Read the `enclave_attestation` member of an opening record strictly. Throws
|
|
82
|
-
* `UnknownAttestationVersion` for a version string this reader does not know,
|
|
83
|
-
* and `AttestationRefused` for anything else that is not the one spelling.
|
|
84
|
-
*/
|
|
85
|
-
export declare function readAttestation(value: unknown): Attestation;
|
|
86
|
-
/** `readAttestation` over bytes that must be `JCS(object)`. */
|
|
87
|
-
export declare function readAttestationJson(raw: Uint8Array): Attestation;
|
|
88
|
-
/**
|
|
89
|
-
* What an adapter answers (checks 2 to 6 and 8). `binding` is the binding the
|
|
90
|
-
* adapter verified its evidence commits to: `confirmed` without one is outside
|
|
91
|
-
* the contract and reads `adapter_failed`, because the kernel runs checks 7
|
|
92
|
-
* and 11 on that binding. Each kind is one the adapter declares in `kinds`.
|
|
93
|
-
*/
|
|
94
|
-
export interface AdapterResult {
|
|
95
|
-
state: (typeof ENCLAVE_STATES)[number];
|
|
96
|
-
kinds?: readonly string[];
|
|
97
|
-
/** The verified token's issue time, seconds since the epoch, or null. */
|
|
98
|
-
issuedAt?: number | null;
|
|
99
|
-
imageId?: string | null;
|
|
100
|
-
hwModel?: string | null;
|
|
101
|
-
tokenChecked?: boolean;
|
|
102
|
-
binding?: Binding | null;
|
|
103
|
-
}
|
|
104
|
-
/**
|
|
105
|
-
* An adapter: the provider it answers for, the failure kinds it declares, its
|
|
106
|
-
* check, and optionally the online line.
|
|
107
|
-
*/
|
|
108
|
-
export interface EnclaveAdapter {
|
|
109
|
-
provider: string;
|
|
110
|
-
kinds: readonly string[];
|
|
111
|
-
check(attestation: Attestation, options: {
|
|
112
|
-
policy: Readonly<Record<string, unknown>>;
|
|
113
|
-
at: string | null;
|
|
114
|
-
}): AdapterResult | Promise<AdapterResult>;
|
|
115
|
-
online?(attestation: Attestation, options: {
|
|
116
|
-
policy: Readonly<Record<string, unknown>>;
|
|
117
|
-
at: string | null;
|
|
118
|
-
manifest: Uint8Array | null;
|
|
119
|
-
rpc: string;
|
|
120
|
-
}): OnlineLine | Promise<OnlineLine>;
|
|
121
|
-
}
|
|
122
|
-
/**
|
|
123
|
-
* The online line (section 8): what the chain says of a `flare-fcc` opening,
|
|
124
|
-
* read by the adapter at the offline line's evaluation time. `confirmed`
|
|
125
|
-
* carries no kind; `not_checked` and `differs` carry one. It moves nothing.
|
|
126
|
-
*/
|
|
127
|
-
export interface OnlineLine {
|
|
128
|
-
state: (typeof ENCLAVE_STATES)[number];
|
|
129
|
-
kinds: string[];
|
|
130
|
-
}
|
|
131
|
-
export interface EnclaveLine {
|
|
132
|
-
state: (typeof ENCLAVE_STATES)[number];
|
|
133
|
-
kinds: string[];
|
|
134
|
-
notes: string[];
|
|
135
|
-
reason: string | null;
|
|
136
|
-
provider: string | null;
|
|
137
|
-
evaluatedAt: string | null;
|
|
138
|
-
evaluation: "stamp" | "token_issue_time" | null;
|
|
139
|
-
tokenChecked: boolean;
|
|
140
|
-
}
|
|
141
|
-
export interface AccountEntry {
|
|
142
|
-
kind: string;
|
|
143
|
-
eventId: string | null;
|
|
144
|
-
}
|
|
145
|
-
export interface RunAccountLine {
|
|
146
|
-
state: (typeof RUN_ACCOUNT_STATES)[number];
|
|
147
|
-
findings: AccountEntry[];
|
|
148
|
-
notes: AccountEntry[];
|
|
149
|
-
closingEventId: string | null;
|
|
150
|
-
reason: string | null;
|
|
151
|
-
}
|
|
152
|
-
export interface RunReading {
|
|
153
|
-
/** The pack by the reader's name for it; two packs can share one (A43). */
|
|
154
|
-
packRef: string;
|
|
155
|
-
/** The pack's position among the packs read, as the case reading's `pack_index`. */
|
|
156
|
-
packIndex: number;
|
|
157
|
-
eventId: string;
|
|
158
|
-
runnerPublicKey: string;
|
|
159
|
-
agentPublicKey: string | null;
|
|
160
|
-
enclave: EnclaveLine;
|
|
161
|
-
account: RunAccountLine;
|
|
162
|
-
/** The online line, where the reader asked for one and the adapter reads the chain; else null. */
|
|
163
|
-
online: OnlineLine | null;
|
|
164
|
-
}
|
|
165
|
-
export interface RunsReading {
|
|
166
|
-
runs: RunReading[];
|
|
167
|
-
}
|
|
168
|
-
/** One pack, as `readCase` takes it. */
|
|
169
|
-
export interface RunPack {
|
|
170
|
-
ref: string;
|
|
171
|
-
bundle: unknown;
|
|
172
|
-
content?: SideContentMap | null;
|
|
173
|
-
}
|
|
174
|
-
/**
|
|
175
|
-
* The time the token is evaluated at (7): the interval end of a stamp that
|
|
176
|
-
* holds the opening record and whose witness the reader's lookup confirmed;
|
|
177
|
-
* otherwise null, the token's own issue time.
|
|
178
|
-
*/
|
|
179
|
-
/**
|
|
180
|
-
* @internal For the kernel's own tests: the enclave line of one opening record,
|
|
181
|
-
* verified as the caller says, under a provider table the caller names. It is
|
|
182
|
-
* how a test reaches a provider outside `ADAPTER_MODULES`; `readRuns` always
|
|
183
|
-
* reads under `ADAPTER_MODULES`.
|
|
184
|
-
*/
|
|
185
|
-
export declare function enclaveLineForTest(record: Record<string, unknown>, publicKey: string, content: Uint8Array | null, policy: unknown, adapters: ReadonlyMap<string, EnclaveAdapter>, table: Readonly<Record<string, string>>): Promise<EnclaveLine>;
|
|
186
|
-
/**
|
|
187
|
-
* The failure kinds an adapter declares as its `kinds`: an array of snake_case
|
|
188
|
-
* strings, at least one, none of them a kind or note the kernel names
|
|
189
|
-
* (`NEUTRAL_KINDS`). `null` where the declaration is not of that form, an
|
|
190
|
-
* empty one included, and then the adapter is not loaded.
|
|
191
|
-
*/
|
|
192
|
-
export declare function declaredKinds(adapter: unknown): ReadonlySet<string> | null;
|
|
193
|
-
export declare function readRuns(packs: readonly RunPack[], options?: {
|
|
194
|
-
policy?: unknown;
|
|
195
|
-
adapters?: ReadonlyMap<string, EnclaveAdapter> | null;
|
|
196
|
-
/** A chain endpoint for the online line, handed to an adapter that reads one. */
|
|
197
|
-
rpc?: string | null;
|
|
198
|
-
/**
|
|
199
|
-
* For each pack by position, the `stamp_ref` of every stamp whose witness
|
|
200
|
-
* the caller looked up and the public record confirmed (the on-chain
|
|
201
|
-
* half's `confirm`). A token is evaluated at a stamp's interval end only
|
|
202
|
-
* there, and at its own issue time otherwise. Absent: no lookup.
|
|
203
|
-
*/
|
|
204
|
-
witnessed?: readonly (readonly string[] | null | undefined)[] | null;
|
|
205
|
-
}): Promise<RunsReading>;
|
|
206
|
-
/** The enclave line, the revocation sentence where a token was checked, and the online line. */
|
|
207
|
-
export declare function renderEnclaveLines(r: RunReading): string[];
|
|
208
|
-
/** The run-account line (specs/run-records.md). */
|
|
209
|
-
export declare function renderAccountLine(r: RunReading): string;
|