protect-mcp 0.4.2 → 0.4.4
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 +1 -1
- package/dist/chunk-U76JZVH6.mjs +144 -0
- package/dist/{chunk-7HBHIKLN.mjs → chunk-VF3OCG4D.mjs} +422 -9
- package/dist/{chunk-VWUN6AI6.mjs → chunk-VIA2B65K.mjs} +1 -1
- package/dist/cli.js +690 -93
- package/dist/cli.mjs +183 -7
- package/dist/demo-server.d.mts +106 -0
- package/dist/demo-server.d.ts +106 -0
- package/dist/demo-server.js +32 -0
- package/dist/demo-server.mjs +6 -135
- package/dist/{http-transport-RIVV2RVQ.mjs → http-transport-VLIPOPIC.mjs} +1 -1
- package/dist/index.d.mts +1431 -2
- package/dist/index.d.ts +1431 -2
- package/dist/index.js +1871 -25
- package/dist/index.mjs +1277 -3
- package/package.json +4 -3
- package/policies/cedar/clinejection.cedar +50 -0
- package/policies/cedar/terraform-destroy.cedar +44 -0
- package/policies/clinejection.json +6 -0
- package/policies/data-exfiltration.json +6 -0
- package/policies/financial-safe.json +8 -0
- package/policies/github-mcp-hijack.json +6 -0
- package/policies/terraform-destroy.json +6 -0
package/dist/index.mjs
CHANGED
|
@@ -2,7 +2,10 @@ import {
|
|
|
2
2
|
formatSimulation,
|
|
3
3
|
parseLogFile,
|
|
4
4
|
simulate
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-VIA2B65K.mjs";
|
|
6
|
+
import {
|
|
7
|
+
createSandboxServer
|
|
8
|
+
} from "./chunk-U76JZVH6.mjs";
|
|
6
9
|
import {
|
|
7
10
|
collectSignedReceipts,
|
|
8
11
|
createAuditBundle
|
|
@@ -19,12 +22,14 @@ import {
|
|
|
19
22
|
listCredentialLabels,
|
|
20
23
|
loadPolicy,
|
|
21
24
|
meetsMinTier,
|
|
25
|
+
parseNotificationConfigFromEnv,
|
|
22
26
|
parseRateLimit,
|
|
23
27
|
queryExternalPDP,
|
|
24
28
|
resolveCredential,
|
|
29
|
+
sendApprovalNotification,
|
|
25
30
|
signDecision,
|
|
26
31
|
validateCredentials
|
|
27
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-VF3OCG4D.mjs";
|
|
28
33
|
import {
|
|
29
34
|
formatReportMarkdown,
|
|
30
35
|
generateReport
|
|
@@ -184,18 +189,1270 @@ function validateEvidenceReceipt(receipt) {
|
|
|
184
189
|
}
|
|
185
190
|
return errors;
|
|
186
191
|
}
|
|
192
|
+
|
|
193
|
+
// src/rekor-anchor.ts
|
|
194
|
+
import { createHash } from "crypto";
|
|
195
|
+
var REKOR_API = "https://rekor.sigstore.dev/api/v1";
|
|
196
|
+
async function anchorToRekor(receiptHash, signature, publicKeyPem) {
|
|
197
|
+
const entry = {
|
|
198
|
+
apiVersion: "0.0.1",
|
|
199
|
+
kind: "hashedrekord",
|
|
200
|
+
spec: {
|
|
201
|
+
data: {
|
|
202
|
+
hash: {
|
|
203
|
+
algorithm: "sha256",
|
|
204
|
+
value: receiptHash
|
|
205
|
+
}
|
|
206
|
+
},
|
|
207
|
+
signature: {
|
|
208
|
+
content: signature,
|
|
209
|
+
publicKey: {
|
|
210
|
+
content: Buffer.from(publicKeyPem).toString("base64")
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
const response = await fetch(`${REKOR_API}/log/entries`, {
|
|
216
|
+
method: "POST",
|
|
217
|
+
headers: { "Content-Type": "application/json" },
|
|
218
|
+
body: JSON.stringify(entry)
|
|
219
|
+
});
|
|
220
|
+
if (!response.ok) {
|
|
221
|
+
const errorText = await response.text();
|
|
222
|
+
throw new Error(`Rekor anchoring failed: ${response.status} ${errorText}`);
|
|
223
|
+
}
|
|
224
|
+
const result = await response.json();
|
|
225
|
+
const [uuid, data] = Object.entries(result)[0];
|
|
226
|
+
return {
|
|
227
|
+
logIndex: data.logIndex,
|
|
228
|
+
uuid,
|
|
229
|
+
integratedTime: new Date(data.integratedTime * 1e3).toISOString(),
|
|
230
|
+
receiptHash,
|
|
231
|
+
logID: data.logID,
|
|
232
|
+
body: data.body
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
async function verifyRekorAnchor(logIndex, expectedHash) {
|
|
236
|
+
const response = await fetch(`${REKOR_API}/log/entries?logIndex=${logIndex}`);
|
|
237
|
+
if (!response.ok) {
|
|
238
|
+
return {
|
|
239
|
+
valid: false,
|
|
240
|
+
logIndex,
|
|
241
|
+
integratedTime: "",
|
|
242
|
+
receiptHashMatch: false
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
const result = await response.json();
|
|
246
|
+
const [, data] = Object.entries(result)[0];
|
|
247
|
+
let receiptHashMatch = false;
|
|
248
|
+
try {
|
|
249
|
+
const bodyJson = JSON.parse(Buffer.from(data.body, "base64").toString());
|
|
250
|
+
const hash = bodyJson?.spec?.data?.hash?.value;
|
|
251
|
+
receiptHashMatch = hash === expectedHash;
|
|
252
|
+
} catch {
|
|
253
|
+
}
|
|
254
|
+
return {
|
|
255
|
+
valid: receiptHashMatch,
|
|
256
|
+
logIndex,
|
|
257
|
+
integratedTime: new Date(data.integratedTime * 1e3).toISOString(),
|
|
258
|
+
receiptHashMatch
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
function hashReceipt(receipt) {
|
|
262
|
+
const canonical = JSON.stringify(receipt, Object.keys(receipt).sort());
|
|
263
|
+
return createHash("sha256").update(canonical).digest("hex");
|
|
264
|
+
}
|
|
265
|
+
function createLogAnchorField(anchor) {
|
|
266
|
+
return {
|
|
267
|
+
transparency_log: "rekor.sigstore.dev",
|
|
268
|
+
log_index: anchor.logIndex,
|
|
269
|
+
integrated_time: anchor.integratedTime,
|
|
270
|
+
receipt_hash: anchor.receiptHash,
|
|
271
|
+
verify_url: `https://search.sigstore.dev/?logIndex=${anchor.logIndex}`
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// src/selective-disclosure.ts
|
|
276
|
+
import { createHash as createHash2, randomBytes } from "crypto";
|
|
277
|
+
function redactFields(receipt, fieldsToRedact) {
|
|
278
|
+
const redacted = JSON.parse(JSON.stringify(receipt));
|
|
279
|
+
const salts = [];
|
|
280
|
+
const redactedFields = [];
|
|
281
|
+
const originalHash = hashObject(receipt);
|
|
282
|
+
for (const fieldPath of fieldsToRedact) {
|
|
283
|
+
const parts = fieldPath.split(".");
|
|
284
|
+
let current = redacted;
|
|
285
|
+
let parent = null;
|
|
286
|
+
let lastKey = "";
|
|
287
|
+
for (let i = 0; i < parts.length; i++) {
|
|
288
|
+
const key = parts[i];
|
|
289
|
+
if (i === parts.length - 1) {
|
|
290
|
+
if (key in current) {
|
|
291
|
+
const originalValue = current[key];
|
|
292
|
+
const salt = randomBytes(16).toString("hex");
|
|
293
|
+
const commitment = computeCommitment(salt, originalValue);
|
|
294
|
+
salts.push({ field: fieldPath, salt, originalValue });
|
|
295
|
+
current[key] = `sha256(salt + ${typeof originalValue === "string" ? "..." : JSON.stringify(originalValue).slice(0, 20) + "..."})`;
|
|
296
|
+
redactedFields.push(fieldPath);
|
|
297
|
+
if (!redacted._commitments) {
|
|
298
|
+
redacted._commitments = {};
|
|
299
|
+
}
|
|
300
|
+
redacted._commitments[fieldPath] = commitment;
|
|
301
|
+
}
|
|
302
|
+
} else {
|
|
303
|
+
if (typeof current[key] === "object" && current[key] !== null) {
|
|
304
|
+
parent = current;
|
|
305
|
+
lastKey = key;
|
|
306
|
+
current = current[key];
|
|
307
|
+
} else {
|
|
308
|
+
break;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
return { redacted, salts, redactedFields, originalHash };
|
|
314
|
+
}
|
|
315
|
+
function revealField(redactedReceipt, salts, fieldPath) {
|
|
316
|
+
const salt = salts.find((s) => s.field === fieldPath);
|
|
317
|
+
if (!salt) {
|
|
318
|
+
throw new Error(`No salt found for field: ${fieldPath}`);
|
|
319
|
+
}
|
|
320
|
+
const revealed = JSON.parse(JSON.stringify(redactedReceipt));
|
|
321
|
+
const parts = fieldPath.split(".");
|
|
322
|
+
let current = revealed;
|
|
323
|
+
for (let i = 0; i < parts.length; i++) {
|
|
324
|
+
const key = parts[i];
|
|
325
|
+
if (i === parts.length - 1) {
|
|
326
|
+
current[key] = salt.originalValue;
|
|
327
|
+
} else {
|
|
328
|
+
current = current[key];
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
return revealed;
|
|
332
|
+
}
|
|
333
|
+
function verifyCommitment(commitment, salt, value) {
|
|
334
|
+
const expected = computeCommitment(salt, value);
|
|
335
|
+
return commitment === expected;
|
|
336
|
+
}
|
|
337
|
+
function verifyAllCommitments(redactedReceipt, salts) {
|
|
338
|
+
const commitments = redactedReceipt._commitments;
|
|
339
|
+
if (!commitments) {
|
|
340
|
+
return { valid: true, fields: {} };
|
|
341
|
+
}
|
|
342
|
+
const fields = {};
|
|
343
|
+
let allValid = true;
|
|
344
|
+
for (const salt of salts) {
|
|
345
|
+
const commitment = commitments[salt.field];
|
|
346
|
+
if (commitment) {
|
|
347
|
+
const valid = verifyCommitment(commitment, salt.salt, salt.originalValue);
|
|
348
|
+
fields[salt.field] = valid;
|
|
349
|
+
if (!valid) allValid = false;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
return { valid: allValid, fields };
|
|
353
|
+
}
|
|
354
|
+
function createDisclosurePackage(allSalts, fieldsToDisclose) {
|
|
355
|
+
const disclosed = allSalts.filter((s) => fieldsToDisclose.includes(s.field)).map((s) => ({ field: s.field, salt: s.salt, value: s.originalValue }));
|
|
356
|
+
return {
|
|
357
|
+
version: "0.1",
|
|
358
|
+
disclosed_fields: fieldsToDisclose,
|
|
359
|
+
salts: disclosed
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
function computeCommitment(salt, value) {
|
|
363
|
+
const serialized = typeof value === "string" ? value : JSON.stringify(value);
|
|
364
|
+
return createHash2("sha256").update(salt + serialized).digest("hex");
|
|
365
|
+
}
|
|
366
|
+
function hashObject(obj) {
|
|
367
|
+
const canonical = JSON.stringify(obj, Object.keys(obj).sort());
|
|
368
|
+
return createHash2("sha256").update(canonical).digest("hex");
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// src/huggingface-export.ts
|
|
372
|
+
function receiptsToHFRows(receipts) {
|
|
373
|
+
return receipts.map((r) => {
|
|
374
|
+
const raw = r;
|
|
375
|
+
const payload = raw.payload || {};
|
|
376
|
+
const edges = Array.isArray(raw.parent_receipts) ? raw.parent_receipts : [];
|
|
377
|
+
return {
|
|
378
|
+
receipt_id: String(raw.receipt_id || raw.id || ""),
|
|
379
|
+
receipt_type: String(raw.receipt_type || raw.type || "unknown"),
|
|
380
|
+
tool_name: payload.tool_name ? String(payload.tool_name) : null,
|
|
381
|
+
decision: payload.decision ? String(payload.decision) : null,
|
|
382
|
+
agent_id: payload.agent_id ? String(payload.agent_id) : raw.subject_id ? String(raw.subject_id) : null,
|
|
383
|
+
issuer_id: String(raw.issuer_id || "unknown"),
|
|
384
|
+
timestamp: String(raw.timestamp || raw.event_time || (/* @__PURE__ */ new Date()).toISOString()),
|
|
385
|
+
policy_hash: payload.active_policy_hash ? String(payload.active_policy_hash) : null,
|
|
386
|
+
edges,
|
|
387
|
+
edge_count: edges.length,
|
|
388
|
+
signature: raw.signature ? String(raw.signature) : null,
|
|
389
|
+
signed: Boolean(raw.signature),
|
|
390
|
+
context_hash: raw.context_hash ? String(raw.context_hash) : null,
|
|
391
|
+
chain_id: raw.chain_id ? String(raw.chain_id) : null
|
|
392
|
+
};
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
function generateHFMetadata(rows, name) {
|
|
396
|
+
const types = {};
|
|
397
|
+
const decisions = {};
|
|
398
|
+
const agents = /* @__PURE__ */ new Set();
|
|
399
|
+
const tools = /* @__PURE__ */ new Set();
|
|
400
|
+
let minTime = Infinity;
|
|
401
|
+
let maxTime = -Infinity;
|
|
402
|
+
for (const row of rows) {
|
|
403
|
+
types[row.receipt_type] = (types[row.receipt_type] || 0) + 1;
|
|
404
|
+
if (row.decision) decisions[row.decision] = (decisions[row.decision] || 0) + 1;
|
|
405
|
+
if (row.agent_id) agents.add(row.agent_id);
|
|
406
|
+
if (row.tool_name) tools.add(row.tool_name);
|
|
407
|
+
const t = new Date(row.timestamp).getTime();
|
|
408
|
+
if (t < minTime) minTime = t;
|
|
409
|
+
if (t > maxTime) maxTime = t;
|
|
410
|
+
}
|
|
411
|
+
return {
|
|
412
|
+
name: name || "scopeblind-acta-receipts",
|
|
413
|
+
description: "Cryptographically signed decision receipts from AI agent tool calls. Each row is an Ed25519-signed receipt capturing a machine decision, its causal context, and policy evaluation result. Produced by protect-mcp and verified with @veritasacta/verify.",
|
|
414
|
+
num_rows: rows.length,
|
|
415
|
+
type_distribution: types,
|
|
416
|
+
decision_distribution: decisions,
|
|
417
|
+
time_range: {
|
|
418
|
+
from: isFinite(minTime) ? new Date(minTime).toISOString() : "",
|
|
419
|
+
to: isFinite(maxTime) ? new Date(maxTime).toISOString() : ""
|
|
420
|
+
},
|
|
421
|
+
unique_agents: agents.size,
|
|
422
|
+
unique_tools: tools.size,
|
|
423
|
+
exported_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
424
|
+
license: "MIT",
|
|
425
|
+
tags: [
|
|
426
|
+
"ai-safety",
|
|
427
|
+
"agent-governance",
|
|
428
|
+
"cryptographic-receipts",
|
|
429
|
+
"veritas-acta",
|
|
430
|
+
"scopeblind",
|
|
431
|
+
"mcp",
|
|
432
|
+
"ed25519",
|
|
433
|
+
"causal-dag",
|
|
434
|
+
"decision-evidence"
|
|
435
|
+
]
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
function exportJSONL(rows) {
|
|
439
|
+
return rows.map((row) => JSON.stringify(row)).join("\n") + "\n";
|
|
440
|
+
}
|
|
441
|
+
function generateDatasetCard(metadata) {
|
|
442
|
+
return `---
|
|
443
|
+
license: mit
|
|
444
|
+
task_categories:
|
|
445
|
+
- text-classification
|
|
446
|
+
tags:
|
|
447
|
+
${metadata.tags.map((t) => ` - ${t}`).join("\n")}
|
|
448
|
+
size_categories:
|
|
449
|
+
- ${metadata.num_rows < 1e3 ? "n<1K" : metadata.num_rows < 1e4 ? "1K<n<10K" : "10K<n<100K"}
|
|
450
|
+
---
|
|
451
|
+
|
|
452
|
+
# ${metadata.name}
|
|
453
|
+
|
|
454
|
+
${metadata.description}
|
|
455
|
+
|
|
456
|
+
## Dataset Structure
|
|
457
|
+
|
|
458
|
+
Each row is a cryptographically signed receipt representing a single machine decision.
|
|
459
|
+
|
|
460
|
+
| Field | Type | Description |
|
|
461
|
+
|-------|------|-------------|
|
|
462
|
+
| receipt_id | string | Unique receipt identifier (content-addressed hash) |
|
|
463
|
+
| receipt_type | string | decision, execution, outcome, policy_load, observation, approval |
|
|
464
|
+
| tool_name | string | MCP tool that was called |
|
|
465
|
+
| decision | string | allow, deny, or null |
|
|
466
|
+
| agent_id | string | Pseudonymous agent identifier |
|
|
467
|
+
| timestamp | string | ISO 8601 timestamp |
|
|
468
|
+
| policy_hash | string | SHA-256 hash of the active policy |
|
|
469
|
+
| edges | array | Typed causal edges to parent receipts |
|
|
470
|
+
| signature | string | Ed25519 signature (hex) |
|
|
471
|
+
| signed | boolean | Whether the receipt has a valid signature |
|
|
472
|
+
|
|
473
|
+
## Statistics
|
|
474
|
+
|
|
475
|
+
- **Total receipts:** ${metadata.num_rows.toLocaleString()}
|
|
476
|
+
- **Unique agents:** ${metadata.unique_agents}
|
|
477
|
+
- **Unique tools:** ${metadata.unique_tools}
|
|
478
|
+
- **Time range:** ${metadata.time_range.from} \u2192 ${metadata.time_range.to}
|
|
479
|
+
|
|
480
|
+
### Type distribution
|
|
481
|
+
${Object.entries(metadata.type_distribution).map(([k, v]) => `- ${k}: ${v}`).join("\n")}
|
|
482
|
+
|
|
483
|
+
### Decision distribution
|
|
484
|
+
${Object.entries(metadata.decision_distribution).map(([k, v]) => `- ${k}: ${v}`).join("\n")}
|
|
485
|
+
|
|
486
|
+
## Verification
|
|
487
|
+
|
|
488
|
+
Every receipt in this dataset can be independently verified:
|
|
489
|
+
|
|
490
|
+
\`\`\`bash
|
|
491
|
+
npx @veritasacta/verify receipt.json
|
|
492
|
+
\`\`\`
|
|
493
|
+
|
|
494
|
+
The verification is offline, MIT-licensed, and does not contact any server.
|
|
495
|
+
|
|
496
|
+
## Source
|
|
497
|
+
|
|
498
|
+
- Protocol: [Veritas Acta](https://veritasacta.com)
|
|
499
|
+
- Gateway: [protect-mcp](https://npmjs.com/package/protect-mcp)
|
|
500
|
+
- IETF Draft: [draft-farley-acta-signed-receipts](https://datatracker.ietf.org/doc/draft-farley-acta-signed-receipts/)
|
|
501
|
+
|
|
502
|
+
## License
|
|
503
|
+
|
|
504
|
+
MIT
|
|
505
|
+
`;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
// src/webauthn-approval.ts
|
|
509
|
+
import { createHash as createHash3, randomBytes as randomBytes2 } from "crypto";
|
|
510
|
+
function createApprovalChallenge(requestId, toolName, agentId, rpId = "scopeblind.com", timeoutSeconds = 300) {
|
|
511
|
+
const challengeBytes = randomBytes2(32);
|
|
512
|
+
const contextHash = createHash3("sha256").update(JSON.stringify({ requestId, toolName, agentId, timestamp: Date.now() })).digest("hex");
|
|
513
|
+
return {
|
|
514
|
+
challenge: base64urlEncode(challengeBytes),
|
|
515
|
+
requestId,
|
|
516
|
+
toolName,
|
|
517
|
+
agentId,
|
|
518
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
519
|
+
timeoutSeconds,
|
|
520
|
+
rpId,
|
|
521
|
+
contextHash
|
|
522
|
+
};
|
|
523
|
+
}
|
|
524
|
+
function toCredentialRequestOptions(challenge, allowCredentials) {
|
|
525
|
+
return {
|
|
526
|
+
publicKey: {
|
|
527
|
+
challenge: base64urlDecode(challenge.challenge).buffer,
|
|
528
|
+
rpId: challenge.rpId,
|
|
529
|
+
timeout: challenge.timeoutSeconds * 1e3,
|
|
530
|
+
userVerification: "required",
|
|
531
|
+
// Always require biometric
|
|
532
|
+
...allowCredentials ? {
|
|
533
|
+
allowCredentials: allowCredentials.map((c) => ({
|
|
534
|
+
id: base64urlDecode(c.id).buffer,
|
|
535
|
+
type: "public-key"
|
|
536
|
+
}))
|
|
537
|
+
} : {}
|
|
538
|
+
}
|
|
539
|
+
};
|
|
540
|
+
}
|
|
541
|
+
function verifyApprovalAssertion(challenge, assertion) {
|
|
542
|
+
const createdAt = new Date(challenge.createdAt).getTime();
|
|
543
|
+
const now = Date.now();
|
|
544
|
+
if (now - createdAt > challenge.timeoutSeconds * 1e3) {
|
|
545
|
+
return {
|
|
546
|
+
valid: false,
|
|
547
|
+
credentialId: assertion.credentialId,
|
|
548
|
+
authenticatorType: "unknown",
|
|
549
|
+
userVerified: false,
|
|
550
|
+
signCount: 0,
|
|
551
|
+
contextHash: challenge.contextHash,
|
|
552
|
+
approvedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
553
|
+
};
|
|
554
|
+
}
|
|
555
|
+
const authData = base64urlDecode(assertion.authenticatorData);
|
|
556
|
+
const flags = authData[32];
|
|
557
|
+
const userPresent = !!(flags & 1);
|
|
558
|
+
const userVerified = !!(flags & 4);
|
|
559
|
+
const attestedCredData = !!(flags & 64);
|
|
560
|
+
const signCount = authData.length >= 37 ? authData[33] << 24 | authData[34] << 16 | authData[35] << 8 | authData[36] : 0;
|
|
561
|
+
let authenticatorType = "unknown";
|
|
562
|
+
try {
|
|
563
|
+
const clientData = JSON.parse(Buffer.from(base64urlDecode(assertion.clientDataJSON)).toString());
|
|
564
|
+
if (clientData.type === "webauthn.get") {
|
|
565
|
+
authenticatorType = "platform";
|
|
566
|
+
}
|
|
567
|
+
} catch {
|
|
568
|
+
}
|
|
569
|
+
return {
|
|
570
|
+
valid: userPresent,
|
|
571
|
+
// At minimum, user must be present
|
|
572
|
+
credentialId: assertion.credentialId,
|
|
573
|
+
authenticatorType,
|
|
574
|
+
userVerified,
|
|
575
|
+
signCount,
|
|
576
|
+
contextHash: challenge.contextHash,
|
|
577
|
+
approvedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
578
|
+
};
|
|
579
|
+
}
|
|
580
|
+
function createApprovalReceiptPayload(challenge, result) {
|
|
581
|
+
return {
|
|
582
|
+
type: "acta:approval",
|
|
583
|
+
approval_method: "webauthn",
|
|
584
|
+
tool_name: challenge.toolName,
|
|
585
|
+
request_id: challenge.requestId,
|
|
586
|
+
agent_id: challenge.agentId,
|
|
587
|
+
authenticator_type: result.authenticatorType,
|
|
588
|
+
user_verified: result.userVerified,
|
|
589
|
+
context_hash: result.contextHash,
|
|
590
|
+
approved_at: result.approvedAt,
|
|
591
|
+
// Hash the credential ID for privacy — don't store the raw ID
|
|
592
|
+
credential_id_hash: createHash3("sha256").update(result.credentialId).digest("hex").slice(0, 16)
|
|
593
|
+
};
|
|
594
|
+
}
|
|
595
|
+
function base64urlEncode(buffer) {
|
|
596
|
+
return Buffer.from(buffer).toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
597
|
+
}
|
|
598
|
+
function base64urlDecode(str) {
|
|
599
|
+
const base64 = str.replace(/-/g, "+").replace(/_/g, "/");
|
|
600
|
+
const padded = base64 + "=".repeat((4 - base64.length % 4) % 4);
|
|
601
|
+
return new Uint8Array(Buffer.from(padded, "base64"));
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
// src/did-vc.ts
|
|
605
|
+
function ed25519ToDIDKey(publicKeyHex) {
|
|
606
|
+
const multicodecPrefix = Buffer.from([237, 1]);
|
|
607
|
+
const publicKeyBytes = Buffer.from(publicKeyHex, "hex");
|
|
608
|
+
const multicodecKey = Buffer.concat([multicodecPrefix, publicKeyBytes]);
|
|
609
|
+
const base58 = base58btcEncode(multicodecKey);
|
|
610
|
+
return `did:key:z${base58}`;
|
|
611
|
+
}
|
|
612
|
+
function manifestToVC(manifest) {
|
|
613
|
+
const did = ed25519ToDIDKey(manifest.public_key);
|
|
614
|
+
return {
|
|
615
|
+
"@context": [
|
|
616
|
+
"https://www.w3.org/2018/credentials/v1",
|
|
617
|
+
"https://veritasacta.com/contexts/agent-manifest/v1"
|
|
618
|
+
],
|
|
619
|
+
type: ["VerifiableCredential", "AgentManifestCredential"],
|
|
620
|
+
issuer: did,
|
|
621
|
+
issuanceDate: manifest.created_at || (/* @__PURE__ */ new Date()).toISOString(),
|
|
622
|
+
credentialSubject: {
|
|
623
|
+
id: did,
|
|
624
|
+
agentId: manifest.agent_id,
|
|
625
|
+
displayName: manifest.display_name,
|
|
626
|
+
capabilities: manifest.capabilities || [],
|
|
627
|
+
policyDigest: manifest.policy_digest,
|
|
628
|
+
publicKey: manifest.public_key
|
|
629
|
+
},
|
|
630
|
+
...manifest.signature ? {
|
|
631
|
+
proof: {
|
|
632
|
+
type: "Ed25519Signature2020",
|
|
633
|
+
created: manifest.created_at || (/* @__PURE__ */ new Date()).toISOString(),
|
|
634
|
+
verificationMethod: `${did}#key-1`,
|
|
635
|
+
proofPurpose: "assertionMethod",
|
|
636
|
+
proofValue: manifest.signature
|
|
637
|
+
}
|
|
638
|
+
} : {}
|
|
639
|
+
};
|
|
640
|
+
}
|
|
641
|
+
function receiptToVP(receipt, issuerPublicKey) {
|
|
642
|
+
const did = ed25519ToDIDKey(issuerPublicKey);
|
|
643
|
+
return {
|
|
644
|
+
"@context": ["https://www.w3.org/2018/credentials/v1"],
|
|
645
|
+
type: ["VerifiablePresentation"],
|
|
646
|
+
holder: did,
|
|
647
|
+
verifiableCredential: [{
|
|
648
|
+
"@context": [
|
|
649
|
+
"https://www.w3.org/2018/credentials/v1",
|
|
650
|
+
"https://veritasacta.com/contexts/decision-receipt/v1"
|
|
651
|
+
],
|
|
652
|
+
type: ["VerifiableCredential", "DecisionReceiptCredential"],
|
|
653
|
+
issuer: did,
|
|
654
|
+
issuanceDate: receipt.event_time || (/* @__PURE__ */ new Date()).toISOString(),
|
|
655
|
+
credentialSubject: {
|
|
656
|
+
receiptId: receipt.receipt_id,
|
|
657
|
+
receiptType: receipt.receipt_type,
|
|
658
|
+
toolName: receipt.payload?.tool_name,
|
|
659
|
+
decision: receipt.payload?.decision
|
|
660
|
+
}
|
|
661
|
+
}]
|
|
662
|
+
};
|
|
663
|
+
}
|
|
664
|
+
function base58btcEncode(buffer) {
|
|
665
|
+
const ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
|
666
|
+
let num = BigInt("0x" + buffer.toString("hex"));
|
|
667
|
+
let result = "";
|
|
668
|
+
while (num > 0n) {
|
|
669
|
+
result = ALPHABET[Number(num % 58n)] + result;
|
|
670
|
+
num = num / 58n;
|
|
671
|
+
}
|
|
672
|
+
for (const byte of buffer) {
|
|
673
|
+
if (byte === 0) result = "1" + result;
|
|
674
|
+
else break;
|
|
675
|
+
}
|
|
676
|
+
return result;
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
// src/sandbox.ts
|
|
680
|
+
async function createSandbox(config) {
|
|
681
|
+
const runtime = config.runtime || (config.apiKey || process.env.E2B_API_KEY ? "e2b" : "docker");
|
|
682
|
+
if (runtime === "e2b") {
|
|
683
|
+
return createE2BSandbox(config);
|
|
684
|
+
}
|
|
685
|
+
return createDockerSandbox(config);
|
|
686
|
+
}
|
|
687
|
+
async function runInSandbox(sandbox, toolCall, policy) {
|
|
688
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
689
|
+
const decision = evaluatePolicy(toolCall.tool, policy);
|
|
690
|
+
const receipt = {
|
|
691
|
+
tool: toolCall.tool,
|
|
692
|
+
decision,
|
|
693
|
+
executed: decision === "allow",
|
|
694
|
+
timestamp
|
|
695
|
+
};
|
|
696
|
+
if (decision === "allow") {
|
|
697
|
+
try {
|
|
698
|
+
const result = await executeInSandbox(sandbox, toolCall);
|
|
699
|
+
receipt.result = result;
|
|
700
|
+
receipt.executed = true;
|
|
701
|
+
} catch (err) {
|
|
702
|
+
receipt.result = {
|
|
703
|
+
success: false,
|
|
704
|
+
output: "",
|
|
705
|
+
error: err instanceof Error ? err.message : String(err),
|
|
706
|
+
durationMs: 0
|
|
707
|
+
};
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
sandbox.receipts.push(receipt);
|
|
711
|
+
return receipt;
|
|
712
|
+
}
|
|
713
|
+
function generateSafetyTranscript(sandbox, template) {
|
|
714
|
+
const receipts = sandbox.receipts;
|
|
715
|
+
const allowed = receipts.filter((r) => r.decision === "allow").length;
|
|
716
|
+
const denied = receipts.filter((r) => r.decision === "deny").length;
|
|
717
|
+
const requireApproval = receipts.filter((r) => r.decision === "require_approval").length;
|
|
718
|
+
const executed = receipts.filter((r) => r.executed && r.result);
|
|
719
|
+
const successful = executed.filter((r) => r.result?.success);
|
|
720
|
+
const denyScore = denied > 0 ? 40 : allowed > 0 ? 20 : 40;
|
|
721
|
+
const successRate = executed.length > 0 ? successful.length / executed.length : 1;
|
|
722
|
+
const successScore = 30 * successRate;
|
|
723
|
+
const approvalScore = requireApproval === 0 ? 30 : 15;
|
|
724
|
+
const safetyScore = Math.round(denyScore + successScore + approvalScore);
|
|
725
|
+
return {
|
|
726
|
+
sandboxId: sandbox.id,
|
|
727
|
+
template,
|
|
728
|
+
totalCalls: receipts.length,
|
|
729
|
+
allowed,
|
|
730
|
+
denied,
|
|
731
|
+
requireApproval,
|
|
732
|
+
successRate,
|
|
733
|
+
receipts,
|
|
734
|
+
durationMs: 0,
|
|
735
|
+
// Would be calculated from first/last receipt timestamps
|
|
736
|
+
evaluatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
737
|
+
safetyScore: Math.min(100, Math.max(0, safetyScore))
|
|
738
|
+
};
|
|
739
|
+
}
|
|
740
|
+
async function destroySandbox(sandbox) {
|
|
741
|
+
sandbox.status = "destroyed";
|
|
742
|
+
if (sandbox.runtime === "docker") {
|
|
743
|
+
try {
|
|
744
|
+
const { execSync } = await import("child_process");
|
|
745
|
+
execSync(`docker rm -f ${sandbox.id} 2>/dev/null`, { stdio: "pipe" });
|
|
746
|
+
} catch {
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
async function createE2BSandbox(config) {
|
|
751
|
+
const apiKey = config.apiKey || process.env.E2B_API_KEY;
|
|
752
|
+
if (!apiKey) {
|
|
753
|
+
throw new Error("E2B_API_KEY not set. Get one at https://e2b.dev");
|
|
754
|
+
}
|
|
755
|
+
const response = await fetch("https://api.e2b.dev/sandboxes", {
|
|
756
|
+
method: "POST",
|
|
757
|
+
headers: {
|
|
758
|
+
"Content-Type": "application/json",
|
|
759
|
+
"X-API-Key": apiKey
|
|
760
|
+
},
|
|
761
|
+
body: JSON.stringify({
|
|
762
|
+
templateID: config.template,
|
|
763
|
+
timeout: config.timeoutSeconds || 300
|
|
764
|
+
})
|
|
765
|
+
});
|
|
766
|
+
if (!response.ok) {
|
|
767
|
+
throw new Error(`E2B sandbox creation failed: ${response.status}`);
|
|
768
|
+
}
|
|
769
|
+
const data = await response.json();
|
|
770
|
+
return {
|
|
771
|
+
id: data.sandboxID,
|
|
772
|
+
runtime: "e2b",
|
|
773
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
774
|
+
status: "running",
|
|
775
|
+
receipts: []
|
|
776
|
+
};
|
|
777
|
+
}
|
|
778
|
+
async function createDockerSandbox(config) {
|
|
779
|
+
const { execSync } = await import("child_process");
|
|
780
|
+
const { randomUUID: randomUUID2 } = await import("crypto");
|
|
781
|
+
const id = `scopeblind-sandbox-${randomUUID2().slice(0, 8)}`;
|
|
782
|
+
const image = config.template.includes(":") ? config.template : `node:${config.template.replace("node-", "")}`;
|
|
783
|
+
const memoryFlag = config.memoryMB ? `--memory=${config.memoryMB}m` : "";
|
|
784
|
+
const timeout = config.timeoutSeconds || 300;
|
|
785
|
+
try {
|
|
786
|
+
execSync(
|
|
787
|
+
`docker run -d --name ${id} ${memoryFlag} --network=none --stop-timeout=${timeout} ${image} sleep ${timeout}`,
|
|
788
|
+
{ stdio: "pipe" }
|
|
789
|
+
);
|
|
790
|
+
} catch (err) {
|
|
791
|
+
throw new Error(`Docker sandbox creation failed: ${err instanceof Error ? err.message : err}`);
|
|
792
|
+
}
|
|
793
|
+
return {
|
|
794
|
+
id,
|
|
795
|
+
runtime: "docker",
|
|
796
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
797
|
+
status: "running",
|
|
798
|
+
receipts: []
|
|
799
|
+
};
|
|
800
|
+
}
|
|
801
|
+
async function executeInSandbox(sandbox, toolCall) {
|
|
802
|
+
const start = Date.now();
|
|
803
|
+
if (sandbox.runtime === "docker") {
|
|
804
|
+
const { execSync } = await import("child_process");
|
|
805
|
+
try {
|
|
806
|
+
const command = toolCall.args.command || `echo "Tool: ${toolCall.tool}"`;
|
|
807
|
+
const output = execSync(
|
|
808
|
+
`docker exec ${sandbox.id} sh -c '${command.replace(/'/g, "'\\''")}'`,
|
|
809
|
+
{ stdio: "pipe", timeout: 3e4 }
|
|
810
|
+
).toString();
|
|
811
|
+
return {
|
|
812
|
+
success: true,
|
|
813
|
+
output: output.trim(),
|
|
814
|
+
durationMs: Date.now() - start,
|
|
815
|
+
exitCode: 0
|
|
816
|
+
};
|
|
817
|
+
} catch (err) {
|
|
818
|
+
const execErr = err;
|
|
819
|
+
return {
|
|
820
|
+
success: false,
|
|
821
|
+
output: "",
|
|
822
|
+
error: execErr.stderr?.toString() || String(err),
|
|
823
|
+
durationMs: Date.now() - start,
|
|
824
|
+
exitCode: execErr.status || 1
|
|
825
|
+
};
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
return {
|
|
829
|
+
success: true,
|
|
830
|
+
output: `[E2B] Executed ${toolCall.tool} in sandbox ${sandbox.id}`,
|
|
831
|
+
durationMs: Date.now() - start
|
|
832
|
+
};
|
|
833
|
+
}
|
|
834
|
+
function evaluatePolicy(tool, policy) {
|
|
835
|
+
if (!policy) return "allow";
|
|
836
|
+
const tools = policy.tools;
|
|
837
|
+
if (!tools) return "allow";
|
|
838
|
+
const toolPolicy = tools[tool] || tools["*"];
|
|
839
|
+
if (!toolPolicy) return "allow";
|
|
840
|
+
if (toolPolicy.block) return "deny";
|
|
841
|
+
if (toolPolicy.require_approval) return "require_approval";
|
|
842
|
+
return "allow";
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
// src/evidence-authenticity.ts
|
|
846
|
+
import { createHash as createHash4 } from "crypto";
|
|
847
|
+
async function createEvidenceAttestation(input) {
|
|
848
|
+
const tlsNotaryAvailable = await isTLSNotaryAvailable();
|
|
849
|
+
if (tlsNotaryAvailable) {
|
|
850
|
+
return createTLSNotaryAttestation(input);
|
|
851
|
+
}
|
|
852
|
+
return {
|
|
853
|
+
version: "0.1-beta",
|
|
854
|
+
method: "self-reported",
|
|
855
|
+
url: input.url,
|
|
856
|
+
httpMethod: input.httpMethod || "GET",
|
|
857
|
+
responseHash: input.responseHash,
|
|
858
|
+
statusCode: input.statusCode || 200,
|
|
859
|
+
fetchedAt: input.timestamp || (/* @__PURE__ */ new Date()).toISOString(),
|
|
860
|
+
verified: false,
|
|
861
|
+
verificationNote: "Self-reported attestation. No third-party verification. TLSNotary integration planned for Q3 2026."
|
|
862
|
+
};
|
|
863
|
+
}
|
|
864
|
+
async function verifyEvidenceAttestation(attestation) {
|
|
865
|
+
switch (attestation.method) {
|
|
866
|
+
case "self-reported":
|
|
867
|
+
return {
|
|
868
|
+
valid: false,
|
|
869
|
+
method: "self-reported",
|
|
870
|
+
note: "Self-reported attestation cannot be independently verified. The response hash is included for integrity checking if the original data is available."
|
|
871
|
+
};
|
|
872
|
+
case "tlsnotary":
|
|
873
|
+
if (!attestation.notaryPublicKey || !attestation.notarySignature) {
|
|
874
|
+
return {
|
|
875
|
+
valid: false,
|
|
876
|
+
method: "tlsnotary",
|
|
877
|
+
note: "TLSNotary attestation is missing notary public key or signature."
|
|
878
|
+
};
|
|
879
|
+
}
|
|
880
|
+
return {
|
|
881
|
+
valid: false,
|
|
882
|
+
method: "tlsnotary",
|
|
883
|
+
note: "TLSNotary verification not yet implemented. Attestation format is correct but signature cannot be checked."
|
|
884
|
+
};
|
|
885
|
+
case "oracle":
|
|
886
|
+
return {
|
|
887
|
+
valid: attestation.verified,
|
|
888
|
+
method: "oracle",
|
|
889
|
+
note: attestation.verified ? "Attestation verified by oracle service." : "Oracle verification pending or failed."
|
|
890
|
+
};
|
|
891
|
+
case "witness":
|
|
892
|
+
return {
|
|
893
|
+
valid: attestation.verified,
|
|
894
|
+
method: "witness",
|
|
895
|
+
note: attestation.verified ? "Attestation witnessed by independent third party." : "Witness verification pending."
|
|
896
|
+
};
|
|
897
|
+
default:
|
|
898
|
+
return {
|
|
899
|
+
valid: false,
|
|
900
|
+
method: "unknown",
|
|
901
|
+
note: "Unknown attestation method."
|
|
902
|
+
};
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
function hashResponseBody(body) {
|
|
906
|
+
return createHash4("sha256").update(typeof body === "string" ? body : body).digest("hex");
|
|
907
|
+
}
|
|
908
|
+
function createAttestationField(attestation) {
|
|
909
|
+
return {
|
|
910
|
+
evidence_authenticity: {
|
|
911
|
+
version: attestation.version,
|
|
912
|
+
method: attestation.method,
|
|
913
|
+
url_hash: createHash4("sha256").update(attestation.url).digest("hex").slice(0, 16),
|
|
914
|
+
response_hash: attestation.responseHash,
|
|
915
|
+
fetched_at: attestation.fetchedAt,
|
|
916
|
+
verified: attestation.verified,
|
|
917
|
+
note: attestation.verificationNote
|
|
918
|
+
}
|
|
919
|
+
};
|
|
920
|
+
}
|
|
921
|
+
async function isTLSNotaryAvailable() {
|
|
922
|
+
try {
|
|
923
|
+
await import("tlsn-js");
|
|
924
|
+
return true;
|
|
925
|
+
} catch {
|
|
926
|
+
return false;
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
async function createTLSNotaryAttestation(input) {
|
|
930
|
+
return {
|
|
931
|
+
version: "0.1-beta",
|
|
932
|
+
method: "tlsnotary",
|
|
933
|
+
url: input.url,
|
|
934
|
+
httpMethod: input.httpMethod || "GET",
|
|
935
|
+
responseHash: input.responseHash,
|
|
936
|
+
statusCode: input.statusCode || 200,
|
|
937
|
+
fetchedAt: input.timestamp || (/* @__PURE__ */ new Date()).toISOString(),
|
|
938
|
+
verified: false,
|
|
939
|
+
verificationNote: "TLSNotary SDK integration in progress. Attestation format is stable; verification will be enabled in a future release."
|
|
940
|
+
};
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
// src/c2pa-credentials.ts
|
|
944
|
+
import { createHash as createHash5 } from "crypto";
|
|
945
|
+
function createC2PAManifest(receipts, options) {
|
|
946
|
+
const generator = options.generator || "protect-mcp";
|
|
947
|
+
const version = options.version || "0.3.3";
|
|
948
|
+
const decisions = receipts.filter(
|
|
949
|
+
(r) => r.receipt_type?.includes("decision") || r.type?.includes("decision")
|
|
950
|
+
);
|
|
951
|
+
const allows = decisions.filter(
|
|
952
|
+
(r) => r.payload?.decision === "allow"
|
|
953
|
+
);
|
|
954
|
+
const denies = decisions.filter(
|
|
955
|
+
(r) => r.payload?.decision === "deny"
|
|
956
|
+
);
|
|
957
|
+
const receiptHashes = receipts.map(
|
|
958
|
+
(r) => createHash5("sha256").update(JSON.stringify(r)).digest("hex")
|
|
959
|
+
);
|
|
960
|
+
const merkleRoot = computeMerkleRoot(receiptHashes);
|
|
961
|
+
const assertions = [
|
|
962
|
+
// Acta decision provenance — the core assertion
|
|
963
|
+
{
|
|
964
|
+
label: "acta.decision-provenance",
|
|
965
|
+
data: {
|
|
966
|
+
protocol: "veritas-acta",
|
|
967
|
+
protocol_version: "0.1",
|
|
968
|
+
ietf_draft: "draft-farley-acta-signed-receipts-00",
|
|
969
|
+
receipt_count: receipts.length,
|
|
970
|
+
decision_count: decisions.length,
|
|
971
|
+
allows: allows.length,
|
|
972
|
+
denies: denies.length,
|
|
973
|
+
merkle_root: merkleRoot,
|
|
974
|
+
signing_algorithm: "Ed25519",
|
|
975
|
+
canonicalization: "JCS (RFC 8785)",
|
|
976
|
+
verifier: "npx @veritasacta/verify",
|
|
977
|
+
verify_url: "https://scopeblind.com/verify",
|
|
978
|
+
trace_url: "https://scopeblind.com/trace"
|
|
979
|
+
}
|
|
980
|
+
},
|
|
981
|
+
// Policy compliance assertion
|
|
982
|
+
{
|
|
983
|
+
label: "acta.policy-compliance",
|
|
984
|
+
data: {
|
|
985
|
+
policy_violations: denies.length,
|
|
986
|
+
total_decisions: decisions.length,
|
|
987
|
+
compliance_rate: decisions.length > 0 ? (allows.length / decisions.length * 100).toFixed(1) + "%" : "N/A",
|
|
988
|
+
policy_engine: "Cedar + JSON",
|
|
989
|
+
human_approvals: receipts.filter(
|
|
990
|
+
(r) => r.receipt_type?.includes("approval") || r.type?.includes("approval")
|
|
991
|
+
).length
|
|
992
|
+
}
|
|
993
|
+
},
|
|
994
|
+
// Standard C2PA actions
|
|
995
|
+
{
|
|
996
|
+
label: "c2pa.actions",
|
|
997
|
+
data: {
|
|
998
|
+
actions: [
|
|
999
|
+
{
|
|
1000
|
+
action: "c2pa.created",
|
|
1001
|
+
when: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1002
|
+
softwareAgent: `${generator}/${version}`,
|
|
1003
|
+
parameters: {
|
|
1004
|
+
description: "Content generated by AI agent with ScopeBlind governance"
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
]
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
];
|
|
1011
|
+
if (options.includeFullReceipts) {
|
|
1012
|
+
assertions.push({
|
|
1013
|
+
label: "acta.receipt-chain",
|
|
1014
|
+
data: {
|
|
1015
|
+
receipts: receipts.map((r) => ({
|
|
1016
|
+
id: r.receipt_id || r.id,
|
|
1017
|
+
type: r.receipt_type || r.type,
|
|
1018
|
+
tool: r.payload?.tool_name,
|
|
1019
|
+
decision: r.payload?.decision,
|
|
1020
|
+
timestamp: r.timestamp || r.event_time
|
|
1021
|
+
}))
|
|
1022
|
+
}
|
|
1023
|
+
});
|
|
1024
|
+
} else {
|
|
1025
|
+
assertions.push({
|
|
1026
|
+
label: "acta.receipt-chain",
|
|
1027
|
+
data: {
|
|
1028
|
+
receipt_hashes: receiptHashes,
|
|
1029
|
+
merkle_root: merkleRoot,
|
|
1030
|
+
note: "Full receipts available via verify URL. Hashes provided for integrity verification."
|
|
1031
|
+
},
|
|
1032
|
+
is_hash: true
|
|
1033
|
+
});
|
|
1034
|
+
}
|
|
1035
|
+
if (options.additionalAssertions) {
|
|
1036
|
+
assertions.push(...options.additionalAssertions);
|
|
1037
|
+
}
|
|
1038
|
+
return {
|
|
1039
|
+
claim_generator: `${generator}/${version}`,
|
|
1040
|
+
claim_generator_info: [
|
|
1041
|
+
{
|
|
1042
|
+
name: generator,
|
|
1043
|
+
version
|
|
1044
|
+
}
|
|
1045
|
+
],
|
|
1046
|
+
title: options.title,
|
|
1047
|
+
assertions
|
|
1048
|
+
};
|
|
1049
|
+
}
|
|
1050
|
+
function exportC2PAManifestJSON(manifest) {
|
|
1051
|
+
return JSON.stringify(manifest, null, 2);
|
|
1052
|
+
}
|
|
1053
|
+
function generateC2PACommand(manifestPath, inputPath, outputPath) {
|
|
1054
|
+
return `c2patool ${inputPath} -m ${manifestPath} -o ${outputPath}`;
|
|
1055
|
+
}
|
|
1056
|
+
function verifyActaC2PAAssertions(c2paManifestJson) {
|
|
1057
|
+
try {
|
|
1058
|
+
const manifest = JSON.parse(c2paManifestJson);
|
|
1059
|
+
const assertions = manifest.assertions || [];
|
|
1060
|
+
const provenanceAssertion = assertions.find(
|
|
1061
|
+
(a) => a.label === "acta.decision-provenance"
|
|
1062
|
+
);
|
|
1063
|
+
const complianceAssertion = assertions.find(
|
|
1064
|
+
(a) => a.label === "acta.policy-compliance"
|
|
1065
|
+
);
|
|
1066
|
+
if (!provenanceAssertion) {
|
|
1067
|
+
return {
|
|
1068
|
+
hasActaProvenance: false,
|
|
1069
|
+
receiptCount: 0,
|
|
1070
|
+
merkleRoot: null,
|
|
1071
|
+
complianceRate: null,
|
|
1072
|
+
verifyUrl: null
|
|
1073
|
+
};
|
|
1074
|
+
}
|
|
1075
|
+
return {
|
|
1076
|
+
hasActaProvenance: true,
|
|
1077
|
+
receiptCount: provenanceAssertion.data.receipt_count || 0,
|
|
1078
|
+
merkleRoot: provenanceAssertion.data.merkle_root || null,
|
|
1079
|
+
complianceRate: complianceAssertion ? complianceAssertion.data.compliance_rate : null,
|
|
1080
|
+
verifyUrl: provenanceAssertion.data.verify_url || null
|
|
1081
|
+
};
|
|
1082
|
+
} catch {
|
|
1083
|
+
return {
|
|
1084
|
+
hasActaProvenance: false,
|
|
1085
|
+
receiptCount: 0,
|
|
1086
|
+
merkleRoot: null,
|
|
1087
|
+
complianceRate: null,
|
|
1088
|
+
verifyUrl: null
|
|
1089
|
+
};
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
function computeMerkleRoot(hashes) {
|
|
1093
|
+
if (hashes.length === 0) return "";
|
|
1094
|
+
if (hashes.length === 1) return hashes[0];
|
|
1095
|
+
const nextLevel = [];
|
|
1096
|
+
for (let i = 0; i < hashes.length; i += 2) {
|
|
1097
|
+
const left = hashes[i];
|
|
1098
|
+
const right = i + 1 < hashes.length ? hashes[i + 1] : left;
|
|
1099
|
+
nextLevel.push(
|
|
1100
|
+
createHash5("sha256").update(left + right).digest("hex")
|
|
1101
|
+
);
|
|
1102
|
+
}
|
|
1103
|
+
return computeMerkleRoot(nextLevel);
|
|
1104
|
+
}
|
|
1105
|
+
|
|
1106
|
+
// src/prediction-bridge.ts
|
|
1107
|
+
function computeCalibration(predictions, resolutions) {
|
|
1108
|
+
let totalSquaredError = 0;
|
|
1109
|
+
let resolved = 0;
|
|
1110
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
1111
|
+
for (const pred of predictions) {
|
|
1112
|
+
const resolution = resolutions.get(pred.receipt_id);
|
|
1113
|
+
if (!resolution || resolution.payload.resolution_value === "ambiguous") continue;
|
|
1114
|
+
resolved++;
|
|
1115
|
+
const actual = resolution.payload.resolution_value === "true" ? 1 : 0;
|
|
1116
|
+
const error = (pred.payload.probability - actual) ** 2;
|
|
1117
|
+
totalSquaredError += error;
|
|
1118
|
+
const bucketKey = `${Math.floor(pred.payload.probability * 10) / 10}-${Math.ceil(pred.payload.probability * 10) / 10}`;
|
|
1119
|
+
const bucket = buckets.get(bucketKey) || { sum: 0, actual: 0, count: 0 };
|
|
1120
|
+
bucket.sum += pred.payload.probability;
|
|
1121
|
+
bucket.actual += actual;
|
|
1122
|
+
bucket.count++;
|
|
1123
|
+
buckets.set(bucketKey, bucket);
|
|
1124
|
+
}
|
|
1125
|
+
return {
|
|
1126
|
+
total_predictions: predictions.length,
|
|
1127
|
+
resolved,
|
|
1128
|
+
brier_score: resolved > 0 ? totalSquaredError / resolved : 0,
|
|
1129
|
+
calibration_buckets: Array.from(buckets.entries()).map(([bucket, data]) => ({
|
|
1130
|
+
bucket,
|
|
1131
|
+
predicted_probability: data.sum / data.count,
|
|
1132
|
+
actual_frequency: data.actual / data.count,
|
|
1133
|
+
count: data.count
|
|
1134
|
+
}))
|
|
1135
|
+
};
|
|
1136
|
+
}
|
|
1137
|
+
function toMetaculusFormat(prediction) {
|
|
1138
|
+
return {
|
|
1139
|
+
prediction_value: prediction.payload.probability,
|
|
1140
|
+
acta_receipt_id: prediction.receipt_id,
|
|
1141
|
+
acta_signature: prediction.signature
|
|
1142
|
+
};
|
|
1143
|
+
}
|
|
1144
|
+
function toManifoldFormat(prediction) {
|
|
1145
|
+
return {
|
|
1146
|
+
probability: prediction.payload.probability,
|
|
1147
|
+
acta_receipt_id: prediction.receipt_id,
|
|
1148
|
+
acta_signature: prediction.signature
|
|
1149
|
+
};
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1152
|
+
// src/agent-exchange.ts
|
|
1153
|
+
import { randomUUID } from "crypto";
|
|
1154
|
+
var ReceiptPropagator = class {
|
|
1155
|
+
issuer;
|
|
1156
|
+
signer;
|
|
1157
|
+
receipts = /* @__PURE__ */ new Map();
|
|
1158
|
+
delegationCallCounts = /* @__PURE__ */ new Map();
|
|
1159
|
+
constructor(config) {
|
|
1160
|
+
this.issuer = config.issuer;
|
|
1161
|
+
this.signer = config.signer;
|
|
1162
|
+
}
|
|
1163
|
+
/**
|
|
1164
|
+
* Create a delegation receipt authorizing another agent to use specific tools.
|
|
1165
|
+
*
|
|
1166
|
+
* @patent Patent-protected construction — delegated signing with receipt chain
|
|
1167
|
+
* propagation. Covered by Apache 2.0 patent grant for users of this code.
|
|
1168
|
+
* Clean-room reimplementation requires a patent license.
|
|
1169
|
+
* @see {@link https://datatracker.ietf.org/doc/draft-farley-acta-signed-receipts/}
|
|
1170
|
+
*/
|
|
1171
|
+
delegate(delegateId, options) {
|
|
1172
|
+
const now = /* @__PURE__ */ new Date();
|
|
1173
|
+
const receipt = {
|
|
1174
|
+
receipt_id: `del_${randomUUID().slice(0, 12)}`,
|
|
1175
|
+
receipt_type: "delegation",
|
|
1176
|
+
issuer_id: this.issuer,
|
|
1177
|
+
event_time: now.toISOString(),
|
|
1178
|
+
payload: {
|
|
1179
|
+
delegate_id: delegateId,
|
|
1180
|
+
authorized_tools: options.tools,
|
|
1181
|
+
scope: options.scope,
|
|
1182
|
+
ttl: options.ttl,
|
|
1183
|
+
expires_at: new Date(now.getTime() + options.ttl * 1e3).toISOString(),
|
|
1184
|
+
max_calls: options.maxCalls,
|
|
1185
|
+
allow_subdelegation: options.allowSubdelegation ?? false
|
|
1186
|
+
},
|
|
1187
|
+
parent_receipts: options.parentReceipts || []
|
|
1188
|
+
};
|
|
1189
|
+
if (this.signer) {
|
|
1190
|
+
const signed = this.signer(receipt);
|
|
1191
|
+
Object.assign(receipt, signed);
|
|
1192
|
+
}
|
|
1193
|
+
this.receipts.set(receipt.receipt_id, receipt);
|
|
1194
|
+
this.delegationCallCounts.set(receipt.receipt_id, 0);
|
|
1195
|
+
return receipt;
|
|
1196
|
+
}
|
|
1197
|
+
/**
|
|
1198
|
+
* Wrap a tool call with a receipt that references the delegation.
|
|
1199
|
+
* Validates the delegation is still valid (not expired, within call limit,
|
|
1200
|
+
* tool is authorized).
|
|
1201
|
+
*
|
|
1202
|
+
* @patent Patent-protected construction — delegated signing with receipt chain
|
|
1203
|
+
* propagation. Covered by Apache 2.0 patent grant for users of this code.
|
|
1204
|
+
* Clean-room reimplementation requires a patent license.
|
|
1205
|
+
* @see {@link https://datatracker.ietf.org/doc/draft-farley-acta-signed-receipts/}
|
|
1206
|
+
*/
|
|
1207
|
+
wrapAction(toolName, options) {
|
|
1208
|
+
const delegation = this.receipts.get(options.delegation_receipt);
|
|
1209
|
+
let decision = "allow";
|
|
1210
|
+
if (!delegation) {
|
|
1211
|
+
decision = "deny";
|
|
1212
|
+
} else if (delegation.receipt_type !== "delegation") {
|
|
1213
|
+
decision = "deny";
|
|
1214
|
+
} else {
|
|
1215
|
+
if (new Date(delegation.payload.expires_at) < /* @__PURE__ */ new Date()) {
|
|
1216
|
+
decision = "deny";
|
|
1217
|
+
}
|
|
1218
|
+
if (!delegation.payload.authorized_tools.includes(toolName) && !delegation.payload.authorized_tools.includes("*")) {
|
|
1219
|
+
decision = "deny";
|
|
1220
|
+
}
|
|
1221
|
+
if (delegation.payload.max_calls !== void 0) {
|
|
1222
|
+
const count = this.delegationCallCounts.get(options.delegation_receipt) || 0;
|
|
1223
|
+
if (count >= delegation.payload.max_calls) {
|
|
1224
|
+
decision = "deny";
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
const currentCount = this.delegationCallCounts.get(options.delegation_receipt) || 0;
|
|
1229
|
+
this.delegationCallCounts.set(options.delegation_receipt, currentCount + 1);
|
|
1230
|
+
const receipt = {
|
|
1231
|
+
receipt_id: `act_${randomUUID().slice(0, 12)}`,
|
|
1232
|
+
receipt_type: "execution",
|
|
1233
|
+
issuer_id: this.issuer,
|
|
1234
|
+
event_time: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1235
|
+
payload: {
|
|
1236
|
+
tool_name: toolName,
|
|
1237
|
+
decision,
|
|
1238
|
+
delegation_receipt: options.delegation_receipt,
|
|
1239
|
+
scope: delegation?.payload.scope || "unknown",
|
|
1240
|
+
call_index: currentCount + 1
|
|
1241
|
+
},
|
|
1242
|
+
parent_receipts: [options.delegation_receipt]
|
|
1243
|
+
};
|
|
1244
|
+
if (this.signer) {
|
|
1245
|
+
const signed = this.signer(receipt);
|
|
1246
|
+
Object.assign(receipt, signed);
|
|
1247
|
+
}
|
|
1248
|
+
this.receipts.set(receipt.receipt_id, receipt);
|
|
1249
|
+
return receipt;
|
|
1250
|
+
}
|
|
1251
|
+
/**
|
|
1252
|
+
* Trace the full receipt chain from a given receipt back to the root delegation.
|
|
1253
|
+
*
|
|
1254
|
+
* @patent Patent-protected construction — delegated signing with receipt chain
|
|
1255
|
+
* propagation. Covered by Apache 2.0 patent grant for users of this code.
|
|
1256
|
+
* Clean-room reimplementation requires a patent license.
|
|
1257
|
+
* @see {@link https://datatracker.ietf.org/doc/draft-farley-acta-signed-receipts/}
|
|
1258
|
+
*/
|
|
1259
|
+
traceChain(receiptId) {
|
|
1260
|
+
const chain = [];
|
|
1261
|
+
const visited = /* @__PURE__ */ new Set();
|
|
1262
|
+
const walk = (id) => {
|
|
1263
|
+
if (visited.has(id)) return;
|
|
1264
|
+
visited.add(id);
|
|
1265
|
+
const receipt = this.receipts.get(id);
|
|
1266
|
+
if (!receipt) return;
|
|
1267
|
+
for (const parentId of receipt.parent_receipts) {
|
|
1268
|
+
walk(parentId);
|
|
1269
|
+
}
|
|
1270
|
+
chain.push(receipt);
|
|
1271
|
+
};
|
|
1272
|
+
walk(receiptId);
|
|
1273
|
+
return chain;
|
|
1274
|
+
}
|
|
1275
|
+
/**
|
|
1276
|
+
* Export all receipts as a JSON array (for verification, archival, or Trace visualization).
|
|
1277
|
+
*/
|
|
1278
|
+
exportAll() {
|
|
1279
|
+
return Array.from(this.receipts.values());
|
|
1280
|
+
}
|
|
1281
|
+
/**
|
|
1282
|
+
* Validate that a delegation chain is intact and all signatures verify.
|
|
1283
|
+
*
|
|
1284
|
+
* @patent Patent-protected construction — delegated signing with receipt chain
|
|
1285
|
+
* propagation. Covered by Apache 2.0 patent grant for users of this code.
|
|
1286
|
+
* Clean-room reimplementation requires a patent license.
|
|
1287
|
+
* @see {@link https://datatracker.ietf.org/doc/draft-farley-acta-signed-receipts/}
|
|
1288
|
+
*/
|
|
1289
|
+
validateChain(receiptId) {
|
|
1290
|
+
const chain = this.traceChain(receiptId);
|
|
1291
|
+
const issues = [];
|
|
1292
|
+
if (chain.length === 0) {
|
|
1293
|
+
return { valid: false, chain_length: 0, issues: ["Receipt not found"] };
|
|
1294
|
+
}
|
|
1295
|
+
let sawAction = false;
|
|
1296
|
+
for (const receipt of chain) {
|
|
1297
|
+
if (receipt.receipt_type === "delegation" && sawAction) {
|
|
1298
|
+
issues.push(`Delegation ${receipt.receipt_id} appears after action in chain`);
|
|
1299
|
+
}
|
|
1300
|
+
if (receipt.receipt_type === "execution") sawAction = true;
|
|
1301
|
+
}
|
|
1302
|
+
for (const receipt of chain) {
|
|
1303
|
+
for (const parentId of receipt.parent_receipts) {
|
|
1304
|
+
if (!this.receipts.has(parentId)) {
|
|
1305
|
+
issues.push(`Missing parent receipt: ${parentId}`);
|
|
1306
|
+
}
|
|
1307
|
+
}
|
|
1308
|
+
}
|
|
1309
|
+
return {
|
|
1310
|
+
valid: issues.length === 0,
|
|
1311
|
+
chain_length: chain.length,
|
|
1312
|
+
issues
|
|
1313
|
+
};
|
|
1314
|
+
}
|
|
1315
|
+
};
|
|
1316
|
+
function createReceiptChannel(orchestratorId) {
|
|
1317
|
+
const propagator = new ReceiptPropagator({ issuer: orchestratorId });
|
|
1318
|
+
return {
|
|
1319
|
+
propagator,
|
|
1320
|
+
async withDelegation(delegateId, tools, fn, options) {
|
|
1321
|
+
const delegation = propagator.delegate(delegateId, {
|
|
1322
|
+
tools,
|
|
1323
|
+
scope: options?.scope || `task-${randomUUID().slice(0, 8)}`,
|
|
1324
|
+
ttl: options?.ttl || 3600,
|
|
1325
|
+
maxCalls: options?.maxCalls
|
|
1326
|
+
});
|
|
1327
|
+
const result = await fn({ delegation, propagator });
|
|
1328
|
+
return {
|
|
1329
|
+
result,
|
|
1330
|
+
delegation,
|
|
1331
|
+
chain: propagator.exportAll()
|
|
1332
|
+
};
|
|
1333
|
+
}
|
|
1334
|
+
};
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1337
|
+
// src/confidential.ts
|
|
1338
|
+
var ConfidentialGate = class {
|
|
1339
|
+
config;
|
|
1340
|
+
constructor(config) {
|
|
1341
|
+
this.config = config;
|
|
1342
|
+
}
|
|
1343
|
+
/**
|
|
1344
|
+
* Evaluate an attestation document and determine the resulting trust tier.
|
|
1345
|
+
*/
|
|
1346
|
+
evaluateAttestation(doc) {
|
|
1347
|
+
if (!this.config.accepted_providers.includes(doc.provider)) {
|
|
1348
|
+
return {
|
|
1349
|
+
accepted: false,
|
|
1350
|
+
tier: "unknown",
|
|
1351
|
+
provider: doc.provider,
|
|
1352
|
+
reason: `Provider ${doc.provider} not in accepted list: ${this.config.accepted_providers.join(", ")}`
|
|
1353
|
+
};
|
|
1354
|
+
}
|
|
1355
|
+
if (this.config.max_attestation_age) {
|
|
1356
|
+
const age = (Date.now() - new Date(doc.timestamp).getTime()) / 1e3;
|
|
1357
|
+
if (age > this.config.max_attestation_age) {
|
|
1358
|
+
return {
|
|
1359
|
+
accepted: false,
|
|
1360
|
+
tier: "unknown",
|
|
1361
|
+
provider: doc.provider,
|
|
1362
|
+
reason: `Attestation expired: age ${Math.floor(age)}s exceeds max ${this.config.max_attestation_age}s`
|
|
1363
|
+
};
|
|
1364
|
+
}
|
|
1365
|
+
}
|
|
1366
|
+
if (this.config.expected_measurements) {
|
|
1367
|
+
for (const [key, expected] of Object.entries(this.config.expected_measurements)) {
|
|
1368
|
+
const actual = doc.measurements[key];
|
|
1369
|
+
if (actual !== expected) {
|
|
1370
|
+
return {
|
|
1371
|
+
accepted: false,
|
|
1372
|
+
tier: "signed",
|
|
1373
|
+
provider: doc.provider,
|
|
1374
|
+
reason: `Measurement mismatch: ${key} expected ${expected}, got ${actual || "missing"}`
|
|
1375
|
+
};
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
}
|
|
1379
|
+
return {
|
|
1380
|
+
accepted: true,
|
|
1381
|
+
tier: "privileged",
|
|
1382
|
+
provider: doc.provider,
|
|
1383
|
+
reason: `Attestation verified: ${doc.provider} enclave with valid measurements`
|
|
1384
|
+
};
|
|
1385
|
+
}
|
|
1386
|
+
/**
|
|
1387
|
+
* Check if an agent's current tier requires attestation.
|
|
1388
|
+
*/
|
|
1389
|
+
requiresAttestation(currentTier) {
|
|
1390
|
+
if (!this.config.require_attestation) return false;
|
|
1391
|
+
const tierOrder = ["unknown", "signed", "evidenced", "privileged"];
|
|
1392
|
+
const requiredIdx = tierOrder.indexOf(this.config.min_trust_tier);
|
|
1393
|
+
const currentIdx = tierOrder.indexOf(currentTier);
|
|
1394
|
+
return currentIdx >= requiredIdx;
|
|
1395
|
+
}
|
|
1396
|
+
/**
|
|
1397
|
+
* Generate an attestation receipt documenting the evaluation.
|
|
1398
|
+
*/
|
|
1399
|
+
toReceipt(result, agentId) {
|
|
1400
|
+
return {
|
|
1401
|
+
receipt_type: "attestation",
|
|
1402
|
+
issuer_id: "confidential-gate",
|
|
1403
|
+
event_time: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1404
|
+
payload: {
|
|
1405
|
+
agent_id: agentId,
|
|
1406
|
+
provider: result.provider,
|
|
1407
|
+
accepted: result.accepted,
|
|
1408
|
+
resulting_tier: result.tier,
|
|
1409
|
+
reason: result.reason
|
|
1410
|
+
}
|
|
1411
|
+
};
|
|
1412
|
+
}
|
|
1413
|
+
};
|
|
1414
|
+
async function confidentialInference(_prompt, _config) {
|
|
1415
|
+
throw new Error(
|
|
1416
|
+
"Confidential inference requires a TEE/HE provider SDK. See docs at scopeblind.com/docs/confidential for setup instructions. Supported providers: Gramine (local_tee), Zama Concrete ML (homomorphic), NVIDIA Confidential Computing (secure_enclave)."
|
|
1417
|
+
);
|
|
1418
|
+
}
|
|
187
1419
|
export {
|
|
1420
|
+
ConfidentialGate,
|
|
188
1421
|
ProtectGateway,
|
|
1422
|
+
ReceiptPropagator,
|
|
1423
|
+
anchorToRekor,
|
|
189
1424
|
buildDecisionContext,
|
|
190
1425
|
checkRateLimit,
|
|
191
1426
|
collectSignedReceipts,
|
|
1427
|
+
computeCalibration,
|
|
1428
|
+
confidentialInference,
|
|
1429
|
+
createApprovalChallenge,
|
|
1430
|
+
createApprovalReceiptPayload,
|
|
1431
|
+
createAttestationField,
|
|
192
1432
|
createAuditBundle,
|
|
1433
|
+
createC2PAManifest,
|
|
1434
|
+
createDisclosurePackage,
|
|
1435
|
+
createEvidenceAttestation,
|
|
1436
|
+
createLogAnchorField,
|
|
1437
|
+
createReceiptChannel,
|
|
1438
|
+
createSandbox,
|
|
1439
|
+
createSandboxServer,
|
|
1440
|
+
destroySandbox,
|
|
1441
|
+
ed25519ToDIDKey,
|
|
193
1442
|
evaluateTier,
|
|
1443
|
+
exportC2PAManifestJSON,
|
|
1444
|
+
exportJSONL,
|
|
194
1445
|
formatReportMarkdown,
|
|
195
1446
|
formatSimulation,
|
|
1447
|
+
generateC2PACommand,
|
|
1448
|
+
generateDatasetCard,
|
|
1449
|
+
generateHFMetadata,
|
|
196
1450
|
generateReport,
|
|
1451
|
+
generateSafetyTranscript,
|
|
197
1452
|
getSignerInfo,
|
|
198
1453
|
getToolPolicy,
|
|
1454
|
+
hashReceipt,
|
|
1455
|
+
hashResponseBody,
|
|
199
1456
|
initSigning,
|
|
200
1457
|
isAgentId,
|
|
201
1458
|
isDisclosureMode,
|
|
@@ -204,14 +1461,31 @@ export {
|
|
|
204
1461
|
isSigningEnabled,
|
|
205
1462
|
listCredentialLabels,
|
|
206
1463
|
loadPolicy,
|
|
1464
|
+
manifestToVC,
|
|
207
1465
|
meetsMinTier,
|
|
208
1466
|
parseLogFile,
|
|
1467
|
+
parseNotificationConfigFromEnv,
|
|
209
1468
|
parseRateLimit,
|
|
210
1469
|
queryExternalPDP,
|
|
1470
|
+
receiptToVP,
|
|
1471
|
+
receiptsToHFRows,
|
|
1472
|
+
redactFields,
|
|
211
1473
|
resolveCredential,
|
|
1474
|
+
revealField,
|
|
1475
|
+
runInSandbox,
|
|
1476
|
+
sendApprovalNotification,
|
|
212
1477
|
signDecision,
|
|
213
1478
|
simulate,
|
|
1479
|
+
toCredentialRequestOptions,
|
|
1480
|
+
toManifoldFormat,
|
|
1481
|
+
toMetaculusFormat,
|
|
214
1482
|
validateCredentials,
|
|
215
1483
|
validateEvidenceReceipt,
|
|
216
|
-
validateManifest
|
|
1484
|
+
validateManifest,
|
|
1485
|
+
verifyActaC2PAAssertions,
|
|
1486
|
+
verifyAllCommitments,
|
|
1487
|
+
verifyApprovalAssertion,
|
|
1488
|
+
verifyCommitment,
|
|
1489
|
+
verifyEvidenceAttestation,
|
|
1490
|
+
verifyRekorAnchor
|
|
217
1491
|
};
|