@emilia-protocol/gate 0.9.5 → 0.11.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 +103 -0
- package/LICENSE +190 -0
- package/README.md +95 -16
- package/action-control-manifest.js +26 -0
- package/action-escrow-custodian.js +395 -0
- package/action-escrow-evidence.js +859 -0
- package/action-escrow-package.js +1669 -0
- package/action-escrow-postgres.js +338 -0
- package/action-escrow-state.js +397 -0
- package/action-escrow-verifiers.js +332 -0
- package/action-escrow.js +2448 -0
- package/adapters/_kit.js +47 -5
- package/adapters/aws.js +15 -4
- package/adapters/github-demo.mjs +25 -22
- package/adapters/github.js +1 -1
- package/adapters/jira.js +1 -0
- package/adapters/linear.js +1 -0
- package/adapters/salesforce.js +1 -0
- package/adapters/stripe.js +1 -1
- package/adapters/supabase.js +26 -4
- package/adapters/vercel.js +33 -4
- package/aec-execution.js +1 -3
- package/breakglass.js +285 -51
- package/control-plane.js +341 -0
- package/coverage.js +722 -0
- package/custody-demo.mjs +13 -3
- package/demo.mjs +9 -3
- package/deploy/helm/README.md +16 -8
- package/deploy/helm/emilia-gate/Chart.yaml +3 -1
- package/deploy/helm/emilia-gate/templates/NOTES.txt +3 -2
- package/deploy/helm/emilia-gate/templates/deployment.yaml +55 -1
- package/deploy/helm/emilia-gate/values.yaml +18 -2
- package/deploy/helm/emilia-gate-service/Chart.yaml +11 -0
- package/deploy/helm/emilia-gate-service/README.md +81 -0
- package/deploy/helm/emilia-gate-service/templates/NOTES.txt +12 -0
- package/deploy/helm/emilia-gate-service/templates/_helpers.tpl +83 -0
- package/deploy/helm/emilia-gate-service/templates/deployment.yaml +153 -0
- package/deploy/helm/emilia-gate-service/templates/migration-job.yaml +73 -0
- package/deploy/helm/emilia-gate-service/templates/networkpolicy.yaml +113 -0
- package/deploy/helm/emilia-gate-service/templates/pdb.yaml +14 -0
- package/deploy/helm/emilia-gate-service/templates/service.yaml +20 -0
- package/deploy/helm/emilia-gate-service/templates/serviceaccount.yaml +8 -0
- package/deploy/helm/emilia-gate-service/tests/fixtures/001_gate.sql +26 -0
- package/deploy/helm/emilia-gate-service/tests/fixtures/002_runtime_access.sql +32 -0
- package/deploy/helm/emilia-gate-service/tests/fixtures/gate.config.mjs +29 -0
- package/deploy/helm/emilia-gate-service/tests/render-check.sh +145 -0
- package/deploy/helm/emilia-gate-service/values.schema.json +145 -0
- package/deploy/helm/emilia-gate-service/values.yaml +166 -0
- package/deploy/sql/001-runtime.sql +707 -0
- package/deploy/terraform/README.md +24 -14
- package/deploy/terraform/main.tf +59 -0
- package/deploy/terraform/service/README.md +81 -0
- package/deploy/terraform/service/main.tf +718 -0
- package/deploy/terraform/service/outputs.tf +19 -0
- package/deploy/terraform/service/tests/validate.sh +24 -0
- package/deploy/terraform/service/tests/validation.tftest.hcl +168 -0
- package/deploy/terraform/service/variables.tf +459 -0
- package/deploy/terraform/service/versions.tf +10 -0
- package/deploy/terraform/variables.tf +95 -2
- package/deployment-attestation.js +248 -0
- package/eg1-conformance.js +46 -12
- package/enterprise.js +6 -2
- package/ep-assure.mjs +3 -2
- package/evidence-postgres.js +357 -0
- package/evidence.js +10 -3
- package/execution-binding.js +141 -26
- package/index.js +556 -115
- package/key-registry.js +51 -19
- package/mcp.js +4 -2
- package/network-witness.js +500 -0
- package/package.json +39 -5
- package/reliance-kernel.js +5 -6
- package/reliance-packet.js +43 -10
- package/reports/assurance-package.js +45 -19
- package/reports/reperform.js +78 -18
- package/reports/underwriter.js +1 -1
- package/settlement.js +300 -0
- package/store-postgres.js +14 -0
- package/store.js +26 -5
- package/strict-json.js +103 -0
- package/witness-postgres.js +97 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
<!-- SPDX-License-Identifier: Apache-2.0 -->
|
|
2
|
+
# Changelog
|
|
3
|
+
|
|
4
|
+
All notable changes to `@emilia-protocol/gate` are documented here.
|
|
5
|
+
This package follows [Semantic Versioning](https://semver.org/).
|
|
6
|
+
|
|
7
|
+
## 0.11.0 (2026-07-17)
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- Action Escrow modules for exact document/action binding, evidence
|
|
12
|
+
verification, a signed lifecycle state machine, durable Postgres state and
|
|
13
|
+
journal storage, licensed-custodian adapters, portable assurance packages,
|
|
14
|
+
and fail-closed release enforcement.
|
|
15
|
+
- Public package exports for `action-escrow`, `action-escrow-state`,
|
|
16
|
+
`action-escrow-postgres`, `action-escrow-custodian`,
|
|
17
|
+
`action-escrow-package`, and `action-escrow-verifiers`.
|
|
18
|
+
|
|
19
|
+
### Security
|
|
20
|
+
|
|
21
|
+
- Release requires exact profile, party, final-document, material-term,
|
|
22
|
+
funding, milestone, action, and approval binding under relying-party-pinned
|
|
23
|
+
policy.
|
|
24
|
+
- Release approvals are fresh and action-specific, release is consumed once,
|
|
25
|
+
storage failure refuses, and an ambiguous provider effect enters
|
|
26
|
+
reconciliation instead of being retried.
|
|
27
|
+
- Release approvals now use the canonical `EP-RESOLUTION-v1` binding-moment
|
|
28
|
+
hash, relying-party-pinned option mapping, initiator, per-party nonce, and
|
|
29
|
+
evaluation time. The reference scenario uses real WebAuthn-shaped P-256
|
|
30
|
+
signatures rather than a resolution-like demo envelope.
|
|
31
|
+
- Runtime roles cannot also act as contract parties. Provider and effect
|
|
32
|
+
references are fenced to prevent substitution across actions or sessions.
|
|
33
|
+
|
|
34
|
+
### Distribution
|
|
35
|
+
|
|
36
|
+
- Gate now depends on `@emilia-protocol/verify` 3.11.0 and
|
|
37
|
+
`@emilia-protocol/require-receipt` 0.6.1. All shipped imports remain within
|
|
38
|
+
declared package boundaries.
|
|
39
|
+
|
|
40
|
+
## 0.10.0 (2026-07-16)
|
|
41
|
+
|
|
42
|
+
### Added
|
|
43
|
+
|
|
44
|
+
- The EMILIA Gate consequence-control plane, including action coverage,
|
|
45
|
+
settlement, metering, deployment-attestation, network-witness, SIEM, and
|
|
46
|
+
control-plane modules.
|
|
47
|
+
- A BYOC GitHub repository-deletion service with complete mediation, strict
|
|
48
|
+
receipt ingress, durable Postgres action/consumption/evidence state,
|
|
49
|
+
authenticated evidence reads, bounded readiness, graceful shutdown, and
|
|
50
|
+
fail-closed recovery of interrupted effects.
|
|
51
|
+
- Helm, Terraform, Docker Compose, and SQL deployment assets for the BYOC
|
|
52
|
+
service. Production assets require explicit non-latest images, separate
|
|
53
|
+
runtime and migration credentials, and operator-owned trust configuration.
|
|
54
|
+
|
|
55
|
+
### Security
|
|
56
|
+
|
|
57
|
+
- Pinned issuer, approver, policy, actuator, meter, attestation, and
|
|
58
|
+
network-witness trust roots are kept outside presenter-controlled evidence.
|
|
59
|
+
- Signed negative human decisions remain durable evidence but cannot satisfy
|
|
60
|
+
authorization, signer, assurance, authority, quorum, or action-material
|
|
61
|
+
predicates.
|
|
62
|
+
- Mobile approval and denial evidence is bound to the exact action, profile,
|
|
63
|
+
presentation, app, device enrollment, RP, origin, and single-use challenge.
|
|
64
|
+
- A same-sequence network-witness conflict permanently poisons that exact
|
|
65
|
+
witness/capture-point stream. Higher sequence numbers cannot restore trust;
|
|
66
|
+
recovery requires an explicitly provisioned replacement stream identity.
|
|
67
|
+
- Ambiguous external effects burn their receipt and become `indeterminate`;
|
|
68
|
+
Gate never retries a consequential effect whose outcome is unknown.
|
|
69
|
+
|
|
70
|
+
### Distribution
|
|
71
|
+
|
|
72
|
+
- Gate now declares the exact `@emilia-protocol/require-receipt` and
|
|
73
|
+
`@emilia-protocol/verify` release bytes it imports. The verifier floor is
|
|
74
|
+
`3.10.1`, which includes the signed-denial authorization fix.
|
|
75
|
+
- The npm package now carries this changelog and the Apache-2.0 license text.
|
|
76
|
+
|
|
77
|
+
## 0.9.2 (2026-07-06)
|
|
78
|
+
|
|
79
|
+
### Added
|
|
80
|
+
`EP-EXTERNAL-VERIFICATION-STATEMENT-v1` (`./reports/external-verification`): the
|
|
81
|
+
artifact a non-EMILIA verifier signs after checking EP evidence. It records a
|
|
82
|
+
procedure, inputs, result, and limitations under the verifier's own Ed25519 key,
|
|
83
|
+
and is accepted only by a relying party pinning that key together with the
|
|
84
|
+
verifier identity out of band. It does not authorize an action or certify
|
|
85
|
+
correctness. A turnkey harness for issuing one over a conformance run lives in
|
|
86
|
+
`examples/external-verification/`.
|
|
87
|
+
|
|
88
|
+
### Fixed
|
|
89
|
+
`./reports/external-verification` imported `canonicalize` from outside the
|
|
90
|
+
package root, which made the published tarball unloadable
|
|
91
|
+
(`ERR_MODULE_NOT_FOUND`) for every consumer, including the package main entry.
|
|
92
|
+
It now imports the byte-identical in-package `canonicalize`. A new
|
|
93
|
+
`package-boundary` test fails closed if any shipped module ever again resolves a
|
|
94
|
+
relative import outside the package root.
|
|
95
|
+
|
|
96
|
+
### Security
|
|
97
|
+
Verification hardening (fail-closed): a pin must name the `verifier_id` it
|
|
98
|
+
vouches for, so a pinned key can never validate a different claimed identity
|
|
99
|
+
(`pin_missing_or_mismatched_verifier_id`); `key_id` is derived from the carried
|
|
100
|
+
public key and a mismatched envelope `key_id` is refused (`key_id_mismatch`),
|
|
101
|
+
since the envelope is outside the signed bytes. Default statement limitations now
|
|
102
|
+
disclose that a statement carries no expiry and no consumer binding, is
|
|
103
|
+
replayable verbatim, and that `generated_at` is signer-asserted, not verified.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
6
|
+
|
|
7
|
+
1. Definitions.
|
|
8
|
+
|
|
9
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
10
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
11
|
+
|
|
12
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
13
|
+
the copyright owner that is granting the License.
|
|
14
|
+
|
|
15
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
16
|
+
other entities that control, are controlled by, or are under common
|
|
17
|
+
control with that entity. For the purposes of this definition,
|
|
18
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
19
|
+
direction or management of such entity, whether by contract or
|
|
20
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
21
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
22
|
+
|
|
23
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
24
|
+
exercising permissions granted by this License.
|
|
25
|
+
|
|
26
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
27
|
+
including but not limited to software source code, documentation
|
|
28
|
+
source, and configuration files.
|
|
29
|
+
|
|
30
|
+
"Object" form shall mean any form resulting from mechanical
|
|
31
|
+
transformation or translation of a Source form, including but
|
|
32
|
+
not limited to compiled object code, generated documentation,
|
|
33
|
+
and conversions to other media types.
|
|
34
|
+
|
|
35
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
36
|
+
Object form, made available under the License, as indicated by a
|
|
37
|
+
copyright notice that is included in or attached to the work
|
|
38
|
+
(an example is provided in the Appendix below).
|
|
39
|
+
|
|
40
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
41
|
+
form, that is based on (or derived from) the Work and for which the
|
|
42
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
43
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
44
|
+
of this License, Derivative Works shall not include works that remain
|
|
45
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
46
|
+
the Work and Derivative Works thereof.
|
|
47
|
+
|
|
48
|
+
"Contribution" shall mean any work of authorship, including
|
|
49
|
+
the original version of the Work and any modifications or additions
|
|
50
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
51
|
+
submitted to the Licensor for inclusion in the Work by the copyright owner
|
|
52
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
53
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
54
|
+
means any form of electronic, verbal, or written communication sent
|
|
55
|
+
to the Licensor or its representatives, including but not limited to
|
|
56
|
+
communication on electronic mailing lists, source code control systems,
|
|
57
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
58
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
59
|
+
excluding communication that is conspicuously marked or otherwise
|
|
60
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
61
|
+
|
|
62
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
63
|
+
on behalf of whom a Contribution has been received by the Licensor and
|
|
64
|
+
subsequently incorporated within the Work.
|
|
65
|
+
|
|
66
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
67
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
68
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
69
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
70
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
71
|
+
Work and such Derivative Works in Source or Object form.
|
|
72
|
+
|
|
73
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
74
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
75
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
76
|
+
(except as stated in this section) patent license to make, have made,
|
|
77
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
78
|
+
where such license applies only to those patent claims licensable
|
|
79
|
+
by such Contributor that are necessarily infringed by their
|
|
80
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
81
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
82
|
+
institute patent litigation against any entity (including a
|
|
83
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
84
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
85
|
+
or contributory patent infringement, then any patent licenses
|
|
86
|
+
granted to You under this License for that Work shall terminate
|
|
87
|
+
as of the date such litigation is filed.
|
|
88
|
+
|
|
89
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
90
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
91
|
+
modifications, and in Source or Object form, provided that You
|
|
92
|
+
meet the following conditions:
|
|
93
|
+
|
|
94
|
+
(a) You must give any other recipients of the Work or
|
|
95
|
+
Derivative Works a copy of this License; and
|
|
96
|
+
|
|
97
|
+
(b) You must cause any modified files to carry prominent notices
|
|
98
|
+
stating that You changed the files; and
|
|
99
|
+
|
|
100
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
101
|
+
that You distribute, all copyright, patent, trademark, and
|
|
102
|
+
attribution notices from the Source form of the Work,
|
|
103
|
+
excluding those notices that do not pertain to any part of
|
|
104
|
+
the Derivative Works; and
|
|
105
|
+
|
|
106
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
107
|
+
distribution, then any Derivative Works that You distribute must
|
|
108
|
+
include a readable copy of the attribution notices contained
|
|
109
|
+
within such NOTICE file, excluding any notices that do not
|
|
110
|
+
pertain to any part of the Derivative Works, in at least one
|
|
111
|
+
of the following places: within a NOTICE text file distributed
|
|
112
|
+
as part of the Derivative Works; within the Source form or
|
|
113
|
+
documentation, if provided along with the Derivative Works; or,
|
|
114
|
+
within a display generated by the Derivative Works, if and
|
|
115
|
+
wherever such third-party notices normally appear. The contents
|
|
116
|
+
of the NOTICE file are for informational purposes only and
|
|
117
|
+
do not modify the License. You may add Your own attribution
|
|
118
|
+
notices within Derivative Works that You distribute, alongside
|
|
119
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
120
|
+
that such additional attribution notices cannot be construed
|
|
121
|
+
as modifying the License.
|
|
122
|
+
|
|
123
|
+
You may add Your own copyright statement to Your modifications and
|
|
124
|
+
may provide additional or different license terms and conditions
|
|
125
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
126
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
127
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
128
|
+
the conditions stated in this License.
|
|
129
|
+
|
|
130
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
131
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
132
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
133
|
+
this License, without any additional terms or conditions.
|
|
134
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
135
|
+
the terms of any separate license agreement you may have executed
|
|
136
|
+
with Licensor regarding such Contributions.
|
|
137
|
+
|
|
138
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
139
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
140
|
+
except as required for reasonable and customary use in describing the
|
|
141
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
142
|
+
|
|
143
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
144
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
145
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
146
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
147
|
+
implied, including, without limitation, any warranties or conditions
|
|
148
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
149
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
150
|
+
appropriateness of using or redistributing the Work and assume any
|
|
151
|
+
risks associated with Your exercise of permissions under this License.
|
|
152
|
+
|
|
153
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
154
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
155
|
+
unless required by applicable law (such as deliberate and grossly
|
|
156
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
157
|
+
liable to You for damages, including any direct, indirect, special,
|
|
158
|
+
incidental, or consequential damages of any character arising as a
|
|
159
|
+
result of this License or out of the use or inability to use the
|
|
160
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
161
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
162
|
+
other commercial damages or losses), even if such Contributor
|
|
163
|
+
has been advised of the possibility of such damages.
|
|
164
|
+
|
|
165
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
166
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
167
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
168
|
+
or other liability obligations and/or rights consistent with this
|
|
169
|
+
License. However, in accepting such obligations, You may act only
|
|
170
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
171
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
172
|
+
defend, and hold each Contributor harmless for any liability
|
|
173
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
174
|
+
of your accepting any such warranty or additional liability.
|
|
175
|
+
|
|
176
|
+
END OF TERMS AND CONDITIONS
|
|
177
|
+
|
|
178
|
+
Copyright 2024–2026 EMILIA Protocol, Inc. and contributors
|
|
179
|
+
|
|
180
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
181
|
+
you may not use this file except in compliance with the License.
|
|
182
|
+
You may obtain a copy of the License at
|
|
183
|
+
|
|
184
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
185
|
+
|
|
186
|
+
Unless required by applicable law or agreed to in writing, software
|
|
187
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
188
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
189
|
+
See the License for the specific language governing permissions and
|
|
190
|
+
limitations under the License.
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @emilia-protocol/gate — EMILIA Gate
|
|
2
2
|
|
|
3
|
-
**The
|
|
3
|
+
**The Consequence Firewall.** Deny-by-default enforcement for consequential machine actions.
|
|
4
4
|
|
|
5
5
|
> If an agent cannot produce a valid receipt, it cannot change money, code, permissions, data,
|
|
6
6
|
> infrastructure, energy, or physical state.
|
|
@@ -32,6 +32,7 @@ import { createTrustedActionFirewall } from '@emilia-protocol/gate';
|
|
|
32
32
|
|
|
33
33
|
const gate = createTrustedActionFirewall({
|
|
34
34
|
trustedKeys: [ISSUER_PUBKEY_B64U], // pin the issuers you trust
|
|
35
|
+
store: sharedConsumptionStore, // durable + ownership-fenced + permanent
|
|
35
36
|
maxAgeSec: 900,
|
|
36
37
|
});
|
|
37
38
|
|
|
@@ -58,6 +59,48 @@ if (!out.ok) throw out.body; // 428 Receipt Required
|
|
|
58
59
|
console.log(out.packet.verdict); // "rely"
|
|
59
60
|
```
|
|
60
61
|
|
|
62
|
+
## Three-plane deployment
|
|
63
|
+
|
|
64
|
+
High-consequence infrastructure separates three jobs instead of asking one
|
|
65
|
+
vendor or appliance to prove its own work:
|
|
66
|
+
|
|
67
|
+
1. **Enforcement plane** — an executor-side Gate returns 428 and does not call
|
|
68
|
+
the actuator until the pinned authorization profile is satisfied.
|
|
69
|
+
2. **Witness plane** — an independently pinned TAP, packet broker, or sensor
|
|
70
|
+
signs privacy-minimized observations. Observation never establishes that an
|
|
71
|
+
action was authorized, blocked, executed, or physically completed.
|
|
72
|
+
3. **Control plane** — a relying party pins the coverage inventory and
|
|
73
|
+
settlement profile, joins signed evidence by exact action digest, reports
|
|
74
|
+
`gated`, `witness_only`, `ungated`, `stale`, or `unknown`, and meters only
|
|
75
|
+
protected actions.
|
|
76
|
+
|
|
77
|
+
```js
|
|
78
|
+
import { evaluateGateControlPlane } from '@emilia-protocol/gate/control-plane';
|
|
79
|
+
|
|
80
|
+
const report = await evaluateGateControlPlane({
|
|
81
|
+
coverage: { deployments, probes, witnesses }, // presenter evidence only
|
|
82
|
+
settlements: [{ bundle }],
|
|
83
|
+
}, {
|
|
84
|
+
coverageInventory, // relying-party pinned
|
|
85
|
+
settlementProfile, // relying-party pinned
|
|
86
|
+
expectedProbeNonces, // current RP challenges, keyed by surface
|
|
87
|
+
attestationVerifiers,
|
|
88
|
+
pinnedProbes,
|
|
89
|
+
pinnedWitnesses,
|
|
90
|
+
witnessSequenceStore, // durable atomic stream checkpoint store
|
|
91
|
+
verifyAuthorization,
|
|
92
|
+
verifyExecution,
|
|
93
|
+
verifyOutcome,
|
|
94
|
+
});
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
The reference demonstration is `node examples/gate-control-plane/demo.mjs`.
|
|
98
|
+
It shows a complete view becoming `witness_only` and settlement-ineligible when
|
|
99
|
+
the Gate is removed while the network witness remains healthy.
|
|
100
|
+
Witness-dependent production decisions fail closed unless `witnessSequenceStore`
|
|
101
|
+
is durable or the relying party supplies a previously accepted durable witness
|
|
102
|
+
result through the explicit trusted-acceptance option.
|
|
103
|
+
|
|
61
104
|
## Default action packs
|
|
62
105
|
|
|
63
106
|
`createTrustedActionFirewall()` ships with high-risk defaults. These are category-based, not just
|
|
@@ -95,21 +138,21 @@ Use your own manifest when you need custom policy:
|
|
|
95
138
|
```js
|
|
96
139
|
import { createGate } from '@emilia-protocol/gate';
|
|
97
140
|
|
|
98
|
-
const gate = createGate({ manifest, trustedKeys: [ISSUER_PUBKEY_B64U] });
|
|
141
|
+
const gate = createGate({ manifest, trustedKeys: [ISSUER_PUBKEY_B64U], store: sharedConsumptionStore });
|
|
99
142
|
```
|
|
100
143
|
|
|
101
144
|
## Framework adapters
|
|
102
145
|
|
|
103
146
|
```js
|
|
104
|
-
// 1) Express / Connect
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
147
|
+
// 1) Express / Connect route wrapper. The handler is the effect callback;
|
|
148
|
+
// Gate owns reservation, execution, consumption, and evidence as one lifecycle.
|
|
149
|
+
app.post('/payments', gate.route(
|
|
150
|
+
async (req, res) => res.json(await releasePayment(req.paymentFromSystemOfRecord)),
|
|
151
|
+
{
|
|
108
152
|
selector: { protocol: 'http', method: 'POST', path: '/payments' },
|
|
109
153
|
observedAction: (req) => req.paymentFromSystemOfRecord,
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
);
|
|
154
|
+
},
|
|
155
|
+
));
|
|
113
156
|
|
|
114
157
|
// 2) Wrap any function
|
|
115
158
|
const release = gate.guard(reallyRelease, {
|
|
@@ -125,6 +168,11 @@ const release = gate.guard(reallyRelease, {
|
|
|
125
168
|
});
|
|
126
169
|
```
|
|
127
170
|
|
|
171
|
+
`gate.middleware()` is intentionally deprecated and always refuses: middleware
|
|
172
|
+
cannot prove that code after `next()` executed, so consuming a one-time receipt
|
|
173
|
+
there would create an authorization-without-effect ambiguity. Use
|
|
174
|
+
`gate.route()`, `gate.guard()`, or `gate.run()` for mutations.
|
|
175
|
+
|
|
128
176
|
## MCP drop-in
|
|
129
177
|
|
|
130
178
|
Agents live at the MCP tool-call boundary. One wrapper turns a dangerous tool into a
|
|
@@ -134,7 +182,7 @@ receipt-required one:
|
|
|
134
182
|
import { createTrustedActionFirewall } from '@emilia-protocol/gate';
|
|
135
183
|
import { gateMcpTool } from '@emilia-protocol/gate/mcp';
|
|
136
184
|
|
|
137
|
-
const gate = createTrustedActionFirewall({ trustedKeys: [ISSUER_PUBKEY_B64U] });
|
|
185
|
+
const gate = createTrustedActionFirewall({ trustedKeys: [ISSUER_PUBKEY_B64U], store: sharedConsumptionStore });
|
|
138
186
|
|
|
139
187
|
server.tool('release_payment', gateMcpTool(
|
|
140
188
|
gate,
|
|
@@ -156,7 +204,7 @@ mutating B). All share one fail-closed contract (`adapters/_kit.js`).
|
|
|
156
204
|
import { createGate } from '@emilia-protocol/gate';
|
|
157
205
|
import { createGithubManifest, guardGithubMutation } from '@emilia-protocol/gate/adapters/github';
|
|
158
206
|
|
|
159
|
-
const gate = createGate({ manifest: createGithubManifest(), trustedKeys: [ISSUER_PUBKEY_B64U] });
|
|
207
|
+
const gate = createGate({ manifest: createGithubManifest(), trustedKeys: [ISSUER_PUBKEY_B64U], store: sharedConsumptionStore });
|
|
160
208
|
await guardGithubMutation(gate, octokit, {
|
|
161
209
|
op: 'repo.delete', // | 'permission.change' | 'branch_protection.remove'
|
|
162
210
|
params: { owner: 'acme', repo: 'prod' },
|
|
@@ -173,7 +221,7 @@ await guardGithubMutation(gate, octokit, {
|
|
|
173
221
|
|
|
174
222
|
```js
|
|
175
223
|
import { createStripeManifest, guardStripeMutation } from '@emilia-protocol/gate/adapters/stripe';
|
|
176
|
-
const gate = createGate({ manifest: createStripeManifest(), trustedKeys: [ISSUER_PUBKEY_B64U] });
|
|
224
|
+
const gate = createGate({ manifest: createStripeManifest(), trustedKeys: [ISSUER_PUBKEY_B64U], store: sharedConsumptionStore });
|
|
177
225
|
await guardStripeMutation(gate, stripe, { op: 'payout.create', params: { amount: 40000, currency: 'usd', destination: 'acct_x' }, receipt });
|
|
178
226
|
// Supabase: guardSupabaseMutation(gate, db, { op: 'sql.destructive', params: { sql }, receipt }) // binds the exact statement
|
|
179
227
|
// AWS: guardAwsMutation(gate, client, { op: 'iam.attach_policy', params: { user, policy_arn }, receipt })
|
|
@@ -203,7 +251,13 @@ if it demonstrably passes all eight checks:
|
|
|
203
251
|
import { createTrustedActionFirewall, createEg1Harness, gateConformance } from '@emilia-protocol/gate';
|
|
204
252
|
|
|
205
253
|
const harness = createEg1Harness();
|
|
206
|
-
const gate = createTrustedActionFirewall({
|
|
254
|
+
const gate = createTrustedActionFirewall({
|
|
255
|
+
trustedKeys: [harness.publicKey],
|
|
256
|
+
approverKeys: harness.approverKeys,
|
|
257
|
+
rpId: harness.rpId,
|
|
258
|
+
allowedOrigins: harness.allowedOrigins,
|
|
259
|
+
allowEphemeralStore: true, // conformance fixture only
|
|
260
|
+
});
|
|
207
261
|
const report = await gateConformance({ gate, harness });
|
|
208
262
|
// report.passed === true; report.badge === 'EG-1 Enforced'
|
|
209
263
|
```
|
|
@@ -216,7 +270,7 @@ into a crisp claim: *"this PR makes `delete_row` earn EG-1."*
|
|
|
216
270
|
## What it adds over a bare verifier
|
|
217
271
|
|
|
218
272
|
`@emilia-protocol/require-receipt` already does manifest matching, offline verification, and the 428
|
|
219
|
-
challenge. The Gate composes that and adds the
|
|
273
|
+
challenge. The Gate composes that and adds the lifecycle controls a firewall needs:
|
|
220
274
|
|
|
221
275
|
- **Assurance tiers** — `software` < `class_a` (device signoff) < `quorum` (m-of-n). A `critical`
|
|
222
276
|
action can demand `class_a` or `quorum`; a lower-assurance receipt is refused (`assurance_too_low`).
|
|
@@ -225,7 +279,9 @@ challenge. The Gate composes that and adds the three things a firewall needs:
|
|
|
225
279
|
of every embedded device/quorum signature, use the EP §6.2 trust-receipt
|
|
226
280
|
verifier in `@emilia-protocol/verify`.
|
|
227
281
|
- **One-time consumption** — a receipt authorizes one action, once. Replays are refused
|
|
228
|
-
(`replay_refused`).
|
|
282
|
+
(`replay_refused`). Gate construction requires a durable, ownership-fenced, permanent store.
|
|
283
|
+
The process-local store is available only through explicit `allowEphemeralStore:true` for tests
|
|
284
|
+
and reference demos.
|
|
229
285
|
- **Evidence log** — the local logger hash-chains decisions and detects alteration when given its
|
|
230
286
|
complete process history. It is not a fleet ledger: a sink cannot prevent restart-from-genesis or
|
|
231
287
|
cross-replica forks. Safety-critical deployments use `createAtomicEvidenceLog()` over a durable
|
|
@@ -235,6 +291,29 @@ challenge. The Gate composes that and adds the three things a firewall needs:
|
|
|
235
291
|
closes "approved harmless X, executed dangerous Y."
|
|
236
292
|
- **Reliance packet** — `gate.reliancePacket()` turns the decision, execution receipt, field binding,
|
|
237
293
|
and evidence head into the compact artifact an auditor, insurer, or investigator can review.
|
|
294
|
+
- **Independent coverage evidence** — deployment attestation plus a separately pinned active probe
|
|
295
|
+
can establish a declared surface as `gated`; a passive network witness alone is always
|
|
296
|
+
`witness_only`. Inventory completeness remains an explicit relying-party assumption.
|
|
297
|
+
|
|
298
|
+
## Action Escrow
|
|
299
|
+
|
|
300
|
+
Action Escrow is the Gate profile for a two-party agreement whose downstream
|
|
301
|
+
release must obey the exact final document. The customer application supplies
|
|
302
|
+
the signed agreement, material terms, party acceptances, funding evidence,
|
|
303
|
+
milestone evidence, and action-specific release approvals. Gate verifies and
|
|
304
|
+
binds those inputs, advances a signed lifecycle, and consumes the release once.
|
|
305
|
+
Each release approval is a standard `EP-RESOLUTION-v1` WebAuthn record over a
|
|
306
|
+
canonical binding moment. Gate independently pins the approval option,
|
|
307
|
+
initiator, per-party nonce, evaluation time, exact action digest, and the
|
|
308
|
+
document and milestone-evidence digests rendered to the approver.
|
|
309
|
+
|
|
310
|
+
The public modules are `action-escrow`, `action-escrow-state`,
|
|
311
|
+
`action-escrow-postgres`, `action-escrow-custodian`,
|
|
312
|
+
`action-escrow-package`, and `action-escrow-verifiers`. A licensed external
|
|
313
|
+
provider holds or moves funds; EMILIA does not take custody, inspect work,
|
|
314
|
+
adjudicate disputes, or make an agreement legally enforceable. An ambiguous
|
|
315
|
+
provider outcome enters reconciliation and is never retried as though nothing
|
|
316
|
+
happened.
|
|
238
317
|
|
|
239
318
|
## Production custody
|
|
240
319
|
|
|
@@ -265,7 +344,7 @@ const registry = createKeyRegistry([
|
|
|
265
344
|
{ kid: 'issuer-1', key: KEY1 },
|
|
266
345
|
{ kid: 'issuer-2', key: KEY2, not_before: '2026-07-01T00:00:00Z' }, // rotation window
|
|
267
346
|
]);
|
|
268
|
-
const gate = createGate({ manifest, keyRegistry: registry });
|
|
347
|
+
const gate = createGate({ manifest, keyRegistry: registry, store: sharedConsumptionStore });
|
|
269
348
|
registry.revoke('issuer-1'); // compromised — refused immediately, live, no redeploy
|
|
270
349
|
```
|
|
271
350
|
|
|
@@ -119,6 +119,9 @@ export function toActionControl(action) {
|
|
|
119
119
|
},
|
|
120
120
|
};
|
|
121
121
|
if (action.quorum) out.quorum = cloneJson(action.quorum);
|
|
122
|
+
if (action.business_authorization || action.businessAuthorization) {
|
|
123
|
+
out.business_authorization = cloneJson(action.business_authorization || action.businessAuthorization);
|
|
124
|
+
}
|
|
122
125
|
return out;
|
|
123
126
|
}
|
|
124
127
|
|
|
@@ -224,6 +227,29 @@ export function validateActionControlManifest(manifest) {
|
|
|
224
227
|
if (control.evidence_output?.execution_attestation !== true) errors.push(`${prefix}.control.evidence_output.execution_attestation must be true`);
|
|
225
228
|
if (control.evidence_output?.reliance_packet !== true) errors.push(`${prefix}.control.evidence_output.reliance_packet must be true`);
|
|
226
229
|
if (action.conformance?.level !== ACTION_CONTROL_CONFORMANCE_LEVEL) errors.push(`${prefix}.conformance.level must be ${ACTION_CONTROL_CONFORMANCE_LEVEL}`);
|
|
230
|
+
if (action.business_authorization !== undefined) {
|
|
231
|
+
const business = action.business_authorization;
|
|
232
|
+
const policy = business?.policy;
|
|
233
|
+
const approvers = business?.allowed_approvers;
|
|
234
|
+
if (!business || typeof business !== 'object' || Array.isArray(business)) {
|
|
235
|
+
errors.push(`${prefix}.business_authorization must be an object`);
|
|
236
|
+
} else {
|
|
237
|
+
if (!policy || typeof policy !== 'object' || Array.isArray(policy)
|
|
238
|
+
|| typeof policy.id !== 'string' || !policy.id
|
|
239
|
+
|| typeof policy.hash !== 'string' || !policy.hash) {
|
|
240
|
+
errors.push(`${prefix}.business_authorization.policy must pin non-empty id and hash`);
|
|
241
|
+
}
|
|
242
|
+
if (typeof business.tenant_id !== 'string' || !business.tenant_id) {
|
|
243
|
+
errors.push(`${prefix}.business_authorization.tenant_id must be a non-empty string`);
|
|
244
|
+
}
|
|
245
|
+
if (!Array.isArray(approvers) || approvers.length === 0
|
|
246
|
+
|| approvers.some((entry) => !entry || typeof entry !== 'object'
|
|
247
|
+
|| typeof entry.subject !== 'string' || !entry.subject
|
|
248
|
+
|| typeof entry.role !== 'string' || !entry.role)) {
|
|
249
|
+
errors.push(`${prefix}.business_authorization.allowed_approvers must name subject and role`);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
227
253
|
}
|
|
228
254
|
}
|
|
229
255
|
return { ok: errors.length === 0, errors };
|