@emilia-protocol/gate 0.11.0 → 0.14.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/CHANGELOG.md +80 -0
- package/README.md +310 -0
- package/action-control-manifest.js +3 -268
- package/action-escrow-custodian.js +3 -394
- package/action-escrow-evidence.js +3 -858
- package/action-escrow-package.js +3 -1668
- package/action-escrow-postgres.js +3 -337
- package/action-escrow-state.js +3 -396
- package/action-escrow-verifiers.js +3 -331
- package/action-escrow.js +3 -2447
- package/action-packs.js +3 -140
- package/adapters/_kit.js +3 -104
- package/adapters/aws.js +3 -108
- package/adapters/cloudflare.js +3 -54
- package/adapters/gcp.js +3 -70
- package/adapters/github.js +3 -109
- package/adapters/jira.js +3 -55
- package/adapters/k8s.js +3 -70
- package/adapters/linear.js +3 -55
- package/adapters/salesforce.js +3 -55
- package/adapters/stripe.js +3 -81
- package/adapters/supabase.js +3 -121
- package/adapters/terraform.js +3 -59
- package/adapters/vercel.js +3 -84
- package/aec-execution.js +3 -312
- package/breakglass.js +3 -582
- package/capability-receipt.js +4 -0
- package/cf1-conformance.js +3 -106
- package/challenge-store.js +3 -69
- package/control-plane.js +3 -340
- package/coverage.js +3 -721
- package/demo.mjs +1 -1
- package/deployment-attestation.js +3 -247
- package/dist/action-control-manifest.d.ts +82 -0
- package/dist/action-control-manifest.d.ts.map +1 -0
- package/dist/action-control-manifest.js +422 -0
- package/dist/action-control-manifest.js.map +1 -0
- package/dist/action-escrow-custodian.d.ts +74 -0
- package/dist/action-escrow-custodian.d.ts.map +1 -0
- package/dist/action-escrow-custodian.js +363 -0
- package/dist/action-escrow-custodian.js.map +1 -0
- package/dist/action-escrow-evidence.d.ts +130 -0
- package/dist/action-escrow-evidence.d.ts.map +1 -0
- package/dist/action-escrow-evidence.js +1012 -0
- package/dist/action-escrow-evidence.js.map +1 -0
- package/dist/action-escrow-package.d.ts +10 -0
- package/dist/action-escrow-package.d.ts.map +1 -0
- package/dist/action-escrow-package.js +1583 -0
- package/dist/action-escrow-package.js.map +1 -0
- package/dist/action-escrow-postgres.d.ts +62 -0
- package/dist/action-escrow-postgres.d.ts.map +1 -0
- package/dist/action-escrow-postgres.js +339 -0
- package/dist/action-escrow-postgres.js.map +1 -0
- package/dist/action-escrow-state.d.ts +141 -0
- package/dist/action-escrow-state.d.ts.map +1 -0
- package/dist/action-escrow-state.js +413 -0
- package/dist/action-escrow-state.js.map +1 -0
- package/dist/action-escrow-verifiers.d.ts +65 -0
- package/dist/action-escrow-verifiers.d.ts.map +1 -0
- package/dist/action-escrow-verifiers.js +421 -0
- package/dist/action-escrow-verifiers.js.map +1 -0
- package/dist/action-escrow.d.ts +112 -0
- package/dist/action-escrow.d.ts.map +1 -0
- package/dist/action-escrow.js +2661 -0
- package/dist/action-escrow.js.map +1 -0
- package/dist/action-packs.d.ts +54 -0
- package/dist/action-packs.d.ts.map +1 -0
- package/dist/action-packs.js +143 -0
- package/dist/action-packs.js.map +1 -0
- package/dist/adapters/_kit.d.ts +50 -0
- package/dist/adapters/_kit.d.ts.map +1 -0
- package/dist/adapters/_kit.js +98 -0
- package/dist/adapters/_kit.js.map +1 -0
- package/dist/adapters/aws.d.ts +158 -0
- package/dist/adapters/aws.d.ts.map +1 -0
- package/dist/adapters/aws.js +136 -0
- package/dist/adapters/aws.js.map +1 -0
- package/dist/adapters/cloudflare.d.ts +116 -0
- package/dist/adapters/cloudflare.d.ts.map +1 -0
- package/dist/adapters/cloudflare.js +75 -0
- package/dist/adapters/cloudflare.js.map +1 -0
- package/dist/adapters/gcp.d.ts +139 -0
- package/dist/adapters/gcp.d.ts.map +1 -0
- package/dist/adapters/gcp.js +69 -0
- package/dist/adapters/gcp.js.map +1 -0
- package/dist/adapters/github.d.ts +123 -0
- package/dist/adapters/github.d.ts.map +1 -0
- package/dist/adapters/github.js +105 -0
- package/dist/adapters/github.js.map +1 -0
- package/dist/adapters/jira.d.ts +109 -0
- package/dist/adapters/jira.d.ts.map +1 -0
- package/dist/adapters/jira.js +54 -0
- package/dist/adapters/jira.js.map +1 -0
- package/dist/adapters/k8s.d.ts +139 -0
- package/dist/adapters/k8s.d.ts.map +1 -0
- package/dist/adapters/k8s.js +69 -0
- package/dist/adapters/k8s.js.map +1 -0
- package/dist/adapters/linear.d.ts +109 -0
- package/dist/adapters/linear.d.ts.map +1 -0
- package/dist/adapters/linear.js +54 -0
- package/dist/adapters/linear.js.map +1 -0
- package/dist/adapters/salesforce.d.ts +109 -0
- package/dist/adapters/salesforce.d.ts.map +1 -0
- package/dist/adapters/salesforce.js +54 -0
- package/dist/adapters/salesforce.js.map +1 -0
- package/dist/adapters/stripe.d.ts +116 -0
- package/dist/adapters/stripe.d.ts.map +1 -0
- package/dist/adapters/stripe.js +77 -0
- package/dist/adapters/stripe.js.map +1 -0
- package/dist/adapters/supabase.d.ts +127 -0
- package/dist/adapters/supabase.d.ts.map +1 -0
- package/dist/adapters/supabase.js +112 -0
- package/dist/adapters/supabase.js.map +1 -0
- package/dist/adapters/terraform.d.ts +109 -0
- package/dist/adapters/terraform.d.ts.map +1 -0
- package/dist/adapters/terraform.js +58 -0
- package/dist/adapters/terraform.js.map +1 -0
- package/dist/adapters/vercel.d.ts +114 -0
- package/dist/adapters/vercel.d.ts.map +1 -0
- package/dist/adapters/vercel.js +81 -0
- package/dist/adapters/vercel.js.map +1 -0
- package/dist/aec-execution.d.ts +107 -0
- package/dist/aec-execution.d.ts.map +1 -0
- package/dist/aec-execution.js +334 -0
- package/dist/aec-execution.js.map +1 -0
- package/dist/breakglass.d.ts +205 -0
- package/dist/breakglass.d.ts.map +1 -0
- package/dist/breakglass.js +627 -0
- package/dist/breakglass.js.map +1 -0
- package/dist/capability-receipt.d.ts +601 -0
- package/dist/capability-receipt.d.ts.map +1 -0
- package/dist/capability-receipt.js +1177 -0
- package/dist/capability-receipt.js.map +1 -0
- package/dist/cf1-conformance.d.ts +83 -0
- package/dist/cf1-conformance.d.ts.map +1 -0
- package/dist/cf1-conformance.js +94 -0
- package/dist/cf1-conformance.js.map +1 -0
- package/dist/challenge-store.d.ts +20 -0
- package/dist/challenge-store.d.ts.map +1 -0
- package/dist/challenge-store.js +62 -0
- package/dist/challenge-store.js.map +1 -0
- package/dist/control-plane.d.ts +136 -0
- package/dist/control-plane.d.ts.map +1 -0
- package/dist/control-plane.js +349 -0
- package/dist/control-plane.js.map +1 -0
- package/dist/coverage.d.ts +156 -0
- package/dist/coverage.d.ts.map +1 -0
- package/dist/coverage.js +768 -0
- package/dist/coverage.js.map +1 -0
- package/dist/deployment-attestation.d.ts +93 -0
- package/dist/deployment-attestation.d.ts.map +1 -0
- package/dist/deployment-attestation.js +262 -0
- package/dist/deployment-attestation.js.map +1 -0
- package/dist/eg1-conformance.d.ts +286 -0
- package/dist/eg1-conformance.d.ts.map +1 -0
- package/dist/eg1-conformance.js +379 -0
- package/dist/eg1-conformance.js.map +1 -0
- package/dist/enterprise.d.ts +88 -0
- package/dist/enterprise.d.ts.map +1 -0
- package/dist/enterprise.js +194 -0
- package/dist/enterprise.js.map +1 -0
- package/dist/evidence-postgres.d.ts +123 -0
- package/dist/evidence-postgres.d.ts.map +1 -0
- package/dist/evidence-postgres.js +343 -0
- package/dist/evidence-postgres.js.map +1 -0
- package/dist/evidence.d.ts +113 -0
- package/dist/evidence.d.ts.map +1 -0
- package/dist/evidence.js +369 -0
- package/dist/evidence.js.map +1 -0
- package/dist/execution-binding.d.ts +49 -0
- package/dist/execution-binding.d.ts.map +1 -0
- package/dist/execution-binding.js +243 -0
- package/dist/execution-binding.js.map +1 -0
- package/dist/formal-runtime-map.d.ts +42 -0
- package/dist/formal-runtime-map.d.ts.map +1 -0
- package/dist/formal-runtime-map.js +23 -0
- package/dist/formal-runtime-map.js.map +1 -0
- package/dist/index.d.ts +1003 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1737 -0
- package/dist/index.js.map +1 -0
- package/dist/key-registry.d.ts +60 -0
- package/dist/key-registry.d.ts.map +1 -0
- package/dist/key-registry.js +144 -0
- package/dist/key-registry.js.map +1 -0
- package/dist/mcp.d.ts +53 -0
- package/dist/mcp.d.ts.map +1 -0
- package/dist/mcp.js +112 -0
- package/dist/mcp.js.map +1 -0
- package/dist/metering.d.ts +80 -0
- package/dist/metering.d.ts.map +1 -0
- package/dist/metering.js +227 -0
- package/dist/metering.js.map +1 -0
- package/dist/metrics.d.ts +68 -0
- package/dist/metrics.d.ts.map +1 -0
- package/dist/metrics.js +242 -0
- package/dist/metrics.js.map +1 -0
- package/dist/network-witness.d.ts +167 -0
- package/dist/network-witness.d.ts.map +1 -0
- package/dist/network-witness.js +520 -0
- package/dist/network-witness.js.map +1 -0
- package/dist/proposal-to-effect.d.ts +146 -0
- package/dist/proposal-to-effect.d.ts.map +1 -0
- package/dist/proposal-to-effect.js +427 -0
- package/dist/proposal-to-effect.js.map +1 -0
- package/dist/protocol-state.d.ts +141 -0
- package/dist/protocol-state.d.ts.map +1 -0
- package/dist/protocol-state.js +106 -0
- package/dist/protocol-state.js.map +1 -0
- package/dist/receipt-program.d.ts +59 -0
- package/dist/receipt-program.d.ts.map +1 -0
- package/dist/receipt-program.js +1053 -0
- package/dist/receipt-program.js.map +1 -0
- package/dist/reliance-kernel.d.ts +66 -0
- package/dist/reliance-kernel.d.ts.map +1 -0
- package/dist/reliance-kernel.js +103 -0
- package/dist/reliance-kernel.js.map +1 -0
- package/dist/reliance-packet.d.ts +67 -0
- package/dist/reliance-packet.d.ts.map +1 -0
- package/dist/reliance-packet.js +176 -0
- package/dist/reliance-packet.js.map +1 -0
- package/dist/remedy-program-postgres.d.ts +37 -0
- package/dist/remedy-program-postgres.d.ts.map +1 -0
- package/dist/remedy-program-postgres.js +291 -0
- package/dist/remedy-program-postgres.js.map +1 -0
- package/dist/remedy-program-receipt.d.ts +97 -0
- package/dist/remedy-program-receipt.d.ts.map +1 -0
- package/dist/remedy-program-receipt.js +817 -0
- package/dist/remedy-program-receipt.js.map +1 -0
- package/dist/remedy-program.d.ts +76 -0
- package/dist/remedy-program.d.ts.map +1 -0
- package/dist/remedy-program.js +1346 -0
- package/dist/remedy-program.js.map +1 -0
- package/dist/reports/art14.d.ts +101 -0
- package/dist/reports/art14.d.ts.map +1 -0
- package/dist/reports/art14.js +340 -0
- package/dist/reports/art14.js.map +1 -0
- package/dist/reports/assurance-package.d.ts +197 -0
- package/dist/reports/assurance-package.d.ts.map +1 -0
- package/dist/reports/assurance-package.js +313 -0
- package/dist/reports/assurance-package.js.map +1 -0
- package/dist/reports/auditor-workpaper.d.ts +194 -0
- package/dist/reports/auditor-workpaper.d.ts.map +1 -0
- package/dist/reports/auditor-workpaper.js +545 -0
- package/dist/reports/auditor-workpaper.js.map +1 -0
- package/dist/reports/external-verification.d.ts +76 -0
- package/dist/reports/external-verification.d.ts.map +1 -0
- package/dist/reports/external-verification.js +209 -0
- package/dist/reports/external-verification.js.map +1 -0
- package/dist/reports/reperform.d.ts +122 -0
- package/dist/reports/reperform.d.ts.map +1 -0
- package/dist/reports/reperform.js +432 -0
- package/dist/reports/reperform.js.map +1 -0
- package/dist/reports/underwriter.d.ts +127 -0
- package/dist/reports/underwriter.d.ts.map +1 -0
- package/dist/reports/underwriter.js +348 -0
- package/dist/reports/underwriter.js.map +1 -0
- package/dist/retention.d.ts +88 -0
- package/dist/retention.d.ts.map +1 -0
- package/dist/retention.js +90 -0
- package/dist/retention.js.map +1 -0
- package/dist/roster.d.ts +113 -0
- package/dist/roster.d.ts.map +1 -0
- package/dist/roster.js +261 -0
- package/dist/roster.js.map +1 -0
- package/dist/runtime-monitor.d.ts +132 -0
- package/dist/runtime-monitor.d.ts.map +1 -0
- package/dist/runtime-monitor.js +197 -0
- package/dist/runtime-monitor.js.map +1 -0
- package/dist/settlement.d.ts +68 -0
- package/dist/settlement.d.ts.map +1 -0
- package/dist/settlement.js +306 -0
- package/dist/settlement.js.map +1 -0
- package/dist/siem.d.ts +261 -0
- package/dist/siem.d.ts.map +1 -0
- package/dist/siem.js +247 -0
- package/dist/siem.js.map +1 -0
- package/dist/store-postgres.d.ts +107 -0
- package/dist/store-postgres.d.ts.map +1 -0
- package/dist/store-postgres.js +152 -0
- package/dist/store-postgres.js.map +1 -0
- package/dist/store.d.ts +95 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +202 -0
- package/dist/store.js.map +1 -0
- package/dist/strict-json.d.ts +14 -0
- package/dist/strict-json.d.ts.map +1 -0
- package/dist/strict-json.js +132 -0
- package/dist/strict-json.js.map +1 -0
- package/dist/trust-program-adapters.d.ts +122 -0
- package/dist/trust-program-adapters.d.ts.map +1 -0
- package/dist/trust-program-adapters.js +802 -0
- package/dist/trust-program-adapters.js.map +1 -0
- package/dist/trust-program-postgres.d.ts +41 -0
- package/dist/trust-program-postgres.d.ts.map +1 -0
- package/dist/trust-program-postgres.js +346 -0
- package/dist/trust-program-postgres.js.map +1 -0
- package/dist/trust-program-revocation.d.ts +206 -0
- package/dist/trust-program-revocation.d.ts.map +1 -0
- package/dist/trust-program-revocation.js +600 -0
- package/dist/trust-program-revocation.js.map +1 -0
- package/dist/trust-program.d.ts +197 -0
- package/dist/trust-program.d.ts.map +1 -0
- package/dist/trust-program.js +1351 -0
- package/dist/trust-program.js.map +1 -0
- package/dist/witness-postgres.d.ts +43 -0
- package/dist/witness-postgres.d.ts.map +1 -0
- package/dist/witness-postgres.js +92 -0
- package/dist/witness-postgres.js.map +1 -0
- package/dist/zk-range-proof.d.ts +78 -0
- package/dist/zk-range-proof.d.ts.map +1 -0
- package/dist/zk-range-proof.js +228 -0
- package/dist/zk-range-proof.js.map +1 -0
- package/eg1-conformance.js +3 -404
- package/enterprise.js +3 -180
- package/ep-assure.mjs +1 -0
- package/evidence-postgres.js +3 -356
- package/evidence.js +4 -360
- package/execution-binding.js +3 -212
- package/formal-runtime-map.js +4 -0
- package/index.js +4 -1249
- package/key-registry.js +3 -134
- package/mcp.js +3 -109
- package/metering.js +3 -226
- package/metrics.js +3 -231
- package/network-witness.js +3 -499
- package/package.json +35 -4
- package/proposal-to-effect.js +4 -0
- package/receipt-program.js +4 -0
- package/reliance-kernel.js +3 -112
- package/reliance-packet.js +3 -175
- package/remedy-program-postgres.js +4 -0
- package/remedy-program-receipt.js +4 -0
- package/remedy-program.js +4 -0
- package/reports/art14.js +0 -0
- package/reports/assurance-package.js +2 -312
- package/reports/auditor-workpaper.js +3 -537
- package/reports/external-verification.js +3 -222
- package/reports/reperform.js +3 -424
- package/reports/underwriter.js +3 -339
- package/retention.js +3 -84
- package/roster.js +3 -264
- package/runtime-monitor.js +4 -0
- package/settlement.js +3 -299
- package/siem.js +3 -235
- package/src/action-control-manifest.ts +424 -0
- package/src/action-escrow-custodian.ts +427 -0
- package/src/action-escrow-evidence.ts +1178 -0
- package/src/action-escrow-package.ts +1821 -0
- package/src/action-escrow-postgres.ts +366 -0
- package/src/action-escrow-state.ts +498 -0
- package/src/action-escrow-verifiers.ts +484 -0
- package/src/action-escrow.ts +3039 -0
- package/src/action-packs.ts +170 -0
- package/src/adapters/_kit.ts +117 -0
- package/src/adapters/aws.ts +142 -0
- package/src/adapters/cloudflare.ts +78 -0
- package/src/adapters/gcp.ts +71 -0
- package/src/adapters/github.ts +110 -0
- package/src/adapters/jira.ts +56 -0
- package/src/adapters/k8s.ts +71 -0
- package/src/adapters/linear.ts +56 -0
- package/src/adapters/salesforce.ts +56 -0
- package/src/adapters/stripe.ts +82 -0
- package/src/adapters/supabase.ts +122 -0
- package/src/adapters/terraform.ts +60 -0
- package/src/adapters/vercel.ts +85 -0
- package/src/aec-execution.ts +354 -0
- package/src/breakglass.ts +647 -0
- package/src/capability-receipt.ts +1258 -0
- package/src/cf1-conformance.ts +120 -0
- package/src/challenge-store.ts +70 -0
- package/src/control-plane.ts +374 -0
- package/src/coverage.ts +832 -0
- package/src/deployment-attestation.ts +259 -0
- package/src/eg1-conformance.ts +471 -0
- package/src/enterprise.ts +195 -0
- package/src/evidence-postgres.ts +374 -0
- package/src/evidence.ts +367 -0
- package/src/execution-binding.ts +236 -0
- package/src/formal-runtime-map.ts +24 -0
- package/src/index.ts +2127 -0
- package/src/key-registry.ts +150 -0
- package/src/mcp.ts +120 -0
- package/src/metering.ts +237 -0
- package/src/metrics.ts +232 -0
- package/src/network-witness.ts +585 -0
- package/src/proposal-to-effect.ts +571 -0
- package/src/protocol-state.ts +143 -0
- package/src/protocol-state.typecheck.ts +94 -0
- package/src/receipt-program.ts +1105 -0
- package/src/reliance-kernel.ts +119 -0
- package/src/reliance-packet.ts +206 -0
- package/src/remedy-program-postgres.ts +367 -0
- package/src/remedy-program-receipt.ts +891 -0
- package/src/remedy-program.ts +1388 -0
- package/src/reports/art14.ts +361 -0
- package/src/reports/assurance-package.ts +330 -0
- package/src/reports/auditor-workpaper.ts +558 -0
- package/src/reports/external-verification.ts +232 -0
- package/src/reports/reperform.ts +441 -0
- package/src/reports/underwriter.ts +356 -0
- package/src/retention.ts +100 -0
- package/src/roster.ts +273 -0
- package/src/runtime-monitor.ts +217 -0
- package/src/settlement.ts +313 -0
- package/src/siem.ts +247 -0
- package/src/store-postgres.ts +167 -0
- package/src/store.ts +214 -0
- package/src/strict-json.ts +115 -0
- package/src/trust-program-adapters.ts +847 -0
- package/src/trust-program-postgres.ts +429 -0
- package/src/trust-program-revocation.ts +751 -0
- package/src/trust-program.ts +1460 -0
- package/src/witness-postgres.ts +106 -0
- package/src/zk-range-proof.ts +250 -0
- package/store-postgres.js +3 -161
- package/store.js +4 -198
- package/strict-json.js +3 -102
- package/trust-program-adapters.js +4 -0
- package/trust-program-postgres.js +4 -0
- package/trust-program-revocation.js +4 -0
- package/trust-program.js +4 -0
- package/witness-postgres.js +3 -96
- package/zk-range-proof.js +4 -0
|
@@ -0,0 +1,802 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
/**
|
|
4
|
+
* Constructor-pinned adapters for the Gate Trust Program profile.
|
|
5
|
+
*
|
|
6
|
+
* These adapters do not create another policy engine. They provide the narrow
|
|
7
|
+
* joins needed to consume existing Quorum, AEC, Receipt Program, and Action
|
|
8
|
+
* Escrow verification results without allowing a presenter to choose verifier
|
|
9
|
+
* functions, trust roots, policies, mappings, or expected values at runtime.
|
|
10
|
+
*/
|
|
11
|
+
import crypto from 'node:crypto';
|
|
12
|
+
// The compatibility entry point resolves to dist both from src during native
|
|
13
|
+
// TypeScript tests and from the compiled dist module.
|
|
14
|
+
// @ts-ignore -- declarations live behind the compatibility entry point.
|
|
15
|
+
import { canonicalize } from '../execution-binding.js';
|
|
16
|
+
const DIGEST = /^sha256:[0-9a-f]{64}$/;
|
|
17
|
+
const BASE64URL = /^[A-Za-z0-9_-]+$/;
|
|
18
|
+
const TRUST_BINDING_KEYS = new Set([
|
|
19
|
+
'instance_id',
|
|
20
|
+
'program_digest',
|
|
21
|
+
'program_version',
|
|
22
|
+
'root_caid',
|
|
23
|
+
'action_digest',
|
|
24
|
+
'stage_id',
|
|
25
|
+
'requirement_id',
|
|
26
|
+
'policy_digest',
|
|
27
|
+
'predecessor_receipt_digests',
|
|
28
|
+
]);
|
|
29
|
+
const ARTIFACT_KEYS = new Set(['evidence_id', 'binding', 'evidence']);
|
|
30
|
+
const QUORUM_EVIDENCE_KEYS = new Set(['members']);
|
|
31
|
+
const QUORUM_MEMBER_KEYS = new Set(['role', 'signoff']);
|
|
32
|
+
const RECEIPT_EVIDENCE_KEYS = new Set(['certificate']);
|
|
33
|
+
const ACTION_ESCROW_EVIDENCE_KEYS = new Set([
|
|
34
|
+
'package', 'document_bytes', 'project_record_bytes',
|
|
35
|
+
]);
|
|
36
|
+
const ACTION_ESCROW_COMPONENT_VERIFIERS = Object.freeze([
|
|
37
|
+
'verifyBinding',
|
|
38
|
+
'verifyProjectRecord',
|
|
39
|
+
'verifyProfile',
|
|
40
|
+
'verifyDocumentExecution',
|
|
41
|
+
'verifyAgreementAcceptance',
|
|
42
|
+
'verifyReleaseApproval',
|
|
43
|
+
'verifyFunding',
|
|
44
|
+
'verifyMilestone',
|
|
45
|
+
'verifyRelease',
|
|
46
|
+
'verifyAmendment',
|
|
47
|
+
'verifyState',
|
|
48
|
+
]);
|
|
49
|
+
const FORBIDDEN_RUNTIME_TRUST_KEYS = new Set([
|
|
50
|
+
'approverKeys',
|
|
51
|
+
'componentVerifiers',
|
|
52
|
+
'expectedAction',
|
|
53
|
+
'expectedActionDigest',
|
|
54
|
+
'expectedAgreementId',
|
|
55
|
+
'expectedContext',
|
|
56
|
+
'expectedProgramDigest',
|
|
57
|
+
'keys',
|
|
58
|
+
'keysByType',
|
|
59
|
+
'mappings',
|
|
60
|
+
'policies',
|
|
61
|
+
'policiesByType',
|
|
62
|
+
'resolveCaid',
|
|
63
|
+
'trustedCertificateKeys',
|
|
64
|
+
'trustedConfiguration',
|
|
65
|
+
'trustedKeys',
|
|
66
|
+
'trustRoots',
|
|
67
|
+
'verificationOptions',
|
|
68
|
+
'verifierFunctions',
|
|
69
|
+
'verifiers',
|
|
70
|
+
]);
|
|
71
|
+
const VERIFY_PACKAGE = '@emilia-protocol/verify';
|
|
72
|
+
const AEC_PACKAGE = '@emilia-protocol/verify/evidence-chain';
|
|
73
|
+
const LOCAL_VERIFY_PACKAGE = '../../verify/index.js';
|
|
74
|
+
const LOCAL_AEC_PACKAGE = '../../verify/evidence-chain.js';
|
|
75
|
+
const RECEIPT_PROGRAM_MODULE = '../receipt-program.js';
|
|
76
|
+
const ACTION_ESCROW_EVIDENCE_MODULE = '../action-escrow-evidence.js';
|
|
77
|
+
async function verifyQuorumDefault(quorum, options) {
|
|
78
|
+
try {
|
|
79
|
+
const verifier = await import(VERIFY_PACKAGE);
|
|
80
|
+
return verifier.verifyQuorum(quorum, options);
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
if (error?.code !== 'ERR_MODULE_NOT_FOUND')
|
|
84
|
+
throw error;
|
|
85
|
+
const verifier = await import(LOCAL_VERIFY_PACKAGE);
|
|
86
|
+
return verifier.verifyQuorum(quorum, options);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
async function verifyAuthorizationChainDefault(chain, options) {
|
|
90
|
+
try {
|
|
91
|
+
const verifier = await import(AEC_PACKAGE);
|
|
92
|
+
return verifier.verifyAuthorizationChain(chain, options);
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
if (error?.code !== 'ERR_MODULE_NOT_FOUND')
|
|
96
|
+
throw error;
|
|
97
|
+
const verifier = await import(LOCAL_AEC_PACKAGE);
|
|
98
|
+
return verifier.verifyAuthorizationChain(chain, options);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
async function verifyReceiptProgramCertificateDefault(certificate, options) {
|
|
102
|
+
const verifier = await import(RECEIPT_PROGRAM_MODULE);
|
|
103
|
+
return verifier.verifyReceiptProgramCertificate(certificate, options);
|
|
104
|
+
}
|
|
105
|
+
async function verifyActionEscrowEvidencePackageDefault(pkg, options) {
|
|
106
|
+
const verifier = await import(ACTION_ESCROW_EVIDENCE_MODULE);
|
|
107
|
+
return verifier.verifyActionEscrowEvidencePackage(pkg, options);
|
|
108
|
+
}
|
|
109
|
+
function refusal(reason) {
|
|
110
|
+
return Object.freeze({ valid: false, reason });
|
|
111
|
+
}
|
|
112
|
+
function terminalRefusal(reason) {
|
|
113
|
+
return Object.freeze({
|
|
114
|
+
valid: false,
|
|
115
|
+
reason,
|
|
116
|
+
outcome: null,
|
|
117
|
+
evidence_digest: null,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
function isRecord(value) {
|
|
121
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value))
|
|
122
|
+
return false;
|
|
123
|
+
const prototype = Object.getPrototypeOf(value);
|
|
124
|
+
return prototype === Object.prototype || prototype === null;
|
|
125
|
+
}
|
|
126
|
+
/** Only enumerable data properties are accepted from a presenter. */
|
|
127
|
+
function isDataRecord(value) {
|
|
128
|
+
if (!isRecord(value))
|
|
129
|
+
return false;
|
|
130
|
+
return Reflect.ownKeys(value).every((key) => {
|
|
131
|
+
if (typeof key !== 'string')
|
|
132
|
+
return false;
|
|
133
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
134
|
+
return descriptor?.enumerable === true && Object.hasOwn(descriptor, 'value');
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
function exactKeys(value, allowed, required = allowed) {
|
|
138
|
+
return isDataRecord(value)
|
|
139
|
+
&& Object.keys(value).every((key) => allowed.has(key))
|
|
140
|
+
&& [...required].every((key) => Object.hasOwn(value, key));
|
|
141
|
+
}
|
|
142
|
+
function canonicalCopy(value) {
|
|
143
|
+
return JSON.parse(canonicalize(value));
|
|
144
|
+
}
|
|
145
|
+
function canonicalDigest(value) {
|
|
146
|
+
return `sha256:${crypto.createHash('sha256')
|
|
147
|
+
.update(Buffer.from(canonicalize(value), 'utf8')).digest('hex')}`;
|
|
148
|
+
}
|
|
149
|
+
function deepFreeze(value) {
|
|
150
|
+
if (!value || typeof value !== 'object' || Object.isFrozen(value))
|
|
151
|
+
return value;
|
|
152
|
+
Object.freeze(value);
|
|
153
|
+
for (const child of Object.values(value))
|
|
154
|
+
deepFreeze(child);
|
|
155
|
+
return value;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Snapshot constructor-owned configuration while preserving injected verifier
|
|
159
|
+
* function identity. Host objects such as KeyObject are immutable references;
|
|
160
|
+
* canonical data and byte arrays are copied.
|
|
161
|
+
*/
|
|
162
|
+
function snapshotPinned(value, seen = new WeakMap()) {
|
|
163
|
+
if (value === null || typeof value !== 'object')
|
|
164
|
+
return value;
|
|
165
|
+
if (value instanceof Uint8Array)
|
|
166
|
+
return Uint8Array.from(value);
|
|
167
|
+
if (value instanceof ArrayBuffer)
|
|
168
|
+
return value.slice(0);
|
|
169
|
+
if (value instanceof Date)
|
|
170
|
+
return new Date(value.getTime());
|
|
171
|
+
if (value instanceof crypto.KeyObject)
|
|
172
|
+
return value;
|
|
173
|
+
if (seen.has(value))
|
|
174
|
+
return seen.get(value);
|
|
175
|
+
if (Array.isArray(value)) {
|
|
176
|
+
const result = [];
|
|
177
|
+
seen.set(value, result);
|
|
178
|
+
for (const entry of value)
|
|
179
|
+
result.push(snapshotPinned(entry, seen));
|
|
180
|
+
return Object.freeze(result);
|
|
181
|
+
}
|
|
182
|
+
if (!isDataRecord(value)) {
|
|
183
|
+
throw new TypeError('pinned adapter configuration must use data properties');
|
|
184
|
+
}
|
|
185
|
+
const result = {};
|
|
186
|
+
seen.set(value, result);
|
|
187
|
+
for (const [key, entry] of Object.entries(value))
|
|
188
|
+
result[key] = snapshotPinned(entry, seen);
|
|
189
|
+
return Object.freeze(result);
|
|
190
|
+
}
|
|
191
|
+
function canonicalInstant(value) {
|
|
192
|
+
if (typeof value !== 'string'
|
|
193
|
+
|| !/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,9})?(?:Z|[+-]\d{2}:\d{2})$/.test(value)) {
|
|
194
|
+
return null;
|
|
195
|
+
}
|
|
196
|
+
const parsed = Date.parse(value);
|
|
197
|
+
return Number.isFinite(parsed) ? new Date(parsed).toISOString() : null;
|
|
198
|
+
}
|
|
199
|
+
function normalizedStrings(value) {
|
|
200
|
+
if (!Array.isArray(value) || value.length === 0 || value.length > 256)
|
|
201
|
+
return null;
|
|
202
|
+
const normalized = [];
|
|
203
|
+
for (const entry of value) {
|
|
204
|
+
if (typeof entry !== 'string' || entry.length === 0 || entry.length > 512
|
|
205
|
+
|| /[\u0000-\u001f\u007f]/.test(entry))
|
|
206
|
+
return null;
|
|
207
|
+
normalized.push(entry);
|
|
208
|
+
}
|
|
209
|
+
return [...new Set(normalized)].sort();
|
|
210
|
+
}
|
|
211
|
+
function normalizedFingerprints(value) {
|
|
212
|
+
if (!Array.isArray(value) || value.length === 0 || value.length > 256
|
|
213
|
+
|| value.some((entry) => typeof entry !== 'string' || !DIGEST.test(entry)))
|
|
214
|
+
return null;
|
|
215
|
+
return [...new Set(value)].sort();
|
|
216
|
+
}
|
|
217
|
+
function containsRuntimeTrustConfiguration(value) {
|
|
218
|
+
const stack = [value];
|
|
219
|
+
const seen = new WeakSet();
|
|
220
|
+
while (stack.length) {
|
|
221
|
+
const current = stack.pop();
|
|
222
|
+
if (!current || typeof current !== 'object')
|
|
223
|
+
continue;
|
|
224
|
+
if (seen.has(current))
|
|
225
|
+
return true;
|
|
226
|
+
seen.add(current);
|
|
227
|
+
if (Array.isArray(current)) {
|
|
228
|
+
stack.push(...current);
|
|
229
|
+
continue;
|
|
230
|
+
}
|
|
231
|
+
if (!isDataRecord(current))
|
|
232
|
+
return true;
|
|
233
|
+
for (const [key, entry] of Object.entries(current)) {
|
|
234
|
+
if (FORBIDDEN_RUNTIME_TRUST_KEYS.has(key))
|
|
235
|
+
return true;
|
|
236
|
+
if (entry && typeof entry === 'object')
|
|
237
|
+
stack.push(entry);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
return false;
|
|
241
|
+
}
|
|
242
|
+
function normalizeVerifiedClaims(result) {
|
|
243
|
+
const subjects = normalizedStrings(result.subjects);
|
|
244
|
+
const keyFingerprints = normalizedFingerprints(result.key_fingerprints);
|
|
245
|
+
const issuedAt = canonicalInstant(result.issued_at);
|
|
246
|
+
const expiresAt = canonicalInstant(result.expires_at);
|
|
247
|
+
const revocationCheckedAt = result.revocation_checked_at === null
|
|
248
|
+
|| result.revocation_checked_at === undefined
|
|
249
|
+
? null : canonicalInstant(result.revocation_checked_at);
|
|
250
|
+
if (!subjects || !keyFingerprints)
|
|
251
|
+
return refusal('evidence_principal_set_invalid');
|
|
252
|
+
if (!issuedAt || !expiresAt || Date.parse(expiresAt) <= Date.parse(issuedAt)) {
|
|
253
|
+
return refusal('evidence_time_invalid');
|
|
254
|
+
}
|
|
255
|
+
if (result.revocation_checked_at !== null && result.revocation_checked_at !== undefined
|
|
256
|
+
&& revocationCheckedAt === null)
|
|
257
|
+
return refusal('evidence_revocation_time_invalid');
|
|
258
|
+
return Object.freeze({
|
|
259
|
+
valid: true,
|
|
260
|
+
reason: null,
|
|
261
|
+
binding_digest: result.binding_digest,
|
|
262
|
+
policy_digest: result.policy_digest,
|
|
263
|
+
subjects,
|
|
264
|
+
key_fingerprints: keyFingerprints,
|
|
265
|
+
issued_at: issuedAt,
|
|
266
|
+
expires_at: expiresAt,
|
|
267
|
+
revocation_checked_at: revocationCheckedAt,
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
function exactTrustBinding(value, requirement, program) {
|
|
271
|
+
if (!exactKeys(value, TRUST_BINDING_KEYS)
|
|
272
|
+
|| typeof value.instance_id !== 'string' || value.instance_id.length === 0
|
|
273
|
+
|| typeof value.stage_id !== 'string' || value.stage_id.length === 0
|
|
274
|
+
|| value.requirement_id !== requirement.requirement_id
|
|
275
|
+
|| value.policy_digest !== requirement.policy_digest
|
|
276
|
+
|| value.program_version !== program.version
|
|
277
|
+
|| value.root_caid !== program.root_caid
|
|
278
|
+
|| value.action_digest !== program.action_digest
|
|
279
|
+
|| !DIGEST.test(value.program_digest)
|
|
280
|
+
|| !Array.isArray(value.predecessor_receipt_digests)
|
|
281
|
+
|| value.predecessor_receipt_digests.some((entry) => typeof entry !== 'string' || !DIGEST.test(entry))
|
|
282
|
+
|| new Set(value.predecessor_receipt_digests).size
|
|
283
|
+
!== value.predecessor_receipt_digests.length
|
|
284
|
+
|| value.predecessor_receipt_digests.some((entry, index) => index > 0
|
|
285
|
+
&& entry < value.predecessor_receipt_digests[index - 1]))
|
|
286
|
+
return null;
|
|
287
|
+
let digest;
|
|
288
|
+
try {
|
|
289
|
+
if (value.program_digest !== canonicalDigest(program))
|
|
290
|
+
return null;
|
|
291
|
+
digest = canonicalDigest(value);
|
|
292
|
+
}
|
|
293
|
+
catch {
|
|
294
|
+
return null;
|
|
295
|
+
}
|
|
296
|
+
return { binding: deepFreeze(canonicalCopy(value)), digest };
|
|
297
|
+
}
|
|
298
|
+
function resolvePinnedInstant(value) {
|
|
299
|
+
return typeof value === 'function' ? value() : value;
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* Wrap any evidence verifier in the Trust Program stage-verifier contract.
|
|
303
|
+
* Runtime artifacts have a closed three-field envelope, so trust configuration
|
|
304
|
+
* cannot ride beside the evidence and influence verification.
|
|
305
|
+
*/
|
|
306
|
+
export function createPinnedEvidenceAdapter({ policyDigest, verify, trustedConfiguration = {}, metadata, }) {
|
|
307
|
+
if (!DIGEST.test(policyDigest) || typeof verify !== 'function'
|
|
308
|
+
|| (metadata !== undefined && typeof metadata !== 'function')) {
|
|
309
|
+
throw new TypeError('pinned evidence adapter configuration invalid');
|
|
310
|
+
}
|
|
311
|
+
const pinnedConfiguration = snapshotPinned(trustedConfiguration);
|
|
312
|
+
return async function pinnedEvidenceAdapter({ artifact, requirement, program }) {
|
|
313
|
+
if (!exactKeys(artifact, ARTIFACT_KEYS))
|
|
314
|
+
return refusal('artifact_schema_invalid');
|
|
315
|
+
if (!isDataRecord(requirement) || !isDataRecord(program))
|
|
316
|
+
return refusal('verification_context_invalid');
|
|
317
|
+
if (requirement.policy_digest !== policyDigest)
|
|
318
|
+
return refusal('requirement_policy_mismatch');
|
|
319
|
+
const expected = exactTrustBinding(artifact.binding, requirement, program);
|
|
320
|
+
if (!expected)
|
|
321
|
+
return refusal('trust_binding_invalid');
|
|
322
|
+
let evidence;
|
|
323
|
+
try {
|
|
324
|
+
evidence = deepFreeze(canonicalCopy(artifact.evidence));
|
|
325
|
+
}
|
|
326
|
+
catch {
|
|
327
|
+
return refusal('evidence_not_canonical');
|
|
328
|
+
}
|
|
329
|
+
if (containsRuntimeTrustConfiguration(evidence)) {
|
|
330
|
+
return refusal('artifact_trust_configuration_forbidden');
|
|
331
|
+
}
|
|
332
|
+
const context = Object.freeze({
|
|
333
|
+
trustedConfiguration: pinnedConfiguration,
|
|
334
|
+
expectedBinding: expected.binding,
|
|
335
|
+
expectedBindingDigest: expected.digest,
|
|
336
|
+
expectedPolicyDigest: policyDigest,
|
|
337
|
+
requirement: deepFreeze(canonicalCopy(requirement)),
|
|
338
|
+
program: deepFreeze(canonicalCopy(program)),
|
|
339
|
+
});
|
|
340
|
+
let verified;
|
|
341
|
+
try {
|
|
342
|
+
verified = await verify(evidence, context);
|
|
343
|
+
}
|
|
344
|
+
catch {
|
|
345
|
+
return refusal('evidence_verification_failed');
|
|
346
|
+
}
|
|
347
|
+
if (!isDataRecord(verified) || verified.valid !== true) {
|
|
348
|
+
return refusal(typeof verified?.reason === 'string'
|
|
349
|
+
? verified.reason : 'evidence_verification_failed');
|
|
350
|
+
}
|
|
351
|
+
let claims = verified;
|
|
352
|
+
if (metadata) {
|
|
353
|
+
try {
|
|
354
|
+
const resolved = await metadata(verified, Object.freeze({ ...context, evidence }));
|
|
355
|
+
if (!isDataRecord(resolved))
|
|
356
|
+
return refusal('evidence_metadata_invalid');
|
|
357
|
+
claims = { ...verified, ...resolved };
|
|
358
|
+
}
|
|
359
|
+
catch {
|
|
360
|
+
return refusal('evidence_metadata_invalid');
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
if (claims.binding_digest !== expected.digest)
|
|
364
|
+
return refusal('evidence_binding_mismatch');
|
|
365
|
+
if (claims.policy_digest !== policyDigest)
|
|
366
|
+
return refusal('evidence_policy_mismatch');
|
|
367
|
+
return normalizeVerifiedClaims(claims);
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
/** Canonical SHA-256 fingerprint of an SPKI public key. */
|
|
371
|
+
export function canonicalKeyFingerprint(value) {
|
|
372
|
+
try {
|
|
373
|
+
let key;
|
|
374
|
+
if (value instanceof crypto.KeyObject) {
|
|
375
|
+
key = value.type === 'public' ? value : crypto.createPublicKey(value);
|
|
376
|
+
}
|
|
377
|
+
else {
|
|
378
|
+
if (typeof value !== 'string' || !BASE64URL.test(value))
|
|
379
|
+
return null;
|
|
380
|
+
const bytes = Buffer.from(value, 'base64url');
|
|
381
|
+
if (bytes.toString('base64url') !== value)
|
|
382
|
+
return null;
|
|
383
|
+
key = crypto.createPublicKey({ key: bytes, type: 'spki', format: 'der' });
|
|
384
|
+
}
|
|
385
|
+
const spki = key.export({ type: 'spki', format: 'der' });
|
|
386
|
+
return `sha256:${crypto.createHash('sha256').update(spki).digest('hex')}`;
|
|
387
|
+
}
|
|
388
|
+
catch {
|
|
389
|
+
return null;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
function publicKeyValue(value) {
|
|
393
|
+
try {
|
|
394
|
+
if (typeof value === 'string')
|
|
395
|
+
return canonicalKeyFingerprint(value) ? value : null;
|
|
396
|
+
if (!(value instanceof crypto.KeyObject))
|
|
397
|
+
return null;
|
|
398
|
+
const key = value.type === 'public' ? value : crypto.createPublicKey(value);
|
|
399
|
+
return key.export({ type: 'spki', format: 'der' }).toString('base64url');
|
|
400
|
+
}
|
|
401
|
+
catch {
|
|
402
|
+
return null;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
function validQuorumPolicy(policy) {
|
|
406
|
+
if (!isDataRecord(policy)
|
|
407
|
+
|| !['threshold', 'ordered'].includes(policy.mode)
|
|
408
|
+
|| !Number.isSafeInteger(policy.required) || policy.required < 1
|
|
409
|
+
|| !Array.isArray(policy.approvers) || policy.approvers.length === 0
|
|
410
|
+
|| policy.required > policy.approvers.length)
|
|
411
|
+
return false;
|
|
412
|
+
const slots = new Set();
|
|
413
|
+
for (const slot of policy.approvers) {
|
|
414
|
+
if (!isDataRecord(slot) || typeof slot.role !== 'string' || slot.role.length === 0
|
|
415
|
+
|| typeof slot.approver !== 'string' || slot.approver.length === 0)
|
|
416
|
+
return false;
|
|
417
|
+
const key = `${slot.role}\u0000${slot.approver}`;
|
|
418
|
+
if (slots.has(key))
|
|
419
|
+
return false;
|
|
420
|
+
slots.add(key);
|
|
421
|
+
}
|
|
422
|
+
return true;
|
|
423
|
+
}
|
|
424
|
+
/** Compose Trust Program with the repository's Quorum verifier. */
|
|
425
|
+
export function createQuorumTrustProgramAdapter(options) {
|
|
426
|
+
const policy = snapshotPinned(options.policy);
|
|
427
|
+
const approverKeys = snapshotPinned(options.approverKeys);
|
|
428
|
+
const verificationOptions = snapshotPinned(options.verificationOptions ?? {});
|
|
429
|
+
const verifyQuorum = options.verifyQuorum ?? verifyQuorumDefault;
|
|
430
|
+
const policyValid = validQuorumPolicy(policy);
|
|
431
|
+
const pinnedKeysValid = policyValid && policy.approvers.every((slot) => publicKeyValue(approverKeys[slot.approver]) !== null);
|
|
432
|
+
return createPinnedEvidenceAdapter({
|
|
433
|
+
policyDigest: options.policyDigest,
|
|
434
|
+
verify: async (evidence, context) => {
|
|
435
|
+
if (!policyValid || !pinnedKeysValid)
|
|
436
|
+
return refusal('quorum_policy_invalid');
|
|
437
|
+
if (!exactKeys(evidence, QUORUM_EVIDENCE_KEYS)
|
|
438
|
+
|| !Array.isArray(evidence.members) || evidence.members.length === 0
|
|
439
|
+
|| evidence.members.length > policy.approvers.length) {
|
|
440
|
+
return refusal('quorum_evidence_schema_invalid');
|
|
441
|
+
}
|
|
442
|
+
const members = [];
|
|
443
|
+
for (const member of evidence.members) {
|
|
444
|
+
if (!exactKeys(member, QUORUM_MEMBER_KEYS)
|
|
445
|
+
|| typeof member.role !== 'string' || !isDataRecord(member.signoff)
|
|
446
|
+
|| !isDataRecord(member.signoff.context)
|
|
447
|
+
|| typeof member.signoff.context.approver !== 'string') {
|
|
448
|
+
return refusal('quorum_evidence_schema_invalid');
|
|
449
|
+
}
|
|
450
|
+
const approver = member.signoff.context.approver;
|
|
451
|
+
const admitted = policy.approvers.some((slot) => slot.role === member.role && slot.approver === approver);
|
|
452
|
+
const publicKey = publicKeyValue(approverKeys[approver]);
|
|
453
|
+
if (!admitted || !publicKey)
|
|
454
|
+
return refusal('quorum_member_not_pinned');
|
|
455
|
+
members.push({
|
|
456
|
+
role: member.role,
|
|
457
|
+
approver_public_key: publicKey,
|
|
458
|
+
signoff: member.signoff,
|
|
459
|
+
});
|
|
460
|
+
}
|
|
461
|
+
let result;
|
|
462
|
+
try {
|
|
463
|
+
result = await verifyQuorum({
|
|
464
|
+
'@type': 'ep.quorum',
|
|
465
|
+
action_hash: context.expectedBindingDigest,
|
|
466
|
+
policy,
|
|
467
|
+
members,
|
|
468
|
+
}, verificationOptions);
|
|
469
|
+
}
|
|
470
|
+
catch {
|
|
471
|
+
return refusal('quorum_verification_failed');
|
|
472
|
+
}
|
|
473
|
+
if (!isDataRecord(result) || result.valid !== true)
|
|
474
|
+
return refusal('quorum_verification_failed');
|
|
475
|
+
const issued = members.map((member) => canonicalInstant(member.signoff.context.issued_at));
|
|
476
|
+
const expires = members.map((member) => canonicalInstant(member.signoff.context.expires_at));
|
|
477
|
+
if (issued.some((entry) => entry === null) || expires.some((entry) => entry === null)) {
|
|
478
|
+
return refusal('evidence_time_invalid');
|
|
479
|
+
}
|
|
480
|
+
const subjects = members.map((member) => member.signoff.context.approver);
|
|
481
|
+
const fingerprints = members.map((member) => canonicalKeyFingerprint(member.approver_public_key));
|
|
482
|
+
if (fingerprints.some((entry) => entry === null))
|
|
483
|
+
return refusal('evidence_principal_set_invalid');
|
|
484
|
+
return {
|
|
485
|
+
valid: true,
|
|
486
|
+
binding_digest: context.expectedBindingDigest,
|
|
487
|
+
policy_digest: options.policyDigest,
|
|
488
|
+
subjects,
|
|
489
|
+
key_fingerprints: fingerprints,
|
|
490
|
+
issued_at: issued.sort()[0],
|
|
491
|
+
expires_at: expires.sort()[0],
|
|
492
|
+
revocation_checked_at: resolvePinnedInstant(options.revocationCheckedAt),
|
|
493
|
+
};
|
|
494
|
+
},
|
|
495
|
+
});
|
|
496
|
+
}
|
|
497
|
+
/** Compose Trust Program with AEC under RP-owned policy, action, and trust roots. */
|
|
498
|
+
export function createAecTrustProgramAdapter(options) {
|
|
499
|
+
if (typeof options.requirement !== 'string' || !options.requirement.trim()) {
|
|
500
|
+
throw new TypeError('AEC relying-party requirement required');
|
|
501
|
+
}
|
|
502
|
+
const keysByType = snapshotPinned(options.keysByType);
|
|
503
|
+
const policiesByType = snapshotPinned(options.policiesByType);
|
|
504
|
+
const verifiers = snapshotPinned(options.verifiers ?? {});
|
|
505
|
+
const verifyAuthorizationChain = options.verifyAuthorizationChain
|
|
506
|
+
?? verifyAuthorizationChainDefault;
|
|
507
|
+
return createPinnedEvidenceAdapter({
|
|
508
|
+
policyDigest: options.policyDigest,
|
|
509
|
+
metadata: options.metadata,
|
|
510
|
+
verify: async (chain, context) => {
|
|
511
|
+
let result;
|
|
512
|
+
try {
|
|
513
|
+
result = await verifyAuthorizationChain(chain, {
|
|
514
|
+
keysByType,
|
|
515
|
+
policiesByType,
|
|
516
|
+
verifiers,
|
|
517
|
+
requirement: options.requirement,
|
|
518
|
+
expectedAction: context.expectedBinding,
|
|
519
|
+
expectedActionDigest: context.expectedBindingDigest,
|
|
520
|
+
verificationTime: resolvePinnedInstant(options.verificationTime),
|
|
521
|
+
});
|
|
522
|
+
}
|
|
523
|
+
catch {
|
|
524
|
+
return refusal('aec_verification_failed');
|
|
525
|
+
}
|
|
526
|
+
const actionDigest = typeof result?.action_digest === 'string'
|
|
527
|
+
? result.action_digest.replace(/^sha256:/, '') : null;
|
|
528
|
+
if (!isDataRecord(result) || result.satisfied !== true
|
|
529
|
+
|| result.expected_action_bound !== true
|
|
530
|
+
|| actionDigest !== context.expectedBindingDigest.slice('sha256:'.length)) {
|
|
531
|
+
return refusal('aec_verification_failed');
|
|
532
|
+
}
|
|
533
|
+
return {
|
|
534
|
+
...result,
|
|
535
|
+
valid: true,
|
|
536
|
+
binding_digest: context.expectedBindingDigest,
|
|
537
|
+
policy_digest: options.policyDigest,
|
|
538
|
+
};
|
|
539
|
+
},
|
|
540
|
+
});
|
|
541
|
+
}
|
|
542
|
+
function receiptProgramOwnership(binding) {
|
|
543
|
+
return isDataRecord(binding)
|
|
544
|
+
&& binding.consequence_mode === 'receipt-program'
|
|
545
|
+
&& typeof binding.capability_template_digest === 'string'
|
|
546
|
+
&& DIGEST.test(binding.capability_template_digest)
|
|
547
|
+
&& binding.escrow_profile_digest === null;
|
|
548
|
+
}
|
|
549
|
+
function actionEscrowOwnership(binding, profileDigest) {
|
|
550
|
+
return isDataRecord(binding)
|
|
551
|
+
&& binding.consequence_mode === 'action-escrow'
|
|
552
|
+
&& binding.capability_template_digest === null
|
|
553
|
+
&& binding.escrow_profile_digest === profileDigest
|
|
554
|
+
&& DIGEST.test(binding.escrow_profile_digest);
|
|
555
|
+
}
|
|
556
|
+
/** Explicitly detect and refuse Action Escrow nested under Receipt Program. */
|
|
557
|
+
export function containsActionEscrowConsequence(value) {
|
|
558
|
+
const stack = [value];
|
|
559
|
+
const seen = new WeakSet();
|
|
560
|
+
while (stack.length) {
|
|
561
|
+
const current = stack.pop();
|
|
562
|
+
if (!current || typeof current !== 'object')
|
|
563
|
+
continue;
|
|
564
|
+
if (seen.has(current))
|
|
565
|
+
return true;
|
|
566
|
+
seen.add(current);
|
|
567
|
+
if (Array.isArray(current)) {
|
|
568
|
+
stack.push(...current);
|
|
569
|
+
continue;
|
|
570
|
+
}
|
|
571
|
+
if (!isDataRecord(current))
|
|
572
|
+
return true;
|
|
573
|
+
for (const [key, entry] of Object.entries(current)) {
|
|
574
|
+
if (key.startsWith('action_escrow')
|
|
575
|
+
|| (key === 'consequence_mode' && entry === 'action-escrow')
|
|
576
|
+
|| (typeof entry === 'string'
|
|
577
|
+
&& (entry.startsWith('EP-ACTION-ESCROW-')
|
|
578
|
+
|| entry.toLowerCase().includes('action-escrow'))))
|
|
579
|
+
return true;
|
|
580
|
+
if (entry && typeof entry === 'object')
|
|
581
|
+
stack.push(entry);
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
return false;
|
|
585
|
+
}
|
|
586
|
+
function withOptions(fn, options) {
|
|
587
|
+
Object.defineProperty(fn, 'options', {
|
|
588
|
+
configurable: false,
|
|
589
|
+
enumerable: false,
|
|
590
|
+
writable: false,
|
|
591
|
+
value: options,
|
|
592
|
+
});
|
|
593
|
+
return Object.freeze(fn);
|
|
594
|
+
}
|
|
595
|
+
/** Verify and normalize one Receipt Program terminal certificate. */
|
|
596
|
+
export function createReceiptProgramTerminalOutcomeVerifier(options) {
|
|
597
|
+
if (typeof options.programId !== 'string' || options.programId.length === 0
|
|
598
|
+
|| (options.programDigest !== undefined && !DIGEST.test(options.programDigest))
|
|
599
|
+
|| typeof options.resolveCaid !== 'function') {
|
|
600
|
+
throw new TypeError('Receipt Program adapter configuration invalid');
|
|
601
|
+
}
|
|
602
|
+
const pinned = snapshotPinned({
|
|
603
|
+
programId: options.programId,
|
|
604
|
+
programDigest: options.programDigest,
|
|
605
|
+
trustedCertificateKeys: options.trustedCertificateKeys,
|
|
606
|
+
expectedContext: options.expectedContext,
|
|
607
|
+
resolveCaid: options.resolveCaid,
|
|
608
|
+
});
|
|
609
|
+
const verifyCertificate = options.verifyReceiptProgramCertificate
|
|
610
|
+
?? verifyReceiptProgramCertificateDefault;
|
|
611
|
+
const verifier = async ({ evidence, authorizationBinding }) => {
|
|
612
|
+
if (!receiptProgramOwnership(authorizationBinding)) {
|
|
613
|
+
return terminalRefusal('consequence_ownership_invalid');
|
|
614
|
+
}
|
|
615
|
+
if (!exactKeys(evidence, RECEIPT_EVIDENCE_KEYS)) {
|
|
616
|
+
return terminalRefusal('receipt_program_evidence_schema_invalid');
|
|
617
|
+
}
|
|
618
|
+
let certificate;
|
|
619
|
+
try {
|
|
620
|
+
certificate = deepFreeze(canonicalCopy(evidence.certificate));
|
|
621
|
+
}
|
|
622
|
+
catch {
|
|
623
|
+
return terminalRefusal('receipt_program_evidence_invalid');
|
|
624
|
+
}
|
|
625
|
+
if (containsActionEscrowConsequence(certificate?.program)) {
|
|
626
|
+
return terminalRefusal('action_escrow_receipt_program_nesting_refused');
|
|
627
|
+
}
|
|
628
|
+
let result;
|
|
629
|
+
try {
|
|
630
|
+
result = await verifyCertificate(certificate, {
|
|
631
|
+
trustedCertificateKeys: pinned.trustedCertificateKeys,
|
|
632
|
+
expectedContext: pinned.expectedContext,
|
|
633
|
+
resolveCaid: pinned.resolveCaid,
|
|
634
|
+
});
|
|
635
|
+
}
|
|
636
|
+
catch {
|
|
637
|
+
return terminalRefusal('receipt_program_verification_failed');
|
|
638
|
+
}
|
|
639
|
+
const certificateProgram = certificate.program;
|
|
640
|
+
if (!isDataRecord(result) || result.ok !== true
|
|
641
|
+
|| !isDataRecord(certificateProgram)
|
|
642
|
+
|| !['executed', 'refused', 'indeterminate'].includes(result.outcome)
|
|
643
|
+
|| certificate.outcome !== result.outcome
|
|
644
|
+
|| certificateProgram.program_id !== pinned.programId
|
|
645
|
+
|| certificateProgram.operation_id !== authorizationBinding.operation_id
|
|
646
|
+
|| certificateProgram.action_digest !== authorizationBinding.action_digest
|
|
647
|
+
|| certificateProgram.caid !== authorizationBinding.root_caid
|
|
648
|
+
|| (pinned.programDigest !== undefined && result.program_digest !== pinned.programDigest)) {
|
|
649
|
+
return terminalRefusal('receipt_program_binding_mismatch');
|
|
650
|
+
}
|
|
651
|
+
return Object.freeze({
|
|
652
|
+
valid: true,
|
|
653
|
+
reason: null,
|
|
654
|
+
outcome: result.outcome,
|
|
655
|
+
evidence_digest: canonicalDigest(certificate),
|
|
656
|
+
});
|
|
657
|
+
};
|
|
658
|
+
return withOptions(verifier, pinned);
|
|
659
|
+
}
|
|
660
|
+
/** Trust Program executionOutcomeVerifier wrapper for Receipt Program. */
|
|
661
|
+
export function createReceiptProgramExecutionOutcomeVerifier(options) {
|
|
662
|
+
const terminal = createReceiptProgramTerminalOutcomeVerifier(options);
|
|
663
|
+
return async function receiptProgramExecutionOutcomeVerifier(input) {
|
|
664
|
+
const result = await terminal(input);
|
|
665
|
+
return result.valid === true
|
|
666
|
+
&& result.outcome === input.outcome
|
|
667
|
+
&& result.evidence_digest === input.evidenceDigest;
|
|
668
|
+
};
|
|
669
|
+
}
|
|
670
|
+
function actionEscrowOutcome(stage) {
|
|
671
|
+
if (stage === 'released' || stage === 'completed')
|
|
672
|
+
return 'executed';
|
|
673
|
+
if (stage === 'cancelled')
|
|
674
|
+
return 'refused';
|
|
675
|
+
if (stage === 'release_indeterminate')
|
|
676
|
+
return 'indeterminate';
|
|
677
|
+
return null;
|
|
678
|
+
}
|
|
679
|
+
/** Verify and normalize one Action Escrow authenticated terminal package. */
|
|
680
|
+
export function createActionEscrowTerminalOutcomeVerifier(options) {
|
|
681
|
+
if (typeof options.agreementId !== 'string' || options.agreementId.length === 0
|
|
682
|
+
|| typeof options.operationId !== 'string' || options.operationId.length === 0
|
|
683
|
+
|| options.operationId.length > 512 || /[\u0000-\u001f\u007f]/.test(options.operationId)
|
|
684
|
+
|| !DIGEST.test(options.releaseActionDigest) || !DIGEST.test(options.profileDigest)
|
|
685
|
+
|| !isDataRecord(options.componentVerifiers)) {
|
|
686
|
+
throw new TypeError('Action Escrow adapter configuration invalid');
|
|
687
|
+
}
|
|
688
|
+
const componentVerifiers = snapshotPinned(options.componentVerifiers);
|
|
689
|
+
const pinned = snapshotPinned({
|
|
690
|
+
agreementId: options.agreementId,
|
|
691
|
+
operationId: options.operationId,
|
|
692
|
+
releaseActionDigest: options.releaseActionDigest,
|
|
693
|
+
profileDigest: options.profileDigest,
|
|
694
|
+
componentVerifiers,
|
|
695
|
+
now: options.now,
|
|
696
|
+
maxDocumentBytes: options.maxDocumentBytes,
|
|
697
|
+
maxProjectRecordBytes: options.maxProjectRecordBytes,
|
|
698
|
+
});
|
|
699
|
+
const verifyPackage = options.verifyActionEscrowEvidencePackage
|
|
700
|
+
?? verifyActionEscrowEvidencePackageDefault;
|
|
701
|
+
const verifier = async ({ evidence, authorizationBinding }) => {
|
|
702
|
+
if (!actionEscrowOwnership(authorizationBinding, pinned.profileDigest)) {
|
|
703
|
+
return terminalRefusal('consequence_ownership_invalid');
|
|
704
|
+
}
|
|
705
|
+
if (authorizationBinding.operation_id !== pinned.operationId) {
|
|
706
|
+
return terminalRefusal('action_escrow_binding_mismatch');
|
|
707
|
+
}
|
|
708
|
+
if (!exactKeys(evidence, ACTION_ESCROW_EVIDENCE_KEYS, new Set(['package', 'document_bytes'])))
|
|
709
|
+
return terminalRefusal('action_escrow_evidence_schema_invalid');
|
|
710
|
+
let pkg;
|
|
711
|
+
try {
|
|
712
|
+
pkg = deepFreeze(canonicalCopy(evidence.package));
|
|
713
|
+
}
|
|
714
|
+
catch {
|
|
715
|
+
return terminalRefusal('action_escrow_evidence_invalid');
|
|
716
|
+
}
|
|
717
|
+
const outcome = actionEscrowOutcome(pkg.stage);
|
|
718
|
+
if (!outcome)
|
|
719
|
+
return terminalRefusal('action_escrow_state_not_terminal');
|
|
720
|
+
if (pkg.agreement_id !== pinned.agreementId || pkg.package_digest === undefined
|
|
721
|
+
|| !DIGEST.test(pkg.package_digest)) {
|
|
722
|
+
return terminalRefusal('action_escrow_binding_mismatch');
|
|
723
|
+
}
|
|
724
|
+
if (outcome !== 'refused'
|
|
725
|
+
&& (!isDataRecord(pkg.release)
|
|
726
|
+
|| pkg.release.operation_idempotency_key !== pinned.operationId)) {
|
|
727
|
+
return terminalRefusal('action_escrow_binding_mismatch');
|
|
728
|
+
}
|
|
729
|
+
if (!(evidence.document_bytes instanceof Uint8Array)
|
|
730
|
+
|| (evidence.project_record_bytes !== undefined
|
|
731
|
+
&& !(evidence.project_record_bytes instanceof Uint8Array))) {
|
|
732
|
+
return terminalRefusal('action_escrow_evidence_invalid');
|
|
733
|
+
}
|
|
734
|
+
const verificationOptions = {
|
|
735
|
+
documentBytes: Uint8Array.from(evidence.document_bytes),
|
|
736
|
+
expectedAgreementId: pinned.agreementId,
|
|
737
|
+
};
|
|
738
|
+
if (evidence.project_record_bytes !== undefined) {
|
|
739
|
+
verificationOptions.projectRecordBytes = Uint8Array.from(evidence.project_record_bytes);
|
|
740
|
+
}
|
|
741
|
+
for (const name of ACTION_ESCROW_COMPONENT_VERIFIERS) {
|
|
742
|
+
const candidate = componentVerifiers[name];
|
|
743
|
+
if (candidate !== undefined) {
|
|
744
|
+
if (typeof candidate !== 'function')
|
|
745
|
+
return terminalRefusal('action_escrow_verifier_invalid');
|
|
746
|
+
verificationOptions[name] = candidate;
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
if (pinned.now !== undefined)
|
|
750
|
+
verificationOptions.now = resolvePinnedInstant(pinned.now);
|
|
751
|
+
if (pinned.maxDocumentBytes !== undefined) {
|
|
752
|
+
verificationOptions.maxDocumentBytes = pinned.maxDocumentBytes;
|
|
753
|
+
}
|
|
754
|
+
if (pinned.maxProjectRecordBytes !== undefined) {
|
|
755
|
+
verificationOptions.maxProjectRecordBytes = pinned.maxProjectRecordBytes;
|
|
756
|
+
}
|
|
757
|
+
let result;
|
|
758
|
+
try {
|
|
759
|
+
result = await verifyPackage(pkg, verificationOptions);
|
|
760
|
+
}
|
|
761
|
+
catch {
|
|
762
|
+
return terminalRefusal('action_escrow_verification_failed');
|
|
763
|
+
}
|
|
764
|
+
if (!isDataRecord(result) || result.valid !== true
|
|
765
|
+
|| result.package_digest !== pkg.package_digest
|
|
766
|
+
|| result.agreement_id !== pinned.agreementId
|
|
767
|
+
|| result.action_digest !== pinned.releaseActionDigest
|
|
768
|
+
|| result.profile_digest !== pinned.profileDigest
|
|
769
|
+
|| authorizationBinding.action_digest !== pinned.releaseActionDigest) {
|
|
770
|
+
return terminalRefusal('action_escrow_binding_mismatch');
|
|
771
|
+
}
|
|
772
|
+
return Object.freeze({
|
|
773
|
+
valid: true,
|
|
774
|
+
reason: null,
|
|
775
|
+
outcome,
|
|
776
|
+
evidence_digest: result.package_digest,
|
|
777
|
+
});
|
|
778
|
+
};
|
|
779
|
+
return withOptions(verifier, pinned);
|
|
780
|
+
}
|
|
781
|
+
/** Trust Program executionOutcomeVerifier wrapper for Action Escrow. */
|
|
782
|
+
export function createActionEscrowExecutionOutcomeVerifier(options) {
|
|
783
|
+
const terminal = createActionEscrowTerminalOutcomeVerifier(options);
|
|
784
|
+
return async function actionEscrowExecutionOutcomeVerifier(input) {
|
|
785
|
+
const result = await terminal(input);
|
|
786
|
+
return result.valid === true
|
|
787
|
+
&& result.outcome === input.outcome
|
|
788
|
+
&& result.evidence_digest === input.evidenceDigest;
|
|
789
|
+
};
|
|
790
|
+
}
|
|
791
|
+
export default {
|
|
792
|
+
canonicalKeyFingerprint,
|
|
793
|
+
containsActionEscrowConsequence,
|
|
794
|
+
createPinnedEvidenceAdapter,
|
|
795
|
+
createQuorumTrustProgramAdapter,
|
|
796
|
+
createAecTrustProgramAdapter,
|
|
797
|
+
createReceiptProgramTerminalOutcomeVerifier,
|
|
798
|
+
createReceiptProgramExecutionOutcomeVerifier,
|
|
799
|
+
createActionEscrowTerminalOutcomeVerifier,
|
|
800
|
+
createActionEscrowExecutionOutcomeVerifier,
|
|
801
|
+
};
|
|
802
|
+
//# sourceMappingURL=trust-program-adapters.js.map
|