@emilia-protocol/gate 0.10.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 +91 -0
- package/README.md +272 -0
- package/action-control-manifest.js +3 -268
- package/action-escrow-custodian.js +4 -0
- package/action-escrow-evidence.js +4 -0
- package/action-escrow-package.js +4 -0
- package/action-escrow-postgres.js +4 -0
- package/action-escrow-state.js +4 -0
- package/action-escrow-verifiers.js +4 -0
- package/action-escrow.js +4 -0
- 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 +47 -4
- 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 -85
- 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,429 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
/**
|
|
3
|
+
* Durable PostgreSQL store for the Gate Trust Program kernel.
|
|
4
|
+
*
|
|
5
|
+
* The database is RPC-only. Every operation runs on one pinned pg client so a
|
|
6
|
+
* transaction can never be split across pooled connections. Logical conflicts
|
|
7
|
+
* are returned as stable store reasons; database ambiguity and outages throw.
|
|
8
|
+
*/
|
|
9
|
+
import crypto from 'node:crypto';
|
|
10
|
+
import { canonicalize } from './execution-binding.js';
|
|
11
|
+
import type {
|
|
12
|
+
TrustProgramResult,
|
|
13
|
+
TrustProgramState,
|
|
14
|
+
TrustProgramStore,
|
|
15
|
+
} from './trust-program.js';
|
|
16
|
+
|
|
17
|
+
export const TRUST_PROGRAM_PG_STORE_VERSION = 'EP-GATE-TRUST-PROGRAM-PG-STORE-v1';
|
|
18
|
+
export const TRUST_PROGRAM_MAX_STATE_BYTES = 4 * 1024 * 1024;
|
|
19
|
+
|
|
20
|
+
const INSTANCE_ID = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/;
|
|
21
|
+
const DIGEST = /^sha256:[0-9a-f]{64}$/;
|
|
22
|
+
const STRICT_INSTANT = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,9})?Z$/;
|
|
23
|
+
const ENVELOPE_KEYS = new Set([
|
|
24
|
+
'ok', 'reason', 'tenant_id', 'instance_id', 'revision', 'state_json', 'state_digest',
|
|
25
|
+
]);
|
|
26
|
+
|
|
27
|
+
type RecordLike = Record<string, any>;
|
|
28
|
+
type QueryResult = { rowCount: number | null; rows?: any[] };
|
|
29
|
+
type PgClient = {
|
|
30
|
+
query: (text: string, params?: any[]) => Promise<QueryResult>;
|
|
31
|
+
release: () => void;
|
|
32
|
+
};
|
|
33
|
+
type PgPool = { connect: () => Promise<PgClient> };
|
|
34
|
+
|
|
35
|
+
export const TRUST_PROGRAM_POSTGRES_SQL = Object.freeze({
|
|
36
|
+
create: `SELECT ok, reason, tenant_id, instance_id, revision, state_json, state_digest
|
|
37
|
+
FROM trust_program_private.trust_program_create(
|
|
38
|
+
$1::text, $2::text, $3::text, $4::text, $5::text
|
|
39
|
+
)`,
|
|
40
|
+
get: `SELECT ok, reason, tenant_id, instance_id, revision, state_json, state_digest
|
|
41
|
+
FROM trust_program_private.trust_program_get($1::text, $2::text)`,
|
|
42
|
+
compareAndSwap: `SELECT ok, reason, tenant_id, instance_id, revision, state_json, state_digest
|
|
43
|
+
FROM trust_program_private.trust_program_compare_and_swap(
|
|
44
|
+
$1::text, $2::text, $3::bigint, $4::bigint, $5::text, $6::text, $7::text
|
|
45
|
+
)`,
|
|
46
|
+
invalidate: `SELECT ok, reason, tenant_id, instance_id, revision, state_json, state_digest
|
|
47
|
+
FROM trust_program_private.trust_program_invalidate(
|
|
48
|
+
$1::text, $2::text, $3::bigint, $4::text, $5::text, $6::text, $7::text
|
|
49
|
+
)`,
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
function isRecord(value: unknown): value is RecordLike {
|
|
53
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value)) return false;
|
|
54
|
+
const prototype = Object.getPrototypeOf(value);
|
|
55
|
+
return prototype === Object.prototype || prototype === null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function exactKeys(value: RecordLike, expected: ReadonlySet<string>) {
|
|
59
|
+
const keys = Reflect.ownKeys(value);
|
|
60
|
+
return keys.length === expected.size
|
|
61
|
+
&& keys.every((key) => typeof key === 'string' && expected.has(key));
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function fail(reason: string) {
|
|
65
|
+
return { ok: false as const, reason };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function assertTenantId(value: unknown): asserts value is string {
|
|
69
|
+
if (typeof value !== 'string'
|
|
70
|
+
|| Buffer.byteLength(value, 'utf8') < 1
|
|
71
|
+
|| Buffer.byteLength(value, 'utf8') > 512
|
|
72
|
+
|| /[\u0000-\u001f\u007f]/.test(value)) {
|
|
73
|
+
throw new TypeError('trust-program tenantId is invalid');
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function assertInstanceId(value: unknown): asserts value is string {
|
|
78
|
+
if (typeof value !== 'string' || !INSTANCE_ID.test(value)) {
|
|
79
|
+
throw new TypeError('trust-program instanceId is invalid');
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function assertRevision(value: unknown, label: string): asserts value is number {
|
|
84
|
+
if (!Number.isSafeInteger(value) || (value as number) < 0) {
|
|
85
|
+
throw new TypeError(`trust-program ${label} revision is invalid`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function stateDigest(stateJson: string) {
|
|
90
|
+
return `sha256:${crypto.createHash('sha256').update(stateJson, 'utf8').digest('hex')}`;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function stateEventAt(state: RecordLike) {
|
|
94
|
+
const value = state.updated_at;
|
|
95
|
+
if (typeof value !== 'string' || !STRICT_INSTANT.test(value) || !Number.isFinite(Date.parse(value))) {
|
|
96
|
+
throw new TypeError('trust-program state updated_at is invalid');
|
|
97
|
+
}
|
|
98
|
+
return value;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function encodeState(
|
|
102
|
+
state: unknown,
|
|
103
|
+
tenantId: string,
|
|
104
|
+
instanceId: string,
|
|
105
|
+
revision: number,
|
|
106
|
+
) {
|
|
107
|
+
if (!isRecord(state)
|
|
108
|
+
|| state.tenant_id !== tenantId
|
|
109
|
+
|| state.instance_id !== instanceId
|
|
110
|
+
|| state.revision !== revision) {
|
|
111
|
+
throw new TypeError('trust-program state binding does not match the store operation');
|
|
112
|
+
}
|
|
113
|
+
let stateJson: string;
|
|
114
|
+
try {
|
|
115
|
+
stateJson = canonicalize(state);
|
|
116
|
+
} catch {
|
|
117
|
+
throw new TypeError('trust-program state must be canonical JSON');
|
|
118
|
+
}
|
|
119
|
+
if (Buffer.byteLength(stateJson, 'utf8') > TRUST_PROGRAM_MAX_STATE_BYTES) {
|
|
120
|
+
throw new TypeError('trust-program state exceeds the durable store limit');
|
|
121
|
+
}
|
|
122
|
+
return {
|
|
123
|
+
stateJson,
|
|
124
|
+
stateDigest: stateDigest(stateJson),
|
|
125
|
+
eventAt: stateEventAt(state),
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function safeRevision(value: unknown) {
|
|
130
|
+
const revision = typeof value === 'string' && /^\d+$/.test(value) ? Number(value) : value;
|
|
131
|
+
if (!Number.isSafeInteger(revision) || (revision as number) < 0) {
|
|
132
|
+
throw new Error('trust-program Postgres returned an invalid revision');
|
|
133
|
+
}
|
|
134
|
+
return revision as number;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function decodeState(
|
|
138
|
+
row: RecordLike,
|
|
139
|
+
expectedTenantId: string,
|
|
140
|
+
expectedInstanceId: string,
|
|
141
|
+
expectedRevision?: number,
|
|
142
|
+
) {
|
|
143
|
+
if (row.tenant_id !== expectedTenantId
|
|
144
|
+
|| row.instance_id !== expectedInstanceId
|
|
145
|
+
|| typeof row.state_json !== 'string'
|
|
146
|
+
|| typeof row.state_digest !== 'string'
|
|
147
|
+
|| !DIGEST.test(row.state_digest)
|
|
148
|
+
|| Buffer.byteLength(row.state_json, 'utf8') > TRUST_PROGRAM_MAX_STATE_BYTES
|
|
149
|
+
|| row.state_digest !== stateDigest(row.state_json)) {
|
|
150
|
+
throw new Error('trust-program Postgres returned an invalid state envelope');
|
|
151
|
+
}
|
|
152
|
+
const revision = safeRevision(row.revision);
|
|
153
|
+
if (expectedRevision !== undefined && revision !== expectedRevision) {
|
|
154
|
+
throw new Error('trust-program Postgres returned an unexpected revision');
|
|
155
|
+
}
|
|
156
|
+
let state: unknown;
|
|
157
|
+
try {
|
|
158
|
+
state = JSON.parse(row.state_json);
|
|
159
|
+
if (!isRecord(state)
|
|
160
|
+
|| canonicalize(state) !== row.state_json
|
|
161
|
+
|| state.tenant_id !== expectedTenantId
|
|
162
|
+
|| state.instance_id !== expectedInstanceId
|
|
163
|
+
|| state.revision !== revision) {
|
|
164
|
+
throw new Error('state mismatch');
|
|
165
|
+
}
|
|
166
|
+
stateEventAt(state);
|
|
167
|
+
} catch {
|
|
168
|
+
throw new Error('trust-program Postgres returned non-canonical state');
|
|
169
|
+
}
|
|
170
|
+
return state as TrustProgramState;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function definitiveRow(
|
|
174
|
+
result: QueryResult,
|
|
175
|
+
operation: string,
|
|
176
|
+
tenantId: string,
|
|
177
|
+
instanceId: string,
|
|
178
|
+
allowedReasons: ReadonlySet<string>,
|
|
179
|
+
expectedRevision?: number,
|
|
180
|
+
): TrustProgramResult {
|
|
181
|
+
if (!result || result.rowCount !== 1 || !Array.isArray(result.rows) || result.rows.length !== 1) {
|
|
182
|
+
throw new Error(`trust-program ${operation} outcome is ambiguous`);
|
|
183
|
+
}
|
|
184
|
+
const row = result.rows[0];
|
|
185
|
+
if (!isRecord(row) || !exactKeys(row, ENVELOPE_KEYS) || typeof row.ok !== 'boolean') {
|
|
186
|
+
throw new Error(`trust-program ${operation} outcome is malformed`);
|
|
187
|
+
}
|
|
188
|
+
if (row.tenant_id !== tenantId || row.instance_id !== instanceId) {
|
|
189
|
+
throw new Error(`trust-program ${operation} Postgres returned a mismatched identity`);
|
|
190
|
+
}
|
|
191
|
+
if (!row.ok) {
|
|
192
|
+
if (typeof row.reason !== 'string' || !allowedReasons.has(row.reason)
|
|
193
|
+
|| (row.revision !== null && row.revision !== undefined)
|
|
194
|
+
|| (row.state_json !== null && row.state_json !== undefined)
|
|
195
|
+
|| (row.state_digest !== null && row.state_digest !== undefined)) {
|
|
196
|
+
throw new Error(`trust-program ${operation} refusal is unrecognized`);
|
|
197
|
+
}
|
|
198
|
+
return fail(row.reason);
|
|
199
|
+
}
|
|
200
|
+
if (row.reason !== null && row.reason !== undefined && row.reason !== '') {
|
|
201
|
+
throw new Error(`trust-program ${operation} success carried a refusal reason`);
|
|
202
|
+
}
|
|
203
|
+
return {
|
|
204
|
+
ok: true as const,
|
|
205
|
+
state: decodeState(row, tenantId, instanceId, expectedRevision),
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function lookupInput(value: unknown) {
|
|
210
|
+
if (!isRecord(value)
|
|
211
|
+
|| Reflect.ownKeys(value).length !== 2
|
|
212
|
+
|| !Object.hasOwn(value, 'tenantId')
|
|
213
|
+
|| !Object.hasOwn(value, 'instanceId')) {
|
|
214
|
+
throw new TypeError('trust-program lookup input is invalid');
|
|
215
|
+
}
|
|
216
|
+
assertTenantId(value.tenantId);
|
|
217
|
+
assertInstanceId(value.instanceId);
|
|
218
|
+
return { tenantId: value.tenantId, instanceId: value.instanceId };
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function invalidatedState(current: RecordLike, reason: string, at: number) {
|
|
222
|
+
if (!isRecord(current.stages)
|
|
223
|
+
|| Object.values(current.stages).some((stage) => !isRecord(stage))
|
|
224
|
+
|| !isRecord(current.execution)) {
|
|
225
|
+
throw new Error('trust-program stored state cannot be invalidated safely');
|
|
226
|
+
}
|
|
227
|
+
const next = structuredClone(current);
|
|
228
|
+
next.status = 'invalidated';
|
|
229
|
+
next.invalidation_reason = reason;
|
|
230
|
+
next.revision += 1;
|
|
231
|
+
next.updated_at = new Date(at).toISOString();
|
|
232
|
+
for (const stage of Object.values(next.stages) as RecordLike[]) stage.status = 'invalidated';
|
|
233
|
+
if (['locked', 'ready'].includes(next.execution.status)) {
|
|
234
|
+
next.execution.status = 'invalidated';
|
|
235
|
+
}
|
|
236
|
+
return next;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Create the exact durable store consumed by createTrustProgramKernel().
|
|
241
|
+
* `pool` must provide node-postgres-style connect(), returning a pinned client
|
|
242
|
+
* with query() and release().
|
|
243
|
+
*/
|
|
244
|
+
export function createTrustProgramPostgresStore(
|
|
245
|
+
{ pool }: { pool?: PgPool } = {},
|
|
246
|
+
): TrustProgramStore {
|
|
247
|
+
if (!pool || typeof pool.connect !== 'function') {
|
|
248
|
+
throw new TypeError('createTrustProgramPostgresStore requires a transaction-capable pg pool');
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
async function transaction<T>(readOnly: boolean, work: (client: PgClient) => Promise<T>) {
|
|
252
|
+
const client = await pool!.connect();
|
|
253
|
+
if (!client || typeof client.query !== 'function' || typeof client.release !== 'function') {
|
|
254
|
+
throw new TypeError('trust-program pg pool returned an invalid client');
|
|
255
|
+
}
|
|
256
|
+
let began = false;
|
|
257
|
+
try {
|
|
258
|
+
await client.query(readOnly
|
|
259
|
+
? 'BEGIN ISOLATION LEVEL REPEATABLE READ READ ONLY'
|
|
260
|
+
: 'BEGIN ISOLATION LEVEL READ COMMITTED READ WRITE');
|
|
261
|
+
began = true;
|
|
262
|
+
const value = await work(client);
|
|
263
|
+
await client.query('COMMIT');
|
|
264
|
+
began = false;
|
|
265
|
+
return value;
|
|
266
|
+
} catch (error) {
|
|
267
|
+
if (began) {
|
|
268
|
+
try {
|
|
269
|
+
await client.query('ROLLBACK');
|
|
270
|
+
} catch (rollbackError) {
|
|
271
|
+
throw new AggregateError(
|
|
272
|
+
[error, rollbackError],
|
|
273
|
+
'trust-program transaction and rollback both failed',
|
|
274
|
+
);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
throw error;
|
|
278
|
+
} finally {
|
|
279
|
+
client.release();
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
async function getWithClient(client: PgClient, tenantId: string, instanceId: string) {
|
|
284
|
+
return definitiveRow(
|
|
285
|
+
await client.query(TRUST_PROGRAM_POSTGRES_SQL.get, [tenantId, instanceId]),
|
|
286
|
+
'get',
|
|
287
|
+
tenantId,
|
|
288
|
+
instanceId,
|
|
289
|
+
new Set(['instance_not_found']),
|
|
290
|
+
);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
return Object.freeze({
|
|
294
|
+
version: TRUST_PROGRAM_PG_STORE_VERSION,
|
|
295
|
+
durable: true,
|
|
296
|
+
async create(input: { tenantId: string; state: TrustProgramState }) {
|
|
297
|
+
if (!isRecord(input)
|
|
298
|
+
|| Reflect.ownKeys(input).length !== 2
|
|
299
|
+
|| !Object.hasOwn(input, 'tenantId')
|
|
300
|
+
|| !Object.hasOwn(input, 'state')) {
|
|
301
|
+
throw new TypeError('trust-program create input is invalid');
|
|
302
|
+
}
|
|
303
|
+
const { tenantId, state } = input;
|
|
304
|
+
const instanceId = state?.instance_id;
|
|
305
|
+
assertTenantId(tenantId);
|
|
306
|
+
assertInstanceId(instanceId);
|
|
307
|
+
const encoded = encodeState(state, tenantId, instanceId, 0);
|
|
308
|
+
return transaction(false, async (client) => definitiveRow(
|
|
309
|
+
await client.query(TRUST_PROGRAM_POSTGRES_SQL.create, [
|
|
310
|
+
tenantId, instanceId, encoded.stateJson, encoded.stateDigest, encoded.eventAt,
|
|
311
|
+
]),
|
|
312
|
+
'create',
|
|
313
|
+
tenantId,
|
|
314
|
+
instanceId,
|
|
315
|
+
new Set(['instance_exists', 'evidence_replayed', 'trust_operation_replayed']),
|
|
316
|
+
0,
|
|
317
|
+
));
|
|
318
|
+
},
|
|
319
|
+
async get(input: { tenantId: string; instanceId: string }) {
|
|
320
|
+
const { tenantId, instanceId } = lookupInput(input);
|
|
321
|
+
return transaction(true, (client) => getWithClient(client, tenantId, instanceId));
|
|
322
|
+
},
|
|
323
|
+
async compareAndSwap(input: {
|
|
324
|
+
tenantId: string;
|
|
325
|
+
instanceId: string;
|
|
326
|
+
expectedRevision: number;
|
|
327
|
+
state: TrustProgramState;
|
|
328
|
+
}) {
|
|
329
|
+
if (!isRecord(input)
|
|
330
|
+
|| Reflect.ownKeys(input).length !== 4
|
|
331
|
+
|| !Object.hasOwn(input, 'tenantId')
|
|
332
|
+
|| !Object.hasOwn(input, 'instanceId')
|
|
333
|
+
|| !Object.hasOwn(input, 'expectedRevision')
|
|
334
|
+
|| !Object.hasOwn(input, 'state')) {
|
|
335
|
+
throw new TypeError('trust-program compareAndSwap input is invalid');
|
|
336
|
+
}
|
|
337
|
+
const { tenantId, instanceId, expectedRevision, state } = input;
|
|
338
|
+
assertTenantId(tenantId);
|
|
339
|
+
assertInstanceId(instanceId);
|
|
340
|
+
assertRevision(expectedRevision, 'expected');
|
|
341
|
+
const nextRevision = expectedRevision + 1;
|
|
342
|
+
if (!Number.isSafeInteger(nextRevision)) {
|
|
343
|
+
throw new TypeError('trust-program next revision is invalid');
|
|
344
|
+
}
|
|
345
|
+
const encoded = encodeState(state, tenantId, instanceId, nextRevision);
|
|
346
|
+
return transaction(false, async (client) => definitiveRow(
|
|
347
|
+
await client.query(TRUST_PROGRAM_POSTGRES_SQL.compareAndSwap, [
|
|
348
|
+
tenantId,
|
|
349
|
+
instanceId,
|
|
350
|
+
expectedRevision,
|
|
351
|
+
nextRevision,
|
|
352
|
+
encoded.stateJson,
|
|
353
|
+
encoded.stateDigest,
|
|
354
|
+
encoded.eventAt,
|
|
355
|
+
]),
|
|
356
|
+
'compareAndSwap',
|
|
357
|
+
tenantId,
|
|
358
|
+
instanceId,
|
|
359
|
+
new Set([
|
|
360
|
+
'instance_not_found', 'revision_conflict', 'clock_regression',
|
|
361
|
+
'evidence_replayed', 'trust_operation_replayed',
|
|
362
|
+
]),
|
|
363
|
+
nextRevision,
|
|
364
|
+
));
|
|
365
|
+
},
|
|
366
|
+
async invalidate(input: {
|
|
367
|
+
tenantId: string;
|
|
368
|
+
instanceId: string;
|
|
369
|
+
expectedRevision: number;
|
|
370
|
+
reason: string;
|
|
371
|
+
at: number;
|
|
372
|
+
}) {
|
|
373
|
+
if (!isRecord(input)
|
|
374
|
+
|| Reflect.ownKeys(input).length !== 5
|
|
375
|
+
|| !Object.hasOwn(input, 'tenantId')
|
|
376
|
+
|| !Object.hasOwn(input, 'instanceId')
|
|
377
|
+
|| !Object.hasOwn(input, 'expectedRevision')
|
|
378
|
+
|| !Object.hasOwn(input, 'reason')
|
|
379
|
+
|| !Object.hasOwn(input, 'at')) {
|
|
380
|
+
throw new TypeError('trust-program invalidate input is invalid');
|
|
381
|
+
}
|
|
382
|
+
const { tenantId, instanceId, expectedRevision, reason, at } = input;
|
|
383
|
+
assertTenantId(tenantId);
|
|
384
|
+
assertInstanceId(instanceId);
|
|
385
|
+
assertRevision(expectedRevision, 'expected');
|
|
386
|
+
if (typeof reason !== 'string' || reason.length < 1 || reason.length > 256) {
|
|
387
|
+
throw new TypeError('trust-program invalidation reason is invalid');
|
|
388
|
+
}
|
|
389
|
+
if (!Number.isSafeInteger(at) || at < 0 || at > 8_640_000_000_000_000) {
|
|
390
|
+
throw new TypeError('trust-program invalidation time is invalid');
|
|
391
|
+
}
|
|
392
|
+
return transaction(false, async (client) => {
|
|
393
|
+
const loaded = await getWithClient(client, tenantId, instanceId);
|
|
394
|
+
if (!loaded.ok) return loaded;
|
|
395
|
+
const current = loaded.state!;
|
|
396
|
+
if (current.revision !== expectedRevision) return fail('revision_conflict');
|
|
397
|
+
if (current.status === 'invalidated') return fail('program_instance_invalidated');
|
|
398
|
+
const next = invalidatedState(current, reason, at);
|
|
399
|
+
const encoded = encodeState(next, tenantId, instanceId, expectedRevision + 1);
|
|
400
|
+
return definitiveRow(
|
|
401
|
+
await client.query(TRUST_PROGRAM_POSTGRES_SQL.invalidate, [
|
|
402
|
+
tenantId,
|
|
403
|
+
instanceId,
|
|
404
|
+
expectedRevision,
|
|
405
|
+
reason,
|
|
406
|
+
encoded.eventAt,
|
|
407
|
+
encoded.stateJson,
|
|
408
|
+
encoded.stateDigest,
|
|
409
|
+
]),
|
|
410
|
+
'invalidate',
|
|
411
|
+
tenantId,
|
|
412
|
+
instanceId,
|
|
413
|
+
new Set([
|
|
414
|
+
'instance_not_found', 'revision_conflict', 'program_instance_invalidated',
|
|
415
|
+
'clock_regression',
|
|
416
|
+
]),
|
|
417
|
+
expectedRevision + 1,
|
|
418
|
+
);
|
|
419
|
+
});
|
|
420
|
+
},
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
export default {
|
|
425
|
+
TRUST_PROGRAM_PG_STORE_VERSION,
|
|
426
|
+
TRUST_PROGRAM_MAX_STATE_BYTES,
|
|
427
|
+
TRUST_PROGRAM_POSTGRES_SQL,
|
|
428
|
+
createTrustProgramPostgresStore,
|
|
429
|
+
};
|