usertrust 1.4.0 → 2.0.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 +17 -1
- package/dist/anomaly/detector.d.ts.map +1 -1
- package/dist/anomaly/detector.js +36 -11
- package/dist/anomaly/detector.js.map +1 -1
- package/dist/anomaly/index.d.ts +2 -2
- package/dist/anomaly/index.d.ts.map +1 -1
- package/dist/anomaly/index.js +1 -1
- package/dist/anomaly/index.js.map +1 -1
- package/dist/anomaly/signals/spend-velocity.d.ts +39 -12
- package/dist/anomaly/signals/spend-velocity.d.ts.map +1 -1
- package/dist/anomaly/signals/spend-velocity.js +66 -43
- package/dist/anomaly/signals/spend-velocity.js.map +1 -1
- package/dist/anomaly/signals/token-rate.d.ts +33 -13
- package/dist/anomaly/signals/token-rate.d.ts.map +1 -1
- package/dist/anomaly/signals/token-rate.js +124 -38
- package/dist/anomaly/signals/token-rate.js.map +1 -1
- package/dist/anomaly/types.d.ts +28 -6
- package/dist/anomaly/types.d.ts.map +1 -1
- package/dist/audit/anchor-doctor.d.ts +42 -0
- package/dist/audit/anchor-doctor.d.ts.map +1 -0
- package/dist/audit/anchor-doctor.js +285 -0
- package/dist/audit/anchor-doctor.js.map +1 -0
- package/dist/audit/anchor-verify.d.ts +229 -0
- package/dist/audit/anchor-verify.d.ts.map +1 -0
- package/dist/audit/anchor-verify.js +809 -0
- package/dist/audit/anchor-verify.js.map +1 -0
- package/dist/audit/anchor.d.ts +177 -0
- package/dist/audit/anchor.d.ts.map +1 -0
- package/dist/audit/anchor.js +922 -0
- package/dist/audit/anchor.js.map +1 -0
- package/dist/audit/canonical.js +1 -1
- package/dist/audit/canonical.js.map +1 -1
- package/dist/audit/chain.d.ts.map +1 -1
- package/dist/audit/chain.js +21 -7
- package/dist/audit/chain.js.map +1 -1
- package/dist/audit/read.d.ts +19 -0
- package/dist/audit/read.d.ts.map +1 -0
- package/dist/audit/read.js +94 -0
- package/dist/audit/read.js.map +1 -0
- package/dist/audit/rekor-verify.d.ts +116 -0
- package/dist/audit/rekor-verify.d.ts.map +1 -0
- package/dist/audit/rekor-verify.js +533 -0
- package/dist/audit/rekor-verify.js.map +1 -0
- package/dist/audit/rekor.d.ts +71 -0
- package/dist/audit/rekor.d.ts.map +1 -0
- package/dist/audit/rekor.js +556 -0
- package/dist/audit/rekor.js.map +1 -0
- package/dist/audit/rotation.js +1 -1
- package/dist/audit/rotation.js.map +1 -1
- package/dist/audit/sigv4.d.ts +44 -0
- package/dist/audit/sigv4.d.ts.map +1 -0
- package/dist/audit/sigv4.js +134 -0
- package/dist/audit/sigv4.js.map +1 -0
- package/dist/audit/verify.d.ts +78 -0
- package/dist/audit/verify.d.ts.map +1 -1
- package/dist/audit/verify.js +195 -1
- package/dist/audit/verify.js.map +1 -1
- package/dist/cli/anchor.d.ts +3 -0
- package/dist/cli/anchor.d.ts.map +1 -0
- package/dist/cli/anchor.js +626 -0
- package/dist/cli/anchor.js.map +1 -0
- package/dist/cli/completions.js +1 -1
- package/dist/cli/export.d.ts +3 -0
- package/dist/cli/export.d.ts.map +1 -0
- package/dist/cli/export.js +58 -0
- package/dist/cli/export.js.map +1 -0
- package/dist/cli/health.js.map +1 -1
- package/dist/cli/init.d.ts.map +1 -1
- package/dist/cli/init.js +99 -2
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/inspect.d.ts.map +1 -1
- package/dist/cli/inspect.js +4 -34
- package/dist/cli/inspect.js.map +1 -1
- package/dist/cli/main.d.ts +2 -2
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/main.js +20 -1
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/pricing.js +1 -1
- package/dist/cli/pricing.js.map +1 -1
- package/dist/cli/ui.d.ts +3 -0
- package/dist/cli/ui.d.ts.map +1 -0
- package/dist/cli/ui.js +35 -0
- package/dist/cli/ui.js.map +1 -0
- package/dist/cli/verify.d.ts.map +1 -1
- package/dist/cli/verify.js +342 -3
- package/dist/cli/verify.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js.map +1 -1
- package/dist/detect.d.ts +71 -16
- package/dist/detect.d.ts.map +1 -1
- package/dist/detect.js +141 -6
- package/dist/detect.js.map +1 -1
- package/dist/export/markdown.d.ts +12 -0
- package/dist/export/markdown.d.ts.map +1 -0
- package/dist/export/markdown.js +142 -0
- package/dist/export/markdown.js.map +1 -0
- package/dist/govern.d.ts +67 -3
- package/dist/govern.d.ts.map +1 -1
- package/dist/govern.js +1011 -219
- package/dist/govern.js.map +1 -1
- package/dist/headless.d.ts +41 -2
- package/dist/headless.d.ts.map +1 -1
- package/dist/headless.js +58 -7
- package/dist/headless.js.map +1 -1
- package/dist/index.d.ts +33 -25
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +30 -23
- package/dist/index.js.map +1 -1
- package/dist/ledger/client.d.ts.map +1 -1
- package/dist/ledger/client.js +57 -46
- package/dist/ledger/client.js.map +1 -1
- package/dist/ledger/engine.d.ts.map +1 -1
- package/dist/ledger/engine.js +22 -13
- package/dist/ledger/engine.js.map +1 -1
- package/dist/ledger/pricing.d.ts +54 -0
- package/dist/ledger/pricing.d.ts.map +1 -1
- package/dist/ledger/pricing.js +128 -8
- package/dist/ledger/pricing.js.map +1 -1
- package/dist/shared/types.d.ts +154 -340
- package/dist/shared/types.d.ts.map +1 -1
- package/dist/shared/types.js +67 -17
- package/dist/shared/types.js.map +1 -1
- package/dist/snapshot/checkpoint.d.ts.map +1 -1
- package/dist/snapshot/checkpoint.js +20 -2
- package/dist/snapshot/checkpoint.js.map +1 -1
- package/dist/streaming.d.ts +13 -3
- package/dist/streaming.d.ts.map +1 -1
- package/dist/streaming.js +88 -30
- package/dist/streaming.js.map +1 -1
- package/dist/supply-chain/sign.d.ts.map +1 -1
- package/dist/supply-chain/sign.js +3 -0
- package/dist/supply-chain/sign.js.map +1 -1
- package/package.json +6 -4
|
@@ -0,0 +1,556 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// Copyright 2026 Usertools, Inc.
|
|
3
|
+
/**
|
|
4
|
+
* Witness sinks: S3 (native SigV4) and Rekor (hashedrekord transparency log).
|
|
5
|
+
*
|
|
6
|
+
* Both are AnchorSinks, so both inherit the emitter's contract: a publish that
|
|
7
|
+
* resolves means the record was DURABLY accepted, and a publish that rejects
|
|
8
|
+
* keeps the record in the outbox for redelivery. Everything here therefore
|
|
9
|
+
* fails closed — a sink that resolved on a response it did not fully understand
|
|
10
|
+
* would silently drop a record out of the append-only store, which is precisely
|
|
11
|
+
* the evidence loss anchoring exists to prevent.
|
|
12
|
+
*
|
|
13
|
+
* What Rekor witnesses is deliberately thin (spec §3, delta D14): the entry
|
|
14
|
+
* carries sha256 of the anchor payload, the record's signature, and the vault's
|
|
15
|
+
* public key — never event data, never the payload itself. The receipt lives in
|
|
16
|
+
* its own file because the anchor record schema is FROZEN; a transparency log
|
|
17
|
+
* must not become a field inside the thing it witnesses.
|
|
18
|
+
*
|
|
19
|
+
* EXPERIMENTAL: the Rekor path is exercised against synthetic responses only —
|
|
20
|
+
* the live API is untested in CI, and the entry `apiVersion` is pinned to
|
|
21
|
+
* 0.0.1.
|
|
22
|
+
*
|
|
23
|
+
* Network access is confined to `httpTransport` at the bottom of this file;
|
|
24
|
+
* every other function is pure or writes to the vault, so tests inject a
|
|
25
|
+
* transport and assert on bytes.
|
|
26
|
+
*/
|
|
27
|
+
import { createHash } from "node:crypto";
|
|
28
|
+
import { closeSync, fsyncSync, mkdirSync, openSync, readdirSync, readFileSync, writeSync, } from "node:fs";
|
|
29
|
+
import { join } from "node:path";
|
|
30
|
+
// Cyclic by design: anchor.ts builds these sinks from SinkConfig, and the Rekor
|
|
31
|
+
// sink needs the vault's identity + anchors directory. Both bindings are
|
|
32
|
+
// function declarations used only at publish time, so the cycle never observes
|
|
33
|
+
// a partially initialized module.
|
|
34
|
+
import { anchorsDir, readAnchorIdentity } from "./anchor.js";
|
|
35
|
+
import { anchorPayloadHash } from "./anchor-verify.js";
|
|
36
|
+
import { canonicalize } from "./canonical.js";
|
|
37
|
+
import { parseRekorReceipt } from "./rekor-verify.js";
|
|
38
|
+
import { sigV4Headers } from "./sigv4.js";
|
|
39
|
+
export const DEFAULT_REKOR_URL = "https://rekor.sigstore.dev";
|
|
40
|
+
const REKOR_ENTRIES_PATH = "/api/v1/log/entries";
|
|
41
|
+
/** Rekor's hashedrekord schema version. Pinned: 0.0.2+ changes the spec shape. */
|
|
42
|
+
const HASHEDREKORD_API_VERSION = "0.0.1";
|
|
43
|
+
const HEX64 = /^[0-9a-f]{64}$/;
|
|
44
|
+
const BASE64 = /^[A-Za-z0-9+/]*={0,2}$/;
|
|
45
|
+
const MAX_ENTRY_BODY_BYTES = 64 * 1024;
|
|
46
|
+
const MAX_CHECKPOINT_BYTES = 8 * 1024;
|
|
47
|
+
const MAX_INCLUSION_PATH = 64;
|
|
48
|
+
const MAX_SET_BYTES = 1024;
|
|
49
|
+
/** Matches the receipt parser's bound: `* 1000` must stay a valid Date. */
|
|
50
|
+
const MAX_INTEGRATED_TIME = 8_640_000_000_000;
|
|
51
|
+
// ── Shared helpers ──
|
|
52
|
+
const is2xx = (status) => status >= 200 && status < 300;
|
|
53
|
+
/**
|
|
54
|
+
* A store's response body on its way into an error message. Anything that looks
|
|
55
|
+
* like a signed header is dropped: a hostile or misconfigured endpoint can echo
|
|
56
|
+
* our request back, and an error string ends up in logs and issue trackers
|
|
57
|
+
* (delta D6). Truncated to 120 characters — the status code carries the meaning.
|
|
58
|
+
*/
|
|
59
|
+
function snippet(body) {
|
|
60
|
+
if (body === "")
|
|
61
|
+
return "";
|
|
62
|
+
const scrubbed = body
|
|
63
|
+
.replace(/authorization[^\n]*/gi, "[redacted]")
|
|
64
|
+
.replace(/x-amz-security-token[^\n]*/gi, "[redacted]")
|
|
65
|
+
.replace(/AWS4-HMAC-SHA256[^\n]*/g, "[redacted]")
|
|
66
|
+
.replace(/\s+/g, " ")
|
|
67
|
+
.trim();
|
|
68
|
+
return scrubbed === "" ? "" : `: ${scrubbed.slice(0, 120)}`;
|
|
69
|
+
}
|
|
70
|
+
const seq12 = (anchorSeq) => String(anchorSeq).padStart(12, "0");
|
|
71
|
+
/** `YYYYMMDDTHHMMSSZ` for SigV4. */
|
|
72
|
+
function amzDate() {
|
|
73
|
+
return `${new Date().toISOString().replace(/[-:]/g, "").slice(0, 15)}Z`;
|
|
74
|
+
}
|
|
75
|
+
function credentialsFromEnv() {
|
|
76
|
+
const accessKeyId = process.env.AWS_ACCESS_KEY_ID;
|
|
77
|
+
const secretAccessKey = process.env.AWS_SECRET_ACCESS_KEY;
|
|
78
|
+
if (!accessKeyId || !secretAccessKey)
|
|
79
|
+
return null;
|
|
80
|
+
const sessionToken = process.env.AWS_SESSION_TOKEN;
|
|
81
|
+
return { accessKeyId, secretAccessKey, ...(sessionToken ? { sessionToken } : {}) };
|
|
82
|
+
}
|
|
83
|
+
// ── S3 sink ──
|
|
84
|
+
/**
|
|
85
|
+
* Endpoint rule for BOTH sinks. Plaintext is refused off-loopback: for S3,
|
|
86
|
+
* SigV4 authenticates the request but does not encrypt it, so an http endpoint
|
|
87
|
+
* on the network would put the credential-bearing headers on the wire; for
|
|
88
|
+
* Rekor, an http log URL lets anyone on the path answer for the witness — and
|
|
89
|
+
* a sink that accepts a forged 201 files forged evidence. Loopback is allowed
|
|
90
|
+
* for dev MinIO/LocalStack and local log instances.
|
|
91
|
+
*/
|
|
92
|
+
export function parseEndpoint(endpoint, sinkName = "s3 sink") {
|
|
93
|
+
let url;
|
|
94
|
+
try {
|
|
95
|
+
url = new URL(endpoint);
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
throw new Error(`${sinkName}: endpoint must include a scheme, got "${endpoint.slice(0, 60)}"`);
|
|
99
|
+
}
|
|
100
|
+
const loopback = url.hostname === "localhost" || url.hostname === "127.0.0.1";
|
|
101
|
+
if (url.protocol !== "https:" && !(url.protocol === "http:" && loopback)) {
|
|
102
|
+
throw new Error(`${sinkName}: endpoint must be https (http is allowed only for localhost/127.0.0.1), got "${url.protocol}//${url.host}"`);
|
|
103
|
+
}
|
|
104
|
+
return url;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Object key + addressing. Virtual-host style against AWS; path-style against a
|
|
108
|
+
* configured endpoint, since S3-compatible stores rarely serve bucket
|
|
109
|
+
* subdomains. Anchor records are a few hundred bytes — one PUT, no multipart.
|
|
110
|
+
*/
|
|
111
|
+
function s3Target(cfg, vaultId, anchorSeq) {
|
|
112
|
+
const prefix = (cfg.prefix ?? "anchors").replace(/^\/+|\/+$/g, "");
|
|
113
|
+
const key = `${prefix === "" ? "" : `${prefix}/`}${vaultId}/${seq12(anchorSeq)}.json`;
|
|
114
|
+
const encoded = key.split("/").map(encodeURIComponent).join("/");
|
|
115
|
+
if (cfg.endpoint !== undefined) {
|
|
116
|
+
const base = parseEndpoint(cfg.endpoint);
|
|
117
|
+
const path = `/${encodeURIComponent(cfg.bucket)}/${encoded}`;
|
|
118
|
+
return { host: base.host, path, url: `${base.protocol}//${base.host}${path}` };
|
|
119
|
+
}
|
|
120
|
+
const host = `${cfg.bucket}.s3.${cfg.region}.amazonaws.com`;
|
|
121
|
+
return { host, path: `/${encoded}`, url: `https://${host}/${encoded}` };
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* PUT one canonical record per object, keyed by vault and anchorSeq. Immutability
|
|
125
|
+
* is the STORE's job (Object Lock retention / a deny-delete bucket policy);
|
|
126
|
+
* `usertrust anchor doctor` reports whether this identity's permissions match
|
|
127
|
+
* that intent.
|
|
128
|
+
*/
|
|
129
|
+
export function s3Sink(cfg, transport = httpTransport) {
|
|
130
|
+
const prefix = (cfg.prefix ?? "anchors").replace(/^\/+|\/+$/g, "");
|
|
131
|
+
return {
|
|
132
|
+
name: `s3:${cfg.bucket}/${prefix}`,
|
|
133
|
+
publish: async (record) => {
|
|
134
|
+
const creds = credentialsFromEnv();
|
|
135
|
+
if (creds === null) {
|
|
136
|
+
throw new Error("s3 sink: AWS credentials not found in environment " +
|
|
137
|
+
"(AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY)");
|
|
138
|
+
}
|
|
139
|
+
const payload = Buffer.from(canonicalize(record), "utf8");
|
|
140
|
+
const target = s3Target(cfg, record.vaultId, record.anchorSeq);
|
|
141
|
+
const extra = { "content-type": "application/json" };
|
|
142
|
+
const signed = sigV4Headers({
|
|
143
|
+
method: "PUT",
|
|
144
|
+
host: target.host,
|
|
145
|
+
path: target.path,
|
|
146
|
+
headers: extra,
|
|
147
|
+
payload,
|
|
148
|
+
region: cfg.region,
|
|
149
|
+
service: "s3",
|
|
150
|
+
amzDate: amzDate(),
|
|
151
|
+
}, creds);
|
|
152
|
+
// sigV4Headers signs the caller's headers but returns only its own —
|
|
153
|
+
// both must go on the wire or the signature covers headers that never
|
|
154
|
+
// arrive.
|
|
155
|
+
const res = await transport({
|
|
156
|
+
method: "PUT",
|
|
157
|
+
url: target.url,
|
|
158
|
+
headers: { ...extra, ...signed },
|
|
159
|
+
body: payload,
|
|
160
|
+
});
|
|
161
|
+
if (!is2xx(res.status)) {
|
|
162
|
+
throw new Error(`s3 sink: HTTP ${res.status}${snippet(res.body)}`);
|
|
163
|
+
}
|
|
164
|
+
},
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
// ── Rekor entry proposal ──
|
|
168
|
+
/**
|
|
169
|
+
* SPKI base64 as PEM text. The exact bytes matter: this text is base64'd into
|
|
170
|
+
* the entry, and the entry's bytes are what the inclusion proof commits to
|
|
171
|
+
* (delta D13). 64-character lines, LF-only, trailing newline.
|
|
172
|
+
*/
|
|
173
|
+
function pemFromSpkiBase64(spkiBase64) {
|
|
174
|
+
const compact = spkiBase64.replace(/\s+/g, "");
|
|
175
|
+
if (compact === "" || !BASE64.test(compact)) {
|
|
176
|
+
throw new Error("rekor sink: vault identity publicKeySpki is not base64");
|
|
177
|
+
}
|
|
178
|
+
const wrapped = (compact.match(/.{1,64}/g) ?? []).join("\n");
|
|
179
|
+
return `-----BEGIN PUBLIC KEY-----\n${wrapped}\n-----END PUBLIC KEY-----\n`;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* The hashedrekord entry we PROPOSE for a record: the anchor payload hash as the
|
|
183
|
+
* artifact, the record's Ed25519 signature, and the vault's public key. The log
|
|
184
|
+
* stores its own serialization of this; the receipt carries the log's bytes, so
|
|
185
|
+
* these are the bytes we sign nothing over and merely offer.
|
|
186
|
+
*/
|
|
187
|
+
export function buildHashedRekordEntry(record, publicKeySpkiBase64) {
|
|
188
|
+
return canonicalize({
|
|
189
|
+
apiVersion: HASHEDREKORD_API_VERSION,
|
|
190
|
+
kind: "hashedrekord",
|
|
191
|
+
spec: {
|
|
192
|
+
data: { hash: { algorithm: "sha256", value: anchorPayloadHash(record) } },
|
|
193
|
+
signature: {
|
|
194
|
+
content: record.sig,
|
|
195
|
+
publicKey: {
|
|
196
|
+
content: Buffer.from(pemFromSpkiBase64(publicKeySpkiBase64), "utf8").toString("base64"),
|
|
197
|
+
},
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
function asObject(value) {
|
|
203
|
+
return value !== null && typeof value === "object" && !Array.isArray(value)
|
|
204
|
+
? value
|
|
205
|
+
: null;
|
|
206
|
+
}
|
|
207
|
+
function isSafeIntAtLeast(value, min) {
|
|
208
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= min;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Validate a 201 down to every field the receipt will quote. A receipt built
|
|
212
|
+
* from a half-understood response is worse than no receipt: it would be filed as
|
|
213
|
+
* evidence and only fail at audit time, long after the anchor left the outbox.
|
|
214
|
+
* Nothing from the response is echoed into these errors — field names only.
|
|
215
|
+
*/
|
|
216
|
+
function parseAcceptedEntry(raw) {
|
|
217
|
+
const bad = (message) => ({
|
|
218
|
+
entry: null,
|
|
219
|
+
error: message,
|
|
220
|
+
});
|
|
221
|
+
let parsed;
|
|
222
|
+
try {
|
|
223
|
+
parsed = JSON.parse(raw);
|
|
224
|
+
}
|
|
225
|
+
catch {
|
|
226
|
+
return bad("body is not valid JSON");
|
|
227
|
+
}
|
|
228
|
+
const response = asObject(parsed);
|
|
229
|
+
if (response === null)
|
|
230
|
+
return bad("body is not a JSON object");
|
|
231
|
+
const uuids = Object.keys(response);
|
|
232
|
+
// Rekor keys the response by entry UUID. Two keys means the log is answering
|
|
233
|
+
// about an entry we did not propose; zero means it answered about none.
|
|
234
|
+
if (uuids.length !== 1)
|
|
235
|
+
return bad(`expected exactly one entry, got ${uuids.length}`);
|
|
236
|
+
const entry = asObject(response[uuids[0]]);
|
|
237
|
+
if (entry === null)
|
|
238
|
+
return bad("entry is not a JSON object");
|
|
239
|
+
if (typeof entry.body !== "string" || entry.body === "" || !BASE64.test(entry.body)) {
|
|
240
|
+
return bad("entry.body must be base64");
|
|
241
|
+
}
|
|
242
|
+
const decoded = Buffer.from(entry.body, "base64");
|
|
243
|
+
if (decoded.length === 0)
|
|
244
|
+
return bad("entry.body decodes to no bytes");
|
|
245
|
+
if (decoded.length > MAX_ENTRY_BODY_BYTES)
|
|
246
|
+
return bad("entry.body exceeds 64 KiB decoded");
|
|
247
|
+
if (!isSafeIntAtLeast(entry.logIndex, 0))
|
|
248
|
+
return bad("entry.logIndex must be a safe integer >= 0");
|
|
249
|
+
// Same bound the receipt parser enforces: a receipt we write must be one we
|
|
250
|
+
// can read back, and `integratedTime * 1000` has to stay a printable Date.
|
|
251
|
+
if (!isSafeIntAtLeast(entry.integratedTime, 1) || entry.integratedTime >= MAX_INTEGRATED_TIME) {
|
|
252
|
+
return bad(`entry.integratedTime must be a safe integer > 0 and < ${MAX_INTEGRATED_TIME}`);
|
|
253
|
+
}
|
|
254
|
+
if (entry.logID !== undefined && (typeof entry.logID !== "string" || !HEX64.test(entry.logID))) {
|
|
255
|
+
return bad("entry.logID must be 64 lowercase hex characters");
|
|
256
|
+
}
|
|
257
|
+
const verification = asObject(entry.verification);
|
|
258
|
+
const proof = asObject(verification?.inclusionProof);
|
|
259
|
+
if (proof === null)
|
|
260
|
+
return bad("entry.verification.inclusionProof is missing");
|
|
261
|
+
// The proof's own index — NOT the entry's global logIndex, which counts
|
|
262
|
+
// across the whole log rather than the tree this proof is against.
|
|
263
|
+
if (!isSafeIntAtLeast(proof.logIndex, 0))
|
|
264
|
+
return bad("inclusionProof.logIndex must be >= 0");
|
|
265
|
+
if (!isSafeIntAtLeast(proof.treeSize, 1))
|
|
266
|
+
return bad("inclusionProof.treeSize must be >= 1");
|
|
267
|
+
if (proof.logIndex >= proof.treeSize) {
|
|
268
|
+
return bad("inclusionProof.logIndex must be < inclusionProof.treeSize");
|
|
269
|
+
}
|
|
270
|
+
if (typeof proof.rootHash !== "string" || !HEX64.test(proof.rootHash)) {
|
|
271
|
+
return bad("inclusionProof.rootHash must be 64 lowercase hex characters");
|
|
272
|
+
}
|
|
273
|
+
if (!Array.isArray(proof.hashes) || proof.hashes.length > MAX_INCLUSION_PATH) {
|
|
274
|
+
return bad(`inclusionProof.hashes must be an array of at most ${MAX_INCLUSION_PATH} hashes`);
|
|
275
|
+
}
|
|
276
|
+
for (const h of proof.hashes) {
|
|
277
|
+
if (typeof h !== "string" || !HEX64.test(h)) {
|
|
278
|
+
return bad("inclusionProof.hashes entries must be 64 lowercase hex characters");
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
if (typeof proof.checkpoint !== "string" ||
|
|
282
|
+
proof.checkpoint === "" ||
|
|
283
|
+
Buffer.byteLength(proof.checkpoint, "utf8") > MAX_CHECKPOINT_BYTES ||
|
|
284
|
+
proof.checkpoint.includes("\r")) {
|
|
285
|
+
return bad("inclusionProof.checkpoint must be a non-empty LF-only string of at most 8 KiB");
|
|
286
|
+
}
|
|
287
|
+
// The signed entry timestamp is what makes integratedTime worth anything to
|
|
288
|
+
// an auditor, so it is captured whenever the log offers one — but a SET with
|
|
289
|
+
// no logID cannot be verified by anybody (the logID is inside the payload it
|
|
290
|
+
// signs), and filing evidence nobody can check is the failure this module
|
|
291
|
+
// exists to avoid.
|
|
292
|
+
const set = verification?.signedEntryTimestamp;
|
|
293
|
+
if (set !== undefined) {
|
|
294
|
+
if (typeof set !== "string" ||
|
|
295
|
+
set === "" ||
|
|
296
|
+
!BASE64.test(set) ||
|
|
297
|
+
Buffer.byteLength(set, "utf8") > MAX_SET_BYTES) {
|
|
298
|
+
return bad("verification.signedEntryTimestamp must be base64 of at most 1 KiB");
|
|
299
|
+
}
|
|
300
|
+
if (entry.logID === undefined) {
|
|
301
|
+
return bad("verification.signedEntryTimestamp present without entry.logID");
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
return {
|
|
305
|
+
entry: {
|
|
306
|
+
body: entry.body,
|
|
307
|
+
integratedTime: entry.integratedTime,
|
|
308
|
+
logIndex: proof.logIndex,
|
|
309
|
+
treeSize: proof.treeSize,
|
|
310
|
+
rootHash: proof.rootHash,
|
|
311
|
+
hashes: proof.hashes,
|
|
312
|
+
checkpoint: proof.checkpoint,
|
|
313
|
+
...(typeof set === "string" ? { signedEntryTimestamp: set } : {}),
|
|
314
|
+
...(typeof entry.logID === "string" ? { logID: entry.logID } : {}),
|
|
315
|
+
},
|
|
316
|
+
error: null,
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
// ── Receipt persistence ──
|
|
320
|
+
/**
|
|
321
|
+
* `<seq12>.<8 hex of sha256(log url)>.json` — one receipt per (anchor, LOG).
|
|
322
|
+
* Keying by anchorSeq alone made two rekor sinks silently overwrite each
|
|
323
|
+
* other's evidence: the second witness's receipt replaced the first's, and the
|
|
324
|
+
* operator ended up with fewer independent attestations than they configured.
|
|
325
|
+
* Readers glob `*.json` in this directory, so pre-existing `<seq12>.json`
|
|
326
|
+
* receipts keep being found.
|
|
327
|
+
*/
|
|
328
|
+
export function rekorReceiptPath(rootDir, anchorSeq, logUrl) {
|
|
329
|
+
const tag = createHash("sha256").update(logUrl, "utf8").digest("hex").slice(0, 8);
|
|
330
|
+
return join(anchorsDir(rootDir), "rekor", `${seq12(anchorSeq)}.${tag}.json`);
|
|
331
|
+
}
|
|
332
|
+
/** Fsync'd receipt write — the same durability the outbox and mirror get. */
|
|
333
|
+
function writeReceipt(rootDir, receipt) {
|
|
334
|
+
const serialized = `${canonicalize(receipt)}\n`;
|
|
335
|
+
// A receipt our own parser rejects is a bug in this module, and it would be
|
|
336
|
+
// discovered at audit time by whoever is relying on it. Fail here instead.
|
|
337
|
+
const check = parseRekorReceipt(serialized);
|
|
338
|
+
if (check.receipt === null) {
|
|
339
|
+
throw new Error(`rekor sink: assembled an unparseable receipt (${check.error})`);
|
|
340
|
+
}
|
|
341
|
+
const dir = join(anchorsDir(rootDir), "rekor");
|
|
342
|
+
mkdirSync(dir, { recursive: true });
|
|
343
|
+
const fd = openSync(rekorReceiptPath(rootDir, receipt.anchorSeq, receipt.log.url), "w", 0o600);
|
|
344
|
+
try {
|
|
345
|
+
writeSync(fd, serialized);
|
|
346
|
+
fsyncSync(fd);
|
|
347
|
+
}
|
|
348
|
+
finally {
|
|
349
|
+
closeSync(fd);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* Do the bytes a log stored commit to THIS record — our payload hash AND our
|
|
354
|
+
* signature? Reused for the 201 response and for receipts already on disk; in
|
|
355
|
+
* both cases the alternative is filing evidence about someone else's entry.
|
|
356
|
+
* Decoded bytes are compared, never base64 spellings, since base64 is not
|
|
357
|
+
* canonical and equivalent encodings are the same signature.
|
|
358
|
+
*/
|
|
359
|
+
function entryBindsRecord(entryBodyBase64, record) {
|
|
360
|
+
let parsed;
|
|
361
|
+
try {
|
|
362
|
+
parsed = JSON.parse(Buffer.from(entryBodyBase64, "base64").toString("utf8"));
|
|
363
|
+
}
|
|
364
|
+
catch {
|
|
365
|
+
return false;
|
|
366
|
+
}
|
|
367
|
+
const spec = asObject(asObject(parsed)?.spec);
|
|
368
|
+
if (spec === null)
|
|
369
|
+
return false;
|
|
370
|
+
const hash = asObject(asObject(spec.data)?.hash);
|
|
371
|
+
const signature = asObject(spec.signature);
|
|
372
|
+
if (hash === null || signature === null || typeof signature.content !== "string")
|
|
373
|
+
return false;
|
|
374
|
+
if (hash.value !== anchorPayloadHash(record))
|
|
375
|
+
return false;
|
|
376
|
+
const logged = Buffer.from(signature.content, "base64");
|
|
377
|
+
const ours = Buffer.from(record.sig, "base64");
|
|
378
|
+
return ours.length > 0 && logged.equals(ours);
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* A receipt already on disk from THIS log that witnesses THIS record. Every
|
|
382
|
+
* `*.json` in the directory is considered, because the filename is a
|
|
383
|
+
* convenience and the receipt's own contents are the evidence — a receipt is
|
|
384
|
+
* only accepted when it names the record, carries its payload hash, and its
|
|
385
|
+
* stored entry binds the record's signature.
|
|
386
|
+
*/
|
|
387
|
+
function findBindingReceipt(rootDir, record, logUrl) {
|
|
388
|
+
const dir = join(anchorsDir(rootDir), "rekor");
|
|
389
|
+
let names;
|
|
390
|
+
try {
|
|
391
|
+
names = readdirSync(dir).filter((f) => f.endsWith(".json"));
|
|
392
|
+
}
|
|
393
|
+
catch {
|
|
394
|
+
return false;
|
|
395
|
+
}
|
|
396
|
+
for (const name of names.sort()) {
|
|
397
|
+
let raw;
|
|
398
|
+
try {
|
|
399
|
+
raw = readFileSync(join(dir, name), "utf-8");
|
|
400
|
+
}
|
|
401
|
+
catch {
|
|
402
|
+
continue;
|
|
403
|
+
}
|
|
404
|
+
const { receipt } = parseRekorReceipt(raw);
|
|
405
|
+
if (receipt === null)
|
|
406
|
+
continue;
|
|
407
|
+
if (receipt.vaultId === record.vaultId &&
|
|
408
|
+
receipt.anchorSeq === record.anchorSeq &&
|
|
409
|
+
receipt.log.url === logUrl &&
|
|
410
|
+
receipt.artifactHash === anchorPayloadHash(record) &&
|
|
411
|
+
entryBindsRecord(receipt.entryBody, record)) {
|
|
412
|
+
return true;
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
return false;
|
|
416
|
+
}
|
|
417
|
+
/**
|
|
418
|
+
* The public key to PROPOSE for a record, resolved from the record's OWN key
|
|
419
|
+
* epoch rather than from whatever key the vault holds today. A record minted
|
|
420
|
+
* before a rotation and redelivered after it is still signed by the old key, so
|
|
421
|
+
* proposing the live key would log a public key that does not verify the
|
|
422
|
+
* signature sitting beside it — a permanently wrong entry in an append-only
|
|
423
|
+
* log. Identities predating key history keep the old behavior; once a history
|
|
424
|
+
* exists, a keyId absent from it is refused rather than guessed at.
|
|
425
|
+
*/
|
|
426
|
+
function spkiForRecord(identity, record) {
|
|
427
|
+
if (identity.keyHistory === undefined)
|
|
428
|
+
return identity.publicKeySpki;
|
|
429
|
+
const known = [
|
|
430
|
+
...identity.keyHistory,
|
|
431
|
+
{ keyId: identity.keyId, publicKeySpki: identity.publicKeySpki },
|
|
432
|
+
];
|
|
433
|
+
const match = known.find((entry) => entry.keyId === record.keyId);
|
|
434
|
+
if (match === undefined) {
|
|
435
|
+
throw new Error(`rekor sink: no public key for keyId ${record.keyId} in this vault's key history`);
|
|
436
|
+
}
|
|
437
|
+
return match.publicKeySpki;
|
|
438
|
+
}
|
|
439
|
+
// ── Rekor sink ──
|
|
440
|
+
/**
|
|
441
|
+
* Publish a record's payload hash to a Rekor transparency log and persist the
|
|
442
|
+
* inclusion receipt next to the mirror.
|
|
443
|
+
*
|
|
444
|
+
* A 409 means the log already holds an entry for this proposal, which happens
|
|
445
|
+
* on exactly one honest path: a crash between writing the receipt and clearing
|
|
446
|
+
* the outbox, so the emitter redelivers a record that IS already witnessed.
|
|
447
|
+
* That case is resolved from the receipt we already hold — never from the 409
|
|
448
|
+
* itself, which carries no evidence. A 409 with no such receipt is a duplicate
|
|
449
|
+
* we cannot account for, and fabricating one from a Location header would mean
|
|
450
|
+
* filing evidence about bytes we never saw (delta D1), so it rejects and the
|
|
451
|
+
* outbox keeps the record for a human.
|
|
452
|
+
*/
|
|
453
|
+
export function rekorSink(rootDir, url = DEFAULT_REKOR_URL, transport = httpTransport) {
|
|
454
|
+
// Same rule as the S3 sink, applied at CONSTRUCTION so a plaintext log URL
|
|
455
|
+
// fails before a record is ever offered to it.
|
|
456
|
+
parseEndpoint(url, "rekor sink");
|
|
457
|
+
const base = url.replace(/\/+$/, "");
|
|
458
|
+
return {
|
|
459
|
+
name: `rekor:${base}`,
|
|
460
|
+
publish: async (record) => {
|
|
461
|
+
const identity = readAnchorIdentity(rootDir);
|
|
462
|
+
if (identity === null) {
|
|
463
|
+
throw new Error("rekor sink: no anchor identity — run `usertrust anchor init` first");
|
|
464
|
+
}
|
|
465
|
+
const proposal = Buffer.from(buildHashedRekordEntry(record, spkiForRecord(identity, record)), "utf8");
|
|
466
|
+
const res = await transport({
|
|
467
|
+
method: "POST",
|
|
468
|
+
url: `${base}${REKOR_ENTRIES_PATH}`,
|
|
469
|
+
headers: {
|
|
470
|
+
accept: "application/json",
|
|
471
|
+
"content-type": "application/json",
|
|
472
|
+
},
|
|
473
|
+
body: proposal,
|
|
474
|
+
});
|
|
475
|
+
if (res.status === 409) {
|
|
476
|
+
if (findBindingReceipt(rootDir, record, base))
|
|
477
|
+
return;
|
|
478
|
+
throw new Error("rekor sink: HTTP 409 (duplicate without local receipt — fetch the entry manually)");
|
|
479
|
+
}
|
|
480
|
+
if (res.status !== 201) {
|
|
481
|
+
throw new Error(`rekor sink: HTTP ${res.status}${snippet(res.body)}`);
|
|
482
|
+
}
|
|
483
|
+
const { entry, error } = parseAcceptedEntry(res.body);
|
|
484
|
+
if (entry === null) {
|
|
485
|
+
throw new Error(`rekor sink: invalid 201 response: ${error}`);
|
|
486
|
+
}
|
|
487
|
+
// A well-formed 201 is not yet OUR 201: the receipt is built from the
|
|
488
|
+
// log's bytes, so a response describing somebody else's entry would be
|
|
489
|
+
// persisted as evidence for this record and only fall apart at audit
|
|
490
|
+
// time. Bind it to the record before trusting a single field of it.
|
|
491
|
+
if (!entryBindsRecord(entry.body, record)) {
|
|
492
|
+
throw new Error("rekor sink: 201 response describes an entry that is not this record's " +
|
|
493
|
+
"(payload hash or signature mismatch)");
|
|
494
|
+
}
|
|
495
|
+
writeReceipt(rootDir, {
|
|
496
|
+
v: 1,
|
|
497
|
+
vaultId: record.vaultId,
|
|
498
|
+
anchorSeq: record.anchorSeq,
|
|
499
|
+
artifactHash: anchorPayloadHash(record),
|
|
500
|
+
// VERBATIM (delta D13): the leaf hash is over the bytes the LOG
|
|
501
|
+
// stored, so any reserialization here would break inclusion.
|
|
502
|
+
entryBody: entry.body,
|
|
503
|
+
log: {
|
|
504
|
+
url: base,
|
|
505
|
+
logIndex: entry.logIndex,
|
|
506
|
+
treeSize: entry.treeSize,
|
|
507
|
+
rootHash: entry.rootHash,
|
|
508
|
+
hashes: entry.hashes,
|
|
509
|
+
checkpoint: entry.checkpoint,
|
|
510
|
+
integratedTime: entry.integratedTime,
|
|
511
|
+
...(entry.signedEntryTimestamp !== undefined
|
|
512
|
+
? { signedEntryTimestamp: entry.signedEntryTimestamp }
|
|
513
|
+
: {}),
|
|
514
|
+
...(entry.logID !== undefined ? { logID: entry.logID } : {}),
|
|
515
|
+
},
|
|
516
|
+
});
|
|
517
|
+
},
|
|
518
|
+
};
|
|
519
|
+
}
|
|
520
|
+
// ── Default transport ──
|
|
521
|
+
/** The module's only network access. `http://` is reachable for dev endpoints. */
|
|
522
|
+
async function httpTransport(opts) {
|
|
523
|
+
const { request } = await (opts.url.startsWith("http://")
|
|
524
|
+
? import("node:http")
|
|
525
|
+
: import("node:https"));
|
|
526
|
+
return new Promise((resolve, reject) => {
|
|
527
|
+
const req = request(opts.url, {
|
|
528
|
+
method: opts.method,
|
|
529
|
+
headers: { ...opts.headers, "content-length": String(opts.body.length) },
|
|
530
|
+
timeout: 15_000,
|
|
531
|
+
}, (res) => {
|
|
532
|
+
const chunks = [];
|
|
533
|
+
res.on("data", (c) => chunks.push(c));
|
|
534
|
+
res.on("end", () => {
|
|
535
|
+
const headers = {};
|
|
536
|
+
for (const [name, value] of Object.entries(res.headers)) {
|
|
537
|
+
if (typeof value === "string")
|
|
538
|
+
headers[name] = value;
|
|
539
|
+
}
|
|
540
|
+
resolve({
|
|
541
|
+
status: res.statusCode ?? 0,
|
|
542
|
+
// Bounded: a receipt is small, and an error body is only ever
|
|
543
|
+
// a snippet.
|
|
544
|
+
body: Buffer.concat(chunks)
|
|
545
|
+
.toString("utf8")
|
|
546
|
+
.slice(0, 256 * 1024),
|
|
547
|
+
headers,
|
|
548
|
+
});
|
|
549
|
+
});
|
|
550
|
+
});
|
|
551
|
+
req.on("timeout", () => req.destroy(new Error("anchor sink: request timeout")));
|
|
552
|
+
req.on("error", reject);
|
|
553
|
+
req.end(opts.body);
|
|
554
|
+
});
|
|
555
|
+
}
|
|
556
|
+
//# sourceMappingURL=rekor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rekor.js","sourceRoot":"","sources":["../../src/audit/rekor.ts"],"names":[],"mappings":"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"}
|
package/dist/audit/rotation.js
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*
|
|
10
10
|
* Structure: .usertrust/audit/<kind>/<YYYY-MM-DD>/<receiptId>.json
|
|
11
11
|
*/
|
|
12
|
-
import { existsSync, mkdirSync,
|
|
12
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
13
13
|
import { join } from "node:path";
|
|
14
14
|
import { AUDIT_DIR, RECEIPT_VERSION, VAULT_DIR } from "../shared/constants.js";
|
|
15
15
|
import { trustId } from "../shared/ids.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rotation.js","sourceRoot":"","sources":["../../src/audit/rotation.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,iCAAiC;AAEjC;;;;;;;;GAQG;AAEH,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,
|
|
1
|
+
{"version":3,"file":"rotation.js","sourceRoot":"","sources":["../../src/audit/rotation.ts"],"names":[],"mappings":"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"}
|