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
@@ -0,0 +1,178 @@
1
+ #!/usr/bin/env node
2
+ // Enigma Memory — working-tree secret scanner.
3
+ // Scans for PEM private keys, bearer-token patterns, DSNs, AWS-style keys,
4
+ // and literal SECURITY.md placeholders. Approved test fixtures must carry an
5
+ // explicit approval comment on the same or previous non-empty line:
6
+ // // secret-scan:approved
7
+ // # secret-scan:approved
8
+ // This script exits non-zero when any unapproved detection remains.
9
+
10
+ import fs from 'node:fs'
11
+ import path from 'node:path'
12
+ import { fileURLToPath, pathToFileURL } from 'node:url'
13
+
14
+ const __filename = fileURLToPath(import.meta.url)
15
+ const APPROVAL_MARKERS = [
16
+ /secret-scan:(?:approved|ignore)/i,
17
+ /\bno[-_]?secret[-_]?scan\b/i,
18
+ ]
19
+
20
+ const SKIP_DIRS = new Set([
21
+ 'node_modules',
22
+ '.git',
23
+ '.enigma',
24
+ '.enigma-review-packet',
25
+ '.enigma-review-packet-debug',
26
+ 'coverage',
27
+ 'dist',
28
+ 'build',
29
+ '.cache',
30
+ 'tmp',
31
+ '.vscode',
32
+ '.idea',
33
+ '.next',
34
+ ])
35
+
36
+ const SKIP_EXTENSIONS = new Set([
37
+ '.png',
38
+ '.jpg',
39
+ '.jpeg',
40
+ '.gif',
41
+ '.webp',
42
+ '.svg',
43
+ '.ico',
44
+ '.pdf',
45
+ '.zip',
46
+ '.tar',
47
+ '.gz',
48
+ '.tgz',
49
+ '.woff',
50
+ '.woff2',
51
+ '.ttf',
52
+ '.otf',
53
+ '.eot',
54
+ '.mp4',
55
+ '.webm',
56
+ '.mp3',
57
+ '.ogg',
58
+ ])
59
+
60
+ // The security-placeholder detector matches its own pattern literal below.
61
+ // The preceding comment marks that line as an approved self-reference.
62
+ const DETECTORS = [
63
+ {
64
+ id: 'pem-private-key',
65
+ pattern: /-----BEGIN\s+(?:RSA\s+|EC\s+|DSA\s+|OPENSSH\s+|ENCRYPTED\s+)?PRIVATE\s+KEY-----/i,
66
+ },
67
+ {
68
+ id: 'aws-access-key-id',
69
+ pattern: /\b(?:AKIA|ASIA|AROA|AIDA)[0-9A-Z]{16}\b/,
70
+ },
71
+ {
72
+ id: 'aws-secret-access-key',
73
+ pattern: /\b(?:aws[_-]?secret[_-]?access[_-]?key|AWS[_-]?SECRET[_-]?ACCESS[_-]?KEY)\s*[=:]\s*["'][A-Za-z0-9/+=]{40}["']/i,
74
+ },
75
+ {
76
+ id: 'bearer-token',
77
+ // Skip placeholders like <token>, ${var}, and $ENV_VAR.
78
+ pattern: /(?:Authorization\s*:\s*Bearer\s+(?![<$\(])\S{8,}|\bbearer\s+[:=]\s*["']?[a-zA-Z0-9_\-]{16,}|\bapi[_-]?token\s*[:=]\s*["'][a-zA-Z0-9_\-]{16,}["'])/i,
79
+ },
80
+ {
81
+ id: 'dsn-with-password',
82
+ pattern: /\b(?:postgres|postgresql|mysql|mysql2|mongodb|redis|amqp|amqps):\/\/[^:]+:[^@\s]+@[^\/\s]+/i,
83
+ },
84
+ {
85
+ id: 'security-placeholder',
86
+ pattern: /REPLACE-WITH/i, // secret-scan:approved self-reference pattern
87
+ },
88
+ ]
89
+
90
+ function hasApprovalComment(line) {
91
+ return APPROVAL_MARKERS.some((m) => m.test(line))
92
+ }
93
+
94
+ function isApproved(lines, index) {
95
+ if (hasApprovalComment(lines[index])) return true
96
+ for (let i = index - 1; i >= 0; i -= 1) {
97
+ const trimmed = lines[i].trim()
98
+ if (trimmed === '') continue
99
+ return hasApprovalComment(trimmed)
100
+ }
101
+ return false
102
+ }
103
+
104
+ function isSkippableFile(rel) {
105
+ const ext = path.extname(rel).toLowerCase()
106
+ if (SKIP_EXTENSIONS.has(ext)) return true
107
+ const base = path.basename(rel)
108
+ if (base === 'package-lock.json') return true
109
+ return false
110
+ }
111
+
112
+ function* walk(root) {
113
+ const entries = fs.readdirSync(root, { withFileTypes: true })
114
+ for (const entry of entries) {
115
+ const full = path.join(root, entry.name)
116
+ if (entry.isDirectory()) {
117
+ if (SKIP_DIRS.has(entry.name)) continue
118
+ yield* walk(full)
119
+ } else if (entry.isFile()) {
120
+ yield full
121
+ }
122
+ }
123
+ }
124
+
125
+ export function scanForSecrets(root) {
126
+ const findings = []
127
+ const rootResolved = path.resolve(root)
128
+ for (const fullPath of walk(rootResolved)) {
129
+ const rel = path.relative(rootResolved, fullPath)
130
+ if (isSkippableFile(rel)) continue
131
+ let text
132
+ try {
133
+ text = fs.readFileSync(fullPath, 'utf8')
134
+ } catch {
135
+ continue
136
+ }
137
+ const lines = text.split(/\r?\n/)
138
+ for (let i = 0; i < lines.length; i += 1) {
139
+ const line = lines[i]
140
+ if (isApproved(lines, i)) continue
141
+ for (const detector of DETECTORS) {
142
+ if (detector.pattern.test(line)) {
143
+ findings.push({
144
+ file: rel,
145
+ line: i + 1,
146
+ type: detector.id,
147
+ })
148
+ break
149
+ }
150
+ }
151
+ }
152
+ }
153
+ return findings
154
+ }
155
+
156
+ function formatFindings(findings) {
157
+ return findings
158
+ .map((f) => `${f.file}:${f.line}: ${f.type}`)
159
+ .join('\n')
160
+ }
161
+
162
+ function main() {
163
+ const rootArg = process.argv.includes('--root')
164
+ ? process.argv[process.argv.indexOf('--root') + 1]
165
+ : path.resolve(path.dirname(__filename), '..')
166
+ const root = path.resolve(rootArg)
167
+ const findings = scanForSecrets(root)
168
+ if (findings.length > 0) {
169
+ process.stderr.write(`secret-scan: ${findings.length} unapproved detection(s)\n`)
170
+ process.stderr.write(formatFindings(findings) + '\n')
171
+ process.exit(1)
172
+ }
173
+ process.stdout.write('secret-scan ok\n')
174
+ }
175
+
176
+ if (import.meta.url === pathToFileURL(process.argv[1]).href) {
177
+ main()
178
+ }
@@ -5,13 +5,15 @@
5
5
  // are not production secrets, HSM custody, or real operator evidence.
6
6
 
7
7
  import { spawnSync } from 'node:child_process'
8
- import { generateKeyPairSync, randomUUID } from 'node:crypto'
8
+ import { createHash, generateKeyPairSync, randomUUID } from 'node:crypto'
9
9
  import fs from 'node:fs'
10
+ import os from 'node:os'
10
11
  import path from 'node:path'
11
12
  import { fileURLToPath } from 'node:url'
12
13
 
13
14
  const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..')
14
- const DEFAULT_SECRETS_DIR = path.join(ROOT, 'deploy', 'secrets-simulation')
15
+ const DEFAULT_SECRETS_DIR = path.join(os.homedir(), '.enigma', 'simulation-secrets')
16
+ const DOCKER_READABLE_SECRET_MODE = 0o644
15
17
 
16
18
  const REQUIRED_SECRET_FILES = [
17
19
  'relay-signing-key',
@@ -27,6 +29,11 @@ const REQUIRED_SECRET_FILES = [
27
29
  'tls.key',
28
30
  ]
29
31
 
32
+ const BEARER_FILES_FOR_DIGEST = {
33
+ 'gateway-admin-auth-bearer': 'ENIGMA_GATEWAY_ADMIN_AUTH_BEARER_SHA256',
34
+ 'gateway-data-plane-auth-bearer': 'ENIGMA_GATEWAY_DATA_PLANE_AUTH_BEARER_SHA256',
35
+ }
36
+
30
37
  function parseArgs(argv) {
31
38
  const flags = { check: false, secretsDir: DEFAULT_SECRETS_DIR }
32
39
  for (let i = 0; i < argv.length; i += 1) {
@@ -41,8 +48,9 @@ function parseArgs(argv) {
41
48
  process.stdout.write(
42
49
  'Usage: node scripts/simulate-production-env.mjs [--check] [--secrets-dir <dir>]\n' +
43
50
  '\n' +
44
- 'Generates local-simulation secret files and a self-signed TLS certificate\n' +
45
- `under ${DEFAULT_SECRETS_DIR} (customizable with --secrets-dir).\n` +
51
+ 'Generates local-simulation secret files and a self-signed TLS certificate.\n' +
52
+ `By default files are written outside the repo to ${DEFAULT_SECRETS_DIR}.\n` +
53
+ 'A path inside the repository is rejected to prevent accidental commits.\n' +
46
54
  'Run with --check to verify required files exist and are non-empty.\n'
47
55
  )
48
56
  process.exit(0)
@@ -51,6 +59,22 @@ function parseArgs(argv) {
51
59
  return flags
52
60
  }
53
61
 
62
+ function isPathInside(child, parent) {
63
+ const c = path.resolve(child)
64
+ const p = path.resolve(parent)
65
+ const rel = path.relative(p, c)
66
+ return rel === '' || !rel.startsWith('..')
67
+ }
68
+
69
+ function assertSecretsDirOutsideRepo(secretsDir) {
70
+ if (isPathInside(secretsDir, ROOT)) {
71
+ throw new Error(
72
+ `Refusing to use secrets directory inside the repository: ${secretsDir}\n` +
73
+ 'Choose a path outside the repo (e.g. --secrets-dir ~/.enigma/simulation-secrets).'
74
+ )
75
+ }
76
+ }
77
+
54
78
  function generateKmsKeyRef() {
55
79
  const pair = generateKeyPairSync('ed25519', {
56
80
  privateKeyEncoding: { type: 'pkcs8', format: 'pem' },
@@ -75,6 +99,7 @@ function generateKmsKeyRef() {
75
99
  const SECRET_GENERATORS = {
76
100
  'relay-signing-key': () => 'local-simulation-relay-signing-key-ref\n',
77
101
  'gateway-signing-key': () => 'local-simulation-gateway-signing-key-ref\n',
102
+ // Simulation-only DSN. Never a real credential. secret-scan:approved
78
103
  'external-storage-dsn': () => 'postgres://enigma:enigma@postgres:5432/enigma?sslmode=disable\n',
79
104
  'kms-key-ref': generateKmsKeyRef,
80
105
  'backup-target-uri': () => 'file:///tmp/enigma-backups\n',
@@ -85,7 +110,8 @@ const SECRET_GENERATORS = {
85
110
  }
86
111
 
87
112
  function ensureDir(dir) {
88
- fs.mkdirSync(dir, { recursive: true })
113
+ fs.mkdirSync(dir, { recursive: true, mode: 0o700 })
114
+ if (process.platform !== 'win32') fs.chmodSync(dir, 0o700)
89
115
  }
90
116
 
91
117
  function isMissingOrEmpty(filePath) {
@@ -97,6 +123,28 @@ function isMissingOrEmpty(filePath) {
97
123
  }
98
124
  }
99
125
 
126
+ function sha256Hex(bufferOrString) {
127
+ return createHash('sha256').update(bufferOrString).digest('hex')
128
+ }
129
+
130
+ function gatewayBearerSha256(filePath) {
131
+ const token = fs.readFileSync(filePath)
132
+ return `sha256:${sha256Hex(token)}`
133
+ }
134
+
135
+ function writeSimulationEnv(secretsDir) {
136
+ const lines = [
137
+ '# Generated by scripts/simulate-production-env.mjs',
138
+ '# This file contains simulation-only digests, not production secrets.',
139
+ '# It is kept next to the other simulation secrets outside the repo.',
140
+ ]
141
+ for (const [name, envVar] of Object.entries(BEARER_FILES_FOR_DIGEST)) {
142
+ const digest = gatewayBearerSha256(path.join(secretsDir, name))
143
+ lines.push(`${envVar}=${digest}`)
144
+ }
145
+ fs.writeFileSync(path.join(secretsDir, 'simulation.env'), lines.join('\n') + '\n', { mode: 0o600 })
146
+ }
147
+
100
148
  function generateTlsCerts(secretsDir) {
101
149
  const key = path.join(secretsDir, 'tls.key')
102
150
  const cert = path.join(secretsDir, 'tls.crt')
@@ -149,18 +197,23 @@ function generateTlsCerts(secretsDir) {
149
197
 
150
198
  function generateSecrets(secretsDir) {
151
199
  ensureDir(secretsDir)
200
+ assertSecretsDirOutsideRepo(secretsDir)
152
201
  for (const name of REQUIRED_SECRET_FILES) {
153
202
  if (name === 'tls.crt' || name === 'tls.key') continue
154
203
  const filePath = path.join(secretsDir, name)
155
204
  if (isMissingOrEmpty(filePath)) {
156
- fs.writeFileSync(filePath, SECRET_GENERATORS[name](), { mode: 0o600 })
205
+ fs.writeFileSync(filePath, SECRET_GENERATORS[name](), { mode: DOCKER_READABLE_SECRET_MODE })
157
206
  }
207
+ // Compose file-backed secrets preserve host file bits. The parent directory
208
+ // remains owner-only while non-root simulation containers receive read access.
209
+ if (process.platform !== 'win32') fs.chmodSync(filePath, DOCKER_READABLE_SECRET_MODE)
158
210
  }
159
211
  const keyPath = path.join(secretsDir, 'tls.key')
160
212
  const certPath = path.join(secretsDir, 'tls.crt')
161
213
  if (isMissingOrEmpty(keyPath) || isMissingOrEmpty(certPath)) {
162
214
  generateTlsCerts(secretsDir)
163
215
  }
216
+ writeSimulationEnv(secretsDir)
164
217
  }
165
218
 
166
219
  function check(secretsDir) {
@@ -177,10 +230,17 @@ function check(secretsDir) {
177
230
  )
178
231
  }
179
232
 
180
- function printStartInstructions() {
233
+ function printStartInstructions(secretsDir) {
234
+ process.stdout.write('\n')
235
+ process.stdout.write('Simulation secrets written outside the repo to:\n')
236
+ process.stdout.write(` ${secretsDir}\n`)
237
+ process.stdout.write('\n')
238
+ process.stdout.write('To start the local production simulation, set the secrets path and run:\n')
239
+ process.stdout.write(` export ENIGMA_SIM_SECRETS_DIR=${secretsDir}\n`)
240
+ process.stdout.write(` docker compose -f deploy/docker-compose.local-production-simulation.yml --env-file ${path.join(secretsDir, 'simulation.env')} up --build -d\n`)
181
241
  process.stdout.write('\n')
182
- process.stdout.write('To start the local production simulation, run:\n')
183
- process.stdout.write(' docker compose -f deploy/docker-compose.local-production-simulation.yml up --build -d\n')
242
+ process.stdout.write('To tear down, use the same env file so the gateway bearer hashes resolve:\n')
243
+ process.stdout.write(` docker compose -f deploy/docker-compose.local-production-simulation.yml --env-file ${path.join(secretsDir, 'simulation.env')} down -v --remove-orphans\n`)
184
244
  process.stdout.write('\n')
185
245
  process.stdout.write('To make the public-looking domain resolve locally, add this line to /etc/hosts\n')
186
246
  process.stdout.write('(or C:\\Windows\\System32\\drivers\\etc\\hosts on Windows):\n')
@@ -198,13 +258,14 @@ function printStartInstructions() {
198
258
 
199
259
  function main() {
200
260
  const flags = parseArgs(process.argv.slice(2))
261
+ assertSecretsDirOutsideRepo(flags.secretsDir)
201
262
  if (flags.check) {
202
263
  check(flags.secretsDir)
203
264
  return
204
265
  }
205
266
  generateSecrets(flags.secretsDir)
206
267
  check(flags.secretsDir)
207
- printStartInstructions()
268
+ printStartInstructions(flags.secretsDir)
208
269
  }
209
270
 
210
271
  main()
@@ -5,6 +5,9 @@ import { fileURLToPath } from 'node:url';
5
5
 
6
6
  export const HOSTED_BACKEND_LIVE_EVIDENCE_SCHEMA = 'enigma.hosted_backend_live_evidence.v1';
7
7
  export const HOSTED_BACKEND_LIVE_RESULT_SCHEMA = 'enigma.hosted_backend_live_result.v1';
8
+ export const HOSTED_BACKEND_RUNTIME_CAPABILITY_SCHEMA = 'enigma.hosted_backend_runtime_capability.v1';
9
+ export const HOSTED_BACKEND_AUTHENTICATED_DATA_PLANE_SCHEMA = 'enigma.hosted_backend_authenticated_data_plane.v1';
10
+ export const PRIVATE_DATA_PLANE_RUNTIME_MARKER = 'enigma.private_data_plane.runtime.v1';
8
11
 
9
12
  export const REQUIRED_REF_KEYS = Object.freeze([
10
13
  'backend_host',
@@ -35,6 +38,11 @@ export const REQUIRED_REF_KEYS = Object.freeze([
35
38
  ]);
36
39
 
37
40
  const REQUIRED_PROBES = Object.freeze(['relay_livez', 'relay_readyz', 'gateway_livez', 'gateway_readyz']);
41
+ const RUNTIME_SERVICES = Object.freeze(['relay', 'gateway']);
42
+ const DATA_PLANE_ROUTES = Object.freeze({
43
+ relay: Object.freeze(['/relay/records', '/pairing/challenge', '/pairing/complete']),
44
+ gateway: Object.freeze(['/policy', '/gateway/evaluate', '/gateway/decision', '/siem/export']),
45
+ });
38
46
  const ACCEPTED_STATUSES = new Set(['observed', 'verified', 'go', 'accepted']);
39
47
  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/@]+@|raw memory|private prompt|full transcript|decrypted capsule|sk-[A-Za-z0-9_-]{16,}|AKIA[0-9A-Z]{16})/iu;
40
48
  const FORBIDDEN_KEY_RE = /(?:password|passwd|pwd|token|api[_-]?key|private[_-]?key|secret|raw[_-]?memory|plaintext|plain[_-]?text|prompt|completion|transcript|embedding|provider[_-]?response|cookie|session)/iu;
@@ -151,6 +159,12 @@ function validateEnvironment(environment, blockers) {
151
159
  for (const field of ['environment_id', 'cloud_provider', 'region', 'owner', 'status']) {
152
160
  if (!nonEmptyString(environment[field])) blockers.push(blocker(`environment.${field} is required`, `environment.${field}`));
153
161
  }
162
+ if (environment.local_simulation !== false) {
163
+ blockers.push(blocker('environment.local_simulation must be false for hosted production evidence', 'environment.local_simulation'));
164
+ }
165
+ if (nonEmptyString(environment.cloud_provider) && environment.cloud_provider.trim().toLowerCase() === 'local') {
166
+ blockers.push(blocker('environment.cloud_provider must identify a non-simulation production provider', 'environment.cloud_provider'));
167
+ }
154
168
  if (!statusAccepted(environment.status)) blockers.push(blocker('environment.status must be observed/verified/go/accepted', 'environment.status'));
155
169
  return { domain };
156
170
  }
@@ -179,6 +193,9 @@ function validateProbe(probe, expectedName, domain, blockers) {
179
193
  if (probe.body.hosted_probe_only === true || probe.body.pages_edge_probe_only === true) {
180
194
  blockers.push(blocker(`${path}.body must not be an edge-probe-only payload`, `${path}.body`));
181
195
  }
196
+ if (probe.body.hosted_backend_live === false || probe.body.private_data_plane_operational === false || probe.body.runtime_capability?.bootstrap_worker === true) {
197
+ blockers.push(blocker(`${path}.body declares the private data plane closed or bootstrap-only`, `${path}.body.runtime_capability`));
198
+ }
182
199
  if (probe.body.service !== expectedService) blockers.push(blocker(`${path}.body.service must be ${expectedService}`, `${path}.body.service`));
183
200
  if (probe.body.ok !== true) blockers.push(blocker(`${path}.body.ok must be true`, `${path}.body.ok`));
184
201
  if (expectedName.endsWith('readyz')) {
@@ -203,6 +220,94 @@ function validateProbes(probes, domain, blockers) {
203
220
  return { covered };
204
221
  }
205
222
 
223
+ function validateRuntimeCapability(capability, blockers) {
224
+ if (!isPlainObject(capability)) {
225
+ blockers.push(blocker('runtime_capability object is required', 'runtime_capability'));
226
+ return { covered: 0 };
227
+ }
228
+ if (capability.schema !== HOSTED_BACKEND_RUNTIME_CAPABILITY_SCHEMA) blockers.push(blocker(`runtime_capability.schema must be ${HOSTED_BACKEND_RUNTIME_CAPABILITY_SCHEMA}`, 'runtime_capability.schema'));
229
+ if (capability.marker !== PRIVATE_DATA_PLANE_RUNTIME_MARKER) blockers.push(blocker(`runtime_capability.marker must be ${PRIVATE_DATA_PLANE_RUNTIME_MARKER}`, 'runtime_capability.marker'));
230
+ if (!isoLike(capability.observed_at)) blockers.push(blocker('runtime_capability.observed_at must be ISO time', 'runtime_capability.observed_at'));
231
+ if (!isPlainObject(capability.services)) {
232
+ blockers.push(blocker('runtime_capability.services object is required', 'runtime_capability.services'));
233
+ return { covered: 0 };
234
+ }
235
+ let covered = 0;
236
+ for (const serviceKey of RUNTIME_SERVICES) {
237
+ const path = `runtime_capability.services.${serviceKey}`;
238
+ const service = capability.services[serviceKey];
239
+ if (!isPlainObject(service)) {
240
+ blockers.push(blocker(`${path} object is required`, path));
241
+ continue;
242
+ }
243
+ const expectedService = serviceKey === 'relay' ? 'enigma-relay' : 'enigma-gateway';
244
+ if (service.service !== expectedService) blockers.push(blocker(`${path}.service must be ${expectedService}`, `${path}.service`));
245
+ if (service.private_data_plane_operational !== true) blockers.push(blocker(`${path}.private_data_plane_operational must be true`, `${path}.private_data_plane_operational`));
246
+ if (service.authentication_enforced !== true) blockers.push(blocker(`${path}.authentication_enforced must be true`, `${path}.authentication_enforced`));
247
+ if (service.bootstrap_worker !== false) blockers.push(blocker(`${path}.bootstrap_worker must be false`, `${path}.bootstrap_worker`));
248
+ if (!nonEmptyString(service.evidence_ref)) blockers.push(blocker(`${path}.evidence_ref is required`, `${path}.evidence_ref`));
249
+ covered += 1;
250
+ }
251
+ return { covered };
252
+ }
253
+
254
+ function authenticatedDataPlaneUrl(value, serviceKey, domain, path, blockers) {
255
+ if (!nonEmptyString(value)) {
256
+ blockers.push(blocker(`${path} is required`, path));
257
+ return null;
258
+ }
259
+ try {
260
+ const url = new URL(value);
261
+ if (url.protocol !== 'https:') blockers.push(blocker(`${path} must use https`, path));
262
+ if (url.username || url.password) blockers.push(blocker(`${path} must not include credentials`, path));
263
+ if (url.search || url.hash) blockers.push(blocker(`${path} must not include query strings or fragments`, path));
264
+ if (isPrivateHost(url.hostname)) blockers.push(blocker(`${path} must not target localhost or private network host`, path));
265
+ const hostname = url.hostname.toLowerCase();
266
+ if (domain && hostname !== domain && !hostname.endsWith(`.${domain}`)) blockers.push(blocker(`${path} host must be the domain or a subdomain`, path));
267
+ if (!DATA_PLANE_ROUTES[serviceKey].includes(url.pathname)) blockers.push(blocker(`${path} must target a ${serviceKey} private data-plane route`, path));
268
+ return url;
269
+ } catch {
270
+ blockers.push(blocker(`${path} must be a valid URL`, path));
271
+ return null;
272
+ }
273
+ }
274
+
275
+ function validateAuthenticatedDataPlane(evidence, domain, blockers) {
276
+ if (!isPlainObject(evidence)) {
277
+ blockers.push(blocker('authenticated_data_plane object is required', 'authenticated_data_plane'));
278
+ return { covered: 0 };
279
+ }
280
+ if (evidence.schema !== HOSTED_BACKEND_AUTHENTICATED_DATA_PLANE_SCHEMA) blockers.push(blocker(`authenticated_data_plane.schema must be ${HOSTED_BACKEND_AUTHENTICATED_DATA_PLANE_SCHEMA}`, 'authenticated_data_plane.schema'));
281
+ if (!isoLike(evidence.observed_at)) blockers.push(blocker('authenticated_data_plane.observed_at must be ISO time', 'authenticated_data_plane.observed_at'));
282
+ if (!isPlainObject(evidence.proofs)) {
283
+ blockers.push(blocker('authenticated_data_plane.proofs object is required', 'authenticated_data_plane.proofs'));
284
+ return { covered: 0 };
285
+ }
286
+ let covered = 0;
287
+ for (const serviceKey of RUNTIME_SERVICES) {
288
+ const path = `authenticated_data_plane.proofs.${serviceKey}`;
289
+ const proof = evidence.proofs[serviceKey];
290
+ if (!isPlainObject(proof)) {
291
+ blockers.push(blocker(`${path} object is required`, path));
292
+ continue;
293
+ }
294
+ const expectedService = serviceKey === 'relay' ? 'enigma-relay' : 'enigma-gateway';
295
+ if (proof.service !== expectedService) blockers.push(blocker(`${path}.service must be ${expectedService}`, `${path}.service`));
296
+ authenticatedDataPlaneUrl(proof.url, serviceKey, domain, `${path}.url`, blockers);
297
+ if (!['GET', 'POST', 'PUT', 'DELETE'].includes(proof.method)) blockers.push(blocker(`${path}.method must be GET/POST/PUT/DELETE`, `${path}.method`));
298
+ if (!Number.isSafeInteger(proof.status_code) || proof.status_code < 200 || proof.status_code >= 300) blockers.push(blocker(`${path}.status_code must be a successful 2xx response`, `${path}.status_code`));
299
+ if (proof.authenticated !== true) blockers.push(blocker(`${path}.authenticated must be true`, `${path}.authenticated`));
300
+ if (proof.authorization_result !== 'allowed') blockers.push(blocker(`${path}.authorization_result must be allowed`, `${path}.authorization_result`));
301
+ if (!isoLike(proof.observed_at)) blockers.push(blocker(`${path}.observed_at must be ISO time`, `${path}.observed_at`));
302
+ for (const field of ['request_hash', 'response_hash']) {
303
+ if (!nonEmptyString(proof[field]) || !/^sha256:[a-f0-9]{64}$/i.test(proof[field])) blockers.push(blocker(`${path}.${field} must be sha256:<64 hex>`, `${path}.${field}`));
304
+ }
305
+ if (!nonEmptyString(proof.evidence_ref)) blockers.push(blocker(`${path}.evidence_ref is required`, `${path}.evidence_ref`));
306
+ covered += 1;
307
+ }
308
+ return { covered };
309
+ }
310
+
206
311
  function validateOperator(operatorAcceptance, blockers) {
207
312
  if (!isPlainObject(operatorAcceptance)) {
208
313
  blockers.push(blocker('operator_acceptance object is required', 'operator_acceptance'));
@@ -238,6 +343,8 @@ export function validateHostedBackendLiveEvidence(evidence, options = {}) {
238
343
  const env = validateEnvironment(evidence.environment, blockers);
239
344
  const refs = validateRefs(evidence.refs, blockers);
240
345
  const probes = validateProbes(evidence.probes, env.domain, blockers);
346
+ const runtimeCapability = validateRuntimeCapability(evidence.runtime_capability, blockers);
347
+ const authenticatedDataPlane = validateAuthenticatedDataPlane(evidence.authenticated_data_plane, env.domain, blockers);
241
348
  validateOperator(evidence.operator_acceptance, blockers);
242
349
  validateClaimBoundary(evidence.claim_boundary, blockers);
243
350
  const result = {
@@ -253,11 +360,15 @@ export function validateHostedBackendLiveEvidence(evidence, options = {}) {
253
360
  refs_missing: refs.missing,
254
361
  required_probes: REQUIRED_PROBES.length,
255
362
  probes_covered: probes.covered,
363
+ runtime_services_required: RUNTIME_SERVICES.length,
364
+ runtime_services_covered: runtimeCapability.covered,
365
+ authenticated_data_plane_proofs_required: RUNTIME_SERVICES.length,
366
+ authenticated_data_plane_proofs_covered: authenticatedDataPlane.covered,
256
367
  operator_decision: evidence.operator_acceptance?.decision ?? null,
257
368
  },
258
369
  claim_boundary: [
259
370
  'Hosted backend live validation checks supplied evidence only; it does not deploy infrastructure, mutate Cloudflare, create DNS records, or generate credentials.',
260
- 'A pass result requires public HTTPS /livez and /readyz probe evidence for relay and gateway plus all required production refs and operator acceptance go.',
371
+ 'A pass result requires public HTTPS /livez and /readyz probes, an explicit operational private-runtime capability marker, successful authenticated relay and gateway data-plane proofs, all required production refs, and operator acceptance go.',
261
372
  'Credentials, bearer tokens, API tokens, private memory payloads, prompts, transcripts, provider responses, and personal contact data must remain outside hosted backend live evidence.',
262
373
  ],
263
374
  };
@@ -0,0 +1,95 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://schemas.enigma.ai/antibody-pack-v1.schema.json",
4
+ "title": "Enigma Antibody Pack v1",
5
+ "type": "object",
6
+ "required": [
7
+ "schema",
8
+ "antibody_pack_id",
9
+ "created_at",
10
+ "version",
11
+ "policy_fingerprints",
12
+ "pack_root",
13
+ "signatures",
14
+ "public_payload_only",
15
+ "private_inputs_included"
16
+ ],
17
+ "additionalProperties": false,
18
+ "properties": {
19
+ "schema": { "const": "enigma.antibody_pack.v1" },
20
+ "antibody_pack_id": { "$ref": "#/$defs/publicId" },
21
+ "created_at": { "type": "string", "format": "date-time" },
22
+ "version": { "type": "string", "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+(?:[-+][A-Za-z0-9.-]+)?$" },
23
+ "policy_fingerprints": {
24
+ "type": "array",
25
+ "minItems": 1,
26
+ "items": { "$ref": "#/$defs/policyFingerprint" }
27
+ },
28
+ "pack_root": { "$ref": "#/$defs/sha256Digest" },
29
+ "signatures": {
30
+ "type": "array",
31
+ "minItems": 1,
32
+ "items": { "$ref": "#/$defs/signatureRef" }
33
+ },
34
+ "public_payload_only": { "const": true },
35
+ "private_inputs_included": { "const": false }
36
+ },
37
+ "$defs": {
38
+ "sha256Digest": { "type": "string", "pattern": "^sha256:[a-f0-9]{64}$" },
39
+ "publicId": { "type": "string", "pattern": "^[a-z0-9][a-z0-9._:-]{7,127}$" },
40
+ "publicRef": { "type": "string", "pattern": "^ref:[A-Za-z0-9][A-Za-z0-9._~:@#?=&%+-]{0,255}$" },
41
+ "detectorId": { "type": "string", "pattern": "^detector:[A-Za-z0-9][A-Za-z0-9._~:@#?=&%+-]{0,191}$" },
42
+ "policyId": { "type": "string", "pattern": "^policy:[A-Za-z0-9][A-Za-z0-9._~:@#?=&%+-]{0,191}$" },
43
+ "signerRef": { "type": "string", "pattern": "^signer:[A-Za-z0-9][A-Za-z0-9._~:@#?=&%+-]{0,191}$" },
44
+ "signaturePublicRef": { "type": "string", "pattern": "^sigref:[A-Za-z0-9][A-Za-z0-9._~:@#?=&%+-]{0,191}$" },
45
+ "policyFingerprint": {
46
+ "type": "object",
47
+ "required": [
48
+ "policy_id",
49
+ "detector_id",
50
+ "detector_ref",
51
+ "policy_hash",
52
+ "risk_labels",
53
+ "threshold_commitment",
54
+ "private_inputs_included"
55
+ ],
56
+ "additionalProperties": false,
57
+ "properties": {
58
+ "policy_id": { "$ref": "#/$defs/policyId" },
59
+ "detector_id": { "$ref": "#/$defs/detectorId" },
60
+ "detector_ref": { "$ref": "#/$defs/publicRef" },
61
+ "policy_hash": { "$ref": "#/$defs/sha256Digest" },
62
+ "risk_labels": {
63
+ "type": "array",
64
+ "items": { "$ref": "#/$defs/riskLabel" },
65
+ "uniqueItems": true
66
+ },
67
+ "threshold_commitment": { "$ref": "#/$defs/sha256Digest" },
68
+ "private_inputs_included": { "const": false }
69
+ }
70
+ },
71
+ "signatureRef": {
72
+ "type": "object",
73
+ "required": ["signer_ref", "signature_ref", "signature_hash", "alg"],
74
+ "additionalProperties": false,
75
+ "properties": {
76
+ "signer_ref": { "$ref": "#/$defs/signerRef" },
77
+ "signature_ref": { "$ref": "#/$defs/signaturePublicRef" },
78
+ "signature_hash": { "$ref": "#/$defs/sha256Digest" },
79
+ "alg": { "type": "string", "enum": ["Ed25519", "ECDSA-P256-SHA256"] }
80
+ }
81
+ },
82
+ "riskLabel": {
83
+ "type": "string",
84
+ "enum": [
85
+ "untrusted_origin",
86
+ "prompt_injection",
87
+ "data_exfiltration",
88
+ "secret_material",
89
+ "memory_poisoning",
90
+ "policy_violation",
91
+ "unknown"
92
+ ]
93
+ }
94
+ }
95
+ }