enigma-memory 0.1.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.
Files changed (105) hide show
  1. package/LICENSE +55 -0
  2. package/README.md +379 -0
  3. package/apps/cli/bin/enigma.mjs +1117 -0
  4. package/apps/desktop/src/app.js +1327 -0
  5. package/apps/desktop/src/index.html +1373 -0
  6. package/apps/desktop/src/styles.css +386 -0
  7. package/apps/gateway/bin/enigma-gateway.mjs +52 -0
  8. package/apps/gateway/src/server.mjs +1403 -0
  9. package/apps/native-host/README.md +265 -0
  10. package/apps/native-host/bin/enigma-native-host.mjs +499 -0
  11. package/apps/native-host/manifests/com.enigma.native_host.chrome.json +9 -0
  12. package/apps/native-host/manifests/com.enigma.native_host.edge.json +9 -0
  13. package/apps/native-host/manifests/com.enigma.native_host.firefox.json +9 -0
  14. package/apps/relay/bin/enigma-relay.mjs +52 -0
  15. package/apps/relay/src/server.mjs +1571 -0
  16. package/apps/verifier/bin/enigma-verify.mjs +240 -0
  17. package/deploy/docker-compose.production.example.yml +150 -0
  18. package/deploy/kubernetes/enigma-backend.example.yaml +580 -0
  19. package/package.json +196 -0
  20. package/packages/adapters/PACKAGE_CONTRACT.md +47 -0
  21. package/packages/adapters/src/index.js +183 -0
  22. package/packages/boundary/src/index.js +468 -0
  23. package/packages/connectors/src/index.js +533 -0
  24. package/packages/core/src/index.js +766 -0
  25. package/packages/enterprise/src/index.js +505 -0
  26. package/packages/importers/src/index.js +1083 -0
  27. package/packages/mcp-server/bin/enigma-mcp.mjs +19 -0
  28. package/packages/mcp-server/src/index.js +1185 -0
  29. package/packages/mesh/src/index.js +531 -0
  30. package/packages/metering/PACKAGE_CONTRACT.md +20 -0
  31. package/packages/metering/src/index.js +246 -0
  32. package/packages/optimizer/src/index.js +707 -0
  33. package/packages/passport/src/index.js +651 -0
  34. package/packages/settlement/PACKAGE_CONTRACT.md +28 -0
  35. package/packages/settlement/src/index.js +369 -0
  36. package/packages/storage/PACKAGE_CONTRACT.md +23 -0
  37. package/packages/storage/src/index.js +392 -0
  38. package/packages/vault/src/index.js +904 -0
  39. package/scripts/build-ai-orchestration-plan.mjs +248 -0
  40. package/scripts/build-cloudflare-pages-release-packet.mjs +287 -0
  41. package/scripts/build-cloudflare-token-policy.mjs +239 -0
  42. package/scripts/build-cloudflare-token-request.mjs +314 -0
  43. package/scripts/build-demo-assets.mjs +263 -0
  44. package/scripts/build-edge-backend-workers.mjs +353 -0
  45. package/scripts/build-goal-completion-audit.mjs +398 -0
  46. package/scripts/build-hosted-probe-worker.mjs +191 -0
  47. package/scripts/build-operator-acceptance-packet.mjs +254 -0
  48. package/scripts/build-operator-evidence-starter.mjs +525 -0
  49. package/scripts/build-production-backend-env-kit.mjs +384 -0
  50. package/scripts/build-production-dependency-report.mjs +369 -0
  51. package/scripts/build-production-handoff-packet.mjs +475 -0
  52. package/scripts/build-production-readiness-manifest.mjs +209 -0
  53. package/scripts/build-production-status-board.mjs +297 -0
  54. package/scripts/build-production-storage-migration.mjs +86 -0
  55. package/scripts/build-production-workplan.mjs +371 -0
  56. package/scripts/build-review-packet.mjs +594 -0
  57. package/scripts/check.mjs +419 -0
  58. package/scripts/cloudflare-ops.mjs +1672 -0
  59. package/scripts/cloudflare-secret-env.mjs +128 -0
  60. package/scripts/collect-hosted-backend-live-evidence.mjs +263 -0
  61. package/scripts/infrastructure-readiness.mjs +944 -0
  62. package/scripts/install-enigma-local.mjs +270 -0
  63. package/scripts/memory-optimization-benchmark.mjs +242 -0
  64. package/scripts/monitor-live-endpoints.mjs +358 -0
  65. package/scripts/release-audit.mjs +5588 -0
  66. package/scripts/release-provenance.mjs +250 -0
  67. package/scripts/run-backend-readiness-smoke.mjs +220 -0
  68. package/scripts/validate-backup-restore-drill.mjs +166 -0
  69. package/scripts/validate-cloudflare-credentials.mjs +112 -0
  70. package/scripts/validate-cloudflare-worker-inspect.mjs +179 -0
  71. package/scripts/validate-domain-tls.mjs +248 -0
  72. package/scripts/validate-hosted-backend-live.mjs +319 -0
  73. package/scripts/validate-incident-drill.mjs +221 -0
  74. package/scripts/validate-kms-custody.mjs +235 -0
  75. package/scripts/validate-legal-compliance-approval.mjs +274 -0
  76. package/scripts/validate-monitoring-alerting.mjs +263 -0
  77. package/scripts/validate-network-access-policy.mjs +285 -0
  78. package/scripts/validate-operator-acceptance.mjs +298 -0
  79. package/scripts/validate-production-manifests.mjs +325 -0
  80. package/scripts/validate-public-site-security.mjs +252 -0
  81. package/scripts/validate-security-threat-model.mjs +285 -0
  82. package/scripts/validate-service-settlement.mjs +256 -0
  83. package/scripts/validate-support-sla.mjs +190 -0
  84. package/scripts/validate-tenant-policy-approval.mjs +228 -0
  85. package/scripts/validate-usage-metering.mjs +224 -0
  86. package/scripts/validate-whitepaper-claims.mjs +166 -0
  87. package/specs/boundary-manifest-v1.schema.json +35 -0
  88. package/specs/capsule-v1.schema.json +55 -0
  89. package/specs/claim-boundary-manifest-v1.schema.json +22 -0
  90. package/specs/connector-profile-v1.schema.json +62 -0
  91. package/specs/deletion-tombstone-v1.schema.json +26 -0
  92. package/specs/enterprise-policy-v1.schema.json +59 -0
  93. package/specs/gateway-request-v1.schema.json +32 -0
  94. package/specs/goal-completion-audit-v1.schema.json +70 -0
  95. package/specs/hosted-backend-live-evidence-v1.schema.json +147 -0
  96. package/specs/import-report-v1.schema.json +214 -0
  97. package/specs/infrastructure-readiness-manifest-v1.schema.json +130 -0
  98. package/specs/memory-event-v1.schema.json +42 -0
  99. package/specs/mesh-node-v1.schema.json +126 -0
  100. package/specs/passport-v1.schema.json +50 -0
  101. package/specs/production-handoff-packet-v1.schema.json +149 -0
  102. package/specs/receipt-v1.schema.json +61 -0
  103. package/specs/relay-record-v1.schema.json +43 -0
  104. package/specs/state-checkpoint-v1.schema.json +37 -0
  105. package/specs/trust-bundle-v1.schema.json +56 -0
@@ -0,0 +1,384 @@
1
+ #!/usr/bin/env node
2
+ import { mkdir, writeFile } from 'node:fs/promises';
3
+ import { dirname, join, resolve } from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
5
+ import { REQUIRED_REF_KEYS } from './validate-hosted-backend-live.mjs';
6
+
7
+ export const PRODUCTION_BACKEND_ENV_KIT_SCHEMA = 'enigma.production_backend_env_kit.v1';
8
+ export const HOSTED_BACKEND_REF_MAP_SCHEMA = 'enigma.production_backend_hosted_ref_map.v1';
9
+
10
+ const DEFAULTS = Object.freeze({
11
+ domain: 'enigmamemory.com',
12
+ tenant: 'enigma-memory',
13
+ environment: 'production',
14
+ });
15
+ const HOSTED_REF_KEYS = Object.freeze([...REQUIRED_REF_KEYS]);
16
+
17
+ const HOSTED_REF_ENV_NAMES = Object.freeze({
18
+ backend_host: ['ENIGMA_BACKEND_HOST_REF', 'ENIGMA_RELAY_DEPLOYMENT_REF', 'ENIGMA_GATEWAY_DEPLOYMENT_REF', 'ENIGMA_RELAY_BACKEND_HOST_REF', 'ENIGMA_GATEWAY_BACKEND_HOST_REF'],
19
+ dns_tls: ['ENIGMA_DNS_TLS_REF', 'ENIGMA_TLS_REF', 'ENIGMA_RELAY_DNS_TLS_REF', 'ENIGMA_GATEWAY_DNS_TLS_REF'],
20
+ durable_storage: ['ENIGMA_DURABLE_STORAGE_REF', 'ENIGMA_EXTERNAL_STORAGE_REF', 'ENIGMA_RELAY_STORAGE_REF', 'ENIGMA_GATEWAY_STORAGE_REF', 'ENIGMA_EXTERNAL_STORAGE_DSN_FILE'],
21
+ kms_or_secret_custody: ['ENIGMA_KMS_KEY_REF', 'ENIGMA_KMS_REF', 'ENIGMA_GATEWAY_SIGNER_REF', 'ENIGMA_KMS_KEY_REF_FILE', 'ENIGMA_GATEWAY_SIGNING_KEY_FILE'],
22
+ backup_restore: ['ENIGMA_BACKUP_TARGET_REF', 'ENIGMA_RESTORE_TARGET_REF', 'ENIGMA_BACKUP_TARGET_URI_FILE'],
23
+ monitoring: ['ENIGMA_MONITORING_REF', 'ENIGMA_RELAY_MONITORING_REF', 'ENIGMA_GATEWAY_MONITORING_REF'],
24
+ siem_or_log_sink: ['ENIGMA_SIEM_REF', 'ENIGMA_AUDIT_SINK_REF', 'ENIGMA_LOG_SINK_REF', 'ENIGMA_SIEM_EXPORT_ENDPOINT_FILE'],
25
+ operator_acceptance: ['ENIGMA_OPERATOR_ACCEPTANCE_REF', 'ENIGMA_OPERATOR_ACCEPTANCE_EVIDENCE_URI', 'ENIGMA_OPERATOR_ACCEPTANCE_EVIDENCE_URI_FILE'],
26
+ runtime_auth: ['ENIGMA_RUNTIME_AUTH_REF', 'ENIGMA_RELAY_RUNTIME_AUTH_REF', 'ENIGMA_PAIRED_CLIENT_AUTH_REF'],
27
+ admin_auth: ['ENIGMA_ADMIN_AUTH_REF', 'ENIGMA_GATEWAY_ADMIN_AUTH_REF'],
28
+ data_plane_auth: ['ENIGMA_DATA_PLANE_AUTH_REF', 'ENIGMA_GATEWAY_DATA_PLANE_AUTH_REF'],
29
+ network_access_policy: ['ENIGMA_NETWORK_ACCESS_POLICY_REF', 'ENIGMA_NETWORK_POLICY_REF'],
30
+ kms_custody: ['ENIGMA_KMS_CUSTODY_REF', 'ENIGMA_KEY_CUSTODY_REF'],
31
+ tenant_policy_approval: ['ENIGMA_TENANT_POLICY_APPROVAL_REF', 'ENIGMA_TENANT_POLICY_REF'],
32
+ usage_metering: ['ENIGMA_USAGE_METERING_REF', 'ENIGMA_METERING_REF'],
33
+ service_settlement: ['ENIGMA_SERVICE_SETTLEMENT_REF', 'ENIGMA_SETTLEMENT_REF'],
34
+ monitoring_alerting: ['ENIGMA_MONITORING_ALERTING_REF', 'ENIGMA_ALERTING_EVIDENCE_REF'],
35
+ public_site_security: ['ENIGMA_PUBLIC_SITE_SECURITY_REF', 'ENIGMA_SITE_SECURITY_REF'],
36
+ security_threat_model: ['ENIGMA_SECURITY_THREAT_MODEL_REF', 'ENIGMA_THREAT_MODEL_REF'],
37
+ legal_compliance_approval: ['ENIGMA_LEGAL_COMPLIANCE_APPROVAL_REF', 'ENIGMA_LEGAL_APPROVAL_REF', 'ENIGMA_LEGAL_COMPLIANCE_REF'],
38
+ support_sla: ['ENIGMA_SUPPORT_SLA_REF'],
39
+ incident_drill: ['ENIGMA_INCIDENT_DRILL_REF'],
40
+ backup_restore_drill: ['ENIGMA_BACKUP_RESTORE_DRILL_REF'],
41
+ relay_deployment: ['ENIGMA_RELAY_DEPLOYMENT_REF', 'ENIGMA_RELAY_BACKEND_HOST_REF'],
42
+ gateway_deployment: ['ENIGMA_GATEWAY_DEPLOYMENT_REF', 'ENIGMA_GATEWAY_BACKEND_HOST_REF'],
43
+ });
44
+
45
+ const SECRET_PLACEHOLDERS = Object.freeze([
46
+ {
47
+ id: 'relay_signing_key',
48
+ file: 'operator-secrets/relay-signing-key',
49
+ mounted_as: '/run/secrets/relay_signing_key',
50
+ used_by: ['relay'],
51
+ placeholder: '<operator-provided-relay-signing-key-file>',
52
+ },
53
+ {
54
+ id: 'gateway_signing_key',
55
+ file: 'operator-secrets/gateway-signing-key',
56
+ mounted_as: '/run/secrets/gateway_signing_key',
57
+ used_by: ['gateway'],
58
+ placeholder: '<operator-provided-gateway-signing-key-file>',
59
+ },
60
+ {
61
+ id: 'external_storage_dsn',
62
+ file: 'operator-secrets/external-storage-dsn',
63
+ mounted_as: '/run/secrets/external_storage_dsn',
64
+ used_by: ['relay', 'gateway'],
65
+ placeholder: '<operator-provided-external-storage-dsn-file>',
66
+ },
67
+ {
68
+ id: 'kms_key_ref',
69
+ file: 'operator-secrets/kms-key-ref',
70
+ mounted_as: '/run/secrets/kms_key_ref',
71
+ used_by: ['relay', 'gateway'],
72
+ placeholder: '<operator-provided-kms-key-ref-file>',
73
+ },
74
+ {
75
+ id: 'backup_target_uri',
76
+ file: 'operator-secrets/backup-target-uri',
77
+ mounted_as: '/run/secrets/backup_target_uri',
78
+ used_by: ['relay', 'gateway'],
79
+ placeholder: '<operator-provided-backup-target-uri-file>',
80
+ },
81
+ {
82
+ id: 'siem_export_endpoint',
83
+ file: 'operator-secrets/siem-export-endpoint',
84
+ mounted_as: '/run/secrets/siem_export_endpoint',
85
+ used_by: ['gateway'],
86
+ placeholder: '<operator-provided-siem-export-endpoint-file>',
87
+ },
88
+ {
89
+ id: 'operator_acceptance_evidence_uri',
90
+ file: 'operator-secrets/operator-acceptance-evidence-uri',
91
+ mounted_as: '/run/secrets/operator_acceptance_evidence_uri',
92
+ used_by: ['relay', 'gateway'],
93
+ placeholder: '<operator-provided-operator-acceptance-evidence-uri-file>',
94
+ },
95
+ ]);
96
+
97
+ class UsageError extends Error {
98
+ constructor(message) {
99
+ super(message);
100
+ this.name = 'UsageError';
101
+ }
102
+ }
103
+
104
+ function usage() {
105
+ return 'Usage: node scripts/build-production-backend-env-kit.mjs --out-dir <dir> [--domain enigmamemory.com] [--tenant enigma-memory] [--environment production]\n\nWrites public-safe Docker Compose operator-env templates, operator-secrets placeholder manifest, hosted ref map, and blocked summary JSON. It creates no credentials, deploys nothing, and never marks launch ready.\n';
106
+ }
107
+
108
+ function requireValue(argv, index, token) {
109
+ const value = argv[index + 1];
110
+ if (typeof value !== 'string' || value.length === 0 || value.startsWith('--')) throw new UsageError(`${token} requires a value`);
111
+ return value;
112
+ }
113
+
114
+ export function parseProductionBackendEnvKitArgs(argv = process.argv.slice(2)) {
115
+ const options = { ...DEFAULTS, outDir: null, help: false };
116
+ for (let index = 0; index < argv.length; index += 1) {
117
+ const token = argv[index];
118
+ if (token === '--help' || token === '-h') options.help = true;
119
+ else if (token === '--out-dir' || token === '--outDir') {
120
+ options.outDir = requireValue(argv, index, token);
121
+ index += 1;
122
+ } else if (token === '--domain') {
123
+ options.domain = requireValue(argv, index, token);
124
+ index += 1;
125
+ } else if (token === '--tenant') {
126
+ options.tenant = requireValue(argv, index, token);
127
+ index += 1;
128
+ } else if (token === '--environment') {
129
+ options.environment = requireValue(argv, index, token);
130
+ index += 1;
131
+ } else if (token.startsWith('--out-dir=')) options.outDir = token.slice('--out-dir='.length);
132
+ else if (token.startsWith('--domain=')) options.domain = token.slice('--domain='.length);
133
+ else if (token.startsWith('--tenant=')) options.tenant = token.slice('--tenant='.length);
134
+ else if (token.startsWith('--environment=')) options.environment = token.slice('--environment='.length);
135
+ else throw new UsageError(`Unknown production backend env kit option: ${token}`);
136
+ }
137
+ return normalizeOptions(options);
138
+ }
139
+
140
+ function safeSlug(value, field) {
141
+ if (typeof value !== 'string') throw new UsageError(`${field} must be a string`);
142
+ const trimmed = value.trim();
143
+ if (!/^[a-z0-9][a-z0-9._-]{0,62}$/u.test(trimmed)) throw new UsageError(`${field} must be a lowercase public-safe slug`);
144
+ return trimmed;
145
+ }
146
+
147
+ function safeDomain(value) {
148
+ if (typeof value !== 'string') throw new UsageError('--domain must be a string');
149
+ const trimmed = value.trim().toLowerCase();
150
+ if (trimmed.includes('://') || trimmed.includes('/') || trimmed.includes('@')) throw new UsageError('--domain must be a bare public host name');
151
+ if (!/^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z]{2,63}$/u.test(trimmed)) throw new UsageError('--domain must be a public DNS host name');
152
+ return trimmed;
153
+ }
154
+
155
+ function normalizeOptions(options) {
156
+ return {
157
+ ...options,
158
+ domain: safeDomain(options.domain ?? DEFAULTS.domain),
159
+ tenant: safeSlug(options.tenant ?? DEFAULTS.tenant, '--tenant'),
160
+ environment: safeSlug(options.environment ?? DEFAULTS.environment, '--environment'),
161
+ };
162
+ }
163
+
164
+ function placeholderFor(name) {
165
+ return `<operator-required-${name.toLowerCase().replaceAll('_', '-')}>`;
166
+ }
167
+
168
+ function envLine([name, value]) {
169
+ return `${name}=${value}`;
170
+ }
171
+
172
+ function serviceEnv({ service, domain, tenant, environment }) {
173
+ const common = [
174
+ ['NODE_ENV', 'production'],
175
+ ['ENIGMA_BACKEND_MODE', 'production'],
176
+ ['ENIGMA_TENANT', tenant],
177
+ ['ENIGMA_ENVIRONMENT', environment],
178
+ ['ENIGMA_PUBLIC_SITE_URL', `https://${domain}/`],
179
+ ['ENIGMA_DISABLE_LOCAL_DEMO_FALLBACK', 'true'],
180
+ ['ENIGMA_REQUIRE_OPERATOR_ACCEPTANCE_EVIDENCE', 'true'],
181
+ ['ENIGMA_READINESS_FAIL_CLOSED', 'true'],
182
+ ['ENIGMA_NETWORK_ACCESS_POLICY_REF', placeholderFor('ENIGMA_NETWORK_ACCESS_POLICY_REF')],
183
+ ['ENIGMA_KMS_CUSTODY_REF', placeholderFor('ENIGMA_KMS_CUSTODY_REF')],
184
+ ['ENIGMA_KMS_KEY_REF', placeholderFor('ENIGMA_KMS_KEY_REF')],
185
+ ['ENIGMA_TENANT_POLICY_APPROVAL_REF', placeholderFor('ENIGMA_TENANT_POLICY_APPROVAL_REF')],
186
+ ['ENIGMA_USAGE_METERING_REF', placeholderFor('ENIGMA_USAGE_METERING_REF')],
187
+ ['ENIGMA_SERVICE_SETTLEMENT_REF', placeholderFor('ENIGMA_SERVICE_SETTLEMENT_REF')],
188
+ ['ENIGMA_MONITORING_ALERTING_REF', placeholderFor('ENIGMA_MONITORING_ALERTING_REF')],
189
+ ['ENIGMA_SIEM_REF', placeholderFor('ENIGMA_SIEM_REF')],
190
+ ['ENIGMA_PUBLIC_SITE_SECURITY_REF', placeholderFor('ENIGMA_PUBLIC_SITE_SECURITY_REF')],
191
+ ['ENIGMA_SECURITY_THREAT_MODEL_REF', placeholderFor('ENIGMA_SECURITY_THREAT_MODEL_REF')],
192
+ ['ENIGMA_LEGAL_COMPLIANCE_APPROVAL_REF', placeholderFor('ENIGMA_LEGAL_COMPLIANCE_APPROVAL_REF')],
193
+ ['ENIGMA_SUPPORT_SLA_REF', placeholderFor('ENIGMA_SUPPORT_SLA_REF')],
194
+ ['ENIGMA_INCIDENT_DRILL_REF', placeholderFor('ENIGMA_INCIDENT_DRILL_REF')],
195
+ ['ENIGMA_BACKUP_RESTORE_DRILL_REF', placeholderFor('ENIGMA_BACKUP_RESTORE_DRILL_REF')],
196
+ ['ENIGMA_OPERATOR_ACCEPTANCE_DECISION', '<operator-required-go-decision>'],
197
+ ['ENIGMA_BACKUP_TARGET_URI_FILE', '/run/secrets/backup_target_uri'],
198
+ ['ENIGMA_KMS_KEY_REF_FILE', '/run/secrets/kms_key_ref'],
199
+ ['ENIGMA_OPERATOR_ACCEPTANCE_EVIDENCE_URI_FILE', '/run/secrets/operator_acceptance_evidence_uri'],
200
+ ];
201
+ if (service === 'relay') {
202
+ return [
203
+ ['ENIGMA_SERVICE_ROLE', 'relay'],
204
+ ['ENIGMA_RELAY_PUBLIC_BASE_URL', `https://relay.${domain}`],
205
+ ['ENIGMA_RELAY_READY_URL', `https://relay.${domain}/readyz`],
206
+ ['ENIGMA_RELAY_LIVE_URL', `https://relay.${domain}/livez`],
207
+ ['ENIGMA_REQUIRE_EXTERNAL_STORAGE', 'true'],
208
+ ['ENIGMA_REQUIRE_EXTERNAL_KMS', 'true'],
209
+ ['ENIGMA_RELAY_BACKEND_HOST_REF', placeholderFor('ENIGMA_RELAY_BACKEND_HOST_REF')],
210
+ ['ENIGMA_RELAY_DEPLOYMENT_REF', placeholderFor('ENIGMA_RELAY_DEPLOYMENT_REF')],
211
+ ['ENIGMA_RELAY_DNS_TLS_REF', placeholderFor('ENIGMA_RELAY_DNS_TLS_REF')],
212
+ ['ENIGMA_RELAY_RUNTIME_AUTH_REF', placeholderFor('ENIGMA_RELAY_RUNTIME_AUTH_REF')],
213
+ ['ENIGMA_RELAY_MONITORING_REF', placeholderFor('ENIGMA_RELAY_MONITORING_REF')],
214
+ ['ENIGMA_RELAY_SIGNING_KEY_FILE', '/run/secrets/relay_signing_key'],
215
+ ['ENIGMA_EXTERNAL_STORAGE_DSN_FILE', '/run/secrets/external_storage_dsn'],
216
+ ...common,
217
+ ];
218
+ }
219
+ return [
220
+ ['ENIGMA_SERVICE_ROLE', 'gateway'],
221
+ ['ENIGMA_GATEWAY_PUBLIC_BASE_URL', `https://gateway.${domain}`],
222
+ ['ENIGMA_GATEWAY_READY_URL', `https://gateway.${domain}/readyz`],
223
+ ['ENIGMA_GATEWAY_LIVE_URL', `https://gateway.${domain}/livez`],
224
+ ['ENIGMA_REQUIRE_EXTERNAL_KMS', 'true'],
225
+ ['ENIGMA_REQUIRE_EXTERNAL_STORAGE', 'true'],
226
+ ['ENIGMA_REQUIRE_SIEM_EXPORT', 'true'],
227
+ ['ENIGMA_GATEWAY_BACKEND_HOST_REF', placeholderFor('ENIGMA_GATEWAY_BACKEND_HOST_REF')],
228
+ ['ENIGMA_GATEWAY_DEPLOYMENT_REF', placeholderFor('ENIGMA_GATEWAY_DEPLOYMENT_REF')],
229
+ ['ENIGMA_GATEWAY_DNS_TLS_REF', placeholderFor('ENIGMA_GATEWAY_DNS_TLS_REF')],
230
+ ['ENIGMA_GATEWAY_MONITORING_REF', placeholderFor('ENIGMA_GATEWAY_MONITORING_REF')],
231
+ ['ENIGMA_GATEWAY_STORAGE_REF', placeholderFor('ENIGMA_GATEWAY_STORAGE_REF')],
232
+ ['ENIGMA_GATEWAY_ADMIN_AUTH_REF', placeholderFor('ENIGMA_GATEWAY_ADMIN_AUTH_REF')],
233
+ ['ENIGMA_GATEWAY_DATA_PLANE_AUTH_REF', placeholderFor('ENIGMA_GATEWAY_DATA_PLANE_AUTH_REF')],
234
+ ['ENIGMA_GATEWAY_ADMIN_AUTH_BEARER_SHA256', '<operator-required-admin-bearer-sha256>'],
235
+ ['ENIGMA_GATEWAY_DATA_PLANE_AUTH_BEARER_SHA256', '<operator-required-data-plane-bearer-sha256>'],
236
+ ['ENIGMA_GATEWAY_SIGNING_KEY_FILE', '/run/secrets/gateway_signing_key'],
237
+ ['ENIGMA_SIEM_EXPORT_ENDPOINT_FILE', '/run/secrets/siem_export_endpoint'],
238
+ ['ENIGMA_EXTERNAL_STORAGE_DSN_FILE', '/run/secrets/external_storage_dsn'],
239
+ ...common,
240
+ ];
241
+ }
242
+
243
+ function renderEnvTemplate(service, options) {
244
+ const title = service === 'relay' ? 'Relay' : 'Gateway';
245
+ return [
246
+ `# Enigma ${title} production operator-env template.`,
247
+ '# Public-safe placeholders only; replace values in your private operator environment.',
248
+ '# Docker Compose keeps service ports loopback-bound; public exposure belongs at reviewed HTTPS ingress for /livez and /readyz only.',
249
+ '# These defaults fail closed until external refs, mounted secret files, and operator acceptance are supplied.',
250
+ ...serviceEnv({ service, ...options }).map(envLine),
251
+ '',
252
+ ].join('\n');
253
+ }
254
+
255
+ function buildHostedRefMap() {
256
+ const refs = {};
257
+ for (const key of HOSTED_REF_KEYS) {
258
+ refs[key] = {
259
+ status: 'operator_required',
260
+ value: `<operator-provided-${key.replaceAll('_', '-')}-evidence-ref>`,
261
+ env_names: HOSTED_REF_ENV_NAMES[key] ?? [],
262
+ accepted_ref_types: ['evidence artifact id', 'review ticket id', 'deployment rollout id', 'artifact digest'],
263
+ };
264
+ }
265
+ return {
266
+ schema: HOSTED_BACKEND_REF_MAP_SCHEMA,
267
+ status: 'blocked_until_operator_refs_are_verified',
268
+ required_ref_count: HOSTED_REF_KEYS.length,
269
+ refs,
270
+ fill_rule: 'Every value must be replaced with a public-safe evidence reference before hosted relay/gateway readiness can be claimed.',
271
+ forbidden_values: ['bearer credential values', 'private key material', 'URLs with credentials', 'memory plaintext', 'prompts', 'transcripts', 'provider responses', 'decrypted content'],
272
+ };
273
+ }
274
+
275
+ function buildSecretPlaceholderManifest() {
276
+ return {
277
+ schema: 'enigma.production_backend_secret_placeholders.v1',
278
+ status: 'placeholder_manifest_only',
279
+ compose_directory: 'operator-secrets/',
280
+ entries: SECRET_PLACEHOLDERS,
281
+ handling: [
282
+ 'Create each listed file only in the private deployment workspace.',
283
+ 'Do not commit filled files, paste values into tickets, or place values in generated public artifacts.',
284
+ 'Leave placeholders blocked until an operator-controlled secret store supplies each mounted file.',
285
+ ],
286
+ };
287
+ }
288
+
289
+ function nextValidationCommands({ domain, tenant, environment }) {
290
+ return [
291
+ `npm run production:backend-env -- --out-dir <backend-env-kit-dir> --domain ${domain} --tenant ${tenant} --environment ${environment}`,
292
+ 'docker compose -f deploy/docker-compose.production.example.yml config # run in the private deployment workspace after copying filled operator-env templates',
293
+ 'npm run production:manifests',
294
+ 'npm run infrastructure:readiness -- --manifest <evidence-dir>/infrastructure-readiness-manifest.json --live --cloudflare-live required',
295
+ `npm run production:hosted-collect -- --relay-url https://relay.${domain} --gateway-url https://gateway.${domain} --refs-json <evidence-dir>/hosted-refs.json --domain ${domain} --environment-id ${environment} --cloud-provider <provider> --region <region> --owner <owner> --operator-decision go --operator-packet-ref <operator-packet-ref> --operator-approved-at <iso> --operator-approved-by <operator> --out <evidence-dir>/hosted-backend-live-collection.json --evidence-out <evidence-dir>/hosted-backend-live.json`,
296
+ 'npm run production:hosted-live -- --evidence <evidence-dir>/hosted-backend-live.json',
297
+ 'npm run production:acceptance -- --packet <operator-acceptance-packet.json>',
298
+ ];
299
+ }
300
+
301
+ export function buildProductionBackendEnvKit(options = {}) {
302
+ const normalized = normalizeOptions({ ...DEFAULTS, ...options });
303
+ const files = {
304
+ 'operator-env/relay.production.env': renderEnvTemplate('relay', normalized),
305
+ 'operator-env/gateway.production.env': renderEnvTemplate('gateway', normalized),
306
+ 'operator-secrets/placeholder-manifest.json': buildSecretPlaceholderManifest(),
307
+ 'hosted-ref-map.json': buildHostedRefMap(),
308
+ };
309
+ const summaryPath = 'PRODUCTION_BACKEND_ENV_KIT_SUMMARY.json';
310
+ const summary = {
311
+ schema: PRODUCTION_BACKEND_ENV_KIT_SCHEMA,
312
+ status: 'blocked_template_only',
313
+ hosted_live_ready: false,
314
+ operator_acceptance_ready: false,
315
+ deployment_performed: false,
316
+ launch_ready: false,
317
+ generated_at: options.generated_at ?? options.generatedAt ?? new Date().toISOString(),
318
+ target: {
319
+ domain: normalized.domain,
320
+ tenant: normalized.tenant,
321
+ environment: normalized.environment,
322
+ },
323
+ generated_file_count: Object.keys(files).length + 1,
324
+ generated_file_roles: ['relay operator-env template', 'gateway operator-env template', 'private mount placeholder manifest', 'hosted ref map', 'summary JSON'],
325
+ docker_compose_reference: 'deploy/docker-compose.production.example.yml',
326
+ loopback_boundary: 'Docker Compose reference ports remain bound to 127.0.0.1; public exposure must be an operator-reviewed HTTPS ingress that exposes only /livez and /readyz.',
327
+ public_claim_boundary: [
328
+ 'This kit is not hosted backend evidence, operator acceptance, deployment proof, or launch approval.',
329
+ 'Relay/gateway public readiness requires real HTTPS probes, verified hosted refs, current manifest validation, and operator acceptance go for this exact target.',
330
+ 'Credential values, private key material, memory plaintext, prompts, transcripts, provider responses, and contact data must stay outside generated files.',
331
+ ],
332
+ fail_closed_defaults: [
333
+ 'ENIGMA_BACKEND_MODE=production',
334
+ 'ENIGMA_DISABLE_LOCAL_DEMO_FALLBACK=true',
335
+ 'ENIGMA_REQUIRE_EXTERNAL_STORAGE=true',
336
+ 'ENIGMA_REQUIRE_SIEM_EXPORT=true',
337
+ 'ENIGMA_REQUIRE_EXTERNAL_KMS=true',
338
+ 'ENIGMA_REQUIRE_OPERATOR_ACCEPTANCE_EVIDENCE=true',
339
+ 'ENIGMA_READINESS_FAIL_CLOSED=true',
340
+ ],
341
+ next_validation_commands: nextValidationCommands(normalized),
342
+ };
343
+ files[summaryPath] = summary;
344
+ return { ...summary, files };
345
+ }
346
+
347
+ export async function writeProductionBackendEnvKit(kit, outDir) {
348
+ if (typeof outDir !== 'string' || outDir.trim().length === 0) throw new UsageError('--out-dir is required');
349
+ const dir = resolve(outDir);
350
+ await mkdir(dir, { recursive: true });
351
+ for (const [relativePath, value] of Object.entries(kit.files)) {
352
+ const target = join(dir, relativePath);
353
+ await mkdir(dirname(target), { recursive: true });
354
+ const body = typeof value === 'string' ? value : `${JSON.stringify(value, null, 2)}\n`;
355
+ await writeFile(target, body, 'utf8');
356
+ }
357
+ return {
358
+ ok: true,
359
+ schema: PRODUCTION_BACKEND_ENV_KIT_SCHEMA,
360
+ out_dir: '<production-backend-env-kit-output>',
361
+ launch_ready: false,
362
+ file_count: Object.keys(kit.files).length,
363
+ generated_file_roles: kit.generated_file_roles,
364
+ next_validation_commands: kit.next_validation_commands,
365
+ };
366
+ }
367
+
368
+ const invokedPath = process.argv[1] ? resolve(process.argv[1]) : '';
369
+ if (invokedPath === fileURLToPath(import.meta.url)) {
370
+ (async () => {
371
+ try {
372
+ const args = parseProductionBackendEnvKitArgs();
373
+ if (args.help) {
374
+ process.stdout.write(usage());
375
+ return;
376
+ }
377
+ const kit = buildProductionBackendEnvKit({ ...args, generated_at: new Date().toISOString() });
378
+ process.stdout.write(`${JSON.stringify(await writeProductionBackendEnvKit(kit, args.outDir), null, 2)}\n`);
379
+ } catch (error) {
380
+ process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
381
+ process.exitCode = 1;
382
+ }
383
+ })();
384
+ }