@emilia-protocol/gate 0.9.5 → 0.10.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 +70 -0
- package/LICENSE +190 -0
- package/README.md +75 -16
- package/action-control-manifest.js +26 -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 +25 -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 +86 -0
- package/witness-postgres.js +97 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<!-- SPDX-License-Identifier: Apache-2.0 -->
|
|
2
2
|
|
|
3
|
-
# EMILIA Gate —
|
|
3
|
+
# EMILIA Gate — deprecated Terraform module (`EP-GATE-TF-v1`)
|
|
4
4
|
|
|
5
5
|
Terraform sibling of the Helm chart (`../helm`, `EP-GATE-HELM-v1`) for BYOC
|
|
6
6
|
(bring-your-own-cloud) installs of the Trusted Action Firewall. Same container
|
|
@@ -13,6 +13,10 @@ in a cluster **you** control:
|
|
|
13
13
|
| `kubernetes_deployment_v1.gate` | The gate pods — non-root, read-only rootfs, no privilege escalation, all capabilities dropped, no service-account token; pinned issuer keys arrive via a non-optional `secretKeyRef` to **your** Secret |
|
|
14
14
|
| `kubernetes_service_v1.gate` | Cluster-internal Service (ClusterIP by default) in front of the pods |
|
|
15
15
|
|
|
16
|
+
**Deprecated:** this legacy module may run per-process in-memory consumption and
|
|
17
|
+
evidence state. New deployments should use `./service`, which targets
|
|
18
|
+
`apps/gate-service` and requires durable operator adapters.
|
|
19
|
+
|
|
16
20
|
**Honest framing:** this is a *reference module* and it is *experimental*. It
|
|
17
21
|
is a starting point for your platform team to review, fork, and own — not a
|
|
18
22
|
managed service, not a turnkey production install. The deployer's cluster, the
|
|
@@ -57,8 +61,9 @@ module "emilia_gate" {
|
|
|
57
61
|
namespace = "emilia" # must already exist
|
|
58
62
|
image = "ghcr.io/your-org/emilia-gate@sha256:..." # pin a digest
|
|
59
63
|
|
|
60
|
-
replicas =
|
|
64
|
+
replicas = 1
|
|
61
65
|
issuer_keys_secret_name = "emilia-gate-issuer-keys" # NAME only, never keys
|
|
66
|
+
github_token_secret_name = "emilia-gate-github"
|
|
62
67
|
|
|
63
68
|
# The deny-by-default policy the gate enforces (EP-ACTION-RISK-MANIFEST).
|
|
64
69
|
manifest_json = file("${path.module}/manifest.json")
|
|
@@ -85,9 +90,11 @@ policy change rolls the pods.
|
|
|
85
90
|
| `EP_GATE_MANIFEST_PATH` | ConfigMap mount | `/etc/emilia-gate/action-risk-manifest.json` |
|
|
86
91
|
| `EP_GATE_METRICS_ENABLED` | `metrics_enabled` | `false` |
|
|
87
92
|
| `EP_GATE_ISSUER_KEYS` | `secretKeyRef` → your existing Secret | — (required) |
|
|
93
|
+
| `GITHUB_TOKEN` | `github_token_secret_name` → existing Secret | — (optional) |
|
|
88
94
|
|
|
89
95
|
Extra plain-text env goes in `extra_env` — **never secrets** (values in that
|
|
90
|
-
map land in Terraform state)
|
|
96
|
+
map land in Terraform state). Use `secret_env` for generic non-optional
|
|
97
|
+
`secretKeyRef` entries; the module accepts Secret names/keys, never values.
|
|
91
98
|
|
|
92
99
|
## Inputs
|
|
93
100
|
|
|
@@ -99,7 +106,10 @@ map land in Terraform state); wire secret env from your own Secrets.
|
|
|
99
106
|
| `issuer_keys_secret_key` | `issuer-keys.json` | Key inside that Secret |
|
|
100
107
|
| `name` | `emilia-gate` | DNS-1123 label |
|
|
101
108
|
| `namespace` | `default` | Must already exist |
|
|
102
|
-
| `replicas` | `
|
|
109
|
+
| `replicas` | `1` | Values above one require both shared backend references |
|
|
110
|
+
| `shared_consumption_backend`, `shared_evidence_backend` | `null` | Secret-backed adapter environment references required above one replica |
|
|
111
|
+
| `github_token_secret_name` | `null` | Existing GitHub token Secret reference |
|
|
112
|
+
| `secret_env` | `{}` | Generic environment-to-existing-Secret references |
|
|
103
113
|
| `port` / `service_port` | `8080` / `8080` | |
|
|
104
114
|
| `service_type` | `ClusterIP` | Anything more exposed is your explicit call |
|
|
105
115
|
| `log_level` | `info` | `error` \| `warn` \| `info` \| `debug` |
|
|
@@ -116,12 +126,11 @@ Outputs: `service_name`, `namespace`, `service_endpoint`, `deployment_name`,
|
|
|
116
126
|
|
|
117
127
|
## Operational notes
|
|
118
128
|
|
|
119
|
-
- **Replay defense across replicas:**
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
`extra_env`) is your configuration responsibility.
|
|
129
|
+
- **Replay defense across replicas:** the module refuses `replicas > 1` unless
|
|
130
|
+
both `shared_consumption_backend` and `shared_evidence_backend` provide
|
|
131
|
+
complete Secret-backed environment references. That proves wiring exists,
|
|
132
|
+
not that a custom legacy image implements the required atomic adapters;
|
|
133
|
+
prefer the service module.
|
|
125
134
|
- **Namespace:** not created by this module — pass one that exists.
|
|
126
135
|
- **Ingress/TLS/NetworkPolicy/ServiceMonitor:** intentionally out of scope.
|
|
127
136
|
The default posture is cluster-internal; exposure decisions belong to the
|
|
@@ -129,10 +138,11 @@ Outputs: `service_name`, `namespace`, `service_endpoint`, `deployment_name`,
|
|
|
129
138
|
|
|
130
139
|
## What has been validated
|
|
131
140
|
|
|
132
|
-
`terraform
|
|
133
|
-
|
|
141
|
+
`packages/gate/deploy/terraform/tests/validate.sh` runs formatting, provider
|
|
142
|
+
schema validation, and mocked plan tests that cover the one-replica default,
|
|
143
|
+
multi-replica refusal, and Secret-backed environment rendering. It uses
|
|
144
|
+
Terraform 1.9.8 with
|
|
134
145
|
`hashicorp/kubernetes` 2.38. A create-only `terraform plan` renders all three
|
|
135
|
-
resources, and the plan-time input validations
|
|
136
|
-
key material, zero replicas) refuse as designed. The module has **not** been
|
|
146
|
+
resources, and the plan-time input validations refuse unsafe scaling. The module has **not** been
|
|
137
147
|
applied against a live cluster as part of this repo's CI — treat it as
|
|
138
148
|
reviewed reference code, not a certified install path.
|
package/deploy/terraform/main.tf
CHANGED
|
@@ -35,6 +35,8 @@ locals {
|
|
|
35
35
|
"app.kubernetes.io/part-of" = "emilia-protocol"
|
|
36
36
|
"emiliaprotocol.ai/module-contract" = local.module_version
|
|
37
37
|
"emiliaprotocol.ai/maturity" = "experimental"
|
|
38
|
+
"emiliaprotocol.ai/deprecated" = "true"
|
|
39
|
+
"emiliaprotocol.ai/replacement" = "emilia-gate-service"
|
|
38
40
|
}, var.extra_labels)
|
|
39
41
|
|
|
40
42
|
selector_labels = {
|
|
@@ -45,6 +47,34 @@ locals {
|
|
|
45
47
|
# Same paths as the Helm chart's container contract.
|
|
46
48
|
manifest_mount_dir = "/etc/emilia-gate"
|
|
47
49
|
manifest_file = "action-risk-manifest.json"
|
|
50
|
+
|
|
51
|
+
secret_env_references = concat(
|
|
52
|
+
var.shared_consumption_backend == null ? [] : [var.shared_consumption_backend],
|
|
53
|
+
var.shared_evidence_backend == null ? [] : [var.shared_evidence_backend],
|
|
54
|
+
var.github_token_secret_name == null ? [] : [{
|
|
55
|
+
env_name = var.github_token_env_name
|
|
56
|
+
secret_name = var.github_token_secret_name
|
|
57
|
+
secret_key = var.github_token_secret_key
|
|
58
|
+
}],
|
|
59
|
+
[for env_name, reference in var.secret_env : {
|
|
60
|
+
env_name = env_name
|
|
61
|
+
secret_name = reference.secret_name
|
|
62
|
+
secret_key = reference.secret_key
|
|
63
|
+
}],
|
|
64
|
+
)
|
|
65
|
+
configurable_env_names = concat(
|
|
66
|
+
[for reference in local.secret_env_references : reference.env_name],
|
|
67
|
+
keys(var.extra_env),
|
|
68
|
+
)
|
|
69
|
+
reserved_env_names = toset([
|
|
70
|
+
"NODE_ENV",
|
|
71
|
+
"EP_GATE_PORT",
|
|
72
|
+
"EP_GATE_LOG_LEVEL",
|
|
73
|
+
"EP_GATE_EVIDENCE_STRICT",
|
|
74
|
+
"EP_GATE_MANIFEST_PATH",
|
|
75
|
+
"EP_GATE_METRICS_ENABLED",
|
|
76
|
+
"EP_GATE_ISSUER_KEYS",
|
|
77
|
+
])
|
|
48
78
|
}
|
|
49
79
|
|
|
50
80
|
# The policy the gate enforces. Plain ConfigMap: the manifest is deny-by-default
|
|
@@ -156,6 +186,20 @@ resource "kubernetes_deployment_v1" "gate" {
|
|
|
156
186
|
}
|
|
157
187
|
}
|
|
158
188
|
|
|
189
|
+
dynamic "env" {
|
|
190
|
+
for_each = { for index, reference in local.secret_env_references : tostring(index) => reference }
|
|
191
|
+
content {
|
|
192
|
+
name = env.value.env_name
|
|
193
|
+
value_from {
|
|
194
|
+
secret_key_ref {
|
|
195
|
+
name = env.value.secret_name
|
|
196
|
+
key = env.value.secret_key
|
|
197
|
+
optional = false
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
159
203
|
dynamic "env" {
|
|
160
204
|
for_each = var.extra_env
|
|
161
205
|
content {
|
|
@@ -233,6 +277,21 @@ resource "kubernetes_deployment_v1" "gate" {
|
|
|
233
277
|
}
|
|
234
278
|
}
|
|
235
279
|
}
|
|
280
|
+
|
|
281
|
+
lifecycle {
|
|
282
|
+
precondition {
|
|
283
|
+
condition = var.replicas == 1 || (var.shared_consumption_backend != null && var.shared_evidence_backend != null)
|
|
284
|
+
error_message = "The deprecated legacy module refuses replicas > 1 without both shared_consumption_backend and shared_evidence_backend Secret references. Prefer terraform/service."
|
|
285
|
+
}
|
|
286
|
+
precondition {
|
|
287
|
+
condition = length(distinct(local.configurable_env_names)) == length(local.configurable_env_names)
|
|
288
|
+
error_message = "Secret-backed and literal environment variables must not use duplicate names."
|
|
289
|
+
}
|
|
290
|
+
precondition {
|
|
291
|
+
condition = length(setintersection(toset(local.configurable_env_names), local.reserved_env_names)) == 0
|
|
292
|
+
error_message = "secret_env and extra_env must not override module-managed environment variables."
|
|
293
|
+
}
|
|
294
|
+
}
|
|
236
295
|
}
|
|
237
296
|
|
|
238
297
|
resource "kubernetes_service_v1" "gate" {
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# EMILIA Gate service Terraform module
|
|
2
|
+
|
|
3
|
+
This Kubernetes module deploys the BYOC image built from `Dockerfile.gate`. It
|
|
4
|
+
does not publish, default, or make a claim about an official EMILIA image.
|
|
5
|
+
|
|
6
|
+
The module creates a dedicated token-free ServiceAccount, migration Job,
|
|
7
|
+
two-replica Deployment, ClusterIP Service, PDB, and additive default-deny
|
|
8
|
+
NetworkPolicies. The migration Job is network-restricted, waits to complete,
|
|
9
|
+
and gates Deployment creation. Its immutable name includes the image, command,
|
|
10
|
+
and `migration_revision`; bump the revision when migration inputs change
|
|
11
|
+
without changing the image.
|
|
12
|
+
|
|
13
|
+
Only existing Secret names and keys enter Terraform. The operator config,
|
|
14
|
+
Postgres URL, Gate API token, and issuer roots are read at pod start with
|
|
15
|
+
non-optional references. Their values are not module variables and therefore
|
|
16
|
+
are not written to Terraform state by this module. The configuration Secret
|
|
17
|
+
must contain `gate.config.mjs` and `migrate.mjs`; these remain operator-owned
|
|
18
|
+
because `apps/gate-service` defines durable adapter contracts rather than
|
|
19
|
+
shipping an unsafe generic production fallback.
|
|
20
|
+
|
|
21
|
+
Set `migration_postgres_secret_name` and `migration_postgres_secret_key` to a
|
|
22
|
+
separate DDL-capable login Secret. Migrations enabled with a missing Secret or
|
|
23
|
+
the runtime Secret name are rejected; there is no fallback. The module cannot
|
|
24
|
+
compare Secret contents, so provision genuinely distinct credentials. The
|
|
25
|
+
long-lived service should use a least-privilege role that cannot alter schema.
|
|
26
|
+
|
|
27
|
+
## Example
|
|
28
|
+
|
|
29
|
+
```hcl
|
|
30
|
+
module "emilia_gate" {
|
|
31
|
+
source = "./packages/gate/deploy/terraform/service"
|
|
32
|
+
|
|
33
|
+
namespace = "emilia-gate"
|
|
34
|
+
image = "registry.example.com/security/emilia-gate-service@sha256:REPLACE"
|
|
35
|
+
|
|
36
|
+
configuration_secret_name = "emilia-gate-configuration"
|
|
37
|
+
postgres_secret_name = "emilia-gate-postgres"
|
|
38
|
+
migration_postgres_secret_name = "emilia-gate-postgres-migrate"
|
|
39
|
+
migration_postgres_secret_key = "database-url"
|
|
40
|
+
api_token_secret_name = "emilia-gate-api-token"
|
|
41
|
+
issuer_roots_secret_name = "emilia-gate-issuer-roots"
|
|
42
|
+
github_token_secret_name = "emilia-gate-github"
|
|
43
|
+
|
|
44
|
+
secret_env = {
|
|
45
|
+
SIEM_TOKEN = {
|
|
46
|
+
secret_name = "emilia-gate-siem"
|
|
47
|
+
secret_key = "token"
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
# For managed Postgres, disable the in-cluster selector and allow only the
|
|
52
|
+
# stable database endpoint or egress-proxy CIDR.
|
|
53
|
+
postgres_pod_labels = {}
|
|
54
|
+
postgres_egress_cidrs = ["10.40.12.8/32"]
|
|
55
|
+
|
|
56
|
+
# Standard NetworkPolicy cannot select FQDNs. Prefer stable egress proxies
|
|
57
|
+
# or an FQDN-aware CNI policy for KMS, GitHub, and SaaS SIEM endpoints.
|
|
58
|
+
kms_egress_cidrs = ["10.40.20.10/32"]
|
|
59
|
+
github_egress_cidrs = ["10.40.20.11/32"]
|
|
60
|
+
siem_egress_cidrs = ["10.40.20.12/32"]
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Configure the `kubernetes` provider in the calling root module. Create the
|
|
65
|
+
namespace and all Secrets outside this module. GitHub and generic secret-backed
|
|
66
|
+
environment inputs render only non-optional `secretKeyRef` metadata; Secret
|
|
67
|
+
values never become variables, Deployment literals, or module-managed state.
|
|
68
|
+
Prefer an immutable image digest
|
|
69
|
+
and a remote Terraform state backend with encryption and access logging even
|
|
70
|
+
though this module stores Secret references only.
|
|
71
|
+
|
|
72
|
+
## Clusterless validation
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
packages/gate/deploy/terraform/service/tests/validate.sh
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
The script runs formatting checks, initializes the Kubernetes provider schema
|
|
79
|
+
in a temporary directory, runs `terraform validate`, and executes mocked plan
|
|
80
|
+
tests for migration credential separation and Secret-backed environment wiring.
|
|
81
|
+
It does not configure credentials or contact a Kubernetes cluster.
|