@actuarial-ts/compliance 0.6.1 → 0.7.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 +6 -2
- package/dist/diagnosticArtifactStream.d.ts +30 -0
- package/dist/diagnosticArtifactStream.d.ts.map +1 -0
- package/dist/diagnosticArtifactStream.js +128 -0
- package/dist/diagnosticArtifactStream.js.map +1 -0
- package/dist/diagnosticByteSource.d.ts +10 -0
- package/dist/diagnosticByteSource.d.ts.map +1 -0
- package/dist/diagnosticByteSource.js +70 -0
- package/dist/diagnosticByteSource.js.map +1 -0
- package/dist/diagnosticByteView.d.ts +3 -0
- package/dist/diagnosticByteView.d.ts.map +1 -0
- package/dist/diagnosticByteView.js +27 -0
- package/dist/diagnosticByteView.js.map +1 -0
- package/dist/diagnosticCompactRun.d.ts +43 -0
- package/dist/diagnosticCompactRun.d.ts.map +1 -0
- package/dist/diagnosticCompactRun.js +253 -0
- package/dist/diagnosticCompactRun.js.map +1 -0
- package/dist/diagnosticReplayFrames.d.ts +10 -0
- package/dist/diagnosticReplayFrames.d.ts.map +1 -0
- package/dist/diagnosticReplayFrames.js +99 -0
- package/dist/diagnosticReplayFrames.js.map +1 -0
- package/dist/diagnosticReplayProtocol.d.ts +17 -0
- package/dist/diagnosticReplayProtocol.d.ts.map +1 -0
- package/dist/diagnosticReplayProtocol.js +98 -0
- package/dist/diagnosticReplayProtocol.js.map +1 -0
- package/dist/diagnosticReplayReader.d.ts +41 -0
- package/dist/diagnosticReplayReader.d.ts.map +1 -0
- package/dist/diagnosticReplayReader.js +346 -0
- package/dist/diagnosticReplayReader.js.map +1 -0
- package/dist/diagnosticReplayValue.d.ts +34 -0
- package/dist/diagnosticReplayValue.d.ts.map +1 -0
- package/dist/diagnosticReplayValue.js +269 -0
- package/dist/diagnosticReplayValue.js.map +1 -0
- package/dist/diagnosticReplayWriter.d.ts +25 -0
- package/dist/diagnosticReplayWriter.d.ts.map +1 -0
- package/dist/diagnosticReplayWriter.js +148 -0
- package/dist/diagnosticReplayWriter.js.map +1 -0
- package/dist/diagnosticRun.d.ts.map +1 -1
- package/dist/diagnosticRun.js +1 -193
- package/dist/diagnosticRun.js.map +1 -1
- package/dist/diagnosticRunEvidence.d.ts +18 -0
- package/dist/diagnosticRunEvidence.d.ts.map +1 -0
- package/dist/diagnosticRunEvidence.js +195 -0
- package/dist/diagnosticRunEvidence.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/sha256Stream.d.ts +6 -0
- package/dist/sha256Stream.d.ts.map +1 -0
- package/dist/sha256Stream.js +103 -0
- package/dist/sha256Stream.js.map +1 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +4 -4
- package/src/diagnosticArtifactStream.ts +148 -0
- package/src/diagnosticByteSource.ts +82 -0
- package/src/diagnosticByteView.ts +27 -0
- package/src/diagnosticCompactRun.ts +462 -0
- package/src/diagnosticReplayFrames.ts +99 -0
- package/src/diagnosticReplayProtocol.ts +99 -0
- package/src/diagnosticReplayReader.ts +428 -0
- package/src/diagnosticReplayValue.ts +269 -0
- package/src/diagnosticReplayWriter.ts +190 -0
- package/src/diagnosticRun.ts +7 -373
- package/src/diagnosticRunEvidence.ts +391 -0
- package/src/index.ts +10 -0
- package/src/sha256Stream.ts +108 -0
- package/src/version.ts +1 -1
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
import { iterateDiagnosticIdentityJson } from "@actuarial-ts/core";
|
|
2
|
+
import { runValidatedMetricDiagnosticsCompact, validateDiagnosticRunInputCompact, } from "@actuarial-ts/data";
|
|
3
|
+
import { digestDiagnosticArtifactChunks } from "./diagnosticArtifactStream.js";
|
|
4
|
+
import { createCompactDiagnosticRunIdentity, } from "./diagnosticCompactRun.js";
|
|
5
|
+
import { diagnosticByteView } from "./diagnosticByteView.js";
|
|
6
|
+
import { consumeDiagnosticByteSource } from "./diagnosticByteSource.js";
|
|
7
|
+
import { decodeReplayFrames, MAX_REPLAY_READ_BYTES, REPLAY_TEXT_UNITS, } from "./diagnosticReplayFrames.js";
|
|
8
|
+
import { ReplayValueBuilder } from "./diagnosticReplayValue.js";
|
|
9
|
+
import { createSha256 } from "./sha256Stream.js";
|
|
10
|
+
import { REPLAY_FORMAT, REPLAY_VERSION, badReplay, mismatch, replayArray, replayCancellation, replayFrameBytes, replayLimit, replayRecord, replayToken, decodeArtifactChunk, } from "./diagnosticReplayProtocol.js";
|
|
11
|
+
const verifiedStreams = new WeakSet();
|
|
12
|
+
class ReplayCursor {
|
|
13
|
+
iterator;
|
|
14
|
+
checkCancellation;
|
|
15
|
+
sequence = 0;
|
|
16
|
+
hash = createSha256();
|
|
17
|
+
constructor(iterator, checkCancellation) {
|
|
18
|
+
this.iterator = iterator;
|
|
19
|
+
this.checkCancellation = checkCancellation;
|
|
20
|
+
}
|
|
21
|
+
async next() {
|
|
22
|
+
this.checkCancellation();
|
|
23
|
+
const item = await this.iterator.next();
|
|
24
|
+
this.checkCancellation();
|
|
25
|
+
if (item.done)
|
|
26
|
+
badReplay("Replay ended before its required trailer or section boundary");
|
|
27
|
+
const frame = item.value;
|
|
28
|
+
if (frame.length < 2 ||
|
|
29
|
+
frame[0] !== this.sequence ||
|
|
30
|
+
!Number.isSafeInteger(frame[0]) ||
|
|
31
|
+
typeof frame[1] !== "string")
|
|
32
|
+
badReplay("Replay frame has an invalid sequence or event");
|
|
33
|
+
this.sequence++;
|
|
34
|
+
if (frame[1] !== "end")
|
|
35
|
+
this.hash.update(replayFrameBytes(frame));
|
|
36
|
+
return frame.slice(1);
|
|
37
|
+
}
|
|
38
|
+
digest() {
|
|
39
|
+
return this.hash.digest();
|
|
40
|
+
}
|
|
41
|
+
async requireEof() {
|
|
42
|
+
this.checkCancellation();
|
|
43
|
+
if (!(await this.iterator.next()).done)
|
|
44
|
+
badReplay("Unexpected frames after the replay trailer");
|
|
45
|
+
this.checkCancellation();
|
|
46
|
+
}
|
|
47
|
+
async close() {
|
|
48
|
+
await this.iterator.return(undefined);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
function event(frame, name, arity) {
|
|
52
|
+
if (frame[0] !== name || frame.length !== arity)
|
|
53
|
+
badReplay(`Expected ${name} with exact arity ${arity}`);
|
|
54
|
+
}
|
|
55
|
+
async function readValue(cursor, ending, limits) {
|
|
56
|
+
const builder = new ReplayValueBuilder(limits);
|
|
57
|
+
for (;;) {
|
|
58
|
+
const frame = await cursor.next();
|
|
59
|
+
if (frame[0] === ending) {
|
|
60
|
+
event(frame, ending, 1);
|
|
61
|
+
return builder.finish();
|
|
62
|
+
}
|
|
63
|
+
builder.push(frame);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/** Compare complete expected canonical text with bounded candidate fragments. */
|
|
67
|
+
async function compareEvidence(cursor, channel, document) {
|
|
68
|
+
const expected = iterateDiagnosticIdentityJson(document);
|
|
69
|
+
let chunk = "", index = 0, position = 0, done = false;
|
|
70
|
+
function advance() {
|
|
71
|
+
while (!done && index === chunk.length) {
|
|
72
|
+
const item = expected.next();
|
|
73
|
+
done = Boolean(item.done);
|
|
74
|
+
chunk = item.done ? "" : item.value;
|
|
75
|
+
index = 0;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
try {
|
|
79
|
+
for (;;) {
|
|
80
|
+
const frame = await cursor.next();
|
|
81
|
+
if (frame[0] === `${channel}-end`) {
|
|
82
|
+
event(frame, `${channel}-end`, 1);
|
|
83
|
+
advance();
|
|
84
|
+
if (!done)
|
|
85
|
+
mismatch(`${channel} evidence is truncated at code-unit offset ${position}`);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
event(frame, channel, 2);
|
|
89
|
+
const text = frame[1];
|
|
90
|
+
if (typeof text !== "string" || text.length === 0 || text.length > REPLAY_TEXT_UNITS)
|
|
91
|
+
badReplay("Invalid bounded canonical evidence fragment");
|
|
92
|
+
let start = 0;
|
|
93
|
+
while (start < text.length) {
|
|
94
|
+
advance();
|
|
95
|
+
if (done)
|
|
96
|
+
mismatch(`${channel} evidence has extra content at code-unit offset ${position}`);
|
|
97
|
+
const length = Math.min(text.length - start, chunk.length - index);
|
|
98
|
+
for (let offset = 0; offset < length; offset++)
|
|
99
|
+
if (text.charCodeAt(start + offset) !== chunk.charCodeAt(index + offset))
|
|
100
|
+
mismatch(`${channel} evidence differs at code-unit offset ${position + offset}`);
|
|
101
|
+
start += length;
|
|
102
|
+
index += length;
|
|
103
|
+
position += length;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
finally {
|
|
108
|
+
expected.return(undefined);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
function artifactMetadata(value) {
|
|
112
|
+
const item = replayRecord(value, [
|
|
113
|
+
"id",
|
|
114
|
+
"scope",
|
|
115
|
+
"assurance",
|
|
116
|
+
"algorithm",
|
|
117
|
+
"value",
|
|
118
|
+
"byteLength",
|
|
119
|
+
]);
|
|
120
|
+
const id = replayToken(item.id);
|
|
121
|
+
if (item.scope !== "input" && item.scope !== "preparation")
|
|
122
|
+
badReplay("Invalid artifact scope");
|
|
123
|
+
const scope = item.scope;
|
|
124
|
+
if (item.assurance === "caller-declared") {
|
|
125
|
+
if (Object.hasOwn(item, "byteLength"))
|
|
126
|
+
badReplay("Declared artifact cannot claim a computed byte length");
|
|
127
|
+
return Object.freeze({
|
|
128
|
+
id,
|
|
129
|
+
scope,
|
|
130
|
+
assurance: "caller-declared",
|
|
131
|
+
algorithm: replayToken(item.algorithm),
|
|
132
|
+
value: replayToken(item.value),
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
if (item.assurance !== "sdk-computed" ||
|
|
136
|
+
item.algorithm !== "sha256" ||
|
|
137
|
+
typeof item.value !== "string" ||
|
|
138
|
+
!/^[a-f0-9]{64}$/.test(item.value) ||
|
|
139
|
+
typeof item.byteLength !== "number" ||
|
|
140
|
+
!Number.isSafeInteger(item.byteLength) ||
|
|
141
|
+
item.byteLength < 0)
|
|
142
|
+
badReplay("Invalid computed artifact digest metadata");
|
|
143
|
+
return Object.freeze({
|
|
144
|
+
id,
|
|
145
|
+
scope,
|
|
146
|
+
assurance: "sdk-computed",
|
|
147
|
+
algorithm: "sha256",
|
|
148
|
+
value: item.value,
|
|
149
|
+
byteLength: item.byteLength,
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
async function readArtifact(cursor, inputLimits, maximumArtifactBytes) {
|
|
153
|
+
const artifact = artifactMetadata(await readValue(cursor, "artifact-data", inputLimits));
|
|
154
|
+
if (artifact.assurance === "caller-declared") {
|
|
155
|
+
event(await cursor.next(), "artifact-end", 1);
|
|
156
|
+
return artifact;
|
|
157
|
+
}
|
|
158
|
+
async function* bytes() {
|
|
159
|
+
for (;;) {
|
|
160
|
+
const frame = await cursor.next();
|
|
161
|
+
if (frame[0] === "artifact-end") {
|
|
162
|
+
event(frame, "artifact-end", 1);
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
event(frame, "bytes", 2);
|
|
166
|
+
yield decodeArtifactChunk(frame[1]);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
const computed = await digestDiagnosticArtifactChunks({
|
|
170
|
+
id: artifact.id,
|
|
171
|
+
scope: artifact.scope,
|
|
172
|
+
expectedByteLength: artifact.byteLength,
|
|
173
|
+
maximumByteLength: maximumArtifactBytes,
|
|
174
|
+
}, bytes());
|
|
175
|
+
if (computed.value !== artifact.value)
|
|
176
|
+
mismatch(`Artifact ${artifact.id} bytes do not match its digest`);
|
|
177
|
+
return computed;
|
|
178
|
+
}
|
|
179
|
+
async function readRun(cursor, artifacts, used, limits) {
|
|
180
|
+
const item = replayRecord(await readValue(cursor, "input-end", limits), [
|
|
181
|
+
"id",
|
|
182
|
+
"input",
|
|
183
|
+
"inputArtifactIds",
|
|
184
|
+
"preparationArtifactIds",
|
|
185
|
+
"preparationLineage",
|
|
186
|
+
]);
|
|
187
|
+
const id = replayToken(item.id);
|
|
188
|
+
function resolve(value, scope) {
|
|
189
|
+
const seen = new Set();
|
|
190
|
+
return replayArray(value).map((key) => {
|
|
191
|
+
const token = replayToken(key);
|
|
192
|
+
if (seen.has(token))
|
|
193
|
+
badReplay("Duplicate artifact reference in replay run");
|
|
194
|
+
seen.add(token);
|
|
195
|
+
const artifact = artifacts.get(token);
|
|
196
|
+
if (!artifact || artifact.scope !== scope)
|
|
197
|
+
badReplay("Replay references an absent artifact or the wrong scope");
|
|
198
|
+
used.add(token);
|
|
199
|
+
return artifact;
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
const inputArtifacts = resolve(item.inputArtifactIds, "input");
|
|
203
|
+
const preparationArtifacts = resolve(item.preparationArtifactIds, "preparation");
|
|
204
|
+
// Candidate raw input always crosses the complete SDK schema, ownership,
|
|
205
|
+
// preparation and execution-policy boundaries. Parsing does not grant trust.
|
|
206
|
+
const completedRun = runValidatedMetricDiagnosticsCompact(validateDiagnosticRunInputCompact(item.input));
|
|
207
|
+
if (completedRun.status !== "completed")
|
|
208
|
+
mismatch(`Replay run ${id} is blocked at ${completedRun.stage}`);
|
|
209
|
+
const provenance = createCompactDiagnosticRunIdentity({
|
|
210
|
+
completedRun,
|
|
211
|
+
inputArtifacts,
|
|
212
|
+
preparationArtifacts,
|
|
213
|
+
preparationLineage: item.preparationLineage,
|
|
214
|
+
});
|
|
215
|
+
await compareEvidence(cursor, "manifest", provenance.manifestIdentityDocument);
|
|
216
|
+
await compareEvidence(cursor, "result", provenance.resultIdentityDocument);
|
|
217
|
+
const end = await cursor.next();
|
|
218
|
+
event(end, "run-end", 4);
|
|
219
|
+
if (end[1] !== provenance.runFingerprint ||
|
|
220
|
+
end[2] !== provenance.resultFingerprint ||
|
|
221
|
+
end[3] !== provenance.runResultFingerprint)
|
|
222
|
+
mismatch("Replayed fingerprint tags do not match the full verified evidence");
|
|
223
|
+
return Object.freeze({
|
|
224
|
+
id,
|
|
225
|
+
runFingerprint: provenance.runFingerprint,
|
|
226
|
+
resultFingerprint: provenance.resultFingerprint,
|
|
227
|
+
runResultFingerprint: provenance.runResultFingerprint,
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Verify all bytes/evidence and independently replay every run, sequentially.
|
|
232
|
+
* Reads must be <=128 KiB. Required resource limits apply before retaining raw
|
|
233
|
+
* inputs; results/audits are compared as text, never reconstructed from a file.
|
|
234
|
+
* Only a final receipt is returned after trailer integrity AND EOF. Hosts must
|
|
235
|
+
* not treat a partially consumed stream as a valid archive. Cancellation is
|
|
236
|
+
* cooperative between chunks/phases; use the signal for host I/O as well.
|
|
237
|
+
*/
|
|
238
|
+
export function verifyDiagnosticReplayStream(chunks, supplied) {
|
|
239
|
+
const options = replayRecord(supplied, ["limits", "signal"]);
|
|
240
|
+
const fields = [
|
|
241
|
+
"maximumEncodedBytes",
|
|
242
|
+
"maximumArtifacts",
|
|
243
|
+
"maximumRuns",
|
|
244
|
+
"maximumArtifactBytes",
|
|
245
|
+
"maximumInputDepth",
|
|
246
|
+
"maximumInputNodes",
|
|
247
|
+
"maximumInputStringUnits",
|
|
248
|
+
"maximumInputTotalStringUnits",
|
|
249
|
+
];
|
|
250
|
+
const raw = replayRecord(options.limits, fields);
|
|
251
|
+
const limits = Object.fromEntries(fields.map((key) => [key, replayLimit(raw[key], key)]));
|
|
252
|
+
const inputLimits = {
|
|
253
|
+
maximumDepth: limits.maximumInputDepth,
|
|
254
|
+
maximumNodes: limits.maximumInputNodes,
|
|
255
|
+
maximumStringUnits: limits.maximumInputStringUnits,
|
|
256
|
+
maximumTotalStringUnits: limits.maximumInputTotalStringUnits,
|
|
257
|
+
};
|
|
258
|
+
const checkCancellation = replayCancellation(options.signal);
|
|
259
|
+
checkCancellation();
|
|
260
|
+
async function* bounded() {
|
|
261
|
+
let size = 0;
|
|
262
|
+
for await (const chunk of consumeDiagnosticByteSource(chunks, checkCancellation)) {
|
|
263
|
+
checkCancellation();
|
|
264
|
+
const view = diagnosticByteView(chunk);
|
|
265
|
+
if (view.length > MAX_REPLAY_READ_BYTES)
|
|
266
|
+
badReplay("Replay reads must be at most 128 KiB");
|
|
267
|
+
if (view.length > limits.maximumEncodedBytes - size)
|
|
268
|
+
badReplay("Replay exceeds the encoded byte limit");
|
|
269
|
+
size += view.length;
|
|
270
|
+
yield new Uint8Array(view);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
async function verify() {
|
|
274
|
+
const cursor = new ReplayCursor(decodeReplayFrames(bounded()), checkCancellation);
|
|
275
|
+
let failed = false;
|
|
276
|
+
try {
|
|
277
|
+
const header = await cursor.next();
|
|
278
|
+
event(header, REPLAY_FORMAT, 2);
|
|
279
|
+
if (header[1] !== REPLAY_VERSION)
|
|
280
|
+
badReplay("Unsupported diagnostic replay version");
|
|
281
|
+
const artifacts = new Map();
|
|
282
|
+
let frame = await cursor.next();
|
|
283
|
+
while (frame[0] === "artifact") {
|
|
284
|
+
event(frame, "artifact", 1);
|
|
285
|
+
if (artifacts.size >= limits.maximumArtifacts)
|
|
286
|
+
badReplay("Replay exceeds its artifact count limit");
|
|
287
|
+
const artifact = await readArtifact(cursor, inputLimits, limits.maximumArtifactBytes);
|
|
288
|
+
if (artifacts.has(artifact.id))
|
|
289
|
+
badReplay("Duplicate artifact ID in replay archive");
|
|
290
|
+
artifacts.set(artifact.id, artifact);
|
|
291
|
+
frame = await cursor.next();
|
|
292
|
+
}
|
|
293
|
+
const runs = [];
|
|
294
|
+
const runIds = new Set(), used = new Set();
|
|
295
|
+
while (frame[0] === "run") {
|
|
296
|
+
event(frame, "run", 1);
|
|
297
|
+
if (runs.length >= limits.maximumRuns)
|
|
298
|
+
badReplay("Replay exceeds its run count limit");
|
|
299
|
+
const run = await readRun(cursor, artifacts, used, inputLimits);
|
|
300
|
+
if (runIds.has(run.id))
|
|
301
|
+
badReplay("Duplicate run ID in replay archive");
|
|
302
|
+
runIds.add(run.id);
|
|
303
|
+
runs.push(run);
|
|
304
|
+
frame = await cursor.next();
|
|
305
|
+
}
|
|
306
|
+
event(frame, "end", 4);
|
|
307
|
+
if (!runs.length ||
|
|
308
|
+
frame[1] !== artifacts.size ||
|
|
309
|
+
frame[2] !== runs.length ||
|
|
310
|
+
used.size !== artifacts.size)
|
|
311
|
+
badReplay("Replay trailer counts, run presence or artifact ownership are invalid");
|
|
312
|
+
const frameDigest = cursor.digest();
|
|
313
|
+
if (frame[3] !== frameDigest)
|
|
314
|
+
mismatch("Replay frame integrity digest does not match");
|
|
315
|
+
await cursor.requireEof();
|
|
316
|
+
const receipt = Object.freeze({
|
|
317
|
+
format: REPLAY_FORMAT,
|
|
318
|
+
version: REPLAY_VERSION,
|
|
319
|
+
artifacts: Object.freeze([...artifacts.values()]),
|
|
320
|
+
runs: Object.freeze(runs),
|
|
321
|
+
frameDigest,
|
|
322
|
+
});
|
|
323
|
+
verifiedStreams.add(receipt);
|
|
324
|
+
return receipt;
|
|
325
|
+
}
|
|
326
|
+
catch (error) {
|
|
327
|
+
failed = true;
|
|
328
|
+
throw error;
|
|
329
|
+
}
|
|
330
|
+
finally {
|
|
331
|
+
try {
|
|
332
|
+
await cursor.close();
|
|
333
|
+
}
|
|
334
|
+
catch (cleanupError) {
|
|
335
|
+
if (!failed)
|
|
336
|
+
throw cleanupError;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
return verify();
|
|
341
|
+
}
|
|
342
|
+
export function assertVerifiedDiagnosticReplayStream(value) {
|
|
343
|
+
if (value === null || typeof value !== "object" || !verifiedStreams.has(value))
|
|
344
|
+
badReplay("Value is not an authentic fully verified replay stream receipt");
|
|
345
|
+
}
|
|
346
|
+
//# sourceMappingURL=diagnosticReplayReader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diagnosticReplayReader.js","sourceRoot":"","sources":["../src/diagnosticReplayReader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { type ReplayFrame } from "./diagnosticReplayFrames.js";
|
|
2
|
+
export interface ReplayValueLimits {
|
|
3
|
+
readonly maximumDepth: number;
|
|
4
|
+
readonly maximumNodes: number;
|
|
5
|
+
/** Maximum UTF-16 code units in one key or string value. */
|
|
6
|
+
readonly maximumStringUnits: number;
|
|
7
|
+
/** Maximum UTF-16 code units across every key and string value in this input. */
|
|
8
|
+
readonly maximumTotalStringUnits: number;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Reconstruct input only, within explicit host resource bounds. Reconstructed
|
|
12
|
+
* values still require full SDK validation. Never use this for candidate
|
|
13
|
+
* result/audit identity channels: those must be compared as text streams.
|
|
14
|
+
*/
|
|
15
|
+
export declare class ReplayValueBuilder {
|
|
16
|
+
private readonly limits;
|
|
17
|
+
private readonly stack;
|
|
18
|
+
private nodes;
|
|
19
|
+
private assigned;
|
|
20
|
+
private root;
|
|
21
|
+
private stringParts;
|
|
22
|
+
private stringUnits;
|
|
23
|
+
private totalStringUnits;
|
|
24
|
+
private stringKind;
|
|
25
|
+
private sealed;
|
|
26
|
+
constructor(limits: ReplayValueLimits);
|
|
27
|
+
private attach;
|
|
28
|
+
push(frame: ReplayFrame): void;
|
|
29
|
+
private consume;
|
|
30
|
+
finish(): unknown;
|
|
31
|
+
}
|
|
32
|
+
/** Live read-only input events. The enclosing genuine run owns its snapshots. */
|
|
33
|
+
export declare function replayValueFrames(value: unknown): Generator<ReplayFrame>;
|
|
34
|
+
//# sourceMappingURL=diagnosticReplayValue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diagnosticReplayValue.d.ts","sourceRoot":"","sources":["../src/diagnosticReplayValue.ts"],"names":[],"mappings":"AACA,OAAO,EAAqB,KAAK,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAElF,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,4DAA4D;IAC5D,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,iFAAiF;IACjF,QAAQ,CAAC,uBAAuB,EAAE,MAAM,CAAC;CAC1C;AAsCD;;;;GAIG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAoB;IAC3C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAmB;IACzC,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,IAAI,CAAU;IACtB,OAAO,CAAC,WAAW,CAAyB;IAC5C,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,gBAAgB,CAAK;IAC7B,OAAO,CAAC,UAAU,CAAgC;IAClD,OAAO,CAAC,MAAM,CAAS;gBAEX,MAAM,EAAE,iBAAiB;IAGrC,OAAO,CAAC,MAAM;IAmBd,IAAI,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI;IAS9B,OAAO,CAAC,OAAO;IA4Ff,MAAM,IAAI,OAAO;CAOlB;AAED,iFAAiF;AACjF,wBAAiB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,SAAS,CAAC,WAAW,CAAC,CAsEzE"}
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
import { ComplianceError } from "./errors.js";
|
|
2
|
+
import { REPLAY_TEXT_UNITS } from "./diagnosticReplayFrames.js";
|
|
3
|
+
function invalid(message) {
|
|
4
|
+
throw new ComplianceError("BAD_DIAGNOSTIC_RUN", message, "$.replayInput");
|
|
5
|
+
}
|
|
6
|
+
function snapshotLimits(limits) {
|
|
7
|
+
if (limits === null ||
|
|
8
|
+
typeof limits !== "object" ||
|
|
9
|
+
(Object.getPrototypeOf(limits) !== Object.prototype && Object.getPrototypeOf(limits) !== null))
|
|
10
|
+
invalid("Replay value limits must be a plain data object");
|
|
11
|
+
const fields = [
|
|
12
|
+
"maximumDepth",
|
|
13
|
+
"maximumNodes",
|
|
14
|
+
"maximumStringUnits",
|
|
15
|
+
"maximumTotalStringUnits",
|
|
16
|
+
];
|
|
17
|
+
const descriptors = Object.getOwnPropertyDescriptors(limits);
|
|
18
|
+
for (const key of Reflect.ownKeys(descriptors))
|
|
19
|
+
if (typeof key !== "string" || !fields.some((field) => field === key))
|
|
20
|
+
invalid("Unknown replay value limit");
|
|
21
|
+
const owned = Object.create(null);
|
|
22
|
+
for (const key of fields) {
|
|
23
|
+
const field = descriptors[key];
|
|
24
|
+
if (!field || !field.enumerable || !("value" in field))
|
|
25
|
+
invalid("Replay value limits require own enumerable data properties");
|
|
26
|
+
const value = field.value;
|
|
27
|
+
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 1)
|
|
28
|
+
invalid("Replay value limits must be positive safe integers");
|
|
29
|
+
owned[key] = value;
|
|
30
|
+
}
|
|
31
|
+
return Object.freeze(owned);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Reconstruct input only, within explicit host resource bounds. Reconstructed
|
|
35
|
+
* values still require full SDK validation. Never use this for candidate
|
|
36
|
+
* result/audit identity channels: those must be compared as text streams.
|
|
37
|
+
*/
|
|
38
|
+
export class ReplayValueBuilder {
|
|
39
|
+
limits;
|
|
40
|
+
stack = [];
|
|
41
|
+
nodes = 0;
|
|
42
|
+
assigned = false;
|
|
43
|
+
root;
|
|
44
|
+
stringParts = null;
|
|
45
|
+
stringUnits = 0;
|
|
46
|
+
totalStringUnits = 0;
|
|
47
|
+
stringKind = null;
|
|
48
|
+
sealed = false;
|
|
49
|
+
constructor(limits) {
|
|
50
|
+
this.limits = snapshotLimits(limits);
|
|
51
|
+
}
|
|
52
|
+
attach(value) {
|
|
53
|
+
if (++this.nodes > this.limits.maximumNodes)
|
|
54
|
+
invalid("Replay input exceeds its node limit");
|
|
55
|
+
const parent = this.stack.at(-1);
|
|
56
|
+
if (!parent) {
|
|
57
|
+
if (this.assigned)
|
|
58
|
+
invalid("Multiple roots in replay input");
|
|
59
|
+
this.root = value;
|
|
60
|
+
this.assigned = true;
|
|
61
|
+
}
|
|
62
|
+
else if (parent.kind === "array")
|
|
63
|
+
parent.value.push(value);
|
|
64
|
+
else {
|
|
65
|
+
if (parent.key === null)
|
|
66
|
+
invalid("Object value is missing its key");
|
|
67
|
+
Object.defineProperty(parent.value, parent.key, {
|
|
68
|
+
value,
|
|
69
|
+
enumerable: true,
|
|
70
|
+
writable: true,
|
|
71
|
+
configurable: true,
|
|
72
|
+
});
|
|
73
|
+
parent.key = null;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
push(frame) {
|
|
77
|
+
if (this.sealed)
|
|
78
|
+
invalid("Replay input builder is finalized");
|
|
79
|
+
try {
|
|
80
|
+
this.consume(frame);
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
this.sealed = true;
|
|
84
|
+
throw error;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
consume(frame) {
|
|
88
|
+
if (!Array.isArray(frame))
|
|
89
|
+
invalid("Replay value event must be an array");
|
|
90
|
+
const [event, payload] = frame;
|
|
91
|
+
const arity = (expected) => {
|
|
92
|
+
if (frame.length !== expected)
|
|
93
|
+
invalid("Invalid replay value event arity");
|
|
94
|
+
};
|
|
95
|
+
if (this.stringParts !== null) {
|
|
96
|
+
if (event === "text") {
|
|
97
|
+
arity(2);
|
|
98
|
+
if (typeof payload !== "string" ||
|
|
99
|
+
payload.length === 0 ||
|
|
100
|
+
payload.length > REPLAY_TEXT_UNITS)
|
|
101
|
+
invalid("Invalid replay text fragment");
|
|
102
|
+
if (payload.length > this.limits.maximumStringUnits - this.stringUnits)
|
|
103
|
+
invalid("Replay input exceeds its string limit");
|
|
104
|
+
if (payload.length > this.limits.maximumTotalStringUnits - this.totalStringUnits)
|
|
105
|
+
invalid("Replay input exceeds its total string limit");
|
|
106
|
+
// Check both budgets before retaining this fragment. Key text counts,
|
|
107
|
+
// and starting another string never resets the whole-input budget.
|
|
108
|
+
this.stringUnits += payload.length;
|
|
109
|
+
this.totalStringUnits += payload.length;
|
|
110
|
+
this.stringParts.push(payload);
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
if (event !== "string-end")
|
|
114
|
+
invalid("Replay string was not terminated");
|
|
115
|
+
arity(1);
|
|
116
|
+
const text = this.stringParts.join("");
|
|
117
|
+
const kind = this.stringKind;
|
|
118
|
+
this.stringParts = null;
|
|
119
|
+
this.stringKind = null;
|
|
120
|
+
if (kind === "value")
|
|
121
|
+
this.attach(text);
|
|
122
|
+
else {
|
|
123
|
+
const parent = this.stack.at(-1);
|
|
124
|
+
if (!parent || parent.kind !== "object" || parent.key !== null)
|
|
125
|
+
invalid("Unexpected replay object key");
|
|
126
|
+
if (parent.lastKey !== null && text <= parent.lastKey)
|
|
127
|
+
invalid("Replay object keys must be strictly increasing and unique");
|
|
128
|
+
parent.lastKey = text;
|
|
129
|
+
parent.key = text;
|
|
130
|
+
}
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
if (event === "string-start") {
|
|
134
|
+
arity(2);
|
|
135
|
+
if (payload !== "key" && payload !== "value")
|
|
136
|
+
invalid("Invalid replay string role");
|
|
137
|
+
const parent = this.stack.at(-1);
|
|
138
|
+
if (payload === "key" && (!parent || parent.kind !== "object" || parent.key !== null))
|
|
139
|
+
invalid("Unexpected replay object key");
|
|
140
|
+
this.stringParts = [];
|
|
141
|
+
this.stringKind = payload;
|
|
142
|
+
this.stringUnits = 0;
|
|
143
|
+
}
|
|
144
|
+
else if (event === "object" || event === "array") {
|
|
145
|
+
arity(1);
|
|
146
|
+
if (this.stack.length >= this.limits.maximumDepth)
|
|
147
|
+
invalid("Replay input exceeds its depth limit");
|
|
148
|
+
const container = event === "array"
|
|
149
|
+
? { kind: "array", value: [] }
|
|
150
|
+
: { kind: "object", value: Object.create(null), lastKey: null, key: null };
|
|
151
|
+
this.attach(container.value);
|
|
152
|
+
this.stack.push(container);
|
|
153
|
+
}
|
|
154
|
+
else if (event === "end-object" || event === "end-array") {
|
|
155
|
+
arity(1);
|
|
156
|
+
const parent = this.stack.at(-1);
|
|
157
|
+
if (!parent ||
|
|
158
|
+
event !== `end-${parent.kind}` ||
|
|
159
|
+
(parent.kind === "object" && parent.key !== null))
|
|
160
|
+
invalid("Mismatched or incomplete replay container");
|
|
161
|
+
this.stack.pop();
|
|
162
|
+
}
|
|
163
|
+
else if (event === "scalar") {
|
|
164
|
+
arity(2);
|
|
165
|
+
if (payload !== null &&
|
|
166
|
+
typeof payload !== "boolean" &&
|
|
167
|
+
!(typeof payload === "number" && Number.isFinite(payload)))
|
|
168
|
+
invalid("Invalid replay scalar");
|
|
169
|
+
this.attach(payload);
|
|
170
|
+
}
|
|
171
|
+
else if (event === "special-number") {
|
|
172
|
+
arity(2);
|
|
173
|
+
// Preserve raw non-finite observations for SDK audit/blocking, not null.
|
|
174
|
+
if (payload === "NaN")
|
|
175
|
+
this.attach(NaN);
|
|
176
|
+
else if (payload === "+Infinity")
|
|
177
|
+
this.attach(Infinity);
|
|
178
|
+
else if (payload === "-Infinity")
|
|
179
|
+
this.attach(-Infinity);
|
|
180
|
+
else if (payload === "-0")
|
|
181
|
+
this.attach(-0);
|
|
182
|
+
else
|
|
183
|
+
invalid("Invalid special replay number");
|
|
184
|
+
}
|
|
185
|
+
else
|
|
186
|
+
invalid("Unknown replay value event");
|
|
187
|
+
}
|
|
188
|
+
finish() {
|
|
189
|
+
if (this.sealed)
|
|
190
|
+
invalid("Replay input builder is finalized");
|
|
191
|
+
this.sealed = true;
|
|
192
|
+
if (!this.assigned || this.stack.length || this.stringParts !== null)
|
|
193
|
+
invalid("Incomplete replay input value");
|
|
194
|
+
return this.root;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
/** Live read-only input events. The enclosing genuine run owns its snapshots. */
|
|
198
|
+
export function* replayValueFrames(value) {
|
|
199
|
+
const active = new Set();
|
|
200
|
+
function* string(text, role) {
|
|
201
|
+
yield ["string-start", role];
|
|
202
|
+
for (let index = 0; index < text.length; index += REPLAY_TEXT_UNITS)
|
|
203
|
+
yield ["text", text.slice(index, index + REPLAY_TEXT_UNITS)];
|
|
204
|
+
yield ["string-end"];
|
|
205
|
+
}
|
|
206
|
+
function* visit(value) {
|
|
207
|
+
if (typeof value === "string") {
|
|
208
|
+
yield* string(value, "value");
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
if (typeof value === "number" && (!Number.isFinite(value) || Object.is(value, -0))) {
|
|
212
|
+
yield [
|
|
213
|
+
"special-number",
|
|
214
|
+
Number.isNaN(value)
|
|
215
|
+
? "NaN"
|
|
216
|
+
: value === Infinity
|
|
217
|
+
? "+Infinity"
|
|
218
|
+
: value === -Infinity
|
|
219
|
+
? "-Infinity"
|
|
220
|
+
: "-0",
|
|
221
|
+
];
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
if (value === null || typeof value === "number" || typeof value === "boolean") {
|
|
225
|
+
yield ["scalar", value];
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
if (typeof value !== "object")
|
|
229
|
+
invalid("Unsupported replay input value");
|
|
230
|
+
const array = Array.isArray(value);
|
|
231
|
+
const prototype = Object.getPrototypeOf(value);
|
|
232
|
+
if (array ? prototype !== Array.prototype : prototype !== null && prototype !== Object.prototype)
|
|
233
|
+
invalid("Replay input must contain plain data");
|
|
234
|
+
if (active.has(value))
|
|
235
|
+
invalid("Replay input contains a cycle");
|
|
236
|
+
active.add(value);
|
|
237
|
+
try {
|
|
238
|
+
yield [array ? "array" : "object"];
|
|
239
|
+
if (array) {
|
|
240
|
+
for (const key of Reflect.ownKeys(value))
|
|
241
|
+
if (key !== "length" &&
|
|
242
|
+
(typeof key !== "string" ||
|
|
243
|
+
!/^(0|[1-9][0-9]*)$/.test(key) ||
|
|
244
|
+
Number(key) >= value.length))
|
|
245
|
+
invalid("Replay input arrays must contain indexed data only");
|
|
246
|
+
for (let index = 0; index < value.length; index++) {
|
|
247
|
+
const field = Object.getOwnPropertyDescriptor(value, String(index));
|
|
248
|
+
if (!field || !("value" in field))
|
|
249
|
+
invalid("Replay input arrays must contain indexed data");
|
|
250
|
+
yield* visit(field.value);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
else
|
|
254
|
+
for (const key of Object.keys(value).sort()) {
|
|
255
|
+
const field = Object.getOwnPropertyDescriptor(value, key);
|
|
256
|
+
if (!field || !("value" in field))
|
|
257
|
+
invalid("Replay input objects must contain data properties");
|
|
258
|
+
yield* string(key, "key");
|
|
259
|
+
yield* visit(field.value);
|
|
260
|
+
}
|
|
261
|
+
yield [array ? "end-array" : "end-object"];
|
|
262
|
+
}
|
|
263
|
+
finally {
|
|
264
|
+
active.delete(value);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
yield* visit(value);
|
|
268
|
+
}
|
|
269
|
+
//# sourceMappingURL=diagnosticReplayValue.js.map
|