icdev 1.0.0__py3-none-any.whl
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.
- icdev/__init__.py +18 -0
- icdev/_paths.py +85 -0
- icdev/_version.py +3 -0
- icdev/data/__init__.py +1 -0
- icdev/data/args/__init__.py +1 -0
- icdev/data/args/agent_authority.yaml +61 -0
- icdev/data/args/agent_config.yaml +355 -0
- icdev/data/args/agentic_fitness.yaml +31 -0
- icdev/data/args/ai_governance_config.yaml +137 -0
- icdev/data/args/atlas_critique_config.yaml +66 -0
- icdev/data/args/bedrock_models.yaml +63 -0
- icdev/data/args/cicd_config.yaml +82 -0
- icdev/data/args/classification_config.yaml +232 -0
- icdev/data/args/cli_config.yaml +154 -0
- icdev/data/args/cloud_config.yaml +63 -0
- icdev/data/args/code_pattern_config.yaml +151 -0
- icdev/data/args/code_quality_config.yaml +47 -0
- icdev/data/args/companion_registry.yaml +202 -0
- icdev/data/args/context_config.yaml +82 -0
- icdev/data/args/csp_monitor_config.yaml +268 -0
- icdev/data/args/cui_markings.yaml +35 -0
- icdev/data/args/db_config.yaml +40 -0
- icdev/data/args/deployment_profiles.yaml +248 -0
- icdev/data/args/dev_profile_config.yaml +144 -0
- icdev/data/args/devsecops_config.yaml +286 -0
- icdev/data/args/endpoint_security_config.yaml +137 -0
- icdev/data/args/extension_config.yaml +79 -0
- icdev/data/args/file_access_tiers.yaml +88 -0
- icdev/data/args/framework_registry.yaml +415 -0
- icdev/data/args/innovation_config.yaml +431 -0
- icdev/data/args/installation_manifest.yaml +1087 -0
- icdev/data/args/llm_config.yaml +495 -0
- icdev/data/args/maintenance_config.yaml +55 -0
- icdev/data/args/memory_config.yaml +83 -0
- icdev/data/args/monitoring_config.yaml +127 -0
- icdev/data/args/mosa_config.yaml +190 -0
- icdev/data/args/nlq_config.yaml +35 -0
- icdev/data/args/observability_config.yaml +39 -0
- icdev/data/args/observability_tracing_config.yaml +170 -0
- icdev/data/args/oscal_tools_config.yaml +43 -0
- icdev/data/args/owasp_agentic_config.yaml +171 -0
- icdev/data/args/phase_registry.yaml +618 -0
- icdev/data/args/project_defaults.yaml +235 -0
- icdev/data/args/prompt_chains.yaml +163 -0
- icdev/data/args/resilience_config.yaml +50 -0
- icdev/data/args/ricoas_config.yaml +191 -0
- icdev/data/args/role_personas.yaml +362 -0
- icdev/data/args/scaling_config.yaml +176 -0
- icdev/data/args/security_gates.yaml +685 -0
- icdev/data/args/skill_injection_config.yaml +322 -0
- icdev/data/args/spec_config.yaml +53 -0
- icdev/data/args/supply_chain_config.yaml +76 -0
- icdev/data/args/translation_config.yaml +228 -0
- icdev/data/args/workflow_templates/ato_acceleration.yaml +54 -0
- icdev/data/args/workflow_templates/build_deploy.yaml +63 -0
- icdev/data/args/workflow_templates/full_compliance.yaml +43 -0
- icdev/data/args/workflow_templates/security_hardening.yaml +55 -0
- icdev/data/args/worktree_config.yaml +34 -0
- icdev/data/args/zta_config.yaml +247 -0
- icdev/data/context/__init__.py +1 -0
- icdev/data/context/agent/__init__.py +1 -0
- icdev/data/context/agent/response_schemas/__init__.py +1 -0
- icdev/data/context/agent/response_schemas/debate_position.json +46 -0
- icdev/data/context/agent/response_schemas/fitness_scorecard.json +74 -0
- icdev/data/context/agent/response_schemas/review_decision.json +39 -0
- icdev/data/context/agent/response_schemas/task_decomposition.json +82 -0
- icdev/data/context/agent/response_schemas/veto_decision.json +40 -0
- icdev/data/context/agentic/__init__.py +1 -0
- icdev/data/context/agentic/architecture_patterns.md +269 -0
- icdev/data/context/agentic/capability_registry.yaml +202 -0
- icdev/data/context/agentic/csp_mcp_registry.yaml +280 -0
- icdev/data/context/agentic/fitness_rubric.md +56 -0
- icdev/data/context/agentic/governance_baseline.md +205 -0
- icdev/data/context/ci/__init__.py +1 -0
- icdev/data/context/ci/worktree_templates.json +44 -0
- icdev/data/context/cloud/__init__.py +1 -0
- icdev/data/context/cloud/csp_service_registry.json +739 -0
- icdev/data/context/compliance/__init__.py +1 -0
- icdev/data/context/compliance/atlas_mitigations.json +293 -0
- icdev/data/context/compliance/atlas_techniques.json +833 -0
- icdev/data/context/compliance/cisa_sbd_requirements.json +432 -0
- icdev/data/context/compliance/cjis_security_policy.json +522 -0
- icdev/data/context/compliance/cmmc_practices.json +2494 -0
- icdev/data/context/compliance/cmmc_report_template.md +142 -0
- icdev/data/context/compliance/cnssi_1253_overlay.json +109 -0
- icdev/data/context/compliance/control_crosswalk.json +1914 -0
- icdev/data/context/compliance/control_families/__init__.py +1 -0
- icdev/data/context/compliance/csp_certifications.json +251 -0
- icdev/data/context/compliance/cssp_report_template.md +193 -0
- icdev/data/context/compliance/cui_templates/__init__.py +1 -0
- icdev/data/context/compliance/cui_templates/banner_block.txt +4 -0
- icdev/data/context/compliance/cui_templates/code_header.txt +8 -0
- icdev/data/context/compliance/cui_templates/document_template.md +35 -0
- icdev/data/context/compliance/data_type_framework_map.json +321 -0
- icdev/data/context/compliance/data_type_registry.json +147 -0
- icdev/data/context/compliance/dod_cssp_8530.json +463 -0
- icdev/data/context/compliance/eu_ai_act_annex_iii.json +108 -0
- icdev/data/context/compliance/export_templates/__init__.py +1 -0
- icdev/data/context/compliance/export_templates/emass_controls.csv.j2 +4 -0
- icdev/data/context/compliance/export_templates/evidence_package.md.j2 +39 -0
- icdev/data/context/compliance/export_templates/executive_summary.md.j2 +55 -0
- icdev/data/context/compliance/export_templates/poam_tracking.csv.j2 +4 -0
- icdev/data/context/compliance/fedramp_20x_ksi_schemas.json +133 -0
- icdev/data/context/compliance/fedramp_high_baseline.json +4370 -0
- icdev/data/context/compliance/fedramp_moderate_baseline.json +2183 -0
- icdev/data/context/compliance/fedramp_report_template.md +181 -0
- icdev/data/context/compliance/fips_200_areas.json +362 -0
- icdev/data/context/compliance/gao_ai_accountability.json +262 -0
- icdev/data/context/compliance/hipaa_security_rule.json +720 -0
- icdev/data/context/compliance/hitrust_csf_v11.json +930 -0
- icdev/data/context/compliance/impact_level_profiles.json +251 -0
- icdev/data/context/compliance/incident_response_template.md +1110 -0
- icdev/data/context/compliance/iso27001_2022_controls.json +750 -0
- icdev/data/context/compliance/iso27001_nist_bridge.json +382 -0
- icdev/data/context/compliance/iso42001_controls.json +254 -0
- icdev/data/context/compliance/ivv_checklist_template.md +80 -0
- icdev/data/context/compliance/ivv_report_template.md +116 -0
- icdev/data/context/compliance/ivv_requirements.json +372 -0
- icdev/data/context/compliance/mosa_crosswalk.json +327 -0
- icdev/data/context/compliance/mosa_framework.json +250 -0
- icdev/data/context/compliance/narrative_templates/AC.md.j2 +101 -0
- icdev/data/context/compliance/narrative_templates/AU.md.j2 +106 -0
- icdev/data/context/compliance/narrative_templates/IA.md.j2 +104 -0
- icdev/data/context/compliance/narrative_templates/SC.md.j2 +102 -0
- icdev/data/context/compliance/narrative_templates/SI.md.j2 +111 -0
- icdev/data/context/compliance/narrative_templates/__init__.py +1 -0
- icdev/data/context/compliance/narrative_templates/default.md.j2 +50 -0
- icdev/data/context/compliance/narrative_templates/executive_summary.j2 +27 -0
- icdev/data/context/compliance/narrative_templates/poam_milestone.j2 +19 -0
- icdev/data/context/compliance/narrative_templates/ssp_section.j2 +11 -0
- icdev/data/context/compliance/nist_800_171_controls.json +1552 -0
- icdev/data/context/compliance/nist_800_207_crosswalk.json +399 -0
- icdev/data/context/compliance/nist_800_207_zta.json +258 -0
- icdev/data/context/compliance/nist_800_53.json +324 -0
- icdev/data/context/compliance/nist_ai_600_1_genai.json +326 -0
- icdev/data/context/compliance/nist_ai_rmf.json +206 -0
- icdev/data/context/compliance/nist_sp_800_60_types.json +1667 -0
- icdev/data/context/compliance/omb_m25_21_high_impact_ai.json +248 -0
- icdev/data/context/compliance/omb_m26_04_unbiased_ai.json +262 -0
- icdev/data/context/compliance/owasp_agentic_asi.json +133 -0
- icdev/data/context/compliance/owasp_agentic_threats.json +285 -0
- icdev/data/context/compliance/owasp_llm_top10.json +274 -0
- icdev/data/context/compliance/pci_dss_v4.json +510 -0
- icdev/data/context/compliance/poam_template.md +117 -0
- icdev/data/context/compliance/safeai_controls.json +512 -0
- icdev/data/context/compliance/sbd_report_template.md +77 -0
- icdev/data/context/compliance/siem_config_templates/__init__.py +1 -0
- icdev/data/context/compliance/siem_config_templates/filebeat.yml +213 -0
- icdev/data/context/compliance/siem_config_templates/log_sources.json +208 -0
- icdev/data/context/compliance/soc2_trust_criteria.json +661 -0
- icdev/data/context/compliance/ssp_template.md +432 -0
- icdev/data/context/compliance/stig_templates/__init__.py +1 -0
- icdev/data/context/compliance/stig_templates/webapp_stig.json +139 -0
- icdev/data/context/compliance/xai_requirements.json +108 -0
- icdev/data/context/dashboard/__init__.py +1 -0
- icdev/data/context/dashboard/nlq_examples.json +50 -0
- icdev/data/context/dashboard/schema_descriptions.json +23 -0
- icdev/data/context/integration/__init__.py +1 -0
- icdev/data/context/integration/approval_workflows.json +32 -0
- icdev/data/context/integration/gitlab_field_mappings.json +33 -0
- icdev/data/context/integration/jira_field_mappings.json +32 -0
- icdev/data/context/integration/reqif_export_schema.json +23 -0
- icdev/data/context/integration/servicenow_field_mappings.json +22 -0
- icdev/data/context/languages/__init__.py +1 -0
- icdev/data/context/languages/framework_patterns.json +205 -0
- icdev/data/context/languages/language_registry.json +279 -0
- icdev/data/context/llm/__init__.py +1 -0
- icdev/data/context/llm/example_provider.py +86 -0
- icdev/data/context/mbse/__init__.py +1 -0
- icdev/data/context/mbse/des_report_template.md +162 -0
- icdev/data/context/mbse/des_requirements.json +411 -0
- icdev/data/context/mbse/digital_thread_patterns.json +403 -0
- icdev/data/context/mbse/reqif_schema.json +280 -0
- icdev/data/context/mbse/sysml_element_types.json +432 -0
- icdev/data/context/modernization/__init__.py +1 -0
- icdev/data/context/modernization/db_type_mappings.json +148 -0
- icdev/data/context/modernization/decomposition_patterns.json +284 -0
- icdev/data/context/modernization/framework_migration_patterns.json +359 -0
- icdev/data/context/modernization/migration_report_template.md +168 -0
- icdev/data/context/modernization/seven_rs_catalog.json +369 -0
- icdev/data/context/modernization/version_upgrade_rules.json +279 -0
- icdev/data/context/oscal/NIST_SP-800-53_rev5_catalog.json +254987 -0
- icdev/data/context/oscal/README.md +43 -0
- icdev/data/context/patterns/__init__.py +1 -0
- icdev/data/context/profiles/__init__.py +1 -0
- icdev/data/context/profiles/dod_baseline_v1.yaml +145 -0
- icdev/data/context/profiles/fedramp_baseline_v1.yaml +143 -0
- icdev/data/context/profiles/financial_baseline_v1.yaml +142 -0
- icdev/data/context/profiles/healthcare_baseline_v1.yaml +135 -0
- icdev/data/context/profiles/law_enforcement_v1.yaml +129 -0
- icdev/data/context/profiles/startup_v1.yaml +134 -0
- icdev/data/context/requirements/__init__.py +1 -0
- icdev/data/context/requirements/ambiguity_patterns.json +97 -0
- icdev/data/context/requirements/boundary_impact_rules.json +123 -0
- icdev/data/context/requirements/default_constitutions.json +67 -0
- icdev/data/context/requirements/document_extraction_rules.json +58 -0
- icdev/data/context/requirements/gap_patterns.json +108 -0
- icdev/data/context/requirements/readiness_rubric.json +78 -0
- icdev/data/context/requirements/red_alternative_patterns.json +210 -0
- icdev/data/context/requirements/safe_templates.json +72 -0
- icdev/data/context/requirements/spec_quality_checklist.json +122 -0
- icdev/data/context/simulation/__init__.py +1 -0
- icdev/data/context/simulation/architecture_patterns.json +36 -0
- icdev/data/context/simulation/coa_templates.json +38 -0
- icdev/data/context/simulation/cost_models.json +23 -0
- icdev/data/context/simulation/risk_categories.json +46 -0
- icdev/data/context/supply_chain/__init__.py +1 -0
- icdev/data/context/supply_chain/isa_templates.json +129 -0
- icdev/data/context/supply_chain/nist_800_161_controls.json +247 -0
- icdev/data/context/supply_chain/scrm_risk_matrix.json +147 -0
- icdev/data/context/templates/__init__.py +1 -0
- icdev/data/context/templates/ansible/__init__.py +1 -0
- icdev/data/context/templates/ansible/playbooks/__init__.py +1 -0
- icdev/data/context/templates/ansible/roles/__init__.py +1 -0
- icdev/data/context/templates/gitlab_ci/__init__.py +1 -0
- icdev/data/context/templates/grafana/__init__.py +1 -0
- icdev/data/context/templates/kubernetes/__init__.py +1 -0
- icdev/data/context/templates/project/__init__.py +1 -0
- icdev/data/context/templates/project/api/__init__.py +1 -0
- icdev/data/context/templates/project/cli/__init__.py +1 -0
- icdev/data/context/templates/project/data_pipeline/__init__.py +1 -0
- icdev/data/context/templates/project/iac/__init__.py +1 -0
- icdev/data/context/templates/project/javascript_frontend/__init__.py +1 -0
- icdev/data/context/templates/project/javascript_frontend/src/__init__.py +1 -0
- icdev/data/context/templates/project/javascript_frontend/tests/__init__.py +1 -0
- icdev/data/context/templates/project/microservice/__init__.py +1 -0
- icdev/data/context/templates/project/python_backend/__init__.py +1 -0
- icdev/data/context/templates/project/python_backend/src/__init__.py +1 -0
- icdev/data/context/templates/project/python_backend/tests/__init__.py +1 -0
- icdev/data/context/templates/project/python_backend/tests/features/__init__.py +1 -0
- icdev/data/context/templates/project/python_backend/tests/steps/__init__.py +1 -0
- icdev/data/context/templates/terraform/__init__.py +1 -0
- icdev/data/context/templates/terraform/govcloud_base/__init__.py +1 -0
- icdev/data/context/templates/terraform/modules/__init__.py +1 -0
- icdev/data/context/tone/__init__.py +1 -0
- icdev/data/context/translation/dependency_mappings.json +186 -0
- icdev/data/context/translation/type_mappings.json +149 -0
- icdev/data/docs/README.md +187 -0
- icdev/data/docs/__init__.py +1 -0
- icdev/data/docs/admin/gateway-guide.md +338 -0
- icdev/data/docs/admin/marketplace-guide.md +396 -0
- icdev/data/docs/admin/monitoring-guide.md +509 -0
- icdev/data/docs/architecture/compliance-framework.md +764 -0
- icdev/data/docs/architecture/database-schema.md +689 -0
- icdev/data/docs/architecture/gotcha-framework.md +518 -0
- icdev/data/docs/architecture/multi-agent-system.md +603 -0
- icdev/data/docs/dx/README.md +106 -0
- icdev/data/docs/dx/__init__.py +1 -0
- icdev/data/docs/dx/ci-cd-integration.md +378 -0
- icdev/data/docs/dx/claude-code-guide.md +213 -0
- icdev/data/docs/dx/companion-guide.md +232 -0
- icdev/data/docs/dx/dev-profiles.md +309 -0
- icdev/data/docs/dx/icdev-yaml-spec.md +219 -0
- icdev/data/docs/dx/integration-tiers.md +279 -0
- icdev/data/docs/dx/llm-routing-guide.md +456 -0
- icdev/data/docs/dx/quickstart.md +192 -0
- icdev/data/docs/dx/sdk-reference.md +356 -0
- icdev/data/docs/dx/unified-mcp-setup.md +525 -0
- icdev/data/docs/features/__init__.py +1 -0
- icdev/data/docs/features/phase-01-gotcha-framework.md +249 -0
- icdev/data/docs/features/phase-02-atlas-build-workflow.md +223 -0
- icdev/data/docs/features/phase-03-tdd-bdd-testing.md +261 -0
- icdev/data/docs/features/phase-04-nist-compliance.md +255 -0
- icdev/data/docs/features/phase-05-security-scanning.md +229 -0
- icdev/data/docs/features/phase-06-infrastructure-deployment.md +288 -0
- icdev/data/docs/features/phase-07-code-review-gates.md +276 -0
- icdev/data/docs/features/phase-08-self-healing.md +223 -0
- icdev/data/docs/features/phase-09-monitoring-observability.md +230 -0
- icdev/data/docs/features/phase-10-dashboard-web-ui.md +218 -0
- icdev/data/docs/features/phase-11-multi-agent-architecture.md +272 -0
- icdev/data/docs/features/phase-12-integration-testing.md +228 -0
- icdev/data/docs/features/phase-13-cicd-integration.md +257 -0
- icdev/data/docs/features/phase-14-secure-by-design-ivv.md +240 -0
- icdev/data/docs/features/phase-15-maintenance-audit.md +192 -0
- icdev/data/docs/features/phase-16-ato-acceleration.md +228 -0
- icdev/data/docs/features/phase-17-multi-framework-compliance.md +223 -0
- icdev/data/docs/features/phase-18-mbse-integration.md +242 -0
- icdev/data/docs/features/phase-19-agentic-generation.md +202 -0
- icdev/data/docs/features/phase-20-fips-security-categorization.md +198 -0
- icdev/data/docs/features/phase-21-saas-multi-tenancy.md +273 -0
- icdev/data/docs/features/phase-22-federated-gotcha-marketplace.md +242 -0
- icdev/data/docs/features/phase-23-universal-compliance-platform.md +238 -0
- icdev/data/docs/features/phase-24-devsecops-pipeline-security.md +198 -0
- icdev/data/docs/features/phase-25-zero-trust-architecture.md +220 -0
- icdev/data/docs/features/phase-26-dod-mosa.md +205 -0
- icdev/data/docs/features/phase-27-cli-capabilities.md +222 -0
- icdev/data/docs/features/phase-28-remote-command-gateway.md +235 -0
- icdev/data/docs/features/phase-29-proactive-monitoring.md +212 -0
- icdev/data/docs/features/phase-30-dashboard-auth.md +215 -0
- icdev/data/docs/features/phase-31-dashboard-ux-low-impact.md +188 -0
- icdev/data/docs/features/phase-32-dashboard-ux-medium-impact.md +223 -0
- icdev/data/docs/features/phase-33-modular-installation.md +218 -0
- icdev/data/docs/features/phase-34-dev-profiles.md +239 -0
- icdev/data/docs/features/phase-35-innovation-engine.md +257 -0
- icdev/data/docs/features/phase-36-evolutionary-intelligence.md +351 -0
- icdev/data/docs/features/phase-37-mitre-atlas-integration.md +485 -0
- icdev/data/docs/features/phase-38-cloud-agnostic-architecture.md +1033 -0
- icdev/data/docs/features/phase-39-observability-operations.md +178 -0
- icdev/data/docs/features/phase-40-nlq-compliance-queries.md +176 -0
- icdev/data/docs/features/phase-41-parallel-cicd.md +169 -0
- icdev/data/docs/features/phase-42-framework-planning.md +177 -0
- icdev/data/docs/features/phase-43-cross-language-translation.md +225 -0
- icdev/data/docs/features/phase-44-innovation-adaptation.md +227 -0
- icdev/data/docs/features/phase-45-owasp-agentic-security.md +239 -0
- icdev/data/docs/features/phase-46-observability-traceability-xai.md +240 -0
- icdev/data/docs/features/phase-47-unified-mcp-gateway.md +257 -0
- icdev/data/docs/features/phase-48-ai-transparency.md +203 -0
- icdev/data/docs/features/phase-49-ai-accountability.md +243 -0
- icdev/data/docs/features/phase-50-ai-governance-intake-chat.md +195 -0
- icdev/data/docs/features/phase-51-unified-chat-dashboard.md +240 -0
- icdev/data/docs/features/phase-52-code-intelligence.md +244 -0
- icdev/data/docs/features/phase-53-fedramp-20x-owasp-asi.md +359 -0
- icdev/data/docs/features/phase-54-slsa-swft-orchestration.md +379 -0
- icdev/data/docs/features/phase-55-a2a-v03-mcp-oauth.md +322 -0
- icdev/data/docs/features/phase-56-evidence-lineage.md +352 -0
- icdev/data/docs/features/phase-57-eu-ai-act-iron-bank.md +319 -0
- icdev/data/docs/features/phase-58-creative-engine.md +370 -0
- icdev/data/docs/features/phase-59-govcon-intelligence.md +535 -0
- icdev/data/docs/features/phase-60-cpmp.md +528 -0
- icdev/data/docs/features/phase-61-orchestration-improvements.md +534 -0
- icdev/data/docs/operations/dashboard-guide.md +354 -0
- icdev/data/docs/operations/deployment-guide.md +556 -0
- icdev/data/docs/operations/saas-admin-guide.md +439 -0
- icdev/data/docs/operations/security-operations-guide.md +733 -0
- icdev/data/docs/runbooks/backup-restore.md +412 -0
- icdev/data/docs/runbooks/troubleshooting.md +499 -0
- icdev/data/features/__init__.py +1 -0
- icdev/data/features/cicd_integration.feature +41 -0
- icdev/data/features/compliance_gates.feature +46 -0
- icdev/data/features/dashboard.feature +72 -0
- icdev/data/features/environment.py +25 -0
- icdev/data/features/project_management.feature +32 -0
- icdev/data/features/requirements_intake.feature +42 -0
- icdev/data/features/saas_platform.feature +53 -0
- icdev/data/features/security_scanning.feature +36 -0
- icdev/data/features/steps/__init__.py +1 -0
- icdev/data/features/steps/cicd_steps.py +465 -0
- icdev/data/features/steps/compliance_steps.py +308 -0
- icdev/data/features/steps/dashboard_steps.py +88 -0
- icdev/data/features/steps/project_steps.py +126 -0
- icdev/data/features/steps/requirements_intake_steps.py +689 -0
- icdev/data/features/steps/saas_platform_steps.py +572 -0
- icdev/data/features/steps/security_steps.py +236 -0
- icdev/data/features/steps/testing_steps.py +226 -0
- icdev/data/features/testing_pipeline.feature +42 -0
- icdev/data/goals/__init__.py +1 -0
- icdev/data/goals/agent_management.md +144 -0
- icdev/data/goals/agentic_generation.md +345 -0
- icdev/data/goals/agentic_threat_model.md +309 -0
- icdev/data/goals/ai_accountability.md +90 -0
- icdev/data/goals/ai_governance_intake.md +132 -0
- icdev/data/goals/ai_transparency.md +76 -0
- icdev/data/goals/atlas_integration.md +405 -0
- icdev/data/goals/ato_acceleration.md +139 -0
- icdev/data/goals/boundary_supply_chain.md +206 -0
- icdev/data/goals/build_app.md +544 -0
- icdev/data/goals/cicd_integration.md +86 -0
- icdev/data/goals/claude_dir_maintenance.md +77 -0
- icdev/data/goals/cli_capabilities.md +340 -0
- icdev/data/goals/cloud_agnostic.md +312 -0
- icdev/data/goals/code_intelligence.md +197 -0
- icdev/data/goals/code_review.md +94 -0
- icdev/data/goals/compliance_workflow.md +858 -0
- icdev/data/goals/continuous_harmonization.md +140 -0
- icdev/data/goals/cross_language_translation.md +171 -0
- icdev/data/goals/dashboard.md +142 -0
- icdev/data/goals/deploy_workflow.md +390 -0
- icdev/data/goals/devsecops_workflow.md +408 -0
- icdev/data/goals/evolutionary_intelligence.md +305 -0
- icdev/data/goals/external_integration.md +113 -0
- icdev/data/goals/framework_planning.md +63 -0
- icdev/data/goals/init_project.md +235 -0
- icdev/data/goals/innovation_engine.md +199 -0
- icdev/data/goals/integration_testing.md +189 -0
- icdev/data/goals/maintenance_audit.md +196 -0
- icdev/data/goals/manifest.md +56 -0
- icdev/data/goals/mbse_integration.md +504 -0
- icdev/data/goals/modernization_workflow.md +618 -0
- icdev/data/goals/monitoring.md +126 -0
- icdev/data/goals/mosa_workflow.md +463 -0
- icdev/data/goals/multi_agent_orchestration.md +68 -0
- icdev/data/goals/nlq_compliance.md +63 -0
- icdev/data/goals/observability.md +64 -0
- icdev/data/goals/observability_traceability_xai.md +154 -0
- icdev/data/goals/owasp_agentic_security.md +395 -0
- icdev/data/goals/parallel_cicd.md +61 -0
- icdev/data/goals/requirements_intake.md +213 -0
- icdev/data/goals/sbd_ivv_workflow.md +195 -0
- icdev/data/goals/security_categorization.md +133 -0
- icdev/data/goals/security_scan.md +381 -0
- icdev/data/goals/self_healing.md +120 -0
- icdev/data/goals/simulation_engine.md +111 -0
- icdev/data/goals/tdd_workflow.md +403 -0
- icdev/data/goals/zero_trust_architecture.md +403 -0
- icdev/data/hardprompts/__init__.py +1 -0
- icdev/data/hardprompts/agent/__init__.py +1 -0
- icdev/data/hardprompts/agent/agentic_architect.md +100 -0
- icdev/data/hardprompts/agent/debate_prompt.md +32 -0
- icdev/data/hardprompts/agent/fitness_evaluation.md +48 -0
- icdev/data/hardprompts/agent/governance_review.md +214 -0
- icdev/data/hardprompts/agent/reviewer_prompt.md +34 -0
- icdev/data/hardprompts/agent/skill_design.md +172 -0
- icdev/data/hardprompts/agent/task_decomposition.md +275 -0
- icdev/data/hardprompts/agent/veto_check_prompt.md +33 -0
- icdev/data/hardprompts/architect/__init__.py +1 -0
- icdev/data/hardprompts/architect/api_design.md +283 -0
- icdev/data/hardprompts/architect/data_model.md +277 -0
- icdev/data/hardprompts/architect/system_design.md +180 -0
- icdev/data/hardprompts/builder/__init__.py +1 -0
- icdev/data/hardprompts/builder/code_generation.md +59 -0
- icdev/data/hardprompts/builder/refactor.md +58 -0
- icdev/data/hardprompts/builder/scaffold_project.md +69 -0
- icdev/data/hardprompts/builder/test_generation.md +87 -0
- icdev/data/hardprompts/ci/__init__.py +1 -0
- icdev/data/hardprompts/ci/worktree_setup.md +35 -0
- icdev/data/hardprompts/compliance/__init__.py +1 -0
- icdev/data/hardprompts/compliance/cmmc_assessment.md +63 -0
- icdev/data/hardprompts/compliance/cssp_assessment.md +75 -0
- icdev/data/hardprompts/compliance/cui_marking.md +86 -0
- icdev/data/hardprompts/compliance/fedramp_assessment.md +55 -0
- icdev/data/hardprompts/compliance/ivv_assessment.md +96 -0
- icdev/data/hardprompts/compliance/poam_generation.md +57 -0
- icdev/data/hardprompts/compliance/sbd_assessment.md +101 -0
- icdev/data/hardprompts/compliance/security_categorization.md +74 -0
- icdev/data/hardprompts/compliance/ssp_generation.md +56 -0
- icdev/data/hardprompts/compliance/stig_evaluation.md +63 -0
- icdev/data/hardprompts/dashboard/__init__.py +1 -0
- icdev/data/hardprompts/dashboard/nlq_system_prompt.md +26 -0
- icdev/data/hardprompts/infra/__init__.py +1 -0
- icdev/data/hardprompts/infra/k8s_manifests.md +118 -0
- icdev/data/hardprompts/infra/pipeline_generation.md +160 -0
- icdev/data/hardprompts/infra/terraform_generation.md +92 -0
- icdev/data/hardprompts/integration/__init__.py +1 -0
- icdev/data/hardprompts/integration/approval_review.md +17 -0
- icdev/data/hardprompts/integration/jira_mapping.md +25 -0
- icdev/data/hardprompts/integration/servicenow_mapping.md +14 -0
- icdev/data/hardprompts/knowledge/__init__.py +1 -0
- icdev/data/hardprompts/knowledge/pattern_detection.md +73 -0
- icdev/data/hardprompts/knowledge/recommendation_engine.md +90 -0
- icdev/data/hardprompts/knowledge/root_cause_analysis.md +91 -0
- icdev/data/hardprompts/maintenance/__init__.py +1 -0
- icdev/data/hardprompts/maintenance/maintenance_assessment.md +82 -0
- icdev/data/hardprompts/mbse/__init__.py +1 -0
- icdev/data/hardprompts/mbse/digital_thread.md +67 -0
- icdev/data/hardprompts/mbse/model_import.md +62 -0
- icdev/data/hardprompts/mbse/model_to_code.md +65 -0
- icdev/data/hardprompts/modernization/__init__.py +1 -0
- icdev/data/hardprompts/modernization/legacy_analysis.md +93 -0
- icdev/data/hardprompts/modernization/migration_planning.md +150 -0
- icdev/data/hardprompts/modernization/seven_r_assessment.md +107 -0
- icdev/data/hardprompts/requirements/__init__.py +1 -0
- icdev/data/hardprompts/requirements/bdd_generation.md +35 -0
- icdev/data/hardprompts/requirements/clarification_prioritization.md +29 -0
- icdev/data/hardprompts/requirements/decomposition.md +60 -0
- icdev/data/hardprompts/requirements/document_extraction.md +45 -0
- icdev/data/hardprompts/requirements/gap_detection.md +70 -0
- icdev/data/hardprompts/requirements/intake_conversation.md +101 -0
- icdev/data/hardprompts/requirements/readiness_assessment.md +39 -0
- icdev/data/hardprompts/requirements/spec_quality.md +33 -0
- icdev/data/hardprompts/requirements/traceability_analysis.md +23 -0
- icdev/data/hardprompts/security/__init__.py +1 -0
- icdev/data/hardprompts/security/endpoint_security.md +78 -0
- icdev/data/hardprompts/security/threat_model.md +70 -0
- icdev/data/hardprompts/security/vulnerability_assessment.md +81 -0
- icdev/data/hardprompts/simulation/__init__.py +1 -0
- icdev/data/hardprompts/simulation/architecture_impact.md +27 -0
- icdev/data/hardprompts/simulation/coa_alternative.md +27 -0
- icdev/data/hardprompts/simulation/coa_generation.md +25 -0
- icdev/data/hardprompts/simulation/compliance_impact.md +28 -0
- icdev/data/hardprompts/simulation/cost_estimation.md +33 -0
- icdev/data/hardprompts/simulation/risk_assessment.md +28 -0
- icdev/data/hardprompts/translation/code_translation.md +68 -0
- icdev/data/hardprompts/translation/dependency_suggestion.md +44 -0
- icdev/data/hardprompts/translation/test_translation.md +64 -0
- icdev/data/hardprompts/translation/translation_repair.md +59 -0
- icdev/py.typed +0 -0
- icdev/tools/__init__.py +1 -0
- icdev/tools/_gen_formatter.py +12 -0
- icdev/tools/a2a/__init__.py +1 -0
- icdev/tools/a2a/agent_cards/architect.json +43 -0
- icdev/tools/a2a/agent_cards/builder.json +50 -0
- icdev/tools/a2a/agent_cards/compliance.json +57 -0
- icdev/tools/a2a/agent_cards/devsecops.json +71 -0
- icdev/tools/a2a/agent_cards/infra.json +57 -0
- icdev/tools/a2a/agent_cards/integration.json +57 -0
- icdev/tools/a2a/agent_cards/knowledge.json +43 -0
- icdev/tools/a2a/agent_cards/mbse.json +57 -0
- icdev/tools/a2a/agent_cards/modernization.json +50 -0
- icdev/tools/a2a/agent_cards/monitor.json +43 -0
- icdev/tools/a2a/agent_cards/orchestrator.json +36 -0
- icdev/tools/a2a/agent_cards/requirements_analyst.json +64 -0
- icdev/tools/a2a/agent_cards/security.json +50 -0
- icdev/tools/a2a/agent_cards/simulation.json +57 -0
- icdev/tools/a2a/agent_cards/supply_chain.json +50 -0
- icdev/tools/a2a/agent_client.py +349 -0
- icdev/tools/a2a/agent_registry.py +412 -0
- icdev/tools/a2a/agent_server.py +579 -0
- icdev/tools/a2a/task.py +200 -0
- icdev/tools/agent/__init__.py +2 -0
- icdev/tools/agent/a2a_agent_card_generator.py +285 -0
- icdev/tools/agent/a2a_discovery_server.py +250 -0
- icdev/tools/agent/agent_executor.py +529 -0
- icdev/tools/agent/agent_memory.py +557 -0
- icdev/tools/agent/agent_models.py +51 -0
- icdev/tools/agent/atlas_critique.py +908 -0
- icdev/tools/agent/authority.py +443 -0
- icdev/tools/agent/bedrock_client.py +1075 -0
- icdev/tools/agent/collaboration.py +871 -0
- icdev/tools/agent/dispatcher_mode.py +665 -0
- icdev/tools/agent/mailbox.py +575 -0
- icdev/tools/agent/prompt_chain_executor.py +1064 -0
- icdev/tools/agent/session_purpose.py +350 -0
- icdev/tools/agent/skill_router.py +638 -0
- icdev/tools/agent/skill_selector.py +486 -0
- icdev/tools/agent/team_orchestrator.py +1108 -0
- icdev/tools/agent/token_tracker.py +290 -0
- icdev/tools/analysis/__init__.py +1 -0
- icdev/tools/analysis/code_analyzer.py +780 -0
- icdev/tools/analysis/runtime_feedback.py +389 -0
- icdev/tools/audit/__init__.py +1 -0
- icdev/tools/audit/audit_logger.py +196 -0
- icdev/tools/audit/audit_query.py +157 -0
- icdev/tools/audit/decision_recorder.py +72 -0
- icdev/tools/builder/__init__.py +1 -0
- icdev/tools/builder/agentic_fitness.py +534 -0
- icdev/tools/builder/agentic_test_templates/test_a2a_callback.py +117 -0
- icdev/tools/builder/agentic_test_templates/test_a2a_lifecycle.feature +52 -0
- icdev/tools/builder/agentic_test_templates/test_agent_card.feature +37 -0
- icdev/tools/builder/agentic_test_templates/test_agent_health.py +128 -0
- icdev/tools/builder/agentic_test_templates/test_memory_system.feature +50 -0
- icdev/tools/builder/agentic_test_templates/test_skill_execution.feature +40 -0
- icdev/tools/builder/app_blueprint.py +1583 -0
- icdev/tools/builder/child_app_generator.py +2852 -0
- icdev/tools/builder/claude_md_generator.py +1734 -0
- icdev/tools/builder/code_generator.py +3703 -0
- icdev/tools/builder/db_init_generator.py +1709 -0
- icdev/tools/builder/dev_profile_manager.py +954 -0
- icdev/tools/builder/formatter.py +768 -0
- icdev/tools/builder/goal_adapter.py +592 -0
- icdev/tools/builder/gotcha_validator.py +812 -0
- icdev/tools/builder/language_support.py +441 -0
- icdev/tools/builder/linter.py +976 -0
- icdev/tools/builder/profile_detector.py +657 -0
- icdev/tools/builder/profile_md_generator.py +723 -0
- icdev/tools/builder/scaffolder.py +1590 -0
- icdev/tools/builder/scaffolder_extended.py +1771 -0
- icdev/tools/builder/test_writer.py +950 -0
- icdev/tools/ci/__init__.py +2 -0
- icdev/tools/ci/connectors/__init__.py +2 -0
- icdev/tools/ci/connectors/base_connector.py +80 -0
- icdev/tools/ci/connectors/connector_registry.py +188 -0
- icdev/tools/ci/connectors/mattermost_connector.py +159 -0
- icdev/tools/ci/connectors/slack_connector.py +197 -0
- icdev/tools/ci/core/__init__.py +2 -0
- icdev/tools/ci/core/air_gap_detector.py +115 -0
- icdev/tools/ci/core/comment_handler.py +192 -0
- icdev/tools/ci/core/conversation_manager.py +479 -0
- icdev/tools/ci/core/event_envelope.py +500 -0
- icdev/tools/ci/core/event_router.py +443 -0
- icdev/tools/ci/core/failure_parser.py +397 -0
- icdev/tools/ci/core/recovery_engine.py +527 -0
- icdev/tools/ci/modules/__init__.py +2 -0
- icdev/tools/ci/modules/agent.py +271 -0
- icdev/tools/ci/modules/git_ops.py +175 -0
- icdev/tools/ci/modules/state.py +117 -0
- icdev/tools/ci/modules/vcs.py +303 -0
- icdev/tools/ci/modules/workflow_ops.py +295 -0
- icdev/tools/ci/modules/worktree.py +340 -0
- icdev/tools/ci/pipeline_config_generator.py +558 -0
- icdev/tools/ci/triggers/__init__.py +2 -0
- icdev/tools/ci/triggers/gitlab_task_monitor.py +330 -0
- icdev/tools/ci/triggers/poll_trigger.py +237 -0
- icdev/tools/ci/triggers/webhook_server.py +356 -0
- icdev/tools/ci/workflows/__init__.py +2 -0
- icdev/tools/ci/workflows/icdev_build.py +140 -0
- icdev/tools/ci/workflows/icdev_comply.py +284 -0
- icdev/tools/ci/workflows/icdev_document.py +152 -0
- icdev/tools/ci/workflows/icdev_e2e.py +188 -0
- icdev/tools/ci/workflows/icdev_patch.py +186 -0
- icdev/tools/ci/workflows/icdev_plan.py +202 -0
- icdev/tools/ci/workflows/icdev_plan_build.py +41 -0
- icdev/tools/ci/workflows/icdev_plan_build_test.py +46 -0
- icdev/tools/ci/workflows/icdev_plan_build_test_review.py +47 -0
- icdev/tools/ci/workflows/icdev_review.py +126 -0
- icdev/tools/ci/workflows/icdev_sdlc.py +261 -0
- icdev/tools/ci/workflows/icdev_test.py +240 -0
- icdev/tools/cli/__init__.py +1 -0
- icdev/tools/cli/output_formatter.py +756 -0
- icdev/tools/cli_formatter.py +42 -0
- icdev/tools/cloud/__init__.py +11 -0
- icdev/tools/cloud/cloud_mode_manager.py +364 -0
- icdev/tools/cloud/csp_changelog.py +383 -0
- icdev/tools/cloud/csp_health_checker.py +268 -0
- icdev/tools/cloud/csp_monitor.py +951 -0
- icdev/tools/cloud/iam_provider.py +593 -0
- icdev/tools/cloud/kms_provider.py +346 -0
- icdev/tools/cloud/monitoring_provider.py +628 -0
- icdev/tools/cloud/provider_factory.py +376 -0
- icdev/tools/cloud/region_validator.py +345 -0
- icdev/tools/cloud/registry_provider.py +563 -0
- icdev/tools/cloud/secrets_provider.py +486 -0
- icdev/tools/cloud/storage_provider.py +446 -0
- icdev/tools/compat/__init__.py +21 -0
- icdev/tools/compat/cli_harmonizer.py +251 -0
- icdev/tools/compat/datetime_utils.py +18 -0
- icdev/tools/compat/db_utils.py +160 -0
- icdev/tools/compat/platform_utils.py +123 -0
- icdev/tools/compliance/__init__.py +1 -0
- icdev/tools/compliance/accountability_manager.py +397 -0
- icdev/tools/compliance/ai_accountability_audit.py +294 -0
- icdev/tools/compliance/ai_impact_assessor.py +273 -0
- icdev/tools/compliance/ai_incident_response.py +301 -0
- icdev/tools/compliance/ai_inventory_manager.py +239 -0
- icdev/tools/compliance/ai_reassessment_scheduler.py +256 -0
- icdev/tools/compliance/ai_transparency_audit.py +248 -0
- icdev/tools/compliance/atlas_assessor.py +278 -0
- icdev/tools/compliance/atlas_report_generator.py +1211 -0
- icdev/tools/compliance/base_assessor.py +597 -0
- icdev/tools/compliance/cato_monitor.py +1385 -0
- icdev/tools/compliance/cato_scheduler.py +699 -0
- icdev/tools/compliance/cjis_assessor.py +76 -0
- icdev/tools/compliance/classification_manager.py +1353 -0
- icdev/tools/compliance/cmmc_assessor.py +1491 -0
- icdev/tools/compliance/cmmc_report_generator.py +1100 -0
- icdev/tools/compliance/compliance_detector.py +463 -0
- icdev/tools/compliance/compliance_exporter.py +427 -0
- icdev/tools/compliance/compliance_status.py +825 -0
- icdev/tools/compliance/control_mapper.py +505 -0
- icdev/tools/compliance/crosswalk_engine.py +1203 -0
- icdev/tools/compliance/cssp_assessor.py +1045 -0
- icdev/tools/compliance/cssp_evidence_collector.py +729 -0
- icdev/tools/compliance/cssp_report_generator.py +1116 -0
- icdev/tools/compliance/cui_marker.py +388 -0
- icdev/tools/compliance/diagram_validator.py +600 -0
- icdev/tools/compliance/emass/__init__.py +2 -0
- icdev/tools/compliance/emass/emass_client.py +840 -0
- icdev/tools/compliance/emass/emass_export.py +777 -0
- icdev/tools/compliance/emass/emass_sync.py +826 -0
- icdev/tools/compliance/eu_ai_act_classifier.py +194 -0
- icdev/tools/compliance/evidence_collector.py +468 -0
- icdev/tools/compliance/fairness_assessor.py +316 -0
- icdev/tools/compliance/fedramp_assessor.py +1808 -0
- icdev/tools/compliance/fedramp_authorization_packager.py +137 -0
- icdev/tools/compliance/fedramp_ksi_generator.py +355 -0
- icdev/tools/compliance/fedramp_report_generator.py +1128 -0
- icdev/tools/compliance/fips199_categorizer.py +881 -0
- icdev/tools/compliance/fips200_validator.py +315 -0
- icdev/tools/compliance/gao_ai_assessor.py +231 -0
- icdev/tools/compliance/gao_evidence_builder.py +308 -0
- icdev/tools/compliance/hipaa_assessor.py +78 -0
- icdev/tools/compliance/hitrust_assessor.py +49 -0
- icdev/tools/compliance/incident_response_plan.py +718 -0
- icdev/tools/compliance/iso27001_assessor.py +92 -0
- icdev/tools/compliance/iso42001_assessor.py +114 -0
- icdev/tools/compliance/ivv_assessor.py +2327 -0
- icdev/tools/compliance/ivv_report_generator.py +1662 -0
- icdev/tools/compliance/model_card_generator.py +297 -0
- icdev/tools/compliance/mosa_assessor.py +117 -0
- icdev/tools/compliance/multi_regime_assessor.py +451 -0
- icdev/tools/compliance/narrative_generator.py +1013 -0
- icdev/tools/compliance/nist_800_207_assessor.py +191 -0
- icdev/tools/compliance/nist_ai_600_1_assessor.py +188 -0
- icdev/tools/compliance/nist_ai_rmf_assessor.py +110 -0
- icdev/tools/compliance/nist_lookup.py +245 -0
- icdev/tools/compliance/omb_m25_21_assessor.py +228 -0
- icdev/tools/compliance/omb_m26_04_assessor.py +188 -0
- icdev/tools/compliance/oscal_catalog_adapter.py +395 -0
- icdev/tools/compliance/oscal_generator.py +2170 -0
- icdev/tools/compliance/oscal_tools.py +1182 -0
- icdev/tools/compliance/owasp_agentic_assessor.py +226 -0
- icdev/tools/compliance/owasp_asi_assessor.py +200 -0
- icdev/tools/compliance/owasp_llm_assessor.py +244 -0
- icdev/tools/compliance/pci_dss_assessor.py +80 -0
- icdev/tools/compliance/pi_compliance_tracker.py +1461 -0
- icdev/tools/compliance/poam_generator.py +405 -0
- icdev/tools/compliance/resolve_marking.py +283 -0
- icdev/tools/compliance/sbd_assessor.py +2068 -0
- icdev/tools/compliance/sbd_report_generator.py +1236 -0
- icdev/tools/compliance/sbom_generator.py +1008 -0
- icdev/tools/compliance/siem_config_generator.py +674 -0
- icdev/tools/compliance/slsa_attestation_generator.py +490 -0
- icdev/tools/compliance/soc2_assessor.py +77 -0
- icdev/tools/compliance/ssp_generator.py +573 -0
- icdev/tools/compliance/stig_checker.py +727 -0
- icdev/tools/compliance/swft_evidence_bundler.py +337 -0
- icdev/tools/compliance/system_card_generator.py +309 -0
- icdev/tools/compliance/traceability_matrix.py +1281 -0
- icdev/tools/compliance/universal_classification_manager.py +1172 -0
- icdev/tools/compliance/xacta/__init__.py +2 -0
- icdev/tools/compliance/xacta/xacta_client.py +449 -0
- icdev/tools/compliance/xacta/xacta_export.py +557 -0
- icdev/tools/compliance/xacta/xacta_sync.py +333 -0
- icdev/tools/compliance/xai_assessor.py +231 -0
- icdev/tools/dashboard/__init__.py +1 -0
- icdev/tools/dashboard/api/__init__.py +1 -0
- icdev/tools/dashboard/api/_pipeline_state.py +17 -0
- icdev/tools/dashboard/api/activity.py +206 -0
- icdev/tools/dashboard/api/admin.py +176 -0
- icdev/tools/dashboard/api/agents.py +53 -0
- icdev/tools/dashboard/api/ai_accountability.py +163 -0
- icdev/tools/dashboard/api/ai_transparency.py +198 -0
- icdev/tools/dashboard/api/audit.py +58 -0
- icdev/tools/dashboard/api/batch.py +666 -0
- icdev/tools/dashboard/api/chat.py +241 -0
- icdev/tools/dashboard/api/cicd.py +219 -0
- icdev/tools/dashboard/api/code_quality.py +223 -0
- icdev/tools/dashboard/api/compliance.py +171 -0
- icdev/tools/dashboard/api/cpmp.py +915 -0
- icdev/tools/dashboard/api/diagrams.py +65 -0
- icdev/tools/dashboard/api/events.py +250 -0
- icdev/tools/dashboard/api/evidence.py +99 -0
- icdev/tools/dashboard/api/fedramp_20x.py +77 -0
- icdev/tools/dashboard/api/govcon.py +1095 -0
- icdev/tools/dashboard/api/intake.py +1171 -0
- icdev/tools/dashboard/api/lineage.py +163 -0
- icdev/tools/dashboard/api/metrics.py +155 -0
- icdev/tools/dashboard/api/nlq.py +72 -0
- icdev/tools/dashboard/api/orchestration.py +472 -0
- icdev/tools/dashboard/api/oscal.py +183 -0
- icdev/tools/dashboard/api/prod_audit.py +183 -0
- icdev/tools/dashboard/api/projects.py +191 -0
- icdev/tools/dashboard/api/proposals.py +1084 -0
- icdev/tools/dashboard/api/traces.py +363 -0
- icdev/tools/dashboard/api/usage.py +234 -0
- icdev/tools/dashboard/app.py +1986 -0
- icdev/tools/dashboard/auth.py +500 -0
- icdev/tools/dashboard/byok.py +245 -0
- icdev/tools/dashboard/chat_manager.py +675 -0
- icdev/tools/dashboard/config.py +116 -0
- icdev/tools/dashboard/diagram_definitions.py +642 -0
- icdev/tools/dashboard/nlq_processor.py +323 -0
- icdev/tools/dashboard/phase_loader.py +136 -0
- icdev/tools/dashboard/sse_manager.py +89 -0
- icdev/tools/dashboard/state_tracker.py +267 -0
- icdev/tools/dashboard/static/css/style.css +706 -0
- icdev/tools/dashboard/static/css/ux.css +2047 -0
- icdev/tools/dashboard/static/js/activity.js +322 -0
- icdev/tools/dashboard/static/js/api.js +161 -0
- icdev/tools/dashboard/static/js/batch.js +814 -0
- icdev/tools/dashboard/static/js/charts.js +618 -0
- icdev/tools/dashboard/static/js/chat.js +1514 -0
- icdev/tools/dashboard/static/js/kanban.js +113 -0
- icdev/tools/dashboard/static/js/live.js +569 -0
- icdev/tools/dashboard/static/js/mermaid-icdev.js +332 -0
- icdev/tools/dashboard/static/js/proposals.js +588 -0
- icdev/tools/dashboard/static/js/shortcuts.js +544 -0
- icdev/tools/dashboard/static/js/tables.js +652 -0
- icdev/tools/dashboard/static/js/tour.js +524 -0
- icdev/tools/dashboard/static/js/ux.js +942 -0
- icdev/tools/dashboard/templates/404.html +10 -0
- icdev/tools/dashboard/templates/activity.html +80 -0
- icdev/tools/dashboard/templates/admin/users.html +144 -0
- icdev/tools/dashboard/templates/ai_accountability.html +235 -0
- icdev/tools/dashboard/templates/ai_transparency.html +263 -0
- icdev/tools/dashboard/templates/base.html +104 -0
- icdev/tools/dashboard/templates/batch.html +23 -0
- icdev/tools/dashboard/templates/chat.html +332 -0
- icdev/tools/dashboard/templates/children.html +149 -0
- icdev/tools/dashboard/templates/cicd.html +253 -0
- icdev/tools/dashboard/templates/code_quality.html +214 -0
- icdev/tools/dashboard/templates/cpmp/cor_detail.html +220 -0
- icdev/tools/dashboard/templates/cpmp/cor_portal.html +91 -0
- icdev/tools/dashboard/templates/cpmp/deliverable_detail.html +197 -0
- icdev/tools/dashboard/templates/cpmp/detail.html +578 -0
- icdev/tools/dashboard/templates/cpmp/portfolio.html +202 -0
- icdev/tools/dashboard/templates/dev_profiles.html +304 -0
- icdev/tools/dashboard/templates/diagrams.html +224 -0
- icdev/tools/dashboard/templates/events/timeline.html +232 -0
- icdev/tools/dashboard/templates/evidence.html +134 -0
- icdev/tools/dashboard/templates/fedramp_20x.html +207 -0
- icdev/tools/dashboard/templates/gateway.html +244 -0
- icdev/tools/dashboard/templates/govcon/capabilities.html +135 -0
- icdev/tools/dashboard/templates/govcon/pipeline.html +214 -0
- icdev/tools/dashboard/templates/govcon/requirements.html +120 -0
- icdev/tools/dashboard/templates/index.html +254 -0
- icdev/tools/dashboard/templates/lineage.html +141 -0
- icdev/tools/dashboard/templates/login.html +51 -0
- icdev/tools/dashboard/templates/monitoring/overview.html +193 -0
- icdev/tools/dashboard/templates/orchestration/dashboard.html +545 -0
- icdev/tools/dashboard/templates/oscal.html +263 -0
- icdev/tools/dashboard/templates/phases.html +150 -0
- icdev/tools/dashboard/templates/prod_audit.html +280 -0
- icdev/tools/dashboard/templates/profile.html +183 -0
- icdev/tools/dashboard/templates/projects/detail.html +583 -0
- icdev/tools/dashboard/templates/projects/list.html +47 -0
- icdev/tools/dashboard/templates/proposals/detail.html +1253 -0
- icdev/tools/dashboard/templates/proposals/list.html +179 -0
- icdev/tools/dashboard/templates/proposals/section_detail.html +193 -0
- icdev/tools/dashboard/templates/provenance.html +181 -0
- icdev/tools/dashboard/templates/query/nlq.html +234 -0
- icdev/tools/dashboard/templates/quick_paths.html +69 -0
- icdev/tools/dashboard/templates/traces.html +155 -0
- icdev/tools/dashboard/templates/translation_detail.html +199 -0
- icdev/tools/dashboard/templates/translations.html +162 -0
- icdev/tools/dashboard/templates/usage.html +225 -0
- icdev/tools/dashboard/templates/wizard.html +539 -0
- icdev/tools/dashboard/templates/xai.html +208 -0
- icdev/tools/dashboard/ux_helpers.py +962 -0
- icdev/tools/dashboard/websocket.py +81 -0
- icdev/tools/db/__init__.py +1 -0
- icdev/tools/db/backup.py +312 -0
- icdev/tools/db/backup_manager.py +832 -0
- icdev/tools/db/init_icdev_db.py +5900 -0
- icdev/tools/db/migrate.py +178 -0
- icdev/tools/db/migration_runner.py +549 -0
- icdev/tools/db/migrations/001_baseline/meta.json +9 -0
- icdev/tools/db/migrations/001_baseline/up.py +68 -0
- icdev/tools/db/migrations/002_memory_enhancements/down.sql +8 -0
- icdev/tools/db/migrations/002_memory_enhancements/meta.json +9 -0
- icdev/tools/db/migrations/002_memory_enhancements/up.py +118 -0
- icdev/tools/db/migrations/003_dev_profiles/meta.json +8 -0
- icdev/tools/db/migrations/003_dev_profiles/up.py +93 -0
- icdev/tools/db/migrations/004_innovation_engine/down.py +19 -0
- icdev/tools/db/migrations/004_innovation_engine/up.py +227 -0
- icdev/tools/db/migrations/005_phase_37_ai_security/down.py +19 -0
- icdev/tools/db/migrations/005_phase_37_ai_security/up.py +258 -0
- icdev/tools/db/migrations/006_phase_36_evolution/down.py +21 -0
- icdev/tools/db/migrations/006_phase_36_evolution/up.py +323 -0
- icdev/tools/db/migrations/007_phase_38_cloud/down.py +14 -0
- icdev/tools/db/migrations/007_phase_38_cloud/up.py +110 -0
- icdev/tools/db/migrations/008_phase36_37_integration/up.py +55 -0
- icdev/tools/db/migrations/__init__.py +2 -0
- icdev/tools/devsecops/__init__.py +2 -0
- icdev/tools/devsecops/attestation_manager.py +458 -0
- icdev/tools/devsecops/network_segmentation_generator.py +614 -0
- icdev/tools/devsecops/pdp_config_generator.py +1256 -0
- icdev/tools/devsecops/pipeline_security_generator.py +484 -0
- icdev/tools/devsecops/policy_generator.py +653 -0
- icdev/tools/devsecops/profile_manager.py +388 -0
- icdev/tools/devsecops/service_mesh_generator.py +1073 -0
- icdev/tools/devsecops/zta_maturity_scorer.py +368 -0
- icdev/tools/devsecops/zta_terraform_generator.py +1303 -0
- icdev/tools/dx/__init__.py +3 -0
- icdev/tools/dx/companion.py +266 -0
- icdev/tools/dx/instruction_generator.py +753 -0
- icdev/tools/dx/mcp_config_generator.py +282 -0
- icdev/tools/dx/skill_translator.py +425 -0
- icdev/tools/dx/tool_detector.py +144 -0
- icdev/tools/extensions/__init__.py +21 -0
- icdev/tools/extensions/builtins/010_ai_governance_chat.py +277 -0
- icdev/tools/extensions/builtins/__init__.py +2 -0
- icdev/tools/extensions/extension_manager.py +455 -0
- icdev/tools/infra/__init__.py +1 -0
- icdev/tools/infra/ansible_generator.py +869 -0
- icdev/tools/infra/dockerfile_generator.py +361 -0
- icdev/tools/infra/infra_status.py +393 -0
- icdev/tools/infra/ironbank_metadata_generator.py +411 -0
- icdev/tools/infra/k8s_generator.py +1002 -0
- icdev/tools/infra/pipeline_generator.py +832 -0
- icdev/tools/infra/rollback.py +400 -0
- icdev/tools/infra/terraform_generator.py +1142 -0
- icdev/tools/infra/terraform_generator_azure.py +1254 -0
- icdev/tools/infra/terraform_generator_gcp.py +953 -0
- icdev/tools/infra/terraform_generator_ibm.py +360 -0
- icdev/tools/infra/terraform_generator_oci.py +919 -0
- icdev/tools/infra/terraform_generator_onprem.py +319 -0
- icdev/tools/innovation/__init__.py +8 -0
- icdev/tools/innovation/competitive_intel.py +492 -0
- icdev/tools/innovation/innovation_manager.py +681 -0
- icdev/tools/innovation/introspective_analyzer.py +774 -0
- icdev/tools/innovation/register_external_patterns.py +440 -0
- icdev/tools/innovation/signal_ranker.py +1038 -0
- icdev/tools/innovation/solution_generator.py +697 -0
- icdev/tools/innovation/standards_monitor.py +466 -0
- icdev/tools/innovation/trend_detector.py +1046 -0
- icdev/tools/innovation/triage_engine.py +1149 -0
- icdev/tools/innovation/web_scanner.py +894 -0
- icdev/tools/installer/__init__.py +1 -0
- icdev/tools/installer/compliance_configurator.py +637 -0
- icdev/tools/installer/installer.py +1711 -0
- icdev/tools/installer/module_registry.py +805 -0
- icdev/tools/installer/platform_setup.py +961 -0
- icdev/tools/integration/__init__.py +2 -0
- icdev/tools/integration/approval_manager.py +561 -0
- icdev/tools/integration/doors_exporter.py +627 -0
- icdev/tools/integration/gitlab_connector.py +784 -0
- icdev/tools/integration/jira_connector.py +774 -0
- icdev/tools/integration/servicenow_connector.py +693 -0
- icdev/tools/knowledge/__init__.py +1 -0
- icdev/tools/knowledge/knowledge_ingest.py +293 -0
- icdev/tools/knowledge/pattern_detector.py +693 -0
- icdev/tools/knowledge/recommendation_engine.py +461 -0
- icdev/tools/knowledge/self_heal_analyzer.py +504 -0
- icdev/tools/llm/__init__.py +72 -0
- icdev/tools/llm/anthropic_provider.py +170 -0
- icdev/tools/llm/azure_openai_provider.py +338 -0
- icdev/tools/llm/bedrock_provider.py +315 -0
- icdev/tools/llm/embedding_provider.py +438 -0
- icdev/tools/llm/gemini_provider.py +381 -0
- icdev/tools/llm/ibm_watsonx_provider.py +232 -0
- icdev/tools/llm/oci_genai_provider.py +462 -0
- icdev/tools/llm/ollama_provider.py +340 -0
- icdev/tools/llm/openai_provider.py +225 -0
- icdev/tools/llm/provider.py +355 -0
- icdev/tools/llm/provider_sdk.py +175 -0
- icdev/tools/llm/router.py +780 -0
- icdev/tools/llm/vertex_ai_provider.py +374 -0
- icdev/tools/maintenance/__init__.py +2 -0
- icdev/tools/maintenance/dependency_scanner.py +1030 -0
- icdev/tools/maintenance/maintenance_auditor.py +815 -0
- icdev/tools/maintenance/remediation_engine.py +966 -0
- icdev/tools/maintenance/vulnerability_checker.py +987 -0
- icdev/tools/mbse/__init__.py +3 -0
- icdev/tools/mbse/des_assessor.py +1186 -0
- icdev/tools/mbse/des_report_generator.py +800 -0
- icdev/tools/mbse/diagram_extractor.py +811 -0
- icdev/tools/mbse/digital_thread.py +1665 -0
- icdev/tools/mbse/model_code_generator.py +1122 -0
- icdev/tools/mbse/model_control_mapper.py +420 -0
- icdev/tools/mbse/pi_model_tracker.py +1093 -0
- icdev/tools/mbse/reqif_parser.py +1483 -0
- icdev/tools/mbse/sync_engine.py +1805 -0
- icdev/tools/mbse/xmi_parser.py +1573 -0
- icdev/tools/mcp/__init__.py +1 -0
- icdev/tools/mcp/base_server.py +535 -0
- icdev/tools/mcp/builder_server.py +725 -0
- icdev/tools/mcp/compliance_server.py +1407 -0
- icdev/tools/mcp/context_indexer.py +199 -0
- icdev/tools/mcp/context_server.py +305 -0
- icdev/tools/mcp/core_server.py +679 -0
- icdev/tools/mcp/devsecops_server.py +432 -0
- icdev/tools/mcp/gap_handlers.py +1079 -0
- icdev/tools/mcp/gateway_server.py +339 -0
- icdev/tools/mcp/generate_registry.py +623 -0
- icdev/tools/mcp/infra_server.py +264 -0
- icdev/tools/mcp/innovation_server.py +316 -0
- icdev/tools/mcp/integration_server.py +527 -0
- icdev/tools/mcp/knowledge_server.py +429 -0
- icdev/tools/mcp/maintenance_server.py +248 -0
- icdev/tools/mcp/marketplace_server.py +499 -0
- icdev/tools/mcp/mbse_server.py +398 -0
- icdev/tools/mcp/modernization_server.py +496 -0
- icdev/tools/mcp/observability_server.py +354 -0
- icdev/tools/mcp/requirements_server.py +415 -0
- icdev/tools/mcp/simulation_server.py +468 -0
- icdev/tools/mcp/standalone/__init__.py +2 -0
- icdev/tools/mcp/standalone/builder.py +59 -0
- icdev/tools/mcp/standalone/compliance.py +59 -0
- icdev/tools/mcp/standalone/core.py +59 -0
- icdev/tools/mcp/standalone/knowledge.py +59 -0
- icdev/tools/mcp/standalone/maintenance.py +59 -0
- icdev/tools/mcp/supply_chain_server.py +476 -0
- icdev/tools/mcp/tool_registry.py +2008 -0
- icdev/tools/mcp/unified_server.py +158 -0
- icdev/tools/memory/__init__.py +2 -0
- icdev/tools/memory/auto_capture.py +347 -0
- icdev/tools/memory/embed_memory.py +158 -0
- icdev/tools/memory/history_compressor.py +334 -0
- icdev/tools/memory/hybrid_search.py +236 -0
- icdev/tools/memory/maintenance_cron.py +289 -0
- icdev/tools/memory/memory_consolidation.py +444 -0
- icdev/tools/memory/memory_db.py +133 -0
- icdev/tools/memory/memory_read.py +102 -0
- icdev/tools/memory/memory_write.py +222 -0
- icdev/tools/memory/semantic_search.py +139 -0
- icdev/tools/memory/time_decay.py +435 -0
- icdev/tools/modernization/__init__.py +3 -0
- icdev/tools/modernization/architecture_extractor.py +734 -0
- icdev/tools/modernization/compliance_bridge.py +1499 -0
- icdev/tools/modernization/db_migration_planner.py +1385 -0
- icdev/tools/modernization/doc_generator.py +1428 -0
- icdev/tools/modernization/framework_migrator.py +1525 -0
- icdev/tools/modernization/legacy_analyzer.py +1948 -0
- icdev/tools/modernization/migration_code_generator.py +1639 -0
- icdev/tools/modernization/migration_report_generator.py +1653 -0
- icdev/tools/modernization/migration_tracker.py +1726 -0
- icdev/tools/modernization/monolith_decomposer.py +1508 -0
- icdev/tools/modernization/seven_r_assessor.py +1658 -0
- icdev/tools/modernization/strangler_fig_manager.py +1705 -0
- icdev/tools/modernization/ui_analyzer.py +771 -0
- icdev/tools/modernization/version_migrator.py +1392 -0
- icdev/tools/monitor/__init__.py +1 -0
- icdev/tools/monitor/alert_correlator.py +495 -0
- icdev/tools/monitor/auto_resolver.py +612 -0
- icdev/tools/monitor/health_checker.py +509 -0
- icdev/tools/monitor/heartbeat_daemon.py +792 -0
- icdev/tools/monitor/log_analyzer.py +516 -0
- icdev/tools/monitor/metric_collector.py +496 -0
- icdev/tools/mosa/__init__.py +10 -0
- icdev/tools/mosa/icd_generator.py +370 -0
- icdev/tools/mosa/modular_design_analyzer.py +683 -0
- icdev/tools/mosa/mosa_code_enforcer.py +349 -0
- icdev/tools/mosa/tsp_generator.py +265 -0
- icdev/tools/observability/__init__.py +100 -0
- icdev/tools/observability/genai_attributes.py +88 -0
- icdev/tools/observability/instrumentation.py +140 -0
- icdev/tools/observability/mlflow_exporter.py +194 -0
- icdev/tools/observability/otel_tracer.py +168 -0
- icdev/tools/observability/provenance/__init__.py +3 -0
- icdev/tools/observability/provenance/prov_recorder.py +324 -0
- icdev/tools/observability/shap/__init__.py +3 -0
- icdev/tools/observability/shap/agent_shap.py +275 -0
- icdev/tools/observability/sqlite_tracer.py +361 -0
- icdev/tools/observability/trace_context.py +205 -0
- icdev/tools/observability/tracer.py +230 -0
- icdev/tools/orchestration/__init__.py +2 -0
- icdev/tools/orchestration/workflow_composer.py +361 -0
- icdev/tools/project/__init__.py +1 -0
- icdev/tools/project/manifest_loader.py +418 -0
- icdev/tools/project/project_create.py +350 -0
- icdev/tools/project/project_list.py +174 -0
- icdev/tools/project/project_scaffold.py +1715 -0
- icdev/tools/project/project_status.py +479 -0
- icdev/tools/project/session_context_builder.py +757 -0
- icdev/tools/project/validate_manifest.py +55 -0
- icdev/tools/registry/__init__.py +10 -0
- icdev/tools/registry/absorption_engine.py +832 -0
- icdev/tools/registry/capability_evaluator.py +668 -0
- icdev/tools/registry/child_registry.py +617 -0
- icdev/tools/registry/cross_pollinator.py +1065 -0
- icdev/tools/registry/genome_manager.py +671 -0
- icdev/tools/registry/learning_collector.py +912 -0
- icdev/tools/registry/propagation_manager.py +942 -0
- icdev/tools/registry/staging_manager.py +742 -0
- icdev/tools/registry/telemetry_collector.py +423 -0
- icdev/tools/requirements/__init__.py +1 -0
- icdev/tools/requirements/ai_governance_scorer.py +208 -0
- icdev/tools/requirements/boundary_analyzer.py +1293 -0
- icdev/tools/requirements/clarification_engine.py +618 -0
- icdev/tools/requirements/complexity_scorer.py +387 -0
- icdev/tools/requirements/consistency_analyzer.py +803 -0
- icdev/tools/requirements/constitution_manager.py +605 -0
- icdev/tools/requirements/decomposition_engine.py +778 -0
- icdev/tools/requirements/document_extractor.py +1016 -0
- icdev/tools/requirements/elicitation_techniques.py +519 -0
- icdev/tools/requirements/gap_detector.py +271 -0
- icdev/tools/requirements/intake_engine.py +2188 -0
- icdev/tools/requirements/prd_generator.py +847 -0
- icdev/tools/requirements/prd_validator.py +595 -0
- icdev/tools/requirements/readiness_scorer.py +313 -0
- icdev/tools/requirements/spec_organizer.py +1029 -0
- icdev/tools/requirements/spec_quality_checker.py +1097 -0
- icdev/tools/requirements/traceability_builder.py +579 -0
- icdev/tools/resilience/__init__.py +34 -0
- icdev/tools/resilience/circuit_breaker.py +340 -0
- icdev/tools/resilience/correlation.py +150 -0
- icdev/tools/resilience/errors.py +81 -0
- icdev/tools/resilience/retry.py +95 -0
- icdev/tools/schemas/__init__.py +27 -0
- icdev/tools/schemas/chat.py +61 -0
- icdev/tools/schemas/compliance.py +56 -0
- icdev/tools/schemas/core.py +85 -0
- icdev/tools/schemas/innovation.py +37 -0
- icdev/tools/schemas/validation.py +109 -0
- icdev/tools/sdk/__init__.py +3 -0
- icdev/tools/sdk/icdev_client.py +218 -0
- icdev/tools/security/__init__.py +1 -0
- icdev/tools/security/agent_output_validator.py +330 -0
- icdev/tools/security/agent_trust_scorer.py +466 -0
- icdev/tools/security/ai_bom_generator.py +725 -0
- icdev/tools/security/ai_telemetry_logger.py +469 -0
- icdev/tools/security/atlas_red_team.py +543 -0
- icdev/tools/security/code_pattern_scanner.py +378 -0
- icdev/tools/security/confabulation_detector.py +271 -0
- icdev/tools/security/container_scanner.py +491 -0
- icdev/tools/security/dependency_auditor.py +944 -0
- icdev/tools/security/endpoint_security_scanner.py +579 -0
- icdev/tools/security/mcp_tool_authorizer.py +243 -0
- icdev/tools/security/prompt_injection_detector.py +737 -0
- icdev/tools/security/sast_runner.py +948 -0
- icdev/tools/security/secret_detector.py +378 -0
- icdev/tools/security/tool_chain_validator.py +357 -0
- icdev/tools/security/vuln_scanner.py +539 -0
- icdev/tools/simulation/__init__.py +2 -0
- icdev/tools/simulation/coa_generator.py +1552 -0
- icdev/tools/simulation/monte_carlo.py +758 -0
- icdev/tools/simulation/scenario_manager.py +1073 -0
- icdev/tools/simulation/simulation_engine.py +1104 -0
- icdev/tools/supply_chain/__init__.py +2 -0
- icdev/tools/supply_chain/cve_triager.py +705 -0
- icdev/tools/supply_chain/dependency_graph.py +645 -0
- icdev/tools/supply_chain/isa_manager.py +540 -0
- icdev/tools/supply_chain/scrm_assessor.py +546 -0
- icdev/tools/testing/__init__.py +2 -0
- icdev/tools/testing/acceptance_validator.py +411 -0
- icdev/tools/testing/claude_dir_validator.py +831 -0
- icdev/tools/testing/data_types.py +199 -0
- icdev/tools/testing/e2e_runner.py +715 -0
- icdev/tools/testing/fuzz_cli.py +306 -0
- icdev/tools/testing/health_check.py +483 -0
- icdev/tools/testing/platform_check.py +143 -0
- icdev/tools/testing/production_audit.py +1862 -0
- icdev/tools/testing/production_remediate.py +804 -0
- icdev/tools/testing/screenshot_validator.py +539 -0
- icdev/tools/testing/smoke_test.py +283 -0
- icdev/tools/testing/test_agent_models.py +117 -0
- icdev/tools/testing/test_orchestrator.py +957 -0
- icdev/tools/testing/utils.py +229 -0
- icdev/tools/translation/__init__.py +17 -0
- icdev/tools/translation/code_translator.py +550 -0
- icdev/tools/translation/dependency_mapper.py +277 -0
- icdev/tools/translation/feature_map.py +395 -0
- icdev/tools/translation/project_assembler.py +439 -0
- icdev/tools/translation/source_extractor.py +609 -0
- icdev/tools/translation/test_translator.py +333 -0
- icdev/tools/translation/translation_manager.py +582 -0
- icdev/tools/translation/translation_validator.py +662 -0
- icdev/tools/translation/type_checker.py +371 -0
- icdev-1.0.0.dist-info/METADATA +868 -0
- icdev-1.0.0.dist-info/RECORD +1105 -0
- icdev-1.0.0.dist-info/WHEEL +5 -0
- icdev-1.0.0.dist-info/entry_points.txt +9 -0
- icdev-1.0.0.dist-info/licenses/LICENSE +254 -0
- icdev-1.0.0.dist-info/licenses/NOTICE +268 -0
- icdev-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,1705 @@
|
|
|
1
|
+
# [TEMPLATE: CUI // SP-CTI]
|
|
2
|
+
#!/usr/bin/env python3
|
|
3
|
+
"""Strangler Fig Pattern Migration Manager for ICDEV DoD Modernization.
|
|
4
|
+
|
|
5
|
+
Manages incremental legacy-to-modern cutover using the strangler fig pattern.
|
|
6
|
+
Tracks per-component migration status, generates API gateway routing configs,
|
|
7
|
+
produces anti-corruption layer (ACL) adapter code, and validates coexistence
|
|
8
|
+
health between legacy and modern systems during the transition period.
|
|
9
|
+
|
|
10
|
+
The strangler fig pattern allows legacy systems to be incrementally replaced
|
|
11
|
+
by routing requests through a facade that dispatches to either the legacy or
|
|
12
|
+
modern implementation on a per-component basis. As each component is migrated
|
|
13
|
+
and validated, traffic is shifted from legacy to modern until the old system
|
|
14
|
+
can be fully decommissioned.
|
|
15
|
+
|
|
16
|
+
Usage:
|
|
17
|
+
# Initialize strangler fig tracking for a migration plan
|
|
18
|
+
python tools/modernization/strangler_fig_manager.py \\
|
|
19
|
+
--plan-id mplan-abc123 --create
|
|
20
|
+
|
|
21
|
+
# Check cutover status dashboard
|
|
22
|
+
python tools/modernization/strangler_fig_manager.py \\
|
|
23
|
+
--plan-id mplan-abc123 --status
|
|
24
|
+
|
|
25
|
+
# Track a component cutover to parallel mode
|
|
26
|
+
python tools/modernization/strangler_fig_manager.py \\
|
|
27
|
+
--plan-id mplan-abc123 --cutover --component-id lcomp-xyz789 --to parallel
|
|
28
|
+
|
|
29
|
+
# Generate routing configuration
|
|
30
|
+
python tools/modernization/strangler_fig_manager.py \\
|
|
31
|
+
--plan-id mplan-abc123 --routing --json
|
|
32
|
+
|
|
33
|
+
# Check coexistence health
|
|
34
|
+
python tools/modernization/strangler_fig_manager.py \\
|
|
35
|
+
--plan-id mplan-abc123 --health
|
|
36
|
+
|
|
37
|
+
# Generate cutover checklist for a component
|
|
38
|
+
python tools/modernization/strangler_fig_manager.py \\
|
|
39
|
+
--plan-id mplan-abc123 --checklist --component-id lcomp-xyz789
|
|
40
|
+
|
|
41
|
+
# Execute cutover (mark as modern)
|
|
42
|
+
python tools/modernization/strangler_fig_manager.py \\
|
|
43
|
+
--plan-id mplan-abc123 --execute-cutover --component-id lcomp-xyz789
|
|
44
|
+
|
|
45
|
+
Classification: CUI // SP-CTI
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
import argparse
|
|
49
|
+
import collections
|
|
50
|
+
import json
|
|
51
|
+
import sqlite3
|
|
52
|
+
import textwrap
|
|
53
|
+
import uuid
|
|
54
|
+
from datetime import datetime, timezone
|
|
55
|
+
from pathlib import Path
|
|
56
|
+
from icdev._paths import get_project_root
|
|
57
|
+
|
|
58
|
+
# ---------------------------------------------------------------------------
|
|
59
|
+
# Configuration
|
|
60
|
+
# ---------------------------------------------------------------------------
|
|
61
|
+
|
|
62
|
+
BASE_DIR = get_project_root()
|
|
63
|
+
DB_PATH = BASE_DIR / "data" / "icdev.db"
|
|
64
|
+
|
|
65
|
+
# Valid cutover statuses for the strangler fig lifecycle
|
|
66
|
+
CUTOVER_STATUSES = ("legacy", "parallel", "modern", "decommissioned")
|
|
67
|
+
|
|
68
|
+
# Mapping from strangler fig cutover status to migration_task status
|
|
69
|
+
CUTOVER_TO_TASK_STATUS = {
|
|
70
|
+
"legacy": "pending",
|
|
71
|
+
"parallel": "in_progress",
|
|
72
|
+
"modern": "completed",
|
|
73
|
+
"decommissioned": "completed",
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
# Classification banner for generated artifacts
|
|
77
|
+
CUI_BANNER = "CUI // SP-CTI"
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
# ---------------------------------------------------------------------------
|
|
81
|
+
# Database helper
|
|
82
|
+
# ---------------------------------------------------------------------------
|
|
83
|
+
|
|
84
|
+
def _get_db():
|
|
85
|
+
"""Return a sqlite3 connection to the ICDEV operational database.
|
|
86
|
+
|
|
87
|
+
The database file must already exist (created by tools/db/init_icdev_db.py).
|
|
88
|
+
Uses row_factory = sqlite3.Row for dict-like access.
|
|
89
|
+
"""
|
|
90
|
+
if not DB_PATH.exists():
|
|
91
|
+
raise FileNotFoundError(
|
|
92
|
+
f"ICDEV database not found at {DB_PATH}. "
|
|
93
|
+
"Run 'python tools/db/init_icdev_db.py' first."
|
|
94
|
+
)
|
|
95
|
+
conn = sqlite3.connect(str(DB_PATH))
|
|
96
|
+
conn.row_factory = sqlite3.Row
|
|
97
|
+
conn.execute("PRAGMA journal_mode=WAL")
|
|
98
|
+
conn.execute("PRAGMA foreign_keys=ON")
|
|
99
|
+
return conn
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def _log_audit(conn, project_id, event_type, actor, action, details=None,
|
|
103
|
+
classification="CUI"):
|
|
104
|
+
"""Write an immutable audit trail entry within an existing connection.
|
|
105
|
+
|
|
106
|
+
Audit trail is append-only per NIST 800-53 AU controls.
|
|
107
|
+
"""
|
|
108
|
+
conn.execute(
|
|
109
|
+
"""INSERT INTO audit_trail
|
|
110
|
+
(project_id, event_type, actor, action, details, classification)
|
|
111
|
+
VALUES (?, ?, ?, ?, ?, ?)""",
|
|
112
|
+
(
|
|
113
|
+
project_id,
|
|
114
|
+
event_type,
|
|
115
|
+
actor,
|
|
116
|
+
action,
|
|
117
|
+
json.dumps(details) if details else None,
|
|
118
|
+
classification,
|
|
119
|
+
),
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
# ---------------------------------------------------------------------------
|
|
124
|
+
# Helper: resolve project_id from plan
|
|
125
|
+
# ---------------------------------------------------------------------------
|
|
126
|
+
|
|
127
|
+
def _get_plan_project_id(conn, plan_id):
|
|
128
|
+
"""Look up the project_id for a migration plan via legacy_applications."""
|
|
129
|
+
row = conn.execute(
|
|
130
|
+
"""SELECT la.project_id
|
|
131
|
+
FROM migration_plans mp
|
|
132
|
+
JOIN legacy_applications la ON mp.legacy_app_id = la.id
|
|
133
|
+
WHERE mp.id = ?""",
|
|
134
|
+
(plan_id,),
|
|
135
|
+
).fetchone()
|
|
136
|
+
return row["project_id"] if row else None
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
# ---------------------------------------------------------------------------
|
|
140
|
+
# 1. Create strangler fig plan
|
|
141
|
+
# ---------------------------------------------------------------------------
|
|
142
|
+
|
|
143
|
+
def create_strangler_plan(plan_id):
|
|
144
|
+
"""Initialize strangler fig tracking for a migration plan.
|
|
145
|
+
|
|
146
|
+
Verifies the plan exists and uses the strangler_fig migration approach,
|
|
147
|
+
then creates cutover tracking tasks for every legacy component and
|
|
148
|
+
catalogues all legacy API endpoints.
|
|
149
|
+
|
|
150
|
+
Args:
|
|
151
|
+
plan_id: Migration plan ID (must exist in migration_plans).
|
|
152
|
+
|
|
153
|
+
Returns:
|
|
154
|
+
dict with plan summary including component and API counts.
|
|
155
|
+
"""
|
|
156
|
+
conn = _get_db()
|
|
157
|
+
try:
|
|
158
|
+
plan = conn.execute(
|
|
159
|
+
"SELECT * FROM migration_plans WHERE id = ?", (plan_id,)
|
|
160
|
+
).fetchone()
|
|
161
|
+
|
|
162
|
+
if not plan:
|
|
163
|
+
raise ValueError(f"Migration plan '{plan_id}' not found.")
|
|
164
|
+
|
|
165
|
+
if plan["migration_approach"] != "strangler_fig":
|
|
166
|
+
raise ValueError(
|
|
167
|
+
f"Plan '{plan_id}' uses migration_approach='{plan['migration_approach']}'. "
|
|
168
|
+
"Strangler fig manager requires migration_approach='strangler_fig'."
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
legacy_app_id = plan["legacy_app_id"]
|
|
172
|
+
|
|
173
|
+
# Fetch all legacy components for this application
|
|
174
|
+
components = conn.execute(
|
|
175
|
+
"SELECT * FROM legacy_components WHERE legacy_app_id = ?",
|
|
176
|
+
(legacy_app_id,),
|
|
177
|
+
).fetchall()
|
|
178
|
+
|
|
179
|
+
# Fetch all legacy APIs for this application
|
|
180
|
+
apis = conn.execute(
|
|
181
|
+
"SELECT * FROM legacy_apis WHERE legacy_app_id = ?",
|
|
182
|
+
(legacy_app_id,),
|
|
183
|
+
).fetchall()
|
|
184
|
+
|
|
185
|
+
# Create a cutover migration_task for each component
|
|
186
|
+
now = datetime.now(timezone.utc).isoformat()
|
|
187
|
+
tasks_created = 0
|
|
188
|
+
for comp in components:
|
|
189
|
+
task_id = f"mtask-{uuid.uuid4().hex[:12]}"
|
|
190
|
+
description = json.dumps({
|
|
191
|
+
"strangler_fig_status": "legacy",
|
|
192
|
+
"component_type": comp["component_type"],
|
|
193
|
+
"qualified_name": comp["qualified_name"],
|
|
194
|
+
})
|
|
195
|
+
try:
|
|
196
|
+
conn.execute(
|
|
197
|
+
"""INSERT INTO migration_tasks
|
|
198
|
+
(id, plan_id, legacy_component_id, task_type, title,
|
|
199
|
+
description, status, created_at)
|
|
200
|
+
VALUES (?, ?, ?, 'cutover', ?, ?, 'pending', ?)""",
|
|
201
|
+
(
|
|
202
|
+
task_id,
|
|
203
|
+
plan_id,
|
|
204
|
+
comp["id"],
|
|
205
|
+
f"Cutover: {comp['name']}",
|
|
206
|
+
description,
|
|
207
|
+
now,
|
|
208
|
+
),
|
|
209
|
+
)
|
|
210
|
+
tasks_created += 1
|
|
211
|
+
except sqlite3.IntegrityError:
|
|
212
|
+
pass # Task may already exist
|
|
213
|
+
|
|
214
|
+
# Update total_tasks on the plan
|
|
215
|
+
conn.execute(
|
|
216
|
+
"""UPDATE migration_plans
|
|
217
|
+
SET total_tasks = total_tasks + ?, status = 'in_progress',
|
|
218
|
+
updated_at = ?
|
|
219
|
+
WHERE id = ?""",
|
|
220
|
+
(tasks_created, now, plan_id),
|
|
221
|
+
)
|
|
222
|
+
|
|
223
|
+
# Log audit event
|
|
224
|
+
project_id = _get_plan_project_id(conn, plan_id)
|
|
225
|
+
_log_audit(
|
|
226
|
+
conn,
|
|
227
|
+
project_id=project_id,
|
|
228
|
+
event_type="migration_planned",
|
|
229
|
+
actor="strangler-fig-manager",
|
|
230
|
+
action=f"Initialized strangler fig tracking for plan {plan_id}",
|
|
231
|
+
details={
|
|
232
|
+
"plan_id": plan_id,
|
|
233
|
+
"legacy_app_id": legacy_app_id,
|
|
234
|
+
"components": len(components),
|
|
235
|
+
"apis": len(apis),
|
|
236
|
+
"tasks_created": tasks_created,
|
|
237
|
+
},
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
conn.commit()
|
|
241
|
+
|
|
242
|
+
summary = {
|
|
243
|
+
"plan_id": plan_id,
|
|
244
|
+
"plan_name": plan["plan_name"],
|
|
245
|
+
"legacy_app_id": legacy_app_id,
|
|
246
|
+
"strategy": plan["strategy"],
|
|
247
|
+
"migration_approach": plan["migration_approach"],
|
|
248
|
+
"component_count": len(components),
|
|
249
|
+
"api_count": len(apis),
|
|
250
|
+
"tasks_created": tasks_created,
|
|
251
|
+
"status": "in_progress",
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
print(f"[INFO] Strangler fig plan initialized for '{plan['plan_name']}'")
|
|
255
|
+
print(f" Components: {len(components)} | APIs: {len(apis)} | Tasks: {tasks_created}")
|
|
256
|
+
return summary
|
|
257
|
+
|
|
258
|
+
finally:
|
|
259
|
+
conn.close()
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
# ---------------------------------------------------------------------------
|
|
263
|
+
# 2. Register facade
|
|
264
|
+
# ---------------------------------------------------------------------------
|
|
265
|
+
|
|
266
|
+
def register_facade(plan_id, legacy_endpoint, modern_endpoint, component_id=None):
|
|
267
|
+
"""Register an endpoint facade mapping for strangler fig routing.
|
|
268
|
+
|
|
269
|
+
Stores the facade as a migration_task with task_type='generate_facade'
|
|
270
|
+
and routing metadata in the description field as JSON.
|
|
271
|
+
|
|
272
|
+
Args:
|
|
273
|
+
plan_id: Migration plan ID.
|
|
274
|
+
legacy_endpoint: Legacy endpoint path (e.g. '/api/v1/users').
|
|
275
|
+
modern_endpoint: Modern endpoint path (e.g. '/api/v2/users').
|
|
276
|
+
component_id: Optional legacy component ID this facade covers.
|
|
277
|
+
|
|
278
|
+
Returns:
|
|
279
|
+
dict with the facade registration details.
|
|
280
|
+
"""
|
|
281
|
+
conn = _get_db()
|
|
282
|
+
try:
|
|
283
|
+
plan = conn.execute(
|
|
284
|
+
"SELECT * FROM migration_plans WHERE id = ?", (plan_id,)
|
|
285
|
+
).fetchone()
|
|
286
|
+
if not plan:
|
|
287
|
+
raise ValueError(f"Migration plan '{plan_id}' not found.")
|
|
288
|
+
|
|
289
|
+
task_id = f"mtask-{uuid.uuid4().hex[:12]}"
|
|
290
|
+
now = datetime.now(timezone.utc).isoformat()
|
|
291
|
+
|
|
292
|
+
facade_props = {
|
|
293
|
+
"legacy_path": legacy_endpoint,
|
|
294
|
+
"modern_path": modern_endpoint,
|
|
295
|
+
"routing": "legacy",
|
|
296
|
+
"component_id": component_id,
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
conn.execute(
|
|
300
|
+
"""INSERT INTO migration_tasks
|
|
301
|
+
(id, plan_id, legacy_component_id, task_type, title,
|
|
302
|
+
description, status, created_at)
|
|
303
|
+
VALUES (?, ?, ?, 'generate_facade', ?, ?, 'in_progress', ?)""",
|
|
304
|
+
(
|
|
305
|
+
task_id,
|
|
306
|
+
plan_id,
|
|
307
|
+
component_id,
|
|
308
|
+
f"Facade: {legacy_endpoint} -> {modern_endpoint}",
|
|
309
|
+
json.dumps(facade_props),
|
|
310
|
+
now,
|
|
311
|
+
),
|
|
312
|
+
)
|
|
313
|
+
|
|
314
|
+
conn.commit()
|
|
315
|
+
|
|
316
|
+
result = {
|
|
317
|
+
"task_id": task_id,
|
|
318
|
+
"plan_id": plan_id,
|
|
319
|
+
"legacy_endpoint": legacy_endpoint,
|
|
320
|
+
"modern_endpoint": modern_endpoint,
|
|
321
|
+
"component_id": component_id,
|
|
322
|
+
"routing": "legacy",
|
|
323
|
+
"registered_at": now,
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
print(f"[INFO] Facade registered: {legacy_endpoint} -> {modern_endpoint}")
|
|
327
|
+
return result
|
|
328
|
+
|
|
329
|
+
finally:
|
|
330
|
+
conn.close()
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
# ---------------------------------------------------------------------------
|
|
334
|
+
# 3. Track cutover
|
|
335
|
+
# ---------------------------------------------------------------------------
|
|
336
|
+
|
|
337
|
+
def track_cutover(plan_id, component_id, status):
|
|
338
|
+
"""Update the cutover status for a specific component.
|
|
339
|
+
|
|
340
|
+
Valid status transitions follow the strangler fig lifecycle:
|
|
341
|
+
legacy -> parallel -> modern -> decommissioned
|
|
342
|
+
|
|
343
|
+
Args:
|
|
344
|
+
plan_id: Migration plan ID.
|
|
345
|
+
component_id: Legacy component ID.
|
|
346
|
+
status: Target cutover status (legacy|parallel|modern|decommissioned).
|
|
347
|
+
|
|
348
|
+
Returns:
|
|
349
|
+
dict with updated component status information.
|
|
350
|
+
"""
|
|
351
|
+
if status not in CUTOVER_STATUSES:
|
|
352
|
+
raise ValueError(
|
|
353
|
+
f"Invalid cutover status '{status}'. "
|
|
354
|
+
f"Valid: {', '.join(CUTOVER_STATUSES)}"
|
|
355
|
+
)
|
|
356
|
+
|
|
357
|
+
conn = _get_db()
|
|
358
|
+
try:
|
|
359
|
+
# Find the cutover task for this component
|
|
360
|
+
task = conn.execute(
|
|
361
|
+
"""SELECT * FROM migration_tasks
|
|
362
|
+
WHERE plan_id = ? AND legacy_component_id = ?
|
|
363
|
+
AND task_type = 'cutover'""",
|
|
364
|
+
(plan_id, component_id),
|
|
365
|
+
).fetchone()
|
|
366
|
+
|
|
367
|
+
if not task:
|
|
368
|
+
raise ValueError(
|
|
369
|
+
f"No cutover task found for component '{component_id}' "
|
|
370
|
+
f"in plan '{plan_id}'."
|
|
371
|
+
)
|
|
372
|
+
|
|
373
|
+
now = datetime.now(timezone.utc).isoformat()
|
|
374
|
+
task_status = CUTOVER_TO_TASK_STATUS[status]
|
|
375
|
+
completed_at = now if status in ("modern", "decommissioned") else None
|
|
376
|
+
|
|
377
|
+
# Update the task description with new strangler_fig_status
|
|
378
|
+
desc = {}
|
|
379
|
+
if task["description"]:
|
|
380
|
+
try:
|
|
381
|
+
desc = json.loads(task["description"])
|
|
382
|
+
except (json.JSONDecodeError, TypeError):
|
|
383
|
+
desc = {}
|
|
384
|
+
desc["strangler_fig_status"] = status
|
|
385
|
+
desc["cutover_updated_at"] = now
|
|
386
|
+
|
|
387
|
+
conn.execute(
|
|
388
|
+
"""UPDATE migration_tasks
|
|
389
|
+
SET status = ?, description = ?, completed_at = ?
|
|
390
|
+
WHERE id = ?""",
|
|
391
|
+
(task_status, json.dumps(desc), completed_at, task["id"]),
|
|
392
|
+
)
|
|
393
|
+
|
|
394
|
+
project_id = _get_plan_project_id(conn, plan_id)
|
|
395
|
+
|
|
396
|
+
# If switching to modern: create digital thread link
|
|
397
|
+
if status == "modern":
|
|
398
|
+
try:
|
|
399
|
+
conn.execute(
|
|
400
|
+
"""INSERT INTO digital_thread_links
|
|
401
|
+
(project_id, source_type, source_id, target_type,
|
|
402
|
+
target_id, link_type, confidence, evidence, created_by)
|
|
403
|
+
VALUES (?, 'legacy_component', ?, 'code_module', ?,
|
|
404
|
+
'replaces', 0.95,
|
|
405
|
+
?, 'strangler-fig-manager')""",
|
|
406
|
+
(
|
|
407
|
+
project_id,
|
|
408
|
+
component_id,
|
|
409
|
+
f"modern-{component_id}",
|
|
410
|
+
"Strangler fig cutover: component migrated to modern implementation",
|
|
411
|
+
),
|
|
412
|
+
)
|
|
413
|
+
except sqlite3.IntegrityError:
|
|
414
|
+
pass # Link already exists
|
|
415
|
+
|
|
416
|
+
# If decommissioned: log audit trail event
|
|
417
|
+
if status == "decommissioned":
|
|
418
|
+
# Fetch component name for audit message
|
|
419
|
+
comp = conn.execute(
|
|
420
|
+
"SELECT name, qualified_name FROM legacy_components WHERE id = ?",
|
|
421
|
+
(component_id,),
|
|
422
|
+
).fetchone()
|
|
423
|
+
comp_name = comp["name"] if comp else component_id
|
|
424
|
+
|
|
425
|
+
_log_audit(
|
|
426
|
+
conn,
|
|
427
|
+
project_id=project_id,
|
|
428
|
+
event_type="strangler_fig_cutover",
|
|
429
|
+
actor="strangler-fig-manager",
|
|
430
|
+
action=f"Decommissioned legacy component: {comp_name}",
|
|
431
|
+
details={
|
|
432
|
+
"plan_id": plan_id,
|
|
433
|
+
"component_id": component_id,
|
|
434
|
+
"component_name": comp_name,
|
|
435
|
+
"qualified_name": comp["qualified_name"] if comp else None,
|
|
436
|
+
"final_status": "decommissioned",
|
|
437
|
+
},
|
|
438
|
+
)
|
|
439
|
+
|
|
440
|
+
conn.commit()
|
|
441
|
+
|
|
442
|
+
result = {
|
|
443
|
+
"plan_id": plan_id,
|
|
444
|
+
"component_id": component_id,
|
|
445
|
+
"cutover_status": status,
|
|
446
|
+
"task_status": task_status,
|
|
447
|
+
"task_id": task["id"],
|
|
448
|
+
"updated_at": now,
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
print(f"[INFO] Component {component_id} cutover status: {status}")
|
|
452
|
+
return result
|
|
453
|
+
|
|
454
|
+
finally:
|
|
455
|
+
conn.close()
|
|
456
|
+
|
|
457
|
+
|
|
458
|
+
# ---------------------------------------------------------------------------
|
|
459
|
+
# 4. Get cutover status dashboard
|
|
460
|
+
# ---------------------------------------------------------------------------
|
|
461
|
+
|
|
462
|
+
def get_cutover_status(plan_id):
|
|
463
|
+
"""Get per-component cutover status dashboard for a migration plan.
|
|
464
|
+
|
|
465
|
+
Queries all cutover tasks, groups by status, and computes overall
|
|
466
|
+
migration progress percentage.
|
|
467
|
+
|
|
468
|
+
Args:
|
|
469
|
+
plan_id: Migration plan ID.
|
|
470
|
+
|
|
471
|
+
Returns:
|
|
472
|
+
dict with status counts, progress percentage, and component list.
|
|
473
|
+
"""
|
|
474
|
+
conn = _get_db()
|
|
475
|
+
try:
|
|
476
|
+
plan = conn.execute(
|
|
477
|
+
"SELECT * FROM migration_plans WHERE id = ?", (plan_id,)
|
|
478
|
+
).fetchone()
|
|
479
|
+
if not plan:
|
|
480
|
+
raise ValueError(f"Migration plan '{plan_id}' not found.")
|
|
481
|
+
|
|
482
|
+
tasks = conn.execute(
|
|
483
|
+
"""SELECT mt.*, lc.name as comp_name, lc.component_type,
|
|
484
|
+
lc.qualified_name
|
|
485
|
+
FROM migration_tasks mt
|
|
486
|
+
LEFT JOIN legacy_components lc ON mt.legacy_component_id = lc.id
|
|
487
|
+
WHERE mt.plan_id = ? AND mt.task_type = 'cutover'""",
|
|
488
|
+
(plan_id,),
|
|
489
|
+
).fetchall()
|
|
490
|
+
|
|
491
|
+
# Count by strangler fig status
|
|
492
|
+
status_counts = collections.Counter()
|
|
493
|
+
components = []
|
|
494
|
+
|
|
495
|
+
for task in tasks:
|
|
496
|
+
desc = {}
|
|
497
|
+
if task["description"]:
|
|
498
|
+
try:
|
|
499
|
+
desc = json.loads(task["description"])
|
|
500
|
+
except (json.JSONDecodeError, TypeError):
|
|
501
|
+
desc = {}
|
|
502
|
+
|
|
503
|
+
sf_status = desc.get("strangler_fig_status", "legacy")
|
|
504
|
+
status_counts[sf_status] += 1
|
|
505
|
+
|
|
506
|
+
components.append({
|
|
507
|
+
"component_id": task["legacy_component_id"],
|
|
508
|
+
"name": task["comp_name"] or "unknown",
|
|
509
|
+
"type": task["component_type"] or "unknown",
|
|
510
|
+
"qualified_name": task["qualified_name"],
|
|
511
|
+
"cutover_status": sf_status,
|
|
512
|
+
"task_id": task["id"],
|
|
513
|
+
"task_status": task["status"],
|
|
514
|
+
})
|
|
515
|
+
|
|
516
|
+
total = len(tasks)
|
|
517
|
+
modern_count = status_counts.get("modern", 0)
|
|
518
|
+
decommissioned_count = status_counts.get("decommissioned", 0)
|
|
519
|
+
migrated = modern_count + decommissioned_count
|
|
520
|
+
progress_pct = round((migrated / total * 100), 2) if total > 0 else 0.0
|
|
521
|
+
|
|
522
|
+
result = {
|
|
523
|
+
"plan_id": plan_id,
|
|
524
|
+
"plan_name": plan["plan_name"],
|
|
525
|
+
"total": total,
|
|
526
|
+
"legacy_count": status_counts.get("legacy", 0),
|
|
527
|
+
"parallel_count": status_counts.get("parallel", 0),
|
|
528
|
+
"modern_count": modern_count,
|
|
529
|
+
"decommissioned_count": decommissioned_count,
|
|
530
|
+
"progress_pct": progress_pct,
|
|
531
|
+
"components": components,
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
print(f"[INFO] Cutover Status for '{plan['plan_name']}'")
|
|
535
|
+
print(f" Total: {total} | Legacy: {status_counts.get('legacy', 0)} | "
|
|
536
|
+
f"Parallel: {status_counts.get('parallel', 0)} | "
|
|
537
|
+
f"Modern: {modern_count} | Decommissioned: {decommissioned_count}")
|
|
538
|
+
print(f" Progress: {progress_pct}%")
|
|
539
|
+
return result
|
|
540
|
+
|
|
541
|
+
finally:
|
|
542
|
+
conn.close()
|
|
543
|
+
|
|
544
|
+
|
|
545
|
+
# ---------------------------------------------------------------------------
|
|
546
|
+
# 5. Generate routing config
|
|
547
|
+
# ---------------------------------------------------------------------------
|
|
548
|
+
|
|
549
|
+
def generate_routing_config(plan_id):
|
|
550
|
+
"""Generate API gateway routing rules for the strangler fig facade.
|
|
551
|
+
|
|
552
|
+
For each registered facade endpoint, determines whether traffic should
|
|
553
|
+
route to the legacy or modern backend based on the component's current
|
|
554
|
+
cutover status. Also generates Nginx and K8s Ingress config snippets
|
|
555
|
+
as comments in the output.
|
|
556
|
+
|
|
557
|
+
Args:
|
|
558
|
+
plan_id: Migration plan ID.
|
|
559
|
+
|
|
560
|
+
Returns:
|
|
561
|
+
dict with routing rules, Nginx snippet, and K8s Ingress snippet.
|
|
562
|
+
"""
|
|
563
|
+
conn = _get_db()
|
|
564
|
+
try:
|
|
565
|
+
# Fetch all facade registrations
|
|
566
|
+
facades = conn.execute(
|
|
567
|
+
"""SELECT mt.*, lc.name as comp_name
|
|
568
|
+
FROM migration_tasks mt
|
|
569
|
+
LEFT JOIN legacy_components lc ON mt.legacy_component_id = lc.id
|
|
570
|
+
WHERE mt.plan_id = ? AND mt.task_type = 'generate_facade'""",
|
|
571
|
+
(plan_id,),
|
|
572
|
+
).fetchall()
|
|
573
|
+
|
|
574
|
+
# Build a component_id -> cutover_status map from cutover tasks
|
|
575
|
+
cutover_tasks = conn.execute(
|
|
576
|
+
"""SELECT legacy_component_id, description
|
|
577
|
+
FROM migration_tasks
|
|
578
|
+
WHERE plan_id = ? AND task_type = 'cutover'""",
|
|
579
|
+
(plan_id,),
|
|
580
|
+
).fetchall()
|
|
581
|
+
|
|
582
|
+
comp_status_map = {}
|
|
583
|
+
for ct in cutover_tasks:
|
|
584
|
+
if ct["legacy_component_id"]:
|
|
585
|
+
desc = {}
|
|
586
|
+
if ct["description"]:
|
|
587
|
+
try:
|
|
588
|
+
desc = json.loads(ct["description"])
|
|
589
|
+
except (json.JSONDecodeError, TypeError):
|
|
590
|
+
desc = {}
|
|
591
|
+
comp_status_map[ct["legacy_component_id"]] = desc.get(
|
|
592
|
+
"strangler_fig_status", "legacy"
|
|
593
|
+
)
|
|
594
|
+
|
|
595
|
+
routes = []
|
|
596
|
+
nginx_lines = [
|
|
597
|
+
f"# {CUI_BANNER}",
|
|
598
|
+
"# Strangler Fig Routing Configuration — Nginx",
|
|
599
|
+
f"# Generated: {datetime.now(timezone.utc).isoformat()}",
|
|
600
|
+
f"# Plan: {plan_id}",
|
|
601
|
+
"",
|
|
602
|
+
]
|
|
603
|
+
k8s_annotations = []
|
|
604
|
+
|
|
605
|
+
for facade in facades:
|
|
606
|
+
props = {}
|
|
607
|
+
if facade["description"]:
|
|
608
|
+
try:
|
|
609
|
+
props = json.loads(facade["description"])
|
|
610
|
+
except (json.JSONDecodeError, TypeError):
|
|
611
|
+
props = {}
|
|
612
|
+
|
|
613
|
+
legacy_path = props.get("legacy_path", "/")
|
|
614
|
+
modern_path = props.get("modern_path", "/")
|
|
615
|
+
comp_id = props.get("component_id") or facade["legacy_component_id"]
|
|
616
|
+
|
|
617
|
+
# Determine routing target based on component cutover status
|
|
618
|
+
comp_cutover = comp_status_map.get(comp_id, "legacy")
|
|
619
|
+
if comp_cutover in ("modern", "decommissioned"):
|
|
620
|
+
target = "modern"
|
|
621
|
+
backend_url = modern_path
|
|
622
|
+
else:
|
|
623
|
+
target = "legacy"
|
|
624
|
+
backend_url = legacy_path
|
|
625
|
+
|
|
626
|
+
route_entry = {
|
|
627
|
+
"path": legacy_path,
|
|
628
|
+
"method": "ALL",
|
|
629
|
+
"target": target,
|
|
630
|
+
"backend_url": backend_url,
|
|
631
|
+
"legacy_url": legacy_path,
|
|
632
|
+
"modern_url": modern_path,
|
|
633
|
+
"component_id": comp_id,
|
|
634
|
+
"component_status": comp_cutover,
|
|
635
|
+
}
|
|
636
|
+
routes.append(route_entry)
|
|
637
|
+
|
|
638
|
+
# Nginx snippet
|
|
639
|
+
upstream = "modern_upstream" if target == "modern" else "legacy_upstream"
|
|
640
|
+
nginx_lines.append(f"location {legacy_path} {{")
|
|
641
|
+
nginx_lines.append(f" # Component: {comp_id} (status: {comp_cutover})")
|
|
642
|
+
nginx_lines.append(f" proxy_pass http://{upstream}{backend_url};")
|
|
643
|
+
nginx_lines.append(f" proxy_set_header X-Strangler-Target {target};")
|
|
644
|
+
nginx_lines.append("}")
|
|
645
|
+
nginx_lines.append("")
|
|
646
|
+
|
|
647
|
+
# K8s Ingress annotation
|
|
648
|
+
k8s_annotations.append({
|
|
649
|
+
"path": legacy_path,
|
|
650
|
+
"service": f"{'modern' if target == 'modern' else 'legacy'}-service",
|
|
651
|
+
"port": 8443 if target == "modern" else 8080,
|
|
652
|
+
})
|
|
653
|
+
|
|
654
|
+
nginx_lines.append(f"# {CUI_BANNER}")
|
|
655
|
+
nginx_snippet = "\n".join(nginx_lines)
|
|
656
|
+
|
|
657
|
+
# Generate K8s Ingress YAML snippet
|
|
658
|
+
k8s_lines = [
|
|
659
|
+
f"# {CUI_BANNER}",
|
|
660
|
+
"# Strangler Fig Routing — K8s Ingress",
|
|
661
|
+
f"# Generated: {datetime.now(timezone.utc).isoformat()}",
|
|
662
|
+
"apiVersion: networking.k8s.io/v1",
|
|
663
|
+
"kind: Ingress",
|
|
664
|
+
"metadata:",
|
|
665
|
+
f" name: strangler-fig-{plan_id}",
|
|
666
|
+
" annotations:",
|
|
667
|
+
" nginx.ingress.kubernetes.io/rewrite-target: /",
|
|
668
|
+
"spec:",
|
|
669
|
+
" rules:",
|
|
670
|
+
" - http:",
|
|
671
|
+
" paths:",
|
|
672
|
+
]
|
|
673
|
+
for ann in k8s_annotations:
|
|
674
|
+
k8s_lines.append(f" - path: {ann['path']}")
|
|
675
|
+
k8s_lines.append(" pathType: Prefix")
|
|
676
|
+
k8s_lines.append(" backend:")
|
|
677
|
+
k8s_lines.append(" service:")
|
|
678
|
+
k8s_lines.append(f" name: {ann['service']}")
|
|
679
|
+
k8s_lines.append(" port:")
|
|
680
|
+
k8s_lines.append(f" number: {ann['port']}")
|
|
681
|
+
k8s_lines.append(f"# {CUI_BANNER}")
|
|
682
|
+
k8s_snippet = "\n".join(k8s_lines)
|
|
683
|
+
|
|
684
|
+
result = {
|
|
685
|
+
"plan_id": plan_id,
|
|
686
|
+
"route_count": len(routes),
|
|
687
|
+
"routes": routes,
|
|
688
|
+
"nginx_config": nginx_snippet,
|
|
689
|
+
"k8s_ingress": k8s_snippet,
|
|
690
|
+
"generated_at": datetime.now(timezone.utc).isoformat(),
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
print(f"[INFO] Generated routing config: {len(routes)} routes")
|
|
694
|
+
return result
|
|
695
|
+
|
|
696
|
+
finally:
|
|
697
|
+
conn.close()
|
|
698
|
+
|
|
699
|
+
|
|
700
|
+
# ---------------------------------------------------------------------------
|
|
701
|
+
# 6. Generate ACL code
|
|
702
|
+
# ---------------------------------------------------------------------------
|
|
703
|
+
|
|
704
|
+
def generate_acl_code(plan_id, boundary_name, language="python"):
|
|
705
|
+
"""Generate anti-corruption layer (ACL) adapter code.
|
|
706
|
+
|
|
707
|
+
Produces adapter classes that translate between legacy and modern
|
|
708
|
+
interfaces, preventing legacy domain concepts from leaking into
|
|
709
|
+
the modern codebase.
|
|
710
|
+
|
|
711
|
+
Args:
|
|
712
|
+
plan_id: Migration plan ID.
|
|
713
|
+
boundary_name: Name for the ACL boundary (used in class names).
|
|
714
|
+
language: Target language ('python', 'java', or 'csharp').
|
|
715
|
+
|
|
716
|
+
Returns:
|
|
717
|
+
str containing the generated adapter source code.
|
|
718
|
+
"""
|
|
719
|
+
conn = _get_db()
|
|
720
|
+
try:
|
|
721
|
+
plan = conn.execute(
|
|
722
|
+
"SELECT * FROM migration_plans WHERE id = ?", (plan_id,)
|
|
723
|
+
).fetchone()
|
|
724
|
+
if not plan:
|
|
725
|
+
raise ValueError(f"Migration plan '{plan_id}' not found.")
|
|
726
|
+
|
|
727
|
+
legacy_app_id = plan["legacy_app_id"]
|
|
728
|
+
|
|
729
|
+
# Fetch components for this plan to build adapter methods
|
|
730
|
+
components = conn.execute(
|
|
731
|
+
"""SELECT lc.* FROM legacy_components lc
|
|
732
|
+
JOIN migration_tasks mt ON mt.legacy_component_id = lc.id
|
|
733
|
+
WHERE mt.plan_id = ? AND mt.task_type = 'cutover'
|
|
734
|
+
ORDER BY lc.name""",
|
|
735
|
+
(plan_id,),
|
|
736
|
+
).fetchall()
|
|
737
|
+
|
|
738
|
+
# Fetch APIs for method signatures
|
|
739
|
+
apis = conn.execute(
|
|
740
|
+
"SELECT * FROM legacy_apis WHERE legacy_app_id = ?",
|
|
741
|
+
(legacy_app_id,),
|
|
742
|
+
).fetchall()
|
|
743
|
+
|
|
744
|
+
# Build API lookup by component_id
|
|
745
|
+
api_by_comp = collections.defaultdict(list)
|
|
746
|
+
for api in apis:
|
|
747
|
+
if api["component_id"]:
|
|
748
|
+
api_by_comp[api["component_id"]].append(api)
|
|
749
|
+
|
|
750
|
+
class_name = f"{_to_pascal_case(boundary_name)}AclAdapter"
|
|
751
|
+
interface_name = f"I{class_name}"
|
|
752
|
+
now = datetime.now(timezone.utc).isoformat()
|
|
753
|
+
|
|
754
|
+
if language == "python":
|
|
755
|
+
code = _generate_python_acl(
|
|
756
|
+
class_name, boundary_name, components, api_by_comp, now
|
|
757
|
+
)
|
|
758
|
+
elif language == "java":
|
|
759
|
+
code = _generate_java_acl(
|
|
760
|
+
class_name, interface_name, boundary_name, components,
|
|
761
|
+
api_by_comp, now
|
|
762
|
+
)
|
|
763
|
+
elif language == "csharp":
|
|
764
|
+
code = _generate_csharp_acl(
|
|
765
|
+
class_name, interface_name, boundary_name, components,
|
|
766
|
+
api_by_comp, now
|
|
767
|
+
)
|
|
768
|
+
else:
|
|
769
|
+
raise ValueError(
|
|
770
|
+
f"Unsupported language '{language}'. "
|
|
771
|
+
"Supported: python, java, csharp"
|
|
772
|
+
)
|
|
773
|
+
|
|
774
|
+
print(f"[INFO] Generated {language} ACL code: {class_name}")
|
|
775
|
+
return code
|
|
776
|
+
|
|
777
|
+
finally:
|
|
778
|
+
conn.close()
|
|
779
|
+
|
|
780
|
+
|
|
781
|
+
def _to_pascal_case(name):
|
|
782
|
+
"""Convert a snake_case or kebab-case name to PascalCase."""
|
|
783
|
+
parts = name.replace("-", "_").split("_")
|
|
784
|
+
return "".join(p.capitalize() for p in parts if p)
|
|
785
|
+
|
|
786
|
+
|
|
787
|
+
def _to_method_name(name, language="python"):
|
|
788
|
+
"""Convert a component name to a safe method name."""
|
|
789
|
+
safe = name.replace("-", "_").replace(".", "_").replace(" ", "_").lower()
|
|
790
|
+
if language == "python":
|
|
791
|
+
return f"translate_{safe}"
|
|
792
|
+
return f"translate{_to_pascal_case(safe)}"
|
|
793
|
+
|
|
794
|
+
|
|
795
|
+
def _generate_python_acl(class_name, boundary, components, api_by_comp, now):
|
|
796
|
+
"""Generate Python ACL adapter class."""
|
|
797
|
+
lines = [
|
|
798
|
+
f"# {CUI_BANNER}",
|
|
799
|
+
f'"""Anti-Corruption Layer adapter for boundary: {boundary}.',
|
|
800
|
+
"",
|
|
801
|
+
f"Auto-generated by ICDEV strangler-fig-manager at {now}.",
|
|
802
|
+
"Maps legacy interfaces to modern domain model.",
|
|
803
|
+
"",
|
|
804
|
+
f"Classification: {CUI_BANNER}",
|
|
805
|
+
'"""',
|
|
806
|
+
"",
|
|
807
|
+
"",
|
|
808
|
+
f"class {class_name}:",
|
|
809
|
+
f' """ACL adapter translating legacy {boundary} interfaces to modern API."""',
|
|
810
|
+
"",
|
|
811
|
+
" def __init__(self, legacy_client, modern_client):",
|
|
812
|
+
' """Initialize with both legacy and modern service clients.',
|
|
813
|
+
"",
|
|
814
|
+
" Args:",
|
|
815
|
+
" legacy_client: Client for the legacy system.",
|
|
816
|
+
" modern_client: Client for the modern system.",
|
|
817
|
+
' """',
|
|
818
|
+
" self._legacy = legacy_client",
|
|
819
|
+
" self._modern = modern_client",
|
|
820
|
+
"",
|
|
821
|
+
]
|
|
822
|
+
|
|
823
|
+
for comp in components:
|
|
824
|
+
method_name = _to_method_name(comp["name"], "python")
|
|
825
|
+
comp_apis = api_by_comp.get(comp["id"], [])
|
|
826
|
+
|
|
827
|
+
lines.append(f" def {method_name}(self, request_data):")
|
|
828
|
+
lines.append(f' """Translate legacy {comp["name"]} request to modern format.')
|
|
829
|
+
lines.append("")
|
|
830
|
+
lines.append(f' Legacy component: {comp["qualified_name"] or comp["name"]}')
|
|
831
|
+
lines.append(f' Component type: {comp["component_type"]}')
|
|
832
|
+
if comp_apis:
|
|
833
|
+
lines.append(" Legacy endpoints:")
|
|
834
|
+
for api in comp_apis:
|
|
835
|
+
lines.append(f" {api['method']} {api['path']}")
|
|
836
|
+
lines.append("")
|
|
837
|
+
lines.append(" Args:")
|
|
838
|
+
lines.append(" request_data: dict with legacy request payload.")
|
|
839
|
+
lines.append("")
|
|
840
|
+
lines.append(" Returns:")
|
|
841
|
+
lines.append(" dict with translated modern response.")
|
|
842
|
+
lines.append(' """')
|
|
843
|
+
lines.append(" # TODO: Implement legacy-to-modern data mapping")
|
|
844
|
+
lines.append(" modern_request = self._map_request(request_data)")
|
|
845
|
+
lines.append(" response = self._modern.call(modern_request)")
|
|
846
|
+
lines.append(" return self._map_response(response)")
|
|
847
|
+
lines.append("")
|
|
848
|
+
|
|
849
|
+
lines.append(" def _map_request(self, legacy_data):")
|
|
850
|
+
lines.append(' """Map legacy request format to modern request format."""')
|
|
851
|
+
lines.append(" # TODO: Implement field-by-field mapping")
|
|
852
|
+
lines.append(" return legacy_data")
|
|
853
|
+
lines.append("")
|
|
854
|
+
lines.append(" def _map_response(self, modern_response):")
|
|
855
|
+
lines.append(' """Map modern response format back to legacy response format."""')
|
|
856
|
+
lines.append(" # TODO: Implement response translation")
|
|
857
|
+
lines.append(" return modern_response")
|
|
858
|
+
lines.append("")
|
|
859
|
+
lines.append(f"# {CUI_BANNER}")
|
|
860
|
+
|
|
861
|
+
return "\n".join(lines)
|
|
862
|
+
|
|
863
|
+
|
|
864
|
+
def _generate_java_acl(class_name, interface_name, boundary, components,
|
|
865
|
+
api_by_comp, now):
|
|
866
|
+
"""Generate Java ACL adapter interface and implementation class."""
|
|
867
|
+
lines = [
|
|
868
|
+
f"// {CUI_BANNER}",
|
|
869
|
+
"/**",
|
|
870
|
+
f" * Anti-Corruption Layer adapter for boundary: {boundary}.",
|
|
871
|
+
" *",
|
|
872
|
+
f" * Auto-generated by ICDEV strangler-fig-manager at {now}.",
|
|
873
|
+
" * Maps legacy interfaces to modern domain model.",
|
|
874
|
+
" *",
|
|
875
|
+
f" * Classification: {CUI_BANNER}",
|
|
876
|
+
" */",
|
|
877
|
+
"",
|
|
878
|
+
f"public interface {interface_name} {{",
|
|
879
|
+
]
|
|
880
|
+
|
|
881
|
+
for comp in components:
|
|
882
|
+
method_name = _to_method_name(comp["name"], "java")
|
|
883
|
+
lines.append(" /**")
|
|
884
|
+
lines.append(f' * Translate legacy {comp["name"]} request to modern format.')
|
|
885
|
+
lines.append(" */")
|
|
886
|
+
lines.append(f" Map<String, Object> {method_name}(Map<String, Object> requestData);")
|
|
887
|
+
lines.append("")
|
|
888
|
+
|
|
889
|
+
lines.append("}")
|
|
890
|
+
lines.append("")
|
|
891
|
+
lines.append("")
|
|
892
|
+
lines.append(f"public class {class_name} implements {interface_name} {{")
|
|
893
|
+
lines.append("")
|
|
894
|
+
lines.append(" private final Object legacyClient;")
|
|
895
|
+
lines.append(" private final Object modernClient;")
|
|
896
|
+
lines.append("")
|
|
897
|
+
lines.append(f" public {class_name}(Object legacyClient, Object modernClient) {{")
|
|
898
|
+
lines.append(" this.legacyClient = legacyClient;")
|
|
899
|
+
lines.append(" this.modernClient = modernClient;")
|
|
900
|
+
lines.append(" }")
|
|
901
|
+
lines.append("")
|
|
902
|
+
|
|
903
|
+
for comp in components:
|
|
904
|
+
method_name = _to_method_name(comp["name"], "java")
|
|
905
|
+
lines.append(" @Override")
|
|
906
|
+
lines.append(f" public Map<String, Object> {method_name}(Map<String, Object> requestData) {{")
|
|
907
|
+
lines.append(f" // TODO: Implement legacy-to-modern mapping for {comp['name']}")
|
|
908
|
+
lines.append(" Map<String, Object> modernRequest = mapRequest(requestData);")
|
|
909
|
+
lines.append(" // Call modern service and translate response")
|
|
910
|
+
lines.append(" return mapResponse(modernRequest);")
|
|
911
|
+
lines.append(" }")
|
|
912
|
+
lines.append("")
|
|
913
|
+
|
|
914
|
+
lines.append(" private Map<String, Object> mapRequest(Map<String, Object> legacyData) {")
|
|
915
|
+
lines.append(" // TODO: Implement field-by-field mapping")
|
|
916
|
+
lines.append(" return legacyData;")
|
|
917
|
+
lines.append(" }")
|
|
918
|
+
lines.append("")
|
|
919
|
+
lines.append(" private Map<String, Object> mapResponse(Map<String, Object> modernResponse) {")
|
|
920
|
+
lines.append(" // TODO: Implement response translation")
|
|
921
|
+
lines.append(" return modernResponse;")
|
|
922
|
+
lines.append(" }")
|
|
923
|
+
lines.append("}")
|
|
924
|
+
lines.append(f"// {CUI_BANNER}")
|
|
925
|
+
|
|
926
|
+
return "\n".join(lines)
|
|
927
|
+
|
|
928
|
+
|
|
929
|
+
def _generate_csharp_acl(class_name, interface_name, boundary, components,
|
|
930
|
+
api_by_comp, now):
|
|
931
|
+
"""Generate C# ACL adapter interface and implementation class."""
|
|
932
|
+
lines = [
|
|
933
|
+
f"// {CUI_BANNER}",
|
|
934
|
+
"/// <summary>",
|
|
935
|
+
f"/// Anti-Corruption Layer adapter for boundary: {boundary}.",
|
|
936
|
+
"///",
|
|
937
|
+
f"/// Auto-generated by ICDEV strangler-fig-manager at {now}.",
|
|
938
|
+
"/// Maps legacy interfaces to modern domain model.",
|
|
939
|
+
"///",
|
|
940
|
+
f"/// Classification: {CUI_BANNER}",
|
|
941
|
+
"/// </summary>",
|
|
942
|
+
"",
|
|
943
|
+
"using System.Collections.Generic;",
|
|
944
|
+
"",
|
|
945
|
+
f"public interface {interface_name}",
|
|
946
|
+
"{",
|
|
947
|
+
]
|
|
948
|
+
|
|
949
|
+
for comp in components:
|
|
950
|
+
method_name = _to_method_name(comp["name"], "csharp")
|
|
951
|
+
lines.append(f" /// <summary>Translate legacy {comp['name']} request to modern format.</summary>")
|
|
952
|
+
lines.append(f" Dictionary<string, object> {method_name}(Dictionary<string, object> requestData);")
|
|
953
|
+
lines.append("")
|
|
954
|
+
|
|
955
|
+
lines.append("}")
|
|
956
|
+
lines.append("")
|
|
957
|
+
lines.append(f"public class {class_name} : {interface_name}")
|
|
958
|
+
lines.append("{")
|
|
959
|
+
lines.append(" private readonly object _legacyClient;")
|
|
960
|
+
lines.append(" private readonly object _modernClient;")
|
|
961
|
+
lines.append("")
|
|
962
|
+
lines.append(f" public {class_name}(object legacyClient, object modernClient)")
|
|
963
|
+
lines.append(" {")
|
|
964
|
+
lines.append(" _legacyClient = legacyClient;")
|
|
965
|
+
lines.append(" _modernClient = modernClient;")
|
|
966
|
+
lines.append(" }")
|
|
967
|
+
lines.append("")
|
|
968
|
+
|
|
969
|
+
for comp in components:
|
|
970
|
+
method_name = _to_method_name(comp["name"], "csharp")
|
|
971
|
+
lines.append(f" public Dictionary<string, object> {method_name}(Dictionary<string, object> requestData)")
|
|
972
|
+
lines.append(" {")
|
|
973
|
+
lines.append(f" // TODO: Implement legacy-to-modern mapping for {comp['name']}")
|
|
974
|
+
lines.append(" var modernRequest = MapRequest(requestData);")
|
|
975
|
+
lines.append(" return MapResponse(modernRequest);")
|
|
976
|
+
lines.append(" }")
|
|
977
|
+
lines.append("")
|
|
978
|
+
|
|
979
|
+
lines.append(" private Dictionary<string, object> MapRequest(Dictionary<string, object> legacyData)")
|
|
980
|
+
lines.append(" {")
|
|
981
|
+
lines.append(" // TODO: Implement field-by-field mapping")
|
|
982
|
+
lines.append(" return legacyData;")
|
|
983
|
+
lines.append(" }")
|
|
984
|
+
lines.append("")
|
|
985
|
+
lines.append(" private Dictionary<string, object> MapResponse(Dictionary<string, object> modernResponse)")
|
|
986
|
+
lines.append(" {")
|
|
987
|
+
lines.append(" // TODO: Implement response translation")
|
|
988
|
+
lines.append(" return modernResponse;")
|
|
989
|
+
lines.append(" }")
|
|
990
|
+
lines.append("}")
|
|
991
|
+
lines.append(f"// {CUI_BANNER}")
|
|
992
|
+
|
|
993
|
+
return "\n".join(lines)
|
|
994
|
+
|
|
995
|
+
|
|
996
|
+
# ---------------------------------------------------------------------------
|
|
997
|
+
# 7. Check coexistence health
|
|
998
|
+
# ---------------------------------------------------------------------------
|
|
999
|
+
|
|
1000
|
+
def check_coexistence_health(plan_id):
|
|
1001
|
+
"""Verify that legacy and modern systems can safely coexist.
|
|
1002
|
+
|
|
1003
|
+
Performs three categories of checks:
|
|
1004
|
+
1. All parallel components have both legacy and modern endpoints
|
|
1005
|
+
2. No circular dependencies between legacy and modern components
|
|
1006
|
+
3. All facade routes are properly defined
|
|
1007
|
+
|
|
1008
|
+
Args:
|
|
1009
|
+
plan_id: Migration plan ID.
|
|
1010
|
+
|
|
1011
|
+
Returns:
|
|
1012
|
+
dict with health status, issues list, and warnings list.
|
|
1013
|
+
"""
|
|
1014
|
+
conn = _get_db()
|
|
1015
|
+
try:
|
|
1016
|
+
plan = conn.execute(
|
|
1017
|
+
"SELECT * FROM migration_plans WHERE id = ?", (plan_id,)
|
|
1018
|
+
).fetchone()
|
|
1019
|
+
if not plan:
|
|
1020
|
+
raise ValueError(f"Migration plan '{plan_id}' not found.")
|
|
1021
|
+
|
|
1022
|
+
issues = []
|
|
1023
|
+
warnings = []
|
|
1024
|
+
|
|
1025
|
+
legacy_app_id = plan["legacy_app_id"]
|
|
1026
|
+
|
|
1027
|
+
# Fetch all cutover tasks with their status
|
|
1028
|
+
cutover_tasks = conn.execute(
|
|
1029
|
+
"""SELECT mt.*, lc.name as comp_name, lc.qualified_name
|
|
1030
|
+
FROM migration_tasks mt
|
|
1031
|
+
LEFT JOIN legacy_components lc ON mt.legacy_component_id = lc.id
|
|
1032
|
+
WHERE mt.plan_id = ? AND mt.task_type = 'cutover'""",
|
|
1033
|
+
(plan_id,),
|
|
1034
|
+
).fetchall()
|
|
1035
|
+
|
|
1036
|
+
# Fetch all facade registrations
|
|
1037
|
+
facades = conn.execute(
|
|
1038
|
+
"""SELECT * FROM migration_tasks
|
|
1039
|
+
WHERE plan_id = ? AND task_type = 'generate_facade'""",
|
|
1040
|
+
(plan_id,),
|
|
1041
|
+
).fetchall()
|
|
1042
|
+
|
|
1043
|
+
# Build facade component set
|
|
1044
|
+
facade_component_ids = set()
|
|
1045
|
+
for f in facades:
|
|
1046
|
+
if f["legacy_component_id"]:
|
|
1047
|
+
facade_component_ids.add(f["legacy_component_id"])
|
|
1048
|
+
if f["description"]:
|
|
1049
|
+
try:
|
|
1050
|
+
props = json.loads(f["description"])
|
|
1051
|
+
cid = props.get("component_id")
|
|
1052
|
+
if cid:
|
|
1053
|
+
facade_component_ids.add(cid)
|
|
1054
|
+
except (json.JSONDecodeError, TypeError):
|
|
1055
|
+
pass
|
|
1056
|
+
|
|
1057
|
+
# Check 1: Parallel components should have facade routes
|
|
1058
|
+
parallel_components = []
|
|
1059
|
+
for task in cutover_tasks:
|
|
1060
|
+
desc = {}
|
|
1061
|
+
if task["description"]:
|
|
1062
|
+
try:
|
|
1063
|
+
desc = json.loads(task["description"])
|
|
1064
|
+
except (json.JSONDecodeError, TypeError):
|
|
1065
|
+
desc = {}
|
|
1066
|
+
sf_status = desc.get("strangler_fig_status", "legacy")
|
|
1067
|
+
|
|
1068
|
+
if sf_status == "parallel":
|
|
1069
|
+
parallel_components.append(task)
|
|
1070
|
+
comp_id = task["legacy_component_id"]
|
|
1071
|
+
if comp_id and comp_id not in facade_component_ids:
|
|
1072
|
+
issues.append({
|
|
1073
|
+
"check": "parallel_without_facade",
|
|
1074
|
+
"severity": "error",
|
|
1075
|
+
"component_id": comp_id,
|
|
1076
|
+
"component_name": task["comp_name"],
|
|
1077
|
+
"message": (
|
|
1078
|
+
f"Component '{task['comp_name']}' is in parallel mode "
|
|
1079
|
+
"but has no facade route registered."
|
|
1080
|
+
),
|
|
1081
|
+
})
|
|
1082
|
+
|
|
1083
|
+
# Check 2: Look for potential circular dependencies
|
|
1084
|
+
# between components that are in different cutover states
|
|
1085
|
+
comp_status_map = {}
|
|
1086
|
+
for task in cutover_tasks:
|
|
1087
|
+
if task["legacy_component_id"]:
|
|
1088
|
+
desc = {}
|
|
1089
|
+
if task["description"]:
|
|
1090
|
+
try:
|
|
1091
|
+
desc = json.loads(task["description"])
|
|
1092
|
+
except (json.JSONDecodeError, TypeError):
|
|
1093
|
+
desc = {}
|
|
1094
|
+
comp_status_map[task["legacy_component_id"]] = desc.get(
|
|
1095
|
+
"strangler_fig_status", "legacy"
|
|
1096
|
+
)
|
|
1097
|
+
|
|
1098
|
+
# Query dependencies for cross-status circular references
|
|
1099
|
+
deps = conn.execute(
|
|
1100
|
+
"""SELECT source_component_id, target_component_id
|
|
1101
|
+
FROM legacy_dependencies
|
|
1102
|
+
WHERE legacy_app_id = ?
|
|
1103
|
+
AND source_component_id IS NOT NULL
|
|
1104
|
+
AND target_component_id IS NOT NULL""",
|
|
1105
|
+
(legacy_app_id,),
|
|
1106
|
+
).fetchall()
|
|
1107
|
+
|
|
1108
|
+
# Check for bidirectional dependencies crossing cutover boundaries
|
|
1109
|
+
dep_pairs = set()
|
|
1110
|
+
for dep in deps:
|
|
1111
|
+
src = dep["source_component_id"]
|
|
1112
|
+
tgt = dep["target_component_id"]
|
|
1113
|
+
src_status = comp_status_map.get(src, "legacy")
|
|
1114
|
+
tgt_status = comp_status_map.get(tgt, "legacy")
|
|
1115
|
+
|
|
1116
|
+
# Flag if modern component depends on legacy component
|
|
1117
|
+
if src_status in ("modern", "decommissioned") and tgt_status == "legacy":
|
|
1118
|
+
pair_key = (src, tgt)
|
|
1119
|
+
if pair_key not in dep_pairs:
|
|
1120
|
+
dep_pairs.add(pair_key)
|
|
1121
|
+
warnings.append({
|
|
1122
|
+
"check": "cross_boundary_dependency",
|
|
1123
|
+
"severity": "warning",
|
|
1124
|
+
"source_id": src,
|
|
1125
|
+
"target_id": tgt,
|
|
1126
|
+
"message": (
|
|
1127
|
+
f"Modern component {src} depends on legacy component {tgt}. "
|
|
1128
|
+
"Consider adding an ACL adapter."
|
|
1129
|
+
),
|
|
1130
|
+
})
|
|
1131
|
+
|
|
1132
|
+
# Flag circular: A depends on B and B depends on A across boundaries
|
|
1133
|
+
reverse_key = (tgt, src)
|
|
1134
|
+
if reverse_key in dep_pairs:
|
|
1135
|
+
issues.append({
|
|
1136
|
+
"check": "circular_cross_boundary",
|
|
1137
|
+
"severity": "error",
|
|
1138
|
+
"components": [src, tgt],
|
|
1139
|
+
"message": (
|
|
1140
|
+
f"Circular dependency detected between {src} and {tgt} "
|
|
1141
|
+
"across cutover boundaries."
|
|
1142
|
+
),
|
|
1143
|
+
})
|
|
1144
|
+
|
|
1145
|
+
# Check 3: All APIs for parallel/modern components should have facades
|
|
1146
|
+
apis = conn.execute(
|
|
1147
|
+
"SELECT * FROM legacy_apis WHERE legacy_app_id = ?",
|
|
1148
|
+
(legacy_app_id,),
|
|
1149
|
+
).fetchall()
|
|
1150
|
+
|
|
1151
|
+
for api in apis:
|
|
1152
|
+
comp_id = api["component_id"]
|
|
1153
|
+
if not comp_id:
|
|
1154
|
+
continue
|
|
1155
|
+
comp_status = comp_status_map.get(comp_id, "legacy")
|
|
1156
|
+
if comp_status in ("parallel", "modern") and comp_id not in facade_component_ids:
|
|
1157
|
+
warnings.append({
|
|
1158
|
+
"check": "api_without_facade",
|
|
1159
|
+
"severity": "warning",
|
|
1160
|
+
"component_id": comp_id,
|
|
1161
|
+
"api_path": api["path"],
|
|
1162
|
+
"api_method": api["method"],
|
|
1163
|
+
"message": (
|
|
1164
|
+
f"API {api['method']} {api['path']} on "
|
|
1165
|
+
f"{comp_status} component has no facade route."
|
|
1166
|
+
),
|
|
1167
|
+
})
|
|
1168
|
+
|
|
1169
|
+
healthy = len(issues) == 0
|
|
1170
|
+
|
|
1171
|
+
result = {
|
|
1172
|
+
"plan_id": plan_id,
|
|
1173
|
+
"healthy": healthy,
|
|
1174
|
+
"issues": issues,
|
|
1175
|
+
"warnings": warnings,
|
|
1176
|
+
"checks_performed": [
|
|
1177
|
+
"parallel_components_have_facades",
|
|
1178
|
+
"no_circular_cross_boundary_deps",
|
|
1179
|
+
"all_facade_routes_defined",
|
|
1180
|
+
],
|
|
1181
|
+
"parallel_count": len(parallel_components),
|
|
1182
|
+
"facade_count": len(facades),
|
|
1183
|
+
"checked_at": datetime.now(timezone.utc).isoformat(),
|
|
1184
|
+
}
|
|
1185
|
+
|
|
1186
|
+
status_label = "HEALTHY" if healthy else "UNHEALTHY"
|
|
1187
|
+
print(f"[INFO] Coexistence Health: {status_label}")
|
|
1188
|
+
print(f" Issues: {len(issues)} | Warnings: {len(warnings)}")
|
|
1189
|
+
return result
|
|
1190
|
+
|
|
1191
|
+
finally:
|
|
1192
|
+
conn.close()
|
|
1193
|
+
|
|
1194
|
+
|
|
1195
|
+
# ---------------------------------------------------------------------------
|
|
1196
|
+
# 8. Generate cutover checklist
|
|
1197
|
+
# ---------------------------------------------------------------------------
|
|
1198
|
+
|
|
1199
|
+
def generate_cutover_checklist(plan_id, component_id):
|
|
1200
|
+
"""Generate a pre-cutover validation checklist for a component.
|
|
1201
|
+
|
|
1202
|
+
Produces a comprehensive checklist that must be satisfied before
|
|
1203
|
+
a component can be safely switched from legacy to modern.
|
|
1204
|
+
|
|
1205
|
+
Args:
|
|
1206
|
+
plan_id: Migration plan ID.
|
|
1207
|
+
component_id: Legacy component ID to generate checklist for.
|
|
1208
|
+
|
|
1209
|
+
Returns:
|
|
1210
|
+
dict with checklist items and their verification status.
|
|
1211
|
+
"""
|
|
1212
|
+
conn = _get_db()
|
|
1213
|
+
try:
|
|
1214
|
+
# Verify plan and component exist
|
|
1215
|
+
plan = conn.execute(
|
|
1216
|
+
"SELECT * FROM migration_plans WHERE id = ?", (plan_id,)
|
|
1217
|
+
).fetchone()
|
|
1218
|
+
if not plan:
|
|
1219
|
+
raise ValueError(f"Migration plan '{plan_id}' not found.")
|
|
1220
|
+
|
|
1221
|
+
comp = conn.execute(
|
|
1222
|
+
"SELECT * FROM legacy_components WHERE id = ?", (component_id,)
|
|
1223
|
+
).fetchone()
|
|
1224
|
+
if not comp:
|
|
1225
|
+
raise ValueError(f"Component '{component_id}' not found.")
|
|
1226
|
+
|
|
1227
|
+
project_id = _get_plan_project_id(conn, plan_id)
|
|
1228
|
+
|
|
1229
|
+
# Check for existing modern implementation (digital thread link)
|
|
1230
|
+
modern_link = conn.execute(
|
|
1231
|
+
"""SELECT * FROM digital_thread_links
|
|
1232
|
+
WHERE project_id = ? AND source_type = 'legacy_component'
|
|
1233
|
+
AND source_id = ? AND link_type = 'replaces'""",
|
|
1234
|
+
(project_id, component_id),
|
|
1235
|
+
).fetchone()
|
|
1236
|
+
|
|
1237
|
+
# Check for test coverage tasks
|
|
1238
|
+
test_tasks = conn.execute(
|
|
1239
|
+
"""SELECT * FROM migration_tasks
|
|
1240
|
+
WHERE plan_id = ? AND legacy_component_id = ?
|
|
1241
|
+
AND task_type = 'generate_test'""",
|
|
1242
|
+
(plan_id, component_id),
|
|
1243
|
+
).fetchall()
|
|
1244
|
+
tests_exist = len(test_tasks) > 0
|
|
1245
|
+
tests_passing = all(t["status"] == "completed" for t in test_tasks) if tests_exist else False
|
|
1246
|
+
|
|
1247
|
+
# Check for facade registration
|
|
1248
|
+
facade = conn.execute(
|
|
1249
|
+
"""SELECT * FROM migration_tasks
|
|
1250
|
+
WHERE plan_id = ? AND legacy_component_id = ?
|
|
1251
|
+
AND task_type = 'generate_facade'""",
|
|
1252
|
+
(plan_id, component_id),
|
|
1253
|
+
).fetchone()
|
|
1254
|
+
|
|
1255
|
+
# Check for schema migration tasks
|
|
1256
|
+
schema_task = conn.execute(
|
|
1257
|
+
"""SELECT * FROM migration_tasks
|
|
1258
|
+
WHERE plan_id = ? AND legacy_component_id = ?
|
|
1259
|
+
AND task_type IN ('migrate_schema', 'migrate_data')""",
|
|
1260
|
+
(plan_id, component_id),
|
|
1261
|
+
).fetchall()
|
|
1262
|
+
data_migrated = all(t["status"] == "completed" for t in schema_task) if schema_task else False
|
|
1263
|
+
|
|
1264
|
+
# Check compliance controls mapped
|
|
1265
|
+
compliance_links = conn.execute(
|
|
1266
|
+
"""SELECT * FROM digital_thread_links
|
|
1267
|
+
WHERE project_id = ? AND source_type = 'legacy_component'
|
|
1268
|
+
AND source_id = ?
|
|
1269
|
+
AND target_type IN ('nist_control', 'stig_rule')""",
|
|
1270
|
+
(project_id, component_id),
|
|
1271
|
+
).fetchall()
|
|
1272
|
+
|
|
1273
|
+
checklist = [
|
|
1274
|
+
{
|
|
1275
|
+
"item": "Modern implementation exists",
|
|
1276
|
+
"verified": modern_link is not None,
|
|
1277
|
+
"details": (
|
|
1278
|
+
f"Digital thread link found: {modern_link['target_id']}"
|
|
1279
|
+
if modern_link else "No modern implementation linked yet"
|
|
1280
|
+
),
|
|
1281
|
+
},
|
|
1282
|
+
{
|
|
1283
|
+
"item": "Tests passing",
|
|
1284
|
+
"verified": tests_passing,
|
|
1285
|
+
"details": (
|
|
1286
|
+
f"{len(test_tasks)} test task(s) completed"
|
|
1287
|
+
if tests_passing else
|
|
1288
|
+
f"{len(test_tasks)} test task(s) found, not all passing"
|
|
1289
|
+
if tests_exist else "No test tasks found"
|
|
1290
|
+
),
|
|
1291
|
+
},
|
|
1292
|
+
{
|
|
1293
|
+
"item": "API compatibility verified",
|
|
1294
|
+
"verified": facade is not None,
|
|
1295
|
+
"details": (
|
|
1296
|
+
"Facade route registered"
|
|
1297
|
+
if facade else "No facade route registered"
|
|
1298
|
+
),
|
|
1299
|
+
},
|
|
1300
|
+
{
|
|
1301
|
+
"item": "Data migration complete",
|
|
1302
|
+
"verified": data_migrated,
|
|
1303
|
+
"details": (
|
|
1304
|
+
f"{len(schema_task)} schema/data task(s) completed"
|
|
1305
|
+
if data_migrated else
|
|
1306
|
+
f"{len(schema_task)} schema/data task(s) pending"
|
|
1307
|
+
if schema_task else "No data migration tasks defined"
|
|
1308
|
+
),
|
|
1309
|
+
},
|
|
1310
|
+
{
|
|
1311
|
+
"item": "Rollback plan exists",
|
|
1312
|
+
"verified": facade is not None,
|
|
1313
|
+
"details": (
|
|
1314
|
+
"Facade allows instant rollback to legacy routing"
|
|
1315
|
+
if facade else "No facade — manual rollback required"
|
|
1316
|
+
),
|
|
1317
|
+
},
|
|
1318
|
+
{
|
|
1319
|
+
"item": "Monitoring in place",
|
|
1320
|
+
"verified": False,
|
|
1321
|
+
"details": "Verify health checks and alerting configured for modern endpoint",
|
|
1322
|
+
},
|
|
1323
|
+
{
|
|
1324
|
+
"item": "Compliance controls mapped",
|
|
1325
|
+
"verified": len(compliance_links) > 0,
|
|
1326
|
+
"details": (
|
|
1327
|
+
f"{len(compliance_links)} compliance link(s) found"
|
|
1328
|
+
if compliance_links else "No compliance controls linked"
|
|
1329
|
+
),
|
|
1330
|
+
},
|
|
1331
|
+
]
|
|
1332
|
+
|
|
1333
|
+
all_verified = all(item["verified"] for item in checklist)
|
|
1334
|
+
|
|
1335
|
+
result = {
|
|
1336
|
+
"plan_id": plan_id,
|
|
1337
|
+
"component_id": component_id,
|
|
1338
|
+
"component_name": comp["name"],
|
|
1339
|
+
"qualified_name": comp["qualified_name"],
|
|
1340
|
+
"ready_for_cutover": all_verified,
|
|
1341
|
+
"verified_count": sum(1 for i in checklist if i["verified"]),
|
|
1342
|
+
"total_checks": len(checklist),
|
|
1343
|
+
"checklist": checklist,
|
|
1344
|
+
"generated_at": datetime.now(timezone.utc).isoformat(),
|
|
1345
|
+
}
|
|
1346
|
+
|
|
1347
|
+
ready_label = "READY" if all_verified else "NOT READY"
|
|
1348
|
+
verified_count = sum(1 for i in checklist if i["verified"])
|
|
1349
|
+
print(f"[INFO] Cutover Checklist for '{comp['name']}': {ready_label}")
|
|
1350
|
+
print(f" Verified: {verified_count}/{len(checklist)}")
|
|
1351
|
+
for item in checklist:
|
|
1352
|
+
mark = "[x]" if item["verified"] else "[ ]"
|
|
1353
|
+
print(f" {mark} {item['item']}")
|
|
1354
|
+
return result
|
|
1355
|
+
|
|
1356
|
+
finally:
|
|
1357
|
+
conn.close()
|
|
1358
|
+
|
|
1359
|
+
|
|
1360
|
+
# ---------------------------------------------------------------------------
|
|
1361
|
+
# 9. Execute cutover
|
|
1362
|
+
# ---------------------------------------------------------------------------
|
|
1363
|
+
|
|
1364
|
+
def execute_cutover(plan_id, component_id):
|
|
1365
|
+
"""Execute the cutover for a component, marking it as migrated to modern.
|
|
1366
|
+
|
|
1367
|
+
This is the operational step that:
|
|
1368
|
+
1. Updates the component status to 'modern'
|
|
1369
|
+
2. Creates a digital thread traceability link
|
|
1370
|
+
3. Updates facade routing to point to modern backend
|
|
1371
|
+
4. Logs an audit trail event
|
|
1372
|
+
5. Updates the migration plan's completed_tasks count
|
|
1373
|
+
|
|
1374
|
+
Args:
|
|
1375
|
+
plan_id: Migration plan ID.
|
|
1376
|
+
component_id: Legacy component ID to cut over.
|
|
1377
|
+
|
|
1378
|
+
Returns:
|
|
1379
|
+
dict with cutover execution result.
|
|
1380
|
+
"""
|
|
1381
|
+
conn = _get_db()
|
|
1382
|
+
try:
|
|
1383
|
+
# Verify plan exists
|
|
1384
|
+
plan = conn.execute(
|
|
1385
|
+
"SELECT * FROM migration_plans WHERE id = ?", (plan_id,)
|
|
1386
|
+
).fetchone()
|
|
1387
|
+
if not plan:
|
|
1388
|
+
raise ValueError(f"Migration plan '{plan_id}' not found.")
|
|
1389
|
+
|
|
1390
|
+
# Verify component exists
|
|
1391
|
+
comp = conn.execute(
|
|
1392
|
+
"SELECT * FROM legacy_components WHERE id = ?", (component_id,)
|
|
1393
|
+
).fetchone()
|
|
1394
|
+
if not comp:
|
|
1395
|
+
raise ValueError(f"Component '{component_id}' not found.")
|
|
1396
|
+
|
|
1397
|
+
# Find the cutover task
|
|
1398
|
+
task = conn.execute(
|
|
1399
|
+
"""SELECT * FROM migration_tasks
|
|
1400
|
+
WHERE plan_id = ? AND legacy_component_id = ?
|
|
1401
|
+
AND task_type = 'cutover'""",
|
|
1402
|
+
(plan_id, component_id),
|
|
1403
|
+
).fetchone()
|
|
1404
|
+
if not task:
|
|
1405
|
+
raise ValueError(
|
|
1406
|
+
f"No cutover task found for component '{component_id}' "
|
|
1407
|
+
f"in plan '{plan_id}'."
|
|
1408
|
+
)
|
|
1409
|
+
|
|
1410
|
+
now = datetime.now(timezone.utc).isoformat()
|
|
1411
|
+
project_id = _get_plan_project_id(conn, plan_id)
|
|
1412
|
+
|
|
1413
|
+
# 1. Update cutover task to completed with modern status
|
|
1414
|
+
desc = {}
|
|
1415
|
+
if task["description"]:
|
|
1416
|
+
try:
|
|
1417
|
+
desc = json.loads(task["description"])
|
|
1418
|
+
except (json.JSONDecodeError, TypeError):
|
|
1419
|
+
desc = {}
|
|
1420
|
+
desc["strangler_fig_status"] = "modern"
|
|
1421
|
+
desc["cutover_executed_at"] = now
|
|
1422
|
+
|
|
1423
|
+
conn.execute(
|
|
1424
|
+
"""UPDATE migration_tasks
|
|
1425
|
+
SET status = 'completed', description = ?, completed_at = ?
|
|
1426
|
+
WHERE id = ?""",
|
|
1427
|
+
(json.dumps(desc), now, task["id"]),
|
|
1428
|
+
)
|
|
1429
|
+
|
|
1430
|
+
# 2. Create digital thread link: legacy_component replaces -> code_module
|
|
1431
|
+
modern_target_id = f"modern-{component_id}"
|
|
1432
|
+
try:
|
|
1433
|
+
conn.execute(
|
|
1434
|
+
"""INSERT INTO digital_thread_links
|
|
1435
|
+
(project_id, source_type, source_id, target_type,
|
|
1436
|
+
target_id, link_type, confidence, evidence, created_by)
|
|
1437
|
+
VALUES (?, 'legacy_component', ?, 'code_module', ?,
|
|
1438
|
+
'replaces', 0.95, ?, 'strangler-fig-manager')""",
|
|
1439
|
+
(
|
|
1440
|
+
project_id,
|
|
1441
|
+
component_id,
|
|
1442
|
+
modern_target_id,
|
|
1443
|
+
f"Cutover executed: {comp['name']} migrated to modern implementation",
|
|
1444
|
+
),
|
|
1445
|
+
)
|
|
1446
|
+
except sqlite3.IntegrityError:
|
|
1447
|
+
pass # Link already exists
|
|
1448
|
+
|
|
1449
|
+
# 3. Update facade routing for this component
|
|
1450
|
+
facade_tasks = conn.execute(
|
|
1451
|
+
"""SELECT * FROM migration_tasks
|
|
1452
|
+
WHERE plan_id = ? AND legacy_component_id = ?
|
|
1453
|
+
AND task_type = 'generate_facade'""",
|
|
1454
|
+
(plan_id, component_id),
|
|
1455
|
+
).fetchall()
|
|
1456
|
+
|
|
1457
|
+
for ft in facade_tasks:
|
|
1458
|
+
f_desc = {}
|
|
1459
|
+
if ft["description"]:
|
|
1460
|
+
try:
|
|
1461
|
+
f_desc = json.loads(ft["description"])
|
|
1462
|
+
except (json.JSONDecodeError, TypeError):
|
|
1463
|
+
f_desc = {}
|
|
1464
|
+
f_desc["routing"] = "modern"
|
|
1465
|
+
f_desc["routing_updated_at"] = now
|
|
1466
|
+
conn.execute(
|
|
1467
|
+
"""UPDATE migration_tasks
|
|
1468
|
+
SET description = ?, status = 'completed'
|
|
1469
|
+
WHERE id = ?""",
|
|
1470
|
+
(json.dumps(f_desc), ft["id"]),
|
|
1471
|
+
)
|
|
1472
|
+
|
|
1473
|
+
# 4. Log audit trail event
|
|
1474
|
+
_log_audit(
|
|
1475
|
+
conn,
|
|
1476
|
+
project_id=project_id,
|
|
1477
|
+
event_type="strangler_fig_cutover",
|
|
1478
|
+
actor="strangler-fig-manager",
|
|
1479
|
+
action=f"Cutover executed for component: {comp['name']}",
|
|
1480
|
+
details={
|
|
1481
|
+
"plan_id": plan_id,
|
|
1482
|
+
"component_id": component_id,
|
|
1483
|
+
"component_name": comp["name"],
|
|
1484
|
+
"qualified_name": comp["qualified_name"],
|
|
1485
|
+
"cutover_status": "modern",
|
|
1486
|
+
"facades_updated": len(facade_tasks),
|
|
1487
|
+
},
|
|
1488
|
+
)
|
|
1489
|
+
|
|
1490
|
+
# 5. Update migration plan completed_tasks count
|
|
1491
|
+
completed = conn.execute(
|
|
1492
|
+
"""SELECT COUNT(*) as cnt FROM migration_tasks
|
|
1493
|
+
WHERE plan_id = ? AND status = 'completed'""",
|
|
1494
|
+
(plan_id,),
|
|
1495
|
+
).fetchone()
|
|
1496
|
+
|
|
1497
|
+
completed_count = completed["cnt"] if completed else 0
|
|
1498
|
+
total = plan["total_tasks"] or 0
|
|
1499
|
+
|
|
1500
|
+
new_plan_status = plan["status"]
|
|
1501
|
+
completion_date = None
|
|
1502
|
+
if completed_count >= total and total > 0:
|
|
1503
|
+
new_plan_status = "completed"
|
|
1504
|
+
completion_date = now
|
|
1505
|
+
|
|
1506
|
+
conn.execute(
|
|
1507
|
+
"""UPDATE migration_plans
|
|
1508
|
+
SET completed_tasks = ?, status = ?, completion_date = ?,
|
|
1509
|
+
updated_at = ?
|
|
1510
|
+
WHERE id = ?""",
|
|
1511
|
+
(completed_count, new_plan_status, completion_date, now, plan_id),
|
|
1512
|
+
)
|
|
1513
|
+
|
|
1514
|
+
conn.commit()
|
|
1515
|
+
|
|
1516
|
+
result = {
|
|
1517
|
+
"plan_id": plan_id,
|
|
1518
|
+
"component_id": component_id,
|
|
1519
|
+
"component_name": comp["name"],
|
|
1520
|
+
"cutover_status": "modern",
|
|
1521
|
+
"task_id": task["id"],
|
|
1522
|
+
"digital_thread_link": {
|
|
1523
|
+
"source_type": "legacy_component",
|
|
1524
|
+
"source_id": component_id,
|
|
1525
|
+
"target_type": "code_module",
|
|
1526
|
+
"target_id": modern_target_id,
|
|
1527
|
+
"link_type": "replaces",
|
|
1528
|
+
},
|
|
1529
|
+
"facades_updated": len(facade_tasks),
|
|
1530
|
+
"plan_completed_tasks": completed_count,
|
|
1531
|
+
"plan_total_tasks": total,
|
|
1532
|
+
"plan_status": new_plan_status,
|
|
1533
|
+
"executed_at": now,
|
|
1534
|
+
}
|
|
1535
|
+
|
|
1536
|
+
print(f"[INFO] Cutover executed for '{comp['name']}'")
|
|
1537
|
+
print(f" Status: modern | Facades updated: {len(facade_tasks)}")
|
|
1538
|
+
print(f" Plan progress: {completed_count}/{total} tasks completed")
|
|
1539
|
+
return result
|
|
1540
|
+
|
|
1541
|
+
finally:
|
|
1542
|
+
conn.close()
|
|
1543
|
+
|
|
1544
|
+
|
|
1545
|
+
# ---------------------------------------------------------------------------
|
|
1546
|
+
# CLI interface
|
|
1547
|
+
# ---------------------------------------------------------------------------
|
|
1548
|
+
|
|
1549
|
+
def main():
|
|
1550
|
+
"""Command-line entry point for the strangler fig migration manager."""
|
|
1551
|
+
parser = argparse.ArgumentParser(
|
|
1552
|
+
description="CUI // SP-CTI -- Strangler Fig Pattern Migration Manager",
|
|
1553
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
1554
|
+
epilog=textwrap.dedent("""\
|
|
1555
|
+
Examples:
|
|
1556
|
+
# Initialize strangler fig tracking
|
|
1557
|
+
python tools/modernization/strangler_fig_manager.py \\
|
|
1558
|
+
--plan-id mplan-abc123 --create
|
|
1559
|
+
|
|
1560
|
+
# Check cutover status
|
|
1561
|
+
python tools/modernization/strangler_fig_manager.py \\
|
|
1562
|
+
--plan-id mplan-abc123 --status
|
|
1563
|
+
|
|
1564
|
+
# Move component to parallel mode
|
|
1565
|
+
python tools/modernization/strangler_fig_manager.py \\
|
|
1566
|
+
--plan-id mplan-abc123 --cutover \\
|
|
1567
|
+
--component-id lcomp-xyz789 --to parallel
|
|
1568
|
+
|
|
1569
|
+
# Generate routing config as JSON
|
|
1570
|
+
python tools/modernization/strangler_fig_manager.py \\
|
|
1571
|
+
--plan-id mplan-abc123 --routing --json
|
|
1572
|
+
|
|
1573
|
+
# Check coexistence health
|
|
1574
|
+
python tools/modernization/strangler_fig_manager.py \\
|
|
1575
|
+
--plan-id mplan-abc123 --health
|
|
1576
|
+
|
|
1577
|
+
# Generate cutover checklist
|
|
1578
|
+
python tools/modernization/strangler_fig_manager.py \\
|
|
1579
|
+
--plan-id mplan-abc123 --checklist \\
|
|
1580
|
+
--component-id lcomp-xyz789
|
|
1581
|
+
|
|
1582
|
+
# Execute cutover
|
|
1583
|
+
python tools/modernization/strangler_fig_manager.py \\
|
|
1584
|
+
--plan-id mplan-abc123 --execute-cutover \\
|
|
1585
|
+
--component-id lcomp-xyz789
|
|
1586
|
+
|
|
1587
|
+
Classification: CUI // SP-CTI
|
|
1588
|
+
"""),
|
|
1589
|
+
)
|
|
1590
|
+
|
|
1591
|
+
parser.add_argument(
|
|
1592
|
+
"--plan-id", required=True,
|
|
1593
|
+
help="Migration plan ID (required for all operations)",
|
|
1594
|
+
)
|
|
1595
|
+
parser.add_argument(
|
|
1596
|
+
"--component-id",
|
|
1597
|
+
help="Legacy component ID (required for --cutover, --checklist, --execute-cutover)",
|
|
1598
|
+
)
|
|
1599
|
+
|
|
1600
|
+
# Action flags
|
|
1601
|
+
action_group = parser.add_mutually_exclusive_group(required=True)
|
|
1602
|
+
action_group.add_argument(
|
|
1603
|
+
"--create", action="store_true",
|
|
1604
|
+
help="Initialize strangler fig tracking for the plan",
|
|
1605
|
+
)
|
|
1606
|
+
action_group.add_argument(
|
|
1607
|
+
"--status", action="store_true",
|
|
1608
|
+
help="Show cutover status dashboard",
|
|
1609
|
+
)
|
|
1610
|
+
action_group.add_argument(
|
|
1611
|
+
"--cutover", action="store_true",
|
|
1612
|
+
help="Track component cutover status change (requires --component-id and --to)",
|
|
1613
|
+
)
|
|
1614
|
+
action_group.add_argument(
|
|
1615
|
+
"--routing", action="store_true",
|
|
1616
|
+
help="Generate API gateway routing configuration",
|
|
1617
|
+
)
|
|
1618
|
+
action_group.add_argument(
|
|
1619
|
+
"--health", action="store_true",
|
|
1620
|
+
help="Check coexistence health between legacy and modern",
|
|
1621
|
+
)
|
|
1622
|
+
action_group.add_argument(
|
|
1623
|
+
"--checklist", action="store_true",
|
|
1624
|
+
help="Generate pre-cutover validation checklist (requires --component-id)",
|
|
1625
|
+
)
|
|
1626
|
+
action_group.add_argument(
|
|
1627
|
+
"--execute-cutover", action="store_true",
|
|
1628
|
+
help="Execute cutover, marking component as modern (requires --component-id)",
|
|
1629
|
+
)
|
|
1630
|
+
|
|
1631
|
+
# Cutover options
|
|
1632
|
+
parser.add_argument(
|
|
1633
|
+
"--to", dest="cutover_target",
|
|
1634
|
+
choices=CUTOVER_STATUSES,
|
|
1635
|
+
help="Target cutover status (used with --cutover)",
|
|
1636
|
+
)
|
|
1637
|
+
|
|
1638
|
+
# Output format
|
|
1639
|
+
parser.add_argument(
|
|
1640
|
+
"--json", action="store_true", dest="json_output",
|
|
1641
|
+
help="Output results as JSON",
|
|
1642
|
+
)
|
|
1643
|
+
|
|
1644
|
+
args = parser.parse_args()
|
|
1645
|
+
|
|
1646
|
+
try:
|
|
1647
|
+
if args.create:
|
|
1648
|
+
result = create_strangler_plan(args.plan_id)
|
|
1649
|
+
if args.json_output:
|
|
1650
|
+
print(json.dumps(result, indent=2))
|
|
1651
|
+
|
|
1652
|
+
elif args.status:
|
|
1653
|
+
result = get_cutover_status(args.plan_id)
|
|
1654
|
+
if args.json_output:
|
|
1655
|
+
print(json.dumps(result, indent=2))
|
|
1656
|
+
|
|
1657
|
+
elif args.cutover:
|
|
1658
|
+
if not args.component_id:
|
|
1659
|
+
parser.error("--cutover requires --component-id")
|
|
1660
|
+
if not args.cutover_target:
|
|
1661
|
+
parser.error("--cutover requires --to <status>")
|
|
1662
|
+
result = track_cutover(
|
|
1663
|
+
args.plan_id, args.component_id, args.cutover_target
|
|
1664
|
+
)
|
|
1665
|
+
if args.json_output:
|
|
1666
|
+
print(json.dumps(result, indent=2))
|
|
1667
|
+
|
|
1668
|
+
elif args.routing:
|
|
1669
|
+
result = generate_routing_config(args.plan_id)
|
|
1670
|
+
if args.json_output:
|
|
1671
|
+
print(json.dumps(result, indent=2))
|
|
1672
|
+
|
|
1673
|
+
elif args.health:
|
|
1674
|
+
result = check_coexistence_health(args.plan_id)
|
|
1675
|
+
if args.json_output:
|
|
1676
|
+
print(json.dumps(result, indent=2))
|
|
1677
|
+
|
|
1678
|
+
elif args.checklist:
|
|
1679
|
+
if not args.component_id:
|
|
1680
|
+
parser.error("--checklist requires --component-id")
|
|
1681
|
+
result = generate_cutover_checklist(args.plan_id, args.component_id)
|
|
1682
|
+
if args.json_output:
|
|
1683
|
+
print(json.dumps(result, indent=2))
|
|
1684
|
+
|
|
1685
|
+
elif args.execute_cutover:
|
|
1686
|
+
if not args.component_id:
|
|
1687
|
+
parser.error("--execute-cutover requires --component-id")
|
|
1688
|
+
result = execute_cutover(args.plan_id, args.component_id)
|
|
1689
|
+
if args.json_output:
|
|
1690
|
+
print(json.dumps(result, indent=2))
|
|
1691
|
+
|
|
1692
|
+
except FileNotFoundError as exc:
|
|
1693
|
+
print(f"[ERROR] {exc}")
|
|
1694
|
+
raise SystemExit(1)
|
|
1695
|
+
except ValueError as exc:
|
|
1696
|
+
print(f"[ERROR] {exc}")
|
|
1697
|
+
raise SystemExit(1)
|
|
1698
|
+
except sqlite3.Error as exc:
|
|
1699
|
+
print(f"[ERROR] Database error: {exc}")
|
|
1700
|
+
raise SystemExit(1)
|
|
1701
|
+
|
|
1702
|
+
|
|
1703
|
+
if __name__ == "__main__":
|
|
1704
|
+
main()
|
|
1705
|
+
# [TEMPLATE: CUI // SP-CTI]
|