enigma-memory 0.1.17 → 0.1.22

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 (290) hide show
  1. package/README.md +85 -27
  2. package/apps/cli/bin/enigma-desktop.mjs +140 -0
  3. package/apps/cli/bin/enigma-terminal.mjs +78 -0
  4. package/apps/cli/bin/enigma.mjs +4979 -3263
  5. package/apps/desktop/electron-main.cjs +217 -0
  6. package/apps/desktop/package.json +12 -0
  7. package/apps/desktop/src/app.js +264 -7
  8. package/apps/desktop/src/index.html +3514 -1373
  9. package/apps/desktop/src/launch-electron.mjs +51 -0
  10. package/apps/desktop/src/server.mjs +2914 -0
  11. package/apps/desktop/src/styles.css +2972 -260
  12. package/apps/desktop/src/zk-browser-prove.mjs +53 -0
  13. package/apps/desktop/src/zk-state.mjs +1789 -0
  14. package/apps/gateway/bin/enigma-gateway.mjs +102 -5
  15. package/apps/gateway/src/server.mjs +271 -8
  16. package/apps/ios/EnigmaCore/Package.swift +12 -0
  17. package/apps/ios/EnigmaCore/Sources/EnigmaCore/EnigmaAPIClient.swift +227 -0
  18. package/apps/ios/EnigmaCore/Sources/EnigmaCore/Models.swift +278 -0
  19. package/apps/ios/EnigmaCore/Sources/EnigmaCore/PKCE.swift +96 -0
  20. package/apps/ios/EnigmaCore/Sources/EnigmaCore/PrivacyMinimizer.swift +187 -0
  21. package/apps/ios/EnigmaCore/Sources/EnigmaCore/ToolModels.swift +129 -0
  22. package/apps/ios/EnigmaCore/Tests/EnigmaCoreTests/EnigmaCoreTests.swift +42 -0
  23. package/apps/ios/EnigmaIOS/Enigma/AppModel.swift +346 -0
  24. package/apps/ios/EnigmaIOS/Enigma/Assets.xcassets/AccentColor.colorset/Contents.json +12 -0
  25. package/apps/ios/EnigmaIOS/Enigma/Assets.xcassets/AppIcon.appiconset/Contents.json +11 -0
  26. package/apps/ios/EnigmaIOS/Enigma/Assets.xcassets/AppIcon.appiconset/EnigmaAppIcon.png +0 -0
  27. package/apps/ios/EnigmaIOS/Enigma/Assets.xcassets/Contents.json +3 -0
  28. package/apps/ios/EnigmaIOS/Enigma/Assets.xcassets/LaunchBackground.colorset/Contents.json +12 -0
  29. package/apps/ios/EnigmaIOS/Enigma/ChatView.swift +181 -0
  30. package/apps/ios/EnigmaIOS/Enigma/CouncilView.swift +78 -0
  31. package/apps/ios/EnigmaIOS/Enigma/CreateView.swift +152 -0
  32. package/apps/ios/EnigmaIOS/Enigma/EnigmaApp.swift +52 -0
  33. package/apps/ios/EnigmaIOS/Enigma/Info.plist +52 -0
  34. package/apps/ios/EnigmaIOS/Enigma/NaturalLanguagePrivacyTagger.swift +26 -0
  35. package/apps/ios/EnigmaIOS/Enigma/OAuthClient.swift +321 -0
  36. package/apps/ios/EnigmaIOS/Enigma/OnboardingView.swift +105 -0
  37. package/apps/ios/EnigmaIOS/Enigma/PrivateVaultView.swift +275 -0
  38. package/apps/ios/EnigmaIOS/Enigma/SecureStore.swift +76 -0
  39. package/apps/ios/EnigmaIOS/Enigma/SettingsView.swift +60 -0
  40. package/apps/ios/EnigmaIOS/Enigma/Theme.swift +80 -0
  41. package/apps/ios/EnigmaIOS/EnigmaIOS.xcodeproj/project.pbxproj +211 -0
  42. package/apps/ios/EnigmaIOS/EnigmaIOS.xcodeproj/xcshareddata/xcschemes/Enigma.xcscheme +23 -0
  43. package/apps/native-host/README.md +19 -8
  44. package/apps/native-host/bin/enigma-native-host.mjs +229 -13
  45. package/apps/relay/bin/enigma-relay.mjs +103 -5
  46. package/apps/relay/src/federation-runtime.mjs +618 -0
  47. package/apps/relay/src/server.mjs +310 -9
  48. package/apps/verifier/bin/enigma-verify.mjs +327 -11
  49. package/cortex-v3/circuits/build/intent_vk_bytes.json +35 -0
  50. package/cortex-v3/circuits/build/sale_vk_bytes.json +35 -0
  51. package/cortex-v3/circuits/build/vk_bytes.json +32 -0
  52. package/cortex-v3/proving-assets.json +64 -0
  53. package/cortex-v3/zk/BUILD-CONTRACT.md +87 -0
  54. package/cortex-v3/zk/action-transition-vk.json +119 -0
  55. package/cortex-v3/zk/alias-adversarial.test.mjs +220 -0
  56. package/cortex-v3/zk/groth16-verify-child.mjs +17 -0
  57. package/cortex-v3/zk/intent-witness.mjs +365 -0
  58. package/cortex-v3/zk/intent-witness.test.mjs +485 -0
  59. package/cortex-v3/zk/proving-assets.mjs +203 -0
  60. package/cortex-v3/zk/sale-witness.mjs +783 -0
  61. package/cortex-v3/zk/sale-witness.test.mjs +784 -0
  62. package/cortex-v3/zk/sealed-sale-release-vk.json +119 -0
  63. package/cortex-v3/zk/settlement-evidence.mjs +722 -0
  64. package/cortex-v3/zk/setup-intent.mjs +688 -0
  65. package/cortex-v3/zk/setup-sale.mjs +666 -0
  66. package/cortex-v3/zk/setup.mjs +594 -0
  67. package/cortex-v3/zk/witness.mjs +184 -0
  68. package/cortex-v3/zk/zk-codec.mjs +232 -0
  69. package/cortex-v3/zk/zk-codec.test.mjs +293 -0
  70. package/cortex-v3/zk/zk-settle.mjs +370 -0
  71. package/cortex-v3/zk/zk-tree.mjs +256 -0
  72. package/cortex-v3/zk/zk-tree.test.mjs +419 -0
  73. package/deploy/SIMULATION.md +14 -9
  74. package/deploy/docker-compose.local-production-simulation.yml +54 -12
  75. package/docs/benchmark-attestation-network.md +487 -487
  76. package/docs/benchmark-reproducibility.md +289 -289
  77. package/docs/blockchain-only-mechanisms.md +400 -400
  78. package/docs/browser-extension-install.md +8 -6
  79. package/docs/client-connectors.md +16 -12
  80. package/docs/demo-proof-network.md +275 -275
  81. package/docs/developer-ecosystem.md +15 -13
  82. package/docs/developer-proof-quickstart.md +325 -325
  83. package/docs/enigma-memory-ready-conformance.md +378 -376
  84. package/docs/install-anywhere.md +64 -30
  85. package/docs/installers-and-desktop.md +8 -7
  86. package/docs/memory-benchmarks.md +1 -1
  87. package/docs/memory-drive-health-model.md +690 -690
  88. package/docs/novelty-invention-candidates.md +161 -161
  89. package/docs/proof-network-build-notes.md +240 -240
  90. package/docs/proof-network-claim-boundaries.md +320 -318
  91. package/docs/proof-network.md +339 -339
  92. package/docs/sdk-api.md +324 -324
  93. package/docs/solana-proof-rail.md +453 -453
  94. package/examples/01-quickstart-agent/index.mjs +49 -0
  95. package/examples/01_agent_memory_quickstart.mjs +57 -0
  96. package/examples/02-multi-agent-swarm/index.mjs +57 -0
  97. package/examples/02_cross_model_passport.mjs +64 -0
  98. package/examples/03-langchain-memory/index.mjs +41 -0
  99. package/examples/03_poseidon_commitment_verification.mjs +71 -0
  100. package/examples/04-python-trading-agent/trader.py +49 -0
  101. package/examples/README.md +27 -0
  102. package/examples/ci/github-actions.yml +7 -2
  103. package/package.json +410 -278
  104. package/packages/adapters/PACKAGE_CONTRACT.md +1 -1
  105. package/packages/connectors/src/index.js +196 -4
  106. package/packages/connectors/swarm-router.mjs +168 -0
  107. package/packages/core/src/index.js +249 -2
  108. package/packages/core/src/version.mjs +7 -0
  109. package/packages/dev-tools/package.json +19 -0
  110. package/packages/dev-tools/src/index.js +4 -0
  111. package/packages/dev-tools/src/memory-benchmark-suite.js +112 -0
  112. package/packages/dev-tools/src/swarm-simulator.js +101 -0
  113. package/packages/dev-tools/src/vault-inspector.js +114 -0
  114. package/packages/dev-tools/src/vector-benchmark.js +100 -0
  115. package/packages/developer-platform/src/access-credentials.js +341 -0
  116. package/packages/developer-platform/src/http.js +132 -0
  117. package/packages/developer-platform/src/index.js +4 -0
  118. package/packages/developer-platform/src/usage-http.js +60 -0
  119. package/packages/developer-platform/src/usage.js +295 -0
  120. package/packages/enclave-runtime/attestation.mjs +159 -0
  121. package/packages/enclave-runtime/index.mjs +47 -0
  122. package/packages/enclave-runtime/session-manager.mjs +253 -0
  123. package/packages/enclave-runtime/zeroization-proof.mjs +227 -0
  124. package/packages/enigma-reflex/package.json +14 -0
  125. package/packages/enigma-reflex/src/index.js +204 -0
  126. package/packages/enigma-reflex/training/generate-dataset.mjs +40 -0
  127. package/packages/enigma-reflex/training/requirements.txt +8 -0
  128. package/packages/enigma-reflex/training/train.py +314 -0
  129. package/packages/enigma-weave/LICENSE +22 -0
  130. package/packages/enigma-weave/UPSTREAM.json +21 -0
  131. package/packages/enigma-weave/package.json +14 -0
  132. package/packages/enigma-weave/src/index.js +286 -0
  133. package/packages/hosted-cloud/src/index.js +80 -5
  134. package/packages/importers/src/index.js +432 -0
  135. package/packages/inference-runtime/src/browser.js +401 -0
  136. package/packages/inference-runtime/src/chat.js +265 -0
  137. package/packages/inference-runtime/src/code.js +407 -0
  138. package/packages/inference-runtime/src/contracts.js +162 -0
  139. package/packages/inference-runtime/src/http.js +232 -0
  140. package/packages/inference-runtime/src/image.js +186 -0
  141. package/packages/inference-runtime/src/index.js +10 -0
  142. package/packages/inference-runtime/src/model-router.js +320 -0
  143. package/packages/inference-runtime/src/platform.js +125 -0
  144. package/packages/inference-runtime/src/privacy.js +400 -0
  145. package/packages/inference-runtime/src/video.js +253 -0
  146. package/packages/mcp-server/README.md +22 -6
  147. package/packages/mcp-server/bin/enigma-mcp.mjs +2 -1
  148. package/packages/mcp-server/src/index.js +2498 -1185
  149. package/packages/mcp-server/src/oauth.js +561 -0
  150. package/packages/mcp-server/src/private-handoff.js +84 -0
  151. package/packages/mcp-server/src/remote-http.js +273 -0
  152. package/packages/mcp-server/src/remote-policy.js +72 -0
  153. package/packages/mcp-server/swarm-bridge.mjs +361 -0
  154. package/packages/mesh/index.d.ts +283 -0
  155. package/packages/mesh/package.json +23 -0
  156. package/packages/mesh/src/crypto.js +189 -0
  157. package/packages/mesh/src/federation-packets.js +353 -0
  158. package/packages/mesh/src/gossip.js +311 -0
  159. package/packages/mesh/src/index.js +6 -0
  160. package/packages/mesh/src/protocol.js +255 -0
  161. package/packages/mesh/src/router.js +279 -0
  162. package/packages/mesh/src/transport.js +306 -0
  163. package/packages/passport/src/index.js +436 -7
  164. package/packages/private-economy/src/credits-http.js +100 -0
  165. package/packages/private-economy/src/credits.js +447 -0
  166. package/packages/private-economy/src/index.js +5 -0
  167. package/packages/private-economy/src/payments-http.js +120 -0
  168. package/packages/private-economy/src/payments.js +509 -0
  169. package/packages/private-economy/src/x402.js +346 -0
  170. package/packages/proof-network/PACKAGE_CONTRACT.md +21 -0
  171. package/packages/rag/index.d.ts +182 -0
  172. package/packages/rag/models/Xenova/all-MiniLM-L6-v2/THIRD_PARTY_LICENSES.txt +207 -0
  173. package/packages/rag/models/Xenova/all-MiniLM-L6-v2/config.json +25 -0
  174. package/packages/rag/models/Xenova/all-MiniLM-L6-v2/onnx/model_quantized.onnx +0 -0
  175. package/packages/rag/models/Xenova/all-MiniLM-L6-v2/sha256-manifest.json +28 -0
  176. package/packages/rag/models/Xenova/all-MiniLM-L6-v2/tokenizer.json +30686 -0
  177. package/packages/rag/models/Xenova/all-MiniLM-L6-v2/tokenizer_config.json +15 -0
  178. package/packages/rag/package.json +27 -0
  179. package/packages/rag/src/blinded-search.js +109 -0
  180. package/packages/rag/src/bm25.js +169 -0
  181. package/packages/rag/src/embeddings.js +459 -0
  182. package/packages/rag/src/hybrid.js +76 -0
  183. package/packages/rag/src/index.js +38 -0
  184. package/packages/rag/src/reranker.js +61 -0
  185. package/packages/rag/src/research.js +107 -0
  186. package/packages/rag/src/vector-store.js +430 -0
  187. package/packages/rag/src/verify-model-artifacts.mjs +4 -0
  188. package/packages/sdk/index.d.ts +760 -0
  189. package/packages/sdk/package.json +33 -0
  190. package/packages/sdk/python/README.md +24 -0
  191. package/packages/sdk/python/enigma_sdk.py +250 -0
  192. package/packages/sdk/python/pyproject.toml +34 -0
  193. package/packages/sdk/python/requirements.txt +1 -0
  194. package/packages/sdk/python/setup.py +20 -0
  195. package/packages/sdk/src/federation/capability-grant.js +389 -0
  196. package/packages/sdk/src/federation/federation-router.js +360 -0
  197. package/packages/sdk/src/federation/ghostmesh-bridge.js +497 -0
  198. package/packages/sdk/src/federation/index.js +3 -0
  199. package/packages/sdk/src/index.js +1796 -0
  200. package/packages/sdk/src/intelligence/contradiction.js +337 -0
  201. package/packages/sdk/src/intelligence/decision-engine.js +155 -0
  202. package/packages/sdk/src/intelligence/index.js +4 -0
  203. package/packages/sdk/src/intelligence/ontology.js +122 -0
  204. package/packages/sdk/src/intelligence/temporal.js +123 -0
  205. package/packages/sdk/src/market-client.js +142 -0
  206. package/packages/sdk/src/mesh-client.js +110 -0
  207. package/packages/sdk/src/middleware/index.js +3 -0
  208. package/packages/sdk/src/middleware/langchain.js +159 -0
  209. package/packages/sdk/src/middleware/llamaindex.js +101 -0
  210. package/packages/sdk/src/middleware/vercel-ai.js +112 -0
  211. package/packages/sdk/src/rag-client.js +85 -0
  212. package/packages/sdk/src/swarm-orchestrator.js +260 -0
  213. package/packages/settlement/PACKAGE_CONTRACT.md +1 -1
  214. package/packages/snapcompact/THIRD_PARTY_LICENSES.txt +40 -0
  215. package/packages/snapcompact/assets/8x13-latin1.bdf +3837 -0
  216. package/packages/snapcompact/index.d.ts +284 -0
  217. package/packages/snapcompact/package.json +25 -0
  218. package/packages/snapcompact/src/index.js +716 -0
  219. package/packages/storage/PACKAGE_CONTRACT.md +1 -1
  220. package/packages/terminal-console/animations.mjs +240 -0
  221. package/packages/terminal-console/auto-anchor.mjs +220 -0
  222. package/packages/terminal-console/banner.mjs +91 -0
  223. package/packages/terminal-console/commands.mjs +459 -0
  224. package/packages/terminal-console/delegation.mjs +152 -0
  225. package/packages/terminal-console/index.mjs +5 -0
  226. package/packages/terminal-console/outbox.mjs +143 -0
  227. package/packages/terminal-console/phantom-bridge.mjs +637 -0
  228. package/packages/terminal-console/repl.mjs +136 -0
  229. package/packages/terminal-console/signer-store.mjs +130 -0
  230. package/packages/terminal-console/solana-rpc.mjs +214 -0
  231. package/packages/terminal-console/solana-transport.mjs +189 -0
  232. package/packages/terminal-tui/dashboard.mjs +214 -0
  233. package/packages/terminal-tui/index.mjs +28 -0
  234. package/packages/terminal-tui/merkle-tree-renderer.mjs +268 -0
  235. package/packages/terminal-tui/telemetry-hud.mjs +137 -0
  236. package/packages/vault/index.d.ts +449 -0
  237. package/packages/vault/package.json +27 -0
  238. package/packages/vault/src/e2ee.mjs +393 -0
  239. package/packages/vault/src/enclave.js +481 -0
  240. package/packages/vault/src/erasure.js +207 -0
  241. package/packages/vault/src/index.js +1150 -125
  242. package/packages/vault/src/persistence.js +307 -0
  243. package/packages/vault/src/poseidon.js +354 -0
  244. package/packages/vault/src/receipt.js +459 -0
  245. package/scripts/benchmark-optical-context.mjs +166 -0
  246. package/scripts/bootstrap-enigma.mjs +502 -0
  247. package/scripts/build-edge-backend-workers.mjs +20 -5
  248. package/scripts/build-goal-completion-audit.mjs +72 -25
  249. package/scripts/build-hosted-api-key-lifecycle.mjs +292 -274
  250. package/scripts/build-hosted-customer-lifecycle.mjs +493 -476
  251. package/scripts/build-hosted-probe-worker.mjs +19 -4
  252. package/scripts/build-installer-assets.mjs +409 -389
  253. package/scripts/build-operator-evidence-starter.mjs +59 -1
  254. package/scripts/build-production-backend-env-kit.mjs +2 -0
  255. package/scripts/build-production-unblocker.mjs +4 -1
  256. package/scripts/build-proof-network-packet.mjs +213 -213
  257. package/scripts/check.mjs +25 -4
  258. package/scripts/collect-hosted-backend-live-evidence.mjs +49 -12
  259. package/scripts/install-enigma-local.mjs +18 -5
  260. package/scripts/release-audit.mjs +74 -115
  261. package/scripts/release-provenance.mjs +12 -2
  262. package/scripts/run-backend-readiness-smoke.mjs +112 -10
  263. package/scripts/run-standard-memory-benchmarks.mjs +1354 -1352
  264. package/scripts/scan-secrets.mjs +178 -0
  265. package/scripts/simulate-production-env.mjs +71 -10
  266. package/scripts/validate-hosted-backend-live.mjs +112 -1
  267. package/specs/antibody-pack-v1.schema.json +95 -0
  268. package/specs/antigen-envelope-v1.schema.json +81 -0
  269. package/specs/boundary-manifest-v1.schema.json +35 -35
  270. package/specs/capsule-v1.schema.json +55 -55
  271. package/specs/claim-boundary-manifest-v1.schema.json +22 -22
  272. package/specs/claim-ledger-v1.schema.json +291 -0
  273. package/specs/context-passport-v1.schema.json +59 -0
  274. package/specs/deletion-tombstone-v1.schema.json +26 -26
  275. package/specs/evidence-packet-v1.schema.json +177 -0
  276. package/specs/hosted-backend-live-evidence-v1.schema.json +72 -3
  277. package/specs/immune-scan-report-v1.schema.json +112 -0
  278. package/specs/lifecycle-receipt-log-v1.schema.json +67 -0
  279. package/specs/memory-atom-v1.schema.json +59 -0
  280. package/specs/memory-event-v1.schema.json +42 -42
  281. package/specs/passport-v1.schema.json +50 -50
  282. package/specs/proof-of-non-use-v1.schema.json +65 -0
  283. package/specs/quarantine-record-v1.schema.json +126 -0
  284. package/specs/receipt-v1.schema.json +61 -61
  285. package/specs/state-checkpoint-v1.schema.json +37 -37
  286. package/specs/trust-bundle-v1.schema.json +56 -56
  287. package/specs/trust-card-v1.schema.json +119 -0
  288. package/docs/proof-network-launch-plan.md +0 -421
  289. package/packages/metering/PACKAGE_CONTRACT.md +0 -20
  290. package/scripts/build-ai-orchestration-plan.mjs +0 -248
@@ -1,476 +1,493 @@
1
- #!/usr/bin/env node
2
- import { writeFile } from 'node:fs/promises';
3
- import { fileURLToPath } from 'node:url';
4
- import { resolve } from 'node:path';
5
-
6
- import {
7
- HOSTED_CLOUD_API_KEY_SCHEMA,
8
- HOSTED_CLOUD_BACKUP_DRILL_SCHEMA,
9
- HOSTED_CLOUD_DASHBOARD_SCHEMA,
10
- HOSTED_CLOUD_CUSTOMER_LIFECYCLE_PACKET_SCHEMA,
11
- HOSTED_CLOUD_CUSTOMER_LIFECYCLE_PHASES,
12
- HOSTED_CLOUD_EXTERNAL_BLOCKERS,
13
- HOSTED_CLOUD_INCIDENT_SLA_SCHEMA,
14
- HOSTED_CLOUD_TENANT_SCHEMA,
15
- HOSTED_CLOUD_USAGE_BILLING_SCHEMA,
16
- HOSTED_CLOUD_USER_ACCOUNT_SCHEMA,
17
- HOSTED_CLOUD_VAULT_SCHEMA,
18
- buildApiKeyContract,
19
- buildBackupDrillContract,
20
- buildDashboardSummary,
21
- buildHostedVaultContract,
22
- buildIncidentSlaRefs,
23
- buildTenantContract,
24
- buildUsageBillingRecord,
25
- buildUserAccountContract,
26
- buildCustomerLifecyclePacket,
27
- validateCustomerLifecyclePacket,
28
- buildHostedCloudReadinessPacket,
29
- HOSTED_CLOUD_READINESS_PACKET_SCHEMA,
30
- } from 'enigma-memory/hosted-cloud';
31
-
32
- export const HOSTED_CUSTOMER_LIFECYCLE_PACKET_SCHEMA = HOSTED_CLOUD_CUSTOMER_LIFECYCLE_PACKET_SCHEMA;
33
- export const HOSTED_CUSTOMER_LIFECYCLE_RELEASE_TARGET = '0.1.17';
34
- export const HOSTED_CLOUD_READINESS_RELEASE_SCHEMA = HOSTED_CLOUD_READINESS_PACKET_SCHEMA;
35
-
36
- const PROVIDED = 'provided';
37
- const BLOCKED_MISSING = 'blocked_missing_evidence';
38
- const BLOCKED_EXTERNAL = 'blocked_external_dependency';
39
- const ALLOWED_STATUSES = new Set([PROVIDED, BLOCKED_MISSING, BLOCKED_EXTERNAL]);
40
- const STATUS_ALIASES = Object.freeze({
41
- blocked: BLOCKED_MISSING,
42
- missing: BLOCKED_MISSING,
43
- external: BLOCKED_EXTERNAL,
44
- });
45
-
46
- const CONTRACT_EVIDENCE = Object.freeze([
47
- {
48
- key: 'user_account',
49
- label: 'Hosted user account contract',
50
- schema: HOSTED_CLOUD_USER_ACCOUNT_SCHEMA,
51
- contractKey: 'user_account',
52
- idField: 'account_id',
53
- },
54
- {
55
- key: 'tenant',
56
- label: 'Hosted tenant contract',
57
- schema: HOSTED_CLOUD_TENANT_SCHEMA,
58
- contractKey: 'tenant',
59
- idField: 'tenant_id',
60
- },
61
- {
62
- key: 'hosted_vault',
63
- label: 'Hosted vault contract',
64
- schema: HOSTED_CLOUD_VAULT_SCHEMA,
65
- contractKey: 'hosted_vault',
66
- idField: 'vault_id',
67
- },
68
- {
69
- key: 'api_key_metadata',
70
- label: 'API key metadata contract',
71
- schema: HOSTED_CLOUD_API_KEY_SCHEMA,
72
- contractKey: 'api_key_metadata',
73
- idField: 'api_key_id',
74
- },
75
- {
76
- key: 'billing',
77
- label: 'Usage billing contract',
78
- schema: HOSTED_CLOUD_USAGE_BILLING_SCHEMA,
79
- contractKey: 'billing',
80
- idField: 'billing_record_id',
81
- },
82
- {
83
- key: 'dashboard',
84
- label: 'Dashboard summary contract',
85
- schema: HOSTED_CLOUD_DASHBOARD_SCHEMA,
86
- contractKey: 'dashboard',
87
- idField: 'dashboard_id',
88
- },
89
- {
90
- key: 'backup_drill',
91
- label: 'Backup drill contract',
92
- schema: HOSTED_CLOUD_BACKUP_DRILL_SCHEMA,
93
- contractKey: 'backup_drill',
94
- idField: 'backup_drill_id',
95
- },
96
- {
97
- key: 'incident_sla_refs',
98
- label: 'Incident and SLA refs contract',
99
- schema: HOSTED_CLOUD_INCIDENT_SLA_SCHEMA,
100
- contractKey: 'incident_sla_refs',
101
- idField: 'incident_sla_id',
102
- },
103
- ]);
104
- const CONTRACT_EVIDENCE_KEYS = new Set(CONTRACT_EVIDENCE.map(({ key }) => key));
105
- const EXTERNAL_BLOCKER_KEYS = new Set(HOSTED_CLOUD_EXTERNAL_BLOCKERS);
106
- const ADDITIONAL_LIFECYCLE_EVIDENCE_KEYS = Object.freeze(['monitoring']);
107
- const EVIDENCE_KEY_ALIASES = Object.freeze({
108
- account: 'user_account',
109
- vault: 'hosted_vault',
110
- api_key: 'api_key_metadata',
111
- backup: 'backup_drill',
112
- incident_sla: 'incident_sla_refs',
113
- support: 'support_ownership',
114
- legal: 'legal_docs',
115
- security_review: 'external_security_review',
116
- });
117
- export const HOSTED_CUSTOMER_LIFECYCLE_EVIDENCE_KEYS = Object.freeze([
118
- ...CONTRACT_EVIDENCE.map(({ key }) => key),
119
- ...HOSTED_CLOUD_EXTERNAL_BLOCKERS,
120
- ...ADDITIONAL_LIFECYCLE_EVIDENCE_KEYS,
121
- ]);
122
- const LIFECYCLE_EVIDENCE_KEY_SET = new Set([
123
- ...HOSTED_CUSTOMER_LIFECYCLE_EVIDENCE_KEYS,
124
- ...Object.keys(EVIDENCE_KEY_ALIASES),
125
- ]);
126
-
127
- const SECRET_VALUE_RE = /(?:Bearer\s+[A-Za-z0-9._~+/=-]{12,}|Basic\s+[A-Za-z0-9+/=-]{12,}|-----BEGIN [A-Z ]*PRIVATE KEY-----|https?:\/\/[^\s/@]+:[^\s/@]+@|sk-[A-Za-z0-9_-]{16,}|AKIA[0-9A-Z]{16}|\b(?:raw memory|plaintext prompts?|plain text prompts?|private prompts?|provider responses?|full transcript|decrypted memory|credentials?|secrets?|passwords?|private keys?|api key secret|api secrets?|access tokens?|refresh tokens?|token values?|credential material)\b)/iu;
128
- const FORBIDDEN_CLAIM_RE = /(?:token\s+(?:roi|profit|return|investment|price)|financial\s+roi|roi\s+claim|(?:roi|profit|return)\s+(?:from|on)\s+token|guaranteed\s+(?:savings|profit|return)|provider(?:-side|\s+side)?\s+(?:deletion|erasure)|model\s+(?:forgetting|forgot|erasure)|makes?\s+models?\s+forget|deleted\s+from\s+every\s+provider)/iu;
129
-
130
- function assertPublicSafeString(value, label) {
131
- if (typeof value !== 'string' || value.trim() === '') throw new Error(`${label} must be a non-empty public ref`);
132
- if (SECRET_VALUE_RE.test(value) || FORBIDDEN_CLAIM_RE.test(value)) {
133
- throw new Error(`${label} contains non-public hosted-cloud material`);
134
- }
135
- return value.trim();
136
- }
137
-
138
- function normalizeStatus(status, key) {
139
- const normalized = STATUS_ALIASES[status] ?? status;
140
- if (!ALLOWED_STATUSES.has(normalized)) throw new Error('evidence status must be provided, blocked_missing_evidence, or blocked_external_dependency');
141
- if (EXTERNAL_BLOCKER_KEYS.has(key) && normalized === BLOCKED_MISSING) return BLOCKED_EXTERNAL;
142
- if (CONTRACT_EVIDENCE_KEYS.has(key) && normalized === BLOCKED_EXTERNAL) return BLOCKED_MISSING;
143
- return normalized;
144
- }
145
-
146
- function defaultEvidenceRef(key) {
147
- const status = EXTERNAL_BLOCKER_KEYS.has(key) ? BLOCKED_EXTERNAL : BLOCKED_MISSING;
148
- return {
149
- key,
150
- status,
151
- ref: `blocked:${key}`,
152
- blocker: EXTERNAL_BLOCKER_KEYS.has(key)
153
- ? `External ${key.replaceAll('_', ' ')} evidence is not provided.`
154
- : `Public-safe ${key.replaceAll('_', ' ')} evidence is not provided.`,
155
- };
156
- }
157
-
158
- function normalizeEvidenceRecord(key, record) {
159
- const status = normalizeStatus(record.status ?? PROVIDED, key);
160
- const ref = assertPublicSafeString(record.ref, 'evidence ref');
161
- const output = { key, status, ref };
162
- if (status !== PROVIDED) output.blocker = record.blocker ?? defaultEvidenceRef(key).blocker;
163
- return output;
164
- }
165
-
166
- export function parseEvidenceRef(value) {
167
- const raw = assertPublicSafeString(value, 'evidence ref argument');
168
- const equalsIndex = raw.indexOf('=');
169
- if (equalsIndex <= 0 || equalsIndex === raw.length - 1) throw new Error('evidence refs must use key=status:ref');
170
- const rawKey = raw.slice(0, equalsIndex).trim();
171
- const key = EVIDENCE_KEY_ALIASES[rawKey] ?? rawKey;
172
- if (!LIFECYCLE_EVIDENCE_KEY_SET.has(rawKey) || !HOSTED_CUSTOMER_LIFECYCLE_EVIDENCE_KEYS.includes(key)) throw new Error(`evidence key must be one of: ${HOSTED_CUSTOMER_LIFECYCLE_EVIDENCE_KEYS.join(', ')}`);
173
- const body = raw.slice(equalsIndex + 1).trim();
174
- const colonIndex = body.indexOf(':');
175
- if (colonIndex > 0) {
176
- const possibleStatus = body.slice(0, colonIndex);
177
- if (ALLOWED_STATUSES.has(possibleStatus) || STATUS_ALIASES[possibleStatus]) {
178
- return normalizeEvidenceRecord(key, { status: possibleStatus, ref: body.slice(colonIndex + 1) });
179
- }
180
- }
181
- return normalizeEvidenceRecord(key, { status: PROVIDED, ref: body });
182
- }
183
-
184
- function normalizeEvidenceRefs(records = []) {
185
- const refs = Object.fromEntries(HOSTED_CUSTOMER_LIFECYCLE_EVIDENCE_KEYS.map((key) => [key, defaultEvidenceRef(key)]));
186
- for (const rawRecord of records) {
187
- const parsedRecord = typeof rawRecord === 'string' ? parseEvidenceRef(rawRecord) : rawRecord;
188
- const key = EVIDENCE_KEY_ALIASES[parsedRecord.key] ?? parsedRecord.key;
189
- if (!HOSTED_CUSTOMER_LIFECYCLE_EVIDENCE_KEYS.includes(key)) throw new Error(`evidence key must be one of: ${HOSTED_CUSTOMER_LIFECYCLE_EVIDENCE_KEYS.join(', ')}`);
190
- const record = { ...parsedRecord, key };
191
- refs[key] = normalizeEvidenceRecord(key, record);
192
- }
193
- return refs;
194
- }
195
-
196
- function operatorEvidenceRefsFrom(evidenceRefs) {
197
- return Object.fromEntries(HOSTED_CLOUD_EXTERNAL_BLOCKERS.map((key) => {
198
- const evidence = evidenceRefs[key];
199
- if (evidence.status === PROVIDED) return [key, { status: PROVIDED, ref: evidence.ref }];
200
- return [key, { status: BLOCKED_EXTERNAL, ref: evidence.ref, blocker: evidence.blocker }];
201
- }));
202
- }
203
-
204
- function refFor(evidenceRefs, key) {
205
- return evidenceRefs[key].ref;
206
- }
207
-
208
- function buildContractFragments({ tenantId, generatedAt, evidenceRefs }) {
209
- const operator_evidence_refs = operatorEvidenceRefsFrom(evidenceRefs);
210
- const base = { tenant_id: tenantId, generated_at: generatedAt, operator_evidence_refs };
211
- const tenant = buildTenantContract({
212
- ...base,
213
- tenant_ref: refFor(evidenceRefs, 'tenant'),
214
- policy_ref: refFor(evidenceRefs, 'tenant'),
215
- retention_policy_ref: refFor(evidenceRefs, 'tenant'),
216
- data_residency_ref: refFor(evidenceRefs, 'tenant'),
217
- });
218
- const userAccount = buildUserAccountContract({
219
- ...base,
220
- subject_ref: refFor(evidenceRefs, 'user_account'),
221
- auth_provider_user_ref: refFor(evidenceRefs, 'auth_provider'),
222
- });
223
- const hostedVault = buildHostedVaultContract({
224
- ...base,
225
- vault_ref: refFor(evidenceRefs, 'hosted_vault'),
226
- storage_ref: refFor(evidenceRefs, 'hosted_vault'),
227
- kms_key_ref: refFor(evidenceRefs, 'hosted_vault'),
228
- backup_policy_ref: refFor(evidenceRefs, 'backup_drill'),
229
- retention_policy_ref: refFor(evidenceRefs, 'tenant'),
230
- });
231
- const apiKeyMetadata = buildApiKeyContract({
232
- ...base,
233
- subject_ref: refFor(evidenceRefs, 'user_account'),
234
- key_fingerprint: `fingerprint:${refFor(evidenceRefs, 'api_key_metadata')}`,
235
- issued_at: generatedAt,
236
- rotation_ref: refFor(evidenceRefs, 'api_key_metadata'),
237
- });
238
- const billing = buildUsageBillingRecord({
239
- ...base,
240
- period_start: generatedAt,
241
- period_end: generatedAt,
242
- billing_provider_customer_ref: refFor(evidenceRefs, 'billing_provider'),
243
- usage_aggregate_ref: refFor(evidenceRefs, 'billing'),
244
- metered_event_count: 0,
245
- billable_units: 0,
246
- amount_due_minor_units: 0,
247
- });
248
- const incidentSlaRefs = buildIncidentSlaRefs({
249
- ...base,
250
- incident_response_ref: refFor(evidenceRefs, 'incident_sla_refs'),
251
- sla_policy_ref: refFor(evidenceRefs, 'incident_sla_refs'),
252
- support_owner_ref: refFor(evidenceRefs, 'support_ownership'),
253
- escalation_policy_ref: refFor(evidenceRefs, 'incident_sla_refs'),
254
- status_page_ref: refFor(evidenceRefs, 'incident_sla_refs'),
255
- });
256
- const backupDrill = buildBackupDrillContract({
257
- ...base,
258
- vault_ref: hostedVault.vault_ref,
259
- performed_at: generatedAt,
260
- backup_snapshot_ref: refFor(evidenceRefs, 'backup_drill'),
261
- restore_evidence_ref: refFor(evidenceRefs, 'backup_drill'),
262
- rpo_minutes: 0,
263
- rto_minutes: 0,
264
- });
265
- const dashboard = buildDashboardSummary({
266
- ...base,
267
- account_count: 0,
268
- active_api_key_count: 0,
269
- hosted_vault_count: 0,
270
- billing_period_ref: billing.billing_record_id,
271
- open_incident_count: 0,
272
- backup_drill_ref: backupDrill.backup_drill_id,
273
- incident_sla_ref: incidentSlaRefs.incident_sla_id,
274
- });
275
- return {
276
- user_account: userAccount,
277
- tenant,
278
- hosted_vault: hostedVault,
279
- api_key_metadata: apiKeyMetadata,
280
- billing,
281
- dashboard,
282
- backup_drill: backupDrill,
283
- incident_sla_refs: incidentSlaRefs,
284
- };
285
- }
286
-
287
- function canonicalContractsFrom(contracts) {
288
- return {
289
- account: contracts.user_account,
290
- tenant: contracts.tenant,
291
- vault: contracts.hosted_vault,
292
- api_key: contracts.api_key_metadata,
293
- billing: contracts.billing,
294
- dashboard: contracts.dashboard,
295
- backup: contracts.backup_drill,
296
- incident_sla: contracts.incident_sla_refs,
297
- };
298
- }
299
-
300
- function firstBlockedEvidence(evidenceRefs, keys) {
301
- for (const key of keys) {
302
- if (evidenceRefs[key].status !== PROVIDED) return evidenceRefs[key];
303
- }
304
- return null;
305
- }
306
-
307
- function providedLifecycleEvidence(evidence) {
308
- return { status: PROVIDED, ref: evidence.ref };
309
- }
310
-
311
- function blockedLifecycleEvidence(evidence) {
312
- return {
313
- status: BLOCKED_EXTERNAL,
314
- ref: evidence.ref,
315
- blocker: evidence.blocker,
316
- };
317
- }
318
-
319
- function coreEvidenceFor(evidenceRefs, phase, keys) {
320
- const blocked = firstBlockedEvidence(evidenceRefs, keys);
321
- if (blocked) return blockedLifecycleEvidence(blocked);
322
- return providedLifecycleEvidence(evidenceRefs[keys[0]]);
323
- }
324
-
325
- function coreRequiredEvidenceRefs(evidenceRefs) {
326
- const refs = {
327
- account: coreEvidenceFor(evidenceRefs, 'account', ['user_account', 'auth_provider']),
328
- tenant: coreEvidenceFor(evidenceRefs, 'tenant', ['tenant']),
329
- vault: coreEvidenceFor(evidenceRefs, 'vault', ['hosted_vault']),
330
- api_key: coreEvidenceFor(evidenceRefs, 'api_key', ['api_key_metadata']),
331
- billing: coreEvidenceFor(evidenceRefs, 'billing', ['billing', 'billing_provider']),
332
- dashboard: coreEvidenceFor(evidenceRefs, 'dashboard', ['dashboard']),
333
- backup: coreEvidenceFor(evidenceRefs, 'backup', ['backup_drill']),
334
- incident_sla: coreEvidenceFor(evidenceRefs, 'incident_sla', ['incident_sla_refs']),
335
- support: coreEvidenceFor(evidenceRefs, 'support', ['support_ownership']),
336
- monitoring: coreEvidenceFor(evidenceRefs, 'monitoring', ['monitoring']),
337
- legal: coreEvidenceFor(evidenceRefs, 'legal', ['legal_docs', 'data_processing_terms']),
338
- security_review: coreEvidenceFor(evidenceRefs, 'security_review', ['external_security_review']),
339
- };
340
- return Object.fromEntries(HOSTED_CLOUD_CUSTOMER_LIFECYCLE_PHASES
341
- .filter((phase) => phase !== 'operator_go_live')
342
- .map((phase) => [phase, refs[phase]]));
343
- }
344
-
345
- function scriptBoundary() {
346
- return {
347
- public_safe_packet_only: true,
348
- aggregates_contract_validators_only: true,
349
- deploys_or_calls_external_providers: false,
350
- sensitive_material_written: false,
351
- customer_content_stored: false,
352
- provider_wiring_required_elsewhere: true,
353
- };
354
- }
355
-
356
- export function buildHostedCustomerLifecyclePacket(options = {}) {
357
- const generatedAt = options.generatedAt ?? new Date().toISOString();
358
- const tenantId = assertPublicSafeString(options.tenant ?? options.tenantId ?? 'blocked:tenant', 'tenant');
359
- const domain = assertPublicSafeString(options.domain ?? 'blocked:domain', 'domain');
360
- const environment = assertPublicSafeString(options.environment ?? 'blocked:environment', 'environment');
361
- const operatorGoLiveRef = options.operatorGoLiveRef === undefined
362
- ? null
363
- : assertPublicSafeString(options.operatorGoLiveRef, 'operator go-live ref');
364
- const evidenceRefs = normalizeEvidenceRefs(options.evidenceRefs ?? []);
365
- const contractFragments = buildContractFragments({ tenantId, generatedAt, evidenceRefs });
366
- const packet = buildCustomerLifecyclePacket({
367
- generated_at: generatedAt,
368
- contracts: canonicalContractsFrom(contractFragments),
369
- required_evidence_refs: coreRequiredEvidenceRefs(evidenceRefs),
370
- operator_go_live_ref: operatorGoLiveRef,
371
- });
372
- validateCustomerLifecyclePacket(packet);
373
- return {
374
- ...packet,
375
- release_target: HOSTED_CUSTOMER_LIFECYCLE_RELEASE_TARGET,
376
- tenant_id: tenantId,
377
- domain,
378
- environment,
379
- evidence_refs: Object.fromEntries(Object.entries(evidenceRefs).map(([key, value]) => [key, { ...value }])),
380
- operator_external_evidence_refs: operatorEvidenceRefsFrom(evidenceRefs),
381
- boundary: scriptBoundary(),
382
- };
383
- }
384
-
385
- export function buildHostedCloudReadinessPacketFromArgs(options = {}) {
386
- const generatedAt = options.generatedAt ?? new Date().toISOString();
387
- const lifecyclePacket = buildHostedCustomerLifecyclePacket({ ...options, generatedAt });
388
- return buildHostedCloudReadinessPacket({
389
- generated_at: generatedAt,
390
- customer_lifecycle_packet: lifecyclePacket,
391
- operator_go_live_ref: options.operatorGoLiveRef ?? null,
392
- });
393
- }
394
-
395
- export function parseArgs(argv) {
396
- const args = {
397
- tenant: undefined,
398
- domain: undefined,
399
- environment: undefined,
400
- operatorGoLiveRef: undefined,
401
- evidenceRefs: [],
402
- readiness: false,
403
- out: undefined,
404
- help: false,
405
- };
406
- for (let index = 0; index < argv.length; index += 1) {
407
- const arg = argv[index];
408
- if (arg === '--help' || arg === '-h') {
409
- args.help = true;
410
- continue;
411
- }
412
- if (arg === '--readiness') { args.readiness = true; continue; }
413
- const readValue = (name) => {
414
- index += 1;
415
- if (index >= argv.length || argv[index].startsWith('--')) throw new Error(`${name} requires a value`);
416
- return argv[index];
417
- };
418
- if (arg === '--tenant') args.tenant = assertPublicSafeString(readValue('--tenant'), 'tenant');
419
- else if (arg === '--domain') args.domain = assertPublicSafeString(readValue('--domain'), 'domain');
420
- else if (arg === '--environment') args.environment = assertPublicSafeString(readValue('--environment'), 'environment');
421
- else if (arg === '--operator-go-live-ref') args.operatorGoLiveRef = assertPublicSafeString(readValue('--operator-go-live-ref'), 'operator go-live ref');
422
- else if (arg === '--evidence-ref') args.evidenceRefs.push(parseEvidenceRef(readValue('--evidence-ref')));
423
- else if (arg === '--out') args.out = assertPublicSafeString(readValue('--out'), 'output file');
424
- else throw new Error('unknown option; use --help');
425
- }
426
- return args;
427
- }
428
-
429
- export function usage() {
430
- return `Usage: node scripts/build-hosted-customer-lifecycle.mjs [options]
431
-
432
- Build a public-safe hosted customer lifecycle packet, or with --readiness a hosted cloud readiness aggregator packet. This script validates local contract fragments only; it does not deploy, create accounts, call providers, or write secrets.
433
-
434
- Options:
435
- --tenant <id> Tenant id. Defaults to blocked:tenant.
436
- --domain <domain> Customer domain. Defaults to blocked:domain.
437
- --environment <env> Environment label. Defaults to blocked:environment.
438
- --operator-go-live-ref <ref> Explicit operator approval evidence ref.
439
- --evidence-ref <key=status:ref> Repeatable evidence ref. key=<ref> implies provided.
440
- Status: provided, blocked_missing_evidence, blocked_external_dependency.
441
- Keys: ${HOSTED_CUSTOMER_LIFECYCLE_EVIDENCE_KEYS.join(', ')}
442
- --readiness Emit a hosted cloud readiness aggregator packet (enigma.hosted_cloud.readiness_packet.v1)
443
- that wraps the lifecycle packet and rolls all readiness surfaces plus
444
- propagated lifecycle blockers into one public-safe readiness assessment.
445
- --out <file> Also write the packet JSON to a file.
446
- --help Show this help.
447
- `;
448
- }
449
-
450
- export async function main(argv = process.argv.slice(2)) {
451
- const args = parseArgs(argv);
452
- if (args.help) {
453
- process.stdout.write(usage());
454
- return 0;
455
- }
456
- const packet = args.readiness
457
- ? buildHostedCloudReadinessPacketFromArgs(args)
458
- : buildHostedCustomerLifecyclePacket(args);
459
- const json = `${JSON.stringify(packet, null, 2)}\n`;
460
- if (args.out) {
461
- try {
462
- await writeFile(args.out, json, 'utf8');
463
- } catch {
464
- throw new Error('failed to write lifecycle packet output');
465
- }
466
- }
467
- process.stdout.write(json);
468
- return 0;
469
- }
470
-
471
- if (process.argv[1] && fileURLToPath(import.meta.url) === resolve(process.argv[1])) {
472
- main().catch((error) => {
473
- process.stderr.write(`Error: ${error?.message ?? 'failed to build lifecycle packet'}\n`);
474
- process.exitCode = 1;
475
- });
476
- }
1
+ #!/usr/bin/env node
2
+ import { writeFile } from 'node:fs/promises';
3
+ import { createHash } from 'node:crypto';
4
+ import { fileURLToPath } from 'node:url';
5
+ import { resolve } from 'node:path';
6
+
7
+ import {
8
+ HOSTED_CLOUD_API_KEY_SCHEMA,
9
+ HOSTED_CLOUD_BACKUP_DRILL_SCHEMA,
10
+ HOSTED_CLOUD_DASHBOARD_SCHEMA,
11
+ HOSTED_CLOUD_CUSTOMER_LIFECYCLE_PACKET_SCHEMA,
12
+ HOSTED_CLOUD_CUSTOMER_LIFECYCLE_PHASES,
13
+ HOSTED_CLOUD_EXTERNAL_BLOCKERS,
14
+ HOSTED_CLOUD_INCIDENT_SLA_SCHEMA,
15
+ HOSTED_CLOUD_TENANT_SCHEMA,
16
+ HOSTED_CLOUD_USAGE_BILLING_SCHEMA,
17
+ HOSTED_CLOUD_USER_ACCOUNT_SCHEMA,
18
+ HOSTED_CLOUD_VAULT_SCHEMA,
19
+ buildApiKeyContract,
20
+ buildBackupDrillContract,
21
+ buildDashboardSummary,
22
+ buildHostedVaultContract,
23
+ buildIncidentSlaRefs,
24
+ buildTenantContract,
25
+ buildUsageBillingRecord,
26
+ buildUserAccountContract,
27
+ buildCustomerLifecyclePacket,
28
+ validateCustomerLifecyclePacket,
29
+ buildHostedCloudReadinessPacket,
30
+ HOSTED_CLOUD_READINESS_PACKET_SCHEMA,
31
+ } from 'enigma-memory/hosted-cloud';
32
+
33
+ export const HOSTED_CUSTOMER_LIFECYCLE_PACKET_SCHEMA = HOSTED_CLOUD_CUSTOMER_LIFECYCLE_PACKET_SCHEMA;
34
+ export const HOSTED_CUSTOMER_LIFECYCLE_RELEASE_TARGET = '0.1.20';
35
+ export const HOSTED_CLOUD_READINESS_RELEASE_SCHEMA = HOSTED_CLOUD_READINESS_PACKET_SCHEMA;
36
+
37
+ const PROVIDED = 'provided';
38
+ const BLOCKED_MISSING = 'blocked_missing_evidence';
39
+ const BLOCKED_EXTERNAL = 'blocked_external_dependency';
40
+ const ALLOWED_STATUSES = new Set([PROVIDED, BLOCKED_MISSING, BLOCKED_EXTERNAL]);
41
+ const STATUS_ALIASES = Object.freeze({
42
+ blocked: BLOCKED_MISSING,
43
+ missing: BLOCKED_MISSING,
44
+ external: BLOCKED_EXTERNAL,
45
+ });
46
+
47
+ const CONTRACT_EVIDENCE = Object.freeze([
48
+ {
49
+ key: 'user_account',
50
+ label: 'Hosted user account contract',
51
+ schema: HOSTED_CLOUD_USER_ACCOUNT_SCHEMA,
52
+ contractKey: 'user_account',
53
+ idField: 'account_id',
54
+ },
55
+ {
56
+ key: 'tenant',
57
+ label: 'Hosted tenant contract',
58
+ schema: HOSTED_CLOUD_TENANT_SCHEMA,
59
+ contractKey: 'tenant',
60
+ idField: 'tenant_id',
61
+ },
62
+ {
63
+ key: 'hosted_vault',
64
+ label: 'Hosted vault contract',
65
+ schema: HOSTED_CLOUD_VAULT_SCHEMA,
66
+ contractKey: 'hosted_vault',
67
+ idField: 'vault_id',
68
+ },
69
+ {
70
+ key: 'api_key_metadata',
71
+ label: 'API key metadata contract',
72
+ schema: HOSTED_CLOUD_API_KEY_SCHEMA,
73
+ contractKey: 'api_key_metadata',
74
+ idField: 'api_key_id',
75
+ },
76
+ {
77
+ key: 'billing',
78
+ label: 'Usage billing contract',
79
+ schema: HOSTED_CLOUD_USAGE_BILLING_SCHEMA,
80
+ contractKey: 'billing',
81
+ idField: 'billing_record_id',
82
+ },
83
+ {
84
+ key: 'dashboard',
85
+ label: 'Dashboard summary contract',
86
+ schema: HOSTED_CLOUD_DASHBOARD_SCHEMA,
87
+ contractKey: 'dashboard',
88
+ idField: 'dashboard_id',
89
+ },
90
+ {
91
+ key: 'backup_drill',
92
+ label: 'Backup drill contract',
93
+ schema: HOSTED_CLOUD_BACKUP_DRILL_SCHEMA,
94
+ contractKey: 'backup_drill',
95
+ idField: 'backup_drill_id',
96
+ },
97
+ {
98
+ key: 'incident_sla_refs',
99
+ label: 'Incident and SLA refs contract',
100
+ schema: HOSTED_CLOUD_INCIDENT_SLA_SCHEMA,
101
+ contractKey: 'incident_sla_refs',
102
+ idField: 'incident_sla_id',
103
+ },
104
+ ]);
105
+ const CONTRACT_EVIDENCE_KEYS = new Set(CONTRACT_EVIDENCE.map(({ key }) => key));
106
+ const EXTERNAL_BLOCKER_KEYS = new Set(HOSTED_CLOUD_EXTERNAL_BLOCKERS);
107
+ const ADDITIONAL_LIFECYCLE_EVIDENCE_KEYS = Object.freeze(['monitoring']);
108
+ const EVIDENCE_KEY_ALIASES = Object.freeze({
109
+ account: 'user_account',
110
+ vault: 'hosted_vault',
111
+ api_key: 'api_key_metadata',
112
+ backup: 'backup_drill',
113
+ incident_sla: 'incident_sla_refs',
114
+ support: 'support_ownership',
115
+ legal: 'legal_docs',
116
+ security_review: 'external_security_review',
117
+ });
118
+ export const HOSTED_CUSTOMER_LIFECYCLE_EVIDENCE_KEYS = Object.freeze([
119
+ ...CONTRACT_EVIDENCE.map(({ key }) => key),
120
+ ...HOSTED_CLOUD_EXTERNAL_BLOCKERS,
121
+ ...ADDITIONAL_LIFECYCLE_EVIDENCE_KEYS,
122
+ ]);
123
+ const LIFECYCLE_EVIDENCE_KEY_SET = new Set([
124
+ ...HOSTED_CUSTOMER_LIFECYCLE_EVIDENCE_KEYS,
125
+ ...Object.keys(EVIDENCE_KEY_ALIASES),
126
+ ]);
127
+
128
+ const SECRET_VALUE_RE = /(?:Bearer\s+[A-Za-z0-9._~+/=-]{12,}|Basic\s+[A-Za-z0-9+/=-]{12,}|-----BEGIN [A-Z ]*PRIVATE KEY-----|https?:\/\/[^\s/@]+:[^\s/@]+@|sk-[A-Za-z0-9_-]{16,}|AKIA[0-9A-Z]{16}|\b(?:raw memory|plaintext prompts?|plain text prompts?|private prompts?|provider responses?|full transcript|decrypted memory|credentials?|secrets?|passwords?|private keys?|api key secret|api secrets?|access tokens?|refresh tokens?|token values?|credential material)\b)/iu;
129
+ const FORBIDDEN_CLAIM_RE = /(?:token\s+(?:roi|profit|return|investment|price)|financial\s+roi|roi\s+claim|(?:roi|profit|return)\s+(?:from|on)\s+token|guaranteed\s+(?:savings|profit|return)|provider(?:-side|\s+side)?\s+(?:deletion|erasure)|model\s+(?:forgetting|forgot|erasure)|makes?\s+models?\s+forget|deleted\s+from\s+every\s+provider)/iu;
130
+
131
+ function assertPublicSafeString(value, label) {
132
+ if (typeof value !== 'string' || value.trim() === '') throw new Error(`${label} must be a non-empty public ref`);
133
+ if (SECRET_VALUE_RE.test(value) || FORBIDDEN_CLAIM_RE.test(value)) {
134
+ throw new Error(`${label} contains non-public hosted-cloud material`);
135
+ }
136
+ return value.trim();
137
+ }
138
+
139
+ function normalizeStatus(status, key) {
140
+ const normalized = STATUS_ALIASES[status] ?? status;
141
+ if (!ALLOWED_STATUSES.has(normalized)) throw new Error('evidence status must be provided, blocked_missing_evidence, or blocked_external_dependency');
142
+ if (EXTERNAL_BLOCKER_KEYS.has(key) && normalized === BLOCKED_MISSING) return BLOCKED_EXTERNAL;
143
+ if (CONTRACT_EVIDENCE_KEYS.has(key) && normalized === BLOCKED_EXTERNAL) return BLOCKED_MISSING;
144
+ return normalized;
145
+ }
146
+
147
+ function defaultEvidenceRef(key) {
148
+ const status = EXTERNAL_BLOCKER_KEYS.has(key) ? BLOCKED_EXTERNAL : BLOCKED_MISSING;
149
+ return {
150
+ key,
151
+ status,
152
+ ref: `blocked:${key}`,
153
+ blocker: EXTERNAL_BLOCKER_KEYS.has(key)
154
+ ? `External ${key.replaceAll('_', ' ')} evidence is not provided.`
155
+ : `Public-safe ${key.replaceAll('_', ' ')} evidence is not provided.`,
156
+ };
157
+ }
158
+
159
+ function normalizeEvidenceRecord(key, record) {
160
+ const status = normalizeStatus(record.status ?? PROVIDED, key);
161
+ const ref = assertPublicSafeString(record.ref, 'evidence ref');
162
+ const output = { key, status, ref };
163
+ if (status !== PROVIDED) output.blocker = record.blocker ?? defaultEvidenceRef(key).blocker;
164
+ return output;
165
+ }
166
+
167
+ export function parseEvidenceRef(value) {
168
+ const raw = assertPublicSafeString(value, 'evidence ref argument');
169
+ const equalsIndex = raw.indexOf('=');
170
+ if (equalsIndex <= 0 || equalsIndex === raw.length - 1) throw new Error('evidence refs must use key=status:ref');
171
+ const rawKey = raw.slice(0, equalsIndex).trim();
172
+ const key = EVIDENCE_KEY_ALIASES[rawKey] ?? rawKey;
173
+ if (!LIFECYCLE_EVIDENCE_KEY_SET.has(rawKey) || !HOSTED_CUSTOMER_LIFECYCLE_EVIDENCE_KEYS.includes(key)) throw new Error(`evidence key must be one of: ${HOSTED_CUSTOMER_LIFECYCLE_EVIDENCE_KEYS.join(', ')}`);
174
+ const body = raw.slice(equalsIndex + 1).trim();
175
+ const colonIndex = body.indexOf(':');
176
+ if (colonIndex > 0) {
177
+ const possibleStatus = body.slice(0, colonIndex);
178
+ if (ALLOWED_STATUSES.has(possibleStatus) || STATUS_ALIASES[possibleStatus]) {
179
+ return normalizeEvidenceRecord(key, { status: possibleStatus, ref: body.slice(colonIndex + 1) });
180
+ }
181
+ }
182
+ return normalizeEvidenceRecord(key, { status: PROVIDED, ref: body });
183
+ }
184
+
185
+ function normalizeEvidenceRefs(records = []) {
186
+ const refs = Object.fromEntries(HOSTED_CUSTOMER_LIFECYCLE_EVIDENCE_KEYS.map((key) => [key, defaultEvidenceRef(key)]));
187
+ for (const rawRecord of records) {
188
+ const parsedRecord = typeof rawRecord === 'string' ? parseEvidenceRef(rawRecord) : rawRecord;
189
+ const key = EVIDENCE_KEY_ALIASES[parsedRecord.key] ?? parsedRecord.key;
190
+ if (!HOSTED_CUSTOMER_LIFECYCLE_EVIDENCE_KEYS.includes(key)) throw new Error(`evidence key must be one of: ${HOSTED_CUSTOMER_LIFECYCLE_EVIDENCE_KEYS.join(', ')}`);
191
+ const record = { ...parsedRecord, key };
192
+ refs[key] = normalizeEvidenceRecord(key, record);
193
+ }
194
+ return refs;
195
+ }
196
+
197
+ function operatorEvidenceRefsFrom(evidenceRefs) {
198
+ return Object.fromEntries(HOSTED_CLOUD_EXTERNAL_BLOCKERS.map((key) => {
199
+ const evidence = evidenceRefs[key];
200
+ if (evidence.status === PROVIDED) return [key, { status: PROVIDED, ref: evidence.ref }];
201
+ return [key, { status: BLOCKED_EXTERNAL, ref: evidence.ref, blocker: evidence.blocker }];
202
+ }));
203
+ }
204
+
205
+ function refFor(evidenceRefs, key) {
206
+ return evidenceRefs[key].ref;
207
+ }
208
+
209
+ function buildContractFragments({ tenantId, generatedAt, evidenceRefs }) {
210
+ const operator_evidence_refs = operatorEvidenceRefsFrom(evidenceRefs);
211
+ const base = { tenant_id: tenantId, generated_at: generatedAt, operator_evidence_refs };
212
+ const tenant = buildTenantContract({
213
+ ...base,
214
+ tenant_ref: refFor(evidenceRefs, 'tenant'),
215
+ policy_ref: refFor(evidenceRefs, 'tenant'),
216
+ retention_policy_ref: refFor(evidenceRefs, 'tenant'),
217
+ data_residency_ref: refFor(evidenceRefs, 'tenant'),
218
+ });
219
+ const userAccount = buildUserAccountContract({
220
+ ...base,
221
+ subject_ref: refFor(evidenceRefs, 'user_account'),
222
+ auth_provider_user_ref: refFor(evidenceRefs, 'auth_provider'),
223
+ });
224
+ const hostedVault = buildHostedVaultContract({
225
+ ...base,
226
+ vault_ref: refFor(evidenceRefs, 'hosted_vault'),
227
+ storage_ref: refFor(evidenceRefs, 'hosted_vault'),
228
+ kms_key_ref: refFor(evidenceRefs, 'hosted_vault'),
229
+ backup_policy_ref: refFor(evidenceRefs, 'backup_drill'),
230
+ retention_policy_ref: refFor(evidenceRefs, 'tenant'),
231
+ });
232
+ const apiKeyMetadata = buildApiKeyContract({
233
+ ...base,
234
+ subject_ref: refFor(evidenceRefs, 'user_account'),
235
+ key_fingerprint: `fingerprint:${refFor(evidenceRefs, 'api_key_metadata')}`,
236
+ issued_at: generatedAt,
237
+ rotation_ref: refFor(evidenceRefs, 'api_key_metadata'),
238
+ });
239
+ const billing = buildUsageBillingRecord({
240
+ ...base,
241
+ period_start: generatedAt,
242
+ period_end: generatedAt,
243
+ billing_provider_customer_ref: refFor(evidenceRefs, 'billing_provider'),
244
+ usage_aggregate_ref: refFor(evidenceRefs, 'billing'),
245
+ metered_event_count: 0,
246
+ billable_units: 0,
247
+ amount_due_minor_units: 0,
248
+ });
249
+ const incidentSlaRefs = buildIncidentSlaRefs({
250
+ ...base,
251
+ incident_response_ref: refFor(evidenceRefs, 'incident_sla_refs'),
252
+ sla_policy_ref: refFor(evidenceRefs, 'incident_sla_refs'),
253
+ support_owner_ref: refFor(evidenceRefs, 'support_ownership'),
254
+ escalation_policy_ref: refFor(evidenceRefs, 'incident_sla_refs'),
255
+ status_page_ref: refFor(evidenceRefs, 'incident_sla_refs'),
256
+ });
257
+ const backupDrill = buildBackupDrillContract({
258
+ ...base,
259
+ vault_ref: hostedVault.vault_ref,
260
+ performed_at: generatedAt,
261
+ backup_snapshot_ref: refFor(evidenceRefs, 'backup_drill'),
262
+ restore_evidence_ref: refFor(evidenceRefs, 'backup_drill'),
263
+ rpo_minutes: 0,
264
+ rto_minutes: 0,
265
+ });
266
+ const dashboard = buildDashboardSummary({
267
+ ...base,
268
+ account_count: 0,
269
+ active_api_key_count: 0,
270
+ hosted_vault_count: 0,
271
+ billing_period_ref: billing.billing_record_id,
272
+ open_incident_count: 0,
273
+ backup_drill_ref: backupDrill.backup_drill_id,
274
+ incident_sla_ref: incidentSlaRefs.incident_sla_id,
275
+ });
276
+ return {
277
+ user_account: userAccount,
278
+ tenant,
279
+ hosted_vault: hostedVault,
280
+ api_key_metadata: apiKeyMetadata,
281
+ billing,
282
+ dashboard,
283
+ backup_drill: backupDrill,
284
+ incident_sla_refs: incidentSlaRefs,
285
+ };
286
+ }
287
+
288
+ function canonicalContractsFrom(contracts) {
289
+ return {
290
+ account: contracts.user_account,
291
+ tenant: contracts.tenant,
292
+ vault: contracts.hosted_vault,
293
+ api_key: contracts.api_key_metadata,
294
+ billing: contracts.billing,
295
+ dashboard: contracts.dashboard,
296
+ backup: contracts.backup_drill,
297
+ incident_sla: contracts.incident_sla_refs,
298
+ };
299
+ }
300
+
301
+ function firstBlockedEvidence(evidenceRefs, keys) {
302
+ for (const key of keys) {
303
+ if (evidenceRefs[key].status !== PROVIDED) return evidenceRefs[key];
304
+ }
305
+ return null;
306
+ }
307
+
308
+ function providedLifecycleEvidence(evidence) {
309
+ return { status: PROVIDED, ref: evidence.ref };
310
+ }
311
+
312
+ function blockedLifecycleEvidence(evidence) {
313
+ return {
314
+ status: BLOCKED_EXTERNAL,
315
+ ref: evidence.ref,
316
+ blocker: evidence.blocker,
317
+ };
318
+ }
319
+
320
+ function coreEvidenceFor(evidenceRefs, phase, keys) {
321
+ const blocked = firstBlockedEvidence(evidenceRefs, keys);
322
+ if (blocked) return blockedLifecycleEvidence(blocked);
323
+ return providedLifecycleEvidence(evidenceRefs[keys[0]]);
324
+ }
325
+
326
+ function coreRequiredEvidenceRefs(evidenceRefs) {
327
+ const refs = {
328
+ account: coreEvidenceFor(evidenceRefs, 'account', ['user_account', 'auth_provider']),
329
+ tenant: coreEvidenceFor(evidenceRefs, 'tenant', ['tenant']),
330
+ vault: coreEvidenceFor(evidenceRefs, 'vault', ['hosted_vault']),
331
+ api_key: coreEvidenceFor(evidenceRefs, 'api_key', ['api_key_metadata']),
332
+ billing: coreEvidenceFor(evidenceRefs, 'billing', ['billing', 'billing_provider']),
333
+ dashboard: coreEvidenceFor(evidenceRefs, 'dashboard', ['dashboard']),
334
+ backup: coreEvidenceFor(evidenceRefs, 'backup', ['backup_drill']),
335
+ incident_sla: coreEvidenceFor(evidenceRefs, 'incident_sla', ['incident_sla_refs']),
336
+ support: coreEvidenceFor(evidenceRefs, 'support', ['support_ownership']),
337
+ monitoring: coreEvidenceFor(evidenceRefs, 'monitoring', ['monitoring']),
338
+ legal: coreEvidenceFor(evidenceRefs, 'legal', ['legal_docs', 'data_processing_terms']),
339
+ security_review: coreEvidenceFor(evidenceRefs, 'security_review', ['external_security_review']),
340
+ };
341
+ return Object.fromEntries(HOSTED_CLOUD_CUSTOMER_LIFECYCLE_PHASES
342
+ .filter((phase) => phase !== 'operator_go_live')
343
+ .map((phase) => [phase, refs[phase]]));
344
+ }
345
+
346
+ function canonicalize(value) {
347
+ if (Array.isArray(value)) return value.map(canonicalize);
348
+ if (value !== null && typeof value === 'object') {
349
+ return Object.fromEntries(Object.keys(value).sort().map((key) => [key, canonicalize(value[key])]));
350
+ }
351
+ return value;
352
+ }
353
+
354
+ function withCanonicalContractHash(value) {
355
+ const { contract_hash: _staleHash, ...canonicalFields } = value;
356
+ return {
357
+ ...canonicalFields,
358
+ contract_hash: `sha256:${createHash('sha256').update(JSON.stringify(canonicalize(canonicalFields))).digest('hex')}`,
359
+ };
360
+ }
361
+
362
+ function scriptBoundary() {
363
+ return {
364
+ public_safe_packet_only: true,
365
+ aggregates_contract_validators_only: true,
366
+ deploys_or_calls_external_providers: false,
367
+ sensitive_material_written: false,
368
+ customer_content_stored: false,
369
+ provider_wiring_required_elsewhere: true,
370
+ };
371
+ }
372
+
373
+ export function buildHostedCustomerLifecyclePacket(options = {}) {
374
+ const generatedAt = options.generatedAt ?? new Date().toISOString();
375
+ const tenantId = assertPublicSafeString(options.tenant ?? options.tenantId ?? 'blocked:tenant', 'tenant');
376
+ const domain = assertPublicSafeString(options.domain ?? 'blocked:domain', 'domain');
377
+ const environment = assertPublicSafeString(options.environment ?? 'blocked:environment', 'environment');
378
+ const operatorGoLiveRef = options.operatorGoLiveRef === undefined
379
+ ? null
380
+ : assertPublicSafeString(options.operatorGoLiveRef, 'operator go-live ref');
381
+ const evidenceRefs = normalizeEvidenceRefs(options.evidenceRefs ?? []);
382
+ const contractFragments = buildContractFragments({ tenantId, generatedAt, evidenceRefs });
383
+ const packet = buildCustomerLifecyclePacket({
384
+ generated_at: generatedAt,
385
+ contracts: canonicalContractsFrom(contractFragments),
386
+ required_evidence_refs: coreRequiredEvidenceRefs(evidenceRefs),
387
+ operator_go_live_ref: operatorGoLiveRef,
388
+ });
389
+ validateCustomerLifecyclePacket(packet);
390
+ return withCanonicalContractHash({
391
+ ...packet,
392
+ release_target: HOSTED_CUSTOMER_LIFECYCLE_RELEASE_TARGET,
393
+ tenant_id: tenantId,
394
+ domain,
395
+ environment,
396
+ evidence_refs: Object.fromEntries(Object.entries(evidenceRefs).map(([key, value]) => [key, { ...value }])),
397
+ operator_external_evidence_refs: operatorEvidenceRefsFrom(evidenceRefs),
398
+ boundary: scriptBoundary(),
399
+ });
400
+ }
401
+
402
+ export function buildHostedCloudReadinessPacketFromArgs(options = {}) {
403
+ const generatedAt = options.generatedAt ?? new Date().toISOString();
404
+ const lifecyclePacket = buildHostedCustomerLifecyclePacket({ ...options, generatedAt });
405
+ return buildHostedCloudReadinessPacket({
406
+ generated_at: generatedAt,
407
+ customer_lifecycle_packet: lifecyclePacket,
408
+ operator_go_live_ref: options.operatorGoLiveRef ?? null,
409
+ });
410
+ }
411
+
412
+ export function parseArgs(argv) {
413
+ const args = {
414
+ tenant: undefined,
415
+ domain: undefined,
416
+ environment: undefined,
417
+ operatorGoLiveRef: undefined,
418
+ evidenceRefs: [],
419
+ readiness: false,
420
+ out: undefined,
421
+ help: false,
422
+ };
423
+ for (let index = 0; index < argv.length; index += 1) {
424
+ const arg = argv[index];
425
+ if (arg === '--help' || arg === '-h') {
426
+ args.help = true;
427
+ continue;
428
+ }
429
+ if (arg === '--readiness') { args.readiness = true; continue; }
430
+ const readValue = (name) => {
431
+ index += 1;
432
+ if (index >= argv.length || argv[index].startsWith('--')) throw new Error(`${name} requires a value`);
433
+ return argv[index];
434
+ };
435
+ if (arg === '--tenant') args.tenant = assertPublicSafeString(readValue('--tenant'), 'tenant');
436
+ else if (arg === '--domain') args.domain = assertPublicSafeString(readValue('--domain'), 'domain');
437
+ else if (arg === '--environment') args.environment = assertPublicSafeString(readValue('--environment'), 'environment');
438
+ else if (arg === '--operator-go-live-ref') args.operatorGoLiveRef = assertPublicSafeString(readValue('--operator-go-live-ref'), 'operator go-live ref');
439
+ else if (arg === '--evidence-ref') args.evidenceRefs.push(parseEvidenceRef(readValue('--evidence-ref')));
440
+ else if (arg === '--out') args.out = assertPublicSafeString(readValue('--out'), 'output file');
441
+ else throw new Error('unknown option; use --help');
442
+ }
443
+ return args;
444
+ }
445
+
446
+ export function usage() {
447
+ return `Usage: node scripts/build-hosted-customer-lifecycle.mjs [options]
448
+
449
+ Build a public-safe hosted customer lifecycle packet, or with --readiness a hosted cloud readiness aggregator packet. This script validates local contract fragments only; it does not deploy, create accounts, call providers, or write secrets.
450
+
451
+ Options:
452
+ --tenant <id> Tenant id. Defaults to blocked:tenant.
453
+ --domain <domain> Customer domain. Defaults to blocked:domain.
454
+ --environment <env> Environment label. Defaults to blocked:environment.
455
+ --operator-go-live-ref <ref> Explicit operator approval evidence ref.
456
+ --evidence-ref <key=status:ref> Repeatable evidence ref. key=<ref> implies provided.
457
+ Status: provided, blocked_missing_evidence, blocked_external_dependency.
458
+ Keys: ${HOSTED_CUSTOMER_LIFECYCLE_EVIDENCE_KEYS.join(', ')}
459
+ --readiness Emit a hosted cloud readiness aggregator packet (enigma.hosted_cloud.readiness_packet.v1)
460
+ that wraps the lifecycle packet and rolls all readiness surfaces plus
461
+ propagated lifecycle blockers into one public-safe readiness assessment.
462
+ --out <file> Also write the packet JSON to a file.
463
+ --help Show this help.
464
+ `;
465
+ }
466
+
467
+ export async function main(argv = process.argv.slice(2)) {
468
+ const args = parseArgs(argv);
469
+ if (args.help) {
470
+ process.stdout.write(usage());
471
+ return 0;
472
+ }
473
+ const packet = args.readiness
474
+ ? buildHostedCloudReadinessPacketFromArgs(args)
475
+ : buildHostedCustomerLifecyclePacket(args);
476
+ const json = `${JSON.stringify(packet, null, 2)}\n`;
477
+ if (args.out) {
478
+ try {
479
+ await writeFile(args.out, json, 'utf8');
480
+ } catch {
481
+ throw new Error('failed to write lifecycle packet output');
482
+ }
483
+ }
484
+ process.stdout.write(json);
485
+ return 0;
486
+ }
487
+
488
+ if (process.argv[1] && fileURLToPath(import.meta.url) === resolve(process.argv[1])) {
489
+ main().catch((error) => {
490
+ process.stderr.write(`Error: ${error?.message ?? 'failed to build lifecycle packet'}\n`);
491
+ process.exitCode = 1;
492
+ });
493
+ }