@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.
- package/CONSTITUTION.md +144 -0
- package/README.md +33 -2
- package/agent-skills/discovery/SKILL.md +48 -0
- package/agent-skills/discovery/topics.json +139 -0
- package/agent-skills/generation-capabilities.json +760 -0
- package/agent-skills/service-lifecycle.json +21 -0
- package/agent-skills/specialists/architecture/SKILL.md +15 -0
- package/agent-skills/specialists/aws/SKILL.md +17 -0
- package/agent-skills/specialists/azure/SKILL.md +7 -0
- package/agent-skills/specialists/composition/SKILL.md +17 -0
- package/agent-skills/specialists/devops/SKILL.md +10 -0
- package/agent-skills/specialists/finops/SKILL.md +7 -0
- package/agent-skills/specialists/gcp/SKILL.md +7 -0
- package/agent-skills/specialists/ibm/SKILL.md +7 -0
- package/agent-skills/specialists/manifest.json +13 -0
- package/agent-skills/specialists/pulumi/SKILL.md +7 -0
- package/agent-skills/specialists/security/SKILL.md +7 -0
- package/agent-skills/specialists/terraform/SKILL.md +14 -0
- package/agent-skills/upstream/aws/LICENSE +175 -0
- package/agent-skills/upstream/aws/SKILL.md +125 -0
- package/agent-skills/upstream/azure/LICENSE +21 -0
- package/agent-skills/upstream/azure/SKILL.md +387 -0
- package/agent-skills/upstream/gcp/LICENSE +202 -0
- package/agent-skills/upstream/gcp/SKILL.md +159 -0
- package/agent-skills/upstream/manifest.json +57 -0
- package/agent-skills/upstream/pulumi/LICENSE +201 -0
- package/agent-skills/upstream/pulumi/SKILL.md +501 -0
- package/agent-skills/upstream/terraform/LICENSE +373 -0
- package/agent-skills/upstream/terraform/SKILL.md +316 -0
- package/agent-skills/workflows/workflows.json +601 -0
- package/cli/architect.mjs +3 -0
- package/cli/runtime.mjs +115 -0
- package/dist/assets/html2canvas.esm-QH1iLAAe.js +22 -0
- package/dist/assets/index-B97MkVMs.css +1 -0
- package/dist/assets/index-qtCM2D7O.js +21271 -0
- package/dist/assets/index.es-C6C0sneB.js +18 -0
- package/dist/assets/purify.es-CAi2OJFm.js +3 -0
- package/dist/assets/visual-export-DjbjgQbA.js +173 -0
- package/dist/favicon.svg +2 -0
- package/dist/fonts/DM-Sans-OFL.txt +93 -0
- package/dist/fonts/Manrope-OFL.txt +93 -0
- package/dist/fonts/NotoSans-Regular.ttf +0 -0
- package/dist/fonts/OFL.txt +94 -0
- package/dist/fonts/dm-sans-latin-wght-normal.woff2 +0 -0
- package/dist/fonts/manrope-latin-wght-normal.woff2 +0 -0
- package/dist/index.html +4 -0
- package/dist/licenses/aws-architect-LICENSE.txt +17 -0
- package/dist/licenses/aws-mcp-LICENSE.txt +175 -0
- package/dist/licenses/aws-mcp-NOTICE.txt +1 -0
- package/dist/licenses/cloud-emulation-notices.txt +36619 -0
- package/dist/licenses/dependency-notices.txt +6379 -0
- package/dist/licenses/emulation-notices.txt +717 -0
- package/dist/licenses/github-copilot-sdk-LICENSE.txt +21 -0
- package/dist/licenses/memory-dependency-notices.txt +3319 -0
- package/dist/licenses/openarchflow-LICENSE.txt +21 -0
- package/dist/licenses/python-dependency-notices.txt +11951 -0
- package/docs/upstream-lock.json +26 -0
- package/knowledge/engineering-practices.json +536 -0
- package/package.json +30 -4
- package/packaging/uv-release-lock.json +54 -0
- package/public/licenses/aws-architect-LICENSE.txt +17 -0
- package/public/licenses/aws-mcp-LICENSE.txt +175 -0
- package/public/licenses/aws-mcp-NOTICE.txt +1 -0
- package/public/licenses/cloud-emulation-notices.txt +36619 -0
- package/public/licenses/dependency-notices.txt +6379 -0
- package/public/licenses/emulation-notices.txt +717 -0
- package/public/licenses/github-copilot-sdk-LICENSE.txt +21 -0
- package/public/licenses/memory-dependency-notices.txt +3319 -0
- package/public/licenses/openarchflow-LICENSE.txt +21 -0
- package/public/licenses/python-dependency-notices.txt +11951 -0
- package/scripts/terraform-render.mjs +8 -0
- package/server/__init__.py +0 -0
- package/server/abstraction.py +28 -0
- package/server/agent_runtime.py +153 -0
- package/server/app.py +257 -0
- package/server/architect.py +112 -0
- package/server/architecture_activity.py +67 -0
- package/server/attachments.py +101 -0
- package/server/cloud-emulation-requirements.txt +29 -0
- package/server/codex_app_server.py +219 -0
- package/server/codex_engineering_backend.py +266 -0
- package/server/codex_worker_policy.py +170 -0
- package/server/contracts.py +315 -0
- package/server/copilot_worker.py +16 -0
- package/server/dependency_mirror.py +54 -0
- package/server/design_patch.py +43 -0
- package/server/emulation-requirements.txt +8 -0
- package/server/emulation_adapters.py +20 -0
- package/server/emulation_routes.py +98 -0
- package/server/emulation_worker.py +351 -0
- package/server/engineering_artifacts.py +215 -0
- package/server/engineering_assets/application-runtime.json +4372 -0
- package/server/engineering_assets/architecture_work.schema.json +79 -0
- package/server/engineering_assets/materialize_runtime.py +62 -0
- package/server/engineering_assets/prepare_tools.py +96 -0
- package/server/engineering_assets/sql_validation.py +59 -0
- package/server/engineering_contexts.py +120 -0
- package/server/engineering_delivery.py +210 -0
- package/server/engineering_finalization.py +210 -0
- package/server/engineering_handoff.py +163 -0
- package/server/engineering_jobs.py +206 -0
- package/server/engineering_knowledge.py +75 -0
- package/server/engineering_reconciliation.py +159 -0
- package/server/engineering_routes.py +469 -0
- package/server/engineering_sessions.py +273 -0
- package/server/engineering_tools.py +166 -0
- package/server/generation_lint.py +18 -0
- package/server/local_providers.py +181 -0
- package/server/local_validation.py +236 -0
- package/server/memory-requirements.lock +181 -0
- package/server/memory-requirements.txt +6 -0
- package/server/memory_routes.py +82 -0
- package/server/memory_service.py +273 -0
- package/server/memory_worker.py +66 -0
- package/server/openai_voice.py +80 -0
- package/server/packaged_app.py +9 -0
- package/server/pricing.py +84 -0
- package/server/process_control_observation.py +31 -0
- package/server/prompts.py +123 -0
- package/server/public_faq_emulation_worker.py +44 -0
- package/server/requirements.lock +1618 -0
- package/server/requirements.txt +68 -0
- package/server/runtime_dependency_locks.py +27 -0
- package/server/runtime_evidence.py +93 -0
- package/server/settings.py +14 -0
- package/server/skills.py +103 -0
- package/server/storage_emulation_worker.py +160 -0
- package/server/structured_emulation_worker.py +48 -0
- package/server/terraform_routes.py +118 -0
- package/server/upstream/__init__.py +0 -0
- package/server/upstream/agent/__init__.py +1 -0
- package/server/upstream/agent/aws_architect.py +600 -0
- package/server/upstream/agent/config/__init__.py +1 -0
- package/server/upstream/agent/config/agent_config.py +82 -0
- package/server/upstream/agent/config/prompts.py +138 -0
- package/server/upstream/agent/rate_limiter.py +62 -0
- package/server/upstream/utils/__init__.py +1 -0
- package/server/upstream/utils/file_writer.py +43 -0
- package/server/validation_applicability.py +85 -0
- package/server/validation_jobs.py +252 -0
- package/server/validation_workers.py +48 -0
- package/server/voice_routes.py +91 -0
- package/server/voice_worker.py +26 -0
- package/specs/028-convergence-evaluation/evidence/20261110-ibm-invoice-native/registry-structured/qualification.json +72 -0
- package/specs/028-convergence-evaluation/evidence/20261110-invoice-runtime/durable-current/receipt.json +61 -0
- package/specs/029-general-purpose-engine/evidence/20261111-runtime-dependencies/sdk/receipt.json +22 -0
- package/src/ArchitectureActivity.jsx +54 -0
- package/src/ArchitectureWorkPanel.jsx +46 -0
- package/src/ArtifactChecks.jsx +49 -0
- package/src/BlockRequirements.jsx +13 -0
- package/src/BrainActivity.jsx +11 -0
- package/src/ChatMessage.jsx +19 -0
- package/src/ChatResizeHandle.jsx +6 -0
- package/src/CodePreview.jsx +8 -0
- package/src/ComponentReview.jsx +31 -0
- package/src/DeliveryViews.jsx +59 -0
- package/src/EmulationPanel.jsx +44 -0
- package/src/EngagementViews.jsx +385 -0
- package/src/EngineeringPanel.jsx +151 -0
- package/src/ImplementationDelivery.jsx +55 -0
- package/src/JourneyViews.jsx +400 -0
- package/src/MemoryPanel.jsx +46 -0
- package/src/OpenAIVoicePanel.jsx +65 -0
- package/src/OutputsView.jsx +65 -0
- package/src/TerraformView.jsx +57 -0
- package/src/WorkbenchDialogs.jsx +532 -0
- package/src/activity-presentation.mjs +28 -0
- package/src/ai-qualification-scenarios.mjs +31 -0
- package/src/approval-application-files.mjs +32 -0
- package/src/approval-applications.mjs +82 -0
- package/src/approval-spec-kit.mjs +30 -0
- package/src/architecture-activity.css +28 -0
- package/src/architecture-activity.mjs +63 -0
- package/src/architecture-work.mjs +176 -0
- package/src/artifact-work.mjs +103 -0
- package/src/async-documents.mjs +191 -0
- package/src/atflow.css +1140 -0
- package/src/atforma.css +748 -0
- package/src/atmem-tokens.css +79 -0
- package/src/aws-preflight.mjs +60 -0
- package/src/aws-public-faq.mjs +102 -0
- package/src/aws-validation-scenarios.mjs +10 -0
- package/src/aws-validation.mjs +48 -0
- package/src/azure-plan-mocks.mjs +25 -0
- package/src/azure-structured.mjs +133 -0
- package/src/bedrock-summary.mjs +152 -0
- package/src/bounded-rag.mjs +60 -0
- package/src/brand.css +9 -0
- package/src/canvas-view.mjs +28 -0
- package/src/capability-composition.mjs +44 -0
- package/src/chat-attachments.mjs +13 -0
- package/src/cloud-provider-locks.mjs +9 -0
- package/src/cloud-storage-scenarios.mjs +2 -0
- package/src/component-review.mjs +55 -0
- package/src/composition-spec-kit.mjs +30 -0
- package/src/consultation-context.mjs +15 -0
- package/src/consultation.mjs +52 -0
- package/src/container-contracts.mjs +5 -0
- package/src/container-inspection.mjs +75 -0
- package/src/container-runtime.mjs +30 -0
- package/src/container-security-inspection.mjs +49 -0
- package/src/container-terraform.mjs +109 -0
- package/src/conversation.mjs +17 -0
- package/src/core.mjs +863 -0
- package/src/cross-cloud-storage.mjs +100 -0
- package/src/delivery-capabilities.mjs +25 -0
- package/src/delivery.mjs +58 -0
- package/src/deployment-ownership.mjs +10 -0
- package/src/deployment-region.mjs +11 -0
- package/src/derive.mjs +31 -0
- package/src/design-build-flow.mjs +10 -0
- package/src/diagram-attention.mjs +24 -0
- package/src/discovery.mjs +359 -0
- package/src/document.mjs +170 -0
- package/src/emulation-feedback.mjs +61 -0
- package/src/emulation-guidance.mjs +37 -0
- package/src/engagement.mjs +274 -0
- package/src/engineering-client.mjs +73 -0
- package/src/engineering-defaults.mjs +17 -0
- package/src/engineering.css +31 -0
- package/src/enterprise-application.mjs +76 -0
- package/src/enterprise-aws-host-infrastructure.mjs +62 -0
- package/src/enterprise-aws-host-tests.mjs +15 -0
- package/src/enterprise-aws-infrastructure-tests.mjs +38 -0
- package/src/enterprise-aws-infrastructure.mjs +138 -0
- package/src/enterprise-google-infrastructure.mjs +84 -0
- package/src/enterprise-google-tests.mjs +25 -0
- package/src/estimate.mjs +188 -0
- package/src/existing-references.mjs +18 -0
- package/src/external-identities.mjs +17 -0
- package/src/faq-lambda-build.mjs +28 -0
- package/src/gcp-structured.mjs +104 -0
- package/src/generation-provider.mjs +7 -0
- package/src/generation-quality.mjs +69 -0
- package/src/handoff.mjs +141 -0
- package/src/ibm-registry.mjs +12 -0
- package/src/ibm-structured.mjs +103 -0
- package/src/identifiers.mjs +15 -0
- package/src/implementation-map.mjs +14 -0
- package/src/implementation-outcome.mjs +8 -0
- package/src/incomplete-terraform.mjs +9 -0
- package/src/integrations.ts +137 -0
- package/src/interface-contracts.mjs +30 -0
- package/src/invoice-application.mjs +66 -0
- package/src/invoice-aws-operations.mjs +136 -0
- package/src/invoice-aws.mjs +143 -0
- package/src/invoice-azure-operations.mjs +147 -0
- package/src/invoice-azure.mjs +134 -0
- package/src/invoice-builder.mjs +35 -0
- package/src/invoice-dependencies.mjs +43 -0
- package/src/invoice-gcp-operations.mjs +178 -0
- package/src/invoice-gcp.mjs +104 -0
- package/src/invoice-ibm-operations.mjs +278 -0
- package/src/invoice-ibm.mjs +142 -0
- package/src/invoice-operations.mjs +143 -0
- package/src/invoice-plan.mjs +45 -0
- package/src/invoice-region.mjs +6 -0
- package/src/invoice-spec-kit.mjs +61 -0
- package/src/invoice-state.mjs +7 -0
- package/src/invoice-terraform.mjs +29 -0
- package/src/invoice-tests.mjs +122 -0
- package/src/journey-workspace.css +72 -0
- package/src/journey.mjs +87 -0
- package/src/levels.mjs +145 -0
- package/src/local-agent.mjs +184 -0
- package/src/main.jsx +2458 -0
- package/src/model-policy-preflight.mjs +34 -0
- package/src/openai-voice.mjs +102 -0
- package/src/output-bundle.mjs +11 -0
- package/src/ownership-inspection.mjs +28 -0
- package/src/pack.mjs +201 -0
- package/src/pricing.mjs +31 -0
- package/src/production-state.mjs +8 -0
- package/src/project-copy.mjs +10 -0
- package/src/project-file.mjs +160 -0
- package/src/project-links.mjs +3 -0
- package/src/protected-state.mjs +43 -0
- package/src/public-faq-builder.mjs +19 -0
- package/src/public-faq-clouds.mjs +251 -0
- package/src/public-faq.mjs +122 -0
- package/src/pulumi.mjs +123 -0
- package/src/python-container.mjs +25 -0
- package/src/python-runtime.mjs +50 -0
- package/src/rag-handler.mjs +43 -0
- package/src/rag-web-assets.mjs +52 -0
- package/src/rag-web.mjs +68 -0
- package/src/records.mjs +177 -0
- package/src/resources.mjs +163 -0
- package/src/review.mjs +252 -0
- package/src/runtime/EnterpriseDocument.java +89 -0
- package/src/runtime/approved_http_destination.py +72 -0
- package/src/runtime/aws-lambda-qualification-lock.json +7 -0
- package/src/runtime/aws-python-lock.json +82 -0
- package/src/runtime/aws-web-python-lock.json +887 -0
- package/src/runtime/aws_json_model.py +42 -0
- package/src/runtime/azure-python-lock.json +863 -0
- package/src/runtime/azure-sources.json +8 -0
- package/src/runtime/azure-test-lock.json +23 -0
- package/src/runtime/azure_acceptance.py +192 -0
- package/src/runtime/azure_structured.py +153 -0
- package/src/runtime/bounded_rag.py +126 -0
- package/src/runtime/catalog_admin.py +70 -0
- package/src/runtime/cloud-sql-proxy-lock.json +8 -0
- package/src/runtime/cloud-sql-proxy-security-review.json +30 -0
- package/src/runtime/connector_cli.py +50 -0
- package/src/runtime/connector_sync.py +70 -0
- package/src/runtime/durable-python-lock.json +247 -0
- package/src/runtime/durable_workflow.py +325 -0
- package/src/runtime/enterprise-application-manifest.json +110 -0
- package/src/runtime/enterprise-application-sources.json +266 -0
- package/src/runtime/enterprise-auth-python-lock.json +592 -0
- package/src/runtime/enterprise-aws-host-bootstrap-source.json +1 -0
- package/src/runtime/enterprise-aws-host-probe-source.json +1 -0
- package/src/runtime/enterprise-aws-task-template.json +235 -0
- package/src/runtime/enterprise-document-lock.json +18 -0
- package/src/runtime/enterprise-document.Dockerfile +15 -0
- package/src/runtime/enterprise-runtime-aws-python-lock.json +1115 -0
- package/src/runtime/enterprise-runtime-azure-python-lock.json +1106 -0
- package/src/runtime/enterprise-runtime-gcp-python-lock.json +1060 -0
- package/src/runtime/enterprise-runtime-ibm-python-lock.json +1096 -0
- package/src/runtime/enterprise-runtime-python-lock.json +1058 -0
- package/src/runtime/enterprise-runtime.Dockerfile +15 -0
- package/src/runtime/enterprise-web-app.js +1 -0
- package/src/runtime/enterprise-web-entry.js +105 -0
- package/src/runtime/enterprise-web-lock.json +29 -0
- package/src/runtime/enterprise-web-notices.txt +229 -0
- package/src/runtime/enterprise-web.css +4 -0
- package/src/runtime/enterprise-web.html +8 -0
- package/src/runtime/enterprise_audit.py +91 -0
- package/src/runtime/enterprise_audit_schema.sql +25 -0
- package/src/runtime/enterprise_auth_schema.sql +67 -0
- package/src/runtime/enterprise_auth_store.py +241 -0
- package/src/runtime/enterprise_aws_host_bootstrap.py +120 -0
- package/src/runtime/enterprise_aws_host_probe.py +105 -0
- package/src/runtime/enterprise_aws_hosts.py +136 -0
- package/src/runtime/enterprise_aws_jobs.py +300 -0
- package/src/runtime/enterprise_aws_objects.py +93 -0
- package/src/runtime/enterprise_aws_transfer.py +83 -0
- package/src/runtime/enterprise_azure_batch_api.py +128 -0
- package/src/runtime/enterprise_azure_host.py +599 -0
- package/src/runtime/enterprise_azure_jobs.py +294 -0
- package/src/runtime/enterprise_azure_objects.py +234 -0
- package/src/runtime/enterprise_azure_pool.py +161 -0
- package/src/runtime/enterprise_azure_transfer.py +122 -0
- package/src/runtime/enterprise_configuration.py +136 -0
- package/src/runtime/enterprise_document.py +116 -0
- package/src/runtime/enterprise_document_cli.py +32 -0
- package/src/runtime/enterprise_document_contract.py +54 -0
- package/src/runtime/enterprise_document_job.py +109 -0
- package/src/runtime/enterprise_document_jobs.py +122 -0
- package/src/runtime/enterprise_document_jobs_schema.sql +23 -0
- package/src/runtime/enterprise_extraction_cache.py +186 -0
- package/src/runtime/enterprise_extraction_schema.sql +17 -0
- package/src/runtime/enterprise_google_jobs.py +275 -0
- package/src/runtime/enterprise_google_transfer.py +85 -0
- package/src/runtime/enterprise_http.py +212 -0
- package/src/runtime/enterprise_identity.py +52 -0
- package/src/runtime/enterprise_knowledge.py +152 -0
- package/src/runtime/enterprise_models.py +94 -0
- package/src/runtime/enterprise_native.py +181 -0
- package/src/runtime/enterprise_oauth.py +132 -0
- package/src/runtime/enterprise_operator.py +160 -0
- package/src/runtime/enterprise_parser_service.py +136 -0
- package/src/runtime/enterprise_parser_transport.py +68 -0
- package/src/runtime/enterprise_queries.py +255 -0
- package/src/runtime/enterprise_queries_schema.sql +27 -0
- package/src/runtime/enterprise_query_service.py +111 -0
- package/src/runtime/enterprise_secrets.py +110 -0
- package/src/runtime/enterprise_sessions.py +95 -0
- package/src/runtime/enterprise_sources.py +260 -0
- package/src/runtime/enterprise_web.py +39 -0
- package/src/runtime/enterprise_worker.py +68 -0
- package/src/runtime/export_contract_acceptance.py +18 -0
- package/src/runtime/faq-output-contract.json +40 -0
- package/src/runtime/faq-web-app.js +41 -0
- package/src/runtime/faq-web.css +1 -0
- package/src/runtime/faq-web.html +6 -0
- package/src/runtime/gcp-sources.json +9 -0
- package/src/runtime/gcp_acceptance.py +110 -0
- package/src/runtime/gcp_structured.py +150 -0
- package/src/runtime/http_acceptance.py +39 -0
- package/src/runtime/iap-web-app.js +36 -0
- package/src/runtime/iap-web-source.json +1 -0
- package/src/runtime/ibm-python-lock.json +856 -0
- package/src/runtime/ibm-sources.json +9 -0
- package/src/runtime/ibm_acceptance.py +133 -0
- package/src/runtime/ibm_structured.py +113 -0
- package/src/runtime/invoice-azapi-provider-lock.json +7 -0
- package/src/runtime/invoice-ibm-provider-lock.json +7 -0
- package/src/runtime/invoice-parser-lock.json +1199 -0
- package/src/runtime/invoice-parser-python-lock.json +56 -0
- package/src/runtime/invoice-parser.Dockerfile +190 -0
- package/src/runtime/invoice-sources.json +58 -0
- package/src/runtime/invoice-test-sources.json +24 -0
- package/src/runtime/invoice-web.css +2 -0
- package/src/runtime/invoice-web.html +12 -0
- package/src/runtime/invoice-web.js +112 -0
- package/src/runtime/invoice_configuration.py +17 -0
- package/src/runtime/invoice_document.py +95 -0
- package/src/runtime/invoice_extraction.py +96 -0
- package/src/runtime/invoice_http.py +129 -0
- package/src/runtime/invoice_identity.py +5 -0
- package/src/runtime/invoice_maintenance.py +40 -0
- package/src/runtime/invoice_native.py +77 -0
- package/src/runtime/invoice_object_store.py +153 -0
- package/src/runtime/invoice_operations.py +108 -0
- package/src/runtime/invoice_operator.py +79 -0
- package/src/runtime/invoice_operator_core.py +39 -0
- package/src/runtime/invoice_operator_job.py +147 -0
- package/src/runtime/invoice_parser_cli.py +17 -0
- package/src/runtime/invoice_parser_identity.py +39 -0
- package/src/runtime/invoice_parser_service.py +89 -0
- package/src/runtime/invoice_parser_transport.py +89 -0
- package/src/runtime/invoice_processing.py +24 -0
- package/src/runtime/invoice_retention.py +16 -0
- package/src/runtime/invoice_runtime_secrets.py +43 -0
- package/src/runtime/invoice_stage.py +80 -0
- package/src/runtime/invoice_web.py +39 -0
- package/src/runtime/invoice_worker.py +50 -0
- package/src/runtime/lambda_faq.py +5 -0
- package/src/runtime/parser-requirements.lock +4 -0
- package/src/runtime/policy_review.py +18 -0
- package/src/runtime/postgres-qualification-lock.json +21 -0
- package/src/runtime/public-faq-sources.json +22 -0
- package/src/runtime/public_catalog_admin.py +122 -0
- package/src/runtime/public_catalog_store.py +125 -0
- package/src/runtime/public_faq.py +144 -0
- package/src/runtime/public_faq_app.py +49 -0
- package/src/runtime/python-container-lock.json +18 -0
- package/src/runtime/rag-sources.json +10 -0
- package/src/runtime/rag_acceptance.py +60 -0
- package/src/runtime/rag_aws_adapter.py +95 -0
- package/src/runtime/rds-ca-source.json +9 -0
- package/src/runtime/rds-global-ca.pem +2888 -0
- package/src/runtime/state-contract-check-source.json +4 -0
- package/src/runtime/state_contract_check.py +338 -0
- package/src/runtime/structured-source.json +1 -0
- package/src/runtime/structured-web-app.js +71 -0
- package/src/runtime/structured-web-source.json +1 -0
- package/src/runtime/structured_http.py +105 -0
- package/src/runtime/structured_output.py +48 -0
- package/src/runtime/web-python-lock.json +802 -0
- package/src/runtime/web_user_admin.py +44 -0
- package/src/runtime/workflow_application.py +62 -0
- package/src/runtime/workflow_bindings.py +128 -0
- package/src/runtime/workflow_configuration.py +40 -0
- package/src/runtime/workflow_connection.py +105 -0
- package/src/runtime/workflow_contract.py +54 -0
- package/src/runtime/workflow_database.py +94 -0
- package/src/runtime/workflow_errors.py +6 -0
- package/src/runtime/workflow_http.py +178 -0
- package/src/runtime/workflow_identity.py +69 -0
- package/src/runtime/workflow_payload.py +118 -0
- package/src/runtime/workflow_process_stage.py +88 -0
- package/src/runtime/workflow_profile.py +91 -0
- package/src/runtime/workflow_review.py +106 -0
- package/src/runtime/workflow_role_bootstrap.py +104 -0
- package/src/runtime/workflow_schema.sql +72 -0
- package/src/runtime/workflow_worker.py +142 -0
- package/src/runtime-settings.mjs +15 -0
- package/src/s3-access.mjs +14 -0
- package/src/source-contracts.mjs +17 -0
- package/src/spec-kit.mjs +186 -0
- package/src/state-custody.mjs +32 -0
- package/src/state-inspection.mjs +45 -0
- package/src/state-spec-kit.mjs +13 -0
- package/src/storage-tests.mjs +25 -0
- package/src/structured-api.mjs +133 -0
- package/src/structured-contract.mjs +19 -0
- package/src/structured-operation-policy.mjs +2 -0
- package/src/structured-web.mjs +17 -0
- package/src/style.css +1 -0
- package/src/system-description.mjs +26 -0
- package/src/terraform-admission.mjs +66 -0
- package/src/terraform-composition.mjs +83 -0
- package/src/terraform-expressions.mjs +46 -0
- package/src/terraform-validation-coverage.mjs +11 -0
- package/src/terraform.mjs +128 -0
- package/src/text-statistics.mjs +51 -0
- package/src/upstream/openarchflow/format-payload.ts +26 -0
- package/src/upstream/openarchflow/import/mermaid.ts +205 -0
- package/src/upstream/openarchflow/import/sql-ddl.ts +109 -0
- package/src/upstream/openarchflow/layout.ts +54 -0
- package/src/upstream/openarchflow/providers/aws.ts +196 -0
- package/src/upstream/openarchflow/providers/azure.ts +126 -0
- package/src/upstream/openarchflow/providers/cloudnative.ts +71 -0
- package/src/upstream/openarchflow/providers/generic.ts +227 -0
- package/src/upstream/openarchflow/providers/integration.ts +22 -0
- package/src/upstream/openarchflow/providers/types.ts +2 -0
- package/src/upstream/openarchflow/templates.ts +937 -0
- package/src/upstream-catalog.mjs +10 -0
- package/src/useChatScroll.jsx +36 -0
- package/src/useEmulation.jsx +36 -0
- package/src/validation-receipt.mjs +10 -0
- package/src/visual-export.mjs +92 -0
- package/src/voice-conversation.mjs +117 -0
- package/src/work-intake.mjs +24 -0
- package/src/workflow-runtime-inventory.mjs +3 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export function faqLambdaBuild(addresses){
|
|
2
|
+
if(!addresses.length||addresses.some(n=>!/^block_[0-9a-f]+$/.test(n)))throw Error('Invalid owned Lambda application addresses');
|
|
3
|
+
return {'build-runtime.py':`"""Build deterministic Python 3.13 / Linux x86_64 public FAQ ZIPs."""
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
import hashlib,json,shutil,subprocess,sys,zipfile
|
|
6
|
+
root=Path(__file__).resolve().parent
|
|
7
|
+
receipts=[]
|
|
8
|
+
for address in ${JSON.stringify(addresses)}:
|
|
9
|
+
source=root/'applications'/address;folder=root/'build'/address
|
|
10
|
+
if folder.exists():shutil.rmtree(folder)
|
|
11
|
+
folder.mkdir(parents=True)
|
|
12
|
+
subprocess.run([sys.executable,'-I','-m','pip','--isolated','install','--disable-pip-version-check','--no-compile','--only-binary=:all:','--require-hashes','--python-version','3.13','--implementation','cp','--abi','cp313','--abi','abi3','--platform','manylinux_2_34_x86_64','--platform','manylinux_2_28_x86_64','--platform','manylinux2014_x86_64','--index-url','https://pypi.org/simple','--target',str(folder),'-r',str(source/'requirements.lock')],check=True)
|
|
13
|
+
modules=['public_faq.py','public_catalog_store.py','public_faq_app.py','structured_http.py','structured_output.py','aws_json_model.py','lambda_faq.py']
|
|
14
|
+
for name in modules+['output-contract.json','faq-deployment.json']:
|
|
15
|
+
shutil.copyfile(source/name,folder/name)
|
|
16
|
+
shutil.copytree(source/'web',folder/'web')
|
|
17
|
+
archive=root/'build'/(address+'.zip')
|
|
18
|
+
with zipfile.ZipFile(archive,'w',compression=zipfile.ZIP_DEFLATED,compresslevel=9)as output:
|
|
19
|
+
for file in sorted(folder.rglob('*')):
|
|
20
|
+
if not file.is_file() or '__pycache__' in file.parts or 'bin' in file.relative_to(folder).parts:continue
|
|
21
|
+
item=zipfile.ZipInfo(file.relative_to(folder).as_posix(),date_time=(1980,1,1,0,0,0));item.create_system=3;item.external_attr=0o100644<<16;item.compress_type=zipfile.ZIP_DEFLATED
|
|
22
|
+
output.writestr(item,file.read_bytes(),compress_type=zipfile.ZIP_DEFLATED,compresslevel=9)
|
|
23
|
+
if archive.stat().st_size>50*1024*1024:raise ValueError('ZIP exceeds direct Lambda upload boundary; implement an artifact-store publication contract rather than silently changing deployment')
|
|
24
|
+
receipts.append({'component':address,'sha256':hashlib.sha256(archive.read_bytes()).hexdigest(),'target':'python3.13-linux-x86_64','sourceFiles':{str(p.relative_to(source)):hashlib.sha256(p.read_bytes()).hexdigest()for p in source.rglob('*')if p.is_file()}})
|
|
25
|
+
(root/'build'/'artifact-hashes.json').write_text(json.dumps(receipts,indent=2)+'\\n')
|
|
26
|
+
print(json.dumps({'status':'built','artifacts':receipts}))
|
|
27
|
+
`};
|
|
28
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import {pythonContainer} from './python-container.mjs';
|
|
2
|
+
import sources from './runtime/gcp-sources.json' with {type:'json'};
|
|
3
|
+
import lock from './runtime/web-python-lock.json' with {type:'json'};
|
|
4
|
+
import testLock from './runtime/azure-test-lock.json' with {type:'json'};
|
|
5
|
+
import base from './runtime/python-container-lock.json' with {type:'json'};
|
|
6
|
+
import webSource from './runtime/iap-web-source.json' with {type:'json'};
|
|
7
|
+
import {STRUCTURED_WEB_HTML,STRUCTURED_WEB_CSS} from './structured-web.mjs';
|
|
8
|
+
import {structuredContract} from './structured-contract.mjs';
|
|
9
|
+
import {existingDeployment} from './deployment-ownership.mjs';
|
|
10
|
+
import {existingReferenceFiles} from './existing-references.mjs';
|
|
11
|
+
import {CLOUD_PROVIDER_LOCKS} from './cloud-provider-locks.mjs';
|
|
12
|
+
|
|
13
|
+
export function gcpStructuredPlan(project,rows){
|
|
14
|
+
const entries=[];
|
|
15
|
+
for(const node of project.nodes){
|
|
16
|
+
if(node.data.provider!=='gcp'||node.data.implementation!=='gcp-structured-app'||node.data.service!=='Google Cloud Run'||existingDeployment(node))continue;
|
|
17
|
+
const contract=structuredContract(node.data.config?.outputContract);if(!contract)continue;
|
|
18
|
+
const maxInput=node.data.config?.maxInputBytes??20000,maxTokens=node.data.config?.maxOutputTokens??1024;
|
|
19
|
+
if(!Number.isInteger(maxInput)||maxInput<1||maxInput>20000||!Number.isInteger(maxTokens)||maxTokens<32||maxTokens>4096)throw Error('Google structured application limits must be 1–20000 input bytes and 32–4096 output tokens.');
|
|
20
|
+
entries.push({row:rows.find(r=>r.id===node.id),contract,maxInput,maxTokens});
|
|
21
|
+
}
|
|
22
|
+
const ids=new Set(entries.map(e=>e.row.id)),browsers=new Set(project.nodes.filter(n=>existingDeployment(n)&&n.data.provider==='tools'&&n.data.binding==='web-browser').map(n=>n.id));
|
|
23
|
+
return {entries,componentIds:[...ids],edgeIds:project.edges.filter(e=>e.integration==='browser-https'&&browsers.has(e.source)&&ids.has(e.target)).map(e=>e.id)};
|
|
24
|
+
}
|
|
25
|
+
const v=n=>'${var.'+n+'}',ref=(type,n,key)=>'${'+type+'.'+n+'.'+key+'}';
|
|
26
|
+
export function gcpStructuredTerraform(project,plan,environment='staging'){
|
|
27
|
+
const entries=plan.gcpStructuredPlan.entries;if(!entries.length)throw Error('No Google structured application composition.');
|
|
28
|
+
const variable={review_approved:{type:'bool',default:false}},examples={review_approved:false},resource={},output={},files={},tests=[];
|
|
29
|
+
const input=(name,description,example,pattern)=>{variable[name]={type:'string',nullable:false,description,validation:{condition:'${can(regex('+JSON.stringify(pattern)+', var.'+name+'))}',error_message:'Supply the reviewed '+name+' value.'}};examples[name]=example;return v(name);};
|
|
30
|
+
const destination=input('project_id','Existing reviewed organization-owned Google Cloud project with billing. No project is recreated.','reviewed-project','^[a-z][a-z0-9-]{4,28}[a-z0-9]$');
|
|
31
|
+
const registryLocation=input('registry_location','Location of the existing Artifact Registry Docker repository.','australia-southeast1','^[a-z]+(?:-[a-z]+[0-9])?$');
|
|
32
|
+
const registry=input('registry_repository','Existing Docker repository in the selected project; no registry is recreated.','reviewed-images','^[a-z][a-z0-9-]{1,61}[a-z0-9]$');
|
|
33
|
+
const gaps=[...plan.gapDetails.map(g=>g.id),...(environment==='production'?['production-state-backup-and-operating-review-required']:[])];
|
|
34
|
+
resource.terraform_data={review_gate:{input:{design_revision:project.revision,environment},lifecycle:{precondition:[{condition:'${var.review_approved && length(local.unfinished_work) == 0}',error_message:'Review the destination, code, access, policy, costs and unresolved scope before planning deployment.'}]}}};
|
|
35
|
+
const add=(type,name,body)=>((resource[type]||={})[name]={...body,depends_on:['terraform_data.review_gate',...(body.depends_on||[])]});
|
|
36
|
+
for(const [name,service]of Object.entries({run:'run.googleapis.com',iap:'iap.googleapis.com',model:'aiplatform.googleapis.com',registry:'artifactregistry.googleapis.com'}))add('google_project_service','required_'+name,{project:destination,service,disable_on_destroy:false});
|
|
37
|
+
for(const name of ['run','iap'])add('google_project_service_identity','required_'+name,{provider:'google-beta',project:destination,service:name+'.googleapis.com',depends_on:['google_project_service.required_'+name]});
|
|
38
|
+
add('google_artifact_registry_repository_iam_member','image_pull',{project:destination,location:registryLocation,repository:registry,role:'roles/artifactregistry.reader',member:ref('google_project_service_identity','required_run','member'),depends_on:['google_project_service.required_registry']});
|
|
39
|
+
const number='${data.google_project.destination.number}';
|
|
40
|
+
for(const {row,contract,maxInput,maxTokens}of entries){
|
|
41
|
+
const n=row.address;
|
|
42
|
+
const name=input(n+'_name','Cloud Run service and dedicated runtime service-account name, kept short for the deterministic URL.','reviewed-ai-app','^[a-z][a-z0-9-]{4,28}[a-z0-9]$');
|
|
43
|
+
const region=input(n+'_region','Explicit regional application/model location. No global model fallback. Verify selected model support and quota.','australia-southeast1','^[a-z]+-[a-z]+[0-9]$');
|
|
44
|
+
if(/^[a-z]+-[a-z]+[0-9]$/.test(row.region)){variable[n+'_region'].default=row.region;examples[n+'_region']=row.region;}
|
|
45
|
+
const imageRepository=input(n+'_image_repository','Repository path for building/publishing this emitted application source.','architect/app','^[a-z0-9]+(?:[._/-][a-z0-9]+)*$');
|
|
46
|
+
const digest=input(n+'_image_digest','Digest from the built, scanned and tested emitted source, pushed with authorization to the existing registry.','sha256:'+'0'.repeat(64),'^sha256:[0-9a-f]{64}$');
|
|
47
|
+
const model=input(n+'_model_id','Reviewed compatible regional Gemini model/version; check lifecycle and quotas. No model availability or price is invented.','gemini-reviewed-version','^gemini-[a-z0-9.-]{1,80}$');
|
|
48
|
+
const group=input(n+'_access_group','Existing authorized company Google group email. IAP manages membership authorization; no group/users are created.','architect-staff@example.test','^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$');
|
|
49
|
+
const reviewName=n+'_policy_review';
|
|
50
|
+
variable[reviewName]={type:'object({ projectId = string, region = string, model = string, abuseLogging = string, approvedBy = string, evidenceSha256 = string, expiresAt = string })',nullable:false,description:'Destination owner review of actual abuse-monitoring terms/exemption, with retained evidence digest and expiry within 31 days. This is operator-attested evidence, not a fabricated provider approval API. The runtime separately reads caching/logging controls before inference.'};
|
|
51
|
+
examples[reviewName]={projectId:'reviewed-project',region:examples[n+'_region'],model:'gemini-reviewed-version',abuseLogging:'REVIEW_REQUIRED',approvedBy:'REVIEW_REQUIRED',evidenceSha256:'0'.repeat(64),expiresAt:'REPLACE_AFTER_REVIEW'};
|
|
52
|
+
const origin='https://'+name+'-'+number+'.'+region+'.run.app';
|
|
53
|
+
add('google_service_account',n,{project:destination,account_id:name,display_name:'Structured AI application runtime'});
|
|
54
|
+
add('google_project_iam_custom_role',n,{project:destination,role_id:'${replace(var.'+n+'_name, "-", "_")}_runtime',title:'Structured application model and policy reader',permissions:['aiplatform.endpoints.predict','aiplatform.cacheConfigs.get','aiplatform.endpoints.fetchPublisherModelConfig'],stage:'GA'});
|
|
55
|
+
add('google_project_iam_member',n,{project:destination,role:ref('google_project_iam_custom_role',n,'name'),member:'serviceAccount:'+ref('google_service_account',n,'email'),depends_on:['google_project_service.required_model']});
|
|
56
|
+
const settings={PROJECT_ID:destination,PROJECT_NUMBER:number,REGION:region,SERVICE_NAME:name,MODEL_ID:model,PUBLIC_ORIGIN:origin,MAX_INPUT_BYTES:String(maxInput),MAX_OUTPUT_TOKENS:String(maxTokens),OUTPUT_CONTRACT_BASE64:btoa(unescape(encodeURIComponent(JSON.stringify(contract)))),POLICY_REVIEW_BASE64:'${base64encode(jsonencode(var.'+reviewName+'))}'};
|
|
57
|
+
const image=registryLocation+'-docker.pkg.dev/'+destination+'/'+registry+'/'+imageRepository+'@'+digest;
|
|
58
|
+
add('google_cloud_run_v2_service',n,{project:destination,name,location:region,deletion_protection:true,ingress:'INGRESS_TRAFFIC_ALL',iap_enabled:true,invoker_iam_disabled:false,labels:{managed_by:'atmem-ai-architect',environment},template:{service_account:ref('google_service_account',n,'email'),timeout:'30s',max_instance_request_concurrency:5,scaling:{min_instance_count:0,max_instance_count:2},containers:{name:'application',image,ports:{container_port:8080},resources:{limits:{cpu:'1',memory:'512Mi'},cpu_idle:true,startup_cpu_boost:true},env:Object.entries(settings).map(([name,value])=>({name,value})),startup_probe:{http_get:{path:'/healthz',port:8080},initial_delay_seconds:0,period_seconds:5,timeout_seconds:2,failure_threshold:12}}},depends_on:['google_project_service.required_run','google_project_service_identity.required_iap','google_project_service_identity.required_run','google_artifact_registry_repository_iam_member.image_pull','google_project_iam_member.'+n]});
|
|
59
|
+
add('google_cloud_run_v2_service_iam_member',n,{project:destination,location:region,name:ref('google_cloud_run_v2_service',n,'name'),role:'roles/run.invoker',member:ref('google_project_service_identity','required_iap','member')});
|
|
60
|
+
add('google_iap_web_cloud_run_service_iam_member',n,{project:destination,location:region,cloud_run_service_name:ref('google_cloud_run_v2_service',n,'name'),role:'roles/iap.httpsResourceAccessor',member:'group:'+group});
|
|
61
|
+
output[n+'_url']={value:origin};
|
|
62
|
+
const folder='applications/'+n+'/';
|
|
63
|
+
for(const [path,body]of Object.entries(sources))files[folder+path]=body;
|
|
64
|
+
files[folder+'web/index.html']=STRUCTURED_WEB_HTML.replace('<button id="sign-in">Sign in</button><button id="sign-out" hidden>Sign out</button>','<button id="clear" type="button">Clear input and result</button>');
|
|
65
|
+
files[folder+'web/app.css']=STRUCTURED_WEB_CSS;files[folder+'web/app.js']=webSource;
|
|
66
|
+
files[folder+'output-contract.json']=JSON.stringify(contract,null,2);
|
|
67
|
+
files[folder+'requirements.lock']=lock.requirements;files[folder+'dependency-sources.json']=JSON.stringify(lock.sources,null,2);
|
|
68
|
+
files[folder+'test-requirements.lock']=testLock.requirements;files[folder+'test-dependency-sources.json']=JSON.stringify(testLock.sources,null,2);
|
|
69
|
+
files[folder+'container-base.json']=JSON.stringify(base,null,2);
|
|
70
|
+
files[folder+'Dockerfile']=pythonContainer('gcp_structured',['gcp_structured.py','structured_output.py','structured_http.py','policy_review.py']);
|
|
71
|
+
files[folder+'.dockerignore']='*\n!requirements.lock\n!output-contract.json\n!gcp_structured.py\n!structured_output.py\n!structured_http.py\n!policy_review.py\n!web/\n!web/*\n';
|
|
72
|
+
files[folder+'BUILD.md']=`# Generated Cloud Run application\n\nIn this directory, create an isolated Python 3.13 environment, install test-requirements.lock with --only-binary=:all: --require-hashes, then run gcp_acceptance.py -v. Tests use ephemeral signed JWTs and scripted transport fixtures. They do not contact Google Cloud.\n\nBuild this source with docker build --platform linux/amd64 --pull -t REVIEWED_LOCATION-docker.pkg.dev/REVIEWED_PROJECT/REVIEWED_REPOSITORY/REVIEWED_IMAGE:REVIEWED_BUILD . ; scan, run container startup/acceptance checks and retain source/image digests. Obtain authorization before authenticating to the existing Artifact Registry and pushing. Supply that exact registry digest as ${n}_image_digest. Terraform does not run build/publish provisioners.\n\nProvide the reviewed project/model/region and destination-owner policy evidence using ${reviewName}; the supplied example is intentionally unapproved. Runtime verifies its scope/expiry, reads disabled project caching and model logging/sharing settings, and blocks before inference if any check is unknown. The owner review covers abuse-monitoring terms/exemption that this application cannot discover through a reliable API. It is an attestation, not independent proof of approval. The application never modifies those project/account-wide controls.\n`;
|
|
73
|
+
tests.push(`run "${n}_identity" {\n command = plan\n assert {\n condition = google_cloud_run_v2_service.${n}.iap_enabled && !google_cloud_run_v2_service.${n}.invoker_iam_disabled\n error_message = "IAP and Cloud Run IAM must remain enabled."\n }\n assert {\n condition = google_cloud_run_v2_service_iam_member.${n}.member == google_project_service_identity.required_iap.member && google_iap_web_cloud_run_service_iam_member.${n}.member == "group:\${var.${n}_access_group}"\n error_message = "Only the IAP agent invokes the service; only the reviewed group receives IAP access."\n }\n assert {\n condition = length(google_project_iam_custom_role.${n}.permissions) == 3 && !contains(google_project_iam_custom_role.${n}.permissions, "aiplatform.endpoints.setPublisherModelConfig")\n error_message = "Runtime must not modify project/account-wide model policy."\n }\n}\nrun "${n}_reject_mutable_image" {\n command = plan\n variables { ${n}_image_digest = "latest" }\n expect_failures = [var.${n}_image_digest]\n}`);
|
|
74
|
+
}
|
|
75
|
+
const config={terraform:{required_version:'>= 1.17.1, < 2.0.0',required_providers:{google:{source:'hashicorp/google',version:'7.46.2'},'google-beta':{source:'hashicorp/google-beta',version:'7.46.2'}}},provider:{google:{project:destination},'google-beta':{project:destination}},data:{google_project:{destination:{project_id:destination}}},variable,locals:{unfinished_work:gaps},resource,output};
|
|
76
|
+
const values=Object.entries({...examples,review_approved:true}).map(([k,value])=>k+' = '+JSON.stringify(value)).join('\n');
|
|
77
|
+
return {...files,...existingReferenceFiles(project),'.terraform.lock.hcl':CLOUD_PROVIDER_LOCKS.gcp+'\n'+CLOUD_PROVIDER_LOCKS.gcpBeta,'main.tf.json':JSON.stringify(config,null,2),'resource-schedule.json':JSON.stringify(plan,null,2),'deployment.tfvars.json.example':JSON.stringify(examples,null,2),'.gitignore':'.terraform/\n*.tfstate*\n*.tfplan\n*.tfvars\n*.tfvars.json\n!deployment.tfvars.json.example\n.venv/\n__pycache__/\n','tests/gcp-structured.tftest.hcl':`mock_provider "google" {\n override_during = plan\n mock_data "google_project" { defaults = { number = "123456789012" } }\n mock_resource "google_service_account" { defaults = { email = "runtime@reviewed-project.iam.gserviceaccount.com" } }\n}\nmock_provider "google-beta" {\n override_during = plan\n mock_resource "google_project_service_identity" { defaults = { email = "service-123456789012@gcp-sa-iap.iam.gserviceaccount.com", member = "serviceAccount:service-123456789012@gcp-sa-iap.iam.gserviceaccount.com" } }\n}\nvariables {\n${values}\n}\n${tests.join('\n')}\nrun "unapproved_blocked" {\n command = plan\n variables { review_approved = false }\n expect_failures = [terraform_data.review_gate]\n}\n`,'README.md':GCP_STRUCTURED_GUIDE};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export const GCP_STRUCTURED_GUIDE=`# Google Cloud structured AI application
|
|
81
|
+
|
|
82
|
+
An explicit gcp-structured-app block composes a Cloud Run browser/API, dedicated keyless runtime service account, narrow project-level model/policy-read role, IAP service identity and company-group access. The Google beta provider is used only for generating Google-managed IAP/Cloud Run service identities; these identities cannot be destroyed through that resource. Existing projects, groups and Artifact Registry repositories are preserved. Required APIs are enabled but never disabled on destroy. Unrelated services/connections remain gaps.
|
|
83
|
+
|
|
84
|
+
IAP is enabled directly on Cloud Run with IAM checks retained. Only its service agent receives the emitted run.invoker grant. The existing company group receives IAP access; no allUsers/allAuthenticatedUsers grant is emitted. Use an organization-owned project with the Google-managed OAuth client; first-time nonorganization/external-identity OAuth flows require a separately reviewed configuration. Reconcile inherited IAM permissions and organizational policies in the real account.
|
|
85
|
+
|
|
86
|
+
The app verifies every non-health request using the signed ES256 IAP JWT, fixed Google key endpoint, exact service audience, issuer, lifetime and user identity. Unsigned identity headers, a caller Authorization header and service-account identities grant no application access. API requests additionally require the exact same-origin browser Origin. The deterministic run.app URL is used deliberately; the service name stays short enough for its DNS limit. Do not use the alternate hashed URL for this browser without updating the reviewed origin contract. IAP membership/organization session policy is the authorization boundary. This is not a continuous directory check or proof of MFA/revocation behavior; issued IAP headers remain valid until expiry/skew. The browser clears input/result without claiming to sign out of the company session.
|
|
87
|
+
|
|
88
|
+
Workload tokens come only from Cloud Run's fixed metadata endpoint with Metadata-Flavor verification, no inherited proxy/netrc configuration, redirects or static key file. A custom role admits prediction and read-only cache/model-policy queries in the selected project. It is project-scoped, not an invented per-publisher-model IAM restriction. The application selects only the reviewed regional Gemini model. Only the Cloud Run platform agent receives reader access on the exact existing image repository.
|
|
89
|
+
|
|
90
|
+
No application input/result is persisted. Before inference, a scoped, expiring destination-owner review must cover actual abuse-monitoring terms/exemption, with retained evidence digest. This is operator-attested evidence, not a provider approval API. Runtime separately reads disabled project caching and disabled model request/response logging and sharing. Unknown/denied controls stop inference. A documented model-policy 404 NOT_FOUND indicates default disabled configuration; other failures do not. The global project caching read uses Google's documented us-central1 control endpoint, sends no ticket input and never changes settings. Review that metadata location, IAP/global identity processing, actual model geography/availability and provider terms against residency requirements. The app does not claim universal zero retention. No tools, grounding, cachedContent or stateful interactions API is used.
|
|
91
|
+
|
|
92
|
+
Build/scan/test emitted applications/* source and the pinned Linux/amd64 image, then obtain authorization to publish to the existing Artifact Registry. Supply the exact image digest and reviewed destination/model/group/policy inputs. The example policy is intentionally unapproved. Protect Terraform state and private variable files. Terraform never builds, publishes, executes a provisioner or authorizes its own policy changes.
|
|
93
|
+
|
|
94
|
+
Use Terraform 1.17.1 or newer (the locally qualified CLI; tests use plan-time mock values). Run terraform init -backend=false, terraform validate and terraform test. Mock plans inspect configuration, not Google account behavior. Run real IAP sign-in/group/expiry tests, metadata identity exchange, policy/model-quality tests, image startup/scan, authorized account plan and operational review before deployment. Scaling/concurrency and token bounds are not invoice caps or availability/latency SLAs. Production remains blocked pending state, backup and operations review. No export proves deployment.
|
|
95
|
+
|
|
96
|
+
References:
|
|
97
|
+
- https://docs.cloud.google.com/run/docs/securing/identity-aware-proxy-cloud-run
|
|
98
|
+
- https://docs.cloud.google.com/iap/docs/signed-headers-howto
|
|
99
|
+
- https://docs.cloud.google.com/run/docs/securing/service-identity
|
|
100
|
+
- https://docs.cloud.google.com/run/docs/triggering/https-request
|
|
101
|
+
- https://docs.cloud.google.com/gemini-enterprise-agent-platform/resources/zero-data-retention
|
|
102
|
+
- https://docs.cloud.google.com/gemini-enterprise-agent-platform/models/capabilities/request-response-logging
|
|
103
|
+
- https://registry.terraform.io/providers/hashicorp/google/7.46.2/docs/resources/cloud_run_v2_service
|
|
104
|
+
`;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import {existingDeployment} from './deployment-ownership.mjs';
|
|
2
|
+
// Select from explicit deployment ownership, never from a default cloud.
|
|
3
|
+
export function generationProviders(project){
|
|
4
|
+
const deployed=project.nodes.filter(n=>n.data.kind!=='note'&&!existingDeployment(n)&&n.data.provider!=='tools').map(n=>n.data.provider);
|
|
5
|
+
return [...new Set(deployed.length?deployed:project.provider&&project.provider!=='tools'?[project.provider]:[])].sort();
|
|
6
|
+
}
|
|
7
|
+
export function isAwsGeneration(project){const p=generationProviders(project);return p.length===1&&p[0]==='aws';}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import {inspectContainerConfiguration} from './container-inspection.mjs';
|
|
2
|
+
import {inspectStateCustody} from './state-inspection.mjs';
|
|
3
|
+
import {inspectOwnership,ownershipInventory} from './ownership-inspection.mjs';
|
|
4
|
+
import {inspectTerraformModules} from './terraform-admission.mjs';
|
|
5
|
+
import {existingDeployment} from './deployment-ownership.mjs';
|
|
6
|
+
import catalogue from '../agent-skills/generation-capabilities.json' with {type:'json'};
|
|
7
|
+
import skillDigests from '../agent-skills/specialists/manifest.json' with {type:'json'};
|
|
8
|
+
import lifecycle from '../agent-skills/service-lifecycle.json' with {type:'json'};
|
|
9
|
+
import {generationProviders} from './generation-provider.mjs';
|
|
10
|
+
import {artifactWorkProjection} from './artifact-work.mjs';
|
|
11
|
+
export function generationQuality(project,plan,files,{environment='staging'}={}){
|
|
12
|
+
const config=JSON.parse(files['main.tf.json']);
|
|
13
|
+
const providers=generationProviders(project),findings=[];
|
|
14
|
+
const add=(code,message,componentId)=>findings.push({code,message,...(componentId?{componentId}:{})});
|
|
15
|
+
inspectStateCustody(project,plan,files,config,environment,add);
|
|
16
|
+
const sources={aws:'hashicorp/aws',azurerm:'hashicorp/azurerm',azuread:'hashicorp/azuread',azapi:'azure/azapi',google:'hashicorp/google','google-beta':'hashicorp/google-beta',ibm:'ibm-cloud/ibm'};
|
|
17
|
+
const admission=inspectTerraformModules(project,plan,files,config,add);
|
|
18
|
+
inspectOwnership(project,admission.configs,add);
|
|
19
|
+
if(files['deployment-ownership.json']!==undefined){
|
|
20
|
+
const stable=value=>JSON.stringify(value,(_,v)=>v&&typeof v==='object'&&!Array.isArray(v)?Object.fromEntries(Object.keys(v).sort().map(k=>[k,v[k]])):v);
|
|
21
|
+
try{if(stable(JSON.parse(files['deployment-ownership.json']))!==stable(ownershipInventory(project,admission.configs)))add('ownership-inventory-mismatch','The ownership inventory changed actual project provenance, disposition, managed addresses or unverified authorization.');}catch{add('ownership-inventory-mismatch','The ownership inventory is invalid.');}
|
|
22
|
+
}
|
|
23
|
+
const prefixes={aws:'aws_',azure:'azurerm_',gcp:'google_',ibm:'ibm_'},emitted=[];
|
|
24
|
+
for(const scope of admission.configs){
|
|
25
|
+
const current=scope.config;
|
|
26
|
+
for(const [name,body]of Object.entries(current.terraform?.required_providers||{}))if(sources[name]!==String(body.source||'').toLowerCase())add('unreviewed-provider',`Provider ${name} in ${scope.path||'root'} is not the reviewed official provider source.`);
|
|
27
|
+
for(const [name,values]of Object.entries(current.provider||{}))for(const body of Array.isArray(values)?values:[values])for(const key of ['access_key','secret_key','token','client_secret','credentials','ibmcloud_api_key'])if(body?.[key])add('embedded-provider-credential',`Provider ${name} in ${scope.path||'root'} contains ${key}; use the operator credential chain.`);
|
|
28
|
+
for(const [type,items]of Object.entries(current.resource||{}))for(const [name,body]of Object.entries(items))if(body?.provisioner)add('execution-hook',`${scope.prefix}${type}.${name} contains an unreviewed provisioner.`);
|
|
29
|
+
if(current.data?.external||current.data?.terraform_remote_state)add('external-execution-or-state','External execution and remote-state readers require a separately reviewed adapter.');
|
|
30
|
+
for(const rule of lifecycle.rules)if(!rule.newCustomerDefaultAllowed&&rule.resourceTypes.some(type=>Object.keys(current.resource?.[type]||{}).length))add('service-eligibility-unverified',`${rule.id}: ${rule.requiredEvidence} Source: ${rule.source.url}`);
|
|
31
|
+
for(const [type,items]of Object.entries(current.resource||{}).filter(([type])=>type!=='terraform_data')){
|
|
32
|
+
emitted.push([scope.prefix+type,items]);const owner=/^(azuread_|azapi_)/.test(type)?'azure':Object.keys(prefixes).find(p=>type.startsWith(prefixes[p]));
|
|
33
|
+
if(!owner||!providers.includes(owner)||scope.provider&&scope.provider!==owner)add('provider-mismatch',`Resource ${scope.prefix}${type} does not match its requested deployment provider.`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
for(const node of project.nodes.filter(n=>n.data.kind!=='note'))if(plan.rows.filter(r=>r.id===node.id).length!==1)add('unregistered-implementation','The resource schedule must retain each component identity exactly once.',node.id);
|
|
37
|
+
const components=plan.rows.map(row=>{
|
|
38
|
+
const node=project.nodes.find(n=>n.id===row.id),d=node?.data||{},scope=admission.scopes.get(row.id),actual=scope?.config||(admission.composed?{}:config),prefix=scope?.prefix||'';
|
|
39
|
+
if(d.implementation==='approval-workflow'){
|
|
40
|
+
add('application-resource-linkage-required','The approval API source is partial assembly; provider resources, worker/domain behavior and operating acceptance remain required.',row.id);
|
|
41
|
+
if(row.implemented)add('unregistered-implementation','Shared approval source cannot be presented as completed infrastructure.',row.id);
|
|
42
|
+
}
|
|
43
|
+
if(node&&!existingDeployment(node)&&d.provider==='aws'&&d.implementation==='invoice-workflow'&&/^(cn-|us-gov-)/.test(d.config?.region||'')){
|
|
44
|
+
add('partition-implementation-required','The requested invoice partition is retained, but its complete ARN/registry/model policy is not implemented by the commercial adapter.',row.id);
|
|
45
|
+
const blocker=(scope?scope.module+':':'')+'invoice-config-region';
|
|
46
|
+
if(!config.locals?.unfinished_work?.includes(blocker))add('missing-work-gate','The unsupported invoice partition lost its component-owned implementation blocker.',row.id);
|
|
47
|
+
}
|
|
48
|
+
if(node)inspectContainerConfiguration(node,row,actual,plan,add,{root:config,scope});
|
|
49
|
+
if(!node||row.provider!==d.provider||!!row.existing!==!!(node&&existingDeployment(node)))add('unregistered-implementation','The schedule changed a component provider or ownership identity.',row.id);
|
|
50
|
+
const contracts=catalogue.contracts.filter(c=>c.provider===d.provider&&(!c.service||c.service===row.service)&&(!c.implementation||c.implementation===d.implementation));
|
|
51
|
+
if(!row.existing&&row.implemented){
|
|
52
|
+
if(!contracts.length)add('unregistered-implementation',`No reviewed compiler contract matches the claimed implementation for ${row.label}.`,row.id);
|
|
53
|
+
for(const c of contracts){
|
|
54
|
+
for(const type of c.resources)if(!actual.resource?.[type]?.[row.address])add('missing-resource',`Compiler claims ${c.id} for ${row.label}, but ${prefix}${type}.${row.address} is absent.`,row.id);
|
|
55
|
+
for(const instance of c.resourceInstances||[]){const name=row.address+instance.suffix;if(!actual.resource?.[instance.type]?.[name])add('missing-resource',`Compiler claims ${c.id} for ${row.label}, but required deployment unit ${prefix}${instance.type}.${name} is absent.`,row.id);}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return {id:row.id,...(scope?{terraformModule:scope.module}:{}),provider:row.provider,ownership:row.existing?'existing':'proposed',contracts:contracts.map(c=>c.id),coverage:row.existing?'reference_or_external_contract':row.implemented?'generated_unverified':'implementation_required'};
|
|
59
|
+
});
|
|
60
|
+
for(const row of plan.rows.filter(r=>!r.implemented))add('implementation-required',`${row.label}: implementation remains required.`,row.id);
|
|
61
|
+
for(const edge of plan.connections.filter(e=>!e.generated))add('connection-required',`Connection ${edge.id} has no generated integration.`);
|
|
62
|
+
const unfinished=config.locals?.unfinished_work||[];
|
|
63
|
+
if(!Array.isArray(unfinished))add('missing-work-gate','Unfinished scope must remain an explicit array of blockers.');
|
|
64
|
+
for(const gap of plan.gapDetails||[]){add('unfinished-scope',gap.message);if(!Array.isArray(unfinished)||!unfinished.includes(gap.id))add('missing-work-gate','The root configuration omits required unfinished scope: '+gap.id+'.');}
|
|
65
|
+
const skills=[...new Set([...catalogue.skills,...providers])].filter(id=>skillDigests[id]).map(id=>({id,sha256:skillDigests[id]}));
|
|
66
|
+
const fatalCodes=new Set(['ownership-inventory-mismatch','ownership-transition-unreviewed','existing-resource-managed','state-custody-mismatch','container-constraint-mismatch','provider-mismatch','missing-resource','unreviewed-provider','embedded-provider-credential','execution-hook','external-execution-or-state','unreviewed-module','unregistered-implementation','service-eligibility-unverified','missing-work-gate']);
|
|
67
|
+
const artifactMappings=artifactWorkProjection(project);
|
|
68
|
+
return {version:1,modules:[...admission.scopes].map(([id,scope])=>({id,module:scope.module,path:scope.path})),fatalFindings:findings.filter(f=>fatalCodes.has(f.code)),designRevision:project.revision,catalogueVersion:catalogue.version,providers,skills,skillUsage:"Referenced reviewed guidance; model execution of skills is not attested by this export.",components,findings,artifactMappings:{file:'architecture-artifact-mappings.json',references:artifactMappings.mappings.map(m=>({id:m.id,artifactId:m.artifactId,artifactSha256:m.artifactSha256,contextStatus:m.contextStatus,recordIds:m.records.map(r=>r.id)})),boundary:artifactMappings.boundary},infrastructureComplete:findings.length===0&&unfinished.length===0&&emitted.length>0,validation:{schema:'not_run',runtime:'not_run',cloudPlan:'not_run'},deploymentCandidate:false,evidenceBoundary:catalogue.evidenceBoundary};
|
|
69
|
+
}
|
package/src/handoff.mjs
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
// Derived engineering evidence. Presence of prose is not implementation or approval.
|
|
2
|
+
import {resourcePlan} from './resources.mjs';
|
|
3
|
+
import {estimate} from './estimate.mjs';
|
|
4
|
+
import {review} from './review.mjs';
|
|
5
|
+
import {requirementNumber} from './derive.mjs';
|
|
6
|
+
export const handoffKey=value=>Array.from(new TextEncoder().encode(String(value)),v=>v.toString(16).padStart(2,'0')).join('');
|
|
7
|
+
const resourceTask=id=>`TASK-RESOURCE-${handoffKey(id)}`;
|
|
8
|
+
|
|
9
|
+
const PROFILES = {
|
|
10
|
+
'Amazon S3': [
|
|
11
|
+
'Agree object ownership, retention/deletion, lifecycle and encryption/key policy; distinguish source data from Terraform state and build artifacts.',
|
|
12
|
+
'Add least-privilege bucket access and transport policy; test denied access, version recovery and deletion behavior.'
|
|
13
|
+
],
|
|
14
|
+
'AWS Lambda': [
|
|
15
|
+
'Specify runtime, entry point, immutable package/image, memory, timeout and concurrency; identify the trigger and its invocation permissions.',
|
|
16
|
+
'Define execution IAM, network egress, secret references and log retention; implement retries, idempotency, checkpoints and dead-letter handling where asynchronous.',
|
|
17
|
+
'Test representative payload sizes, duplicate events, throttling and downstream failures; measure cold and warm execution where latency matters.'
|
|
18
|
+
],
|
|
19
|
+
'Amazon OpenSearch': [
|
|
20
|
+
'Choose a provisioned domain or Serverless explicitly; select lexical, vector or hybrid retrieval before creating resources.',
|
|
21
|
+
'Define index mappings, document/version IDs, ACL and region filters, deletion propagation and reindexing; for vectors select embedding model and dimensions.',
|
|
22
|
+
'Specify encryption, network and data-access policies, capacity and recovery; prove filtered retrieval excludes unauthorized titles, snippets and documents.'
|
|
23
|
+
],
|
|
24
|
+
'Amazon OpenSearch Serverless': [
|
|
25
|
+
'Specify collection type, encryption, network and data-access policies, private connectivity and capacity limits.',
|
|
26
|
+
'Define index mappings and creation ownership; for vector search select embedding model/dimensions and query strategy.',
|
|
27
|
+
'Test permissions, document deletion, capacity, reindex/recovery and source ACL freshness.'
|
|
28
|
+
],
|
|
29
|
+
'Amazon OpenSearch domain': [
|
|
30
|
+
'Specify engine version, node/storage sizing, availability layout, encryption, private connectivity and fine-grained access.',
|
|
31
|
+
'Define index mappings, snapshot/restore, upgrades and capacity; for vectors select embedding model and dimensions.',
|
|
32
|
+
'Test recovery, document deletion and ACL/region-filtered retrieval under the agreed workload.'
|
|
33
|
+
],
|
|
34
|
+
'Amazon Bedrock': [
|
|
35
|
+
'Select exact generation and, if needed, embedding model IDs, invocation API and inference mode; verify account access, regional availability and quotas with dated evidence.',
|
|
36
|
+
'Map every inference destination to the agreed processing boundary; a regional endpoint or APAC profile does not by itself establish country-only processing.',
|
|
37
|
+
'Implement scoped invocation IAM, token/time limits, retries and budget controls; keep source authorization before model invocation.',
|
|
38
|
+
'Define prompt-injection handling, authorized citations, insufficient-evidence responses and output checks; test these separately from model guardrails.'
|
|
39
|
+
],
|
|
40
|
+
'Amazon Bedrock Guardrails': [
|
|
41
|
+
'Select supported policies, thresholds and a versioned guardrail; specify input/output invocation and behavior when checks fail or are unavailable.',
|
|
42
|
+
'Evaluate false positives, bypasses and restricted content with fixtures; guardrails do not substitute for source ACL enforcement.'
|
|
43
|
+
],
|
|
44
|
+
'Amazon Bedrock Knowledge Bases': [
|
|
45
|
+
'Select the embedding model, backing store, data sources, chunking, synchronization and service roles explicitly.',
|
|
46
|
+
'Verify connector support for source ACLs, deletions and freshness; implement missing permission enforcement before retrieval.',
|
|
47
|
+
'Test sync failures, reindexing, authorized citations and country boundaries for ingestion, embeddings and generation.'
|
|
48
|
+
],
|
|
49
|
+
'AWS App Runner': [
|
|
50
|
+
'Verify account eligibility before retaining App Runner; it is closed to new customers. Record the hosting decision and current official availability evidence.',
|
|
51
|
+
'Specify one deployment unit per actual application, immutable image, registry access, instance role, ingress/egress, health checks and scaling.',
|
|
52
|
+
'Design identity sessions, secrets, custom domain/TLS, logs and rollback; test deployment health and source dependency failures.'
|
|
53
|
+
],
|
|
54
|
+
'Amazon ECS': [
|
|
55
|
+
'Choose explicit ECS/Fargate resources or a reviewed managed deployment mode; define the task image, execution/task roles and secret references.',
|
|
56
|
+
'Specify subnets, security groups, ingress/load balancing, egress, health checks, scaling and deployment rollback.',
|
|
57
|
+
'Measure resource limits and request latency; test unhealthy deployments, dependency failures and recovery.'
|
|
58
|
+
],
|
|
59
|
+
'Amazon DynamoDB': [
|
|
60
|
+
'Define partition/sort keys and access patterns, capacity mode, indexes, encryption, point-in-time recovery and deletion protection.',
|
|
61
|
+
'Specify conditional writes, idempotency, TTL semantics and retention; test contention, throttling and restoration.'
|
|
62
|
+
],
|
|
63
|
+
'Amazon SQS': [
|
|
64
|
+
'Choose standard/FIFO semantics, encryption, queue policy, retention, visibility timeout and dead-letter/redrive settings.',
|
|
65
|
+
'Define producer/consumer IAM and retries; prove duplicate processing is safe and poison messages can be recovered.'
|
|
66
|
+
],
|
|
67
|
+
'Amazon CloudWatch': [
|
|
68
|
+
'Define structured redacted logs, retention, metrics, alarms, dashboards and alert ownership for each component.',
|
|
69
|
+
'Test ingestion failure, denied access and latency alarms; verify sensitive prompts, source text and credentials are excluded.'
|
|
70
|
+
],
|
|
71
|
+
};
|
|
72
|
+
export function engineeringSteps(row) {
|
|
73
|
+
if(row.containerContract)return [`Review terraform/main.tf.json resource ${row.containerContract.type}.${row.address} and the associated variables in deployment.tfvars.json.example.`, `Build the supplied application image, pin ${row.address}_image to its SHA-256 digest, and verify it listens on port 8080; infrastructure does not establish application behavior.`, 'Run terraform validate and terraform test using tests/container.tftest.hcl; review private ingress, runtime identity, registry access, platform prerequisites and destination-specific startup/rollback tests before applying.'];
|
|
74
|
+
if(row.externalReference)return ['Preserve the external browser; no resource or import is required.','Define and test its HTTPS/application interactions, including denied access and unavailable service behavior.'];
|
|
75
|
+
if(row.existingServiceReference)return ['Preserve this externally managed service without creating or importing it.','Document its owner, endpoint, identity and integration contract; test actual connections separately.'];
|
|
76
|
+
if(row.reference)return ['Bind the required Terraform ARN input to a reviewed existing same-account IAM role or user; never recreate the identity.','Verify scoped bucket/object permissions, effective boundaries and organization policies, versioned reads and denied access; the generated grant is not account-access evidence.'];
|
|
77
|
+
if(row.existing)return [
|
|
78
|
+
'Identify system owner, tenant/location, supported APIs and permitted read scopes; document a reference contract instead of recreating the system.',
|
|
79
|
+
'Specify identity mapping, source permissions, pagination/rate limits, update/delete events and maximum synchronization lag.',
|
|
80
|
+
'Define credential rotation, outages and recovery; test revoked access and unavailable sources using approved fixtures before live integration.'
|
|
81
|
+
];
|
|
82
|
+
return PROFILES[row.service] || [
|
|
83
|
+
`Confirm the exact ${row.provider} service, deployment mode, region and supported resource types using current primary documentation.`,
|
|
84
|
+
'Specify runtime/artifact, identity, network paths, secrets, capacity, health checks and operational owner; resolve whether this is infrastructure or a responsibility within another application.',
|
|
85
|
+
'Document service-specific failure modes, retention/recovery and acceptance tests; do not substitute a similarly named service or another provider.'
|
|
86
|
+
];
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function handoffAssessment(project, now = new Date()) {
|
|
90
|
+
const resources=resourcePlan(project), decisions=(project.decisions||[]).filter(d=>d.status==='Accepted'), needs=project.needs||[], findings=[];
|
|
91
|
+
const add=(id,priority,area,message,action,taskIds=['TASK-SCOPE'],componentIds=[],requirementIds=[])=>findings.push({id,priority,area,message,action,taskIds,componentIds,requirementIds,status:'open'});
|
|
92
|
+
const costs=estimate(project,now);
|
|
93
|
+
if(costs.gaps.length)add('cost-coverage',2,'cost',`${costs.gaps.length} cost worksheet gaps remain; unpriced resources are not free.`,'Complete usage assumptions and dated regional price sources; reconcile all billable dimensions with the reviewed plan.',['TASK-COST-BASELINE','TASK-COST']);
|
|
94
|
+
if(!(project.facts||[]).some(f=>f.name==='budget.per_month')&&!needs.some(r=>r.category==='cost'))add('budget-target',2,'cost','No budget constraint is recorded.','Agree a budget or explicitly document that no budget limit was specified; do not invent a price target.',['TASK-COST-BASELINE']);
|
|
95
|
+
for(const f of review(project).filter(f=>f.status==='open'&&['blocker','major'].includes(f.severity)))add(`review-${handoffKey(f.key)}`,f.severity==='blocker'?1:2,'security',f.statement,f.action,['TASK-SECURITY-DESIGN','TASK-SECURITY'],f.components);
|
|
96
|
+
const regionDecisions=decisions.filter(d=>d.subject==='cloud.region').map(d=>String(d.decision||'').trim());
|
|
97
|
+
if(new Set(regionDecisions).size>1)add('region-decisions-conflict',1,'placement','Multiple accepted deployment-region decisions disagree.','Resolve or supersede conflicting decisions explicitly; do not choose the most convenient value.');
|
|
98
|
+
const agreed=subject=>decisions.some(d=>d.subject===subject&&String(d.decision||'').trim());
|
|
99
|
+
if(!project.brief?.application?.trim())add('scope-outcome',1,'scope','No structured application outcome is recorded.','Confirm a concise outcome, intended users and exclusions; raw conversation fragments are not an implementation brief.');
|
|
100
|
+
if(!(project.useCases||[]).length)add('scope-boundary',1,'scope','No explicit scope boundary is recorded.','Record included and excluded use cases before sizing or implementation.');
|
|
101
|
+
if(!resources.rows.length)add('architecture-empty',1,'architecture','No deployable or existing components are described.','Define the components and interactions; an empty Terraform configuration is not a deployment.');
|
|
102
|
+
if(resources.rows.some(r=>r.provider!=='tools'))for(const [subject,label]of [['platform.cloud','cloud provider'],['data.country','data country and processing boundary'],['cloud.region','deployment region']])if(!agreed(subject))add(`decision-${subject}`,1,'placement',`The ${label} is not independently confirmed.`,`Record an explicit ${subject} decision. Proposed diagram placement is not approval.`);
|
|
103
|
+
for(const row of resources.rows){
|
|
104
|
+
const task=[resourceTask(row.id)], ids=[row.id], key=handoffKey(row.id);
|
|
105
|
+
if(!row.existing&®ionDecisions.length===1&®ionDecisions[0]!==row.region&&!/proposed|to be|unknown|confirm|select|tbd/i.test(row.region))add(`region-conflict-${key}`,1,'placement',`${row.label}: diagram placement differs from the accepted region decision.`,'Confirm whether this is intentional multi-region placement or stale design data; reconcile without silently overriding either source.',task,ids);
|
|
106
|
+
if(row.selection==='Ambiguous service names')add(`service-ambiguous-${key}`,1,'architecture',`${row.label}: multiple service names match.`, 'Set an explicit service; do not generate infrastructure from this label.',task,ids);
|
|
107
|
+
if(row.service==='Amazon OpenSearch')add(`search-mode-${key}`,1,'architecture',`${row.label}: OpenSearch deployment mode is unresolved.`,'Choose domain or Serverless and the retrieval/index design before generating resource types.',task,ids);
|
|
108
|
+
if(!row.existing && /proposed|to be|unknown|confirm|select|tbd/i.test(row.region))add(`placement-${key}`,2,'placement',`${row.label}: placement is unresolved.`,'Verify service/model availability and record the chosen region without silently replacing proposed placement.',task,ids);
|
|
109
|
+
if(!row.existing && !row.implemented)add(`implementation-${key}`,2,'implementation',`${row.label}: native infrastructure/application implementation is absent.`,engineeringSteps(row)[0],task,ids);
|
|
110
|
+
if(row.reference)add(`existing-${key}`,2,'integration',`${row.label}: ARN input and bucket-scoped access policy are generated; account-specific verification remains.`,'Supply the existing same-account role/user ARN; verify effective IAM permissions, organization controls and positive/negative runtime access. No identity is created or modified.',task,ids);
|
|
111
|
+
else if(row.existing)add(`existing-${key}`,2,'integration',`${row.label}: existing-system contract and access are unverified.`,engineeringSteps(row)[0],task,ids);
|
|
112
|
+
}
|
|
113
|
+
const appRunner=resources.rows.filter(r=>r.service==='AWS App Runner'&&!r.existing);
|
|
114
|
+
if(appRunner.length)add('service-lifecycle-apprunner',1,'availability','App Runner eligibility needs verification.','AWS closed App Runner to new customers. Verify existing-customer eligibility or agree an alternative. Source: https://docs.aws.amazon.com/apprunner/latest/dg/apprunner-availability-change.html (reviewed 2026-11-07).',appRunner.map(r=>resourceTask(r.id)),appRunner.map(r=>r.id));
|
|
115
|
+
const apps=resources.rows.filter(r=>['AWS App Runner','Amazon ECS'].includes(r.service));
|
|
116
|
+
if(apps.length>1)add('deployment-unit-mapping',1,'architecture','Multiple application blocks may represent shared responsibilities.','Map logical blocks to physical deployment units. Preserve accepted consolidation decisions; do not create one service per diagram block automatically.',apps.map(r=>resourceTask(r.id)),apps.map(r=>r.id));
|
|
117
|
+
if(!needs.length)add('requirements-empty',1,'acceptance','No acceptance requirements are recorded.','Agree observable behavior and success criteria before declaring the handoff implementation-ready.');
|
|
118
|
+
for(const r of needs){
|
|
119
|
+
const number=requirementNumber(project,r.id),task=[`TASK-ACCEPTANCE-${handoffKey(r.id)}`],key=handoffKey(r.id);
|
|
120
|
+
if(r.source!=='user')add(`requirement-proposed-${key}`,1,'acceptance',`${number} remains proposed.`,'Confirm, revise or explicitly defer this requirement; do not promote it through generation.',task,[],[r.id]);
|
|
121
|
+
const missing=(r.links||[]).filter(id=>!resources.rows.some(row=>row.id===id));
|
|
122
|
+
if(!r.links?.length||missing.length)add(`traceability-${key}`,2,'traceability',`${number} has ${missing.length?'references to missing components':'no component links'}.`,'Map the requirement to relevant components or record why it is project-wide; do not guess the mapping.',task,[],[r.id]);
|
|
123
|
+
// A scalar measure omits workload/window/negative cases, so never marks acceptance ready.
|
|
124
|
+
add(`acceptance-${key}`,2,'acceptance',`${number}: executable acceptance evidence is not supplied.`,r.measure?'Define workload, measurement window, first-output versus completed-response boundary and repeatable positive/negative cases.':'Agree an observable pass/fail criterion, fixtures and evidence location.',task,r.links||[],[r.id]);
|
|
125
|
+
}
|
|
126
|
+
for(const q of (project.openQuestions||[]).filter(q=>q.status==='open'))add(`question-${handoffKey(q.id)}`,1,'decision',q.question,'Resolve or explicitly defer this question with an owner and affected tasks.');
|
|
127
|
+
const order=['scope','architecture','placement','availability','security','decision','cost','acceptance','traceability','implementation','integration'];
|
|
128
|
+
findings.sort((a,b)=>a.priority-b.priority||order.indexOf(a.area)-order.indexOf(b.area)||a.id.localeCompare(b.id));
|
|
129
|
+
return {
|
|
130
|
+
format:'atmem.handoff-assessment',version:1,designRevision:project.revision,
|
|
131
|
+
status:'engineering_required',
|
|
132
|
+
stages:{design:findings.some(f=>f.priority===1)?'decisions_required':'review_required',infrastructure:resources.gaps.length===0&&resources.rows.length?'generated_implementation_unverified':resources.rows.some(r=>r.implemented&&!r.existing)?'partial_implementation':'not_implemented',localValidation:'not_attached',cloudPlan:'not_run',staging:'not_verified',production:'approval_not_attached'},
|
|
133
|
+
counts:{components:resources.rows.length,generatedFoundations:resources.rows.filter(r=>r.foundation).length,connections:resources.connections.length,priorityDecisions:findings.filter(f=>f.priority===1).length},
|
|
134
|
+
nextAction:findings.find(f=>f.priority===1)?.action||'Review component engineering work and confirm the implementation scope.',
|
|
135
|
+
findings,
|
|
136
|
+
evidencePolicy:'Generated documents and asserted decisions are design evidence only. Schema validation, mock tests, account plans and deployed-system tests require separate receipts tied to the exact configuration. This export does not ingest implementation evidence.',
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
export function handoffMarkdown(report){
|
|
140
|
+
return `# Handoff readiness\n\nStatus: engineering required. No deployment readiness is implied.\n\n## Next action\n\n${report.nextAction}\n\n## Evidence stages\n\n${Object.entries(report.stages).map(([k,v])=>`- ${k}: ${v}`).join('\n')}\n\n${report.evidencePolicy}\n\n## Decisions and engineering gaps\n\n${report.findings.map(f=>`### ${f.id} — priority ${f.priority}\n\n${f.message}\n\nAction: ${f.action}\n\nTasks: ${f.taskIds.join(', ')}`).join('\n\n')}\n`;
|
|
141
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// Reviewed 2026-11-10: IBM's registry hostname is not its Code Engine region.
|
|
2
|
+
// https://cloud.ibm.com/docs/Registry?topic=Registry-registry_overview
|
|
3
|
+
export const IBM_REGISTRY_HOSTS=Object.freeze({'au-syd':'au.icr.io','br-sao':'br.icr.io','ca-mon':'ca2.icr.io','ca-tor':'ca.icr.io','eu-de':'de.icr.io','eu-es':'es.icr.io','eu-gb':'uk.icr.io','in-che':'in.icr.io','in-mum':'in2.icr.io','jp-osa':'jp2.icr.io','jp-tok':'jp.icr.io','us-south':'us.icr.io'});
|
|
4
|
+
export function ibmRegistryHost(region){
|
|
5
|
+
if(!Object.hasOwn(IBM_REGISTRY_HOSTS,region))throw Error('Select an explicitly supported regional IBM registry; no global fallback is inferred');
|
|
6
|
+
return IBM_REGISTRY_HOSTS[region];
|
|
7
|
+
}
|
|
8
|
+
export function ibmRegistryHostExpression(variable='var.region'){
|
|
9
|
+
if(!/^var\.[a-z][a-z0-9_]*$/.test(variable))throw Error('Use a compiler-owned registry region variable');
|
|
10
|
+
return'${lookup('+JSON.stringify(IBM_REGISTRY_HOSTS)+','+variable+')}';
|
|
11
|
+
}
|
|
12
|
+
export function ibmRegistryRegionValidation(){return{condition:'${contains('+JSON.stringify(Object.keys(IBM_REGISTRY_HOSTS))+',var.region)}',error_message:'Use a reviewed regional Container Registry location; an invented region hostname or implicit global fallback is not supported.'};}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import {ibmRegistryHostExpression,ibmRegistryRegionValidation}from'./ibm-registry.mjs';
|
|
2
|
+
import sources from './runtime/ibm-sources.json' with {type:'json'};
|
|
3
|
+
import lock from './runtime/ibm-python-lock.json' with {type:'json'};
|
|
4
|
+
import testLock from './runtime/azure-test-lock.json' with {type:'json'};
|
|
5
|
+
import base from './runtime/python-container-lock.json' with {type:'json'};
|
|
6
|
+
import {pythonContainer} from './python-container.mjs';
|
|
7
|
+
import {STRUCTURED_WEB_HTML,STRUCTURED_WEB_CSS,STRUCTURED_WEB_JS} from './structured-web.mjs';
|
|
8
|
+
import {structuredContract} from './structured-contract.mjs';
|
|
9
|
+
import {existingDeployment} from './deployment-ownership.mjs';
|
|
10
|
+
import {existingReferenceFiles} from './existing-references.mjs';
|
|
11
|
+
import {CLOUD_PROVIDER_LOCKS} from './cloud-provider-locks.mjs';
|
|
12
|
+
|
|
13
|
+
export function ibmStructuredPlan(project,rows){
|
|
14
|
+
const entries=[];
|
|
15
|
+
for(const node of project.nodes){
|
|
16
|
+
if(node.data.provider!=='ibm'||node.data.implementation!=='ibm-structured-app'||node.data.service!=='IBM Code Engine'||existingDeployment(node))continue;
|
|
17
|
+
const contract=structuredContract(node.data.config?.outputContract);if(!contract)continue;
|
|
18
|
+
const maxInput=node.data.config?.maxInputBytes??20000,maxTokens=node.data.config?.maxOutputTokens??1024;
|
|
19
|
+
if(!Number.isInteger(maxInput)||maxInput<1||maxInput>20000||!Number.isInteger(maxTokens)||maxTokens<32||maxTokens>4096)throw Error('IBM structured application limits must be 1–20000 input bytes and 32–4096 output tokens.');
|
|
20
|
+
entries.push({row:rows.find(r=>r.id===node.id),contract,maxInput,maxTokens});
|
|
21
|
+
}
|
|
22
|
+
const ids=new Set(entries.map(e=>e.row.id)),browsers=new Set(project.nodes.filter(n=>existingDeployment(n)&&n.data.provider==='tools'&&n.data.binding==='web-browser').map(n=>n.id));
|
|
23
|
+
return {entries,componentIds:[...ids],edgeIds:project.edges.filter(e=>e.integration==='browser-https'&&browsers.has(e.source)&&ids.has(e.target)).map(e=>e.id)};
|
|
24
|
+
}
|
|
25
|
+
const v=n=>'${var.'+n+'}',ref=(type,n,key)=>'${'+type+'.'+n+'.'+key+'}';
|
|
26
|
+
const UUID='^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$';
|
|
27
|
+
export function ibmStructuredTerraform(project,plan,environment='staging'){
|
|
28
|
+
const entries=plan.ibmStructuredPlan.entries;if(!entries.length)throw Error('No IBM structured application composition.');
|
|
29
|
+
const variable={review_approved:{type:'bool',default:false}},examples={review_approved:false},resource={},output={},files={},tests=[];
|
|
30
|
+
const input=(name,description,example,pattern)=>{variable[name]={type:'string',nullable:false,description,validation:{condition:'${can(regex('+JSON.stringify(pattern)+', var.'+name+'))}',error_message:'Supply the reviewed '+name+' value.'}};examples[name]=example;return v(name);};
|
|
31
|
+
const account=input('account_id','Existing destination IBM account. The referenced Code Engine project must belong to it.','a'.repeat(32),'^[0-9a-f]{32}$');
|
|
32
|
+
const region=input('region','Reviewed region with Code Engine, App ID and the selected watsonx model. Verify availability, identity processing and terms; no global fallback.','au-syd','^[a-z]{2}-[a-z]+$');
|
|
33
|
+
if(entries.every(e=>e.row.region===entries[0].row.region)&&/^[a-z]{2}-[a-z]+$/.test(entries[0].row.region)){variable.region.default=entries[0].row.region;examples.region=entries[0].row.region;}
|
|
34
|
+
variable.region.validation=ibmRegistryRegionValidation();
|
|
35
|
+
const ceProject=input('code_engine_project_id','Existing Code Engine project; never recreate or import it.','11111111-1111-1111-1111-111111111111',UUID);
|
|
36
|
+
const registry=input('registry_namespace','Existing regional IBM Container Registry namespace.','reviewed-namespace','^[a-z0-9]+(?:[-_][a-z0-9]+)*$');
|
|
37
|
+
const pullSecret=input('registry_pull_secret','Existing authorized registry-pull secret NAME in that Code Engine project. No credential values are exported or written to state.','reviewed-registry-pull','^[a-z][a-z0-9-]{1,61}[a-z0-9]$');
|
|
38
|
+
const gaps=[...plan.gapDetails.map(g=>g.id),...(environment==='production'?['production-state-backup-and-operating-review-required']:[])];
|
|
39
|
+
resource.terraform_data={review_gate:{input:{design_revision:project.revision,environment},lifecycle:{precondition:[{condition:'${var.review_approved && length(local.unfinished_work) == 0}',error_message:'Review destination, code, access, model policy, costs and unresolved scope before planning deployment.'},{condition:'${data.ibm_code_engine_project.destination.account_id == var.account_id && data.ibm_code_engine_project.destination.region == var.region}',error_message:'Preserve the existing Code Engine project: account and region must match the reviewed destination.'}]}}};
|
|
40
|
+
const add=(type,name,body)=>((resource[type]||={})[name]={...body,depends_on:['terraform_data.review_gate',...(body.depends_on||[])]});
|
|
41
|
+
for(const {row,contract,maxInput,maxTokens}of entries){
|
|
42
|
+
const n=row.address;
|
|
43
|
+
const name=input(n+'_name','Application and App ID registration name.','reviewed-ai-app','^[a-z][a-z0-9-]{2,48}[a-z0-9]$');
|
|
44
|
+
const repository=input(n+'_image_repository','Reviewed path for the emitted application image in the existing registry namespace.','architect/app','^[a-z0-9]+(?:[._/-][a-z0-9]+)*$');
|
|
45
|
+
const digest=input(n+'_image_digest','Exact built, scanned and tested emitted image digest. Publishing requires authorization.','sha256:'+'0'.repeat(64),'^sha256:[0-9a-f]{64}$');
|
|
46
|
+
const wxProject=input(n+'_watsonx_project_id','Existing watsonx data-platform project; associate the reviewed runtime instance and add this generated trusted profile as an authorized collaborator. IAM access alone does not establish project membership.','22222222-2222-2222-2222-222222222222',UUID);
|
|
47
|
+
const instance=input(n+'_runtime_instance_id','Existing associated watsonx.ai Runtime service instance GUID, scoped by the generated IAM policy. Not a Cloud Projects deployment ID.','33333333-3333-3333-3333-333333333333',UUID);
|
|
48
|
+
const model=input(n+'_model_id','Reviewed regional Text Chat model with JSON-object output support; verify lifecycle, model terms and quotas.','ibm/reviewed-model','^[a-z0-9][a-z0-9_.-]{0,79}/[a-z0-9][a-z0-9_.-]{0,99}$');
|
|
49
|
+
const appidPlan=input(n+'_appid_plan','Current App ID service plan reviewed by the implementing engineer against the catalog and accepted budget. No price is invented.','graduated-tier','^[a-z][a-z0-9-]{1,79}$');
|
|
50
|
+
const subjects=n+'_authorized_user_subjects';variable[subjects]={type:'set(string)',default:[],nullable:false,description:'Admin-enrolled Cloud Directory user subjects from this NEW owned App ID tenant. Initially empty denies everyone. Enroll staff securely, then review and add exact subjects. This authoritative role assignment must not target a shared/existing tenant.',validation:{condition:'${alltrue([for subject in var.'+subjects+' : can(regex("^[A-Za-z0-9|:_@.-]{1,200}$", subject))])}',error_message:'Supply exact administrator-reviewed user subjects.'}};examples[subjects]=[];
|
|
51
|
+
const review=n+'_policy_review';variable[review]={type:'object({ accountId = string, projectId = string, runtimeInstanceId = string, region = string, model = string, retentionReview = string, approvedBy = string, evidenceSha256 = string, expiresAt = string })',nullable:false,description:'Scoped destination-owner review of actual model/provider retention and data-processing terms. Evidence digest and expiry within 31 days; operator attestation, not a fabricated approval API.'};examples[review]={accountId:examples.account_id,projectId:examples[n+'_watsonx_project_id'],runtimeInstanceId:examples[n+'_runtime_instance_id'],region:examples.region,model:examples[n+'_model_id'],retentionReview:'REVIEW_REQUIRED',approvedBy:'REVIEW_REQUIRED',evidenceSha256:'0'.repeat(64),expiresAt:'REPLACE_AFTER_REVIEW'};
|
|
52
|
+
add('ibm_resource_instance',n,{name,service:'appid',plan:appidPlan,location:region,resource_group_id:'${data.ibm_code_engine_project.destination.resource_group_id}',lifecycle:{prevent_destroy:true,postcondition:[{condition:'${self.account_id == var.account_id}',error_message:'App ID tenant must belong to the reviewed account.'}]}});
|
|
53
|
+
const tenant=ref('ibm_resource_instance',n,'guid'),client=ref('ibm_appid_application',n,'client_id');
|
|
54
|
+
add('ibm_appid_application',n,{tenant_id:tenant,name,type:'singlepageapp'});
|
|
55
|
+
add('ibm_appid_application_scopes',n,{tenant_id:tenant,client_id:client,scopes:['process']});
|
|
56
|
+
add('ibm_appid_role',n,{tenant_id:tenant,name:'WorkspaceUser',access:[{application_id:client,scopes:['process']}],depends_on:['ibm_appid_application_scopes.'+n]});
|
|
57
|
+
add('ibm_appid_user_roles',n,{for_each:v(subjects),tenant_id:tenant,subject:'${each.value}',role_ids:[ref('ibm_appid_role',n,'role_id')]});
|
|
58
|
+
add('ibm_appid_idp_cloud_directory',n,{tenant_id:tenant,is_active:true,signup_enabled:false,self_service_enabled:false,welcome_enabled:false,reset_password_enabled:true,reset_password_notification_enabled:true,identity_field:'email',identity_confirm_access_mode:'FULL',identity_confirm_methods:['email']});
|
|
59
|
+
for(const idp of ['facebook','google','saml'])add('ibm_appid_idp_'+idp,n,{tenant_id:tenant,is_active:false});
|
|
60
|
+
add('ibm_iam_trusted_profile',n,{name,description:'Keyless Code Engine model runtime; no end-user login authority'});
|
|
61
|
+
add('ibm_iam_trusted_profile_link',n,{profile_id:ref('ibm_iam_trusted_profile',n,'profile_id'),cr_type:'CE',link:{crn:'${data.ibm_code_engine_project.destination.crn}',component_name:ref('ibm_code_engine_app',n,'name'),component_type:'app'}});
|
|
62
|
+
add('ibm_iam_trusted_profile_policy',n,{iam_id:ref('ibm_iam_trusted_profile',n,'iam_id'),roles:['Writer'],resources:{service:'pm-20',resource_instance_id:instance,region},description:'Instance-scoped watsonx Runtime access. Writer includes broader instance operations; it is not an invented prediction-only IAM permission.'});
|
|
63
|
+
const settings={ACCOUNT_ID:account,WATSONX_PROJECT_ID:wxProject,RUNTIME_INSTANCE_ID:instance,MODEL_REGION:region,MODEL_ID:model,IAM_PROFILE_ID:ref('ibm_iam_trusted_profile',n,'profile_id'),APPID_TENANT_ID:tenant,APPID_CLIENT_ID:client,APPID_ISSUER:ref('ibm_appid_application',n,'oauth_server_url'),AUTH_SCOPE:name+'/process',OUTPUT_CONTRACT_BASE64:btoa(unescape(encodeURIComponent(JSON.stringify(contract)))),MAX_INPUT_BYTES:String(maxInput),MAX_OUTPUT_TOKENS:String(maxTokens),POLICY_REVIEW_BASE64:'${base64encode(jsonencode(var.'+review+'))}'};
|
|
64
|
+
add('ibm_code_engine_app',n,{project_id:ceProject,name,image_reference:ibmRegistryHostExpression()+'/'+registry+'/'+repository+'@'+digest,image_secret:pullSecret,image_port:8080,managed_domain_mappings:'local_public',run_as_user:10001,run_compute_resource_token_enabled:true,scale_cpu_limit:'0.5',scale_memory_limit:'1G',scale_min_instances:0,scale_max_instances:2,scale_concurrency:5,scale_concurrency_target:5,scale_request_timeout:30,run_env_variables:Object.entries(settings).map(([name,value])=>({name,value,type:'literal'})),probe_readiness:{type:'http',path:'/healthz',port:8080,initial_delay:2,interval:5,timeout:2,failure_threshold:12},depends_on:['ibm_iam_trusted_profile_policy.'+n]});
|
|
65
|
+
// Link follows app creation: making the app depend on its own link would cycle.
|
|
66
|
+
add('ibm_appid_redirect_urls',n,{tenant_id:tenant,urls:[ref('ibm_code_engine_app',n,'endpoint')+'/']});
|
|
67
|
+
output[n+'_url']={value:ref('ibm_code_engine_app',n,'endpoint')};output[n+'_appid_tenant_id']={value:tenant};output[n+'_trusted_profile_iam_id']={value:ref('ibm_iam_trusted_profile',n,'iam_id')};
|
|
68
|
+
const folder='applications/'+n+'/';for(const [path,body]of Object.entries(sources))files[folder+path]=body;
|
|
69
|
+
files[folder+'web/index.html']=STRUCTURED_WEB_HTML.replace('>Sign out</button>','>Clear workspace</button>');files[folder+'web/app.css']=STRUCTURED_WEB_CSS;files[folder+'web/app.js']=STRUCTURED_WEB_JS;
|
|
70
|
+
files[folder+'output-contract.json']=JSON.stringify(contract,null,2);
|
|
71
|
+
files[folder+'requirements.lock']=lock.requirements;files[folder+'dependency-sources.json']=JSON.stringify(lock.sources,null,2);files[folder+'test-requirements.lock']=testLock.requirements;files[folder+'test-dependency-sources.json']=JSON.stringify(testLock.sources,null,2);files[folder+'container-base.json']=JSON.stringify(base,null,2);
|
|
72
|
+
const modules=['ibm_structured.py','structured_output.py','structured_http.py','policy_review.py'];files[folder+'Dockerfile']=pythonContainer('ibm_structured',modules);files[folder+'.dockerignore']='*\n!requirements.lock\n!output-contract.json\n'+modules.map(p=>'!'+p+'\n').join('')+'!web/\n!web/*\n';
|
|
73
|
+
files[folder+'BUILD.md']=`# Generated Code Engine application\n\nCreate an isolated Python 3.13 environment; install test-requirements.lock using binary wheels and --require-hashes. Run ibm_acceptance.py -v. Local signed-JWT/ASGI/SDK/transport fixtures never establish live IBM behavior.\n\nBuild with docker build --platform linux/amd64 --pull -t REVIEWED_REGIONAL_REGISTRY/REVIEWED_NAMESPACE/REVIEWED_IMAGE:REVIEWED_BUILD . ; scan and run the exact image nonroot/read-only. Retain source/image digests. Obtain authorization before logging into the existing registry and publishing; supply that immutable digest as ${n}_image_digest. The existing Code Engine project must already contain its authorized registry-pull secret (${examples.registry_pull_secret}); Terraform references the name without exporting credential values.\n\nSupply reviewed destination/model inputs and ${review}. The example review is unapproved. Add the generated trusted profile IAM identity to the existing watsonx data-platform project with the minimum supported collaborator role, associate its runtime instance, and verify model access with synthetic data. This separate project authorization cannot be inferred from IAM Writer access. Do not add account-wide Manager/Admin or an API key to bypass a failure.\n\nThis new App ID tenant initially admits no application users. After authorized provisioning, enroll staff using its administrator workflow, distribute credentials securely, and add reviewed subjects to ${subjects}; inspect the next plan. The role assignment is authoritative only within this owned tenant. Test allowed user, wrong user/tenant, missing scope and expired/revoked sessions. No passwords or user-managed secrets belong in variables or state.\n`;
|
|
74
|
+
tests.push(`run "${n}_sydney_registry" {\n command = plan\n assert {\n condition = var.region != "au-syd" || startswith(ibm_code_engine_app.${n}.image_reference,"au.icr.io/")\n error_message = "Sydney image pulls must use au.icr.io, never a region-derived invented registry."\n }\n}`);
|
|
75
|
+
tests.push(`run "${n}_identity" {\n command = plan\n assert {\n condition = ibm_code_engine_app.${n}.run_compute_resource_token_enabled && ibm_code_engine_app.${n}.run_as_user == 10001\n error_message = "Use nonroot Code Engine compute identity."\n }\n assert {\n condition = ibm_appid_application.${n}.type == "singlepageapp" && !ibm_appid_idp_cloud_directory.${n}.signup_enabled && !ibm_appid_idp_google.${n}.is_active && !ibm_appid_idp_facebook.${n}.is_active && !ibm_appid_idp_saml.${n}.is_active\n error_message = "Only admin-enrolled scoped users belong in this owned App ID tenant."\n }\n assert {\n condition = ibm_iam_trusted_profile_policy.${n}.resources[0].resource_instance_id == var.${n}_runtime_instance_id && ibm_iam_trusted_profile_policy.${n}.resources[0].service == "pm-20" && ibm_iam_trusted_profile_policy.${n}.roles == tolist(["Writer"])\n error_message = "No account-wide model grant or substituted service."\n }\n assert {\n condition = ibm_iam_trusted_profile_link.${n}.cr_type == "CE" && ibm_iam_trusted_profile_link.${n}.link[0].component_type == "app" && length(ibm_appid_user_roles.${n}) == 0\n error_message = "Bind this compute resource; user allowlist starts empty."\n }\n}\nrun "${n}_reject_mutable_image" {\n command = plan\n variables { ${n}_image_digest = "latest" }\n expect_failures = [var.${n}_image_digest]\n}`);
|
|
76
|
+
}
|
|
77
|
+
const config={terraform:{required_version:'>= 1.17.1, < 2.0.0',required_providers:{ibm:{source:'IBM-Cloud/ibm',version:'1.89.0'}}},provider:{ibm:{region}},data:{ibm_code_engine_project:{destination:{project_id:ceProject}}},variable,locals:{unfinished_work:gaps},resource,output};
|
|
78
|
+
const values=Object.entries({...examples,review_approved:true}).map(([k,value])=>k+' = '+JSON.stringify(value)).join('\n');
|
|
79
|
+
return {...files,...existingReferenceFiles(project),'.terraform.lock.hcl':CLOUD_PROVIDER_LOCKS.ibm,'main.tf.json':JSON.stringify(config,null,2),'resource-schedule.json':JSON.stringify(plan,null,2),'deployment.tfvars.json.example':JSON.stringify(examples,null,2),'.gitignore':'.terraform/\n*.tfstate*\n*.tfplan\n*.tfvars\n*.tfvars.json\n!deployment.tfvars.json.example\n.venv/\n__pycache__/\n','tests/ibm-structured.tftest.hcl':`mock_provider "ibm" {\n override_during = plan\n mock_data "ibm_code_engine_project" { defaults = { account_id = "${examples.account_id}", region = "${examples.region}", resource_group_id = "${'b'.repeat(32)}", crn = "crn:v1:bluemix:public:codeengine:au-syd:a/${examples.account_id}:11111111-1111-1111-1111-111111111111::" } }\n}\nvariables {\n${values}\n}\n${tests.join('\n')}\nrun "wrong_account_blocked" {\n command = plan\n variables { account_id = "${'c'.repeat(32)}" }\n expect_failures = [terraform_data.review_gate]\n}\nrun "unapproved_blocked" {\n command = plan\n variables { review_approved = false }\n expect_failures = [terraform_data.review_gate]\n}\n`,'README.md':IBM_STRUCTURED_GUIDE};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export const IBM_STRUCTURED_GUIDE=`# IBM structured AI application
|
|
83
|
+
|
|
84
|
+
The explicit ibm-structured-app module emits a Python 3.13 browser/API on Code Engine, a NEW owned App ID tenant and single-page PKCE registration, scoped WorkspaceUser role, disabled social/self-signup paths, dedicated trusted profile and exact Code Engine compute-resource link. Existing Code Engine project, private registry/pull secret, watsonx data-platform project and associated runtime instance are preserved. Independent blocks/connections retain their gaps.
|
|
85
|
+
|
|
86
|
+
User and workload identities are separate. The API verifies RS256 App ID signatures from its fixed public key endpoint, exact issuer, single client audience, tenant, authenticated Cloud Directory method and application process scope before and after inference. ID/anonymous/machine tokens do not grant user access. No custom user-attribute-to-scope mapping is created. Protect tenant administration; token scopes last until expiry, and immediate revocation, existing SSO, MFA or private networking are not implemented by this module. The browser keeps access tokens in memory, verifies OAuth state and S256 PKCE, clears private input/results on access loss, and offers local workspace clearing without claiming global identity-provider logout.
|
|
87
|
+
|
|
88
|
+
The fixed Code Engine compute-resource token is exchanged by the hash-pinned IBM SDK using the generated trusted profile. No application API key or client secret is emitted. The exact linked project/app is trusted; there is no account-wide compute rule. The runtime receives Writer only on the reviewed pm-20 runtime instance. This role includes broader instance operations and is not prediction-only. Data-platform project collaborator membership and associated-instance/model access are separate destination prerequisites; verify them instead of expanding IAM or introducing static credentials. The app becomes live before its compute link is created, then inference can work after account propagation and project authorization; do not create an app/link dependency cycle. Health is liveness, not model readiness.
|
|
89
|
+
|
|
90
|
+
One bounded regional Text Chat request uses the reviewed model/project, JSON-object output, no tools, no automatic retry or saved session. Invalid, duplicate, extra, truncated or action-bearing output fails closed. Independent schema checks and human review do not establish semantic model quality. A scoped, expiring destination-owner review of actual retention/processing terms is required before workload authentication or inference. It is operator-attested evidence, not a fabricated IBM privacy approval API. No app input/result persistence is implemented; identity/IAM/global processing and actual model geography still need review against residency requirements.
|
|
91
|
+
|
|
92
|
+
Use BUILD.md and Terraform 1.17.1+. Run terraform init -backend=false, terraform validate and terraform test; inspect the empty user allowlist and wrong-account/unapproved/mutable-image negative tests. Build, scan and locally test the exact Linux image, obtain authorization to publish, and supply its immutable registry digest. Account plan, current service/model availability, quota, costs, real App ID signup denial and role tokens, Code Engine token exchange, dataplatform model access, model quality and operations must be checked before deployment. Production state/backup/operating review remains gated. Scaling/token limits are not an invoice cap or SLA. Terraform state/variable files require protection; no export proves deployment.
|
|
93
|
+
|
|
94
|
+
References:
|
|
95
|
+
- https://cloud.ibm.com/docs/codeengine?topic=codeengine-trusted-profiles-authentication-file
|
|
96
|
+
- https://cloud.ibm.com/docs/codeengine?topic=codeengine-inside-env-vars
|
|
97
|
+
- https://cloud.ibm.com/docs/appid?topic=appid-single-page
|
|
98
|
+
- https://cloud.ibm.com/docs/appid?topic=appid-access-control
|
|
99
|
+
- https://cloud.ibm.com/docs/appid?topic=appid-token-validation
|
|
100
|
+
- https://cloud.ibm.com/docs/apis/watsonx-ai
|
|
101
|
+
- https://cloud.ibm.com/docs/iam?topic=iam-iam-service-roles-actions
|
|
102
|
+
- https://registry.terraform.io/providers/IBM-Cloud/ibm/1.89.0/docs/resources/iam_trusted_profile_link
|
|
103
|
+
`;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import {sha256} from '@noble/hashes/sha2.js';
|
|
2
|
+
const hex=bytes=>Array.from(bytes,b=>b.toString(16).padStart(2,'0')).join('');
|
|
3
|
+
// Preserve established short addresses. Long Unicode identities use a bounded
|
|
4
|
+
// digest token; original identities remain in project/manifest/requirement links.
|
|
5
|
+
// Odd-length digest tokens cannot overlap any legacy even-length UTF-8 hex token.
|
|
6
|
+
export function identityToken(value){
|
|
7
|
+
if(typeof value!=='string'||!value)throw Error('Use a nonempty component identity.');
|
|
8
|
+
try{encodeURIComponent(value);}catch{throw Error('Use a well-formed Unicode identity; no characters were replaced.');}
|
|
9
|
+
const bytes=new TextEncoder().encode(value);
|
|
10
|
+
return bytes.length<=124?hex(bytes):'d'+hex(sha256(bytes));
|
|
11
|
+
}
|
|
12
|
+
export const resourceAddress=id=>'block_'+identityToken(id);
|
|
13
|
+
export function assertDistinctIdentifiers(ids,token=identityToken){
|
|
14
|
+
const seen=new Map();for(const id of ids){const name=token(id);if(seen.has(name))throw Error(seen.get(name)===id?'Duplicate component identity; no output was overwritten.':'Component namespace collision; retain both original identities and stop generation.');seen.set(name,id);}
|
|
15
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import {inspectTerraformModules} from './terraform-admission.mjs';
|
|
2
|
+
// Concrete links are derived from emitted files, not fabricated repository paths.
|
|
3
|
+
export function implementationMap(project,plan,files){
|
|
4
|
+
const config=JSON.parse(files['main.tf.json']),admission=inspectTerraformModules(project,plan,files,config,()=>{});
|
|
5
|
+
const components=plan.rows.map(row=>{
|
|
6
|
+
const scope=admission.scopes.get(row.id),current=scope?.config||(admission.composed?{}:config);
|
|
7
|
+
const addresses=Object.entries(current.resource||{}).flatMap(([type,items])=>Object.keys(items).filter(name=>name===row.address||name.startsWith(row.address+'_')).map(name=>(scope?.prefix||'')+type+'.'+name));
|
|
8
|
+
const generatedFiles=Object.entries(files).filter(([name,body])=>scope?name.startsWith(scope.path+'/'):name!=='resource-schedule.json'&&(!admission.composed&&row.invoice||name.includes(row.address)||typeof body==='string'&&body.includes(row.address))).map(([name])=>'terraform/'+name);
|
|
9
|
+
const variables=scope?Object.keys(current.variable||{}).map(name=>name==='review_approved'?name:scope.module+'__'+name).filter(name=>Object.hasOwn(config.variable||{},name)):Object.keys(config.variable||{}).filter(name=>!admission.composed&&row.invoice||name.startsWith(row.address+'_'));
|
|
10
|
+
return {id:row.id,...(scope?{module:scope.module,modulePath:'terraform/'+scope.path}:{}),ownership:row.existing?'existing':row.sourceExisting?'existing_source_new_deployment':'proposed',terraformAddresses:addresses,generatedFiles,requiredInputs:variables,requirements:(project.needs||[]).filter(r=>r.links?.includes(row.id)).map(r=>r.id),applicationImplementation:project.nodes.find(n=>n.id===row.id)?.data.implementation==='approval-workflow'?'shared_api_assembly_only':row.containerContract?'supplied_image_required':row.existing?'external_behavior_unverified':generatedFiles.some(p=>p.includes('/handlers/'))?'generated_runtime_unverified':generatedFiles.some(p=>p.includes('/web/')||p.includes('/applications/'))?'generated_application_unverified':row.implemented&&addresses.length?'managed_service_configuration_unverified':'not_established'};
|
|
11
|
+
});
|
|
12
|
+
const interfaces=project.edges.map(edge=>({id:edge.id,source:edge.source,target:edge.target,purpose:edge.label||'',integration:edge.integration||null,access:edge.access||null,generated:!!plan.connections.find(e=>e.id===edge.id)?.generated,requiredContractFields:['request/event schema','response/result schema','identity and authorization','timeout','retry and idempotency','error and recovery','observability','acceptance fixtures'],status:'runtime_contract_evidence_required'}));
|
|
13
|
+
return {version:1,designRevision:project.revision,components,interfaces,commands:admission.composed?['terraform init -backend=false','terraform validate',...admission.configs.filter(s=>s.path).flatMap(s=>['terraform -chdir='+s.path+' init -backend=false','terraform -chdir='+s.path+' validate','terraform -chdir='+s.path+' test'])]:['terraform init -backend=false','terraform validate','terraform test'],evidenceBoundary:'File and resource links are generated artifact facts; runtime behavior and destination account validation require separate evidence.'};
|
|
14
|
+
}
|