@emilia-protocol/gate 0.11.0 → 0.13.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 +58 -0
- package/README.md +252 -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 +1002 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1736 -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/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 +31 -2
- 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 +2122 -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/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,286 @@
|
|
|
1
|
+
export declare const EG1_VERSION = "EG-1";
|
|
2
|
+
/**
|
|
3
|
+
* Mint a GENUINE WebAuthn ECDSA-P256 device signoff over an authorization
|
|
4
|
+
* context — the same structure @emilia-protocol/verify verifyWebAuthnSignoff
|
|
5
|
+
* checks. This is what earns a receipt its class_a tier: a real per-signer
|
|
6
|
+
* assertion, not a self-asserted `outcome` string. Used to build the Class-A and
|
|
7
|
+
* quorum evidence the EG-1 harness embeds so the Gate can CRYPTOGRAPHICALLY
|
|
8
|
+
* credit the tier.
|
|
9
|
+
* @param {{ actionHash?: string, approver?: string, issuedAtMs?: number, nonce?: string, prevContextHash?: string }} [opts]
|
|
10
|
+
*/
|
|
11
|
+
export declare function mintDeviceSignoff({ actionHash, approver, issuedAtMs, nonce, prevContextHash, }?: {
|
|
12
|
+
actionHash?: string;
|
|
13
|
+
approver?: string;
|
|
14
|
+
issuedAtMs?: number;
|
|
15
|
+
nonce?: string;
|
|
16
|
+
prevContextHash?: string;
|
|
17
|
+
}): {
|
|
18
|
+
signoff: {
|
|
19
|
+
'@type': string;
|
|
20
|
+
context: {
|
|
21
|
+
prev_context_hash?: string | undefined;
|
|
22
|
+
ep_version: string;
|
|
23
|
+
context_type: string;
|
|
24
|
+
action_hash: string | undefined;
|
|
25
|
+
policy: string;
|
|
26
|
+
nonce: string;
|
|
27
|
+
approver: string | undefined;
|
|
28
|
+
initiator: string;
|
|
29
|
+
issued_at: string;
|
|
30
|
+
expires_at: string;
|
|
31
|
+
};
|
|
32
|
+
webauthn: {
|
|
33
|
+
authenticator_data: string;
|
|
34
|
+
client_data_json: string;
|
|
35
|
+
signature: string;
|
|
36
|
+
};
|
|
37
|
+
approver_public_key: string;
|
|
38
|
+
};
|
|
39
|
+
approver_public_key: string;
|
|
40
|
+
context: {
|
|
41
|
+
prev_context_hash?: string | undefined;
|
|
42
|
+
ep_version: string;
|
|
43
|
+
context_type: string;
|
|
44
|
+
action_hash: string | undefined;
|
|
45
|
+
policy: string;
|
|
46
|
+
nonce: string;
|
|
47
|
+
approver: string | undefined;
|
|
48
|
+
initiator: string;
|
|
49
|
+
issued_at: string;
|
|
50
|
+
expires_at: string;
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Mint a GENUINE EP-QUORUM-v1 evidence document: N distinct humans, each on a
|
|
55
|
+
* distinct device key, each with a real WebAuthn assertion bound to the SAME
|
|
56
|
+
* action_hash, within a window. verifyQuorum returns valid for it. This is what
|
|
57
|
+
* earns a receipt its `quorum` tier — never a bare {signers,threshold} block.
|
|
58
|
+
* @param {{ actionHash?: string, threshold?: number, approvers?: Array<{ role: string, approver: string }>, issuedAtMs?: number }} [opts]
|
|
59
|
+
*/
|
|
60
|
+
export declare function mintQuorumEvidence({ actionHash, threshold, approvers, issuedAtMs, }?: {
|
|
61
|
+
actionHash?: string;
|
|
62
|
+
threshold?: number;
|
|
63
|
+
approvers?: Array<{
|
|
64
|
+
role: string;
|
|
65
|
+
approver: string;
|
|
66
|
+
}>;
|
|
67
|
+
issuedAtMs?: number;
|
|
68
|
+
}): {
|
|
69
|
+
'@type': string;
|
|
70
|
+
action_hash: string | undefined;
|
|
71
|
+
policy: {
|
|
72
|
+
mode: string;
|
|
73
|
+
required: number;
|
|
74
|
+
approvers: {
|
|
75
|
+
role: string;
|
|
76
|
+
approver: string;
|
|
77
|
+
}[];
|
|
78
|
+
distinct_humans: boolean;
|
|
79
|
+
window_sec: number;
|
|
80
|
+
};
|
|
81
|
+
members: {
|
|
82
|
+
role: string;
|
|
83
|
+
approver_public_key: string;
|
|
84
|
+
signoff: {
|
|
85
|
+
'@type': string;
|
|
86
|
+
context: {
|
|
87
|
+
prev_context_hash?: string | undefined;
|
|
88
|
+
ep_version: string;
|
|
89
|
+
context_type: string;
|
|
90
|
+
action_hash: string | undefined;
|
|
91
|
+
policy: string;
|
|
92
|
+
nonce: string;
|
|
93
|
+
approver: string | undefined;
|
|
94
|
+
initiator: string;
|
|
95
|
+
issued_at: string;
|
|
96
|
+
expires_at: string;
|
|
97
|
+
};
|
|
98
|
+
webauthn: {
|
|
99
|
+
authenticator_data: string;
|
|
100
|
+
client_data_json: string;
|
|
101
|
+
signature: string;
|
|
102
|
+
};
|
|
103
|
+
};
|
|
104
|
+
}[];
|
|
105
|
+
};
|
|
106
|
+
export declare const EG1_DEFAULT_SELECTOR: Readonly<{
|
|
107
|
+
protocol: "mcp";
|
|
108
|
+
tool: "release_payment";
|
|
109
|
+
}>;
|
|
110
|
+
export declare const EG1_DEFAULT_ACTION: Readonly<{
|
|
111
|
+
action_type: "payment.release";
|
|
112
|
+
amount_usd: 40000;
|
|
113
|
+
currency: "USD";
|
|
114
|
+
payment_instruction_id: "pi_eg1_40000";
|
|
115
|
+
beneficiary_account_hash: "sha256:eg1-beneficiary";
|
|
116
|
+
}>;
|
|
117
|
+
export declare const EG1_CHECKS: readonly {
|
|
118
|
+
id: string;
|
|
119
|
+
title: string;
|
|
120
|
+
}[];
|
|
121
|
+
/**
|
|
122
|
+
* Create an EG-1 harness: a throwaway issuer key + a receipt minter for the
|
|
123
|
+
* scenarios. Configure the subject's gate to trust `publicKey` for the run.
|
|
124
|
+
*/
|
|
125
|
+
export declare function createEg1Harness({ now, action, idPrefix, }?: {
|
|
126
|
+
now?: () => number;
|
|
127
|
+
action?: Record<string, unknown>;
|
|
128
|
+
idPrefix?: string;
|
|
129
|
+
}): {
|
|
130
|
+
publicKey: string;
|
|
131
|
+
approverKeys: {
|
|
132
|
+
'ep:key:eg1:class-a': {
|
|
133
|
+
approver_id: string;
|
|
134
|
+
public_key: string;
|
|
135
|
+
key_class: string;
|
|
136
|
+
};
|
|
137
|
+
'ep:key:eg1:class-a-2': {
|
|
138
|
+
approver_id: string;
|
|
139
|
+
public_key: string;
|
|
140
|
+
key_class: string;
|
|
141
|
+
};
|
|
142
|
+
'ep:key:eg1:controller': {
|
|
143
|
+
approver_id: string;
|
|
144
|
+
public_key: string;
|
|
145
|
+
key_class: string;
|
|
146
|
+
};
|
|
147
|
+
};
|
|
148
|
+
quorumPolicy: {
|
|
149
|
+
mode: string;
|
|
150
|
+
required: number;
|
|
151
|
+
distinct_humans: boolean;
|
|
152
|
+
window_sec: number;
|
|
153
|
+
approvers: {
|
|
154
|
+
role: string;
|
|
155
|
+
approver: string;
|
|
156
|
+
}[];
|
|
157
|
+
};
|
|
158
|
+
mint: ({ outcome, quorum, fakeQuorum, tamper, extra, }?: {
|
|
159
|
+
outcome?: "allow" | "allow_with_signoff";
|
|
160
|
+
quorum?: {
|
|
161
|
+
threshold?: number;
|
|
162
|
+
signers?: any[];
|
|
163
|
+
} | null;
|
|
164
|
+
fakeQuorum?: boolean;
|
|
165
|
+
tamper?: Record<string, any> | null;
|
|
166
|
+
extra?: Record<string, any>;
|
|
167
|
+
}) => {
|
|
168
|
+
'@version': string;
|
|
169
|
+
payload: {
|
|
170
|
+
receipt_id: string;
|
|
171
|
+
subject: string;
|
|
172
|
+
issuer: string;
|
|
173
|
+
created_at: string;
|
|
174
|
+
claim: Record<string, any>;
|
|
175
|
+
quorum?: any;
|
|
176
|
+
assurance_proof?: any;
|
|
177
|
+
signoff?: any;
|
|
178
|
+
approver_public_key?: string;
|
|
179
|
+
};
|
|
180
|
+
signature: {
|
|
181
|
+
algorithm: string;
|
|
182
|
+
value: string;
|
|
183
|
+
};
|
|
184
|
+
};
|
|
185
|
+
action: Record<string, unknown>;
|
|
186
|
+
actionHash: string;
|
|
187
|
+
now: () => number;
|
|
188
|
+
rpId: string;
|
|
189
|
+
allowedOrigins: string[];
|
|
190
|
+
};
|
|
191
|
+
/**
|
|
192
|
+
* Adapt an @emilia-protocol/gate instance into an EG-1 `invoke`. The gate must
|
|
193
|
+
* have been built trusting the harness public key. Uses gate.run() so the
|
|
194
|
+
* execution proof + reliance packet are produced on the allowed path.
|
|
195
|
+
*/
|
|
196
|
+
export declare function makeGateInvoke(gate: any, { selector, action }?: {
|
|
197
|
+
selector?: Readonly<{
|
|
198
|
+
protocol: "mcp";
|
|
199
|
+
tool: "release_payment";
|
|
200
|
+
}> | undefined;
|
|
201
|
+
action?: Readonly<{
|
|
202
|
+
action_type: "payment.release";
|
|
203
|
+
amount_usd: 40000;
|
|
204
|
+
currency: "USD";
|
|
205
|
+
payment_instruction_id: "pi_eg1_40000";
|
|
206
|
+
beneficiary_account_hash: "sha256:eg1-beneficiary";
|
|
207
|
+
}> | undefined;
|
|
208
|
+
}): ({ receipt, observedAction }: {
|
|
209
|
+
receipt: any;
|
|
210
|
+
observedAction: any;
|
|
211
|
+
}) => Promise<{
|
|
212
|
+
allowed: boolean;
|
|
213
|
+
status: any;
|
|
214
|
+
reason: any;
|
|
215
|
+
decisionHash?: undefined;
|
|
216
|
+
execution?: undefined;
|
|
217
|
+
packet?: undefined;
|
|
218
|
+
} | {
|
|
219
|
+
allowed: boolean;
|
|
220
|
+
status: number;
|
|
221
|
+
reason: any;
|
|
222
|
+
decisionHash: any;
|
|
223
|
+
execution: any;
|
|
224
|
+
packet: any;
|
|
225
|
+
}>;
|
|
226
|
+
/**
|
|
227
|
+
* Drive a subject through the eight EG-1 checks and return a JSON report.
|
|
228
|
+
* @param {object} [o]
|
|
229
|
+
* @param {(scenario:object)=>Promise<object>} [o.invoke] the integration under test
|
|
230
|
+
* @param {object} [o.harness] from createEg1Harness()
|
|
231
|
+
* @param {object} [o.action] the high-risk action (defaults to the harness action)
|
|
232
|
+
*/
|
|
233
|
+
export declare function runEg1({ invoke, harness, action, }?: {
|
|
234
|
+
invoke?: (scenario: {
|
|
235
|
+
receipt: any;
|
|
236
|
+
observedAction: any;
|
|
237
|
+
}) => Promise<{
|
|
238
|
+
allowed: boolean;
|
|
239
|
+
status?: number | null;
|
|
240
|
+
reason?: string | null;
|
|
241
|
+
decisionHash?: string | null;
|
|
242
|
+
execution?: {
|
|
243
|
+
authorizes_decision?: string | null;
|
|
244
|
+
} | null;
|
|
245
|
+
packet?: {
|
|
246
|
+
verdict?: string | null;
|
|
247
|
+
} | null;
|
|
248
|
+
}>;
|
|
249
|
+
harness?: ReturnType<typeof createEg1Harness>;
|
|
250
|
+
action?: Record<string, any>;
|
|
251
|
+
}): Promise<{
|
|
252
|
+
standard: string;
|
|
253
|
+
passed: boolean;
|
|
254
|
+
badge: string;
|
|
255
|
+
summary: {
|
|
256
|
+
passed: number;
|
|
257
|
+
total: number;
|
|
258
|
+
};
|
|
259
|
+
checks: any[];
|
|
260
|
+
generated_at: string;
|
|
261
|
+
}>;
|
|
262
|
+
declare const _default: {
|
|
263
|
+
EG1_VERSION: string;
|
|
264
|
+
EG1_CHECKS: readonly {
|
|
265
|
+
id: string;
|
|
266
|
+
title: string;
|
|
267
|
+
}[];
|
|
268
|
+
EG1_DEFAULT_ACTION: Readonly<{
|
|
269
|
+
action_type: "payment.release";
|
|
270
|
+
amount_usd: 40000;
|
|
271
|
+
currency: "USD";
|
|
272
|
+
payment_instruction_id: "pi_eg1_40000";
|
|
273
|
+
beneficiary_account_hash: "sha256:eg1-beneficiary";
|
|
274
|
+
}>;
|
|
275
|
+
EG1_DEFAULT_SELECTOR: Readonly<{
|
|
276
|
+
protocol: "mcp";
|
|
277
|
+
tool: "release_payment";
|
|
278
|
+
}>;
|
|
279
|
+
createEg1Harness: typeof createEg1Harness;
|
|
280
|
+
makeGateInvoke: typeof makeGateInvoke;
|
|
281
|
+
runEg1: typeof runEg1;
|
|
282
|
+
mintDeviceSignoff: typeof mintDeviceSignoff;
|
|
283
|
+
mintQuorumEvidence: typeof mintQuorumEvidence;
|
|
284
|
+
};
|
|
285
|
+
export default _default;
|
|
286
|
+
//# sourceMappingURL=eg1-conformance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"eg1-conformance.d.ts","sourceRoot":"","sources":["../src/eg1-conformance.ts"],"names":[],"mappings":"AAmCA,eAAO,MAAM,WAAW,SAAS,CAAC;AAalC;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,UAAU,EACV,QAAQ,EACR,UAAuB,EACvB,KAAK,EACL,eAA2B,GAC5B,GAAE;IACD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,eAAe,CAAC,EAAE,MAAM,CAAC;CACrB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAoCL;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,EACjC,UAAU,EACV,SAAa,EACb,SAAS,EACT,UAAuB,GACxB,GAAE;IACD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACtD,UAAU,CAAC,EAAE,MAAM,CAAC;CAChB;;;;;;;kBAFsB,MAAM;sBAAY,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAoBnD;AAID,eAAO,MAAM,oBAAoB;;;EAA8D,CAAC;AAChG,eAAO,MAAM,kBAAkB;;;;;;EAM7B,CAAC;AAEH,eAAO,MAAM,UAAU;;;GASrB,CAAC;AAEH;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,EAC/B,GAAc,EACd,MAA2B,EAC3B,QAAgB,GACjB,GAAE;IAAE,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6DAqH9E;QACD,OAAO,CAAC,EAAE,OAAO,GAAG,oBAAoB,CAAC;QACzC,MAAM,CAAC,EAAE;YAAE,SAAS,CAAC,EAAE,MAAM,CAAC;YAAC,OAAO,CAAC,EAAE,GAAG,EAAE,CAAA;SAAE,GAAG,IAAI,CAAC;QACxD,UAAU,CAAC,EAAE,OAAO,CAAC;QACrB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC;QACpC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;KAC7B;;;wBAMe,MAAM;qBACT,MAAM;oBACP,MAAM;wBACF,MAAM;mBACX,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;qBACjB,GAAG;8BACM,GAAG;sBACX,GAAG;kCACS,MAAM;;;;;;;;;;;;EA0CjC;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,IAAI,KAAA,EAAE,EAAE,QAA+B,EAAE,MAA2B,EAAE;;;;;;;;;;;;CAAK,IAI1F;;;CAA2B;;;;;;;;;;;;;;GAiB1C;AAID;;;;;;GAMG;AACH,wBAAsB,MAAM,CAAC,EAC3B,MAAM,EACN,OAAO,EACP,MAAM,GACP,GAAE;IACD,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE;QAAE,OAAO,EAAE,GAAG,CAAC;QAAC,cAAc,EAAE,GAAG,CAAA;KAAE,KAAK,OAAO,CAAC;QACpE,OAAO,EAAE,OAAO,CAAC;QACjB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACvB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACvB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC7B,SAAS,CAAC,EAAE;YAAE,mBAAmB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;SAAE,GAAG,IAAI,CAAC;QAC3D,MAAM,CAAC,EAAE;YAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;SAAE,GAAG,IAAI,CAAC;KAC7C,CAAC,CAAC;IACH,OAAO,CAAC,EAAE,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC;IAC9C,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CACzB;;;;;;;;;;GA6DL;;;;;;;;;;;;;;;;;;;;;;;;AAED,wBAAsK"}
|
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
/**
|
|
4
|
+
* EG-1 Conformance — the binary artifact that turns "we adopted EMILIA Gate"
|
|
5
|
+
* from a claim into a test result.
|
|
6
|
+
*
|
|
7
|
+
* The question EG-1 answers: *does your integration actually ENFORCE the gate,
|
|
8
|
+
* or are you only claiming it?* An integration earns EG-1 only if it
|
|
9
|
+
* demonstrably:
|
|
10
|
+
* 1. refuses a high-risk action with NO receipt (428);
|
|
11
|
+
* 2. refuses a software-tier receipt on a Class-A action;
|
|
12
|
+
* 3. refuses when the observed execution drifts from the authorized fields;
|
|
13
|
+
* 4. RUNS the action for a valid Class-A/quorum receipt;
|
|
14
|
+
* 5. refuses a replay of the same receipt;
|
|
15
|
+
* 6. refuses a tampered receipt;
|
|
16
|
+
* 7. emits an execution proof bound to the authorization decision;
|
|
17
|
+
* 8. produces a reliance packet whose verdict is "rely".
|
|
18
|
+
*
|
|
19
|
+
* This module is pure (no dependency on index.js, so no import cycle): it owns a
|
|
20
|
+
* throwaway issuer keypair, mints the scenario receipts, and drives any
|
|
21
|
+
* "subject" through the eight checks. A subject is an async `invoke` function
|
|
22
|
+
* representing one attempt at the guarded dangerous action:
|
|
23
|
+
*
|
|
24
|
+
* invoke({ receipt, observedAction }) -> {
|
|
25
|
+
* allowed: boolean, status: number, reason: string,
|
|
26
|
+
* // present only on an allowed run:
|
|
27
|
+
* decisionHash?: string, execution?: { authorizes_decision }, packet?: { verdict }
|
|
28
|
+
* }
|
|
29
|
+
*
|
|
30
|
+
* For integrations built on @emilia-protocol/gate, `makeGateInvoke(gate, ...)`
|
|
31
|
+
* produces a conformant `invoke` from `gate.run()`. Custom integrations (an HTTP
|
|
32
|
+
* service, a different language) implement `invoke` themselves and configure
|
|
33
|
+
* their gate to trust `harness.publicKey` for the run.
|
|
34
|
+
*/
|
|
35
|
+
import crypto from 'node:crypto';
|
|
36
|
+
export const EG1_VERSION = 'EG-1';
|
|
37
|
+
// Same sorted-key canonical JSON the receipt signature is computed over.
|
|
38
|
+
const canon = (v) => (v == null ? JSON.stringify(v)
|
|
39
|
+
: Array.isArray(v) ? `[${v.map(canon).join(',')}]`
|
|
40
|
+
: typeof v === 'object' ? `{${Object.keys(v).sort().map((k) => JSON.stringify(k) + ':' + canon(v[k])).join(',')}}`
|
|
41
|
+
: JSON.stringify(v));
|
|
42
|
+
const sha256Hex = (v) => crypto.createHash('sha256').update(v, 'utf8').digest('hex');
|
|
43
|
+
const sha256Bytes = (v) => crypto.createHash('sha256').update(v).digest();
|
|
44
|
+
const RP_ID = 'emiliaprotocol.ai';
|
|
45
|
+
const RP_ORIGIN = `https://www.${RP_ID}`;
|
|
46
|
+
/**
|
|
47
|
+
* Mint a GENUINE WebAuthn ECDSA-P256 device signoff over an authorization
|
|
48
|
+
* context — the same structure @emilia-protocol/verify verifyWebAuthnSignoff
|
|
49
|
+
* checks. This is what earns a receipt its class_a tier: a real per-signer
|
|
50
|
+
* assertion, not a self-asserted `outcome` string. Used to build the Class-A and
|
|
51
|
+
* quorum evidence the EG-1 harness embeds so the Gate can CRYPTOGRAPHICALLY
|
|
52
|
+
* credit the tier.
|
|
53
|
+
* @param {{ actionHash?: string, approver?: string, issuedAtMs?: number, nonce?: string, prevContextHash?: string }} [opts]
|
|
54
|
+
*/
|
|
55
|
+
export function mintDeviceSignoff({ actionHash, approver, issuedAtMs = Date.now(), nonce, prevContextHash = undefined, } = {}) {
|
|
56
|
+
const signer = crypto.generateKeyPairSync('ec', { namedCurve: 'P-256' });
|
|
57
|
+
const context = {
|
|
58
|
+
ep_version: '1.0', context_type: 'ep.signoff.v1',
|
|
59
|
+
action_hash: actionHash,
|
|
60
|
+
policy: 'policy_eg1',
|
|
61
|
+
nonce: nonce || ('sig_' + crypto.randomBytes(16).toString('hex')),
|
|
62
|
+
approver,
|
|
63
|
+
initiator: 'ent_agent_eg1',
|
|
64
|
+
issued_at: new Date(issuedAtMs).toISOString(),
|
|
65
|
+
expires_at: new Date(issuedAtMs + 5 * 60_000).toISOString(),
|
|
66
|
+
...(prevContextHash !== undefined ? { prev_context_hash: prevContextHash } : {}),
|
|
67
|
+
};
|
|
68
|
+
const challenge = crypto.createHash('sha256').update(canon(context), 'utf8').digest().toString('base64url');
|
|
69
|
+
const clientData = Buffer.from(JSON.stringify({ type: 'webauthn.get', challenge, origin: `https://www.${RP_ID}` }), 'utf8');
|
|
70
|
+
const authData = Buffer.concat([
|
|
71
|
+
crypto.createHash('sha256').update(RP_ID, 'utf8').digest(),
|
|
72
|
+
Buffer.from([0x05]), // UP | UV
|
|
73
|
+
Buffer.from([0, 0, 0, 1]),
|
|
74
|
+
]);
|
|
75
|
+
const signed = Buffer.concat([authData, crypto.createHash('sha256').update(clientData).digest()]);
|
|
76
|
+
const signature = crypto.sign('sha256', signed, signer.privateKey).toString('base64url');
|
|
77
|
+
return {
|
|
78
|
+
signoff: {
|
|
79
|
+
'@type': 'ep.signoff',
|
|
80
|
+
context,
|
|
81
|
+
webauthn: {
|
|
82
|
+
authenticator_data: authData.toString('base64url'),
|
|
83
|
+
client_data_json: clientData.toString('base64url'),
|
|
84
|
+
signature,
|
|
85
|
+
},
|
|
86
|
+
approver_public_key: signer.publicKey.export({ type: 'spki', format: 'der' }).toString('base64url'),
|
|
87
|
+
},
|
|
88
|
+
approver_public_key: signer.publicKey.export({ type: 'spki', format: 'der' }).toString('base64url'),
|
|
89
|
+
context,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Mint a GENUINE EP-QUORUM-v1 evidence document: N distinct humans, each on a
|
|
94
|
+
* distinct device key, each with a real WebAuthn assertion bound to the SAME
|
|
95
|
+
* action_hash, within a window. verifyQuorum returns valid for it. This is what
|
|
96
|
+
* earns a receipt its `quorum` tier — never a bare {signers,threshold} block.
|
|
97
|
+
* @param {{ actionHash?: string, threshold?: number, approvers?: Array<{ role: string, approver: string }>, issuedAtMs?: number }} [opts]
|
|
98
|
+
*/
|
|
99
|
+
export function mintQuorumEvidence({ actionHash, threshold = 2, approvers, issuedAtMs = Date.now(), } = {}) {
|
|
100
|
+
const people = approvers || Array.from({ length: threshold }, (_, i) => ({ role: `approver_${i + 1}`, approver: `ep:approver:eg1_${i + 1}` }));
|
|
101
|
+
const members = people.map((p, i) => {
|
|
102
|
+
const s = mintDeviceSignoff({ actionHash, approver: p.approver, issuedAtMs: issuedAtMs + i * 1000 });
|
|
103
|
+
return { role: p.role, approver_public_key: s.approver_public_key, signoff: { '@type': s.signoff['@type'], context: s.signoff.context, webauthn: s.signoff.webauthn } };
|
|
104
|
+
});
|
|
105
|
+
return {
|
|
106
|
+
'@type': 'ep.quorum',
|
|
107
|
+
action_hash: actionHash,
|
|
108
|
+
policy: {
|
|
109
|
+
mode: 'threshold',
|
|
110
|
+
required: threshold,
|
|
111
|
+
approvers: people,
|
|
112
|
+
distinct_humans: true,
|
|
113
|
+
window_sec: 900,
|
|
114
|
+
},
|
|
115
|
+
members,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
// The default high-risk action EG-1 exercises: a Class-A money movement, which
|
|
119
|
+
// the default gate manifest guards (selector { protocol:'mcp', tool:'release_payment' }).
|
|
120
|
+
export const EG1_DEFAULT_SELECTOR = Object.freeze({ protocol: 'mcp', tool: 'release_payment' });
|
|
121
|
+
export const EG1_DEFAULT_ACTION = Object.freeze({
|
|
122
|
+
action_type: 'payment.release',
|
|
123
|
+
amount_usd: 40000,
|
|
124
|
+
currency: 'USD',
|
|
125
|
+
payment_instruction_id: 'pi_eg1_40000',
|
|
126
|
+
beneficiary_account_hash: 'sha256:eg1-beneficiary',
|
|
127
|
+
});
|
|
128
|
+
export const EG1_CHECKS = Object.freeze([
|
|
129
|
+
{ id: 'missing_receipt_refused', title: 'missing receipt → 428' },
|
|
130
|
+
{ id: 'software_on_classA_refused', title: 'software receipt on Class-A action → refused' },
|
|
131
|
+
{ id: 'execution_drift_refused', title: 'observed execution drift → refused' },
|
|
132
|
+
{ id: 'valid_classA_runs', title: 'valid Class-A/quorum receipt → runs' },
|
|
133
|
+
{ id: 'replay_refused', title: 'same receipt replay → refused' },
|
|
134
|
+
{ id: 'tampered_refused', title: 'tampered receipt → refused' },
|
|
135
|
+
{ id: 'execution_proof_binds', title: 'execution proof binds to authorization decision' },
|
|
136
|
+
{ id: 'reliance_packet_rely', title: 'reliance packet returns verdict "rely"' },
|
|
137
|
+
]);
|
|
138
|
+
/**
|
|
139
|
+
* Create an EG-1 harness: a throwaway issuer key + a receipt minter for the
|
|
140
|
+
* scenarios. Configure the subject's gate to trust `publicKey` for the run.
|
|
141
|
+
*/
|
|
142
|
+
export function createEg1Harness({ now = Date.now, action = EG1_DEFAULT_ACTION, idPrefix = 'eg1', } = {}) {
|
|
143
|
+
const { publicKey, privateKey } = crypto.generateKeyPairSync('ed25519');
|
|
144
|
+
const pub = publicKey.export({ type: 'spki', format: 'der' }).toString('base64url');
|
|
145
|
+
const approverA = crypto.generateKeyPairSync('ec', { namedCurve: 'P-256' });
|
|
146
|
+
const approverA2 = crypto.generateKeyPairSync('ec', { namedCurve: 'P-256' });
|
|
147
|
+
const approverB = crypto.generateKeyPairSync('ed25519');
|
|
148
|
+
const approverKeys = {
|
|
149
|
+
'ep:key:eg1:class-a': {
|
|
150
|
+
approver_id: 'ep:approver:eg1:cfo',
|
|
151
|
+
public_key: approverA.publicKey.export({ type: 'spki', format: 'der' }).toString('base64url'),
|
|
152
|
+
key_class: 'A',
|
|
153
|
+
},
|
|
154
|
+
'ep:key:eg1:class-a-2': {
|
|
155
|
+
approver_id: 'ep:approver:eg1:security-officer',
|
|
156
|
+
public_key: approverA2.publicKey.export({ type: 'spki', format: 'der' }).toString('base64url'),
|
|
157
|
+
key_class: 'A',
|
|
158
|
+
},
|
|
159
|
+
'ep:key:eg1:controller': {
|
|
160
|
+
approver_id: 'ep:approver:eg1:controller',
|
|
161
|
+
public_key: approverB.publicKey.export({ type: 'spki', format: 'der' }).toString('base64url'),
|
|
162
|
+
key_class: 'B',
|
|
163
|
+
},
|
|
164
|
+
};
|
|
165
|
+
const quorumPolicy = {
|
|
166
|
+
mode: 'threshold', required: 2, distinct_humans: true, window_sec: 900,
|
|
167
|
+
approvers: [
|
|
168
|
+
{ role: 'cfo', approver: approverKeys['ep:key:eg1:class-a'].approver_id },
|
|
169
|
+
{ role: 'security_officer', approver: approverKeys['ep:key:eg1:class-a-2'].approver_id },
|
|
170
|
+
],
|
|
171
|
+
};
|
|
172
|
+
let counter = 0;
|
|
173
|
+
const nowMs = () => (typeof now === 'function' ? now() : now);
|
|
174
|
+
// The action_hash the self-contained human device assertions are bound to.
|
|
175
|
+
// Derived from the action so the signoff/quorum evidence is about THIS action.
|
|
176
|
+
const actionHash = crypto.createHash('sha256').update(canon(action), 'utf8').digest('hex');
|
|
177
|
+
function assuranceContext(payload) {
|
|
178
|
+
return {
|
|
179
|
+
'@version': 'EP-ASSURANCE-CONTEXT-v1',
|
|
180
|
+
receipt_id: payload.receipt_id,
|
|
181
|
+
claim_hash: `sha256:${sha256Hex(canon(payload.claim))}`,
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
function classASignoff(digest, { keyId = 'ep:key:eg1:class-a', keyPair = approverA, approver = 'ep:approver:eg1:cfo', } = {}) {
|
|
185
|
+
const challenge = Buffer.from(digest).toString('base64url');
|
|
186
|
+
const clientDataJSON = Buffer.from(JSON.stringify({ type: 'webauthn.get', challenge, origin: RP_ORIGIN }), 'utf8');
|
|
187
|
+
const rpIdHash = crypto.createHash('sha256').update(RP_ID).digest();
|
|
188
|
+
const authData = Buffer.concat([rpIdHash, Buffer.from([0x05]), Buffer.from([0, 0, 0, 0])]); // UP + UV
|
|
189
|
+
const signedData = Buffer.concat([authData, sha256Bytes(clientDataJSON)]);
|
|
190
|
+
return {
|
|
191
|
+
approver,
|
|
192
|
+
approver_key_id: keyId,
|
|
193
|
+
key_class: 'A',
|
|
194
|
+
webauthn: {
|
|
195
|
+
authenticator_data: authData.toString('base64url'),
|
|
196
|
+
client_data_json: clientDataJSON.toString('base64url'),
|
|
197
|
+
signature: crypto.sign('sha256', signedData, keyPair.privateKey).toString('base64url'),
|
|
198
|
+
},
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
function softwareSignoff(digest) {
|
|
202
|
+
return {
|
|
203
|
+
approver: 'ep:approver:eg1:controller',
|
|
204
|
+
approver_key_id: 'ep:key:eg1:controller',
|
|
205
|
+
key_class: 'B',
|
|
206
|
+
signature: crypto.sign(null, digest, approverB.privateKey).toString('base64url'),
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
function assuranceProof(payload, quorum) {
|
|
210
|
+
const context = assuranceContext(payload);
|
|
211
|
+
const contextHash = `sha256:${sha256Hex(canon(context))}`;
|
|
212
|
+
const digest = Buffer.from(contextHash.replace(/^sha256:/, ''), 'hex');
|
|
213
|
+
const threshold = Number(quorum?.threshold ?? quorum?.m ?? 1);
|
|
214
|
+
const signoffs = [classASignoff(digest)];
|
|
215
|
+
if (threshold >= 2) {
|
|
216
|
+
signoffs.push(classASignoff(digest, {
|
|
217
|
+
keyId: 'ep:key:eg1:class-a-2',
|
|
218
|
+
keyPair: approverA2,
|
|
219
|
+
approver: 'ep:approver:eg1:security-officer',
|
|
220
|
+
}));
|
|
221
|
+
}
|
|
222
|
+
return {
|
|
223
|
+
'@version': 'EP-ASSURANCE-PROOF-v1',
|
|
224
|
+
context_hash: contextHash,
|
|
225
|
+
threshold: threshold >= 2 ? threshold : 1,
|
|
226
|
+
signoffs,
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Mint a scenario receipt.
|
|
231
|
+
* @param {object} o
|
|
232
|
+
* @param {'allow'|'allow_with_signoff'} [o.outcome] 'allow'=software; 'allow_with_signoff'
|
|
233
|
+
* embeds a REAL WebAuthn device signoff so the receipt cryptographically earns class_a.
|
|
234
|
+
* @param {object|boolean} [o.quorum] request quorum-tier evidence. Truthy -> a REAL
|
|
235
|
+
* EP-QUORUM-v1 doc (distinct humans + distinct keys + per-signer assertions). If an
|
|
236
|
+
* object with `threshold`/`signers`, its size sets the quorum size.
|
|
237
|
+
* @param {boolean} [o.fakeQuorum] embed an UNVERIFIABLE self-asserted quorum block
|
|
238
|
+
* ({signers,threshold}) with no per-signer signatures — used to prove the Gate
|
|
239
|
+
* REFUSES it (must NOT be credited quorum). For adversarial tests only.
|
|
240
|
+
* @param {object} [o.tamper] fields assigned to the claim AFTER signing (breaks the signature)
|
|
241
|
+
* @param {object} [o.extra] extra fields merged into the claim before signing
|
|
242
|
+
*/
|
|
243
|
+
function mint({ outcome = 'allow_with_signoff', quorum = null, fakeQuorum = false, tamper = null, extra = {}, } = {}) {
|
|
244
|
+
const approver = outcome === 'allow'
|
|
245
|
+
? 'ep:approver:eg1:controller'
|
|
246
|
+
: 'ep:approver:eg1:cfo';
|
|
247
|
+
const claim = { ...action, outcome, approver, ...extra };
|
|
248
|
+
const payload = {
|
|
249
|
+
receipt_id: `${idPrefix}_${++counter}`,
|
|
250
|
+
subject: 'agent:eg1-conformance',
|
|
251
|
+
issuer: 'ep:org:eg1',
|
|
252
|
+
created_at: new Date(nowMs()).toISOString(),
|
|
253
|
+
claim,
|
|
254
|
+
};
|
|
255
|
+
if (fakeQuorum) {
|
|
256
|
+
// Self-asserted ONLY — NO members / NO signatures / NO pinned proof. The
|
|
257
|
+
// Gate must refuse to credit this as quorum (assurance_too_low). For
|
|
258
|
+
// adversarial tests that prove payload claims are never trusted.
|
|
259
|
+
payload.quorum = { signers: ['ep:a', 'ep:b'], threshold: 2 };
|
|
260
|
+
}
|
|
261
|
+
else if (outcome === 'allow_with_signoff' || quorum) {
|
|
262
|
+
// Genuine, per-signer-verifiable evidence. The PRIMARY proof is the pinned
|
|
263
|
+
// EP-ASSURANCE-PROOF-v1 (verified against the harness's pinned approverKeys),
|
|
264
|
+
// which is what the EG-1 gate/custody path checks. We ALSO embed self-contained
|
|
265
|
+
// evidence (EP-QUORUM-v1 / WebAuthn device signoff) so a relying party that
|
|
266
|
+
// does NOT pin keys can still cryptographically credit the tier (DoD audit fix).
|
|
267
|
+
payload.assurance_proof = assuranceProof(payload, quorum);
|
|
268
|
+
if (quorum) {
|
|
269
|
+
const threshold = Number.isInteger(quorum.threshold) ? quorum.threshold
|
|
270
|
+
: (Array.isArray(quorum.signers) ? quorum.signers.length : 2);
|
|
271
|
+
payload.quorum = mintQuorumEvidence({
|
|
272
|
+
actionHash,
|
|
273
|
+
threshold,
|
|
274
|
+
approvers: quorumPolicy.approvers.slice(0, threshold),
|
|
275
|
+
issuedAtMs: nowMs(),
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
else {
|
|
279
|
+
const s = mintDeviceSignoff({ actionHash, approver, issuedAtMs: nowMs() });
|
|
280
|
+
payload.signoff = s.signoff;
|
|
281
|
+
payload.approver_public_key = s.approver_public_key;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
const value = crypto.sign(null, Buffer.from(canon(payload), 'utf8'), privateKey).toString('base64url');
|
|
285
|
+
const receipt = { '@version': 'EP-RECEIPT-v1', payload, signature: { algorithm: 'Ed25519', value } };
|
|
286
|
+
if (tamper)
|
|
287
|
+
Object.assign(receipt.payload.claim, tamper); // tamper AFTER signing -> signature no longer binds
|
|
288
|
+
return receipt;
|
|
289
|
+
}
|
|
290
|
+
return { publicKey: pub, approverKeys, quorumPolicy, mint, action, actionHash, now: nowMs, rpId: RP_ID, allowedOrigins: [RP_ORIGIN] };
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Adapt an @emilia-protocol/gate instance into an EG-1 `invoke`. The gate must
|
|
294
|
+
* have been built trusting the harness public key. Uses gate.run() so the
|
|
295
|
+
* execution proof + reliance packet are produced on the allowed path.
|
|
296
|
+
*/
|
|
297
|
+
export function makeGateInvoke(gate, { selector = EG1_DEFAULT_SELECTOR, action = EG1_DEFAULT_ACTION } = {}) {
|
|
298
|
+
if (!gate || typeof gate.run !== 'function') {
|
|
299
|
+
throw new Error('makeGateInvoke requires an EMILIA Gate instance (with .run)');
|
|
300
|
+
}
|
|
301
|
+
return async ({ receipt, observedAction }) => {
|
|
302
|
+
const out = await gate.run({ selector, receipt, observedAction: observedAction ?? action }, async () => ({ eg1: 'side-effect-ran' }));
|
|
303
|
+
if (!out.ok) {
|
|
304
|
+
return { allowed: false, status: out.status, reason: out.authorization?.reason ?? 'refused' };
|
|
305
|
+
}
|
|
306
|
+
return {
|
|
307
|
+
allowed: true,
|
|
308
|
+
status: 200,
|
|
309
|
+
reason: out.authorization?.reason ?? 'allow',
|
|
310
|
+
decisionHash: out.authorization?.evidence?.hash ?? null,
|
|
311
|
+
execution: out.execution ?? null,
|
|
312
|
+
packet: out.packet ?? null,
|
|
313
|
+
};
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
const pick = (r) => ({ allowed: !!r.allowed, status: r.status ?? null, reason: r.reason ?? null });
|
|
317
|
+
/**
|
|
318
|
+
* Drive a subject through the eight EG-1 checks and return a JSON report.
|
|
319
|
+
* @param {object} [o]
|
|
320
|
+
* @param {(scenario:object)=>Promise<object>} [o.invoke] the integration under test
|
|
321
|
+
* @param {object} [o.harness] from createEg1Harness()
|
|
322
|
+
* @param {object} [o.action] the high-risk action (defaults to the harness action)
|
|
323
|
+
*/
|
|
324
|
+
export async function runEg1({ invoke, harness, action, } = {}) {
|
|
325
|
+
if (typeof invoke !== 'function')
|
|
326
|
+
throw new Error('runEg1 requires an invoke(scenario) function');
|
|
327
|
+
if (!harness || typeof harness.mint !== 'function')
|
|
328
|
+
throw new Error('runEg1 requires a harness from createEg1Harness()');
|
|
329
|
+
const act = action || harness.action || EG1_DEFAULT_ACTION;
|
|
330
|
+
const observed = act;
|
|
331
|
+
const drift = { ...act, amount_usd: Number(act.amount_usd ?? 0) + 1 };
|
|
332
|
+
const results = {};
|
|
333
|
+
const set = (id, pass, observed_) => { results[id] = { pass: !!pass, observed: observed_ }; };
|
|
334
|
+
// 1. missing receipt → 428
|
|
335
|
+
let r = await invoke({ receipt: null, observedAction: observed });
|
|
336
|
+
set('missing_receipt_refused', !r.allowed && r.status === 428, pick(r));
|
|
337
|
+
// 2. software receipt on a Class-A action → refused
|
|
338
|
+
r = await invoke({ receipt: harness.mint({ outcome: 'allow' }), observedAction: observed });
|
|
339
|
+
set('software_on_classA_refused', !r.allowed && /assurance/i.test(r.reason || ''), pick(r));
|
|
340
|
+
// 3. observed execution drift → refused
|
|
341
|
+
r = await invoke({ receipt: harness.mint({ outcome: 'allow_with_signoff' }), observedAction: drift });
|
|
342
|
+
set('execution_drift_refused', !r.allowed && /binding/i.test(r.reason || ''), pick(r));
|
|
343
|
+
// 4. valid Class-A receipt → runs (capture for 5/7/8)
|
|
344
|
+
const valid = harness.mint({ outcome: 'allow_with_signoff' });
|
|
345
|
+
r = await invoke({ receipt: valid, observedAction: observed });
|
|
346
|
+
const validAllowed = r.allowed === true;
|
|
347
|
+
set('valid_classA_runs', validAllowed, pick(r));
|
|
348
|
+
// 7. execution proof binds to the authorization decision
|
|
349
|
+
const boundOk = validAllowed
|
|
350
|
+
&& !!r.execution && !!r.execution.authorizes_decision
|
|
351
|
+
&& !!r.decisionHash && r.execution.authorizes_decision === r.decisionHash;
|
|
352
|
+
set('execution_proof_binds', boundOk, {
|
|
353
|
+
authorizes_decision: r.execution?.authorizes_decision ?? null,
|
|
354
|
+
decision_hash: r.decisionHash ?? null,
|
|
355
|
+
});
|
|
356
|
+
// 8. reliance packet verdict "rely"
|
|
357
|
+
set('reliance_packet_rely', validAllowed && String(r.packet?.verdict || '').toLowerCase() === 'rely', {
|
|
358
|
+
verdict: r.packet?.verdict ?? null,
|
|
359
|
+
});
|
|
360
|
+
// 5. same receipt replay → refused
|
|
361
|
+
r = await invoke({ receipt: valid, observedAction: observed });
|
|
362
|
+
set('replay_refused', !r.allowed && /replay/i.test(r.reason || ''), pick(r));
|
|
363
|
+
// 6. tampered receipt → refused
|
|
364
|
+
r = await invoke({ receipt: harness.mint({ outcome: 'allow_with_signoff', tamper: { amount_usd: 9_999_999 } }), observedAction: observed });
|
|
365
|
+
set('tampered_refused', !r.allowed && r.status === 428, pick(r));
|
|
366
|
+
const checks = EG1_CHECKS.map((c) => ({ id: c.id, title: c.title, ...results[c.id] }));
|
|
367
|
+
const passedCount = checks.filter((c) => c.pass).length;
|
|
368
|
+
const passed = passedCount === checks.length;
|
|
369
|
+
return {
|
|
370
|
+
standard: EG1_VERSION,
|
|
371
|
+
passed,
|
|
372
|
+
badge: passed ? 'EG-1 Enforced' : 'EG-1 not earned',
|
|
373
|
+
summary: { passed: passedCount, total: checks.length },
|
|
374
|
+
checks,
|
|
375
|
+
generated_at: new Date(harness.now ? harness.now() : Date.now()).toISOString(),
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
export default { EG1_VERSION, EG1_CHECKS, EG1_DEFAULT_ACTION, EG1_DEFAULT_SELECTOR, createEg1Harness, makeGateInvoke, runEg1, mintDeviceSignoff, mintQuorumEvidence };
|
|
379
|
+
//# sourceMappingURL=eg1-conformance.js.map
|