@atmem/architect 0.0.0-stage → 0.2.0-alpha.4.1

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 (498) hide show
  1. package/CONSTITUTION.md +144 -0
  2. package/README.md +33 -2
  3. package/agent-skills/discovery/SKILL.md +48 -0
  4. package/agent-skills/discovery/topics.json +139 -0
  5. package/agent-skills/generation-capabilities.json +760 -0
  6. package/agent-skills/service-lifecycle.json +21 -0
  7. package/agent-skills/specialists/architecture/SKILL.md +15 -0
  8. package/agent-skills/specialists/aws/SKILL.md +17 -0
  9. package/agent-skills/specialists/azure/SKILL.md +7 -0
  10. package/agent-skills/specialists/composition/SKILL.md +17 -0
  11. package/agent-skills/specialists/devops/SKILL.md +10 -0
  12. package/agent-skills/specialists/finops/SKILL.md +7 -0
  13. package/agent-skills/specialists/gcp/SKILL.md +7 -0
  14. package/agent-skills/specialists/ibm/SKILL.md +7 -0
  15. package/agent-skills/specialists/manifest.json +13 -0
  16. package/agent-skills/specialists/pulumi/SKILL.md +7 -0
  17. package/agent-skills/specialists/security/SKILL.md +7 -0
  18. package/agent-skills/specialists/terraform/SKILL.md +14 -0
  19. package/agent-skills/upstream/aws/LICENSE +175 -0
  20. package/agent-skills/upstream/aws/SKILL.md +125 -0
  21. package/agent-skills/upstream/azure/LICENSE +21 -0
  22. package/agent-skills/upstream/azure/SKILL.md +387 -0
  23. package/agent-skills/upstream/gcp/LICENSE +202 -0
  24. package/agent-skills/upstream/gcp/SKILL.md +159 -0
  25. package/agent-skills/upstream/manifest.json +57 -0
  26. package/agent-skills/upstream/pulumi/LICENSE +201 -0
  27. package/agent-skills/upstream/pulumi/SKILL.md +501 -0
  28. package/agent-skills/upstream/terraform/LICENSE +373 -0
  29. package/agent-skills/upstream/terraform/SKILL.md +316 -0
  30. package/agent-skills/workflows/workflows.json +601 -0
  31. package/cli/architect.mjs +3 -0
  32. package/cli/runtime.mjs +115 -0
  33. package/dist/assets/html2canvas.esm-QH1iLAAe.js +22 -0
  34. package/dist/assets/index-B97MkVMs.css +1 -0
  35. package/dist/assets/index-qtCM2D7O.js +21271 -0
  36. package/dist/assets/index.es-C6C0sneB.js +18 -0
  37. package/dist/assets/purify.es-CAi2OJFm.js +3 -0
  38. package/dist/assets/visual-export-DjbjgQbA.js +173 -0
  39. package/dist/favicon.svg +2 -0
  40. package/dist/fonts/DM-Sans-OFL.txt +93 -0
  41. package/dist/fonts/Manrope-OFL.txt +93 -0
  42. package/dist/fonts/NotoSans-Regular.ttf +0 -0
  43. package/dist/fonts/OFL.txt +94 -0
  44. package/dist/fonts/dm-sans-latin-wght-normal.woff2 +0 -0
  45. package/dist/fonts/manrope-latin-wght-normal.woff2 +0 -0
  46. package/dist/index.html +4 -0
  47. package/dist/licenses/aws-architect-LICENSE.txt +17 -0
  48. package/dist/licenses/aws-mcp-LICENSE.txt +175 -0
  49. package/dist/licenses/aws-mcp-NOTICE.txt +1 -0
  50. package/dist/licenses/cloud-emulation-notices.txt +36619 -0
  51. package/dist/licenses/dependency-notices.txt +6379 -0
  52. package/dist/licenses/emulation-notices.txt +717 -0
  53. package/dist/licenses/github-copilot-sdk-LICENSE.txt +21 -0
  54. package/dist/licenses/memory-dependency-notices.txt +3319 -0
  55. package/dist/licenses/openarchflow-LICENSE.txt +21 -0
  56. package/dist/licenses/python-dependency-notices.txt +11951 -0
  57. package/docs/upstream-lock.json +26 -0
  58. package/knowledge/engineering-practices.json +536 -0
  59. package/package.json +30 -4
  60. package/packaging/uv-release-lock.json +54 -0
  61. package/public/licenses/aws-architect-LICENSE.txt +17 -0
  62. package/public/licenses/aws-mcp-LICENSE.txt +175 -0
  63. package/public/licenses/aws-mcp-NOTICE.txt +1 -0
  64. package/public/licenses/cloud-emulation-notices.txt +36619 -0
  65. package/public/licenses/dependency-notices.txt +6379 -0
  66. package/public/licenses/emulation-notices.txt +717 -0
  67. package/public/licenses/github-copilot-sdk-LICENSE.txt +21 -0
  68. package/public/licenses/memory-dependency-notices.txt +3319 -0
  69. package/public/licenses/openarchflow-LICENSE.txt +21 -0
  70. package/public/licenses/python-dependency-notices.txt +11951 -0
  71. package/scripts/terraform-render.mjs +8 -0
  72. package/server/__init__.py +0 -0
  73. package/server/abstraction.py +28 -0
  74. package/server/agent_runtime.py +153 -0
  75. package/server/app.py +257 -0
  76. package/server/architect.py +112 -0
  77. package/server/architecture_activity.py +67 -0
  78. package/server/attachments.py +101 -0
  79. package/server/cloud-emulation-requirements.txt +29 -0
  80. package/server/codex_app_server.py +219 -0
  81. package/server/codex_engineering_backend.py +266 -0
  82. package/server/codex_worker_policy.py +170 -0
  83. package/server/contracts.py +315 -0
  84. package/server/copilot_worker.py +16 -0
  85. package/server/dependency_mirror.py +54 -0
  86. package/server/design_patch.py +43 -0
  87. package/server/emulation-requirements.txt +8 -0
  88. package/server/emulation_adapters.py +20 -0
  89. package/server/emulation_routes.py +98 -0
  90. package/server/emulation_worker.py +351 -0
  91. package/server/engineering_artifacts.py +215 -0
  92. package/server/engineering_assets/application-runtime.json +4372 -0
  93. package/server/engineering_assets/architecture_work.schema.json +79 -0
  94. package/server/engineering_assets/materialize_runtime.py +62 -0
  95. package/server/engineering_assets/prepare_tools.py +96 -0
  96. package/server/engineering_assets/sql_validation.py +59 -0
  97. package/server/engineering_contexts.py +120 -0
  98. package/server/engineering_delivery.py +210 -0
  99. package/server/engineering_finalization.py +210 -0
  100. package/server/engineering_handoff.py +163 -0
  101. package/server/engineering_jobs.py +206 -0
  102. package/server/engineering_knowledge.py +75 -0
  103. package/server/engineering_reconciliation.py +159 -0
  104. package/server/engineering_routes.py +469 -0
  105. package/server/engineering_sessions.py +273 -0
  106. package/server/engineering_tools.py +166 -0
  107. package/server/generation_lint.py +18 -0
  108. package/server/local_providers.py +181 -0
  109. package/server/local_validation.py +236 -0
  110. package/server/memory-requirements.lock +181 -0
  111. package/server/memory-requirements.txt +6 -0
  112. package/server/memory_routes.py +82 -0
  113. package/server/memory_service.py +273 -0
  114. package/server/memory_worker.py +66 -0
  115. package/server/openai_voice.py +80 -0
  116. package/server/packaged_app.py +9 -0
  117. package/server/pricing.py +84 -0
  118. package/server/process_control_observation.py +31 -0
  119. package/server/prompts.py +123 -0
  120. package/server/public_faq_emulation_worker.py +44 -0
  121. package/server/requirements.lock +1618 -0
  122. package/server/requirements.txt +68 -0
  123. package/server/runtime_dependency_locks.py +27 -0
  124. package/server/runtime_evidence.py +93 -0
  125. package/server/settings.py +14 -0
  126. package/server/skills.py +103 -0
  127. package/server/storage_emulation_worker.py +160 -0
  128. package/server/structured_emulation_worker.py +48 -0
  129. package/server/terraform_routes.py +118 -0
  130. package/server/upstream/__init__.py +0 -0
  131. package/server/upstream/agent/__init__.py +1 -0
  132. package/server/upstream/agent/aws_architect.py +600 -0
  133. package/server/upstream/agent/config/__init__.py +1 -0
  134. package/server/upstream/agent/config/agent_config.py +82 -0
  135. package/server/upstream/agent/config/prompts.py +138 -0
  136. package/server/upstream/agent/rate_limiter.py +62 -0
  137. package/server/upstream/utils/__init__.py +1 -0
  138. package/server/upstream/utils/file_writer.py +43 -0
  139. package/server/validation_applicability.py +85 -0
  140. package/server/validation_jobs.py +252 -0
  141. package/server/validation_workers.py +48 -0
  142. package/server/voice_routes.py +91 -0
  143. package/server/voice_worker.py +26 -0
  144. package/specs/028-convergence-evaluation/evidence/20261110-ibm-invoice-native/registry-structured/qualification.json +72 -0
  145. package/specs/028-convergence-evaluation/evidence/20261110-invoice-runtime/durable-current/receipt.json +61 -0
  146. package/specs/029-general-purpose-engine/evidence/20261111-runtime-dependencies/sdk/receipt.json +22 -0
  147. package/src/ArchitectureActivity.jsx +54 -0
  148. package/src/ArchitectureWorkPanel.jsx +46 -0
  149. package/src/ArtifactChecks.jsx +49 -0
  150. package/src/BlockRequirements.jsx +13 -0
  151. package/src/BrainActivity.jsx +11 -0
  152. package/src/ChatMessage.jsx +19 -0
  153. package/src/ChatResizeHandle.jsx +6 -0
  154. package/src/CodePreview.jsx +8 -0
  155. package/src/ComponentReview.jsx +31 -0
  156. package/src/DeliveryViews.jsx +59 -0
  157. package/src/EmulationPanel.jsx +44 -0
  158. package/src/EngagementViews.jsx +385 -0
  159. package/src/EngineeringPanel.jsx +151 -0
  160. package/src/ImplementationDelivery.jsx +55 -0
  161. package/src/JourneyViews.jsx +400 -0
  162. package/src/MemoryPanel.jsx +46 -0
  163. package/src/OpenAIVoicePanel.jsx +65 -0
  164. package/src/OutputsView.jsx +65 -0
  165. package/src/TerraformView.jsx +57 -0
  166. package/src/WorkbenchDialogs.jsx +532 -0
  167. package/src/activity-presentation.mjs +28 -0
  168. package/src/ai-qualification-scenarios.mjs +31 -0
  169. package/src/approval-application-files.mjs +32 -0
  170. package/src/approval-applications.mjs +82 -0
  171. package/src/approval-spec-kit.mjs +30 -0
  172. package/src/architecture-activity.css +28 -0
  173. package/src/architecture-activity.mjs +63 -0
  174. package/src/architecture-work.mjs +176 -0
  175. package/src/artifact-work.mjs +103 -0
  176. package/src/async-documents.mjs +191 -0
  177. package/src/atflow.css +1140 -0
  178. package/src/atforma.css +748 -0
  179. package/src/atmem-tokens.css +79 -0
  180. package/src/aws-preflight.mjs +60 -0
  181. package/src/aws-public-faq.mjs +102 -0
  182. package/src/aws-validation-scenarios.mjs +10 -0
  183. package/src/aws-validation.mjs +48 -0
  184. package/src/azure-plan-mocks.mjs +25 -0
  185. package/src/azure-structured.mjs +133 -0
  186. package/src/bedrock-summary.mjs +152 -0
  187. package/src/bounded-rag.mjs +60 -0
  188. package/src/brand.css +9 -0
  189. package/src/canvas-view.mjs +28 -0
  190. package/src/capability-composition.mjs +44 -0
  191. package/src/chat-attachments.mjs +13 -0
  192. package/src/cloud-provider-locks.mjs +9 -0
  193. package/src/cloud-storage-scenarios.mjs +2 -0
  194. package/src/component-review.mjs +55 -0
  195. package/src/composition-spec-kit.mjs +30 -0
  196. package/src/consultation-context.mjs +15 -0
  197. package/src/consultation.mjs +52 -0
  198. package/src/container-contracts.mjs +5 -0
  199. package/src/container-inspection.mjs +75 -0
  200. package/src/container-runtime.mjs +30 -0
  201. package/src/container-security-inspection.mjs +49 -0
  202. package/src/container-terraform.mjs +109 -0
  203. package/src/conversation.mjs +17 -0
  204. package/src/core.mjs +863 -0
  205. package/src/cross-cloud-storage.mjs +100 -0
  206. package/src/delivery-capabilities.mjs +25 -0
  207. package/src/delivery.mjs +58 -0
  208. package/src/deployment-ownership.mjs +10 -0
  209. package/src/deployment-region.mjs +11 -0
  210. package/src/derive.mjs +31 -0
  211. package/src/design-build-flow.mjs +10 -0
  212. package/src/diagram-attention.mjs +24 -0
  213. package/src/discovery.mjs +359 -0
  214. package/src/document.mjs +170 -0
  215. package/src/emulation-feedback.mjs +61 -0
  216. package/src/emulation-guidance.mjs +37 -0
  217. package/src/engagement.mjs +274 -0
  218. package/src/engineering-client.mjs +73 -0
  219. package/src/engineering-defaults.mjs +17 -0
  220. package/src/engineering.css +31 -0
  221. package/src/enterprise-application.mjs +76 -0
  222. package/src/enterprise-aws-host-infrastructure.mjs +62 -0
  223. package/src/enterprise-aws-host-tests.mjs +15 -0
  224. package/src/enterprise-aws-infrastructure-tests.mjs +38 -0
  225. package/src/enterprise-aws-infrastructure.mjs +138 -0
  226. package/src/enterprise-google-infrastructure.mjs +84 -0
  227. package/src/enterprise-google-tests.mjs +25 -0
  228. package/src/estimate.mjs +188 -0
  229. package/src/existing-references.mjs +18 -0
  230. package/src/external-identities.mjs +17 -0
  231. package/src/faq-lambda-build.mjs +28 -0
  232. package/src/gcp-structured.mjs +104 -0
  233. package/src/generation-provider.mjs +7 -0
  234. package/src/generation-quality.mjs +69 -0
  235. package/src/handoff.mjs +141 -0
  236. package/src/ibm-registry.mjs +12 -0
  237. package/src/ibm-structured.mjs +103 -0
  238. package/src/identifiers.mjs +15 -0
  239. package/src/implementation-map.mjs +14 -0
  240. package/src/implementation-outcome.mjs +8 -0
  241. package/src/incomplete-terraform.mjs +9 -0
  242. package/src/integrations.ts +137 -0
  243. package/src/interface-contracts.mjs +30 -0
  244. package/src/invoice-application.mjs +66 -0
  245. package/src/invoice-aws-operations.mjs +136 -0
  246. package/src/invoice-aws.mjs +143 -0
  247. package/src/invoice-azure-operations.mjs +147 -0
  248. package/src/invoice-azure.mjs +134 -0
  249. package/src/invoice-builder.mjs +35 -0
  250. package/src/invoice-dependencies.mjs +43 -0
  251. package/src/invoice-gcp-operations.mjs +178 -0
  252. package/src/invoice-gcp.mjs +104 -0
  253. package/src/invoice-ibm-operations.mjs +278 -0
  254. package/src/invoice-ibm.mjs +142 -0
  255. package/src/invoice-operations.mjs +143 -0
  256. package/src/invoice-plan.mjs +45 -0
  257. package/src/invoice-region.mjs +6 -0
  258. package/src/invoice-spec-kit.mjs +61 -0
  259. package/src/invoice-state.mjs +7 -0
  260. package/src/invoice-terraform.mjs +29 -0
  261. package/src/invoice-tests.mjs +122 -0
  262. package/src/journey-workspace.css +72 -0
  263. package/src/journey.mjs +87 -0
  264. package/src/levels.mjs +145 -0
  265. package/src/local-agent.mjs +184 -0
  266. package/src/main.jsx +2458 -0
  267. package/src/model-policy-preflight.mjs +34 -0
  268. package/src/openai-voice.mjs +102 -0
  269. package/src/output-bundle.mjs +11 -0
  270. package/src/ownership-inspection.mjs +28 -0
  271. package/src/pack.mjs +201 -0
  272. package/src/pricing.mjs +31 -0
  273. package/src/production-state.mjs +8 -0
  274. package/src/project-copy.mjs +10 -0
  275. package/src/project-file.mjs +160 -0
  276. package/src/project-links.mjs +3 -0
  277. package/src/protected-state.mjs +43 -0
  278. package/src/public-faq-builder.mjs +19 -0
  279. package/src/public-faq-clouds.mjs +251 -0
  280. package/src/public-faq.mjs +122 -0
  281. package/src/pulumi.mjs +123 -0
  282. package/src/python-container.mjs +25 -0
  283. package/src/python-runtime.mjs +50 -0
  284. package/src/rag-handler.mjs +43 -0
  285. package/src/rag-web-assets.mjs +52 -0
  286. package/src/rag-web.mjs +68 -0
  287. package/src/records.mjs +177 -0
  288. package/src/resources.mjs +163 -0
  289. package/src/review.mjs +252 -0
  290. package/src/runtime/EnterpriseDocument.java +89 -0
  291. package/src/runtime/approved_http_destination.py +72 -0
  292. package/src/runtime/aws-lambda-qualification-lock.json +7 -0
  293. package/src/runtime/aws-python-lock.json +82 -0
  294. package/src/runtime/aws-web-python-lock.json +887 -0
  295. package/src/runtime/aws_json_model.py +42 -0
  296. package/src/runtime/azure-python-lock.json +863 -0
  297. package/src/runtime/azure-sources.json +8 -0
  298. package/src/runtime/azure-test-lock.json +23 -0
  299. package/src/runtime/azure_acceptance.py +192 -0
  300. package/src/runtime/azure_structured.py +153 -0
  301. package/src/runtime/bounded_rag.py +126 -0
  302. package/src/runtime/catalog_admin.py +70 -0
  303. package/src/runtime/cloud-sql-proxy-lock.json +8 -0
  304. package/src/runtime/cloud-sql-proxy-security-review.json +30 -0
  305. package/src/runtime/connector_cli.py +50 -0
  306. package/src/runtime/connector_sync.py +70 -0
  307. package/src/runtime/durable-python-lock.json +247 -0
  308. package/src/runtime/durable_workflow.py +325 -0
  309. package/src/runtime/enterprise-application-manifest.json +110 -0
  310. package/src/runtime/enterprise-application-sources.json +266 -0
  311. package/src/runtime/enterprise-auth-python-lock.json +592 -0
  312. package/src/runtime/enterprise-aws-host-bootstrap-source.json +1 -0
  313. package/src/runtime/enterprise-aws-host-probe-source.json +1 -0
  314. package/src/runtime/enterprise-aws-task-template.json +235 -0
  315. package/src/runtime/enterprise-document-lock.json +18 -0
  316. package/src/runtime/enterprise-document.Dockerfile +15 -0
  317. package/src/runtime/enterprise-runtime-aws-python-lock.json +1115 -0
  318. package/src/runtime/enterprise-runtime-azure-python-lock.json +1106 -0
  319. package/src/runtime/enterprise-runtime-gcp-python-lock.json +1060 -0
  320. package/src/runtime/enterprise-runtime-ibm-python-lock.json +1096 -0
  321. package/src/runtime/enterprise-runtime-python-lock.json +1058 -0
  322. package/src/runtime/enterprise-runtime.Dockerfile +15 -0
  323. package/src/runtime/enterprise-web-app.js +1 -0
  324. package/src/runtime/enterprise-web-entry.js +105 -0
  325. package/src/runtime/enterprise-web-lock.json +29 -0
  326. package/src/runtime/enterprise-web-notices.txt +229 -0
  327. package/src/runtime/enterprise-web.css +4 -0
  328. package/src/runtime/enterprise-web.html +8 -0
  329. package/src/runtime/enterprise_audit.py +91 -0
  330. package/src/runtime/enterprise_audit_schema.sql +25 -0
  331. package/src/runtime/enterprise_auth_schema.sql +67 -0
  332. package/src/runtime/enterprise_auth_store.py +241 -0
  333. package/src/runtime/enterprise_aws_host_bootstrap.py +120 -0
  334. package/src/runtime/enterprise_aws_host_probe.py +105 -0
  335. package/src/runtime/enterprise_aws_hosts.py +136 -0
  336. package/src/runtime/enterprise_aws_jobs.py +300 -0
  337. package/src/runtime/enterprise_aws_objects.py +93 -0
  338. package/src/runtime/enterprise_aws_transfer.py +83 -0
  339. package/src/runtime/enterprise_azure_batch_api.py +128 -0
  340. package/src/runtime/enterprise_azure_host.py +599 -0
  341. package/src/runtime/enterprise_azure_jobs.py +294 -0
  342. package/src/runtime/enterprise_azure_objects.py +234 -0
  343. package/src/runtime/enterprise_azure_pool.py +161 -0
  344. package/src/runtime/enterprise_azure_transfer.py +122 -0
  345. package/src/runtime/enterprise_configuration.py +136 -0
  346. package/src/runtime/enterprise_document.py +116 -0
  347. package/src/runtime/enterprise_document_cli.py +32 -0
  348. package/src/runtime/enterprise_document_contract.py +54 -0
  349. package/src/runtime/enterprise_document_job.py +109 -0
  350. package/src/runtime/enterprise_document_jobs.py +122 -0
  351. package/src/runtime/enterprise_document_jobs_schema.sql +23 -0
  352. package/src/runtime/enterprise_extraction_cache.py +186 -0
  353. package/src/runtime/enterprise_extraction_schema.sql +17 -0
  354. package/src/runtime/enterprise_google_jobs.py +275 -0
  355. package/src/runtime/enterprise_google_transfer.py +85 -0
  356. package/src/runtime/enterprise_http.py +212 -0
  357. package/src/runtime/enterprise_identity.py +52 -0
  358. package/src/runtime/enterprise_knowledge.py +152 -0
  359. package/src/runtime/enterprise_models.py +94 -0
  360. package/src/runtime/enterprise_native.py +181 -0
  361. package/src/runtime/enterprise_oauth.py +132 -0
  362. package/src/runtime/enterprise_operator.py +160 -0
  363. package/src/runtime/enterprise_parser_service.py +136 -0
  364. package/src/runtime/enterprise_parser_transport.py +68 -0
  365. package/src/runtime/enterprise_queries.py +255 -0
  366. package/src/runtime/enterprise_queries_schema.sql +27 -0
  367. package/src/runtime/enterprise_query_service.py +111 -0
  368. package/src/runtime/enterprise_secrets.py +110 -0
  369. package/src/runtime/enterprise_sessions.py +95 -0
  370. package/src/runtime/enterprise_sources.py +260 -0
  371. package/src/runtime/enterprise_web.py +39 -0
  372. package/src/runtime/enterprise_worker.py +68 -0
  373. package/src/runtime/export_contract_acceptance.py +18 -0
  374. package/src/runtime/faq-output-contract.json +40 -0
  375. package/src/runtime/faq-web-app.js +41 -0
  376. package/src/runtime/faq-web.css +1 -0
  377. package/src/runtime/faq-web.html +6 -0
  378. package/src/runtime/gcp-sources.json +9 -0
  379. package/src/runtime/gcp_acceptance.py +110 -0
  380. package/src/runtime/gcp_structured.py +150 -0
  381. package/src/runtime/http_acceptance.py +39 -0
  382. package/src/runtime/iap-web-app.js +36 -0
  383. package/src/runtime/iap-web-source.json +1 -0
  384. package/src/runtime/ibm-python-lock.json +856 -0
  385. package/src/runtime/ibm-sources.json +9 -0
  386. package/src/runtime/ibm_acceptance.py +133 -0
  387. package/src/runtime/ibm_structured.py +113 -0
  388. package/src/runtime/invoice-azapi-provider-lock.json +7 -0
  389. package/src/runtime/invoice-ibm-provider-lock.json +7 -0
  390. package/src/runtime/invoice-parser-lock.json +1199 -0
  391. package/src/runtime/invoice-parser-python-lock.json +56 -0
  392. package/src/runtime/invoice-parser.Dockerfile +190 -0
  393. package/src/runtime/invoice-sources.json +58 -0
  394. package/src/runtime/invoice-test-sources.json +24 -0
  395. package/src/runtime/invoice-web.css +2 -0
  396. package/src/runtime/invoice-web.html +12 -0
  397. package/src/runtime/invoice-web.js +112 -0
  398. package/src/runtime/invoice_configuration.py +17 -0
  399. package/src/runtime/invoice_document.py +95 -0
  400. package/src/runtime/invoice_extraction.py +96 -0
  401. package/src/runtime/invoice_http.py +129 -0
  402. package/src/runtime/invoice_identity.py +5 -0
  403. package/src/runtime/invoice_maintenance.py +40 -0
  404. package/src/runtime/invoice_native.py +77 -0
  405. package/src/runtime/invoice_object_store.py +153 -0
  406. package/src/runtime/invoice_operations.py +108 -0
  407. package/src/runtime/invoice_operator.py +79 -0
  408. package/src/runtime/invoice_operator_core.py +39 -0
  409. package/src/runtime/invoice_operator_job.py +147 -0
  410. package/src/runtime/invoice_parser_cli.py +17 -0
  411. package/src/runtime/invoice_parser_identity.py +39 -0
  412. package/src/runtime/invoice_parser_service.py +89 -0
  413. package/src/runtime/invoice_parser_transport.py +89 -0
  414. package/src/runtime/invoice_processing.py +24 -0
  415. package/src/runtime/invoice_retention.py +16 -0
  416. package/src/runtime/invoice_runtime_secrets.py +43 -0
  417. package/src/runtime/invoice_stage.py +80 -0
  418. package/src/runtime/invoice_web.py +39 -0
  419. package/src/runtime/invoice_worker.py +50 -0
  420. package/src/runtime/lambda_faq.py +5 -0
  421. package/src/runtime/parser-requirements.lock +4 -0
  422. package/src/runtime/policy_review.py +18 -0
  423. package/src/runtime/postgres-qualification-lock.json +21 -0
  424. package/src/runtime/public-faq-sources.json +22 -0
  425. package/src/runtime/public_catalog_admin.py +122 -0
  426. package/src/runtime/public_catalog_store.py +125 -0
  427. package/src/runtime/public_faq.py +144 -0
  428. package/src/runtime/public_faq_app.py +49 -0
  429. package/src/runtime/python-container-lock.json +18 -0
  430. package/src/runtime/rag-sources.json +10 -0
  431. package/src/runtime/rag_acceptance.py +60 -0
  432. package/src/runtime/rag_aws_adapter.py +95 -0
  433. package/src/runtime/rds-ca-source.json +9 -0
  434. package/src/runtime/rds-global-ca.pem +2888 -0
  435. package/src/runtime/state-contract-check-source.json +4 -0
  436. package/src/runtime/state_contract_check.py +338 -0
  437. package/src/runtime/structured-source.json +1 -0
  438. package/src/runtime/structured-web-app.js +71 -0
  439. package/src/runtime/structured-web-source.json +1 -0
  440. package/src/runtime/structured_http.py +105 -0
  441. package/src/runtime/structured_output.py +48 -0
  442. package/src/runtime/web-python-lock.json +802 -0
  443. package/src/runtime/web_user_admin.py +44 -0
  444. package/src/runtime/workflow_application.py +62 -0
  445. package/src/runtime/workflow_bindings.py +128 -0
  446. package/src/runtime/workflow_configuration.py +40 -0
  447. package/src/runtime/workflow_connection.py +105 -0
  448. package/src/runtime/workflow_contract.py +54 -0
  449. package/src/runtime/workflow_database.py +94 -0
  450. package/src/runtime/workflow_errors.py +6 -0
  451. package/src/runtime/workflow_http.py +178 -0
  452. package/src/runtime/workflow_identity.py +69 -0
  453. package/src/runtime/workflow_payload.py +118 -0
  454. package/src/runtime/workflow_process_stage.py +88 -0
  455. package/src/runtime/workflow_profile.py +91 -0
  456. package/src/runtime/workflow_review.py +106 -0
  457. package/src/runtime/workflow_role_bootstrap.py +104 -0
  458. package/src/runtime/workflow_schema.sql +72 -0
  459. package/src/runtime/workflow_worker.py +142 -0
  460. package/src/runtime-settings.mjs +15 -0
  461. package/src/s3-access.mjs +14 -0
  462. package/src/source-contracts.mjs +17 -0
  463. package/src/spec-kit.mjs +186 -0
  464. package/src/state-custody.mjs +32 -0
  465. package/src/state-inspection.mjs +45 -0
  466. package/src/state-spec-kit.mjs +13 -0
  467. package/src/storage-tests.mjs +25 -0
  468. package/src/structured-api.mjs +133 -0
  469. package/src/structured-contract.mjs +19 -0
  470. package/src/structured-operation-policy.mjs +2 -0
  471. package/src/structured-web.mjs +17 -0
  472. package/src/style.css +1 -0
  473. package/src/system-description.mjs +26 -0
  474. package/src/terraform-admission.mjs +66 -0
  475. package/src/terraform-composition.mjs +83 -0
  476. package/src/terraform-expressions.mjs +46 -0
  477. package/src/terraform-validation-coverage.mjs +11 -0
  478. package/src/terraform.mjs +128 -0
  479. package/src/text-statistics.mjs +51 -0
  480. package/src/upstream/openarchflow/format-payload.ts +26 -0
  481. package/src/upstream/openarchflow/import/mermaid.ts +205 -0
  482. package/src/upstream/openarchflow/import/sql-ddl.ts +109 -0
  483. package/src/upstream/openarchflow/layout.ts +54 -0
  484. package/src/upstream/openarchflow/providers/aws.ts +196 -0
  485. package/src/upstream/openarchflow/providers/azure.ts +126 -0
  486. package/src/upstream/openarchflow/providers/cloudnative.ts +71 -0
  487. package/src/upstream/openarchflow/providers/generic.ts +227 -0
  488. package/src/upstream/openarchflow/providers/integration.ts +22 -0
  489. package/src/upstream/openarchflow/providers/types.ts +2 -0
  490. package/src/upstream/openarchflow/templates.ts +937 -0
  491. package/src/upstream-catalog.mjs +10 -0
  492. package/src/useChatScroll.jsx +36 -0
  493. package/src/useEmulation.jsx +36 -0
  494. package/src/validation-receipt.mjs +10 -0
  495. package/src/visual-export.mjs +92 -0
  496. package/src/voice-conversation.mjs +117 -0
  497. package/src/work-intake.mjs +24 -0
  498. package/src/workflow-runtime-inventory.mjs +3 -0
@@ -0,0 +1,91 @@
1
+ """Append-only private audit: owned identity/trace plus bounded outcome counts.
2
+
3
+ Never store questions, titles, source/document IDs, snippets, answers or secrets.
4
+ Withheld events must remain recordable after consent/session expiry or withdrawal;
5
+ this writer is not an authorization grant. SQL failure prevents answer release.
6
+ """
7
+ import hashlib
8
+ from pathlib import Path
9
+ import re
10
+ import uuid
11
+ from psycopg import sql
12
+ from enterprise_identity import CompanyPrincipal
13
+ from enterprise_sources import SourceUnavailable
14
+
15
+
16
+ class KnowledgeAudit:
17
+ def __init__(self, auth, account_id):
18
+ if not isinstance(account_id, str) or not re.fullmatch(r'[A-Za-z0-9_-]{1,128}', account_id):
19
+ raise ValueError('Supply the owned company audit domain')
20
+ self.auth, self.account_id = auth, account_id
21
+
22
+ def bind(self, principal, *, query_id=None, attempt=None):
23
+ if not isinstance(principal, CompanyPrincipal) or principal.account_id != self.account_id:
24
+ raise ValueError('Audit identity must belong to the owned company')
25
+ if query_id is not None:
26
+ if (not isinstance(query_id, str) or str(uuid.UUID(query_id)) != query_id
27
+ or type(attempt) is not int or not 1 <= attempt <= 3):
28
+ raise ValueError('Supply the owned canonical question attempt')
29
+ elif attempt is not None:
30
+ raise ValueError('Audit attempt requires its question identity')
31
+ trace = str(uuid.uuid4())
32
+
33
+ def record(event):
34
+ if (not isinstance(event, dict) or set(event) not in (
35
+ {'event', 'outcome', 'sources'}, {'event', 'outcome', 'sources', 'documents'})
36
+ or event['event'] not in {'knowledge.answer', 'knowledge.release'}
37
+ or event['outcome'] not in ({'answered', 'abstained', 'withheld'} if event['event'] == 'knowledge.answer' else {'released', 'withheld'})
38
+ or type(event['sources']) is not int or not 1 <= event['sources'] <= 20):
39
+ raise ValueError('Invalid owned audit event')
40
+ documents = event.get('documents')
41
+ if ((documents is not None and (type(documents) is not int or not 0 <= documents <= event['sources'] * 4))
42
+ or (event['outcome'] != 'withheld' and documents is None)):
43
+ raise ValueError('Invalid owned audit counts')
44
+ values = (self.account_id, principal.key, trace, query_id, attempt,
45
+ event['event'], event['outcome'], event['sources'], documents)
46
+ try:
47
+ with self.auth.transaction() as cursor:
48
+ statement = '''INSERT INTO enterprise_audit.events
49
+ (account_id,principal_key,trace_id,query_id,attempt,event,outcome,source_count,document_count)
50
+ SELECT %s,%s,%s,%s,%s,%s,%s,%s,%s'''
51
+ if query_id is not None:
52
+ # The trace comes from a known owned question/attempt, not
53
+ # an arbitrary event dictionary or model-provided identity.
54
+ statement += ''' WHERE EXISTS(SELECT 1 FROM enterprise_queries.requests
55
+ WHERE id=%s AND account_id=%s AND principal_key=%s AND attempt>=%s)'''
56
+ values += (query_id, self.account_id, principal.key, attempt)
57
+ cursor.execute(statement, values)
58
+ if cursor.rowcount != 1:
59
+ raise ValueError('Audit question binding is no longer available')
60
+ except Exception:
61
+ raise SourceUnavailable('knowledge_audit_unavailable') from None
62
+ return record
63
+
64
+
65
+ def initialize_audit(conn):
66
+ if conn.autocommit:
67
+ raise ValueError('Use an operator transaction for a fresh audit schema')
68
+ body = Path(__file__).with_name('enterprise_audit_schema.sql').read_bytes()
69
+ conn.execute(body.decode())
70
+ conn.execute('INSERT INTO enterprise_audit.schema_version VALUES(1,%s)', (hashlib.sha256(body).hexdigest(),))
71
+
72
+
73
+ def grant_audit_writer(conn, role):
74
+ if conn.autocommit or not isinstance(role, str) or not re.fullmatch(r'[A-Za-z0-9_.@-]{1,63}', role):
75
+ raise ValueError('Use an owned nonadministrative role and operator transaction')
76
+ expected = hashlib.sha256(Path(__file__).with_name('enterprise_audit_schema.sql').read_bytes()).hexdigest()
77
+ if conn.execute('SELECT version,source_sha256 FROM enterprise_audit.schema_version').fetchone() != (1, expected):
78
+ raise ValueError('Review the exact fresh audit schema before granting access')
79
+ flags = conn.execute('SELECT rolsuper,rolcreatedb,rolcreaterole,rolreplication,rolbypassrls,rolcanlogin FROM pg_roles WHERE rolname=%s', (role,)).fetchone()
80
+ if not flags or any(flags[:5]) or not flags[5] or conn.execute("SELECT has_schema_privilege(%s,'enterprise_audit','CREATE')", (role,)).fetchone()[0]:
81
+ raise ValueError('Use a nonadministrative role that does not own the audit schema')
82
+ for table in ['memberships', 'source_mappings', 'company_bindings', 'schema_version']:
83
+ if conn.execute('SELECT has_table_privilege(%s,%s,%s)', (role, 'enterprise_auth.' + table, 'INSERT,UPDATE,DELETE,TRUNCATE,TRIGGER,REFERENCES')).fetchone()[0]:
84
+ raise ValueError('Audit runtime must not inherit authority-table write privileges')
85
+ if conn.execute("SELECT has_table_privilege(%s,'enterprise_audit.events','SELECT,UPDATE,DELETE,TRUNCATE,TRIGGER,REFERENCES')", (role,)).fetchone()[0]:
86
+ raise ValueError('Audit writer must not inherit history read/change permissions')
87
+ target = sql.Identifier(role)
88
+ conn.execute(sql.SQL('GRANT USAGE ON SCHEMA enterprise_audit TO {}').format(target))
89
+ conn.execute(sql.SQL('GRANT SELECT ON enterprise_audit.schema_version TO {}').format(target))
90
+ conn.execute(sql.SQL('GRANT INSERT ON enterprise_audit.events TO {}').format(target))
91
+ conn.execute(sql.SQL('GRANT USAGE ON SEQUENCE enterprise_audit.events_id_seq TO {}').format(target))
@@ -0,0 +1,25 @@
1
+ -- Fresh owned installation. Runtime can append, but cannot read/rewrite history.
2
+ CREATE SCHEMA enterprise_audit;
3
+ REVOKE ALL ON SCHEMA enterprise_audit FROM PUBLIC;
4
+ CREATE TABLE enterprise_audit.schema_version(
5
+ version integer PRIMARY KEY CHECK(version=1),source_sha256 text NOT NULL
6
+ );
7
+ CREATE TABLE enterprise_audit.events(
8
+ id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
9
+ account_id text NOT NULL,principal_key text NOT NULL CHECK(principal_key ~ '^[0-9a-f]{64}$'),
10
+ trace_id uuid NOT NULL,query_id uuid,attempt integer CHECK(attempt BETWEEN 1 AND 3),
11
+ event text NOT NULL CHECK(event IN('knowledge.answer','knowledge.release')),
12
+ outcome text NOT NULL CHECK(outcome IN('answered','abstained','withheld','released')),
13
+ source_count integer NOT NULL CHECK(source_count BETWEEN 1 AND 20),
14
+ document_count integer CHECK(document_count BETWEEN 0 AND 80),
15
+ created_at timestamptz NOT NULL DEFAULT clock_timestamp(),
16
+ CHECK((query_id IS NULL)=(attempt IS NULL)),
17
+ CHECK((event='knowledge.answer' AND outcome IN('answered','abstained','withheld'))
18
+ OR(event='knowledge.release' AND outcome IN('released','withheld'))),
19
+ CHECK((outcome='withheld') OR document_count IS NOT NULL),
20
+ CHECK(document_count IS NULL OR document_count<=source_count*4)
21
+ );
22
+ CREATE INDEX enterprise_audit_owner_time ON enterprise_audit.events(account_id,created_at);
23
+ CREATE INDEX enterprise_audit_query ON enterprise_audit.events(account_id,query_id,attempt);
24
+ REVOKE ALL ON ALL TABLES IN SCHEMA enterprise_audit FROM PUBLIC;
25
+ REVOKE ALL ON ALL SEQUENCES IN SCHEMA enterprise_audit FROM PUBLIC;
@@ -0,0 +1,67 @@
1
+ -- Fresh owned installation only. Operator controls membership/source mappings;
2
+ -- application roles must never acquire their write permissions.
3
+ CREATE SCHEMA enterprise_auth;
4
+ REVOKE ALL ON SCHEMA enterprise_auth FROM PUBLIC;
5
+ CREATE TABLE enterprise_auth.schema_version(version integer PRIMARY KEY CHECK(version=1),source_sha256 text NOT NULL);
6
+ CREATE TABLE enterprise_auth.company_bindings(
7
+ account_id text PRIMARY KEY,session_domain text NOT NULL CHECK(session_domain ~ '^[0-9a-f]{64}$'),
8
+ version bigint NOT NULL CHECK(version>0),actor text NOT NULL DEFAULT current_user,
9
+ updated_at timestamptz NOT NULL DEFAULT clock_timestamp()
10
+ );
11
+ CREATE TABLE enterprise_auth.memberships(
12
+ account_id text NOT NULL,principal_key text NOT NULL CHECK(principal_key ~ '^[0-9a-f]{64}$'),
13
+ issuer text NOT NULL,subject text NOT NULL,active boolean NOT NULL DEFAULT false,
14
+ PRIMARY KEY(account_id,principal_key)
15
+ );
16
+ CREATE TABLE enterprise_auth.source_mappings(
17
+ account_id text NOT NULL,principal_key text NOT NULL,source_id text NOT NULL,
18
+ source_subject text NOT NULL CHECK(length(source_subject) BETWEEN 1 AND 255),
19
+ version bigint NOT NULL CHECK(version>0),active boolean NOT NULL DEFAULT false,
20
+ PRIMARY KEY(account_id,principal_key,source_id),
21
+ FOREIGN KEY(account_id,principal_key)REFERENCES enterprise_auth.memberships
22
+ );
23
+ CREATE TABLE enterprise_auth.attempts(
24
+ state_sha256 text PRIMARY KEY CHECK(state_sha256 ~ '^[0-9a-f]{64}$'),
25
+ account_id text NOT NULL,principal_key text NOT NULL,source_id text NOT NULL,
26
+ mapping_version bigint NOT NULL,browser_sha256 text NOT NULL,
27
+ flow_ciphertext text NOT NULL,expires_at timestamptz NOT NULL,consumed_at timestamptz,completed_at timestamptz,
28
+ FOREIGN KEY(account_id,principal_key,source_id)REFERENCES enterprise_auth.source_mappings
29
+ );
30
+ CREATE INDEX enterprise_auth_attempts_expiry ON enterprise_auth.attempts(expires_at);
31
+ CREATE TABLE enterprise_auth.connections(
32
+ account_id text NOT NULL,principal_key text NOT NULL,source_id text NOT NULL,
33
+ mapping_version bigint NOT NULL,consent_id uuid NOT NULL,revision bigint NOT NULL CHECK(revision>0),
34
+ credential_ciphertext text,status text NOT NULL CHECK(status IN('connected','refreshing','needs_reconnect','revoked')),
35
+ updated_at timestamptz NOT NULL DEFAULT clock_timestamp(),
36
+ PRIMARY KEY(account_id,principal_key,source_id),
37
+ FOREIGN KEY(account_id,principal_key,source_id)REFERENCES enterprise_auth.source_mappings,
38
+ CHECK((status IN('connected','refreshing'))=(credential_ciphertext IS NOT NULL))
39
+ );
40
+ CREATE TABLE enterprise_auth.events(
41
+ id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
42
+ account_id text NOT NULL,principal_key text NOT NULL,source_id text NOT NULL,
43
+ event text NOT NULL CHECK(event IN('connect_started','connect_completed','refresh_completed','needs_reconnect','disconnected','session_started','session_ended')),
44
+ created_at timestamptz NOT NULL DEFAULT clock_timestamp()
45
+ );
46
+ CREATE TABLE enterprise_auth.administration_events(
47
+ id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
48
+ account_id text NOT NULL,principal_key text CHECK(principal_key IS NULL OR principal_key ~ '^[0-9a-f]{64}$'),
49
+ actor text NOT NULL DEFAULT current_user,
50
+ action text NOT NULL CHECK(action IN('membership_enabled','membership_disabled','mapping_updated','company_registration_updated')),
51
+ source_alias text CHECK(source_alias IN('sharepoint','confluence')),
52
+ mapping_version bigint,registration_version bigint,registration_domain text CHECK(registration_domain IS NULL OR registration_domain ~ '^[0-9a-f]{64}$'),active boolean NOT NULL,
53
+ created_at timestamptz NOT NULL DEFAULT clock_timestamp(),
54
+ CHECK((action='mapping_updated')=(source_alias IS NOT NULL AND mapping_version IS NOT NULL)),
55
+ CHECK((action='company_registration_updated')=(principal_key IS NULL)),
56
+ CHECK((action='company_registration_updated')=(registration_version IS NOT NULL AND registration_domain IS NOT NULL))
57
+ );
58
+ CREATE TABLE enterprise_auth.sessions(
59
+ session_sha256 text PRIMARY KEY CHECK(session_sha256 ~ '^[0-9a-f]{64}$'),
60
+ account_id text NOT NULL,principal_key text NOT NULL,csrf_sha256 text NOT NULL,
61
+ nonce_ciphertext text NOT NULL,expires_at timestamptz NOT NULL,
62
+ created_at timestamptz NOT NULL DEFAULT clock_timestamp(),revoked_at timestamptz,
63
+ FOREIGN KEY(account_id,principal_key)REFERENCES enterprise_auth.memberships
64
+ );
65
+ CREATE INDEX enterprise_auth_sessions_owner ON enterprise_auth.sessions(account_id,principal_key,created_at);
66
+ REVOKE ALL ON ALL TABLES IN SCHEMA enterprise_auth FROM PUBLIC;
67
+ REVOKE ALL ON ALL SEQUENCES IN SCHEMA enterprise_auth FROM PUBLIC;
@@ -0,0 +1,241 @@
1
+ """Transactional, encrypted per-person source credentials and one-use OAuth state.
2
+
3
+ DB transport and the encryption key are injected by an owned native deployment.
4
+ No cloud key is generated or persisted here. API credentials are never logged.
5
+ """
6
+ from contextlib import contextmanager
7
+ from dataclasses import dataclass,field
8
+ import hashlib
9
+ import base64
10
+ import hmac
11
+ import json
12
+ from pathlib import Path
13
+ import re
14
+ import secrets
15
+ import uuid
16
+ from cryptography.fernet import Fernet,InvalidToken
17
+ from cryptography.hazmat.primitives import hashes
18
+ from cryptography.hazmat.primitives.kdf.hkdf import HKDF
19
+ from psycopg.rows import dict_row
20
+ from enterprise_identity import CompanyPrincipal
21
+ from enterprise_sources import SourceDenied,SourceUnavailable,DelegatedAccess
22
+
23
+
24
+ def digest(value):return hashlib.sha256(value.encode()).hexdigest()
25
+ def opaque(value):
26
+ if not isinstance(value,str)or not 1<=len(value)<=160 or any(ord(c)<33 for c in value):raise SourceDenied('invalid_source_binding')
27
+ return value
28
+
29
+
30
+ def secret_binding(value):
31
+ if not isinstance(value,str)or not re.fullmatch(r'[A-Za-z0-9_-]{32,160}',value):raise SourceDenied('invalid_oauth_browser_binding')
32
+ return value
33
+
34
+
35
+ class CredentialBox:
36
+ def __init__(self,key):
37
+ self.box=Fernet(key)
38
+ self._fingerprint_key=HKDF(algorithm=hashes.SHA256(),length=32,salt=None,info=b'atmem-enterprise-private-fingerprint-v1').derive(base64.urlsafe_b64decode(key))
39
+ def fingerprint(self,context,value):
40
+ raw=json.dumps({'context':context,'value':value},sort_keys=True,separators=(',',':')).encode()
41
+ if len(raw)>2000000:raise SourceUnavailable('credential_material_too_large')
42
+ return hmac.new(self._fingerprint_key,raw,hashlib.sha256).hexdigest()
43
+ def seal(self,context,value):
44
+ raw=json.dumps({'context':context,'value':value},sort_keys=True,separators=(',',':')).encode()
45
+ if len(raw)>2000000:raise SourceUnavailable('credential_material_too_large')
46
+ return self.box.encrypt(raw).decode()
47
+ def open(self,context,ciphertext):
48
+ try:
49
+ raw=self.box.decrypt(ciphertext.encode());value=json.loads(raw)
50
+ if value['context']!=context or not isinstance(value['value'],dict):raise ValueError('Invalid context')
51
+ return value['value']
52
+ except (InvalidToken,ValueError,KeyError,TypeError,AttributeError):raise SourceDenied('credential_binding_invalid')from None
53
+
54
+
55
+ @dataclass(frozen=True)
56
+ class SourceMapping:
57
+ source_id: str
58
+ source_subject: str
59
+ version: int
60
+ attempt_sha256: str|None = field(default=None,repr=False,compare=False)
61
+
62
+
63
+ @dataclass(frozen=True)
64
+ class SourceWitness:
65
+ source_id: str
66
+ source_subject: str = field(repr=False)
67
+ mapping_version: int
68
+ consent_id: str = field(repr=False)
69
+
70
+
71
+ class EnterpriseAuthStore:
72
+ def __init__(self,connect,key,*,company_domain=None):
73
+ if company_domain is not None and(not isinstance(company_domain,str)or not re.fullmatch('[0-9a-f]{64}',company_domain)):raise ValueError('Use the owned company authority domain')
74
+ self.connect=connect;self.box=CredentialBox(key);self.company_domain=company_domain
75
+
76
+ @contextmanager
77
+ def transaction(self):
78
+ with self.connect()as conn:
79
+ if conn.autocommit:raise ValueError('Credential operations require a transaction')
80
+ with conn.cursor(row_factory=dict_row)as cur:
81
+ cur.execute("SET LOCAL search_path=pg_catalog,enterprise_auth,pg_temp");cur.execute("SET LOCAL lock_timeout='3s'");cur.execute("SET LOCAL statement_timeout='10s'")
82
+ yield cur
83
+
84
+ def require_company(self,cur,account_id):
85
+ if self.company_domain is not None:
86
+ row=cur.execute('SELECT session_domain FROM enterprise_auth.company_bindings WHERE account_id=%s',(account_id,)).fetchone()
87
+ if not row or row['session_domain']!=self.company_domain:raise SourceDenied('company_registration_changed')
88
+
89
+ def _authorize(self,cur,principal,source_id=None):
90
+ if not isinstance(principal,CompanyPrincipal):raise SourceDenied('company_identity_required')
91
+ principal.require()
92
+ self.require_company(cur,principal.account_id)
93
+ membership=cur.execute('SELECT issuer,subject,active FROM enterprise_auth.memberships WHERE account_id=%s AND principal_key=%s',(principal.account_id,principal.key)).fetchone()
94
+ if not membership or not membership['active']or membership['issuer']!=principal.issuer or membership['subject']!=principal.subject:raise SourceDenied('company_membership_required')
95
+ if source_id is None:return None
96
+ opaque(source_id)
97
+ row=cur.execute('SELECT source_subject,version,active FROM enterprise_auth.source_mappings WHERE account_id=%s AND principal_key=%s AND source_id=%s',(principal.account_id,principal.key,source_id)).fetchone()
98
+ if not row or not row['active']:raise SourceDenied('source_mapping_required')
99
+ return SourceMapping(source_id,row['source_subject'],row['version'])
100
+
101
+ def authorize(self,principal):
102
+ with self.transaction()as cur:self._authorize(cur,principal)
103
+
104
+ def source_witness(self,principal,source_id):
105
+ with self.transaction()as cur:
106
+ mapping=self._authorize(cur,principal,source_id)
107
+ row=cur.execute('SELECT mapping_version,consent_id,status FROM enterprise_auth.connections WHERE account_id=%s AND principal_key=%s AND source_id=%s',(principal.account_id,principal.key,source_id)).fetchone()
108
+ # Refresh can rotate credential material without changing consent.
109
+ # Native adapters independently check the access token's lifetime and
110
+ # current source permissions; failed/uncertain reconnection is denied.
111
+ if not row or row['status']not in {'connected','refreshing'}or row['mapping_version']!=mapping.version:raise SourceDenied('source_consent_required')
112
+ return SourceWitness(source_id,mapping.source_subject,mapping.version,str(row['consent_id']))
113
+
114
+ def check_source_witness(self,principal,witness):
115
+ if not isinstance(witness,SourceWitness)or self.source_witness(principal,witness.source_id)!=witness:raise SourceDenied('source_connection_changed')
116
+
117
+ def context(self,principal,mapping,kind):return [kind,principal.account_id,principal.key,mapping.source_id,mapping.version]
118
+ def event(self,cur,principal,source_id,event):cur.execute('INSERT INTO enterprise_auth.events(account_id,principal_key,source_id,event)VALUES(%s,%s,%s,%s)',(principal.account_id,principal.key,source_id,event))
119
+
120
+ def begin(self,principal,source_id,browser_nonce,flow,state=None):
121
+ secret_binding(browser_nonce)
122
+ if not isinstance(flow,dict):raise ValueError('Supply a native OAuth flow object')
123
+ state=state or secrets.token_urlsafe(32);secret_binding(state)
124
+ with self.transaction()as cur:
125
+ mapping=self._authorize(cur,principal,source_id)
126
+ cur.execute('SELECT pg_advisory_xact_lock(hashtextextended(%s,0))',('enterprise-oauth-start:'+principal.account_id+':'+principal.key,))
127
+ # Bound abandoned attempts without deleting another person's state.
128
+ cur.execute("DELETE FROM enterprise_auth.attempts WHERE account_id=%s AND principal_key=%s AND expires_at<clock_timestamp()AND(consumed_at IS NULL OR consumed_at<clock_timestamp()-interval '1 minute')",(principal.account_id,principal.key))
129
+ count=cur.execute('SELECT count(*) AS n FROM enterprise_auth.attempts WHERE account_id=%s AND principal_key=%s AND consumed_at IS NULL',(principal.account_id,principal.key)).fetchone()['n']
130
+ if count>=5:raise SourceUnavailable('oauth_attempt_limit')
131
+ encrypted=self.box.seal(self.context(principal,mapping,'flow')+[digest(state)],flow)
132
+ cur.execute("INSERT INTO enterprise_auth.attempts(state_sha256,account_id,principal_key,source_id,mapping_version,browser_sha256,flow_ciphertext,expires_at)VALUES(%s,%s,%s,%s,%s,%s,%s,clock_timestamp()+interval '5 minutes')",(digest(state),principal.account_id,principal.key,source_id,mapping.version,digest(browser_nonce),encrypted))
133
+ self.event(cur,principal,source_id,'connect_started')
134
+ return state
135
+
136
+ def consume(self,principal,source_id,browser_nonce,state):
137
+ secret_binding(browser_nonce);secret_binding(state)
138
+ with self.transaction()as cur:
139
+ mapping=self._authorize(cur,principal,source_id)
140
+ row=cur.execute('UPDATE enterprise_auth.attempts SET consumed_at=clock_timestamp()WHERE state_sha256=%s AND account_id=%s AND principal_key=%s AND source_id=%s AND mapping_version=%s AND browser_sha256=%s AND consumed_at IS NULL AND expires_at>clock_timestamp() RETURNING flow_ciphertext',(digest(state),principal.account_id,principal.key,source_id,mapping.version,digest(browser_nonce))).fetchone()
141
+ if not row:raise SourceDenied('oauth_state_unavailable')
142
+ flow=self.box.open(self.context(principal,mapping,'flow')+[digest(state)],row['flow_ciphertext'])
143
+ # Commit consumption before any network exchange: uncertain code redemption
144
+ # requires a fresh consent flow, never a blind authorization-code replay.
145
+ return SourceMapping(mapping.source_id,mapping.source_subject,mapping.version,digest(state)),flow
146
+
147
+ def save(self,principal,mapping,material):
148
+ if not isinstance(material,dict):raise ValueError('Supply verified native credential material')
149
+ with self.transaction()as cur:
150
+ current=self._authorize(cur,principal,mapping.source_id)
151
+ if current!=mapping:raise SourceDenied('source_mapping_changed')
152
+ if not isinstance(mapping.attempt_sha256,str)or not re.fullmatch('[0-9a-f]{64}',mapping.attempt_sha256):raise SourceDenied('source_consent_unavailable')
153
+ self._connection_lock(cur,principal,mapping.source_id)
154
+ receipt=cur.execute("SELECT state_sha256 FROM enterprise_auth.attempts WHERE state_sha256=%s AND account_id=%s AND principal_key=%s AND source_id=%s AND mapping_version=%s AND consumed_at IS NOT NULL AND consumed_at>clock_timestamp()-interval '1 minute'AND completed_at IS NULL FOR UPDATE",(mapping.attempt_sha256,principal.account_id,principal.key,mapping.source_id,mapping.version)).fetchone()
155
+ if not receipt:raise SourceDenied('source_connection_changed')
156
+ consent_id=str(uuid.uuid4())
157
+ encrypted=self.box.seal(self.context(principal,mapping,'credential')+[consent_id],material)
158
+ cur.execute("INSERT INTO enterprise_auth.connections(account_id,principal_key,source_id,mapping_version,consent_id,revision,credential_ciphertext,status)VALUES(%s,%s,%s,%s,%s,1,%s,'connected')ON CONFLICT(account_id,principal_key,source_id)DO UPDATE SET mapping_version=EXCLUDED.mapping_version,consent_id=EXCLUDED.consent_id,revision=enterprise_auth.connections.revision+1,credential_ciphertext=EXCLUDED.credential_ciphertext,status='connected',updated_at=clock_timestamp()",(principal.account_id,principal.key,mapping.source_id,mapping.version,consent_id,encrypted))
159
+ cur.execute('UPDATE enterprise_auth.attempts SET completed_at=clock_timestamp()WHERE state_sha256=%s',(mapping.attempt_sha256,))
160
+ self.event(cur,principal,mapping.source_id,'connect_completed')
161
+
162
+ def _abandon(self,principal,source_id,revision):
163
+ with self.transaction()as cur:
164
+ row=cur.execute("UPDATE enterprise_auth.connections SET credential_ciphertext=NULL,status='needs_reconnect',updated_at=clock_timestamp()WHERE account_id=%s AND principal_key=%s AND source_id=%s AND revision=%s AND status='refreshing'RETURNING revision",(principal.account_id,principal.key,source_id,revision)).fetchone()
165
+ if row:self.event(cur,principal,source_id,'needs_reconnect')
166
+
167
+ def credentials(self,principal,source_id,refresh):
168
+ # Persist the refresh intent BEFORE HTTP. A crash leaves a durable fence,
169
+ # not an old token that another replica can silently reuse. No DB lock is
170
+ # held across the source request; revocation/disconnection can proceed.
171
+ stale=False
172
+ with self.transaction()as cur:
173
+ mapping=self._authorize(cur,principal,source_id)
174
+ row=cur.execute("SELECT mapping_version,consent_id,revision,credential_ciphertext,status,updated_at<clock_timestamp()-interval '1 minute' AS stale FROM enterprise_auth.connections WHERE account_id=%s AND principal_key=%s AND source_id=%s FOR UPDATE",(principal.account_id,principal.key,source_id)).fetchone()
175
+ if not row or row['mapping_version']!=mapping.version or row['status']not in {'connected','refreshing'}:raise SourceDenied('source_reconnection_required')
176
+ if row['status']=='refreshing':
177
+ if not row['stale']:raise SourceUnavailable('source_refresh_in_progress')
178
+ cur.execute("UPDATE enterprise_auth.connections SET credential_ciphertext=NULL,status='needs_reconnect',updated_at=clock_timestamp()WHERE account_id=%s AND principal_key=%s AND source_id=%s",(principal.account_id,principal.key,source_id))
179
+ self.event(cur,principal,source_id,'needs_reconnect');stale=True
180
+ else:
181
+ context=self.context(principal,mapping,'credential')+[str(row['consent_id'])];material=self.box.open(context,row['credential_ciphertext']);revision=row['revision']+1
182
+ cur.execute("UPDATE enterprise_auth.connections SET status='refreshing',revision=%s,updated_at=clock_timestamp()WHERE account_id=%s AND principal_key=%s AND source_id=%s",(revision,principal.account_id,principal.key,source_id))
183
+ if stale:raise SourceDenied('source_reconnection_required')
184
+ try:
185
+ updated,access=refresh(mapping,material)
186
+ if not isinstance(updated,dict)or not isinstance(access,DelegatedAccess)or access.source_subject!=mapping.source_subject:raise SourceDenied('source_refresh_identity_mismatch')
187
+ access.require(principal.key)
188
+ with self.transaction()as cur:
189
+ if self._authorize(cur,principal,source_id)!=mapping:raise SourceDenied('source_mapping_changed')
190
+ changed=cur.execute("UPDATE enterprise_auth.connections SET credential_ciphertext=%s,status='connected',revision=revision+1,updated_at=clock_timestamp()WHERE account_id=%s AND principal_key=%s AND source_id=%s AND revision=%s AND status='refreshing'RETURNING revision",(self.box.seal(context,updated),principal.account_id,principal.key,source_id,revision)).fetchone()
191
+ if not changed:raise SourceDenied('source_connection_changed')
192
+ self.event(cur,principal,source_id,'refresh_completed')
193
+ except Exception:
194
+ try:self._abandon(principal,source_id,revision)
195
+ except Exception:pass # Durable refreshing fence already committed.
196
+ raise SourceDenied('source_reconnection_required')from None
197
+ return access
198
+
199
+ def connection_status(self,principal,source_id):
200
+ with self.transaction()as cur:
201
+ self._authorize(cur,principal)
202
+ mapping=cur.execute('SELECT version,active FROM enterprise_auth.source_mappings WHERE account_id=%s AND principal_key=%s AND source_id=%s',(principal.account_id,principal.key,source_id)).fetchone()
203
+ if not mapping or not mapping['active']:return 'needs_setup'
204
+ row=cur.execute('SELECT mapping_version,status FROM enterprise_auth.connections WHERE account_id=%s AND principal_key=%s AND source_id=%s',(principal.account_id,principal.key,source_id)).fetchone()
205
+ if not row or row['mapping_version']!=mapping['version']:return 'needs_reconnect'
206
+ return row['status']
207
+
208
+ def _connection_lock(self,cur,principal,source_id):
209
+ cur.execute('SELECT pg_advisory_xact_lock(hashtextextended(%s,0))',('enterprise-connection:'+principal.account_id+':'+principal.key+':'+source_id,))
210
+
211
+ def disconnect(self,principal,source_id):
212
+ with self.transaction()as cur:
213
+ self._authorize(cur,principal,source_id)
214
+ self._connection_lock(cur,principal,source_id)
215
+ cur.execute("UPDATE enterprise_auth.connections SET credential_ciphertext=NULL,status='revoked',revision=revision+1,updated_at=clock_timestamp()WHERE account_id=%s AND principal_key=%s AND source_id=%s",(principal.account_id,principal.key,source_id))
216
+ cur.execute('DELETE FROM enterprise_auth.attempts WHERE account_id=%s AND principal_key=%s AND source_id=%s',(principal.account_id,principal.key,source_id))
217
+ self.event(cur,principal,source_id,'disconnected')
218
+
219
+
220
+ def initialize_auth_store(conn):
221
+ source=Path(__file__).with_name('enterprise_auth_schema.sql').read_bytes()
222
+ conn.execute(source.decode());conn.execute('INSERT INTO enterprise_auth.schema_version VALUES(1,%s)',(hashlib.sha256(source).hexdigest(),))
223
+
224
+
225
+ def grant_auth_runtime(conn,role):
226
+ from psycopg import sql
227
+ if conn.autocommit or not isinstance(role,str)or not re.fullmatch(r'[A-Za-z0-9_.@-]{1,63}',role):raise ValueError('Use an owned nonadministrative broker role and transaction')
228
+ expected=hashlib.sha256(Path(__file__).with_name('enterprise_auth_schema.sql').read_bytes()).hexdigest()
229
+ if conn.execute('SELECT version,source_sha256 FROM enterprise_auth.schema_version').fetchone()!=(1,expected):raise ValueError('Review the owned exact schema before grants')
230
+ flags=conn.execute('SELECT rolsuper,rolcreatedb,rolcreaterole,rolreplication,rolbypassrls,rolcanlogin FROM pg_roles WHERE rolname=%s',(role,)).fetchone()
231
+ if not flags or any(flags[:5])or not flags[5]:raise ValueError('Use an existing nonadministrative broker login')
232
+ if conn.execute('SELECT has_schema_privilege(%s,%s,%s)',(role,'enterprise_auth','CREATE')).fetchone()[0]:raise ValueError('Broker must not own or create authentication schema objects')
233
+ for table in ['memberships','source_mappings','company_bindings','schema_version']:
234
+ if conn.execute('SELECT has_table_privilege(%s,%s,%s)',(role,'enterprise_auth.'+table,'INSERT,UPDATE,DELETE,TRUNCATE,TRIGGER,REFERENCES')).fetchone()[0]:raise ValueError('Broker must not inherit authority-table write privileges')
235
+ name=sql.Identifier(role)
236
+ conn.execute(sql.SQL('GRANT USAGE ON SCHEMA enterprise_auth TO {}').format(name))
237
+ conn.execute(sql.SQL('GRANT SELECT ON enterprise_auth.schema_version,enterprise_auth.memberships,enterprise_auth.source_mappings,enterprise_auth.company_bindings TO {}').format(name))
238
+ conn.execute(sql.SQL('GRANT SELECT,INSERT,UPDATE,DELETE ON enterprise_auth.attempts,enterprise_auth.sessions TO {}').format(name))
239
+ conn.execute(sql.SQL('GRANT SELECT,INSERT,UPDATE ON enterprise_auth.connections TO {}').format(name))
240
+ conn.execute(sql.SQL('GRANT INSERT ON enterprise_auth.events TO {}').format(name))
241
+ conn.execute(sql.SQL('GRANT USAGE ON ALL SEQUENCES IN SCHEMA enterprise_auth TO {}').format(name))
@@ -0,0 +1,120 @@
1
+ """New dedicated ECS host preparation; no client content or credentials accepted."""
2
+ import base64
3
+ import json
4
+ import os
5
+ from pathlib import Path
6
+ import re
7
+ import stat
8
+ import subprocess
9
+ import sys
10
+ import uuid
11
+ sys.path.insert(0,str(Path(__file__).resolve().parent))
12
+ from enterprise_aws_host_probe import expected_policy,first_rule_matches
13
+
14
+
15
+ def unique(pairs):
16
+ result={}
17
+ for key,value in pairs:
18
+ if key in result:raise ValueError('Ambiguous host configuration')
19
+ result[key]=value
20
+ return result
21
+
22
+
23
+ def environment(raw):
24
+ values={}
25
+ for line in raw.splitlines():
26
+ if not line.strip()or line.lstrip().startswith('#'):continue
27
+ key,separator,value=line.partition('=')
28
+ if not separator or not re.fullmatch('[A-Z][A-Z0-9_]*',key)or key in values:raise ValueError('Invalid ECS environment')
29
+ values[key]=value
30
+ return values
31
+
32
+
33
+ def required(expected):
34
+ expected=expected_policy(expected)
35
+ return {'ECS_CLUSTER':expected['clusterArn'],'ECS_ENABLE_TASK_IAM_ROLE':'true','ECS_ENABLE_TASK_IAM_ROLE_NETWORK_HOST':'false',
36
+ 'ECS_ENGINE_TASK_CLEANUP_WAIT_DURATION':'1s','ECS_INSTANCE_ATTRIBUTES':json.dumps({'atmem-document-policy':expected['policySha256']},sort_keys=True,separators=(',',':'))}
37
+
38
+
39
+ def read_optional(path):
40
+ try:return Path(path).read_text()
41
+ except FileNotFoundError:return ''
42
+
43
+
44
+ def atomic(path,text):
45
+ path=Path(path);path.parent.mkdir(mode=0o755,parents=True,exist_ok=True)
46
+ parent=os.open(path.parent,os.O_RDONLY|os.O_DIRECTORY|os.O_NOFOLLOW);temporary='.atmem-'+uuid.uuid4().hex
47
+ try:
48
+ info=os.fstat(parent)
49
+ if info.st_uid!=os.geteuid()or stat.S_IMODE(info.st_mode)&0o022:raise ValueError('Unsafe host configuration directory')
50
+ try:
51
+ info=os.stat(path.name,dir_fd=parent,follow_symlinks=False)
52
+ if not stat.S_ISREG(info.st_mode)or info.st_uid!=os.geteuid():raise ValueError('Refuse unowned host configuration')
53
+ except FileNotFoundError:pass
54
+ fd=os.open(temporary,os.O_WRONLY|os.O_CREAT|os.O_EXCL|os.O_NOFOLLOW,0o600,dir_fd=parent)
55
+ with os.fdopen(fd,'w')as stream:stream.write(text);stream.flush();os.fsync(stream.fileno())
56
+ os.replace(temporary,path.name,src_dir_fd=parent,dst_dir_fd=parent);os.fsync(parent)
57
+ finally:
58
+ try:os.unlink(temporary,dir_fd=parent)
59
+ except FileNotFoundError:pass
60
+ os.close(parent)
61
+
62
+
63
+ def prepare(expected,*,read=read_optional,write=atomic):
64
+ updates=required(expected);raw=read('/etc/ecs/ecs.config');existing=environment(raw)
65
+ if existing.get('ECS_CLUSTER')not in {None,'','default',updates['ECS_CLUSTER']}:raise ValueError('Do not adopt an existing ECS host')
66
+ attributes=json.loads(existing.get('ECS_INSTANCE_ATTRIBUTES','{}'),object_pairs_hook=unique)
67
+ if attributes not in [{},{'atmem-document-policy':expected['policySha256']}]:raise ValueError('Do not replace existing host ownership')
68
+ daemon=json.loads(read('/etc/docker/daemon.json')or'{}',object_pairs_hook=unique)
69
+ if not isinstance(daemon,dict):raise ValueError('Invalid native daemon configuration')
70
+ daemon.update({'log-driver':'none','live-restore':False});daemon.pop('log-opts',None)
71
+ lines=[];seen=set()
72
+ for line in raw.splitlines():
73
+ key=line.partition('=')[0]
74
+ if key in updates:lines.append(key+'='+updates[key]);seen.add(key)
75
+ else:lines.append(line)
76
+ lines += [key+'='+value for key,value in updates.items()if key not in seen]
77
+ write('/etc/docker/daemon.json',json.dumps(daemon,sort_keys=True,separators=(',',':'))+'\n')
78
+ write('/etc/ecs/ecs.config','\n'.join(lines)+'\n')
79
+
80
+
81
+ def command(argv,*,absent=False):
82
+ if argv[0]=='/usr/bin/docker':argv=[argv[0],'--host','unix:///var/run/docker.sock',*argv[1:]]
83
+ result=subprocess.run(argv,stdin=subprocess.DEVNULL,stdout=subprocess.PIPE,stderr=subprocess.DEVNULL,timeout=4,
84
+ env={'PATH':'/usr/sbin:/usr/bin:/sbin:/bin','LANG':'C'})
85
+ if absent and result.returncode==1:return None
86
+ if result.returncode or len(result.stdout)>32768:raise ValueError('Native host preparation failed')
87
+ return result.stdout.decode().strip()
88
+
89
+
90
+ def guard(expected,*,read=read_optional,run=command):
91
+ updates=required(expected);values=environment(read('/etc/ecs/ecs.config'))
92
+ if any(values.get(key)!=value for key,value in updates.items()):raise ValueError('ECS configuration not prepared')
93
+ daemon=json.loads(read('/etc/docker/daemon.json'),object_pairs_hook=unique)
94
+ if daemon.get('log-driver')!='none'or daemon.get('live-restore',False)is not False or daemon.get('bridge','docker0')!='docker0':raise ValueError('Unsafe prepared daemon')
95
+ for field,value in [('LoggingDriver','none'),('LiveRestoreEnabled',False)]:
96
+ if json.loads(run(['/usr/bin/docker','info','--format','{{json .'+field+'}}']))!=value:raise ValueError('Running daemon differs from prepared policy')
97
+ options=json.loads(run(['/usr/bin/docker','info','--format','{{json .SecurityOptions}}']))
98
+ if 'name=seccomp,profile=builtin'not in options:raise ValueError('Native seccomp is not active')
99
+ bridge=json.loads(run(['/usr/bin/docker','network','inspect','bridge','--format','{{json .Options}}']))
100
+ if bridge.get('com.docker.network.bridge.name')!='docker0':raise ValueError('Default bridge changed')
101
+ for tool,destination in [('/usr/sbin/iptables','169.254.169.254/32'),('/usr/sbin/ip6tables','fd00:ec2::254/128')]:
102
+ if run([tool,'-w','2','-S','DOCKER-USER'],absent=True)is None:run([tool,'-w','2','-N','DOCKER-USER'])
103
+ for chain,rule in [('DOCKER-USER',['-i','docker0','-d',destination,'-j','DROP']),('FORWARD',['-j','DOCKER-USER'])]:
104
+ for _ in range(4):
105
+ if run([tool,'-w','2','-D',chain,*rule],absent=True)is None:break
106
+ run([tool,'-w','2','-I',chain,'1',*rule])
107
+ if not first_rule_matches(run([tool,'-w','2','-S','DOCKER-USER']),'DOCKER-USER',{'-i':'docker0','-d':destination,'-j':'DROP'}):raise ValueError('Metadata rule installation failed')
108
+ if not first_rule_matches(run([tool,'-w','2','-S','FORWARD']),'FORWARD',{'-j':'DOCKER-USER'}):raise ValueError('Metadata forwarding hook installation failed')
109
+
110
+
111
+ def main():
112
+ try:
113
+ if os.geteuid()!=0 or len(sys.argv)!=3 or sys.argv[1]not in {'prepare','guard'}or len(sys.argv[2])>4096:raise ValueError()
114
+ expected=json.loads(base64.b64decode(sys.argv[2],validate=True),object_pairs_hook=unique)
115
+ (prepare if sys.argv[1]=='prepare'else guard)(expected)
116
+ print(json.dumps({'status':'ok','phase':sys.argv[1]}))
117
+ except Exception:raise SystemExit(2)from None
118
+
119
+
120
+ if __name__=='__main__':main()