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,1711 @@
|
|
|
1
|
+
# [TEMPLATE: CUI // SP-CTI]
|
|
2
|
+
#!/usr/bin/env python3
|
|
3
|
+
"""ICDEV Modular Installer — central CLI for configuring and installing ICDEV.
|
|
4
|
+
|
|
5
|
+
Supports three modes of operation:
|
|
6
|
+
|
|
7
|
+
1. **Interactive wizard** (``--interactive``):
|
|
8
|
+
Guided 6-step terminal wizard that walks users through organization type,
|
|
9
|
+
team size, compliance posture, deployment target, and optional modules.
|
|
10
|
+
|
|
11
|
+
2. **Profile-based** (``--profile <name>``):
|
|
12
|
+
Non-interactive installation driven by a deployment profile from
|
|
13
|
+
``args/deployment_profiles.yaml``, with optional CLI overrides for
|
|
14
|
+
compliance frameworks and platform.
|
|
15
|
+
|
|
16
|
+
3. **Upgrade / add-module** (``--upgrade``, ``--add-module``, ``--add-compliance``,
|
|
17
|
+
``--status``):
|
|
18
|
+
Post-install operations to extend an existing installation with additional
|
|
19
|
+
modules or compliance frameworks.
|
|
20
|
+
|
|
21
|
+
All modes support ``--dry-run`` to preview changes without executing them,
|
|
22
|
+
``--json`` for machine-readable output, and ``--human`` for colorized terminal
|
|
23
|
+
output.
|
|
24
|
+
|
|
25
|
+
Dependencies: Python stdlib only (json, pathlib, argparse, sqlite3, re,
|
|
26
|
+
datetime). PyYAML used when available but not required.
|
|
27
|
+
|
|
28
|
+
CLI::
|
|
29
|
+
|
|
30
|
+
# Interactive wizard
|
|
31
|
+
python tools/installer/installer.py --interactive
|
|
32
|
+
|
|
33
|
+
# Profile-based
|
|
34
|
+
python tools/installer/installer.py --profile dod_team
|
|
35
|
+
python tools/installer/installer.py --profile dod_team --compliance fedramp_high,cmmc --platform k8s
|
|
36
|
+
|
|
37
|
+
# Upgrade / add
|
|
38
|
+
python tools/installer/installer.py --upgrade
|
|
39
|
+
python tools/installer/installer.py --add-module marketplace
|
|
40
|
+
python tools/installer/installer.py --add-compliance hipaa
|
|
41
|
+
python tools/installer/installer.py --status
|
|
42
|
+
python tools/installer/installer.py --status --json
|
|
43
|
+
|
|
44
|
+
# Dry run
|
|
45
|
+
python tools/installer/installer.py --profile dod_team --dry-run
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
from __future__ import annotations
|
|
49
|
+
|
|
50
|
+
import argparse
|
|
51
|
+
import json
|
|
52
|
+
import re
|
|
53
|
+
import sqlite3
|
|
54
|
+
import sys
|
|
55
|
+
from datetime import datetime, timezone
|
|
56
|
+
from pathlib import Path
|
|
57
|
+
from typing import Any, Dict, List, Optional, Set, Tuple
|
|
58
|
+
from icdev._paths import get_project_root
|
|
59
|
+
|
|
60
|
+
# ---------------------------------------------------------------------------
|
|
61
|
+
# Path resolution
|
|
62
|
+
# ---------------------------------------------------------------------------
|
|
63
|
+
|
|
64
|
+
BASE_DIR = get_project_root()
|
|
65
|
+
DATA_DIR = BASE_DIR / "data"
|
|
66
|
+
DB_PATH = DATA_DIR / "icdev.db"
|
|
67
|
+
MANIFEST_PATH = BASE_DIR / "args" / "installation_manifest.yaml"
|
|
68
|
+
PROFILES_PATH = BASE_DIR / "args" / "deployment_profiles.yaml"
|
|
69
|
+
CUI_MARKINGS_PATH = BASE_DIR / "args" / "cui_markings.yaml"
|
|
70
|
+
REGISTRY_PATH = DATA_DIR / "installation.json"
|
|
71
|
+
|
|
72
|
+
# Ensure BASE_DIR is on sys.path so that ``from tools.xxx import ...`` works
|
|
73
|
+
# when invoked directly (consistent with other ICDEV CLI tools).
|
|
74
|
+
if str(BASE_DIR) not in sys.path:
|
|
75
|
+
sys.path.insert(0, str(BASE_DIR))
|
|
76
|
+
|
|
77
|
+
# ---------------------------------------------------------------------------
|
|
78
|
+
# Lazy imports — keep module-level import list minimal so that the installer
|
|
79
|
+
# can be imported even when sibling modules are not yet installed.
|
|
80
|
+
# ---------------------------------------------------------------------------
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def _get_module_registry():
|
|
84
|
+
"""Import and return the ModuleRegistry class."""
|
|
85
|
+
from icdev.tools.installer.module_registry import ModuleRegistry
|
|
86
|
+
return ModuleRegistry
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def _get_compliance_configurator():
|
|
90
|
+
"""Import and return the ComplianceConfigurator class."""
|
|
91
|
+
from icdev.tools.installer.compliance_configurator import ComplianceConfigurator
|
|
92
|
+
return ComplianceConfigurator
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
# ---------------------------------------------------------------------------
|
|
96
|
+
# Lightweight YAML loader (mirrors module_registry.py pattern)
|
|
97
|
+
# ---------------------------------------------------------------------------
|
|
98
|
+
|
|
99
|
+
def _load_yaml(path: Path) -> Dict[str, Any]:
|
|
100
|
+
"""Load a YAML file, falling back to a minimal parser if PyYAML is absent."""
|
|
101
|
+
try:
|
|
102
|
+
import yaml # type: ignore
|
|
103
|
+
with open(path, "r", encoding="utf-8") as fh:
|
|
104
|
+
return yaml.safe_load(fh) or {}
|
|
105
|
+
except ImportError:
|
|
106
|
+
pass
|
|
107
|
+
|
|
108
|
+
# Minimal fallback — sufficient for the flat/nested structures in the
|
|
109
|
+
# deployment_profiles and installation_manifest files.
|
|
110
|
+
result: Dict[str, Any] = {}
|
|
111
|
+
if not path.exists():
|
|
112
|
+
return result
|
|
113
|
+
with open(path, "r", encoding="utf-8") as fh:
|
|
114
|
+
lines = fh.readlines()
|
|
115
|
+
|
|
116
|
+
stack: List[Tuple[int, str, Dict]] = [] # (indent, key, dict_ref)
|
|
117
|
+
current: Dict[str, Any] = result
|
|
118
|
+
|
|
119
|
+
for line in lines:
|
|
120
|
+
stripped = line.rstrip()
|
|
121
|
+
if not stripped or stripped.lstrip().startswith("#"):
|
|
122
|
+
continue
|
|
123
|
+
indent = len(line) - len(line.lstrip())
|
|
124
|
+
content = stripped.lstrip()
|
|
125
|
+
|
|
126
|
+
# Pop stack to correct nesting level
|
|
127
|
+
while stack and stack[-1][0] >= indent:
|
|
128
|
+
stack.pop()
|
|
129
|
+
if stack:
|
|
130
|
+
current = stack[-1][2]
|
|
131
|
+
else:
|
|
132
|
+
current = result
|
|
133
|
+
|
|
134
|
+
# List item
|
|
135
|
+
if content.startswith("- "):
|
|
136
|
+
item = content[2:].strip()
|
|
137
|
+
# Find parent key
|
|
138
|
+
if stack:
|
|
139
|
+
parent_key = stack[-1][1]
|
|
140
|
+
parent_dict = stack[-2][2] if len(stack) > 1 else result
|
|
141
|
+
existing = parent_dict.get(parent_key)
|
|
142
|
+
if not isinstance(existing, list):
|
|
143
|
+
parent_dict[parent_key] = []
|
|
144
|
+
parent_dict[parent_key].append(item)
|
|
145
|
+
continue
|
|
146
|
+
|
|
147
|
+
# Key: value pair
|
|
148
|
+
if ":" in content:
|
|
149
|
+
key, _, val = content.partition(":")
|
|
150
|
+
key = key.strip().strip('"').strip("'")
|
|
151
|
+
val = val.strip().strip('"').strip("'")
|
|
152
|
+
|
|
153
|
+
if val.startswith("[") and val.endswith("]"):
|
|
154
|
+
# Inline list: [a, b, c]
|
|
155
|
+
items = [
|
|
156
|
+
v.strip().strip('"').strip("'")
|
|
157
|
+
for v in val[1:-1].split(",")
|
|
158
|
+
if v.strip()
|
|
159
|
+
]
|
|
160
|
+
current[key] = items
|
|
161
|
+
elif val:
|
|
162
|
+
# Scalar value
|
|
163
|
+
if val.lower() == "true":
|
|
164
|
+
current[key] = True
|
|
165
|
+
elif val.lower() == "false":
|
|
166
|
+
current[key] = False
|
|
167
|
+
else:
|
|
168
|
+
current[key] = val
|
|
169
|
+
else:
|
|
170
|
+
# Nested mapping — create empty dict and push to stack
|
|
171
|
+
current[key] = {}
|
|
172
|
+
stack.append((indent, key, current[key]))
|
|
173
|
+
current = current[key]
|
|
174
|
+
continue
|
|
175
|
+
|
|
176
|
+
# Non-nested key — still push for potential list children
|
|
177
|
+
stack.append((indent, key, current))
|
|
178
|
+
|
|
179
|
+
return result
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
# ---------------------------------------------------------------------------
|
|
183
|
+
# ModularDBInitializer
|
|
184
|
+
# ---------------------------------------------------------------------------
|
|
185
|
+
|
|
186
|
+
class ModularDBInitializer:
|
|
187
|
+
"""Selectively initialize database tables based on installed modules.
|
|
188
|
+
|
|
189
|
+
Instead of running the full 143-table init_icdev_db.py monolith, this
|
|
190
|
+
class reads the ``db_table_groups`` mapping from the installation manifest
|
|
191
|
+
and creates only the tables required by the selected modules.
|
|
192
|
+
|
|
193
|
+
This is strictly additive — existing tables are never dropped.
|
|
194
|
+
"""
|
|
195
|
+
|
|
196
|
+
def __init__(
|
|
197
|
+
self,
|
|
198
|
+
manifest_path: Optional[Path] = None,
|
|
199
|
+
db_path: Optional[Path] = None,
|
|
200
|
+
) -> None:
|
|
201
|
+
self.manifest_path = manifest_path or MANIFEST_PATH
|
|
202
|
+
self.db_path = db_path or DB_PATH
|
|
203
|
+
self._manifest = _load_yaml(self.manifest_path) if self.manifest_path.exists() else {}
|
|
204
|
+
self._schema_sql: Optional[str] = None
|
|
205
|
+
|
|
206
|
+
# ------------------------------------------------------------------
|
|
207
|
+
# Schema SQL extraction
|
|
208
|
+
# ------------------------------------------------------------------
|
|
209
|
+
|
|
210
|
+
def _load_schema_sql(self) -> str:
|
|
211
|
+
"""Load the full SCHEMA_SQL string from init_icdev_db.py."""
|
|
212
|
+
if self._schema_sql is not None:
|
|
213
|
+
return self._schema_sql
|
|
214
|
+
|
|
215
|
+
init_path = BASE_DIR / "tools" / "db" / "init_icdev_db.py"
|
|
216
|
+
if not init_path.exists():
|
|
217
|
+
self._schema_sql = ""
|
|
218
|
+
return self._schema_sql
|
|
219
|
+
|
|
220
|
+
# Import SCHEMA_SQL from the module
|
|
221
|
+
try:
|
|
222
|
+
import importlib.util
|
|
223
|
+
spec = importlib.util.spec_from_file_location("init_icdev_db", str(init_path))
|
|
224
|
+
if spec and spec.loader:
|
|
225
|
+
mod = importlib.util.module_from_spec(spec)
|
|
226
|
+
spec.loader.exec_module(mod) # type: ignore[union-attr]
|
|
227
|
+
self._schema_sql = getattr(mod, "SCHEMA_SQL", "")
|
|
228
|
+
else:
|
|
229
|
+
self._schema_sql = ""
|
|
230
|
+
except Exception:
|
|
231
|
+
self._schema_sql = ""
|
|
232
|
+
|
|
233
|
+
return self._schema_sql
|
|
234
|
+
|
|
235
|
+
def _extract_create_statements(self, table_names: List[str]) -> List[str]:
|
|
236
|
+
"""Extract CREATE TABLE IF NOT EXISTS statements for specific tables.
|
|
237
|
+
|
|
238
|
+
Parses the full SCHEMA_SQL to find the complete CREATE TABLE statement
|
|
239
|
+
for each requested table name.
|
|
240
|
+
"""
|
|
241
|
+
schema = self._load_schema_sql()
|
|
242
|
+
if not schema:
|
|
243
|
+
return []
|
|
244
|
+
|
|
245
|
+
statements: List[str] = []
|
|
246
|
+
# Split on CREATE TABLE boundaries
|
|
247
|
+
pattern = re.compile(
|
|
248
|
+
r"(CREATE\s+TABLE\s+IF\s+NOT\s+EXISTS\s+(\w+)\s*\(.*?\);)",
|
|
249
|
+
re.DOTALL | re.IGNORECASE,
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
for match in pattern.finditer(schema):
|
|
253
|
+
full_stmt = match.group(1)
|
|
254
|
+
tbl_name = match.group(2)
|
|
255
|
+
if tbl_name in table_names:
|
|
256
|
+
statements.append(full_stmt)
|
|
257
|
+
|
|
258
|
+
# Also extract CREATE INDEX statements for matched tables
|
|
259
|
+
idx_pattern = re.compile(
|
|
260
|
+
r"(CREATE\s+INDEX\s+IF\s+NOT\s+EXISTS\s+\w+\s+ON\s+(\w+)\s*\(.*?\);)",
|
|
261
|
+
re.DOTALL | re.IGNORECASE,
|
|
262
|
+
)
|
|
263
|
+
for match in idx_pattern.finditer(schema):
|
|
264
|
+
idx_stmt = match.group(1)
|
|
265
|
+
idx_table = match.group(2)
|
|
266
|
+
if idx_table in table_names:
|
|
267
|
+
statements.append(idx_stmt)
|
|
268
|
+
|
|
269
|
+
return statements
|
|
270
|
+
|
|
271
|
+
def _resolve_table_groups(self, module_ids: List[str]) -> List[str]:
|
|
272
|
+
"""Resolve module IDs to a deduplicated list of table names.
|
|
273
|
+
|
|
274
|
+
Uses the ``db_table_groups`` section of the installation manifest to
|
|
275
|
+
map module -> group IDs -> table names.
|
|
276
|
+
"""
|
|
277
|
+
modules_cfg = self._manifest.get("modules", {})
|
|
278
|
+
table_groups_cfg = self._manifest.get("db_table_groups", {})
|
|
279
|
+
|
|
280
|
+
# Collect all group IDs needed
|
|
281
|
+
group_ids: List[str] = []
|
|
282
|
+
for mod_id in module_ids:
|
|
283
|
+
mod_def = modules_cfg.get(mod_id, {})
|
|
284
|
+
groups = mod_def.get("db_table_groups", [])
|
|
285
|
+
if isinstance(groups, str):
|
|
286
|
+
groups = [groups]
|
|
287
|
+
for g in groups:
|
|
288
|
+
if g and g not in group_ids:
|
|
289
|
+
group_ids.append(g)
|
|
290
|
+
|
|
291
|
+
# Resolve group IDs to table names
|
|
292
|
+
table_names: List[str] = []
|
|
293
|
+
for gid in group_ids:
|
|
294
|
+
group_def = table_groups_cfg.get(gid, {})
|
|
295
|
+
tables = group_def.get("tables", [])
|
|
296
|
+
if isinstance(tables, str):
|
|
297
|
+
tables = [tables]
|
|
298
|
+
for t in tables:
|
|
299
|
+
if t and t not in table_names:
|
|
300
|
+
table_names.append(t)
|
|
301
|
+
|
|
302
|
+
return table_names
|
|
303
|
+
|
|
304
|
+
def initialize(
|
|
305
|
+
self,
|
|
306
|
+
module_ids: List[str],
|
|
307
|
+
dry_run: bool = False,
|
|
308
|
+
) -> Dict[str, Any]:
|
|
309
|
+
"""Create database tables required by the given modules.
|
|
310
|
+
|
|
311
|
+
Args:
|
|
312
|
+
module_ids: List of module IDs to initialize tables for.
|
|
313
|
+
dry_run: If True, return the plan without executing.
|
|
314
|
+
|
|
315
|
+
Returns:
|
|
316
|
+
Dict with ``tables_created``, ``sql_statements`` (dry-run),
|
|
317
|
+
and ``db_path``.
|
|
318
|
+
"""
|
|
319
|
+
table_names = self._resolve_table_groups(module_ids)
|
|
320
|
+
|
|
321
|
+
if not table_names:
|
|
322
|
+
return {
|
|
323
|
+
"tables_created": [],
|
|
324
|
+
"table_count": 0,
|
|
325
|
+
"db_path": str(self.db_path),
|
|
326
|
+
"dry_run": dry_run,
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
statements = self._extract_create_statements(table_names)
|
|
330
|
+
|
|
331
|
+
if dry_run:
|
|
332
|
+
return {
|
|
333
|
+
"tables_planned": table_names,
|
|
334
|
+
"table_count": len(table_names),
|
|
335
|
+
"sql_statement_count": len(statements),
|
|
336
|
+
"db_path": str(self.db_path),
|
|
337
|
+
"dry_run": True,
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
# Execute the SQL
|
|
341
|
+
self.db_path.parent.mkdir(parents=True, exist_ok=True)
|
|
342
|
+
conn = sqlite3.connect(str(self.db_path))
|
|
343
|
+
tables_created: List[str] = []
|
|
344
|
+
try:
|
|
345
|
+
for stmt in statements:
|
|
346
|
+
try:
|
|
347
|
+
conn.execute(stmt)
|
|
348
|
+
except sqlite3.OperationalError:
|
|
349
|
+
pass # Table/index already exists or other benign error
|
|
350
|
+
|
|
351
|
+
conn.commit()
|
|
352
|
+
|
|
353
|
+
# Verify which tables now exist
|
|
354
|
+
cursor = conn.execute(
|
|
355
|
+
"SELECT name FROM sqlite_master WHERE type='table' ORDER BY name"
|
|
356
|
+
)
|
|
357
|
+
existing_tables = {row[0] for row in cursor.fetchall()}
|
|
358
|
+
tables_created = [t for t in table_names if t in existing_tables]
|
|
359
|
+
finally:
|
|
360
|
+
conn.close()
|
|
361
|
+
|
|
362
|
+
return {
|
|
363
|
+
"tables_created": tables_created,
|
|
364
|
+
"table_count": len(tables_created),
|
|
365
|
+
"db_path": str(self.db_path),
|
|
366
|
+
"dry_run": False,
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
# ---------------------------------------------------------------------------
|
|
371
|
+
# Profile and manifest loaders
|
|
372
|
+
# ---------------------------------------------------------------------------
|
|
373
|
+
|
|
374
|
+
def _load_profiles() -> Dict[str, Any]:
|
|
375
|
+
"""Load deployment profiles from YAML."""
|
|
376
|
+
if not PROFILES_PATH.exists():
|
|
377
|
+
return {}
|
|
378
|
+
return _load_yaml(PROFILES_PATH)
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
def _load_manifest() -> Dict[str, Any]:
|
|
382
|
+
"""Load installation manifest from YAML."""
|
|
383
|
+
if not MANIFEST_PATH.exists():
|
|
384
|
+
return {}
|
|
385
|
+
return _load_yaml(MANIFEST_PATH)
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
def _get_all_module_ids(manifest: Dict[str, Any]) -> List[str]:
|
|
389
|
+
"""Return all module IDs from the manifest."""
|
|
390
|
+
modules = manifest.get("modules", {})
|
|
391
|
+
return list(modules.keys())
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
def _get_all_compliance_ids(manifest: Dict[str, Any]) -> List[str]:
|
|
395
|
+
"""Return module IDs that are compliance posture modules."""
|
|
396
|
+
modules = manifest.get("modules", {})
|
|
397
|
+
return [
|
|
398
|
+
mod_id for mod_id, mod_def in modules.items()
|
|
399
|
+
if isinstance(mod_def, dict) and mod_def.get("compliance_posture")
|
|
400
|
+
]
|
|
401
|
+
|
|
402
|
+
|
|
403
|
+
def _get_required_module_ids(manifest: Dict[str, Any]) -> List[str]:
|
|
404
|
+
"""Return module IDs that are required (always installed)."""
|
|
405
|
+
modules = manifest.get("modules", {})
|
|
406
|
+
return [
|
|
407
|
+
mod_id for mod_id, mod_def in modules.items()
|
|
408
|
+
if isinstance(mod_def, dict) and mod_def.get("required")
|
|
409
|
+
]
|
|
410
|
+
|
|
411
|
+
|
|
412
|
+
# ---------------------------------------------------------------------------
|
|
413
|
+
# Topological sort for dependency resolution
|
|
414
|
+
# ---------------------------------------------------------------------------
|
|
415
|
+
|
|
416
|
+
def _topological_sort(
|
|
417
|
+
module_ids: List[str],
|
|
418
|
+
manifest: Dict[str, Any],
|
|
419
|
+
) -> List[str]:
|
|
420
|
+
"""Resolve and topologically sort modules by their dependencies.
|
|
421
|
+
|
|
422
|
+
Automatically includes transitive dependencies. Returns modules in
|
|
423
|
+
install order (dependencies first).
|
|
424
|
+
|
|
425
|
+
Raises:
|
|
426
|
+
ValueError: If a circular dependency is detected.
|
|
427
|
+
"""
|
|
428
|
+
modules_cfg = manifest.get("modules", {})
|
|
429
|
+
|
|
430
|
+
# Build full set including transitive deps
|
|
431
|
+
required: Set[str] = set()
|
|
432
|
+
queue = list(module_ids)
|
|
433
|
+
while queue:
|
|
434
|
+
mod_id = queue.pop(0)
|
|
435
|
+
if mod_id in required:
|
|
436
|
+
continue
|
|
437
|
+
required.add(mod_id)
|
|
438
|
+
mod_def = modules_cfg.get(mod_id, {})
|
|
439
|
+
deps = mod_def.get("depends_on", []) or mod_def.get("dependencies", [])
|
|
440
|
+
if isinstance(deps, str):
|
|
441
|
+
deps = [deps]
|
|
442
|
+
for dep in deps:
|
|
443
|
+
if dep not in required:
|
|
444
|
+
queue.append(dep)
|
|
445
|
+
|
|
446
|
+
# Kahn's algorithm for topological sort
|
|
447
|
+
in_degree: Dict[str, int] = {m: 0 for m in required}
|
|
448
|
+
adj: Dict[str, List[str]] = {m: [] for m in required}
|
|
449
|
+
|
|
450
|
+
for mod_id in required:
|
|
451
|
+
mod_def = modules_cfg.get(mod_id, {})
|
|
452
|
+
deps = mod_def.get("depends_on", []) or mod_def.get("dependencies", [])
|
|
453
|
+
if isinstance(deps, str):
|
|
454
|
+
deps = [deps]
|
|
455
|
+
for dep in deps:
|
|
456
|
+
if dep in required:
|
|
457
|
+
adj[dep].append(mod_id)
|
|
458
|
+
in_degree[mod_id] += 1
|
|
459
|
+
|
|
460
|
+
queue = [m for m in required if in_degree[m] == 0]
|
|
461
|
+
queue.sort() # deterministic ordering
|
|
462
|
+
sorted_list: List[str] = []
|
|
463
|
+
|
|
464
|
+
while queue:
|
|
465
|
+
node = queue.pop(0)
|
|
466
|
+
sorted_list.append(node)
|
|
467
|
+
for neighbor in sorted(adj.get(node, [])):
|
|
468
|
+
in_degree[neighbor] -= 1
|
|
469
|
+
if in_degree[neighbor] == 0:
|
|
470
|
+
queue.append(neighbor)
|
|
471
|
+
|
|
472
|
+
if len(sorted_list) != len(required):
|
|
473
|
+
missing = required - set(sorted_list)
|
|
474
|
+
raise ValueError(
|
|
475
|
+
f"Circular dependency detected among modules: {', '.join(sorted(missing))}"
|
|
476
|
+
)
|
|
477
|
+
|
|
478
|
+
return sorted_list
|
|
479
|
+
|
|
480
|
+
|
|
481
|
+
# ---------------------------------------------------------------------------
|
|
482
|
+
# CUI markings update
|
|
483
|
+
# ---------------------------------------------------------------------------
|
|
484
|
+
|
|
485
|
+
def _update_cui_markings(enabled: bool, dry_run: bool = False) -> Dict[str, Any]:
|
|
486
|
+
"""Update the CUI markings YAML to enable or disable CUI banners.
|
|
487
|
+
|
|
488
|
+
This modifies the ``enabled`` field in ``args/cui_markings.yaml``. If the
|
|
489
|
+
file does not have an ``enabled`` field, one is prepended.
|
|
490
|
+
"""
|
|
491
|
+
if dry_run:
|
|
492
|
+
return {"cui_enabled": enabled, "dry_run": True, "path": str(CUI_MARKINGS_PATH)}
|
|
493
|
+
|
|
494
|
+
if not CUI_MARKINGS_PATH.exists():
|
|
495
|
+
return {"cui_enabled": enabled, "error": "cui_markings.yaml not found"}
|
|
496
|
+
|
|
497
|
+
with open(CUI_MARKINGS_PATH, "r", encoding="utf-8") as fh:
|
|
498
|
+
content = fh.read()
|
|
499
|
+
|
|
500
|
+
# Check if an `enabled:` key already exists
|
|
501
|
+
enabled_pattern = re.compile(r"^enabled:\s*(true|false)\s*$", re.MULTILINE | re.IGNORECASE)
|
|
502
|
+
new_value = "true" if enabled else "false"
|
|
503
|
+
|
|
504
|
+
if enabled_pattern.search(content):
|
|
505
|
+
content = enabled_pattern.sub(f"enabled: {new_value}", content)
|
|
506
|
+
else:
|
|
507
|
+
# Prepend at the top (after any initial comments)
|
|
508
|
+
lines = content.split("\n")
|
|
509
|
+
insert_idx = 0
|
|
510
|
+
for i, line in enumerate(lines):
|
|
511
|
+
if line.strip() and not line.strip().startswith("#"):
|
|
512
|
+
insert_idx = i
|
|
513
|
+
break
|
|
514
|
+
lines.insert(insert_idx, f"enabled: {new_value}\n")
|
|
515
|
+
content = "\n".join(lines)
|
|
516
|
+
|
|
517
|
+
with open(CUI_MARKINGS_PATH, "w", encoding="utf-8") as fh:
|
|
518
|
+
fh.write(content)
|
|
519
|
+
|
|
520
|
+
return {"cui_enabled": enabled, "dry_run": False, "path": str(CUI_MARKINGS_PATH)}
|
|
521
|
+
|
|
522
|
+
|
|
523
|
+
# ---------------------------------------------------------------------------
|
|
524
|
+
# Installation engine
|
|
525
|
+
# ---------------------------------------------------------------------------
|
|
526
|
+
|
|
527
|
+
def install(
|
|
528
|
+
modules: List[str],
|
|
529
|
+
compliance_frameworks: List[str],
|
|
530
|
+
profile_name: str,
|
|
531
|
+
platform_target: str,
|
|
532
|
+
team_size: str = "",
|
|
533
|
+
cui_enabled: bool = False,
|
|
534
|
+
dry_run: bool = False,
|
|
535
|
+
) -> Dict[str, Any]:
|
|
536
|
+
"""Execute the full installation sequence.
|
|
537
|
+
|
|
538
|
+
Steps:
|
|
539
|
+
1. Resolve all module dependencies (topological sort).
|
|
540
|
+
2. Create ``data/`` directory if needed.
|
|
541
|
+
3. Initialize database with required table groups.
|
|
542
|
+
4. Update ``data/installation.json`` via ModuleRegistry.
|
|
543
|
+
5. Update ``args/cui_markings.yaml``.
|
|
544
|
+
6. Return summary.
|
|
545
|
+
|
|
546
|
+
Args:
|
|
547
|
+
modules: List of module IDs to install.
|
|
548
|
+
compliance_frameworks: Compliance framework IDs to activate.
|
|
549
|
+
profile_name: Profile identifier used.
|
|
550
|
+
platform_target: Deployment platform (docker, k8s, etc.).
|
|
551
|
+
team_size: Team size range string.
|
|
552
|
+
cui_enabled: Whether CUI markings should be enabled.
|
|
553
|
+
dry_run: If True, preview without executing.
|
|
554
|
+
|
|
555
|
+
Returns:
|
|
556
|
+
Dict with full installation summary.
|
|
557
|
+
"""
|
|
558
|
+
manifest = _load_manifest()
|
|
559
|
+
now = datetime.now(timezone.utc).isoformat()
|
|
560
|
+
|
|
561
|
+
# Merge compliance framework modules into the module list
|
|
562
|
+
ComplianceConfiguratorCls = _get_compliance_configurator()
|
|
563
|
+
configurator = ComplianceConfiguratorCls()
|
|
564
|
+
compliance_config = configurator.configure_posture(compliance_frameworks)
|
|
565
|
+
compliance_modules = compliance_config.get("required_modules", [])
|
|
566
|
+
|
|
567
|
+
# Combine explicit modules + compliance modules + always-required modules
|
|
568
|
+
required_modules = _get_required_module_ids(manifest)
|
|
569
|
+
all_module_ids: List[str] = list(required_modules)
|
|
570
|
+
for m in modules:
|
|
571
|
+
if m not in all_module_ids:
|
|
572
|
+
all_module_ids.append(m)
|
|
573
|
+
for m in compliance_modules:
|
|
574
|
+
if m not in all_module_ids:
|
|
575
|
+
all_module_ids.append(m)
|
|
576
|
+
|
|
577
|
+
# Resolve dependencies and topological sort
|
|
578
|
+
try:
|
|
579
|
+
sorted_modules = _topological_sort(all_module_ids, manifest)
|
|
580
|
+
except ValueError as e:
|
|
581
|
+
return {
|
|
582
|
+
"success": False,
|
|
583
|
+
"error": str(e),
|
|
584
|
+
"timestamp": now,
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
# Validate that all modules exist in manifest
|
|
588
|
+
modules_cfg = manifest.get("modules", {})
|
|
589
|
+
unknown = [m for m in sorted_modules if m not in modules_cfg]
|
|
590
|
+
if unknown:
|
|
591
|
+
return {
|
|
592
|
+
"success": False,
|
|
593
|
+
"error": f"Unknown modules: {', '.join(unknown)}",
|
|
594
|
+
"timestamp": now,
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
if dry_run:
|
|
598
|
+
# Build table list for preview
|
|
599
|
+
db_init = ModularDBInitializer()
|
|
600
|
+
db_result = db_init.initialize(sorted_modules, dry_run=True)
|
|
601
|
+
return {
|
|
602
|
+
"success": True,
|
|
603
|
+
"dry_run": True,
|
|
604
|
+
"profile": profile_name,
|
|
605
|
+
"platform": platform_target,
|
|
606
|
+
"team_size": team_size,
|
|
607
|
+
"modules": sorted_modules,
|
|
608
|
+
"module_count": len(sorted_modules),
|
|
609
|
+
"compliance_frameworks": compliance_frameworks,
|
|
610
|
+
"cui_enabled": cui_enabled or compliance_config.get("cui_enabled", False),
|
|
611
|
+
"impact_level": compliance_config.get("impact_level", "IL2"),
|
|
612
|
+
"db_tables_planned": db_result.get("tables_planned", []),
|
|
613
|
+
"db_table_count": db_result.get("table_count", 0),
|
|
614
|
+
"security_gate_overrides": compliance_config.get("security_gate_overrides", {}),
|
|
615
|
+
"timestamp": now,
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
# Step 1: Create data directory
|
|
619
|
+
DATA_DIR.mkdir(parents=True, exist_ok=True)
|
|
620
|
+
|
|
621
|
+
# Step 2: Initialize database tables
|
|
622
|
+
db_init = ModularDBInitializer()
|
|
623
|
+
db_result = db_init.initialize(sorted_modules, dry_run=False)
|
|
624
|
+
|
|
625
|
+
# Step 3: Update installation.json via ModuleRegistry
|
|
626
|
+
ModuleRegistryCls = _get_module_registry()
|
|
627
|
+
registry = ModuleRegistryCls()
|
|
628
|
+
install_results: List[Dict[str, Any]] = []
|
|
629
|
+
for mod_id in sorted_modules:
|
|
630
|
+
result = registry.install_module(mod_id)
|
|
631
|
+
install_results.append(result)
|
|
632
|
+
|
|
633
|
+
# Update registry metadata
|
|
634
|
+
registry_data = registry.export_config()
|
|
635
|
+
registry_data["profile"] = profile_name
|
|
636
|
+
registry_data["platform"] = platform_target
|
|
637
|
+
registry_data["team_size"] = team_size
|
|
638
|
+
registry_data["compliance_posture"] = compliance_frameworks
|
|
639
|
+
effective_cui = cui_enabled or compliance_config.get("cui_enabled", False)
|
|
640
|
+
registry_data["cui_enabled"] = effective_cui
|
|
641
|
+
registry_data["impact_level"] = compliance_config.get("impact_level", "IL2")
|
|
642
|
+
registry_data["security_gate_overrides"] = compliance_config.get(
|
|
643
|
+
"security_gate_overrides", {}
|
|
644
|
+
)
|
|
645
|
+
registry_data["last_updated"] = now
|
|
646
|
+
|
|
647
|
+
# Persist updated registry
|
|
648
|
+
REGISTRY_PATH.parent.mkdir(parents=True, exist_ok=True)
|
|
649
|
+
with open(REGISTRY_PATH, "w", encoding="utf-8") as fh:
|
|
650
|
+
json.dump(registry_data, fh, indent=2, default=str)
|
|
651
|
+
|
|
652
|
+
# Step 4: Update CUI markings
|
|
653
|
+
cui_result = _update_cui_markings(effective_cui)
|
|
654
|
+
|
|
655
|
+
# Build module summary
|
|
656
|
+
module_summary: List[Dict[str, str]] = []
|
|
657
|
+
for mod_id in sorted_modules:
|
|
658
|
+
mod_def = modules_cfg.get(mod_id, {})
|
|
659
|
+
module_summary.append({
|
|
660
|
+
"id": mod_id,
|
|
661
|
+
"name": mod_def.get("name", mod_id) if isinstance(mod_def, dict) else mod_id,
|
|
662
|
+
"category": mod_def.get("category", "") if isinstance(mod_def, dict) else "",
|
|
663
|
+
})
|
|
664
|
+
|
|
665
|
+
failed = [r for r in install_results if not r.get("success")]
|
|
666
|
+
|
|
667
|
+
return {
|
|
668
|
+
"success": len(failed) == 0,
|
|
669
|
+
"dry_run": False,
|
|
670
|
+
"profile": profile_name,
|
|
671
|
+
"platform": platform_target,
|
|
672
|
+
"team_size": team_size,
|
|
673
|
+
"modules_installed": sorted_modules,
|
|
674
|
+
"module_count": len(sorted_modules),
|
|
675
|
+
"module_summary": module_summary,
|
|
676
|
+
"compliance_frameworks": compliance_frameworks,
|
|
677
|
+
"cui_enabled": effective_cui,
|
|
678
|
+
"impact_level": compliance_config.get("impact_level", "IL2"),
|
|
679
|
+
"db_tables_created": db_result.get("tables_created", []),
|
|
680
|
+
"db_table_count": db_result.get("table_count", 0),
|
|
681
|
+
"security_gate_overrides": compliance_config.get("security_gate_overrides", {}),
|
|
682
|
+
"failures": failed if failed else [],
|
|
683
|
+
"registry_path": str(REGISTRY_PATH),
|
|
684
|
+
"db_path": str(DB_PATH),
|
|
685
|
+
"timestamp": now,
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
|
|
689
|
+
# ---------------------------------------------------------------------------
|
|
690
|
+
# Interactive wizard
|
|
691
|
+
# ---------------------------------------------------------------------------
|
|
692
|
+
|
|
693
|
+
def _prompt_choice(prompt: str, options: List[str], default: int = 0) -> int:
|
|
694
|
+
"""Display a numbered list and prompt for a single selection.
|
|
695
|
+
|
|
696
|
+
Args:
|
|
697
|
+
prompt: Header text for the prompt.
|
|
698
|
+
options: List of option display strings.
|
|
699
|
+
default: Zero-based default selection index.
|
|
700
|
+
|
|
701
|
+
Returns:
|
|
702
|
+
Zero-based index of selected option.
|
|
703
|
+
"""
|
|
704
|
+
print(f"\n{prompt}")
|
|
705
|
+
print("-" * 50)
|
|
706
|
+
for i, opt in enumerate(options):
|
|
707
|
+
marker = " *" if i == default else ""
|
|
708
|
+
print(f" {i + 1}. {opt}{marker}")
|
|
709
|
+
print()
|
|
710
|
+
|
|
711
|
+
while True:
|
|
712
|
+
raw = input(f"Enter choice [1-{len(options)}] (default={default + 1}): ").strip()
|
|
713
|
+
if not raw:
|
|
714
|
+
return default
|
|
715
|
+
try:
|
|
716
|
+
choice = int(raw) - 1
|
|
717
|
+
if 0 <= choice < len(options):
|
|
718
|
+
return choice
|
|
719
|
+
print(f" Please enter a number between 1 and {len(options)}.")
|
|
720
|
+
except ValueError:
|
|
721
|
+
print(" Please enter a valid number.")
|
|
722
|
+
|
|
723
|
+
|
|
724
|
+
def _prompt_multi_choice(
|
|
725
|
+
prompt: str,
|
|
726
|
+
options: List[str],
|
|
727
|
+
defaults: Optional[List[int]] = None,
|
|
728
|
+
) -> List[int]:
|
|
729
|
+
"""Display a numbered list and prompt for multiple selections.
|
|
730
|
+
|
|
731
|
+
Args:
|
|
732
|
+
prompt: Header text.
|
|
733
|
+
options: List of option display strings.
|
|
734
|
+
defaults: Zero-based indices that are pre-selected.
|
|
735
|
+
|
|
736
|
+
Returns:
|
|
737
|
+
List of zero-based indices of selected options.
|
|
738
|
+
"""
|
|
739
|
+
if defaults is None:
|
|
740
|
+
defaults = []
|
|
741
|
+
|
|
742
|
+
print(f"\n{prompt}")
|
|
743
|
+
print("-" * 50)
|
|
744
|
+
for i, opt in enumerate(options):
|
|
745
|
+
check = "[x]" if i in defaults else "[ ]"
|
|
746
|
+
print(f" {i + 1}. {check} {opt}")
|
|
747
|
+
print()
|
|
748
|
+
print(" Enter numbers separated by commas (e.g., 1,3,5)")
|
|
749
|
+
print(" Press Enter to accept defaults, or 'none' to clear all.")
|
|
750
|
+
print()
|
|
751
|
+
|
|
752
|
+
while True:
|
|
753
|
+
raw = input("Your selection: ").strip()
|
|
754
|
+
if not raw:
|
|
755
|
+
return list(defaults)
|
|
756
|
+
if raw.lower() == "none":
|
|
757
|
+
return []
|
|
758
|
+
try:
|
|
759
|
+
indices = []
|
|
760
|
+
for part in raw.split(","):
|
|
761
|
+
part = part.strip()
|
|
762
|
+
if not part:
|
|
763
|
+
continue
|
|
764
|
+
# Support ranges like 1-3
|
|
765
|
+
if "-" in part:
|
|
766
|
+
start, end = part.split("-", 1)
|
|
767
|
+
for n in range(int(start), int(end) + 1):
|
|
768
|
+
idx = n - 1
|
|
769
|
+
if 0 <= idx < len(options) and idx not in indices:
|
|
770
|
+
indices.append(idx)
|
|
771
|
+
else:
|
|
772
|
+
idx = int(part) - 1
|
|
773
|
+
if 0 <= idx < len(options) and idx not in indices:
|
|
774
|
+
indices.append(idx)
|
|
775
|
+
return indices
|
|
776
|
+
except ValueError:
|
|
777
|
+
print(" Please enter valid numbers separated by commas.")
|
|
778
|
+
|
|
779
|
+
|
|
780
|
+
def _prompt_confirm(prompt: str, default: bool = True) -> bool:
|
|
781
|
+
"""Prompt for yes/no confirmation.
|
|
782
|
+
|
|
783
|
+
Args:
|
|
784
|
+
prompt: Question text.
|
|
785
|
+
default: Default answer.
|
|
786
|
+
|
|
787
|
+
Returns:
|
|
788
|
+
True for yes, False for no.
|
|
789
|
+
"""
|
|
790
|
+
suffix = "[Y/n]" if default else "[y/N]"
|
|
791
|
+
while True:
|
|
792
|
+
raw = input(f"\n{prompt} {suffix}: ").strip().lower()
|
|
793
|
+
if not raw:
|
|
794
|
+
return default
|
|
795
|
+
if raw in ("y", "yes"):
|
|
796
|
+
return True
|
|
797
|
+
if raw in ("n", "no"):
|
|
798
|
+
return False
|
|
799
|
+
print(" Please enter 'y' or 'n'.")
|
|
800
|
+
|
|
801
|
+
|
|
802
|
+
def run_interactive(dry_run: bool = False) -> Dict[str, Any]:
|
|
803
|
+
"""Run the 6-step interactive installation wizard.
|
|
804
|
+
|
|
805
|
+
Steps:
|
|
806
|
+
1. Organization type (profile selection)
|
|
807
|
+
2. Team size
|
|
808
|
+
3. Compliance posture (multi-select)
|
|
809
|
+
4. Deployment target
|
|
810
|
+
5. Additional capabilities (optional modules)
|
|
811
|
+
6. Review and confirm
|
|
812
|
+
|
|
813
|
+
Returns:
|
|
814
|
+
Installation result dict.
|
|
815
|
+
"""
|
|
816
|
+
profiles_data = _load_profiles()
|
|
817
|
+
manifest = _load_manifest()
|
|
818
|
+
profiles = profiles_data.get("profiles", {})
|
|
819
|
+
platforms = profiles_data.get("platforms", {})
|
|
820
|
+
|
|
821
|
+
print()
|
|
822
|
+
print("=" * 60)
|
|
823
|
+
print(" ICDEV Modular Installer — Interactive Wizard")
|
|
824
|
+
print("=" * 60)
|
|
825
|
+
|
|
826
|
+
# ------------------------------------------------------------------
|
|
827
|
+
# Step 1: Organization Type (profile selection)
|
|
828
|
+
# ------------------------------------------------------------------
|
|
829
|
+
profile_ids = [pid for pid in profiles.keys() if pid != "custom"]
|
|
830
|
+
profile_ids.append("custom")
|
|
831
|
+
profile_options = []
|
|
832
|
+
for pid in profile_ids:
|
|
833
|
+
pdef = profiles.get(pid, {})
|
|
834
|
+
name = pdef.get("name", pid) if isinstance(pdef, dict) else pid
|
|
835
|
+
desc = pdef.get("description", "") if isinstance(pdef, dict) else ""
|
|
836
|
+
profile_options.append(f"{name} — {desc}" if desc else name)
|
|
837
|
+
|
|
838
|
+
choice_idx = _prompt_choice(
|
|
839
|
+
"Step 1/6: What type of organization are you?",
|
|
840
|
+
profile_options,
|
|
841
|
+
default=0,
|
|
842
|
+
)
|
|
843
|
+
selected_profile_id = profile_ids[choice_idx]
|
|
844
|
+
selected_profile = profiles.get(selected_profile_id, {})
|
|
845
|
+
if not isinstance(selected_profile, dict):
|
|
846
|
+
selected_profile = {}
|
|
847
|
+
|
|
848
|
+
# ------------------------------------------------------------------
|
|
849
|
+
# Step 2: Team Size
|
|
850
|
+
# ------------------------------------------------------------------
|
|
851
|
+
team_sizes = ["1-5", "5-15", "15-50", "50-200", "200+"]
|
|
852
|
+
default_team_size_idx = 0
|
|
853
|
+
profile_team = selected_profile.get("team_size", "")
|
|
854
|
+
for i, ts in enumerate(team_sizes):
|
|
855
|
+
if ts in str(profile_team):
|
|
856
|
+
default_team_size_idx = i
|
|
857
|
+
break
|
|
858
|
+
|
|
859
|
+
team_choice = _prompt_choice(
|
|
860
|
+
"Step 2/6: What is your team size?",
|
|
861
|
+
[
|
|
862
|
+
"1-5 (solo / small team)",
|
|
863
|
+
"5-15 (small team)",
|
|
864
|
+
"15-50 (medium team)",
|
|
865
|
+
"50-200 (large team)",
|
|
866
|
+
"200+ (enterprise)",
|
|
867
|
+
],
|
|
868
|
+
default=default_team_size_idx,
|
|
869
|
+
)
|
|
870
|
+
team_size = team_sizes[team_choice]
|
|
871
|
+
|
|
872
|
+
# ------------------------------------------------------------------
|
|
873
|
+
# Step 3: Compliance Posture
|
|
874
|
+
# ------------------------------------------------------------------
|
|
875
|
+
all_compliance = _get_all_compliance_ids(manifest)
|
|
876
|
+
modules_cfg = manifest.get("modules", {})
|
|
877
|
+
compliance_options = []
|
|
878
|
+
for cid in all_compliance:
|
|
879
|
+
cdef = modules_cfg.get(cid, {})
|
|
880
|
+
name = cdef.get("name", cid) if isinstance(cdef, dict) else cid
|
|
881
|
+
compliance_options.append(f"{cid}: {name}")
|
|
882
|
+
|
|
883
|
+
# Pre-select from profile
|
|
884
|
+
profile_compliance = selected_profile.get("default_compliance", [])
|
|
885
|
+
if isinstance(profile_compliance, str):
|
|
886
|
+
if profile_compliance.upper() == "ALL":
|
|
887
|
+
profile_compliance = list(all_compliance)
|
|
888
|
+
else:
|
|
889
|
+
profile_compliance = [profile_compliance]
|
|
890
|
+
|
|
891
|
+
default_indices = []
|
|
892
|
+
for i, cid in enumerate(all_compliance):
|
|
893
|
+
if cid in profile_compliance:
|
|
894
|
+
default_indices.append(i)
|
|
895
|
+
|
|
896
|
+
compliance_indices = _prompt_multi_choice(
|
|
897
|
+
"Step 3/6: Which compliance frameworks do you need?",
|
|
898
|
+
compliance_options,
|
|
899
|
+
defaults=default_indices,
|
|
900
|
+
)
|
|
901
|
+
selected_compliance = [all_compliance[i] for i in compliance_indices]
|
|
902
|
+
|
|
903
|
+
# ------------------------------------------------------------------
|
|
904
|
+
# Step 4: Deployment Target
|
|
905
|
+
# ------------------------------------------------------------------
|
|
906
|
+
platform_ids = list(platforms.keys()) if isinstance(platforms, dict) else []
|
|
907
|
+
platform_options = []
|
|
908
|
+
for pid in platform_ids:
|
|
909
|
+
pdef = platforms.get(pid, {})
|
|
910
|
+
name = pdef.get("name", pid) if isinstance(pdef, dict) else pid
|
|
911
|
+
desc = pdef.get("description", "") if isinstance(pdef, dict) else ""
|
|
912
|
+
platform_options.append(f"{name} — {desc}" if desc else name)
|
|
913
|
+
|
|
914
|
+
default_platform_idx = 0
|
|
915
|
+
profile_platform = selected_profile.get("default_platform", "docker")
|
|
916
|
+
for i, pid in enumerate(platform_ids):
|
|
917
|
+
if pid == profile_platform:
|
|
918
|
+
default_platform_idx = i
|
|
919
|
+
break
|
|
920
|
+
|
|
921
|
+
if platform_options:
|
|
922
|
+
platform_choice = _prompt_choice(
|
|
923
|
+
"Step 4/6: Where will you deploy?",
|
|
924
|
+
platform_options,
|
|
925
|
+
default=default_platform_idx,
|
|
926
|
+
)
|
|
927
|
+
selected_platform = platform_ids[platform_choice]
|
|
928
|
+
else:
|
|
929
|
+
selected_platform = "docker"
|
|
930
|
+
|
|
931
|
+
# ------------------------------------------------------------------
|
|
932
|
+
# Step 5: Additional Capabilities
|
|
933
|
+
# ------------------------------------------------------------------
|
|
934
|
+
# Gather modules already included from profile + compliance
|
|
935
|
+
profile_modules = selected_profile.get("modules", [])
|
|
936
|
+
if isinstance(profile_modules, str):
|
|
937
|
+
if profile_modules.upper() == "ALL":
|
|
938
|
+
profile_modules = _get_all_module_ids(manifest)
|
|
939
|
+
else:
|
|
940
|
+
profile_modules = [profile_modules]
|
|
941
|
+
|
|
942
|
+
required_ids = set(_get_required_module_ids(manifest))
|
|
943
|
+
already_included = set(profile_modules) | required_ids
|
|
944
|
+
|
|
945
|
+
# Compliance modules
|
|
946
|
+
ComplianceConfiguratorCls = _get_compliance_configurator()
|
|
947
|
+
configurator = ComplianceConfiguratorCls()
|
|
948
|
+
comp_config = configurator.configure_posture(selected_compliance)
|
|
949
|
+
comp_modules = set(comp_config.get("required_modules", []))
|
|
950
|
+
already_included |= comp_modules
|
|
951
|
+
|
|
952
|
+
# Optional modules not yet selected
|
|
953
|
+
all_module_ids = _get_all_module_ids(manifest)
|
|
954
|
+
optional_ids = [
|
|
955
|
+
m for m in all_module_ids
|
|
956
|
+
if m not in already_included and not modules_cfg.get(m, {}).get("compliance_posture")
|
|
957
|
+
]
|
|
958
|
+
|
|
959
|
+
optional_options = []
|
|
960
|
+
for mid in optional_ids:
|
|
961
|
+
mdef = modules_cfg.get(mid, {})
|
|
962
|
+
name = mdef.get("name", mid) if isinstance(mdef, dict) else mid
|
|
963
|
+
desc = mdef.get("description", "") if isinstance(mdef, dict) else ""
|
|
964
|
+
short_desc = desc[:60] + "..." if len(desc) > 60 else desc
|
|
965
|
+
optional_options.append(f"{mid}: {name} — {short_desc}")
|
|
966
|
+
|
|
967
|
+
# Pre-check recommended addons from profile
|
|
968
|
+
recommended = selected_profile.get("recommended_addons", [])
|
|
969
|
+
if isinstance(recommended, str):
|
|
970
|
+
recommended = [recommended]
|
|
971
|
+
optional_defaults = [i for i, mid in enumerate(optional_ids) if mid in recommended]
|
|
972
|
+
|
|
973
|
+
selected_addons: List[str] = []
|
|
974
|
+
if optional_options:
|
|
975
|
+
addon_indices = _prompt_multi_choice(
|
|
976
|
+
"Step 5/6: Select additional capabilities (optional):",
|
|
977
|
+
optional_options,
|
|
978
|
+
defaults=optional_defaults,
|
|
979
|
+
)
|
|
980
|
+
selected_addons = [optional_ids[i] for i in addon_indices]
|
|
981
|
+
|
|
982
|
+
# ------------------------------------------------------------------
|
|
983
|
+
# Build final module list
|
|
984
|
+
# ------------------------------------------------------------------
|
|
985
|
+
final_modules = list(profile_modules)
|
|
986
|
+
for m in selected_addons:
|
|
987
|
+
if m not in final_modules:
|
|
988
|
+
final_modules.append(m)
|
|
989
|
+
|
|
990
|
+
# Determine CUI from profile + compliance
|
|
991
|
+
cui_enabled = selected_profile.get("cui_enabled", False)
|
|
992
|
+
if comp_config.get("cui_enabled"):
|
|
993
|
+
cui_enabled = True
|
|
994
|
+
|
|
995
|
+
# ------------------------------------------------------------------
|
|
996
|
+
# Step 6: Review & Confirm
|
|
997
|
+
# ------------------------------------------------------------------
|
|
998
|
+
print()
|
|
999
|
+
print("=" * 60)
|
|
1000
|
+
print(" Step 6/6: Review Your Installation")
|
|
1001
|
+
print("=" * 60)
|
|
1002
|
+
print()
|
|
1003
|
+
print(f" Profile: {selected_profile.get('name', selected_profile_id)}")
|
|
1004
|
+
print(f" Team Size: {team_size}")
|
|
1005
|
+
print(f" Platform: {selected_platform}")
|
|
1006
|
+
print(f" CUI Markings: {'enabled' if cui_enabled else 'disabled'}")
|
|
1007
|
+
print(f" Impact Level: {comp_config.get('impact_level', 'IL2')}")
|
|
1008
|
+
print()
|
|
1009
|
+
print(" Compliance Frameworks:")
|
|
1010
|
+
if selected_compliance:
|
|
1011
|
+
for fw in selected_compliance:
|
|
1012
|
+
print(f" - {fw}")
|
|
1013
|
+
else:
|
|
1014
|
+
print(" (none)")
|
|
1015
|
+
print()
|
|
1016
|
+
print(" Modules to install:")
|
|
1017
|
+
try:
|
|
1018
|
+
sorted_preview = _topological_sort(final_modules, manifest)
|
|
1019
|
+
except ValueError:
|
|
1020
|
+
sorted_preview = final_modules
|
|
1021
|
+
for mod_id in sorted_preview:
|
|
1022
|
+
mdef = modules_cfg.get(mod_id, {})
|
|
1023
|
+
name = mdef.get("name", mod_id) if isinstance(mdef, dict) else mod_id
|
|
1024
|
+
print(f" - {mod_id}: {name}")
|
|
1025
|
+
print()
|
|
1026
|
+
|
|
1027
|
+
if dry_run:
|
|
1028
|
+
print(" [DRY RUN] No changes will be made.")
|
|
1029
|
+
print()
|
|
1030
|
+
|
|
1031
|
+
if not _prompt_confirm("Proceed with installation?"):
|
|
1032
|
+
return {"success": False, "error": "Installation cancelled by user."}
|
|
1033
|
+
|
|
1034
|
+
return install(
|
|
1035
|
+
modules=final_modules,
|
|
1036
|
+
compliance_frameworks=selected_compliance,
|
|
1037
|
+
profile_name=selected_profile_id,
|
|
1038
|
+
platform_target=selected_platform,
|
|
1039
|
+
team_size=team_size,
|
|
1040
|
+
cui_enabled=cui_enabled,
|
|
1041
|
+
dry_run=dry_run,
|
|
1042
|
+
)
|
|
1043
|
+
|
|
1044
|
+
|
|
1045
|
+
# ---------------------------------------------------------------------------
|
|
1046
|
+
# Profile-based (non-interactive) installation
|
|
1047
|
+
# ---------------------------------------------------------------------------
|
|
1048
|
+
|
|
1049
|
+
def run_profile(
|
|
1050
|
+
profile_name: str,
|
|
1051
|
+
compliance_override: Optional[List[str]] = None,
|
|
1052
|
+
platform_override: Optional[str] = None,
|
|
1053
|
+
dry_run: bool = False,
|
|
1054
|
+
) -> Dict[str, Any]:
|
|
1055
|
+
"""Run installation from a named deployment profile.
|
|
1056
|
+
|
|
1057
|
+
Args:
|
|
1058
|
+
profile_name: Profile ID from deployment_profiles.yaml.
|
|
1059
|
+
compliance_override: Override the profile's default_compliance.
|
|
1060
|
+
platform_override: Override the profile's default_platform.
|
|
1061
|
+
dry_run: If True, preview without executing.
|
|
1062
|
+
|
|
1063
|
+
Returns:
|
|
1064
|
+
Installation result dict.
|
|
1065
|
+
"""
|
|
1066
|
+
profiles_data = _load_profiles()
|
|
1067
|
+
manifest = _load_manifest()
|
|
1068
|
+
profiles = profiles_data.get("profiles", {})
|
|
1069
|
+
|
|
1070
|
+
if profile_name not in profiles:
|
|
1071
|
+
available = ", ".join(sorted(profiles.keys()))
|
|
1072
|
+
return {
|
|
1073
|
+
"success": False,
|
|
1074
|
+
"error": f"Unknown profile: '{profile_name}'. Available: {available}",
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
profile = profiles[profile_name]
|
|
1078
|
+
if not isinstance(profile, dict):
|
|
1079
|
+
profile = {}
|
|
1080
|
+
|
|
1081
|
+
# Resolve modules
|
|
1082
|
+
profile_modules = profile.get("modules", [])
|
|
1083
|
+
if isinstance(profile_modules, str):
|
|
1084
|
+
if profile_modules.upper() == "ALL":
|
|
1085
|
+
profile_modules = _get_all_module_ids(manifest)
|
|
1086
|
+
else:
|
|
1087
|
+
profile_modules = [profile_modules]
|
|
1088
|
+
|
|
1089
|
+
# Resolve compliance
|
|
1090
|
+
compliance = compliance_override
|
|
1091
|
+
if compliance is None:
|
|
1092
|
+
compliance = profile.get("default_compliance", [])
|
|
1093
|
+
if isinstance(compliance, str):
|
|
1094
|
+
if compliance.upper() == "ALL":
|
|
1095
|
+
compliance = _get_all_compliance_ids(manifest)
|
|
1096
|
+
else:
|
|
1097
|
+
compliance = [compliance]
|
|
1098
|
+
|
|
1099
|
+
# Resolve platform
|
|
1100
|
+
platform = platform_override or profile.get("default_platform", "docker")
|
|
1101
|
+
|
|
1102
|
+
# CUI
|
|
1103
|
+
cui_enabled = profile.get("cui_enabled", False)
|
|
1104
|
+
|
|
1105
|
+
# Team size
|
|
1106
|
+
team_size = profile.get("team_size", "")
|
|
1107
|
+
|
|
1108
|
+
return install(
|
|
1109
|
+
modules=profile_modules,
|
|
1110
|
+
compliance_frameworks=compliance,
|
|
1111
|
+
profile_name=profile_name,
|
|
1112
|
+
platform_target=platform,
|
|
1113
|
+
team_size=team_size,
|
|
1114
|
+
cui_enabled=cui_enabled,
|
|
1115
|
+
dry_run=dry_run,
|
|
1116
|
+
)
|
|
1117
|
+
|
|
1118
|
+
|
|
1119
|
+
# ---------------------------------------------------------------------------
|
|
1120
|
+
# Upgrade / add-module operations
|
|
1121
|
+
# ---------------------------------------------------------------------------
|
|
1122
|
+
|
|
1123
|
+
def show_upgrade_options() -> Dict[str, Any]:
|
|
1124
|
+
"""Show modules that can be added to the current installation.
|
|
1125
|
+
|
|
1126
|
+
Returns:
|
|
1127
|
+
Dict with available modules grouped by category.
|
|
1128
|
+
"""
|
|
1129
|
+
ModuleRegistryCls = _get_module_registry()
|
|
1130
|
+
registry = ModuleRegistryCls()
|
|
1131
|
+
available = registry.get_available()
|
|
1132
|
+
upgrade_path = registry.get_upgrade_path()
|
|
1133
|
+
installed = registry.get_installed()
|
|
1134
|
+
|
|
1135
|
+
installed_count = sum(1 for v in installed.values() if v.get("installed"))
|
|
1136
|
+
|
|
1137
|
+
return {
|
|
1138
|
+
"installed_count": installed_count,
|
|
1139
|
+
"available_now": available,
|
|
1140
|
+
"available_now_count": len(available),
|
|
1141
|
+
"full_upgrade_path": upgrade_path,
|
|
1142
|
+
"full_upgrade_count": len(upgrade_path),
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
|
|
1146
|
+
def add_module(
|
|
1147
|
+
module_id: str,
|
|
1148
|
+
dry_run: bool = False,
|
|
1149
|
+
) -> Dict[str, Any]:
|
|
1150
|
+
"""Add a single module to an existing installation.
|
|
1151
|
+
|
|
1152
|
+
Resolves dependencies and initializes required DB tables.
|
|
1153
|
+
|
|
1154
|
+
Args:
|
|
1155
|
+
module_id: The module to add.
|
|
1156
|
+
dry_run: Preview without executing.
|
|
1157
|
+
|
|
1158
|
+
Returns:
|
|
1159
|
+
Dict with result summary.
|
|
1160
|
+
"""
|
|
1161
|
+
manifest = _load_manifest()
|
|
1162
|
+
modules_cfg = manifest.get("modules", {})
|
|
1163
|
+
|
|
1164
|
+
if module_id not in modules_cfg:
|
|
1165
|
+
return {
|
|
1166
|
+
"success": False,
|
|
1167
|
+
"error": f"Unknown module: '{module_id}'",
|
|
1168
|
+
"available": list(modules_cfg.keys()),
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
# Load current installation
|
|
1172
|
+
ModuleRegistryCls = _get_module_registry()
|
|
1173
|
+
registry = ModuleRegistryCls()
|
|
1174
|
+
installed = registry.get_installed()
|
|
1175
|
+
installed_ids = [k for k, v in installed.items() if v.get("installed")]
|
|
1176
|
+
|
|
1177
|
+
if module_id in installed_ids:
|
|
1178
|
+
return {
|
|
1179
|
+
"success": True,
|
|
1180
|
+
"module_id": module_id,
|
|
1181
|
+
"note": "Module is already installed.",
|
|
1182
|
+
}
|
|
1183
|
+
|
|
1184
|
+
# Resolve what needs to be installed (module + deps)
|
|
1185
|
+
try:
|
|
1186
|
+
sorted_new = _topological_sort([module_id], manifest)
|
|
1187
|
+
except ValueError as e:
|
|
1188
|
+
return {"success": False, "error": str(e)}
|
|
1189
|
+
|
|
1190
|
+
# Filter out already installed
|
|
1191
|
+
to_install = [m for m in sorted_new if m not in installed_ids]
|
|
1192
|
+
|
|
1193
|
+
if dry_run:
|
|
1194
|
+
db_init = ModularDBInitializer()
|
|
1195
|
+
db_result = db_init.initialize(to_install, dry_run=True)
|
|
1196
|
+
return {
|
|
1197
|
+
"success": True,
|
|
1198
|
+
"dry_run": True,
|
|
1199
|
+
"module_id": module_id,
|
|
1200
|
+
"modules_to_install": to_install,
|
|
1201
|
+
"db_tables_planned": db_result.get("tables_planned", []),
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
# Initialize DB tables for new modules
|
|
1205
|
+
db_init = ModularDBInitializer()
|
|
1206
|
+
db_result = db_init.initialize(to_install, dry_run=False)
|
|
1207
|
+
|
|
1208
|
+
# Register modules
|
|
1209
|
+
results = []
|
|
1210
|
+
for mid in to_install:
|
|
1211
|
+
r = registry.install_module(mid)
|
|
1212
|
+
results.append(r)
|
|
1213
|
+
|
|
1214
|
+
failed = [r for r in results if not r.get("success")]
|
|
1215
|
+
|
|
1216
|
+
return {
|
|
1217
|
+
"success": len(failed) == 0,
|
|
1218
|
+
"dry_run": False,
|
|
1219
|
+
"module_id": module_id,
|
|
1220
|
+
"modules_installed": to_install,
|
|
1221
|
+
"db_tables_created": db_result.get("tables_created", []),
|
|
1222
|
+
"failures": failed if failed else [],
|
|
1223
|
+
}
|
|
1224
|
+
|
|
1225
|
+
|
|
1226
|
+
def add_compliance(
|
|
1227
|
+
framework_id: str,
|
|
1228
|
+
dry_run: bool = False,
|
|
1229
|
+
) -> Dict[str, Any]:
|
|
1230
|
+
"""Add a compliance framework to an existing installation.
|
|
1231
|
+
|
|
1232
|
+
Resolves required modules, initializes DB tables, and updates the
|
|
1233
|
+
compliance posture in the registry.
|
|
1234
|
+
|
|
1235
|
+
Args:
|
|
1236
|
+
framework_id: Compliance framework ID (e.g., hipaa, cmmc).
|
|
1237
|
+
dry_run: Preview without executing.
|
|
1238
|
+
|
|
1239
|
+
Returns:
|
|
1240
|
+
Dict with result summary.
|
|
1241
|
+
"""
|
|
1242
|
+
ComplianceConfiguratorCls = _get_compliance_configurator()
|
|
1243
|
+
configurator = ComplianceConfiguratorCls()
|
|
1244
|
+
|
|
1245
|
+
# Validate framework
|
|
1246
|
+
posture_config = configurator.configure_posture([framework_id])
|
|
1247
|
+
if posture_config.get("unknown_frameworks"):
|
|
1248
|
+
available_postures = configurator.list_postures()
|
|
1249
|
+
return {
|
|
1250
|
+
"success": False,
|
|
1251
|
+
"error": f"Unknown framework: '{framework_id}'",
|
|
1252
|
+
"available": [p["id"] for p in available_postures],
|
|
1253
|
+
}
|
|
1254
|
+
|
|
1255
|
+
required_modules = posture_config.get("required_modules", [])
|
|
1256
|
+
cui_needed = posture_config.get("cui_enabled", False)
|
|
1257
|
+
|
|
1258
|
+
# Load current state
|
|
1259
|
+
ModuleRegistryCls = _get_module_registry()
|
|
1260
|
+
registry = ModuleRegistryCls()
|
|
1261
|
+
installed = registry.get_installed()
|
|
1262
|
+
installed_ids = [k for k, v in installed.items() if v.get("installed")]
|
|
1263
|
+
current_config = registry.export_config()
|
|
1264
|
+
current_posture = current_config.get("compliance_posture", [])
|
|
1265
|
+
|
|
1266
|
+
if framework_id in current_posture:
|
|
1267
|
+
return {
|
|
1268
|
+
"success": True,
|
|
1269
|
+
"framework_id": framework_id,
|
|
1270
|
+
"note": "Framework is already in the compliance posture.",
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1273
|
+
# Determine new modules needed
|
|
1274
|
+
to_install = [m for m in required_modules if m not in installed_ids]
|
|
1275
|
+
|
|
1276
|
+
if dry_run:
|
|
1277
|
+
db_init = ModularDBInitializer()
|
|
1278
|
+
db_result = db_init.initialize(to_install, dry_run=True) if to_install else {}
|
|
1279
|
+
return {
|
|
1280
|
+
"success": True,
|
|
1281
|
+
"dry_run": True,
|
|
1282
|
+
"framework_id": framework_id,
|
|
1283
|
+
"modules_to_install": to_install,
|
|
1284
|
+
"cui_enabled": cui_needed,
|
|
1285
|
+
"db_tables_planned": db_result.get("tables_planned", []) if db_result else [],
|
|
1286
|
+
"security_gate_overrides": posture_config.get("security_gate_overrides", {}),
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1289
|
+
# Install new modules
|
|
1290
|
+
manifest = _load_manifest()
|
|
1291
|
+
if to_install:
|
|
1292
|
+
try:
|
|
1293
|
+
sorted_new = _topological_sort(to_install, manifest)
|
|
1294
|
+
except ValueError as e:
|
|
1295
|
+
return {"success": False, "error": str(e)}
|
|
1296
|
+
to_install = [m for m in sorted_new if m not in installed_ids]
|
|
1297
|
+
|
|
1298
|
+
db_init = ModularDBInitializer()
|
|
1299
|
+
db_init.initialize(to_install, dry_run=False)
|
|
1300
|
+
|
|
1301
|
+
for mid in to_install:
|
|
1302
|
+
registry.install_module(mid)
|
|
1303
|
+
|
|
1304
|
+
# Update compliance posture in registry
|
|
1305
|
+
updated_posture = list(current_posture)
|
|
1306
|
+
if framework_id not in updated_posture:
|
|
1307
|
+
updated_posture.append(framework_id)
|
|
1308
|
+
|
|
1309
|
+
# Update CUI if needed
|
|
1310
|
+
effective_cui = current_config.get("cui_enabled", False)
|
|
1311
|
+
if cui_needed:
|
|
1312
|
+
effective_cui = True
|
|
1313
|
+
_update_cui_markings(True)
|
|
1314
|
+
|
|
1315
|
+
# Merge gate overrides
|
|
1316
|
+
existing_gates = current_config.get("security_gate_overrides", {})
|
|
1317
|
+
existing_gates.update(posture_config.get("security_gate_overrides", {}))
|
|
1318
|
+
|
|
1319
|
+
# Persist registry
|
|
1320
|
+
current_config["compliance_posture"] = updated_posture
|
|
1321
|
+
current_config["cui_enabled"] = effective_cui
|
|
1322
|
+
current_config["security_gate_overrides"] = existing_gates
|
|
1323
|
+
current_config["last_updated"] = datetime.now(timezone.utc).isoformat()
|
|
1324
|
+
|
|
1325
|
+
REGISTRY_PATH.parent.mkdir(parents=True, exist_ok=True)
|
|
1326
|
+
with open(REGISTRY_PATH, "w", encoding="utf-8") as fh:
|
|
1327
|
+
json.dump(current_config, fh, indent=2, default=str)
|
|
1328
|
+
|
|
1329
|
+
return {
|
|
1330
|
+
"success": True,
|
|
1331
|
+
"dry_run": False,
|
|
1332
|
+
"framework_id": framework_id,
|
|
1333
|
+
"modules_installed": to_install,
|
|
1334
|
+
"compliance_posture": updated_posture,
|
|
1335
|
+
"cui_enabled": effective_cui,
|
|
1336
|
+
"security_gate_overrides": existing_gates,
|
|
1337
|
+
}
|
|
1338
|
+
|
|
1339
|
+
|
|
1340
|
+
def show_status() -> Dict[str, Any]:
|
|
1341
|
+
"""Return the current installation status.
|
|
1342
|
+
|
|
1343
|
+
Returns:
|
|
1344
|
+
Dict with installed modules, compliance posture, platform, etc.
|
|
1345
|
+
"""
|
|
1346
|
+
ModuleRegistryCls = _get_module_registry()
|
|
1347
|
+
registry = ModuleRegistryCls()
|
|
1348
|
+
|
|
1349
|
+
installed = registry.get_installed()
|
|
1350
|
+
config = registry.export_config()
|
|
1351
|
+
validation = registry.validate()
|
|
1352
|
+
|
|
1353
|
+
installed_count = sum(1 for v in installed.values() if v.get("installed"))
|
|
1354
|
+
total_available = len(_get_all_module_ids(_load_manifest()))
|
|
1355
|
+
|
|
1356
|
+
return {
|
|
1357
|
+
"profile": config.get("profile", "default"),
|
|
1358
|
+
"platform": config.get("platform", "unknown"),
|
|
1359
|
+
"team_size": config.get("team_size", ""),
|
|
1360
|
+
"installed_modules": installed,
|
|
1361
|
+
"installed_count": installed_count,
|
|
1362
|
+
"total_available": total_available,
|
|
1363
|
+
"coverage": f"{installed_count}/{total_available}",
|
|
1364
|
+
"compliance_posture": config.get("compliance_posture", []),
|
|
1365
|
+
"cui_enabled": config.get("cui_enabled", False),
|
|
1366
|
+
"impact_level": config.get("impact_level", "IL2"),
|
|
1367
|
+
"security_gate_overrides": config.get("security_gate_overrides", {}),
|
|
1368
|
+
"validation": validation,
|
|
1369
|
+
"installed_at": config.get("installed_at", ""),
|
|
1370
|
+
"last_updated": config.get("last_updated", ""),
|
|
1371
|
+
"registry_path": str(REGISTRY_PATH),
|
|
1372
|
+
"db_path": str(DB_PATH),
|
|
1373
|
+
}
|
|
1374
|
+
|
|
1375
|
+
|
|
1376
|
+
# ---------------------------------------------------------------------------
|
|
1377
|
+
# Human-readable output formatting
|
|
1378
|
+
# ---------------------------------------------------------------------------
|
|
1379
|
+
|
|
1380
|
+
def _format_install_result_human(result: Dict[str, Any]) -> str:
|
|
1381
|
+
"""Format installation result for terminal display."""
|
|
1382
|
+
lines = [
|
|
1383
|
+
"",
|
|
1384
|
+
"=" * 60,
|
|
1385
|
+
" ICDEV Installation Summary",
|
|
1386
|
+
"=" * 60,
|
|
1387
|
+
"",
|
|
1388
|
+
]
|
|
1389
|
+
|
|
1390
|
+
if result.get("dry_run"):
|
|
1391
|
+
lines.append(" *** DRY RUN — no changes were made ***")
|
|
1392
|
+
lines.append("")
|
|
1393
|
+
|
|
1394
|
+
success = result.get("success", False)
|
|
1395
|
+
lines.append(f" Status: {'SUCCESS' if success else 'FAILED'}")
|
|
1396
|
+
if result.get("error"):
|
|
1397
|
+
lines.append(f" Error: {result['error']}")
|
|
1398
|
+
lines.append(f" Profile: {result.get('profile', 'N/A')}")
|
|
1399
|
+
lines.append(f" Platform: {result.get('platform', 'N/A')}")
|
|
1400
|
+
lines.append(f" Team Size: {result.get('team_size', 'N/A')}")
|
|
1401
|
+
lines.append(f" CUI Markings: {'enabled' if result.get('cui_enabled') else 'disabled'}")
|
|
1402
|
+
lines.append(f" Impact Level: {result.get('impact_level', 'IL2')}")
|
|
1403
|
+
lines.append("")
|
|
1404
|
+
|
|
1405
|
+
# Modules
|
|
1406
|
+
modules = result.get("modules_installed") or result.get("modules", [])
|
|
1407
|
+
lines.append(f" Modules ({len(modules)}):")
|
|
1408
|
+
for mod_id in modules:
|
|
1409
|
+
lines.append(f" - {mod_id}")
|
|
1410
|
+
lines.append("")
|
|
1411
|
+
|
|
1412
|
+
# Compliance
|
|
1413
|
+
compliance = result.get("compliance_frameworks", [])
|
|
1414
|
+
lines.append(f" Compliance Frameworks ({len(compliance)}):")
|
|
1415
|
+
if compliance:
|
|
1416
|
+
for fw in compliance:
|
|
1417
|
+
lines.append(f" - {fw}")
|
|
1418
|
+
else:
|
|
1419
|
+
lines.append(" (none)")
|
|
1420
|
+
lines.append("")
|
|
1421
|
+
|
|
1422
|
+
# DB tables
|
|
1423
|
+
tables_key = "db_tables_created" if not result.get("dry_run") else "db_tables_planned"
|
|
1424
|
+
tables = result.get(tables_key, [])
|
|
1425
|
+
table_count = result.get("db_table_count", len(tables))
|
|
1426
|
+
lines.append(f" Database Tables: {table_count}")
|
|
1427
|
+
lines.append("")
|
|
1428
|
+
|
|
1429
|
+
# Failures
|
|
1430
|
+
failures = result.get("failures", [])
|
|
1431
|
+
if failures:
|
|
1432
|
+
lines.append(" Failures:")
|
|
1433
|
+
for f in failures:
|
|
1434
|
+
lines.append(f" - {f.get('module_id', '?')}: {f.get('error', '?')}")
|
|
1435
|
+
lines.append("")
|
|
1436
|
+
|
|
1437
|
+
# Paths
|
|
1438
|
+
if result.get("registry_path"):
|
|
1439
|
+
lines.append(f" Registry: {result['registry_path']}")
|
|
1440
|
+
if result.get("db_path"):
|
|
1441
|
+
lines.append(f" Database: {result['db_path']}")
|
|
1442
|
+
lines.append("")
|
|
1443
|
+
|
|
1444
|
+
return "\n".join(lines)
|
|
1445
|
+
|
|
1446
|
+
|
|
1447
|
+
def _format_status_human(result: Dict[str, Any]) -> str:
|
|
1448
|
+
"""Format status output for terminal display."""
|
|
1449
|
+
lines = [
|
|
1450
|
+
"",
|
|
1451
|
+
"=" * 60,
|
|
1452
|
+
" ICDEV Installation Status",
|
|
1453
|
+
"=" * 60,
|
|
1454
|
+
"",
|
|
1455
|
+
f" Profile: {result.get('profile', 'default')}",
|
|
1456
|
+
f" Platform: {result.get('platform', 'unknown')}",
|
|
1457
|
+
f" Team Size: {result.get('team_size', 'N/A')}",
|
|
1458
|
+
f" Coverage: {result.get('coverage', '0/0')}",
|
|
1459
|
+
f" CUI Markings: {'enabled' if result.get('cui_enabled') else 'disabled'}",
|
|
1460
|
+
f" Impact Level: {result.get('impact_level', 'IL2')}",
|
|
1461
|
+
f" Installed At: {result.get('installed_at', 'N/A')}",
|
|
1462
|
+
f" Last Updated: {result.get('last_updated', 'N/A')}",
|
|
1463
|
+
"",
|
|
1464
|
+
]
|
|
1465
|
+
|
|
1466
|
+
# Installed modules
|
|
1467
|
+
installed = result.get("installed_modules", {})
|
|
1468
|
+
lines.append(f" Installed Modules ({result.get('installed_count', 0)}):")
|
|
1469
|
+
if installed:
|
|
1470
|
+
lines.append(f" {'Module':<25} {'Version':<10} {'Installed At'}")
|
|
1471
|
+
lines.append(f" {'-' * 25} {'-' * 10} {'-' * 25}")
|
|
1472
|
+
for mod_id, info in sorted(installed.items()):
|
|
1473
|
+
if isinstance(info, dict) and info.get("installed"):
|
|
1474
|
+
name = info.get("name", mod_id)
|
|
1475
|
+
ver = info.get("version", "?")
|
|
1476
|
+
ts = info.get("installed_at", "?")
|
|
1477
|
+
lines.append(f" {name:<25} {ver:<10} {ts}")
|
|
1478
|
+
else:
|
|
1479
|
+
lines.append(" (none)")
|
|
1480
|
+
lines.append("")
|
|
1481
|
+
|
|
1482
|
+
# Compliance posture
|
|
1483
|
+
posture = result.get("compliance_posture", [])
|
|
1484
|
+
lines.append(f" Compliance Posture ({len(posture)}):")
|
|
1485
|
+
if posture:
|
|
1486
|
+
for fw in posture:
|
|
1487
|
+
lines.append(f" - {fw}")
|
|
1488
|
+
else:
|
|
1489
|
+
lines.append(" (none)")
|
|
1490
|
+
lines.append("")
|
|
1491
|
+
|
|
1492
|
+
# Validation
|
|
1493
|
+
validation = result.get("validation", {})
|
|
1494
|
+
valid = validation.get("valid", True)
|
|
1495
|
+
lines.append(f" Validation: {'VALID' if valid else 'ISSUES FOUND'}")
|
|
1496
|
+
issues = validation.get("issues", [])
|
|
1497
|
+
if issues:
|
|
1498
|
+
for issue in issues:
|
|
1499
|
+
lines.append(f" - {issue}")
|
|
1500
|
+
lines.append("")
|
|
1501
|
+
|
|
1502
|
+
return "\n".join(lines)
|
|
1503
|
+
|
|
1504
|
+
|
|
1505
|
+
def _format_upgrade_human(result: Dict[str, Any]) -> str:
|
|
1506
|
+
"""Format upgrade options for terminal display."""
|
|
1507
|
+
lines = [
|
|
1508
|
+
"",
|
|
1509
|
+
"=" * 60,
|
|
1510
|
+
" ICDEV — Available Upgrades",
|
|
1511
|
+
"=" * 60,
|
|
1512
|
+
"",
|
|
1513
|
+
f" Currently installed: {result.get('installed_count', 0)} modules",
|
|
1514
|
+
"",
|
|
1515
|
+
]
|
|
1516
|
+
|
|
1517
|
+
available = result.get("available_now", [])
|
|
1518
|
+
lines.append(f" Ready to install ({len(available)}):")
|
|
1519
|
+
if available:
|
|
1520
|
+
for mod in available:
|
|
1521
|
+
lines.append(f" {mod['module_id']:<25} {mod.get('name', '')}")
|
|
1522
|
+
if mod.get("description"):
|
|
1523
|
+
lines.append(f" {mod['description'][:70]}")
|
|
1524
|
+
else:
|
|
1525
|
+
lines.append(" (none — all dependencies must be satisfied first)")
|
|
1526
|
+
lines.append("")
|
|
1527
|
+
|
|
1528
|
+
blocked = [m for m in result.get("full_upgrade_path", []) if not m.get("deps_met")]
|
|
1529
|
+
if blocked:
|
|
1530
|
+
lines.append(f" Blocked (dependencies unmet): {len(blocked)}")
|
|
1531
|
+
for mod in blocked:
|
|
1532
|
+
deps = ", ".join(mod.get("dependencies", []))
|
|
1533
|
+
lines.append(f" {mod['module_id']:<25} needs: {deps}")
|
|
1534
|
+
lines.append("")
|
|
1535
|
+
|
|
1536
|
+
lines.append(" To add a module:")
|
|
1537
|
+
lines.append(" python tools/installer/installer.py --add-module <module_id>")
|
|
1538
|
+
lines.append("")
|
|
1539
|
+
|
|
1540
|
+
return "\n".join(lines)
|
|
1541
|
+
|
|
1542
|
+
|
|
1543
|
+
# ---------------------------------------------------------------------------
|
|
1544
|
+
# CLI entry point
|
|
1545
|
+
# ---------------------------------------------------------------------------
|
|
1546
|
+
|
|
1547
|
+
def main() -> None:
|
|
1548
|
+
"""Parse CLI arguments and dispatch to the appropriate mode."""
|
|
1549
|
+
parser = argparse.ArgumentParser(
|
|
1550
|
+
description="ICDEV Modular Installer — configure and install ICDEV components",
|
|
1551
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
1552
|
+
epilog="""\
|
|
1553
|
+
Examples:
|
|
1554
|
+
# Interactive wizard
|
|
1555
|
+
python tools/installer/installer.py --interactive
|
|
1556
|
+
|
|
1557
|
+
# Install from profile
|
|
1558
|
+
python tools/installer/installer.py --profile dod_team
|
|
1559
|
+
python tools/installer/installer.py --profile healthcare --compliance hipaa,hitrust --platform k8s
|
|
1560
|
+
|
|
1561
|
+
# Add modules after install
|
|
1562
|
+
python tools/installer/installer.py --add-module marketplace
|
|
1563
|
+
python tools/installer/installer.py --add-compliance hipaa
|
|
1564
|
+
|
|
1565
|
+
# Check status
|
|
1566
|
+
python tools/installer/installer.py --status
|
|
1567
|
+
python tools/installer/installer.py --status --json
|
|
1568
|
+
|
|
1569
|
+
# Dry run
|
|
1570
|
+
python tools/installer/installer.py --profile dod_team --dry-run
|
|
1571
|
+
""",
|
|
1572
|
+
)
|
|
1573
|
+
|
|
1574
|
+
# Mode selection
|
|
1575
|
+
mode_group = parser.add_argument_group("Installation Modes")
|
|
1576
|
+
mode_group.add_argument(
|
|
1577
|
+
"--interactive", action="store_true",
|
|
1578
|
+
help="Run the interactive 6-step installation wizard",
|
|
1579
|
+
)
|
|
1580
|
+
mode_group.add_argument(
|
|
1581
|
+
"--profile", metavar="NAME",
|
|
1582
|
+
help="Install using a named deployment profile (e.g., dod_team, healthcare)",
|
|
1583
|
+
)
|
|
1584
|
+
mode_group.add_argument(
|
|
1585
|
+
"--upgrade", action="store_true",
|
|
1586
|
+
help="Show available modules that can be added to the current installation",
|
|
1587
|
+
)
|
|
1588
|
+
mode_group.add_argument(
|
|
1589
|
+
"--add-module", metavar="MODULE_ID",
|
|
1590
|
+
help="Add a single module (with dependencies) to the current installation",
|
|
1591
|
+
)
|
|
1592
|
+
mode_group.add_argument(
|
|
1593
|
+
"--add-compliance", metavar="FRAMEWORK_ID",
|
|
1594
|
+
help="Add a compliance framework (with required modules) to the installation",
|
|
1595
|
+
)
|
|
1596
|
+
mode_group.add_argument(
|
|
1597
|
+
"--status", action="store_true",
|
|
1598
|
+
help="Show the current installation status",
|
|
1599
|
+
)
|
|
1600
|
+
|
|
1601
|
+
# Overrides for profile mode
|
|
1602
|
+
override_group = parser.add_argument_group("Profile Overrides")
|
|
1603
|
+
override_group.add_argument(
|
|
1604
|
+
"--compliance", metavar="FRAMEWORKS",
|
|
1605
|
+
help="Comma-separated compliance framework IDs (overrides profile default)",
|
|
1606
|
+
)
|
|
1607
|
+
override_group.add_argument(
|
|
1608
|
+
"--platform", metavar="PLATFORM",
|
|
1609
|
+
help="Deployment platform: docker, k8s, helm, aws_govcloud, azure_gov, on_prem",
|
|
1610
|
+
)
|
|
1611
|
+
|
|
1612
|
+
# Output options
|
|
1613
|
+
output_group = parser.add_argument_group("Output Options")
|
|
1614
|
+
output_group.add_argument(
|
|
1615
|
+
"--json", action="store_true",
|
|
1616
|
+
help="Output results as JSON",
|
|
1617
|
+
)
|
|
1618
|
+
output_group.add_argument(
|
|
1619
|
+
"--human", action="store_true",
|
|
1620
|
+
help="Human-friendly colorized terminal output",
|
|
1621
|
+
)
|
|
1622
|
+
output_group.add_argument(
|
|
1623
|
+
"--dry-run", action="store_true",
|
|
1624
|
+
help="Preview what would be installed without executing",
|
|
1625
|
+
)
|
|
1626
|
+
|
|
1627
|
+
args = parser.parse_args()
|
|
1628
|
+
use_json = args.json
|
|
1629
|
+
|
|
1630
|
+
def _output(result: Dict[str, Any], formatter=None) -> None:
|
|
1631
|
+
"""Print result as JSON or human-readable."""
|
|
1632
|
+
if use_json:
|
|
1633
|
+
print(json.dumps(result, indent=2, default=str))
|
|
1634
|
+
elif formatter:
|
|
1635
|
+
print(formatter(result))
|
|
1636
|
+
else:
|
|
1637
|
+
# Fallback: try to use output_formatter if available
|
|
1638
|
+
try:
|
|
1639
|
+
from icdev.tools.cli.output_formatter import auto_format
|
|
1640
|
+
print(auto_format(result, title="ICDEV Installer"))
|
|
1641
|
+
except ImportError:
|
|
1642
|
+
print(json.dumps(result, indent=2, default=str))
|
|
1643
|
+
|
|
1644
|
+
try:
|
|
1645
|
+
# ------- Interactive mode -------
|
|
1646
|
+
if args.interactive:
|
|
1647
|
+
result = run_interactive(dry_run=args.dry_run)
|
|
1648
|
+
_output(result, _format_install_result_human)
|
|
1649
|
+
|
|
1650
|
+
# ------- Profile mode -------
|
|
1651
|
+
elif args.profile:
|
|
1652
|
+
compliance_override = None
|
|
1653
|
+
if args.compliance:
|
|
1654
|
+
compliance_override = [
|
|
1655
|
+
f.strip() for f in args.compliance.split(",") if f.strip()
|
|
1656
|
+
]
|
|
1657
|
+
|
|
1658
|
+
result = run_profile(
|
|
1659
|
+
profile_name=args.profile,
|
|
1660
|
+
compliance_override=compliance_override,
|
|
1661
|
+
platform_override=args.platform,
|
|
1662
|
+
dry_run=args.dry_run,
|
|
1663
|
+
)
|
|
1664
|
+
_output(result, _format_install_result_human)
|
|
1665
|
+
|
|
1666
|
+
if not use_json and result.get("success") and not args.dry_run:
|
|
1667
|
+
print(" Installation complete. Run --status to verify.")
|
|
1668
|
+
print()
|
|
1669
|
+
|
|
1670
|
+
# ------- Upgrade -------
|
|
1671
|
+
elif args.upgrade:
|
|
1672
|
+
result = show_upgrade_options()
|
|
1673
|
+
_output(result, _format_upgrade_human)
|
|
1674
|
+
|
|
1675
|
+
# ------- Add module -------
|
|
1676
|
+
elif args.add_module:
|
|
1677
|
+
result = add_module(args.add_module, dry_run=args.dry_run)
|
|
1678
|
+
_output(result, _format_install_result_human)
|
|
1679
|
+
|
|
1680
|
+
# ------- Add compliance -------
|
|
1681
|
+
elif args.add_compliance:
|
|
1682
|
+
result = add_compliance(args.add_compliance, dry_run=args.dry_run)
|
|
1683
|
+
_output(result, _format_install_result_human)
|
|
1684
|
+
|
|
1685
|
+
# ------- Status -------
|
|
1686
|
+
elif args.status:
|
|
1687
|
+
result = show_status()
|
|
1688
|
+
_output(result, _format_status_human)
|
|
1689
|
+
|
|
1690
|
+
else:
|
|
1691
|
+
parser.print_help()
|
|
1692
|
+
sys.exit(0)
|
|
1693
|
+
|
|
1694
|
+
except KeyboardInterrupt:
|
|
1695
|
+
print("\n\n Installation cancelled.")
|
|
1696
|
+
sys.exit(130)
|
|
1697
|
+
except Exception as exc:
|
|
1698
|
+
error_result = {
|
|
1699
|
+
"success": False,
|
|
1700
|
+
"error": str(exc),
|
|
1701
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
1702
|
+
}
|
|
1703
|
+
if use_json:
|
|
1704
|
+
print(json.dumps(error_result, indent=2, default=str))
|
|
1705
|
+
else:
|
|
1706
|
+
print(f"\nERROR: {exc}", file=sys.stderr)
|
|
1707
|
+
sys.exit(1)
|
|
1708
|
+
|
|
1709
|
+
|
|
1710
|
+
if __name__ == "__main__":
|
|
1711
|
+
main()
|