enigma-memory 0.1.10 → 0.1.12
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/README.md +38 -7
- package/apps/cli/bin/enigma.mjs +636 -49
- package/deploy/SIMULATION.md +152 -0
- package/deploy/docker-compose.local-production-simulation.yml +237 -0
- package/deploy/docker-compose.production.example.yml +19 -0
- package/deploy/kms-mock.mjs +64 -0
- package/deploy/nginx.local-production-simulation.conf +33 -0
- package/deploy/siem-mock.mjs +50 -0
- package/docs/benchmark-attestation-network.md +488 -0
- package/docs/benchmark-reproducibility.md +19 -2
- package/docs/blockchain-only-mechanisms.md +388 -0
- package/docs/demo-proof-network.md +275 -0
- package/docs/developer-ecosystem.md +62 -11
- package/docs/developer-proof-quickstart.md +325 -0
- package/docs/enigma-memory-ready-conformance.md +376 -0
- package/docs/enterprise-proof-control-plane.md +365 -0
- package/docs/market-category-narrative.md +398 -0
- package/docs/memory-drive-health-model.md +649 -0
- package/docs/memory-drive-strategy.md +458 -0
- package/docs/memory-passport-standard.md +445 -0
- package/docs/novelty-invention-candidates.md +161 -0
- package/docs/privacy-ledger-model.md +229 -0
- package/docs/proof-network-build-notes.md +240 -0
- package/docs/proof-network-claim-boundaries.md +318 -0
- package/docs/proof-network-dashboard-spec.md +773 -0
- package/docs/proof-network-glossary.md +27 -0
- package/docs/proof-network-launch-plan.md +421 -0
- package/docs/proof-network-operator-protocol.md +432 -0
- package/docs/proof-network-roadmap.md +431 -0
- package/docs/proof-network-test-plan.md +216 -0
- package/docs/proof-network-threat-model.md +373 -0
- package/docs/proof-network.md +257 -0
- package/docs/sdk-api.md +130 -10
- package/docs/solana-devnet-acceptance.md +226 -0
- package/docs/solana-proof-rail.md +453 -0
- package/examples/proof-network-anchor.json +37 -0
- package/examples/proof-network-attestation.json +35 -0
- package/examples/proof-network-grant.json +27 -0
- package/examples/proof-network-packet.json +71 -0
- package/package.json +40 -4
- package/packages/mcp-server/src/index.js +1 -1
- package/packages/proof-network/src/index.js +570 -0
- package/scripts/build-hosted-api-key-lifecycle.mjs +1 -1
- package/scripts/build-hosted-customer-lifecycle.mjs +1 -1
- package/scripts/build-installer-assets.mjs +1 -1
- package/scripts/build-proof-network-packet.mjs +213 -0
- package/scripts/run-standard-memory-benchmarks.mjs +1 -1
- package/scripts/simulate-production-env.mjs +210 -0
- package/scripts/wait-for-backend-ready.mjs +101 -0
- package/specs/goal-completion-audit-v1.schema.json +1 -0
- package/specs/proof-network-anchor-batch-v1.schema.json +125 -0
- package/specs/proof-network-benchmark-attestation-v1.schema.json +103 -0
- package/specs/proof-network-capability-grant-v1.schema.json +132 -0
- package/specs/proof-network-packet-v1.schema.json +171 -0
- package/scripts/install-enigma-local.mjs +0 -270
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# Enigma Memory — Local Production Simulation
|
|
2
|
+
|
|
3
|
+
**CLAIM BOUNDARY:** This is a `local-simulation` environment. It uses
|
|
4
|
+
self-signed TLS, bind-mounted file "secrets", a mocked KMS, and a mocked SIEM.
|
|
5
|
+
It is **not** a production deployment and must not be used as go-live evidence.
|
|
6
|
+
|
|
7
|
+
## Public-looking domain (local testing only)
|
|
8
|
+
|
|
9
|
+
The simulation is configured to answer on `sim.enigmamemory.com` so that the
|
|
10
|
+
hosted-backend live validator accepts the non-localhost HTTPS probe URLs. For
|
|
11
|
+
real go-live evidence the operator must point the chosen public domain at the
|
|
12
|
+
deployment's public IP address; the local simulation uses a hosts-file or local
|
|
13
|
+
DNS trick instead.
|
|
14
|
+
|
|
15
|
+
On the host running Docker, map the domain to the loopback interface:
|
|
16
|
+
|
|
17
|
+
```text
|
|
18
|
+
127.0.0.1 sim.enigmamemory.com relay.sim.enigmamemory.com gateway.sim.enigmamemory.com
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
On Linux/macOS add that line to `/etc/hosts`; on Windows add it to
|
|
22
|
+
`C:\Windows\System32\drivers\etc\hosts`. Then the following commands work from
|
|
23
|
+
the host:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
curl -k https://sim.enigmamemory.com:8443/readyz
|
|
27
|
+
curl -k https://sim.enigmamemory.com:9443/readyz
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
The tls-proxy service also declares `extra_hosts` entries for the same domain
|
|
31
|
+
names so that containers can resolve them locally when needed.
|
|
32
|
+
|
|
33
|
+
## Quick start
|
|
34
|
+
|
|
35
|
+
1. Generate secrets and a self-signed TLS certificate:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
node scripts/simulate-production-env.mjs
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Files are written to `deploy/secrets-simulation/` (gitignored).
|
|
42
|
+
|
|
43
|
+
2. Start the simulation:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
docker compose -f deploy/docker-compose.local-production-simulation.yml up --build -d
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
3. Wait for the backend to become ready:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
node scripts/wait-for-backend-ready.mjs
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
4. Inspect readiness over HTTPS:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
curl -k https://localhost:8443/readyz
|
|
59
|
+
curl -k https://localhost:9443/readyz
|
|
60
|
+
curl -k https://sim.enigmamemory.com:8443/readyz
|
|
61
|
+
curl -k https://sim.enigmamemory.com:9443/readyz
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Stop
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
docker compose -f deploy/docker-compose.local-production-simulation.yml down
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
To also remove the Postgres volume and mock event data:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
docker compose -f deploy/docker-compose.local-production-simulation.yml down -v
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Ports and routes
|
|
77
|
+
|
|
78
|
+
| Service | Public port | Internal port | Health route | Notes |
|
|
79
|
+
|--------|-------------|---------------|--------------|-------|
|
|
80
|
+
| relay | `8443` (HTTPS, loopback) | `8787` | `/readyz`, `/livez` | TLS terminated by `tls-proxy`; also answers on `sim.enigmamemory.com` and `relay.sim.enigmamemory.com` |
|
|
81
|
+
| gateway | `9443` (HTTPS, loopback) | `8797` | `/readyz`, `/livez` | TLS terminated by `tls-proxy`; also answers on `sim.enigmamemory.com` and `gateway.sim.enigmamemory.com` |
|
|
82
|
+
| postgres | not exposed | `5432` | — | Used as the simulated durable store |
|
|
83
|
+
| kms-mock | not exposed | `3000` | `/healthz` | Serves a generated Ed25519 key ref |
|
|
84
|
+
| siem-mock | not exposed | `3000` | `/healthz` | Accepts `POST /events`, writes minimized metadata to `/data/siem-events.jsonl` |
|
|
85
|
+
|
|
86
|
+
## Verify secret files
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
node scripts/simulate-production-env.mjs --check
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
This reports whether all required files in `deploy/secrets-simulation/` exist
|
|
93
|
+
and are non-empty.
|
|
94
|
+
|
|
95
|
+
## Simulation-only behavior
|
|
96
|
+
|
|
97
|
+
- `ENIGMA_OPERATOR_ACCEPTANCE_DECISION` is set to `go` so the readiness
|
|
98
|
+
endpoints can turn green locally. This is **not** real operator acceptance.
|
|
99
|
+
- `ENIGMA_DISABLE_LOCAL_DEMO_FALLBACK` is `true`, but the "external" storage,
|
|
100
|
+
KMS, and SIEM are local mocks.
|
|
101
|
+
- The TLS certificate is self-signed; curl requires `-k`/`--insecure`.
|
|
102
|
+
- The certificate SAN list includes `localhost`, `127.0.0.1`,
|
|
103
|
+
`sim.enigmamemory.com`, `relay.sim.enigmamemory.com`,
|
|
104
|
+
`gateway.sim.enigmamemory.com`, and `*.sim.enigmamemory.com`.
|
|
105
|
+
|
|
106
|
+
## Collect hosted backend live evidence
|
|
107
|
+
|
|
108
|
+
The simulation can be probed as if it were a public hosted deployment by
|
|
109
|
+
using the public-looking domain `sim.enigmamemory.com`. Because the domain
|
|
110
|
+
has no real DNS record, the collector resolves it to `127.0.0.1` locally and
|
|
111
|
+
accepts the self-signed certificate.
|
|
112
|
+
|
|
113
|
+
1. Build a simulation operator acceptance packet:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
node scripts/build-operator-acceptance-packet.mjs \
|
|
117
|
+
--complete-fixture --decision go --packet-id sim-operator-acceptance \
|
|
118
|
+
--tenant enigma-sim --deployment-mode hosted --environment local-simulation \
|
|
119
|
+
--target-regions local --requested-go-live-date 2026-06-25 \
|
|
120
|
+
--evidence-repository https://github.com/enigma-memory/evidence/sim \
|
|
121
|
+
--packet-owner "Simulation Owner" \
|
|
122
|
+
--last-updated 2026-06-25T00:00:00.000Z \
|
|
123
|
+
--owners-json .enigma/sim-owner-overrides.json \
|
|
124
|
+
--evidence-refs .enigma/sim-evidence-overrides.json \
|
|
125
|
+
--out .enigma/sim-operator-acceptance.json --validate
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
2. Collect and validate live evidence:
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
node .enigma/collect-sim-evidence.mjs \
|
|
132
|
+
--relay-url https://sim.enigmamemory.com:8443 \
|
|
133
|
+
--gateway-url https://sim.enigmamemory.com:9443 \
|
|
134
|
+
--refs-json .enigma/sim-hosted-refs.json \
|
|
135
|
+
--domain sim.enigmamemory.com --environment-id local-simulation \
|
|
136
|
+
--cloud-provider local --region local --owner enigma-sim \
|
|
137
|
+
--operator-decision go \
|
|
138
|
+
--operator-packet-ref .enigma/sim-operator-acceptance.json \
|
|
139
|
+
--operator-approved-at <iso8601> --operator-approved-by enigma-sim \
|
|
140
|
+
--out .enigma/hosted-backend-live-collection.json \
|
|
141
|
+
--evidence-out .enigma/hosted-backend-live-simulated.json
|
|
142
|
+
|
|
143
|
+
node scripts/validate-hosted-backend-live.mjs \
|
|
144
|
+
--evidence .enigma/hosted-backend-live-simulated.json
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
The expected result is `status: accepted` with all four probes observed and no
|
|
148
|
+
blockers. The wrapper does not mutate DNS or deploy infrastructure and never
|
|
149
|
+
sends credentials.
|
|
150
|
+
|
|
151
|
+
Never commit `deploy/secrets-simulation/` or `*.pem` files. Both are
|
|
152
|
+
`.gitignore`d.
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
# Enigma Memory — local production simulation.
|
|
2
|
+
# CLAIM BOUNDARY: This compose file is local-simulation only. It uses
|
|
3
|
+
# self-signed TLS, bind-mounted file "secrets", a mocked KMS, and a mocked
|
|
4
|
+
# SIEM. It is not a production deployment and does not prove hosted/BYOC
|
|
5
|
+
# readiness.
|
|
6
|
+
#
|
|
7
|
+
# LOCAL DNS NOTE: From the host, map sim.enigmamemory.com (and optional
|
|
8
|
+
# relay.sim.enigmamemory.com and gateway.sim.enigmamemory.com) to 127.0.0.1
|
|
9
|
+
# via /etc/hosts or local DNS. This lets curl -k reach the tls-proxy container
|
|
10
|
+
# whose ports are published on the loopback interface. For real validation the
|
|
11
|
+
# operator must point the chosen public domain at the deployment's public IP.
|
|
12
|
+
services:
|
|
13
|
+
postgres:
|
|
14
|
+
image: postgres:17-alpine
|
|
15
|
+
environment:
|
|
16
|
+
POSTGRES_USER: enigma
|
|
17
|
+
POSTGRES_PASSWORD: enigma
|
|
18
|
+
POSTGRES_DB: enigma
|
|
19
|
+
volumes:
|
|
20
|
+
- pgdata:/var/lib/postgresql/data
|
|
21
|
+
healthcheck:
|
|
22
|
+
test: ["CMD-SHELL", "pg_isready -U enigma -d enigma"]
|
|
23
|
+
interval: 10s
|
|
24
|
+
timeout: 3s
|
|
25
|
+
retries: 5
|
|
26
|
+
start_period: 5s
|
|
27
|
+
restart: unless-stopped
|
|
28
|
+
|
|
29
|
+
kms-mock:
|
|
30
|
+
image: node:24-alpine
|
|
31
|
+
command: ["node", "/app/deploy/kms-mock.mjs"]
|
|
32
|
+
environment:
|
|
33
|
+
PORT: "3000"
|
|
34
|
+
KMS_KEY_REF_PATH: "/data/kms-key-ref.json"
|
|
35
|
+
KMS_KEY_ID: "local-simulation-kms-key"
|
|
36
|
+
volumes:
|
|
37
|
+
- ./kms-mock.mjs:/app/deploy/kms-mock.mjs:ro
|
|
38
|
+
- ./secrets-simulation:/app/secrets-simulation:ro
|
|
39
|
+
- kms-data:/data
|
|
40
|
+
healthcheck:
|
|
41
|
+
test: ["CMD-SHELL", "node -e \"fetch('http://127.0.0.1:3000/healthz').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))\""]
|
|
42
|
+
interval: 10s
|
|
43
|
+
timeout: 3s
|
|
44
|
+
retries: 5
|
|
45
|
+
start_period: 3s
|
|
46
|
+
restart: unless-stopped
|
|
47
|
+
|
|
48
|
+
siem-mock:
|
|
49
|
+
image: node:24-alpine
|
|
50
|
+
command: ["node", "/app/deploy/siem-mock.mjs"]
|
|
51
|
+
environment:
|
|
52
|
+
PORT: "3000"
|
|
53
|
+
SIEM_SINK_PATH: "/data/siem-events.jsonl"
|
|
54
|
+
volumes:
|
|
55
|
+
- ./siem-mock.mjs:/app/deploy/siem-mock.mjs:ro
|
|
56
|
+
- siem-data:/data
|
|
57
|
+
healthcheck:
|
|
58
|
+
test: ["CMD-SHELL", "node -e \"fetch('http://127.0.0.1:3000/healthz').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))\""]
|
|
59
|
+
interval: 10s
|
|
60
|
+
timeout: 3s
|
|
61
|
+
retries: 5
|
|
62
|
+
start_period: 3s
|
|
63
|
+
restart: unless-stopped
|
|
64
|
+
|
|
65
|
+
relay:
|
|
66
|
+
build:
|
|
67
|
+
context: ..
|
|
68
|
+
dockerfile: Dockerfile
|
|
69
|
+
image: enigma-local:simulation
|
|
70
|
+
entrypoint: ["enigma-relay"]
|
|
71
|
+
command: ["serve", "--host", "0.0.0.0", "--port", "8787"]
|
|
72
|
+
secrets:
|
|
73
|
+
- relay_signing_key
|
|
74
|
+
- external_storage_dsn
|
|
75
|
+
- kms_key_ref
|
|
76
|
+
- backup_target_uri
|
|
77
|
+
- operator_acceptance_evidence_uri
|
|
78
|
+
environment:
|
|
79
|
+
NODE_ENV: production
|
|
80
|
+
ENIGMA_BACKEND_MODE: production
|
|
81
|
+
ENIGMA_REQUIRE_EXTERNAL_STORAGE: "true"
|
|
82
|
+
ENIGMA_REQUIRE_EXTERNAL_KMS: "true"
|
|
83
|
+
ENIGMA_DISABLE_LOCAL_DEMO_FALLBACK: "true"
|
|
84
|
+
ENIGMA_REQUIRE_OPERATOR_ACCEPTANCE_EVIDENCE: "true"
|
|
85
|
+
ENIGMA_READINESS_FAIL_CLOSED: "true"
|
|
86
|
+
ENIGMA_RELAY_BACKEND_HOST_REF: local-simulation-relay-backend-host-ref
|
|
87
|
+
ENIGMA_RELAY_DNS_TLS_REF: local-simulation-relay-dns-tls-ref
|
|
88
|
+
ENIGMA_RELAY_RUNTIME_AUTH_REF: local-simulation-relay-runtime-auth-ref
|
|
89
|
+
ENIGMA_RELAY_MONITORING_REF: local-simulation-relay-monitoring-ref
|
|
90
|
+
ENIGMA_SIEM_REF: local-simulation-siem-ref
|
|
91
|
+
ENIGMA_BACKUP_TARGET_URI_FILE: /run/secrets/backup_target_uri
|
|
92
|
+
ENIGMA_NETWORK_ACCESS_POLICY_REF: local-simulation-network-access-policy-ref
|
|
93
|
+
ENIGMA_KMS_CUSTODY_REF: local-simulation-kms-custody-ref
|
|
94
|
+
ENIGMA_KMS_KEY_REF: local-simulation-kms-key-ref
|
|
95
|
+
ENIGMA_TENANT_POLICY_APPROVAL_REF: local-simulation-tenant-policy-approval-ref
|
|
96
|
+
ENIGMA_USAGE_METERING_REF: local-simulation-usage-metering-ref
|
|
97
|
+
ENIGMA_SERVICE_SETTLEMENT_REF: local-simulation-service-settlement-ref
|
|
98
|
+
ENIGMA_MONITORING_ALERTING_REF: local-simulation-monitoring-alerting-ref
|
|
99
|
+
ENIGMA_PUBLIC_SITE_SECURITY_REF: local-simulation-public-site-security-ref
|
|
100
|
+
ENIGMA_SECURITY_THREAT_MODEL_REF: local-simulation-security-threat-model-ref
|
|
101
|
+
ENIGMA_LEGAL_COMPLIANCE_APPROVAL_REF: local-simulation-legal-compliance-approval-ref
|
|
102
|
+
ENIGMA_SUPPORT_SLA_REF: local-simulation-support-sla-ref
|
|
103
|
+
ENIGMA_INCIDENT_DRILL_REF: local-simulation-incident-drill-ref
|
|
104
|
+
ENIGMA_BACKUP_RESTORE_DRILL_REF: local-simulation-backup-restore-drill-ref
|
|
105
|
+
ENIGMA_OPERATOR_ACCEPTANCE_DECISION: go
|
|
106
|
+
ENIGMA_RELAY_SIGNING_KEY_FILE: /run/secrets/relay_signing_key
|
|
107
|
+
ENIGMA_EXTERNAL_STORAGE_DSN_FILE: /run/secrets/external_storage_dsn
|
|
108
|
+
ENIGMA_KMS_KEY_REF_FILE: /run/secrets/kms_key_ref
|
|
109
|
+
ENIGMA_OPERATOR_ACCEPTANCE_EVIDENCE_URI_FILE: /run/secrets/operator_acceptance_evidence_uri
|
|
110
|
+
depends_on:
|
|
111
|
+
postgres:
|
|
112
|
+
condition: service_healthy
|
|
113
|
+
read_only: true
|
|
114
|
+
user: "1000:1000"
|
|
115
|
+
cap_drop: ["ALL"]
|
|
116
|
+
security_opt:
|
|
117
|
+
- no-new-privileges:true
|
|
118
|
+
tmpfs:
|
|
119
|
+
- /tmp:rw,noexec,nosuid,size=64m
|
|
120
|
+
healthcheck:
|
|
121
|
+
test: ["CMD-SHELL", "node -e \"Promise.all([fetch('http://127.0.0.1:8787/livez'),fetch('http://127.0.0.1:8787/readyz')]).then(rs=>process.exit(rs.every(r=>r.ok)?0:1)).catch(()=>process.exit(1))\""]
|
|
122
|
+
interval: 15s
|
|
123
|
+
timeout: 5s
|
|
124
|
+
retries: 5
|
|
125
|
+
start_period: 10s
|
|
126
|
+
restart: unless-stopped
|
|
127
|
+
|
|
128
|
+
gateway:
|
|
129
|
+
build:
|
|
130
|
+
context: ..
|
|
131
|
+
dockerfile: Dockerfile
|
|
132
|
+
image: enigma-local:simulation
|
|
133
|
+
entrypoint: ["enigma-gateway"]
|
|
134
|
+
command: ["serve", "--host", "0.0.0.0", "--port", "8797"]
|
|
135
|
+
secrets:
|
|
136
|
+
- gateway_signing_key
|
|
137
|
+
- external_storage_dsn
|
|
138
|
+
- kms_key_ref
|
|
139
|
+
- siem_export_endpoint
|
|
140
|
+
- backup_target_uri
|
|
141
|
+
- operator_acceptance_evidence_uri
|
|
142
|
+
environment:
|
|
143
|
+
NODE_ENV: production
|
|
144
|
+
ENIGMA_BACKEND_MODE: production
|
|
145
|
+
ENIGMA_REQUIRE_EXTERNAL_STORAGE: "true"
|
|
146
|
+
ENIGMA_REQUIRE_EXTERNAL_KMS: "true"
|
|
147
|
+
ENIGMA_REQUIRE_SIEM_EXPORT: "true"
|
|
148
|
+
ENIGMA_DISABLE_LOCAL_DEMO_FALLBACK: "true"
|
|
149
|
+
ENIGMA_REQUIRE_OPERATOR_ACCEPTANCE_EVIDENCE: "true"
|
|
150
|
+
ENIGMA_READINESS_FAIL_CLOSED: "true"
|
|
151
|
+
ENIGMA_GATEWAY_BACKEND_HOST_REF: local-simulation-gateway-backend-host-ref
|
|
152
|
+
ENIGMA_GATEWAY_DNS_TLS_REF: local-simulation-gateway-dns-tls-ref
|
|
153
|
+
ENIGMA_GATEWAY_MONITORING_REF: local-simulation-gateway-monitoring-ref
|
|
154
|
+
ENIGMA_GATEWAY_STORAGE_REF: local-simulation-gateway-storage-ref
|
|
155
|
+
ENIGMA_SIEM_REF: local-simulation-siem-ref
|
|
156
|
+
ENIGMA_GATEWAY_ADMIN_AUTH_REF: local-simulation-gateway-admin-auth-ref
|
|
157
|
+
ENIGMA_GATEWAY_DATA_PLANE_AUTH_REF: local-simulation-gateway-data-plane-auth-ref
|
|
158
|
+
ENIGMA_BACKUP_TARGET_URI_FILE: /run/secrets/backup_target_uri
|
|
159
|
+
ENIGMA_NETWORK_ACCESS_POLICY_REF: local-simulation-network-access-policy-ref
|
|
160
|
+
ENIGMA_KMS_CUSTODY_REF: local-simulation-kms-custody-ref
|
|
161
|
+
ENIGMA_KMS_KEY_REF: local-simulation-kms-key-ref
|
|
162
|
+
ENIGMA_TENANT_POLICY_APPROVAL_REF: local-simulation-tenant-policy-approval-ref
|
|
163
|
+
ENIGMA_USAGE_METERING_REF: local-simulation-usage-metering-ref
|
|
164
|
+
ENIGMA_SERVICE_SETTLEMENT_REF: local-simulation-service-settlement-ref
|
|
165
|
+
ENIGMA_MONITORING_ALERTING_REF: local-simulation-monitoring-alerting-ref
|
|
166
|
+
ENIGMA_PUBLIC_SITE_SECURITY_REF: local-simulation-public-site-security-ref
|
|
167
|
+
ENIGMA_SECURITY_THREAT_MODEL_REF: local-simulation-security-threat-model-ref
|
|
168
|
+
ENIGMA_LEGAL_COMPLIANCE_APPROVAL_REF: local-simulation-legal-compliance-approval-ref
|
|
169
|
+
ENIGMA_SUPPORT_SLA_REF: local-simulation-support-sla-ref
|
|
170
|
+
ENIGMA_INCIDENT_DRILL_REF: local-simulation-incident-drill-ref
|
|
171
|
+
ENIGMA_BACKUP_RESTORE_DRILL_REF: local-simulation-backup-restore-drill-ref
|
|
172
|
+
ENIGMA_OPERATOR_ACCEPTANCE_DECISION: go
|
|
173
|
+
ENIGMA_GATEWAY_ADMIN_AUTH_BEARER_SHA256: sha256:6655800954551a39fc1cde811dbe44366ab67b369170b16f4f7c421b5b695870
|
|
174
|
+
ENIGMA_GATEWAY_DATA_PLANE_AUTH_BEARER_SHA256: sha256:21030e3332a199d4b729cd5a8035fdf43f0abdb541af9ee9917639ff67abdecb
|
|
175
|
+
ENIGMA_GATEWAY_SIGNING_KEY_FILE: /run/secrets/gateway_signing_key
|
|
176
|
+
ENIGMA_KMS_KEY_REF_FILE: /run/secrets/kms_key_ref
|
|
177
|
+
ENIGMA_SIEM_EXPORT_ENDPOINT_FILE: /run/secrets/siem_export_endpoint
|
|
178
|
+
ENIGMA_EXTERNAL_STORAGE_DSN_FILE: /run/secrets/external_storage_dsn
|
|
179
|
+
ENIGMA_OPERATOR_ACCEPTANCE_EVIDENCE_URI_FILE: /run/secrets/operator_acceptance_evidence_uri
|
|
180
|
+
depends_on:
|
|
181
|
+
postgres:
|
|
182
|
+
condition: service_healthy
|
|
183
|
+
read_only: true
|
|
184
|
+
user: "1000:1000"
|
|
185
|
+
cap_drop: ["ALL"]
|
|
186
|
+
security_opt:
|
|
187
|
+
- no-new-privileges:true
|
|
188
|
+
tmpfs:
|
|
189
|
+
- /tmp:rw,noexec,nosuid,size=64m
|
|
190
|
+
healthcheck:
|
|
191
|
+
test: ["CMD-SHELL", "node -e \"Promise.all([fetch('http://127.0.0.1:8797/livez'),fetch('http://127.0.0.1:8797/readyz')]).then(rs=>process.exit(rs.every(r=>r.ok)?0:1)).catch(()=>process.exit(1))\""]
|
|
192
|
+
interval: 15s
|
|
193
|
+
timeout: 5s
|
|
194
|
+
retries: 5
|
|
195
|
+
start_period: 10s
|
|
196
|
+
restart: unless-stopped
|
|
197
|
+
|
|
198
|
+
tls-proxy:
|
|
199
|
+
image: nginx:alpine
|
|
200
|
+
ports:
|
|
201
|
+
- "127.0.0.1:8443:8443"
|
|
202
|
+
- "127.0.0.1:9443:9443"
|
|
203
|
+
volumes:
|
|
204
|
+
- ./secrets-simulation/tls.crt:/etc/nginx/ssl/tls.crt:ro
|
|
205
|
+
- ./secrets-simulation/tls.key:/etc/nginx/ssl/tls.key:ro
|
|
206
|
+
- ./nginx.local-production-simulation.conf:/etc/nginx/conf.d/default.conf:ro
|
|
207
|
+
extra_hosts:
|
|
208
|
+
- "sim.enigmamemory.com:127.0.0.1"
|
|
209
|
+
- "relay.sim.enigmamemory.com:127.0.0.1"
|
|
210
|
+
- "gateway.sim.enigmamemory.com:127.0.0.1"
|
|
211
|
+
depends_on:
|
|
212
|
+
relay:
|
|
213
|
+
condition: service_healthy
|
|
214
|
+
gateway:
|
|
215
|
+
condition: service_healthy
|
|
216
|
+
restart: unless-stopped
|
|
217
|
+
|
|
218
|
+
secrets:
|
|
219
|
+
relay_signing_key:
|
|
220
|
+
file: ./secrets-simulation/relay-signing-key
|
|
221
|
+
gateway_signing_key:
|
|
222
|
+
file: ./secrets-simulation/gateway-signing-key
|
|
223
|
+
external_storage_dsn:
|
|
224
|
+
file: ./secrets-simulation/external-storage-dsn
|
|
225
|
+
kms_key_ref:
|
|
226
|
+
file: ./secrets-simulation/kms-key-ref
|
|
227
|
+
backup_target_uri:
|
|
228
|
+
file: ./secrets-simulation/backup-target-uri
|
|
229
|
+
siem_export_endpoint:
|
|
230
|
+
file: ./secrets-simulation/siem-export-endpoint
|
|
231
|
+
operator_acceptance_evidence_uri:
|
|
232
|
+
file: ./secrets-simulation/operator-acceptance-evidence-uri
|
|
233
|
+
|
|
234
|
+
volumes:
|
|
235
|
+
pgdata:
|
|
236
|
+
kms-data:
|
|
237
|
+
siem-data:
|
|
@@ -3,6 +3,12 @@
|
|
|
3
3
|
# backend availability. Provide real external storage, KMS/signing material,
|
|
4
4
|
# SIEM export, backups, monitoring, ingress/TLS, and acceptance evidence first.
|
|
5
5
|
|
|
6
|
+
# Network egress must be default-deny at the host or container-network layer.
|
|
7
|
+
# Allow only the specific endpoints required for storage, KMS, SIEM, backups,
|
|
8
|
+
# monitoring, and operator acceptance evidence. The loopback-only port bindings
|
|
9
|
+
# below are not a public ingress; place an operator-managed reverse proxy or
|
|
10
|
+
# API gateway in front for any public or private admin/data-plane routing.
|
|
11
|
+
|
|
6
12
|
services:
|
|
7
13
|
relay:
|
|
8
14
|
image: ghcr.io/enigma-ai/enigma:operator-pinned-digest-required
|
|
@@ -64,6 +70,8 @@ services:
|
|
|
64
70
|
retries: 3
|
|
65
71
|
start_period: 10s
|
|
66
72
|
restart: unless-stopped
|
|
73
|
+
networks:
|
|
74
|
+
- enigma-backend
|
|
67
75
|
|
|
68
76
|
gateway:
|
|
69
77
|
image: ghcr.io/enigma-ai/enigma:operator-pinned-digest-required
|
|
@@ -132,6 +140,8 @@ services:
|
|
|
132
140
|
retries: 3
|
|
133
141
|
start_period: 10s
|
|
134
142
|
restart: unless-stopped
|
|
143
|
+
networks:
|
|
144
|
+
- enigma-backend
|
|
135
145
|
|
|
136
146
|
secrets:
|
|
137
147
|
relay_signing_key:
|
|
@@ -148,3 +158,12 @@ secrets:
|
|
|
148
158
|
file: ./operator-secrets/siem-export-endpoint
|
|
149
159
|
operator_acceptance_evidence_uri:
|
|
150
160
|
file: ./operator-secrets/operator-acceptance-evidence-uri
|
|
161
|
+
|
|
162
|
+
networks:
|
|
163
|
+
# Isolated backend bridge. Egress is not restricted by Docker Compose itself;
|
|
164
|
+
# the operator must enforce default-deny outbound policy at the host firewall
|
|
165
|
+
# or an egress proxy, allowing only the storage/KMS/SIEM/backup/monitoring
|
|
166
|
+
# endpoints declared by the secrets and refs above.
|
|
167
|
+
enigma-backend:
|
|
168
|
+
driver: bridge
|
|
169
|
+
internal: false
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Enigma Memory — local-simulation KMS mock.
|
|
3
|
+
// CLAIM BOUNDARY: local-simulation only. This is not HSM-grade key custody.
|
|
4
|
+
|
|
5
|
+
import { createServer } from 'node:http'
|
|
6
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'
|
|
7
|
+
import { dirname } from 'node:path'
|
|
8
|
+
import { generateKeyPairSync } from 'node:crypto'
|
|
9
|
+
|
|
10
|
+
const PORT = Number(process.env.PORT || '3000')
|
|
11
|
+
const KEY_REF_PATH = process.env.KMS_KEY_REF_PATH || '/data/kms-key-ref.json'
|
|
12
|
+
const KEY_ID = process.env.KMS_KEY_ID || 'local-simulation-kms-key'
|
|
13
|
+
|
|
14
|
+
function ensureKeyRef() {
|
|
15
|
+
if (existsSync(KEY_REF_PATH)) {
|
|
16
|
+
return JSON.parse(readFileSync(KEY_REF_PATH, 'utf8'))
|
|
17
|
+
}
|
|
18
|
+
mkdirSync(dirname(KEY_REF_PATH), { recursive: true })
|
|
19
|
+
const pair = generateKeyPairSync('ed25519', {
|
|
20
|
+
privateKeyEncoding: { type: 'pkcs8', format: 'pem' },
|
|
21
|
+
publicKeyEncoding: { type: 'spki', format: 'pem' },
|
|
22
|
+
})
|
|
23
|
+
const ref = {
|
|
24
|
+
schema: 'enigma.local_simulation_kms_key_ref.v1',
|
|
25
|
+
key_id: KEY_ID,
|
|
26
|
+
alg: 'Ed25519',
|
|
27
|
+
public_key: pair.publicKey,
|
|
28
|
+
private_key: pair.privateKey,
|
|
29
|
+
claim_boundary: 'local-simulation only. This is not HSM-grade key custody.',
|
|
30
|
+
}
|
|
31
|
+
writeFileSync(KEY_REF_PATH, JSON.stringify(ref, null, 2))
|
|
32
|
+
return ref
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const keyRef = ensureKeyRef()
|
|
36
|
+
|
|
37
|
+
const server = createServer((req, res) => {
|
|
38
|
+
if (req.method === 'GET' && req.url === '/healthz') {
|
|
39
|
+
res.writeHead(200, { 'content-type': 'application/json; charset=utf-8' })
|
|
40
|
+
res.end(JSON.stringify({ ok: true, service: 'kms-mock', key_id: keyRef.key_id }))
|
|
41
|
+
return
|
|
42
|
+
}
|
|
43
|
+
if (req.method === 'GET' && req.url === '/') {
|
|
44
|
+
res.writeHead(200, { 'content-type': 'application/json; charset=utf-8' })
|
|
45
|
+
res.end(
|
|
46
|
+
JSON.stringify({
|
|
47
|
+
schema: keyRef.schema,
|
|
48
|
+
key_id: keyRef.key_id,
|
|
49
|
+
alg: keyRef.alg,
|
|
50
|
+
public_key: keyRef.public_key,
|
|
51
|
+
claim_boundary: keyRef.claim_boundary,
|
|
52
|
+
})
|
|
53
|
+
)
|
|
54
|
+
return
|
|
55
|
+
}
|
|
56
|
+
res.writeHead(404, { 'content-type': 'application/json; charset=utf-8' })
|
|
57
|
+
res.end(JSON.stringify({ ok: false, error: 'not found' }))
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
server.listen(PORT, '0.0.0.0', () => {
|
|
61
|
+
process.stdout.write(
|
|
62
|
+
`${JSON.stringify({ ok: true, service: 'kms-mock', listening: true, port: PORT, key_id: keyRef.key_id })}\n`
|
|
63
|
+
)
|
|
64
|
+
})
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Enigma Memory — local-simulation TLS termination.
|
|
2
|
+
# CLAIM BOUNDARY: local-simulation only. Uses the self-signed certificate
|
|
3
|
+
# generated by scripts/simulate-production-env.mjs; not production TLS.
|
|
4
|
+
|
|
5
|
+
server {
|
|
6
|
+
listen 8443 ssl;
|
|
7
|
+
server_name localhost sim.enigmamemory.com relay.sim.enigmamemory.com *.sim.enigmamemory.com;
|
|
8
|
+
|
|
9
|
+
ssl_certificate /etc/nginx/ssl/tls.crt;
|
|
10
|
+
ssl_certificate_key /etc/nginx/ssl/tls.key;
|
|
11
|
+
|
|
12
|
+
location / {
|
|
13
|
+
proxy_pass http://relay:8787;
|
|
14
|
+
proxy_set_header Host $host;
|
|
15
|
+
proxy_set_header X-Real-IP $remote_addr;
|
|
16
|
+
proxy_http_version 1.1;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
server {
|
|
21
|
+
listen 9443 ssl;
|
|
22
|
+
server_name localhost sim.enigmamemory.com gateway.sim.enigmamemory.com *.sim.enigmamemory.com;
|
|
23
|
+
|
|
24
|
+
ssl_certificate /etc/nginx/ssl/tls.crt;
|
|
25
|
+
ssl_certificate_key /etc/nginx/ssl/tls.key;
|
|
26
|
+
|
|
27
|
+
location / {
|
|
28
|
+
proxy_pass http://gateway:8797;
|
|
29
|
+
proxy_set_header Host $host;
|
|
30
|
+
proxy_set_header X-Real-IP $remote_addr;
|
|
31
|
+
proxy_http_version 1.1;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Enigma Memory — local-simulation SIEM audit-sink mock.
|
|
3
|
+
// CLAIM BOUNDARY: local-simulation only. Stores minimized event metadata,
|
|
4
|
+
// never raw memory plaintext.
|
|
5
|
+
|
|
6
|
+
import { createServer } from 'node:http'
|
|
7
|
+
import { createHash } from 'node:crypto'
|
|
8
|
+
import { appendFileSync, mkdirSync } from 'node:fs'
|
|
9
|
+
import { dirname } from 'node:path'
|
|
10
|
+
|
|
11
|
+
const PORT = Number(process.env.PORT || '3000')
|
|
12
|
+
const SINK_PATH = process.env.SIEM_SINK_PATH || '/data/siem-events.jsonl'
|
|
13
|
+
|
|
14
|
+
mkdirSync(dirname(SINK_PATH), { recursive: true })
|
|
15
|
+
|
|
16
|
+
const server = createServer((req, res) => {
|
|
17
|
+
if (req.method === 'GET' && req.url === '/healthz') {
|
|
18
|
+
res.writeHead(200, { 'content-type': 'application/json; charset=utf-8' })
|
|
19
|
+
res.end(JSON.stringify({ ok: true, service: 'siem-mock' }))
|
|
20
|
+
return
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (req.method === 'POST' && req.url === '/events') {
|
|
24
|
+
const chunks = []
|
|
25
|
+
req.on('data', (chunk) => chunks.push(chunk))
|
|
26
|
+
req.on('end', () => {
|
|
27
|
+
const body = Buffer.concat(chunks)
|
|
28
|
+
const minimized = {
|
|
29
|
+
received_at: new Date().toISOString(),
|
|
30
|
+
source_ip: req.socket.remoteAddress,
|
|
31
|
+
path: req.url,
|
|
32
|
+
content_length: body.length,
|
|
33
|
+
content_hash: `sha256:${createHash('sha256').update(body).digest('hex')}`,
|
|
34
|
+
}
|
|
35
|
+
appendFileSync(SINK_PATH, `${JSON.stringify(minimized)}\n`)
|
|
36
|
+
res.writeHead(202, { 'content-type': 'application/json; charset=utf-8' })
|
|
37
|
+
res.end(JSON.stringify({ ok: true, accepted: true }))
|
|
38
|
+
})
|
|
39
|
+
return
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
res.writeHead(404, { 'content-type': 'application/json; charset=utf-8' })
|
|
43
|
+
res.end(JSON.stringify({ ok: false, error: 'not found' }))
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
server.listen(PORT, '0.0.0.0', () => {
|
|
47
|
+
process.stdout.write(
|
|
48
|
+
`${JSON.stringify({ ok: true, service: 'siem-mock', listening: true, port: PORT, sink: SINK_PATH })}\n`
|
|
49
|
+
)
|
|
50
|
+
})
|