@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,170 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// EMILIA Gate default action packs: the high-risk families that should require
|
|
3
|
+
// pre-execution human authorization before a machine mutates the world.
|
|
4
|
+
|
|
5
|
+
export const ACTION_RISK_MANIFEST_VERSION = 'EP-ACTION-RISK-MANIFEST-v0.1';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Shape of a single action-pack entry. `business_authorization` is not part
|
|
9
|
+
* of the shipped defaults below but is a legitimate dynamic extension point:
|
|
10
|
+
* callers (e.g. lib/gate/reference-lab.js) attach it to a manifest entry
|
|
11
|
+
* after createDefaultActionRiskManifest() returns, before enforcement.
|
|
12
|
+
*/
|
|
13
|
+
type ActionPack = {
|
|
14
|
+
id: string;
|
|
15
|
+
label: string;
|
|
16
|
+
action_type: string;
|
|
17
|
+
risk?: string;
|
|
18
|
+
receipt_required: boolean;
|
|
19
|
+
assurance_class?: string;
|
|
20
|
+
match: { protocol: string; tool: string };
|
|
21
|
+
why?: string;
|
|
22
|
+
execution_binding?: { required_fields: string[]; caid_selector?: { field: string } };
|
|
23
|
+
business_authorization?: Record<string, any>;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export const HIGH_RISK_ACTION_PACKS: readonly ActionPack[] = Object.freeze([
|
|
27
|
+
Object.freeze({
|
|
28
|
+
id: 'money_movement.release',
|
|
29
|
+
label: 'Money movement',
|
|
30
|
+
action_type: 'payment.release',
|
|
31
|
+
risk: 'critical',
|
|
32
|
+
receipt_required: true,
|
|
33
|
+
assurance_class: 'class_a',
|
|
34
|
+
match: { protocol: 'mcp', tool: 'release_payment' },
|
|
35
|
+
why: 'Moves funds or releases value. Requires a named human signoff, not an agent-only key.',
|
|
36
|
+
execution_binding: {
|
|
37
|
+
required_fields: ['action_type', 'amount_usd', 'currency', 'payment_instruction_id', 'beneficiary_account_hash'],
|
|
38
|
+
caid_selector: { field: 'action_caid' },
|
|
39
|
+
},
|
|
40
|
+
}),
|
|
41
|
+
Object.freeze({
|
|
42
|
+
id: 'money_movement.bank_details_change',
|
|
43
|
+
label: 'Bank-detail change',
|
|
44
|
+
action_type: 'payment.bank_details.change',
|
|
45
|
+
risk: 'critical',
|
|
46
|
+
receipt_required: true,
|
|
47
|
+
assurance_class: 'class_a',
|
|
48
|
+
match: { protocol: 'mcp', tool: 'change_bank_details' },
|
|
49
|
+
why: 'Changes where future money flows. Treats payee, beneficiary, vendor, and payroll account changes as high-risk by category.',
|
|
50
|
+
execution_binding: {
|
|
51
|
+
required_fields: ['action_type', 'account_holder_id', 'payment_instruction_id', 'bank_account_hash'],
|
|
52
|
+
},
|
|
53
|
+
}),
|
|
54
|
+
Object.freeze({
|
|
55
|
+
id: 'production.deploy',
|
|
56
|
+
label: 'Production deploy',
|
|
57
|
+
action_type: 'deploy.production',
|
|
58
|
+
risk: 'critical',
|
|
59
|
+
receipt_required: true,
|
|
60
|
+
assurance_class: 'quorum',
|
|
61
|
+
match: { protocol: 'mcp', tool: 'deploy_production' },
|
|
62
|
+
why: 'Changes live production behavior. Quorum is the cryptographic two-person rule for hard operational cuts.',
|
|
63
|
+
execution_binding: {
|
|
64
|
+
required_fields: ['action_type', 'repo', 'commit_sha', 'environment', 'artifact_digest'],
|
|
65
|
+
},
|
|
66
|
+
}),
|
|
67
|
+
Object.freeze({
|
|
68
|
+
id: 'permissions.admin_change',
|
|
69
|
+
label: 'Permission or admin change',
|
|
70
|
+
action_type: 'permission.admin.change',
|
|
71
|
+
risk: 'critical',
|
|
72
|
+
receipt_required: true,
|
|
73
|
+
assurance_class: 'quorum',
|
|
74
|
+
match: { protocol: 'mcp', tool: 'change_permissions' },
|
|
75
|
+
why: 'Changes who can act next. Privilege changes deserve stronger proof than the session that requested them.',
|
|
76
|
+
execution_binding: {
|
|
77
|
+
required_fields: ['action_type', 'principal_id', 'role', 'scope'],
|
|
78
|
+
},
|
|
79
|
+
}),
|
|
80
|
+
Object.freeze({
|
|
81
|
+
id: 'data.bulk_export',
|
|
82
|
+
label: 'Bulk data export',
|
|
83
|
+
action_type: 'data.export',
|
|
84
|
+
risk: 'high',
|
|
85
|
+
receipt_required: true,
|
|
86
|
+
assurance_class: 'class_a',
|
|
87
|
+
match: { protocol: 'mcp', tool: 'export_customer_data' },
|
|
88
|
+
why: 'Moves sensitive data out of its system of record. The recipient and purpose must be bound to the approval.',
|
|
89
|
+
execution_binding: {
|
|
90
|
+
required_fields: ['action_type', 'dataset', 'recipient', 'purpose', 'row_count_max'],
|
|
91
|
+
},
|
|
92
|
+
}),
|
|
93
|
+
Object.freeze({
|
|
94
|
+
id: 'records.delete',
|
|
95
|
+
label: 'Record deletion',
|
|
96
|
+
action_type: 'record.delete',
|
|
97
|
+
risk: 'high',
|
|
98
|
+
receipt_required: true,
|
|
99
|
+
assurance_class: 'class_a',
|
|
100
|
+
match: { protocol: 'mcp', tool: 'delete_record' },
|
|
101
|
+
why: 'Destroys or hides state. The record identity and pre-state must be bound before deletion.',
|
|
102
|
+
execution_binding: {
|
|
103
|
+
required_fields: ['action_type', 'record_type', 'record_id', 'before_state_hash'],
|
|
104
|
+
},
|
|
105
|
+
}),
|
|
106
|
+
Object.freeze({
|
|
107
|
+
id: 'regulated.decision_override',
|
|
108
|
+
label: 'Regulated decision override',
|
|
109
|
+
action_type: 'regulated.decision.override',
|
|
110
|
+
risk: 'critical',
|
|
111
|
+
receipt_required: true,
|
|
112
|
+
assurance_class: 'quorum',
|
|
113
|
+
match: { protocol: 'mcp', tool: 'override_regulated_decision' },
|
|
114
|
+
why: 'Changes a decision with legal, benefit, credit, clinical, or safety impact. Requires named accountability.',
|
|
115
|
+
execution_binding: {
|
|
116
|
+
required_fields: ['action_type', 'case_id', 'decision_id', 'subject_id', 'override_reason'],
|
|
117
|
+
},
|
|
118
|
+
}),
|
|
119
|
+
]);
|
|
120
|
+
|
|
121
|
+
export const DEFAULT_PASS_THROUGH_ACTIONS: readonly ActionPack[] = Object.freeze([
|
|
122
|
+
Object.freeze({
|
|
123
|
+
id: 'observe.read_status',
|
|
124
|
+
label: 'Read-only status',
|
|
125
|
+
action_type: 'read.status',
|
|
126
|
+
receipt_required: false,
|
|
127
|
+
match: { protocol: 'mcp', tool: 'read_status' },
|
|
128
|
+
}),
|
|
129
|
+
]);
|
|
130
|
+
|
|
131
|
+
export function createDefaultActionRiskManifest({
|
|
132
|
+
includePassThrough = true,
|
|
133
|
+
extraActions = [],
|
|
134
|
+
}: { includePassThrough?: boolean; extraActions?: ActionPack[] } = {}) {
|
|
135
|
+
return {
|
|
136
|
+
'@version': ACTION_RISK_MANIFEST_VERSION,
|
|
137
|
+
actions: [
|
|
138
|
+
...HIGH_RISK_ACTION_PACKS.map((a) => ({
|
|
139
|
+
...a,
|
|
140
|
+
match: { ...a.match },
|
|
141
|
+
execution_binding: a.execution_binding
|
|
142
|
+
? {
|
|
143
|
+
...a.execution_binding,
|
|
144
|
+
required_fields: [...a.execution_binding.required_fields],
|
|
145
|
+
...(a.execution_binding.caid_selector
|
|
146
|
+
? { caid_selector: { ...a.execution_binding.caid_selector } }
|
|
147
|
+
: {}),
|
|
148
|
+
}
|
|
149
|
+
: undefined,
|
|
150
|
+
})),
|
|
151
|
+
...(includePassThrough ? DEFAULT_PASS_THROUGH_ACTIONS.map((a) => ({ ...a, match: { ...a.match } })) : []),
|
|
152
|
+
...extraActions,
|
|
153
|
+
],
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export const DEFAULT_GATE_MANIFEST = Object.freeze(createDefaultActionRiskManifest());
|
|
158
|
+
|
|
159
|
+
export function highRiskActionTypes(actions = HIGH_RISK_ACTION_PACKS) {
|
|
160
|
+
return actions.filter((a) => a.receipt_required).map((a) => a.action_type);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export default {
|
|
164
|
+
ACTION_RISK_MANIFEST_VERSION,
|
|
165
|
+
HIGH_RISK_ACTION_PACKS,
|
|
166
|
+
DEFAULT_PASS_THROUGH_ACTIONS,
|
|
167
|
+
DEFAULT_GATE_MANIFEST,
|
|
168
|
+
createDefaultActionRiskManifest,
|
|
169
|
+
highRiskActionTypes,
|
|
170
|
+
};
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
/**
|
|
3
|
+
* EMILIA Gate — System-of-Record adapter kit. One enforcement contract shared by
|
|
4
|
+
* every adapter (GitHub, Stripe, Supabase, AWS, ...): map a destructive op to a
|
|
5
|
+
* gate selector + the observed system-of-record fields, run it through
|
|
6
|
+
* gate.run(), and FAIL CLOSED — if the gate refuses, the real client call is
|
|
7
|
+
* never made and we throw EMILIA_RECEIPT_REQUIRED.
|
|
8
|
+
*
|
|
9
|
+
* An op spec is: { selector, observed(params) -> {fields...},
|
|
10
|
+
* actuator?(params, observed) -> {fields...}, perform(client, actuator) -> result }.
|
|
11
|
+
* `observed` must return the same material fields the action pack binds, drawn
|
|
12
|
+
* from the call params (the system-of-record facts), so a receipt for resource A
|
|
13
|
+
* cannot authorize a mutation of resource B.
|
|
14
|
+
*/
|
|
15
|
+
import { canonicalize, hashCanonical } from '../execution-binding.js';
|
|
16
|
+
|
|
17
|
+
export { hashCanonical };
|
|
18
|
+
|
|
19
|
+
function deepFreeze(value) {
|
|
20
|
+
if (value && typeof value === 'object' && !Object.isFrozen(value)) {
|
|
21
|
+
for (const child of Object.values(value)) deepFreeze(child);
|
|
22
|
+
Object.freeze(value);
|
|
23
|
+
}
|
|
24
|
+
return value;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** Canonical plain-data snapshot used at the actuator boundary. */
|
|
28
|
+
export function canonicalActuatorObject(value) {
|
|
29
|
+
return deepFreeze(JSON.parse(canonicalize(value)));
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** Build an EP-ACTION-RISK-MANIFEST-v0.1 from a frozen action pack (deep-copied). */
|
|
33
|
+
export function manifestFromPack(pack, extraActions = []) {
|
|
34
|
+
return {
|
|
35
|
+
'@version': 'EP-ACTION-RISK-MANIFEST-v0.1',
|
|
36
|
+
actions: [
|
|
37
|
+
...pack.map((a) => ({
|
|
38
|
+
...a,
|
|
39
|
+
match: { ...a.match },
|
|
40
|
+
execution_binding: a.execution_binding
|
|
41
|
+
? { ...a.execution_binding, required_fields: [...a.execution_binding.required_fields] }
|
|
42
|
+
: undefined,
|
|
43
|
+
...(a.business_authorization
|
|
44
|
+
? { business_authorization: canonicalActuatorObject(a.business_authorization) }
|
|
45
|
+
: {}),
|
|
46
|
+
})),
|
|
47
|
+
...extraActions,
|
|
48
|
+
],
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Create an adapter from a system name + op map.
|
|
54
|
+
* @returns {{ ops:object, OPS:readonly string[], guard:(gate,client,{op,params,receipt})=>Promise<{result,reliance,execution}> }}
|
|
55
|
+
*/
|
|
56
|
+
export function createAdapter({ system, ops }) {
|
|
57
|
+
if (!system || !ops || typeof ops !== 'object') throw new Error('createAdapter requires { system, ops }');
|
|
58
|
+
const OPS = Object.freeze(Object.keys(ops));
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* @param {object} gate
|
|
62
|
+
* @param {object} client
|
|
63
|
+
*/
|
|
64
|
+
async function guard(
|
|
65
|
+
gate,
|
|
66
|
+
client,
|
|
67
|
+
{ op, params = {}, receipt = null }: { op?: string; params?: object; receipt?: any } = {},
|
|
68
|
+
) {
|
|
69
|
+
if (!gate || typeof gate.run !== 'function') throw new Error(`${system} adapter requires an EMILIA Gate (with .run)`);
|
|
70
|
+
const spec = ops[op as string];
|
|
71
|
+
if (!spec) throw new Error(`${system} adapter: unknown op "${op}" (expected one of: ${OPS.join(', ')})`);
|
|
72
|
+
if (!receipt) {
|
|
73
|
+
const refused = await gate.run(
|
|
74
|
+
{ selector: spec.selector, receipt: null, observedAction: null },
|
|
75
|
+
() => { throw new Error('unreachable_adapter_effect'); },
|
|
76
|
+
);
|
|
77
|
+
const e = new Error(`EMILIA Gate refused ${system}:${op} — ${refused.authorization.reason}`) as Error & {
|
|
78
|
+
code?: string; status?: any; gate?: any; challenge?: any;
|
|
79
|
+
};
|
|
80
|
+
e.code = 'EMILIA_RECEIPT_REQUIRED';
|
|
81
|
+
e.status = refused.status;
|
|
82
|
+
e.gate = refused.authorization;
|
|
83
|
+
e.challenge = refused.body;
|
|
84
|
+
throw e;
|
|
85
|
+
}
|
|
86
|
+
// Snapshot before any asynchronous verification. Caller-owned params may be
|
|
87
|
+
// mutated while gate.run() awaits evidence/storage; neither the observation
|
|
88
|
+
// nor the eventual provider call may follow that mutable reference.
|
|
89
|
+
const input = canonicalActuatorObject(params);
|
|
90
|
+
const observedAction = canonicalActuatorObject(spec.observed(input));
|
|
91
|
+
// Default to the verified fields only. Operations that need a preimage for a
|
|
92
|
+
// bound digest (SQL, RLS, secret values, queries) must opt in with an explicit
|
|
93
|
+
// actuator() constructor. The unrestricted caller object is never passed.
|
|
94
|
+
const actuator = canonicalActuatorObject(
|
|
95
|
+
typeof spec.actuator === 'function' ? spec.actuator(input, observedAction) : observedAction,
|
|
96
|
+
);
|
|
97
|
+
const out = await gate.run(
|
|
98
|
+
{ selector: spec.selector, receipt, observedAction },
|
|
99
|
+
() => spec.perform(client, actuator),
|
|
100
|
+
);
|
|
101
|
+
if (!out.ok) {
|
|
102
|
+
const e = new Error(`EMILIA Gate refused ${system}:${op} — ${out.authorization.reason}`) as Error & {
|
|
103
|
+
code?: string; status?: any; gate?: any; challenge?: any;
|
|
104
|
+
};
|
|
105
|
+
e.code = 'EMILIA_RECEIPT_REQUIRED';
|
|
106
|
+
e.status = out.status;
|
|
107
|
+
e.gate = out.authorization;
|
|
108
|
+
e.challenge = out.body;
|
|
109
|
+
throw e;
|
|
110
|
+
}
|
|
111
|
+
return { result: out.result, reliance: out.packet, execution: out.execution };
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return { ops, OPS, guard };
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export default { createAdapter, manifestFromPack, hashCanonical, canonicalActuatorObject };
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
/**
|
|
3
|
+
* EMILIA Gate — AWS System-of-Record adapter (IAM + network).
|
|
4
|
+
*
|
|
5
|
+
* "Install this before your agent can change cloud permissions or open the
|
|
6
|
+
* network." Wraps the high-blast-radius AWS operations — attach IAM policy,
|
|
7
|
+
* create access key, delete user, and open a security-group ingress — so they
|
|
8
|
+
* never reach AWS without a valid, sufficiently-assured, non-replayed receipt
|
|
9
|
+
* bound to THIS principal/policy/group. Privilege and network changes default
|
|
10
|
+
* to quorum (the two-person rule).
|
|
11
|
+
*
|
|
12
|
+
* import { IAMClient, EC2Client } from '@aws-sdk/...';
|
|
13
|
+
* import { createGate } from '@emilia-protocol/gate';
|
|
14
|
+
* import { createAwsManifest, guardAwsMutation } from '@emilia-protocol/gate/adapters/aws';
|
|
15
|
+
*
|
|
16
|
+
* const gate = createGate({ manifest: createAwsManifest(), trustedKeys: [ISSUER], store: sharedConsumptionStore });
|
|
17
|
+
* // client: { iam: { attachUserPolicy, createAccessKey, deleteUser }, ec2: { authorizeSecurityGroupIngress } }
|
|
18
|
+
* await guardAwsMutation(gate, client, {
|
|
19
|
+
* op: 'iam.attach_policy', params: { user: 'svc-bot', policy_arn: 'arn:aws:iam::aws:policy/AdministratorAccess' }, receipt,
|
|
20
|
+
* });
|
|
21
|
+
*/
|
|
22
|
+
import { createAdapter, manifestFromPack } from './_kit.js';
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @typedef {object} AwsIamClient
|
|
26
|
+
* @property {(input: {UserName: string, PolicyArn: string}) => any} attachUserPolicy
|
|
27
|
+
* @property {(input: {UserName: string}) => any} createAccessKey
|
|
28
|
+
* @property {(input: {UserName: string}) => any} deleteUser
|
|
29
|
+
*/
|
|
30
|
+
/**
|
|
31
|
+
* @typedef {object} AwsEc2Client
|
|
32
|
+
* @property {(input: {GroupId: string, CidrIp: string, FromPort: number, ToPort: number, IpProtocol: string}) => any} authorizeSecurityGroupIngress
|
|
33
|
+
*/
|
|
34
|
+
/** @typedef {{ iam: AwsIamClient, ec2: AwsEc2Client }} AwsClient */
|
|
35
|
+
|
|
36
|
+
export const AWS_ACTION_PACK = Object.freeze([
|
|
37
|
+
Object.freeze({
|
|
38
|
+
id: 'aws.iam.attach_policy', label: 'IAM attach policy', action_type: 'aws.iam.attach_policy',
|
|
39
|
+
risk: 'critical', receipt_required: true, assurance_class: 'quorum',
|
|
40
|
+
match: { protocol: 'aws', tool: 'attach_user_policy' },
|
|
41
|
+
why: 'Grants permissions. Privilege escalation deserves the two-person rule.',
|
|
42
|
+
execution_binding: { required_fields: ['action_type', 'user', 'policy_arn'] },
|
|
43
|
+
}),
|
|
44
|
+
Object.freeze({
|
|
45
|
+
id: 'aws.iam.create_access_key', label: 'IAM create access key', action_type: 'aws.iam.create_access_key',
|
|
46
|
+
risk: 'critical', receipt_required: true, assurance_class: 'class_a',
|
|
47
|
+
match: { protocol: 'aws', tool: 'create_access_key' },
|
|
48
|
+
why: 'Mints long-lived credentials. Bind the user to a named approval.',
|
|
49
|
+
execution_binding: { required_fields: ['action_type', 'user'] },
|
|
50
|
+
}),
|
|
51
|
+
Object.freeze({
|
|
52
|
+
id: 'aws.iam.delete_user', label: 'IAM delete user', action_type: 'aws.iam.delete_user',
|
|
53
|
+
risk: 'high', receipt_required: true, assurance_class: 'class_a',
|
|
54
|
+
match: { protocol: 'aws', tool: 'delete_user' },
|
|
55
|
+
why: 'Destroys an identity. Bind the target user.',
|
|
56
|
+
execution_binding: { required_fields: ['action_type', 'user'] },
|
|
57
|
+
}),
|
|
58
|
+
Object.freeze({
|
|
59
|
+
id: 'aws.ec2.authorize_ingress', label: 'Open security-group ingress', action_type: 'aws.ec2.authorize_ingress',
|
|
60
|
+
risk: 'critical', receipt_required: true, assurance_class: 'quorum',
|
|
61
|
+
match: { protocol: 'aws', tool: 'authorize_security_group_ingress' },
|
|
62
|
+
why: 'Opens the network. Bind group/CIDR/port so 0.0.0.0/0:22 cannot slip through.',
|
|
63
|
+
execution_binding: { required_fields: ['action_type', 'group_id', 'cidr', 'protocol', 'from_port', 'to_port'] },
|
|
64
|
+
}),
|
|
65
|
+
]);
|
|
66
|
+
|
|
67
|
+
const OPS = {
|
|
68
|
+
'iam.attach_policy': {
|
|
69
|
+
selector: { protocol: 'aws', tool: 'attach_user_policy' },
|
|
70
|
+
/** @param {{user: string, policy_arn: string}} p */
|
|
71
|
+
observed: (p) => ({ action_type: 'aws.iam.attach_policy', user: p.user, policy_arn: p.policy_arn }),
|
|
72
|
+
/**
|
|
73
|
+
* @param {AwsClient} client
|
|
74
|
+
* @param {{user: string, policy_arn: string}} p
|
|
75
|
+
*/
|
|
76
|
+
perform: (client, p) => client.iam.attachUserPolicy({ UserName: p.user, PolicyArn: p.policy_arn }),
|
|
77
|
+
},
|
|
78
|
+
'iam.create_access_key': {
|
|
79
|
+
selector: { protocol: 'aws', tool: 'create_access_key' },
|
|
80
|
+
/** @param {{user: string}} p */
|
|
81
|
+
observed: (p) => ({ action_type: 'aws.iam.create_access_key', user: p.user }),
|
|
82
|
+
/**
|
|
83
|
+
* @param {AwsClient} client
|
|
84
|
+
* @param {{user: string}} p
|
|
85
|
+
*/
|
|
86
|
+
perform: (client, p) => client.iam.createAccessKey({ UserName: p.user }),
|
|
87
|
+
},
|
|
88
|
+
'iam.delete_user': {
|
|
89
|
+
selector: { protocol: 'aws', tool: 'delete_user' },
|
|
90
|
+
/** @param {{user: string}} p */
|
|
91
|
+
observed: (p) => ({ action_type: 'aws.iam.delete_user', user: p.user }),
|
|
92
|
+
/**
|
|
93
|
+
* @param {AwsClient} client
|
|
94
|
+
* @param {{user: string}} p
|
|
95
|
+
*/
|
|
96
|
+
perform: (client, p) => client.iam.deleteUser({ UserName: p.user }),
|
|
97
|
+
},
|
|
98
|
+
'ec2.authorize_ingress': {
|
|
99
|
+
selector: { protocol: 'aws', tool: 'authorize_security_group_ingress' },
|
|
100
|
+
/** @param {{group_id: string, cidr: string, protocol?: string, from_port: number, to_port?: number}} p */
|
|
101
|
+
observed: (p) => ({
|
|
102
|
+
action_type: 'aws.ec2.authorize_ingress',
|
|
103
|
+
group_id: p.group_id,
|
|
104
|
+
cidr: p.cidr,
|
|
105
|
+
protocol: p.protocol ?? 'tcp',
|
|
106
|
+
from_port: p.from_port,
|
|
107
|
+
to_port: p.to_port ?? p.from_port,
|
|
108
|
+
}),
|
|
109
|
+
/**
|
|
110
|
+
* @param {AwsClient} client
|
|
111
|
+
* @param {{group_id: string, cidr: string, protocol: string, from_port: number, to_port: number}} p
|
|
112
|
+
*/
|
|
113
|
+
perform: (client, p) => client.ec2.authorizeSecurityGroupIngress({
|
|
114
|
+
GroupId: p.group_id,
|
|
115
|
+
CidrIp: p.cidr,
|
|
116
|
+
FromPort: p.from_port,
|
|
117
|
+
ToPort: p.to_port,
|
|
118
|
+
IpProtocol: p.protocol,
|
|
119
|
+
}),
|
|
120
|
+
},
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
const adapter = createAdapter({ system: 'aws', ops: OPS });
|
|
124
|
+
export const AWS_OPS = adapter.OPS;
|
|
125
|
+
|
|
126
|
+
/** @param {object[]} extraActions */
|
|
127
|
+
export function createAwsManifest(extraActions = []) {
|
|
128
|
+
return manifestFromPack(AWS_ACTION_PACK, extraActions);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Guard a high-blast-radius AWS mutation behind the gate.
|
|
133
|
+
* @param {object} gate a gate built with createAwsManifest()
|
|
134
|
+
* @param {AwsClient} client { iam: {attachUserPolicy, createAccessKey, deleteUser}, ec2: {authorizeSecurityGroupIngress} }
|
|
135
|
+
* @param {{ op: string, params?: object, receipt?: any }} args { op, params, receipt }
|
|
136
|
+
* @throws Error{code:'EMILIA_RECEIPT_REQUIRED'} if refused — the call never reaches AWS
|
|
137
|
+
*/
|
|
138
|
+
export function guardAwsMutation(gate, client, args) {
|
|
139
|
+
return adapter.guard(gate, client, /** @type {{ op: any, params: any, receipt: any }} */ (args));
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export default { AWS_ACTION_PACK, AWS_OPS, createAwsManifest, guardAwsMutation };
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
/**
|
|
3
|
+
* EMILIA Gate — Cloudflare System-of-Record adapter.
|
|
4
|
+
* Guards DNS record delete, zone delete, and WAF/firewall disable so they never
|
|
5
|
+
* reach Cloudflare without a receipt bound to THIS zone. Client injected.
|
|
6
|
+
*/
|
|
7
|
+
import { createAdapter, manifestFromPack } from './_kit.js';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @typedef {object} CloudflareClient
|
|
11
|
+
* @property {(input: {zone: string, recordId: string}) => any} deleteDnsRecord
|
|
12
|
+
* @property {(input: {zone: string}) => any} deleteZone
|
|
13
|
+
* @property {(input: {zone: string, ruleId: string, enabled: boolean}) => any} setFirewallRule
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
export const CLOUDFLARE_ACTION_PACK = Object.freeze([
|
|
17
|
+
Object.freeze({
|
|
18
|
+
id: 'cloudflare.dns.delete', label: 'Delete DNS record', action_type: 'cloudflare.dns.delete',
|
|
19
|
+
risk: 'high', receipt_required: true, assurance_class: 'class_a',
|
|
20
|
+
match: { protocol: 'cloudflare', tool: 'delete_dns_record' },
|
|
21
|
+
why: 'Removing DNS can take a service offline or enable takeover. Bind zone+record.',
|
|
22
|
+
execution_binding: { required_fields: ['action_type', 'zone', 'record_id'] },
|
|
23
|
+
}),
|
|
24
|
+
Object.freeze({
|
|
25
|
+
id: 'cloudflare.zone.delete', label: 'Delete zone', action_type: 'cloudflare.zone.delete',
|
|
26
|
+
risk: 'critical', receipt_required: true, assurance_class: 'quorum',
|
|
27
|
+
match: { protocol: 'cloudflare', tool: 'delete_zone' },
|
|
28
|
+
why: 'Deletes an entire zone. Quorum.',
|
|
29
|
+
execution_binding: { required_fields: ['action_type', 'zone'] },
|
|
30
|
+
}),
|
|
31
|
+
Object.freeze({
|
|
32
|
+
id: 'cloudflare.firewall.disable', label: 'Disable firewall rule', action_type: 'cloudflare.firewall.disable',
|
|
33
|
+
risk: 'critical', receipt_required: true, assurance_class: 'quorum',
|
|
34
|
+
match: { protocol: 'cloudflare', tool: 'set_firewall_rule' },
|
|
35
|
+
why: 'Disabling WAF/firewall opens the perimeter. Quorum + bind zone+rule.',
|
|
36
|
+
execution_binding: { required_fields: ['action_type', 'zone', 'rule_id'] },
|
|
37
|
+
}),
|
|
38
|
+
]);
|
|
39
|
+
|
|
40
|
+
const OPS = {
|
|
41
|
+
'dns.delete': {
|
|
42
|
+
selector: { protocol: 'cloudflare', tool: 'delete_dns_record' },
|
|
43
|
+
/** @param {{zone: string, record_id: string}} p */
|
|
44
|
+
observed: (p) => ({ action_type: 'cloudflare.dns.delete', zone: p.zone, record_id: p.record_id }),
|
|
45
|
+
/**
|
|
46
|
+
* @param {CloudflareClient} c
|
|
47
|
+
* @param {{zone: string, record_id: string}} p
|
|
48
|
+
*/
|
|
49
|
+
perform: (c, p) => c.deleteDnsRecord({ zone: p.zone, recordId: p.record_id }),
|
|
50
|
+
},
|
|
51
|
+
'zone.delete': {
|
|
52
|
+
selector: { protocol: 'cloudflare', tool: 'delete_zone' },
|
|
53
|
+
/** @param {{zone: string}} p */
|
|
54
|
+
observed: (p) => ({ action_type: 'cloudflare.zone.delete', zone: p.zone }),
|
|
55
|
+
/**
|
|
56
|
+
* @param {CloudflareClient} c
|
|
57
|
+
* @param {{zone: string}} p
|
|
58
|
+
*/
|
|
59
|
+
perform: (c, p) => c.deleteZone({ zone: p.zone }),
|
|
60
|
+
},
|
|
61
|
+
'firewall.disable': {
|
|
62
|
+
selector: { protocol: 'cloudflare', tool: 'set_firewall_rule' },
|
|
63
|
+
/** @param {{zone: string, rule_id: string}} p */
|
|
64
|
+
observed: (p) => ({ action_type: 'cloudflare.firewall.disable', zone: p.zone, rule_id: p.rule_id }),
|
|
65
|
+
/**
|
|
66
|
+
* @param {CloudflareClient} c
|
|
67
|
+
* @param {{zone: string, rule_id: string}} p
|
|
68
|
+
*/
|
|
69
|
+
perform: (c, p) => c.setFirewallRule({ zone: p.zone, ruleId: p.rule_id, enabled: false }),
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const adapter = createAdapter({ system: 'cloudflare', ops: OPS });
|
|
74
|
+
export const CLOUDFLARE_OPS = adapter.OPS;
|
|
75
|
+
/** @param {object[]} extra */
|
|
76
|
+
export function createCloudflareManifest(extra = []) { return manifestFromPack(CLOUDFLARE_ACTION_PACK, extra); }
|
|
77
|
+
export function guardCloudflareMutation(gate, client, args) { return adapter.guard(gate, client, args); }
|
|
78
|
+
export default { CLOUDFLARE_ACTION_PACK, CLOUDFLARE_OPS, createCloudflareManifest, guardCloudflareMutation };
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
/**
|
|
3
|
+
* EMILIA Gate — Google Cloud System-of-Record adapter.
|
|
4
|
+
*
|
|
5
|
+
* "Install this before your agent can change cloud permissions or delete a
|
|
6
|
+
* project." Guards the high-blast-radius GCP operations — IAM policy set,
|
|
7
|
+
* service-account key create, project delete, storage bucket delete — so they
|
|
8
|
+
* never reach GCP without a receipt bound to THIS resource/member/role. Client
|
|
9
|
+
* is injected (the @google-cloud SDKs or a thin wrapper).
|
|
10
|
+
*/
|
|
11
|
+
import { createAdapter, manifestFromPack } from './_kit.js';
|
|
12
|
+
|
|
13
|
+
export const GCP_ACTION_PACK = Object.freeze([
|
|
14
|
+
Object.freeze({
|
|
15
|
+
id: 'gcp.iam.set_policy', label: 'GCP IAM set policy', action_type: 'gcp.iam.set_policy',
|
|
16
|
+
risk: 'critical', receipt_required: true, assurance_class: 'quorum',
|
|
17
|
+
match: { protocol: 'gcp', tool: 'set_iam_policy' },
|
|
18
|
+
why: 'Grants cloud permissions. Bind resource+member+role; quorum.',
|
|
19
|
+
execution_binding: { required_fields: ['action_type', 'resource', 'member', 'role'] },
|
|
20
|
+
}),
|
|
21
|
+
Object.freeze({
|
|
22
|
+
id: 'gcp.sa_key.create', label: 'GCP service-account key create', action_type: 'gcp.sa_key.create',
|
|
23
|
+
risk: 'critical', receipt_required: true, assurance_class: 'class_a',
|
|
24
|
+
match: { protocol: 'gcp', tool: 'create_service_account_key' },
|
|
25
|
+
why: 'Mints long-lived cloud credentials. Bind the service account.',
|
|
26
|
+
execution_binding: { required_fields: ['action_type', 'service_account'] },
|
|
27
|
+
}),
|
|
28
|
+
Object.freeze({
|
|
29
|
+
id: 'gcp.project.delete', label: 'GCP project delete', action_type: 'gcp.project.delete',
|
|
30
|
+
risk: 'critical', receipt_required: true, assurance_class: 'quorum',
|
|
31
|
+
match: { protocol: 'gcp', tool: 'delete_project' },
|
|
32
|
+
why: 'Deletes an entire project. Quorum.',
|
|
33
|
+
execution_binding: { required_fields: ['action_type', 'project'] },
|
|
34
|
+
}),
|
|
35
|
+
Object.freeze({
|
|
36
|
+
id: 'gcp.storage.bucket_delete', label: 'GCP bucket delete', action_type: 'gcp.storage.bucket_delete',
|
|
37
|
+
risk: 'high', receipt_required: true, assurance_class: 'class_a',
|
|
38
|
+
match: { protocol: 'gcp', tool: 'delete_bucket' },
|
|
39
|
+
why: 'Destroys a storage bucket and its objects. Bind the bucket.',
|
|
40
|
+
execution_binding: { required_fields: ['action_type', 'bucket'] },
|
|
41
|
+
}),
|
|
42
|
+
]);
|
|
43
|
+
|
|
44
|
+
const OPS = {
|
|
45
|
+
'iam.set_policy': {
|
|
46
|
+
selector: { protocol: 'gcp', tool: 'set_iam_policy' },
|
|
47
|
+
observed: (p) => ({ action_type: 'gcp.iam.set_policy', resource: p.resource, member: p.member, role: p.role }),
|
|
48
|
+
perform: (c, p) => c.setIamPolicy({ resource: p.resource, member: p.member, role: p.role }),
|
|
49
|
+
},
|
|
50
|
+
'sa_key.create': {
|
|
51
|
+
selector: { protocol: 'gcp', tool: 'create_service_account_key' },
|
|
52
|
+
observed: (p) => ({ action_type: 'gcp.sa_key.create', service_account: p.service_account }),
|
|
53
|
+
perform: (c, p) => c.createServiceAccountKey({ service_account: p.service_account }),
|
|
54
|
+
},
|
|
55
|
+
'project.delete': {
|
|
56
|
+
selector: { protocol: 'gcp', tool: 'delete_project' },
|
|
57
|
+
observed: (p) => ({ action_type: 'gcp.project.delete', project: p.project }),
|
|
58
|
+
perform: (c, p) => c.deleteProject({ project: p.project }),
|
|
59
|
+
},
|
|
60
|
+
'storage.bucket_delete': {
|
|
61
|
+
selector: { protocol: 'gcp', tool: 'delete_bucket' },
|
|
62
|
+
observed: (p) => ({ action_type: 'gcp.storage.bucket_delete', bucket: p.bucket }),
|
|
63
|
+
perform: (c, p) => c.deleteBucket({ bucket: p.bucket }),
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const adapter = createAdapter({ system: 'gcp', ops: OPS });
|
|
68
|
+
export const GCP_OPS = adapter.OPS;
|
|
69
|
+
export function createGcpManifest(extraActions = []) { return manifestFromPack(GCP_ACTION_PACK, extraActions); }
|
|
70
|
+
export function guardGcpMutation(gate, client, args) { return adapter.guard(gate, client, args); }
|
|
71
|
+
export default { GCP_ACTION_PACK, GCP_OPS, createGcpManifest, guardGcpMutation };
|