@atmem/architect 0.0.0-stage → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CONSTITUTION.md +144 -0
- package/LICENSE +202 -0
- package/NOTICE +6 -0
- package/README.md +31 -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-BTLHaa3J.css +1 -0
- package/dist/assets/index-CQ2C1gKF.js +21338 -0
- package/dist/assets/index.es-DTyqIdaO.js +18 -0
- package/dist/assets/purify.es-CAi2OJFm.js +3 -0
- package/dist/assets/visual-export-Ox0j5xj5.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/atmem-APACHE-2.0.txt +202 -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/atmem-APACHE-2.0.txt +202 -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 +193 -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 +221 -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 +172 -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 +483 -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 +185 -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_context.py +58 -0
- package/server/memory_routes.py +141 -0
- package/server/memory_service.py +306 -0
- package/server/memory_worker.py +129 -0
- package/server/openai_voice.py +80 -0
- package/server/orca_handoff.py +90 -0
- package/server/packaged_app.py +9 -0
- package/server/pricing.py +190 -0
- package/server/process_control_observation.py +31 -0
- package/server/prompts.py +136 -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/server/windows_snapshot.py +119 -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 +39 -0
- package/src/ArtifactChecks.jsx +49 -0
- package/src/BlockRequirements.jsx +13 -0
- package/src/BrainActivity.jsx +11 -0
- package/src/ChatMessage.jsx +29 -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 +387 -0
- package/src/EngineeringPanel.jsx +151 -0
- package/src/FileTree.jsx +7 -0
- package/src/FinalChecklist.jsx +15 -0
- package/src/HelpNote.jsx +3 -0
- package/src/ImplementationDelivery.jsx +91 -0
- package/src/JourneyViews.jsx +403 -0
- package/src/LocationChoices.jsx +12 -0
- package/src/MemoryPanel.jsx +58 -0
- package/src/OpenAIVoicePanel.jsx +66 -0
- package/src/OutputsView.jsx +71 -0
- package/src/ProjectChecks.jsx +44 -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 +18 -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 +190 -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/final-package.mjs +34 -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 +106 -0
- package/src/journey.mjs +97 -0
- package/src/levels.mjs +145 -0
- package/src/local-agent.mjs +184 -0
- package/src/main.jsx +2481 -0
- package/src/model-policy-preflight.mjs +34 -0
- package/src/openai-voice.mjs +102 -0
- package/src/output-bundle.mjs +13 -0
- package/src/ownership-inspection.mjs +28 -0
- package/src/pack.mjs +201 -0
- package/src/pricing.mjs +85 -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 +37 -0
- package/src/useEmulation.jsx +36 -0
- package/src/useEngineeringStatus.mjs +17 -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,278 @@
|
|
|
1
|
+
import{v,r,l,UUID}from'./invoice-builder.mjs';
|
|
2
|
+
|
|
3
|
+
// IBM 2.9 supports JobDefinition, not a Terraform cron subscription resource.
|
|
4
|
+
// Keep job delivery separate from scheduling/alert acceptance under qualification.
|
|
5
|
+
export function ibmInvoiceOperations(b,n,{projectId,pull}){
|
|
6
|
+
const{add}=b;
|
|
7
|
+
b.variable.operations_enabled={type:'bool',default:false,description:'Create the three fixed SQL operating tasks after reviewed immutable image publication. Scheduling and alert acceptance are separate.'};
|
|
8
|
+
b.examples.operations_enabled=false;b.testExpressions.operations_enabled='true';
|
|
9
|
+
b.variable.maintenance_enabled={type:'bool',default:false,description:'Enable operating alerts after bootstrap; separately install the owned cron sources and verify successful runs before application release.'};b.examples.maintenance_enabled=false;b.testExpressions.maintenance_enabled='true';
|
|
10
|
+
const logs=b.input('operator_logs_instance_id','Existing reviewed same-region Cloud Logs instance receiving this region\'s Code Engine platform logs. Existing account routing is preserved.','88888888-8888-4888-8888-888888888888',UUID);
|
|
11
|
+
const webhook=b.input('operator_notification_integration_id','Existing verified Cloud Logs outgoing integration numeric ID; verify intended on-call recipients/delivery without exposing its endpoint or credentials.','12345','^[1-9][0-9]{0,9}$');
|
|
12
|
+
b.variable.operator_notification_integration_id.validation.condition='${can(regex("^[1-9][0-9]{0,9}$",var.operator_notification_integration_id)) && try(tonumber(var.operator_notification_integration_id),0) <= 4294967295}';
|
|
13
|
+
b.resource.terraform_data.review_gate.lifecycle.precondition.push({condition:'${!var.maintenance_enabled || var.operations_enabled}',error_message:'Operating alerts and schedules require fixed operator tasks.'},{condition:'${!var.applications_enabled || (var.operations_enabled && var.maintenance_enabled)}',error_message:'Initialize SQL and verify operating schedules, log routing and notifications before application release.'});
|
|
14
|
+
b.locals.operator_deployment=b.output.operator_deployment.value;
|
|
15
|
+
b.locals.operator_secret_name=l('name')+'-operator-sql';
|
|
16
|
+
const literal=(name,value)=>({name,value,type:'literal'});
|
|
17
|
+
const reference=(name,type,key,reference)=>({name,type,key,reference});
|
|
18
|
+
for(const action of ['initialize','maintain','monitor']){
|
|
19
|
+
const env=[literal('DATABASE_NAME','ibmclouddb'),literal('OPERATOR_DEPLOYMENT_BASE64','${base64encode(jsonencode(local.operator_deployment))}'),...Object.entries({DATABASE_HOST:'host',DATABASE_PORT:'port',DATABASE_CA_PEM:'ca_pem',DATABASE_USER:'operator_user'}).map(([name,key])=>reference(name,'config_map_key_reference',key,l('database_config_name'))),reference('DATABASE_PASSWORD','secret_key_reference','password',l('operator_secret_name'))];
|
|
20
|
+
// Bootstrap needs the two runtime passwords, never the worker's accounting token.
|
|
21
|
+
if(action==='initialize')for(const purpose of ['api','worker'])env.push(reference(purpose.toUpperCase()+'_DATABASE_PASSWORD','secret_key_reference','password',l(purpose==='api'?'api_secret_name':'worker_secret_name')));
|
|
22
|
+
add('ibm_code_engine_job',n+'_operator_'+action,{count:'${var.operations_enabled ? 1 : 0}',project_id:projectId,name:l('name')+'-'+action,image_reference:v('runtime_image'),image_secret:pull,run_commands:['python','-I','/app/invoice_operator_job.py'],run_arguments:[action,'--execute'],run_mode:'task',run_as_user:10001,run_service_account:'none',run_compute_resource_token_enabled:false,scale_array_spec:'0',scale_cpu_limit:'1',scale_memory_limit:'1G',scale_max_execution_time:960,scale_retry_limit:0,run_env_variables:env,depends_on:['ibm_database.'+n]});
|
|
23
|
+
}
|
|
24
|
+
const owned='app:"codeengine" AND codeengine.projectGuid:"'+projectId+'" AND codeengine.region:"'+b.region+'"';
|
|
25
|
+
const query=(action,status)=>owned+' AND codeengine.component:"'+l('name')+'-'+action+'" AND message:"invoice-operator-v1" AND message:"'+status+'"';
|
|
26
|
+
const failures=owned+' AND ('+['initialize','maintain','monitor'].map(action=>'codeengine.component:"'+l('name')+'-'+action+'"').join(' OR ')+') AND ((message:"invoice-operator-v1" AND (message:"failed" OR message:"attention" OR message:"backlog")) OR level:"error" OR level:"fatal")';
|
|
27
|
+
const definitions=[['failed',failures,'more_than_or_unspecified',0,'minutes_5_or_unspecified'],['monitor_missing',query('monitor','ok'),'less_than',1,'hours_2'],['maintenance_missing',query('maintain','ok'),'less_than',1,'hours_36']];
|
|
28
|
+
b.output.operator_log_queries={value:Object.fromEntries(definitions.map(([purpose,filter])=>[purpose,filter]))};
|
|
29
|
+
for(const[purpose,filter,condition,threshold,window]of definitions){
|
|
30
|
+
add('ibm_logs_alert_definition',n+'_'+purpose,{instance_id:logs,region:b.region,name:l('name')+'-'+purpose,description:'Owned SQL operator '+purpose+'. Verify native log samples, alert evaluation and existing on-call delivery before release; no customer invoice data in notifications.',enabled:v('maintenance_enabled'),phantom_mode:false,priority:'p2',type:'logs_threshold',logs_threshold:{condition_type:condition,evaluation_delay_ms:60000,notification_payload_filter:[],logs_filter:{simple_filter:{lucene_query:filter}},rules:[{condition:{threshold,time_window:{logs_time_window_specific_value:window}},override:{priority:'p2'}}],undetected_values_management:{auto_retire_timeframe:'never_or_unspecified',trigger_undetected_values:condition==='less_than'}},notification_group:{webhooks:[{minutes:1,notify_on:'triggered_and_resolved',integration:{integration_id:'${tonumber(var.operator_notification_integration_id)}'}}]},incidents_settings:{minutes:10,notify_on:'triggered_and_resolved'}});
|
|
31
|
+
b.files['monitoring/'+purpose+'.lucene']=filter+'\n';
|
|
32
|
+
}
|
|
33
|
+
b.output.operator_jobs={value:{account:v('account_id'),region:b.region,projectId,maintenanceEnabled:v('maintenance_enabled'),operatorSecret:l('operator_secret_name'),names:Object.fromEntries(['initialize','maintain','monitor'].map(action=>[action,l('name')+'-'+action]))}};
|
|
34
|
+
b.files['scripts/run-operator.py']=IBM_OPERATOR_RUNNER;
|
|
35
|
+
b.files['OPERATING_JOBS.md']=IBM_OPERATING_JOBS;
|
|
36
|
+
b.assertions.push(`run "operator_before_applications" {
|
|
37
|
+
command = plan
|
|
38
|
+
variables {
|
|
39
|
+
applications_enabled = false
|
|
40
|
+
maintenance_enabled = false
|
|
41
|
+
}
|
|
42
|
+
assert {
|
|
43
|
+
condition = length(ibm_code_engine_job.${n}_operator_initialize) == 1 && length(ibm_code_engine_app.${n}_api) == 0 && ibm_code_engine_job.${n}_operator_monitor[0].run_service_account == "none" && !ibm_code_engine_job.${n}_operator_monitor[0].run_compute_resource_token_enabled && ibm_code_engine_job.${n}_operator_monitor[0].scale_retry_limit == 0
|
|
44
|
+
error_message = "Bootstrap is separate, bounded and without application/cloud authority."
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
run "operator_mutable_image_rejected" {
|
|
48
|
+
command = plan
|
|
49
|
+
variables {
|
|
50
|
+
applications_enabled = false
|
|
51
|
+
runtime_image = "unreviewed:latest"
|
|
52
|
+
maintenance_enabled = false
|
|
53
|
+
}
|
|
54
|
+
expect_failures = [var.runtime_image]
|
|
55
|
+
}
|
|
56
|
+
run "operating_jobs_required" {
|
|
57
|
+
command = plan
|
|
58
|
+
variables {
|
|
59
|
+
operations_enabled = false
|
|
60
|
+
maintenance_enabled = false
|
|
61
|
+
}
|
|
62
|
+
expect_failures = [terraform_data.review_gate]
|
|
63
|
+
}
|
|
64
|
+
run "maintenance_without_jobs_rejected" {
|
|
65
|
+
command = plan
|
|
66
|
+
variables {
|
|
67
|
+
applications_enabled = false
|
|
68
|
+
operations_enabled = false
|
|
69
|
+
}
|
|
70
|
+
expect_failures = [terraform_data.review_gate]
|
|
71
|
+
}
|
|
72
|
+
run "notification_id_overflow_rejected" {
|
|
73
|
+
command = plan
|
|
74
|
+
variables { operator_notification_integration_id = "4294967296" }
|
|
75
|
+
expect_failures = [var.operator_notification_integration_id]
|
|
76
|
+
}
|
|
77
|
+
`);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const IBM_OPERATING_JOBS=`# IBM fixed invoice operating tasks
|
|
81
|
+
|
|
82
|
+
This package delivers initialize/maintain/monitor task definitions, an explicit
|
|
83
|
+
owned cron installer/observer, and Cloud Logs alert definitions. Local tests do not
|
|
84
|
+
prove real native execution, log routing, notification delivery or deployment.
|
|
85
|
+
|
|
86
|
+
Foundation uses applications_enabled=false, operations_enabled=false and
|
|
87
|
+
maintenance_enabled=false. Publish
|
|
88
|
+
the reviewed immutable runtime image into the owned registry only when authorized.
|
|
89
|
+
Set operations_enabled=true with applications still false to create fixed tasks.
|
|
90
|
+
Populate the separate operator SQL secret outside Terraform. databaseConfig also
|
|
91
|
+
needs operator_user: the exact administrative login for this new owned database.
|
|
92
|
+
Only initialize receives the separate API and worker SQL password keys. No task
|
|
93
|
+
receives the accounting token, parser token, model or object-store authority.
|
|
94
|
+
|
|
95
|
+
The destination operator installs/authenticates IBM Cloud CLI and its reviewed Code
|
|
96
|
+
Engine plugin in a dedicated private CLI home. For example, set IBMCLOUD_HOME to
|
|
97
|
+
this package's .local/ibm-operator-cli during login/plugin setup. Keep that directory
|
|
98
|
+
mode 0700 and outside source control. Never copy a user's global CLI credentials.
|
|
99
|
+
|
|
100
|
+
Preview: python3 scripts/run-operator.py initialize
|
|
101
|
+
Authorized execution adds --execute. The helper reads this package's Terraform
|
|
102
|
+
output, explicitly selects its account/region/project in the isolated CLI home,
|
|
103
|
+
then submits the fixed task with --wait. It supplies no image, environment, command
|
|
104
|
+
or service-account overrides. Job-launch permission is privileged; do not grant it
|
|
105
|
+
to the application, worker, model or public user. Retain the actual completed job
|
|
106
|
+
and initialized:true/monitor/maintenance receipt, not merely submit acceptance.
|
|
107
|
+
|
|
108
|
+
After bootstrap, run maintain and monitor once and inspect actual successful
|
|
109
|
+
receipts in the existing Cloud Logs destination. Verify that regional Code Engine
|
|
110
|
+
platform logging is routed to operator_logs_instance_id through the existing
|
|
111
|
+
account routing. Review its region/data custody and the existing outgoing
|
|
112
|
+
notification integration. Do not replace account log routing or expose credentials.
|
|
113
|
+
Read terraform output -json operator_log_queries for resolved queries; monitoring/
|
|
114
|
+
files are readable Terraform expression templates, not resolved instance selectors.
|
|
115
|
+
The Lucene filters use documented app/codeengine.projectGuid/region/component and
|
|
116
|
+
message/level fields, never deprecated label.Namespace/Project/Stream fields.
|
|
117
|
+
Verify the actual native samples match each emitted query before enabling alerts;
|
|
118
|
+
account parsing/routing can change message layout. Missing SQL monitor alerts after
|
|
119
|
+
two hours; missing daily maintenance after 36 hours. Undetected values trigger
|
|
120
|
+
missing-run alerts; native zero-sample evaluation/delivery still need acceptance.
|
|
121
|
+
Notifications exclude payload fields; no invoice/subject/amount is emitted by jobs.
|
|
122
|
+
|
|
123
|
+
Keep applications false, set maintenance_enabled=true, apply reviewed alerts, then
|
|
124
|
+
preview python3 scripts/run-operator.py install-schedules. With authorized --execute,
|
|
125
|
+
the helper uses supported Knative PingSource and IBM JobDefinition APIs in this
|
|
126
|
+
project's isolated KUBECONFIG. Only maintain (02:17 UTC daily) and monitor (hourly at
|
|
127
|
+
minute 7) are scheduled. Initialize is never scheduled. It refuses unrelated source
|
|
128
|
+
ownership and uses native resourceVersion to avoid overwriting concurrent changes.
|
|
129
|
+
Use check-schedules --execute to observe configuration and current Ready generation.
|
|
130
|
+
Ready means reconciled source configuration, not successful SQL work. Retain actual
|
|
131
|
+
successful scheduled task/log/alert delivery evidence before application release.
|
|
132
|
+
Cron sources are explicitly operated resources outside Terraform because IBM 2.9
|
|
133
|
+
has no cron subscription resource; do not hide account writes in a provisioner.
|
|
134
|
+
Before rollback, identify the two exact owned PingSource names/UIDs, verify their
|
|
135
|
+
owner references and remove only those sources with the authorized native operator;
|
|
136
|
+
do not delete the namespace/project. Disable alerts during an approved maintenance
|
|
137
|
+
window. Installed sources persist independently of the Terraform boolean: changing
|
|
138
|
+
maintenance_enabled=false does not pause or delete an installed source.
|
|
139
|
+
|
|
140
|
+
Each task uses one array index, no automatic retries and a 960-second platform
|
|
141
|
+
limit; the application enforces its own 900-second work deadline. Private SQL TLS,
|
|
142
|
+
actual native login privileges, task outcome, schedules and alert delivery still
|
|
143
|
+
need separately authorized destination checks. Provider schema/mocks are not
|
|
144
|
+
deployment, SQL runtime or scheduling evidence.
|
|
145
|
+
`;
|
|
146
|
+
|
|
147
|
+
const IBM_OPERATOR_RUNNER=`"""Preview or explicitly execute a fixed owned IBM Code Engine task."""
|
|
148
|
+
import argparse
|
|
149
|
+
from contextlib import contextmanager
|
|
150
|
+
import copy
|
|
151
|
+
import fcntl
|
|
152
|
+
import json
|
|
153
|
+
import os
|
|
154
|
+
from pathlib import Path
|
|
155
|
+
import re
|
|
156
|
+
import stat
|
|
157
|
+
import subprocess
|
|
158
|
+
|
|
159
|
+
ROOT=Path(__file__).resolve().parents[1]
|
|
160
|
+
|
|
161
|
+
def unique_object(pairs):
|
|
162
|
+
value={}
|
|
163
|
+
for key,child in pairs:
|
|
164
|
+
if key in value:raise ValueError('Duplicate operator output field')
|
|
165
|
+
value[key]=child
|
|
166
|
+
return value
|
|
167
|
+
|
|
168
|
+
def configuration():
|
|
169
|
+
result=subprocess.run(['terraform','output','-json','operator_jobs'],cwd=ROOT,check=True,capture_output=True,text=True,timeout=30)
|
|
170
|
+
value=json.loads(result.stdout,object_pairs_hook=unique_object)
|
|
171
|
+
if not isinstance(value,dict)or set(value)!={'account','region','projectId','maintenanceEnabled','operatorSecret','names'}or type(value['maintenanceEnabled'])is not bool:raise ValueError('Use the owned operator_jobs output')
|
|
172
|
+
if not re.fullmatch(r'[0-9a-f]{32}',value['account'])or not re.fullmatch(r'[a-z]{2}-[a-z]+',value['region'])or not re.fullmatch(r'[0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}',value['projectId']):raise ValueError('Invalid native destination')
|
|
173
|
+
names=value['names']
|
|
174
|
+
if not isinstance(names,dict)or set(names)!={'initialize','maintain','monitor'}:raise ValueError('Use all three fixed jobs')
|
|
175
|
+
prefix=None
|
|
176
|
+
for action,name in names.items():
|
|
177
|
+
if not isinstance(name,str)or not re.fullmatch(r'invoice-[0-9a-f]{12}-'+action,name):raise ValueError('Use a fixed owned task')
|
|
178
|
+
current=name.removesuffix('-'+action)
|
|
179
|
+
if prefix is not None and current!=prefix:raise ValueError('Mixed deployment jobs')
|
|
180
|
+
prefix=current
|
|
181
|
+
return value
|
|
182
|
+
|
|
183
|
+
def commands(value,action):
|
|
184
|
+
return [['ibmcloud','target','-c',value['account'],'-r',value['region']],['ibmcloud','ce','project','select','--id',value['projectId'],'--quiet'],['ibmcloud','ce','jobrun','submit','--job',value['names'][action],'--wait','--wait-timeout','1000']]
|
|
185
|
+
|
|
186
|
+
@contextmanager
|
|
187
|
+
def private_context():
|
|
188
|
+
home=ROOT/'.local/ibm-operator-cli'
|
|
189
|
+
# Pre-existing private CLI authentication is required; do not silently adopt
|
|
190
|
+
# global account context or follow a symlink to somebody else's CLI state.
|
|
191
|
+
metadata=home.lstat()
|
|
192
|
+
if not stat.S_ISDIR(metadata.st_mode)or metadata.st_uid!=os.geteuid()or metadata.st_mode&0o077:raise ValueError('Authenticate in the owned mode-0700 CLI directory first')
|
|
193
|
+
lock=os.open(home/'operator.lock',os.O_CREAT|os.O_RDWR|os.O_NOFOLLOW,0o600)
|
|
194
|
+
with os.fdopen(lock,'w')as stream:
|
|
195
|
+
metadata=os.fstat(stream.fileno())
|
|
196
|
+
if not stat.S_ISREG(metadata.st_mode)or metadata.st_uid!=os.geteuid()or metadata.st_mode&0o077:raise ValueError('Use a private owned operation lock')
|
|
197
|
+
fcntl.flock(stream,fcntl.LOCK_EX|fcntl.LOCK_NB)
|
|
198
|
+
kube=home/'operator-kubeconfig'
|
|
199
|
+
if kube.exists()or kube.is_symlink():
|
|
200
|
+
metadata=kube.lstat()
|
|
201
|
+
if not stat.S_ISREG(metadata.st_mode)or metadata.st_uid!=os.geteuid()or metadata.st_mode&0o077:raise ValueError('Use a private owned kubeconfig')
|
|
202
|
+
env={**os.environ,'IBMCLOUD_HOME':str(home),'IBMCLOUD_TRACE':'false','KUBECONFIG':str(kube)}
|
|
203
|
+
previous=os.umask(0o077)
|
|
204
|
+
try:yield env
|
|
205
|
+
finally:os.umask(previous)
|
|
206
|
+
|
|
207
|
+
def kubectl(env,arguments,body=None):
|
|
208
|
+
result=subprocess.run(['kubectl',*arguments],cwd=ROOT,env=env,check=True,capture_output=True,text=True,input=json.dumps(body)if body is not None else None,timeout=150)
|
|
209
|
+
if len(result.stdout)>1000000:raise ValueError('Unexpected native resource response')
|
|
210
|
+
return result.stdout.strip()
|
|
211
|
+
|
|
212
|
+
def get_resource(env,kind,name,namespace,optional=False):
|
|
213
|
+
raw=kubectl(env,['get',kind,name,'--namespace',namespace,'-o','json',*(['--ignore-not-found']if optional else[])])
|
|
214
|
+
if optional and not raw:return None
|
|
215
|
+
return json.loads(raw,object_pairs_hook=unique_object)
|
|
216
|
+
|
|
217
|
+
def ownership(value,job,namespace,prefix,name):
|
|
218
|
+
metadata=value.get('metadata',{});references=metadata.get('ownerReferences',[])
|
|
219
|
+
expected={'apiVersion':'codeengine.cloud.ibm.com/v1beta1','kind':'JobDefinition','name':job['metadata']['name'],'uid':job['metadata']['uid'],'controller':False,'blockOwnerDeletion':False}
|
|
220
|
+
if value.get('apiVersion')!='sources.knative.dev/v1'or value.get('kind')!='PingSource'or metadata.get('namespace')!=namespace or metadata.get('name')!=name or metadata.get('labels',{}).get('atmem.ai/operator-package')!=prefix or expected not in references:raise ValueError('Refuse unrelated cron source ownership')
|
|
221
|
+
if len(references)!=1 or not metadata.get('uid')or not metadata.get('resourceVersion'):raise ValueError('Ambiguous cron source identity')
|
|
222
|
+
|
|
223
|
+
def schedule_spec(job,action):
|
|
224
|
+
return {'schedule':'17 2 * * *'if action=='maintain'else'7 * * * *','timezone':'UTC','contentType':'application/json','data':'{}','sink':{'ref':{'apiVersion':'codeengine.cloud.ibm.com/v1beta1','kind':'JobDefinition','name':job['metadata']['name']}}}
|
|
225
|
+
|
|
226
|
+
def verify_ready(value,expected):
|
|
227
|
+
spec=value.get('spec',{})
|
|
228
|
+
if any(spec.get(key)!=child for key,child in expected.items()):raise ValueError('Cron configuration differs from the owned task contract')
|
|
229
|
+
status=value.get('status',{});generation=value['metadata'].get('generation')
|
|
230
|
+
if type(generation)is not int or status.get('observedGeneration')!=generation or not any(c.get('type')=='Ready'and c.get('status')=='True'for c in status.get('conditions',[])):raise ValueError('Cron source has not reconciled this generation')
|
|
231
|
+
|
|
232
|
+
def schedules(value,env,install):
|
|
233
|
+
if install and not value['maintenanceEnabled']:raise ValueError('Enable reviewed operating alerts before installing schedules')
|
|
234
|
+
target=commands(value,'monitor')[:2];target[1]=[*target[1],'--kubecfg']
|
|
235
|
+
for command in target:subprocess.run(command,cwd=ROOT,env=env,check=True,timeout=120)
|
|
236
|
+
namespace=kubectl(env,['config','view','--minify','-o','jsonpath={.contexts[0].context.namespace}'])
|
|
237
|
+
if not re.fullmatch(r'[a-z0-9][a-z0-9-]{0,62}',namespace):raise ValueError('Use the selected native project namespace')
|
|
238
|
+
prefix=value['names']['monitor'].removesuffix('-monitor');result=[]
|
|
239
|
+
# Observe both targets and ownership boundaries before making either write.
|
|
240
|
+
pending=[]
|
|
241
|
+
for action in ['maintain','monitor']:
|
|
242
|
+
job=get_resource(env,'jobdefinitions.codeengine.cloud.ibm.com',value['names'][action],namespace)
|
|
243
|
+
metadata=job.get('metadata',{})
|
|
244
|
+
if job.get('apiVersion')!='codeengine.cloud.ibm.com/v1beta1'or job.get('kind')!='JobDefinition'or metadata.get('name')!=value['names'][action]or metadata.get('namespace')!=namespace or not metadata.get('uid'):raise ValueError('Use the actual owned IBM JobDefinition')
|
|
245
|
+
name=value['names'][action]+'-timer';current=get_resource(env,'pingsources.sources.knative.dev',name,namespace,optional=True)
|
|
246
|
+
if current is not None:ownership(current,job,namespace,prefix,name)
|
|
247
|
+
pending.append((action,job,name,current))
|
|
248
|
+
for action,job,name,current in pending:
|
|
249
|
+
spec=schedule_spec(job,action)
|
|
250
|
+
if install:
|
|
251
|
+
if current is None:
|
|
252
|
+
document={'apiVersion':'sources.knative.dev/v1','kind':'PingSource','metadata':{'name':name,'namespace':namespace,'labels':{'atmem.ai/operator-package':prefix},'ownerReferences':[{'apiVersion':'codeengine.cloud.ibm.com/v1beta1','kind':'JobDefinition','name':job['metadata']['name'],'uid':job['metadata']['uid'],'controller':False,'blockOwnerDeletion':False}]},'spec':spec}
|
|
253
|
+
kubectl(env,['create','-f','-','-o','json'],document)
|
|
254
|
+
elif any(current.get('spec',{}).get(key)!=child for key,child in spec.items()):
|
|
255
|
+
# Retain existing metadata/UID and resourceVersion. Native API
|
|
256
|
+
# conflicts fail; never --force, adopt or retry an overwrite.
|
|
257
|
+
document=copy.deepcopy(current);document.pop('status',None);document['spec']=spec
|
|
258
|
+
kubectl(env,['replace','-f','-','-o','json'],document)
|
|
259
|
+
kubectl(env,['wait','--for=condition=Ready','pingsources.sources.knative.dev/'+name,'--namespace',namespace,'--timeout=120s'])
|
|
260
|
+
actual=get_resource(env,'pingsources.sources.knative.dev',name,namespace)
|
|
261
|
+
ownership(actual,job,namespace,prefix,name);verify_ready(actual,spec)
|
|
262
|
+
result.append({'action':action,'name':name,'uid':actual['metadata']['uid'],'generation':actual['metadata']['generation'],'ready':True})
|
|
263
|
+
print(json.dumps({'format':'invoice-ibm-schedules-v1','sources':result,'jobExecutionValidated':False}))
|
|
264
|
+
|
|
265
|
+
def main():
|
|
266
|
+
parser=argparse.ArgumentParser(description=__doc__)
|
|
267
|
+
parser.add_argument('action',choices=['initialize','maintain','monitor','install-schedules','check-schedules']);parser.add_argument('--execute',action='store_true');args=parser.parse_args()
|
|
268
|
+
value=configuration();scheduling=args.action in {'install-schedules','check-schedules'}
|
|
269
|
+
if not args.execute:
|
|
270
|
+
plan=commands(value,'monitor')[:2]if scheduling else commands(value,args.action)
|
|
271
|
+
print(json.dumps({'execute':False,'commands':plan,'cloudOperations':False,'schedules':{action:{'job':value['names'][action],'cron':'17 2 * * *'if action=='maintain'else'7 * * * *','timezone':'UTC'}for action in ['maintain','monitor']}if scheduling else None}));return
|
|
272
|
+
with private_context()as env:
|
|
273
|
+
if scheduling:schedules(value,env,args.action=='install-schedules')
|
|
274
|
+
else:
|
|
275
|
+
for index,command in enumerate(commands(value,args.action)):subprocess.run(command,cwd=ROOT,env=env,check=True,timeout=1100 if index==2 else 120)
|
|
276
|
+
|
|
277
|
+
if __name__=='__main__':main()
|
|
278
|
+
`;
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import {invoiceBuilder,v,r,l,UUID}from'./invoice-builder.mjs';
|
|
2
|
+
import {ibmRegistryHostExpression,ibmRegistryRegionValidation}from'./ibm-registry.mjs';
|
|
3
|
+
import {ibmInvoiceOperations}from'./invoice-ibm-operations.mjs';
|
|
4
|
+
import providerLock from'./runtime/invoice-ibm-provider-lock.json'with{type:'json'};
|
|
5
|
+
|
|
6
|
+
// Native composition under qualification; no cloud operation is performed here.
|
|
7
|
+
export function ibmInvoiceTerraform(project,row,environment='staging'){
|
|
8
|
+
if(row.provider!=='ibm')throw Error('IBM invoice compilation cannot substitute another cloud');
|
|
9
|
+
const b=invoiceBuilder(project,row,environment),{input,add,region}=b,n=row.address;
|
|
10
|
+
const account=input('account_id','Expected existing IBM Cloud account. No account is created.','a'.repeat(32),'^[0-9a-f]{32}$');
|
|
11
|
+
const group=input('resource_group_name','Existing reviewed destination resource group; never recreated.','reviewed-applications','^[A-Za-z0-9 _.-]{1,128}$');
|
|
12
|
+
const model=input('model_id','Reviewed regional watsonx JSON-object model; verify lifecycle, regional availability and processing terms.','ibm/reviewed-model','^[a-z0-9][a-z0-9_.-]{0,79}/[a-z0-9][a-z0-9_.-]{0,99}$');
|
|
13
|
+
const wxProject=input('watsonx_project_id','Existing watsonx project; authorize only the worker trusted profile and associate its runtime instance.','22222222-2222-2222-2222-222222222222',UUID);
|
|
14
|
+
const instance=input('runtime_instance_id','Existing associated watsonx.ai Runtime instance GUID, not a deployment ID.','33333333-3333-3333-3333-333333333333',UUID);
|
|
15
|
+
const endpoint=input('accounting_endpoint','Existing reviewed accounting HTTPS adapter; never provision a replacement.','https://accounting.example.test/actions','^https://[A-Za-z0-9.-]+(:[0-9]{1,5})?(/[^?#@ ]*)?$');
|
|
16
|
+
const scope=input('accounting_scope','Reviewed accounting scope bound to each approval.','owned-team','^[A-Za-z0-9_.:/-]{1,200}$');
|
|
17
|
+
const pull=input('registry_pull_secret','Name of the separately populated registry-pull secret in the new owned Code Engine project. No credential in Terraform.','registry-pull','^[a-z][a-z0-9-]{1,61}[a-z0-9]$');
|
|
18
|
+
if(!row.region)b.variable.region.validation=ibmRegistryRegionValidation();
|
|
19
|
+
for(const purpose of ['runtime','parser']){
|
|
20
|
+
input(purpose+'_image','Reviewed immutable image in this package-owned regional registry namespace. Empty during foundation.','au.icr.io/reviewed-namespace/'+purpose+'@sha256:'+'a'.repeat(64));b.variable[purpose+'_image'].default='';
|
|
21
|
+
b.variable[purpose+'_image'].validation={condition:'${!(var.applications_enabled'+(purpose==='runtime'?' || var.operations_enabled':'')+') || can(regex("@sha256:[0-9a-f]{64}$",var.'+purpose+'_image))}',error_message:'Use the reviewed immutable image digest before releasing applications.'};
|
|
22
|
+
b.resource.terraform_data.review_gate.lifecycle.precondition.push({condition:'${!(var.applications_enabled'+(purpose==='runtime'?' || var.operations_enabled':'')+') || startswith(var.'+purpose+'_image,format("%s/%s/'+purpose+'@sha256:",'+ibmRegistryHostExpression().slice(2,-1)+',local.name))}',error_message:'Images must use the exact owned regional registry namespace, not an invented hostname or foreign repository.'});
|
|
23
|
+
b.testExpressions[purpose+'_image']='format("au.icr.io/invoice-%s/'+purpose+'@sha256:'+'a'.repeat(64)+'",substr(sha256('+JSON.stringify(b.seed)+'),0,12))';
|
|
24
|
+
}
|
|
25
|
+
b.variable.staff_subjects={type:'set(string)',default:[],description:'Explicit existing admin-enrolled App ID subjects. Application membership/reviewer grants are separately admitted in SQL.',validation:{condition:'${alltrue([for subject in var.staff_subjects : can(regex("^[A-Za-z0-9_.:@-]{1,200}$",subject))])}',error_message:'Use exact verified staff subjects, never public signup or display-name guesses.'}};b.examples.staff_subjects=['44444444-4444-4444-4444-444444444444'];
|
|
26
|
+
b.variable.policy_review_base64={type:'string',default:'',description:'Scoped expiring model privacy/processing-terms review. Empty blocks inference; no approval is fabricated.'};b.examples.policy_review_base64='';
|
|
27
|
+
b.variable.replay_review_base64={type:'string',default:'',description:'Scoped expiring acceptance of actual accounting idempotency. Empty disables automatic uncertain replay.'};b.examples.replay_review_base64='';
|
|
28
|
+
b.data.ibm_resource_group={destination:{name:group}};
|
|
29
|
+
b.resource.terraform_data.review_gate.lifecycle.precondition.push({condition:'${data.ibm_resource_group.destination.account_id == var.account_id && (!var.applications_enabled || length(var.staff_subjects)>0)}',error_message:'Verify the destination account and explicit staff admission before release.'});
|
|
30
|
+
const rg=r('data.ibm_resource_group','destination','id'),projectId=r('ibm_code_engine_project',n,'project_id');
|
|
31
|
+
Object.assign(b.locals,{destination_contract:{id:'normalized-action-v1',endpointSha256:'${sha256(var.accounting_endpoint)}',scope,mappingVersion:1},destination_contract_base64:'${base64encode(jsonencode(local.destination_contract))}',database_config_name:l('name')+'-database',parser_secret_name:l('name')+'-parser',api_secret_name:l('name')+'-api-sql',worker_secret_name:l('name')+'-worker',bucket_name:'${format("%s-%s",local.name,substr(var.account_id,0,8))}'});
|
|
32
|
+
add('ibm_code_engine_project',n,{name:l('name'),resource_group_id:rg,lifecycle:{prevent_destroy:true}});
|
|
33
|
+
add('ibm_cr_namespace',n,{name:l('name'),resource_group_id:rg,lifecycle:{prevent_destroy:true}});
|
|
34
|
+
// Use the maintained Classic private-service endpoint contract, not an assumed
|
|
35
|
+
// direct Code Engine -> VPC/Gen2 route. There is no public SQL fallback.
|
|
36
|
+
add('ibm_database',n,{name:l('name'),service:'databases-for-postgresql',plan:'standard',location:region,resource_group_id:rg,version:'18',service_endpoints:'private',deletion_protection:true,group:{group_id:'member',memory:{allocation_mb:2048},disk:{allocation_mb:20480},members:{allocation_count:2}},configuration:JSON.stringify({log_statement:'none',log_min_error_statement:'panic',log_parameter_max_length_on_error:0}),lifecycle:{prevent_destroy:true}});
|
|
37
|
+
add('ibm_resource_instance',n+'_documents',{name:l('name')+'-documents',service:'cloud-object-storage',plan:'standard',location:'global',resource_group_id:rg,lifecycle:{prevent_destroy:true}});
|
|
38
|
+
add('ibm_cos_bucket',n,{bucket_name:l('bucket_name'),resource_instance_id:r('ibm_resource_instance',n+'_documents','id'),region_location:region,storage_class:'standard',endpoint_type:'public',force_delete:false,object_versioning:{enable:true},lifecycle:{prevent_destroy:true}});
|
|
39
|
+
add('ibm_cos_bucket_lifecycle_configuration',n,{bucket_crn:r('ibm_cos_bucket',n,'crn'),bucket_location:region,endpoint_type:'public',lifecycle_rule:[{rule_id:'invoice-originals-90-days',status:'enable',filter:{prefix:'accounts/'},expiration:{days:90},noncurrent_version_expiration:{noncurrent_days:1}},{rule_id:'unfinished-upload-cleanup',status:'enable',filter:{prefix:'accounts/'},abort_incomplete_multipart_upload:{days_after_initiation:1}}]});
|
|
40
|
+
for(const purpose of ['api','worker']){
|
|
41
|
+
add('ibm_iam_trusted_profile',n+'_'+purpose,{name:l('name')+'-'+purpose,description:'Dedicated invoice '+purpose+'; SQL login and business membership are independent.'});
|
|
42
|
+
add('ibm_iam_trusted_profile_link',n+'_'+purpose,{count:'${var.applications_enabled ? 1 : 0}',profile_id:r('ibm_iam_trusted_profile',n+'_'+purpose,'profile_id'),cr_type:'CE',link:{crn:r('ibm_code_engine_project',n,'crn'),component_name:l('name')+'-'+purpose,component_type:'app'},depends_on:['ibm_code_engine_app.'+n+'_'+purpose]});
|
|
43
|
+
add('ibm_iam_trusted_profile_policy',n+'_'+purpose+'_documents',{iam_id:r('ibm_iam_trusted_profile',n+'_'+purpose,'iam_id'),roles:purpose==='api'?['Object Reader','Object Writer']:['Object Reader'],resources:{service:'cloud-object-storage',resource_instance_id:r('ibm_resource_instance',n+'_documents','guid'),resource_type:'bucket',resource:l('bucket_name')}});
|
|
44
|
+
}
|
|
45
|
+
add('ibm_iam_trusted_profile_policy',n+'_model',{iam_id:r('ibm_iam_trusted_profile',n+'_worker','iam_id'),roles:['Writer'],resources:{service:'pm-20',resource_instance_id:instance,region},description:'Instance-scoped native watsonx role. Writer is broader than prediction-only; separate project collaborator admission remains required.'});
|
|
46
|
+
add('ibm_resource_instance',n+'_identity',{name:l('name')+'-staff',service:'appid',plan:'graduated-tier',location:region,resource_group_id:rg,lifecycle:{prevent_destroy:true}});
|
|
47
|
+
const tenant=r('ibm_resource_instance',n+'_identity','guid'),client=r('ibm_appid_application',n,'client_id');
|
|
48
|
+
add('ibm_appid_application',n,{tenant_id:tenant,name:l('name'),type:'singlepageapp'});
|
|
49
|
+
add('ibm_appid_application_scopes',n,{tenant_id:tenant,client_id:client,scopes:['process']});
|
|
50
|
+
add('ibm_appid_role',n,{tenant_id:tenant,name:'InvoiceStaff',access:[{application_id:client,scopes:['process']}],depends_on:['ibm_appid_application_scopes.'+n]});
|
|
51
|
+
add('ibm_appid_user_roles',n,{for_each:'${var.applications_enabled ? var.staff_subjects : toset([])}',tenant_id:tenant,subject:'${each.value}',role_ids:[r('ibm_appid_role',n,'role_id')]});
|
|
52
|
+
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']});
|
|
53
|
+
for(const idp of ['google','facebook','saml'])add('ibm_appid_idp_'+idp,n,{tenant_id:tenant,is_active:false});
|
|
54
|
+
const literal=(name,value)=>({name,value,type:'literal'}),reference=(name,type,key,ref)=>({name,type,key,reference:ref});
|
|
55
|
+
const common={ACCOUNT_ID:l('account_uuid'),REGION:region,WORKFLOW_NAMESPACE:'invoice',DATABASE_NAME:'ibmclouddb',DOCUMENT_BUCKET:l('bucket_name'),DESTINATION_CONTRACT_BASE64:l('destination_contract_base64')};
|
|
56
|
+
for(const purpose of ['api','worker','parser']){
|
|
57
|
+
const settings=purpose==='parser'?{PARSER_AUTH_MODE:'shared-token'}:purpose==='api'?{...common,SERVICE_NAME:l('name')+'-api',PUBLIC_ORIGIN_MODE:'code-engine-default',DATABASE_USER:l('api_db_user'),IAM_PROFILE_ID:r('ibm_iam_trusted_profile',n+'_api','profile_id'),APPID_TENANT_ID:tenant,APPID_CLIENT_ID:client,APPID_ISSUER:r('ibm_appid_application',n,'oauth_server_url'),AUTH_SCOPE:l('name')+'/process'}:{...common,DATABASE_USER:l('worker_db_user'),IAM_PROFILE_ID:r('ibm_iam_trusted_profile',n+'_worker','profile_id'),IBM_ACCOUNT_ID:account,WATSONX_PROJECT_ID:wxProject,RUNTIME_INSTANCE_ID:instance,MODEL_REGION:region,MODEL_ID:model,MAX_OUTPUT_TOKENS:'2048',POLICY_REVIEW_BASE64:v('policy_review_base64'),PARSER_ENDPOINT:r('ibm_code_engine_app',n+'_parser[0]','endpoint')+'/extract',DESTINATION_ENDPOINT:endpoint,DESTINATION_SCOPE:scope,DESTINATION_REPLAY_REVIEW_BASE64:v('replay_review_base64')};
|
|
58
|
+
const env=Object.entries(settings).map(([name,value])=>literal(name,value));
|
|
59
|
+
if(purpose!=='parser')env.push(...[['DATABASE_HOST','host'],['DATABASE_PORT','port'],['DATABASE_CA_PEM','ca_pem']].map(([name,key])=>reference(name,'config_map_key_reference',key,l('database_config_name'))),reference('DATABASE_PASSWORD','secret_key_reference','password',l(purpose==='api'?'api_secret_name':'worker_secret_name')));
|
|
60
|
+
if(purpose==='worker')env.push(reference('DESTINATION_TOKEN','secret_key_reference','accounting_token',l('worker_secret_name')));
|
|
61
|
+
if(purpose!=='api')env.push(reference('PARSER_SHARED_TOKEN','secret_key_reference','token',l('parser_secret_name')));
|
|
62
|
+
add('ibm_code_engine_app',n+'_'+purpose,{count:'${var.applications_enabled ? 1 : 0}',project_id:projectId,name:l('name')+'-'+purpose,image_reference:v(purpose==='parser'?'parser_image':'runtime_image'),image_secret:pull,image_port:8080,managed_domain_mappings:purpose==='api'?'local_public':purpose==='parser'?'local_private':'local',run_as_user:10001,run_service_account:'none',run_compute_resource_token_enabled:purpose!=='parser',scale_cpu_limit:'1',scale_memory_limit:purpose==='parser'?'2G':'1G',scale_min_instances:1,scale_max_instances:1,scale_concurrency:purpose==='api'?32:1,scale_concurrency_target:purpose==='api'?16:1,scale_request_timeout:purpose==='parser'?150:300,run_env_variables:env,...(purpose==='api'?{}:{run_commands:['python','-I','/app/'+(purpose==='worker'?'invoice_worker.py':'invoice_parser_service.py')]}),probe_readiness:{type:'http',path:'/healthz',port:8080,initial_delay:2,interval:5,timeout:2,failure_threshold:12},depends_on:purpose==='parser'?[]:['ibm_iam_trusted_profile_policy.'+n+'_'+purpose+'_documents',...(purpose==='worker'?['ibm_iam_trusted_profile_policy.'+n+'_model']:[])]});
|
|
63
|
+
}
|
|
64
|
+
add('ibm_appid_redirect_urls',n,{count:'${var.applications_enabled ? 1 : 0}',tenant_id:tenant,urls:[r('ibm_code_engine_app',n+'_api[0]','endpoint')+'/']});
|
|
65
|
+
b.output.application_url={value:'${var.applications_enabled ? ibm_code_engine_app.'+n+'_api[0].endpoint : null}'};
|
|
66
|
+
b.output.code_engine_project={value:projectId};b.output.registry={value:ibmRegistryHostExpression()+'/'+l('name')};
|
|
67
|
+
b.output.operator_deployment={value:{provider:'ibm',deploymentId:l('account_uuid'),accountId:l('account_uuid'),namespace:'invoice',tenantId:null,bindings:Object.fromEntries(['api','worker'].map(purpose=>[purpose,{name:l(purpose+'_db_user'),principal:'${uuidv5("url",'+JSON.stringify(b.seed+'/'+purpose+'-sql-credential')+')}'}]))}};
|
|
68
|
+
b.output.database_bootstrap={value:{deploymentCrn:r('ibm_database',n,'id'),database:'ibmclouddb',projectId,databaseConfig:l('database_config_name'),apiSecret:l('api_secret_name'),workerSecret:l('worker_secret_name'),parserSecret:l('parser_secret_name'),registryPullSecret:pull}};
|
|
69
|
+
ibmInvoiceOperations(b,n,{projectId,pull});
|
|
70
|
+
b.files['CODE_ENGINE_INPUTS.md']=IBM_INPUTS;
|
|
71
|
+
b.assertions.push(`run "private_database_and_parser" {\n command = plan\n assert {\n condition = ibm_database.${n}.service_endpoints == "private" && ibm_database.${n}.version == "18" && ibm_database.${n}.deletion_protection\n error_message = "Retain private native PostgreSQL and recovery protection."\n }\n assert {\n condition = ibm_code_engine_app.${n}_parser[0].managed_domain_mappings == "local_private" && !ibm_code_engine_app.${n}_parser[0].run_compute_resource_token_enabled && ibm_code_engine_app.${n}_parser[0].run_service_account == "none"\n error_message = "Untrusted PDF parser has private TLS and no cloud compute/API identity."\n }\n assert {\n condition = startswith(ibm_code_engine_app.${n}_api[0].image_reference,"au.icr.io/") && ibm_code_engine_app.${n}_worker[0].scale_min_instances == 1\n error_message = "Use the actual Sydney registry hostname and retain the background worker."\n }\n}\nrun "foundation_only" {\n command = plan\n variables {\n applications_enabled = false\n operations_enabled = false\n maintenance_enabled = false\n }\n assert {\n condition = length(ibm_code_engine_app.${n}_api) == 0 && length(ibm_code_engine_app.${n}_worker) == 0 && length(ibm_code_engine_app.${n}_parser) == 0 && length(ibm_code_engine_job.${n}_operator_initialize) == 0\n error_message = "Bootstrap and publication precede application release."\n }\n}\nrun "mutable_image_rejected" {\n command = plan\n variables { runtime_image = "unreviewed:latest" }\n expect_failures = [var.runtime_image]\n}\nrun "foreign_registry_rejected" {\n command = plan\n variables { runtime_image = "foreign.test/runtime@sha256:${'a'.repeat(64)}" }\n expect_failures = [terraform_data.review_gate]\n}\nrun "empty_staff_rejected" {\n command = plan\n variables { staff_subjects = [] }\n expect_failures = [terraform_data.review_gate]\n}\nrun "wrong_account_rejected" {\n command = plan\n variables { account_id = "${'c'.repeat(32)}" }\n expect_failures = [terraform_data.review_gate]\n}`);
|
|
72
|
+
let mock='mock_provider "ibm" {\n override_during = plan\n mock_data "ibm_resource_group" { defaults = { id="'+ 'b'.repeat(32)+'",account_id="'+'a'.repeat(32)+'" } }\n mock_resource "ibm_code_engine_project" { defaults = { project_id="11111111-1111-4111-8111-111111111111",crn="crn:v1:bluemix:public:codeengine:au-syd:a/'+ 'a'.repeat(32)+':11111111-1111-4111-8111-111111111111::" } }\n mock_resource "ibm_resource_instance" { defaults = { guid="55555555-5555-4555-8555-555555555555",id="crn:v1:bluemix:public:cloud-object-storage:global:a/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:55555555-5555-4555-8555-555555555555::" } }\n mock_resource "ibm_iam_trusted_profile" { defaults = { profile_id="Profile-66666666-6666-4666-8666-666666666666",iam_id="iam-Profile-66666666-6666-4666-8666-666666666666" } }\n mock_resource "ibm_appid_application" { defaults = { client_id="77777777-7777-4777-8777-777777777777",oauth_server_url="https://au-syd.appid.cloud.ibm.com/oauth/v4/55555555-5555-4555-8555-555555555555" } }\n}\n';
|
|
73
|
+
mock+='override_resource {\n override_during = plan\n target = ibm_cos_bucket.'+n+'\n values = { crn = "crn:v1:bluemix:public:cloud-object-storage:global:a/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:55555555-5555-4555-8555-555555555555:bucket:fixture-invoices" }\n}\n';
|
|
74
|
+
for(const [purpose,digit]of [['api','6'],['worker','8']])mock+='override_resource {\n override_during = plan\n target = ibm_iam_trusted_profile.'+n+'_'+purpose+'\n values = '+JSON.stringify({profile_id:'Profile-'+digit.repeat(8)+'-'+digit.repeat(4)+'-4'+digit.repeat(3)+'-8'+digit.repeat(3)+'-'+digit.repeat(12),iam_id:'iam-Profile-'+digit.repeat(8)+'-'+digit.repeat(4)+'-4'+digit.repeat(3)+'-8'+digit.repeat(3)+'-'+digit.repeat(12)})+'\n}\n';
|
|
75
|
+
for(const purpose of ['api','parser'])mock+='override_resource {\n override_during = plan\n target = ibm_code_engine_app.'+n+'_'+purpose+'[0]\n values = { endpoint = format("https://invoice-%s-'+purpose+'.project-fixture.'+(purpose==='parser'?'private.':'')+'au-syd.codeengine.appdomain.cloud",substr(sha256('+JSON.stringify(b.seed)+'),0,12)) }\n}\n';
|
|
76
|
+
return b.finish({ibm:{region}},{ibm:{source:'IBM-Cloud/ibm',version:providerLock.version}},providerLock.lock,mock,IBM_GUIDE);
|
|
77
|
+
}
|
|
78
|
+
const IBM_GUIDE=`# IBM invoice workflow (under qualification)
|
|
79
|
+
|
|
80
|
+
A new owned Code Engine project hosts the public App ID/PKCE staff API, a minimum-one
|
|
81
|
+
background queue worker and a separate private-TLS parser. Only worker/parser hold
|
|
82
|
+
the parser-only 256-bit admission token; it grants no cloud/document/SQL/action
|
|
83
|
+
permission. The parser has neither a compute resource token nor Code Engine API
|
|
84
|
+
service-account authority. API and worker use separate native trusted profiles,
|
|
85
|
+
SQL logins and secret references. Staff authentication is separate from live SQL
|
|
86
|
+
membership and reviewer authority; public self-registration is disabled.
|
|
87
|
+
|
|
88
|
+
The dedicated PostgreSQL 18 Classic instance uses private IBM service endpoints;
|
|
89
|
+
no unimplemented direct VPC/Gen2 route or public SQL fallback is asserted. Exact
|
|
90
|
+
regional service availability, private connectivity, CA verification and inherited
|
|
91
|
+
permissions require authorized destination checks. Documents are private, versioned
|
|
92
|
+
and stored regionally with a 90-day current / one-day noncurrent lifecycle. The
|
|
93
|
+
regional S3 API uses authenticated TLS. Cloud control-plane/log/backup behavior and
|
|
94
|
+
account policy need separate review; no exact erasure deadline is promised.
|
|
95
|
+
|
|
96
|
+
Sydney Container Registry uses au.icr.io, not au-syd.icr.io. The namespace is owned
|
|
97
|
+
by this package. Foundation creates resources with applications_enabled=false.
|
|
98
|
+
CODE_ENGINE_INPUTS.md specifies separately populated config/secret references.
|
|
99
|
+
Publish immutable reviewed images only when authorized, initialize SQL and staff
|
|
100
|
+
membership through the separate operator, then review application release. The
|
|
101
|
+
worker's instance-scoped watsonx Writer role is broader than prediction-only;
|
|
102
|
+
separate project collaborator admission and the scoped model policy review remain
|
|
103
|
+
required. An empty policy review blocks inference and never fabricates approval.
|
|
104
|
+
|
|
105
|
+
Native schemas/mocks and local images do not prove the real account, IBM private
|
|
106
|
+
network, model processing, restore or deployment. Full managed operator/scheduled
|
|
107
|
+
retention delivery, monitoring, state strategy, registry/Spec Kit admission and the
|
|
108
|
+
complete conversation/export checks remain qualification work. No cloud operation
|
|
109
|
+
is performed by generating this package. Preserve the external accounting system.
|
|
110
|
+
`;
|
|
111
|
+
const IBM_INPUTS=`# Code Engine foundation inputs and ownership
|
|
112
|
+
|
|
113
|
+
Use the database_bootstrap and operator_deployment outputs, not guessed identifiers.
|
|
114
|
+
The new database's built-in application database is ibmclouddb; the separate operator
|
|
115
|
+
owns the new workflow schema. Application SQL passwords are distinct strong random
|
|
116
|
+
values created outside Terraform. Native trusted profiles authorize COS/model
|
|
117
|
+
access, not database login: operator bindings use stable owned credential UUIDs,
|
|
118
|
+
not a false claim of native IAM-to-SQL authentication.
|
|
119
|
+
|
|
120
|
+
In the new Code Engine project, an authorized operator creates these references
|
|
121
|
+
from private mode-0600 inputs, without placing secret values in Terraform/state:
|
|
122
|
+
- registry_pull_secret: native registry configuration, private namespace pull only.
|
|
123
|
+
- databaseConfig config map: exact private host, port, native PEM ca_pem and operator_user.
|
|
124
|
+
- operator_jobs.operatorSecret: separate operator SQL password; only operating tasks.
|
|
125
|
+
- apiSecret generic secret: password for the generated API SQL login only.
|
|
126
|
+
- workerSecret generic secret: worker SQL password and existing accounting_token.
|
|
127
|
+
- parserSecret generic secret: token, exactly 64 lowercase hexadecimal characters
|
|
128
|
+
from 32 cryptographically random bytes; only worker and parser reference it.
|
|
129
|
+
|
|
130
|
+
Read native connection/CA metadata for this exact database deployment. Never use a
|
|
131
|
+
public hostname or weaken TLS verification to bypass private connectivity. Supply
|
|
132
|
+
bootstrap's private operator files and create both nonadministrative logins, exact
|
|
133
|
+
schema/grants and memberships. Native CA/token rotation requires an explicit rollout;
|
|
134
|
+
rotate parser/worker together and verify old/missing tokens are denied. The parent
|
|
135
|
+
parser removes the token from its environment and its native tools use a minimal
|
|
136
|
+
explicit environment. This is not an OS sandbox or proof of inherited platform IAM.
|
|
137
|
+
|
|
138
|
+
The API derives its same-origin policy only from documented Code Engine app/domain/
|
|
139
|
+
subdomain/region settings matched to its compiler-owned service name. No request
|
|
140
|
+
Host or Forwarded header chooses a trusted origin. The App ID redirect resource
|
|
141
|
+
references the created API endpoint after creation, avoiding a Terraform cycle.
|
|
142
|
+
`;
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
export const INVOICE_OPERATIONS=`# Invoice workflow operations
|
|
2
|
+
|
|
3
|
+
This is a private staff application. The generated API and worker SQL identities
|
|
4
|
+
cannot create accounts, admit staff, erase audit history or perform operator repairs.
|
|
5
|
+
Keep the schema-owner credential separate. No command below authorizes deployment.
|
|
6
|
+
|
|
7
|
+
## Bootstrap and staff access
|
|
8
|
+
|
|
9
|
+
Run Terraform foundation with applications_enabled=false. Review the actual account,
|
|
10
|
+
regional availability, costs, private network access and provider identity settings.
|
|
11
|
+
Supply the real accounting endpoint, scope and native secret outside Terraform state.
|
|
12
|
+
Build, scan and publish the emitted API/worker and parser images when authorized;
|
|
13
|
+
pin their exact digests in the emitted repositories before enabling applications.
|
|
14
|
+
|
|
15
|
+
Create a private .local directory (mode 0700), and keep all operator input files mode
|
|
16
|
+
0600 and outside source control. Run the operator from the emitted application
|
|
17
|
+
directory, using a Python 3.13 environment installed with requirements.lock hashes.
|
|
18
|
+
The operator needs an approved connection path to the private native database.
|
|
19
|
+
Never expose PostgreSQL publicly to make bootstrap easier.
|
|
20
|
+
|
|
21
|
+
operator-connection.json has exactly these fields:
|
|
22
|
+
host, port (integer), dbname, user, passwordFile, caFile.
|
|
23
|
+
The password/token and reviewed native PEM CA are absolute separate file paths.
|
|
24
|
+
There is no inline password, insecure TLS option or arbitrary connection string.
|
|
25
|
+
AWS includes rds-global-ca.pem plus its pinned public-source receipt; verify native
|
|
26
|
+
CA availability for the selected database and update/rebuild before CA expiry.
|
|
27
|
+
IBM supplies its database-specific CA and separately provisioned SQL passwords.
|
|
28
|
+
Azure's operator must be authorized for native Entra mapping in postgres as well as
|
|
29
|
+
schema administration in the application database. Google native IAM SQL users must
|
|
30
|
+
exist before the separate schema/grant step. Short-lived tokens must remain valid
|
|
31
|
+
for the bounded operator action; the tool does not silently acquire extra privilege.
|
|
32
|
+
|
|
33
|
+
operator-deployment.json has exactly: provider, deploymentId (UUID), accountId (UUID),
|
|
34
|
+
namespace (invoice), bindings (api and worker), tenantId (Azure UUID, otherwise null).
|
|
35
|
+
Each binding has name and principal; Google additionally has created_by_package:true.
|
|
36
|
+
Use exact Terraform outputs/native identity subjects, never guessed display names.
|
|
37
|
+
AWS emits the complete nonsecret operator_deployment output. With an approved
|
|
38
|
+
foundation and private connection available, retain that output in the private file.
|
|
39
|
+
|
|
40
|
+
Preview (no database connection or write):
|
|
41
|
+
|
|
42
|
+
python -I invoice_operator.py initialize --connection-file .local/operator-connection.json --deployment-file .local/operator-deployment.json
|
|
43
|
+
|
|
44
|
+
Add --execute only for the reviewed authorized destination. Initialization creates
|
|
45
|
+
owned native login mappings, the exact version-1 schema/queue and restricted grants.
|
|
46
|
+
It refuses to adopt an unrelated role or schema. Re-running the exact owned bootstrap
|
|
47
|
+
is supported; a changed schema requires a reviewed migration, not reinitialization.
|
|
48
|
+
IBM initialization additionally reads --input-file with apiPasswordFile and
|
|
49
|
+
workerPasswordFile pointing to private strong passwords; never rotate existing
|
|
50
|
+
owned passwords implicitly. Roll out credentials explicitly when rotating them.
|
|
51
|
+
|
|
52
|
+
Membership uses --input-file containing subject (verified native login subject),
|
|
53
|
+
roles (explicit array of user/reviewer/supervisor/owner), active (boolean):
|
|
54
|
+
|
|
55
|
+
python -I invoice_operator.py membership --connection-file .local/operator-connection.json --deployment-file .local/operator-deployment.json --input-file .local/member.json --execute
|
|
56
|
+
|
|
57
|
+
Inviting/signing in at the native identity service does not automatically grant
|
|
58
|
+
application membership. Ordinary staff get user; three designated reviewers get
|
|
59
|
+
reviewer. Revocation uses active:false; role replacement is explicit. Native JWT
|
|
60
|
+
expiry and live SQL membership are different boundaries. Test both at the destination.
|
|
61
|
+
|
|
62
|
+
## Ninety-day retention
|
|
63
|
+
|
|
64
|
+
The invoice API and processing stages refuse payloads whose creation time is outside
|
|
65
|
+
the 90-day retention window, including data recovered from old backups. Private-store
|
|
66
|
+
lifecycles remove original objects separately; version/noncurrent deletion and native
|
|
67
|
+
provider deletion are asynchronous. Backups may retain expired data for the stated
|
|
68
|
+
backup window. This is not an exact physical-deletion deadline or legal-retention SLA.
|
|
69
|
+
|
|
70
|
+
AWS, Azure and Google emit fixed operating jobs/schedules in OPERATING_JOBS.md.
|
|
71
|
+
The IBM native job adapter remains under qualification; do not assume its schedules
|
|
72
|
+
exist. The shared job entrypoint supports preview (without --execute), initialize,
|
|
73
|
+
maintain and monitor using the emitted owned metadata and separate operator identity.
|
|
74
|
+
It is never an API/model endpoint.
|
|
75
|
+
|
|
76
|
+
For the manual CLI maintenance path, pause uploads/API and workers, allow bounded
|
|
77
|
+
work to settle, then run:
|
|
78
|
+
|
|
79
|
+
python -I invoice_operator.py purge-expired --connection-file .local/operator-connection.json --deployment-file .local/operator-deployment.json --execute --confirm-workloads-stopped
|
|
80
|
+
|
|
81
|
+
It removes at most 500 expired operations, their historical suggestions/audit and
|
|
82
|
+
owned queue notifications per transaction. Repeat while moreMayRemain is true.
|
|
83
|
+
Active queue jobs/live leases cause rollback; settle them before retrying. Other
|
|
84
|
+
accounts/namespaces, staff memberships and young records are preserved. Retain the
|
|
85
|
+
count-only maintenance receipt and alert on failure/overdue runs. The fixed
|
|
86
|
+
maintain job additionally bounds a whole execution to twenty 500-record batches,
|
|
87
|
+
reports remaining backlog nonzero and uses the same live-job/lease/ownership guards
|
|
88
|
+
for online expired-only cleanup. Concurrent young submissions are serialized by
|
|
89
|
+
transaction locks and preserved. Restore/reconciliation still require the isolated
|
|
90
|
+
paused boundary. See the provider-specific native job definitions for scheduling;
|
|
91
|
+
a script file alone does not establish that a schedule exists.
|
|
92
|
+
|
|
93
|
+
Deduplication is scoped to the retained operation lifetime. Do not promise unlimited
|
|
94
|
+
historical deduplication after the client-directed 90-day payload/audit deletion.
|
|
95
|
+
Destination operators must independently retain the idempotency identity as required
|
|
96
|
+
by their accounting contract. Do not clear an unknown outcome to resend it.
|
|
97
|
+
|
|
98
|
+
## Backup, restore and uncertain deliveries
|
|
99
|
+
|
|
100
|
+
Review native managed backup retention, encryption, restore region and current
|
|
101
|
+
provider procedures. Restore to an isolated new database/endpoint with API/workers
|
|
102
|
+
stopped. Do not point running workers at a restored snapshot: the accounting service
|
|
103
|
+
may have accepted deliveries after that snapshot's recovery point.
|
|
104
|
+
|
|
105
|
+
With private operator files explicitly pointing to the isolated restored database:
|
|
106
|
+
|
|
107
|
+
python -I invoice_operator.py quarantine-restore --connection-file .local/restored-connection.json --deployment-file .local/operator-deployment.json --execute --confirm-workloads-stopped
|
|
108
|
+
|
|
109
|
+
Repeat while moreMayRemain is true. The tool fences restored approved/in-flight
|
|
110
|
+
deliveries as unknown, preserves approval hashes and clears stale queue notifications.
|
|
111
|
+
Interrupted extraction leases are fenced back to pending; the normal worker rebuilds
|
|
112
|
+
those notifications after expiry cleanup. This avoids retaining a restored doing
|
|
113
|
+
job forever or restarting an old external delivery. Attempt limits are preserved.
|
|
114
|
+
The stopped-workloads flag is an operator assertion, not proof that cloud workloads
|
|
115
|
+
were stopped. Purge expired restored records before reopening. Reapply reviewed native
|
|
116
|
+
runtime identity grants/membership as appropriate; verify current revocations and
|
|
117
|
+
object versions. Exercise read, denied access, fresh extraction and same-key behavior
|
|
118
|
+
on an isolated synthetic fixture before cutover. Keep old endpoints for rollback;
|
|
119
|
+
never dual-run workers on divergent databases. A local logical restore test does not
|
|
120
|
+
prove native PITR, object recovery, production RPO/RTO or destination availability.
|
|
121
|
+
|
|
122
|
+
For each uncertain delivery, independently query the existing accounting system by
|
|
123
|
+
operation ID and payload digest. If it confirms completion, store a private JSON
|
|
124
|
+
receipt with operation_id, payload_sha256, external_id and accountable operator:
|
|
125
|
+
|
|
126
|
+
python -I invoice_operator.py reconcile-completed --connection-file .local/operator-connection.json --deployment-file .local/operator-deployment.json --input-file .local/verified-receipt.json --execute --confirm-workloads-stopped
|
|
127
|
+
|
|
128
|
+
The tool checks exact ownership/state/approval integrity and records the supplied
|
|
129
|
+
receipt without making an external request. It does not verify the human's accounting
|
|
130
|
+
lookup. A missing receipt is not permission to resend. Automatic same-key replay needs
|
|
131
|
+
the scoped, expiring destination-contract review described in the worker configuration.
|
|
132
|
+
Never rewrite an approved payload, endpoint, account or idempotency key for a retry.
|
|
133
|
+
|
|
134
|
+
## Monitoring and release checks
|
|
135
|
+
|
|
136
|
+
Alert on stale pending/approved work, dead/unknown outcomes, repeated parser/model
|
|
137
|
+
failures, storage/database growth and failed retention windows. Healthz means process
|
|
138
|
+
alive; it does not establish database/model/destination readiness. Keep payloads,
|
|
139
|
+
credentials and document text out of telemetry. Scale worker/parser capacity together
|
|
140
|
+
after throughput/quota tests. Before production, qualify native sign-in/token expiry,
|
|
141
|
+
workload IAM, private ingress, TLS, native storage versions, actual model quality,
|
|
142
|
+
external accounting idempotency and restore/cutover with authorized destination tests.
|
|
143
|
+
`;
|