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,1986 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# CUI // SP-CTI
|
|
3
|
+
"""
|
|
4
|
+
ICDEV Web Dashboard - Flask Application
|
|
5
|
+
========================================
|
|
6
|
+
Provides a web interface for monitoring projects, agents, compliance,
|
|
7
|
+
and system health within the ICDEV framework.
|
|
8
|
+
|
|
9
|
+
Usage:
|
|
10
|
+
python tools/dashboard/app.py [--port 5000] [--debug]
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import argparse
|
|
14
|
+
import sqlite3
|
|
15
|
+
import sys
|
|
16
|
+
import uuid
|
|
17
|
+
from datetime import datetime, timezone
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
from icdev._paths import get_project_root
|
|
20
|
+
|
|
21
|
+
# ---------------------------------------------------------------------------
|
|
22
|
+
# Path setup (so `tools.dashboard.config` is importable when run directly)
|
|
23
|
+
# ---------------------------------------------------------------------------
|
|
24
|
+
BASE_DIR = get_project_root()
|
|
25
|
+
if str(BASE_DIR) not in sys.path:
|
|
26
|
+
sys.path.insert(0, str(BASE_DIR))
|
|
27
|
+
|
|
28
|
+
from flask import Flask, render_template, jsonify, request as flask_request, g, session as flask_session, redirect, url_for, flash
|
|
29
|
+
|
|
30
|
+
from icdev.tools.dashboard.config import (
|
|
31
|
+
DB_PATH,
|
|
32
|
+
CUI_BANNER_TOP,
|
|
33
|
+
CUI_BANNER_BOTTOM,
|
|
34
|
+
CUI_DESIGNATION,
|
|
35
|
+
CUI_BANNER_ENABLED,
|
|
36
|
+
BYOK_ENABLED,
|
|
37
|
+
PORT,
|
|
38
|
+
DEBUG,
|
|
39
|
+
)
|
|
40
|
+
from icdev.tools.dashboard.auth import register_dashboard_auth, validate_api_key, log_auth_event
|
|
41
|
+
from icdev.tools.dashboard.websocket import init_socketio, get_socketio
|
|
42
|
+
from icdev.tools.dashboard.api.projects import projects_api
|
|
43
|
+
from icdev.tools.dashboard.api.agents import agents_api
|
|
44
|
+
from icdev.tools.dashboard.api.compliance import compliance_api
|
|
45
|
+
from icdev.tools.dashboard.api.audit import audit_api
|
|
46
|
+
from icdev.tools.dashboard.api.metrics import metrics_api
|
|
47
|
+
from icdev.tools.dashboard.api.events import events_bp
|
|
48
|
+
from icdev.tools.dashboard.api.nlq import nlq_bp
|
|
49
|
+
from icdev.tools.dashboard.api.batch import batch_api
|
|
50
|
+
from icdev.tools.dashboard.api.diagrams import diagrams_api
|
|
51
|
+
from icdev.tools.dashboard.api.cicd import cicd_api
|
|
52
|
+
from icdev.tools.dashboard.api.intake import intake_api
|
|
53
|
+
from icdev.tools.dashboard.api.admin import admin_api
|
|
54
|
+
from icdev.tools.dashboard.api.activity import activity_api
|
|
55
|
+
from icdev.tools.dashboard.api.usage import usage_api
|
|
56
|
+
from icdev.tools.dashboard.api.traces import traces_api, provenance_api, xai_api
|
|
57
|
+
from icdev.tools.dashboard.api.oscal import oscal_api
|
|
58
|
+
from icdev.tools.dashboard.api.prod_audit import prod_audit_api
|
|
59
|
+
from icdev.tools.dashboard.api.ai_transparency import ai_transparency_api
|
|
60
|
+
from icdev.tools.dashboard.api.ai_accountability import ai_accountability_api
|
|
61
|
+
from icdev.tools.dashboard.api.code_quality import code_quality_api
|
|
62
|
+
from icdev.tools.dashboard.api.fedramp_20x import fedramp_20x_api
|
|
63
|
+
from icdev.tools.dashboard.api.evidence import evidence_api
|
|
64
|
+
from icdev.tools.dashboard.api.lineage import lineage_api
|
|
65
|
+
# D-CHILD-6: GovProposal/CPMP/GovCon conditionally loaded
|
|
66
|
+
import os as _os
|
|
67
|
+
_GOVCON_ENABLED = _os.environ.get("ICDEV_GOVCON_ENABLED", "false").lower() == "true"
|
|
68
|
+
_HAS_GOVCON = False
|
|
69
|
+
if _GOVCON_ENABLED:
|
|
70
|
+
try:
|
|
71
|
+
from icdev.tools.dashboard.api.proposals import proposals_api
|
|
72
|
+
from icdev.tools.dashboard.api.govcon import govcon_api
|
|
73
|
+
from icdev.tools.dashboard.api.cpmp import cpmp_api
|
|
74
|
+
_HAS_GOVCON = True
|
|
75
|
+
except ImportError:
|
|
76
|
+
_HAS_GOVCON = False
|
|
77
|
+
from icdev.tools.dashboard.api.orchestration import orchestration_api
|
|
78
|
+
try:
|
|
79
|
+
from icdev.tools.dashboard.api.chat import chat_api
|
|
80
|
+
_HAS_CHAT_API = True
|
|
81
|
+
except ImportError:
|
|
82
|
+
_HAS_CHAT_API = False
|
|
83
|
+
from icdev.tools.dashboard.ux_helpers import register_ux_filters
|
|
84
|
+
|
|
85
|
+
# ---------------------------------------------------------------------------
|
|
86
|
+
# GovCon/CPMP/Proposals page registration (D-CHILD-6: isolated)
|
|
87
|
+
# ---------------------------------------------------------------------------
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def _register_govcon_pages(app: "Flask", _get_db):
|
|
91
|
+
"""Register GovProposal/CPMP/GovCon SSR page routes on the Flask app.
|
|
92
|
+
|
|
93
|
+
Called only when _HAS_GOVCON is True. Extracted from create_app() so that
|
|
94
|
+
child apps (and parent apps with ICDEV_GOVCON_ENABLED=false) never register
|
|
95
|
+
these routes.
|
|
96
|
+
"""
|
|
97
|
+
|
|
98
|
+
@app.route("/cpmp")
|
|
99
|
+
def cpmp_portfolio_page():
|
|
100
|
+
"""CPMP Portfolio — contract performance overview, health scoring."""
|
|
101
|
+
try:
|
|
102
|
+
from icdev.tools.govcon.portfolio_manager import get_portfolio_summary
|
|
103
|
+
portfolio_data = get_portfolio_summary()
|
|
104
|
+
pf = portfolio_data.get("portfolio", {})
|
|
105
|
+
contracts = pf.get("contracts", [])
|
|
106
|
+
upcoming = pf.get("upcoming_deliverables", [])
|
|
107
|
+
portfolio = {
|
|
108
|
+
"total_contracts": pf.get("total_contracts", 0),
|
|
109
|
+
"active_contracts": pf.get("active_contracts", 0),
|
|
110
|
+
"total_value": pf.get("total_value", 0),
|
|
111
|
+
"burn_rate": pf.get("burn_rate_pct", 0),
|
|
112
|
+
"overdue_deliverables": pf.get("overdue_deliverables", 0),
|
|
113
|
+
"at_risk": pf.get("at_risk_contracts", 0),
|
|
114
|
+
"health_distribution": pf.get("health_distribution", {"green": 0, "yellow": 0, "red": 0}),
|
|
115
|
+
}
|
|
116
|
+
return render_template("cpmp/portfolio.html", portfolio=portfolio, contracts=contracts, upcoming_deliverables=upcoming)
|
|
117
|
+
except Exception as e:
|
|
118
|
+
import traceback; traceback.print_exc()
|
|
119
|
+
return render_template("cpmp/portfolio.html", portfolio={"total_contracts": 0, "active_contracts": 0, "total_value": 0, "burn_rate": 0, "overdue_deliverables": 0, "health_distribution": {"green": 0, "yellow": 0, "red": 0}}, contracts=[], upcoming_deliverables=[], error=str(e))
|
|
120
|
+
|
|
121
|
+
@app.route("/cpmp/<contract_id>")
|
|
122
|
+
def cpmp_detail_page(contract_id):
|
|
123
|
+
"""CPMP Contract Detail — 7-tab view."""
|
|
124
|
+
try:
|
|
125
|
+
from icdev.tools.govcon.contract_manager import get_contract, list_clins, list_wbs, list_deliverables
|
|
126
|
+
contract_result = get_contract(contract_id)
|
|
127
|
+
if contract_result.get("status") == "error":
|
|
128
|
+
return render_template("404.html", message="Contract not found"), 404
|
|
129
|
+
contract = contract_result.get("contract", contract_result)
|
|
130
|
+
clins = list_clins(contract_id).get("clins", [])
|
|
131
|
+
wbs_elements = list_wbs(contract_id).get("wbs_elements", [])
|
|
132
|
+
deliverables = list_deliverables(contract_id).get("deliverables", [])
|
|
133
|
+
try:
|
|
134
|
+
from icdev.tools.govcon.subcontractor_tracker import list_subcontractors
|
|
135
|
+
subcontractors = list_subcontractors(contract_id).get("subcontractors", [])
|
|
136
|
+
except Exception:
|
|
137
|
+
subcontractors = []
|
|
138
|
+
try:
|
|
139
|
+
from icdev.tools.govcon.evm_engine import aggregate_contract_evm
|
|
140
|
+
evm = aggregate_contract_evm(contract_id)
|
|
141
|
+
if "indicators" in evm and isinstance(evm["indicators"], dict):
|
|
142
|
+
evm.update(evm["indicators"])
|
|
143
|
+
except Exception:
|
|
144
|
+
evm = {}
|
|
145
|
+
try:
|
|
146
|
+
from icdev.tools.govcon.cpars_predictor import predict_cpars, list_assessments
|
|
147
|
+
cpars_prediction = predict_cpars(contract_id)
|
|
148
|
+
if "dimension_scores" in cpars_prediction:
|
|
149
|
+
cpars_prediction["dimensions"] = {
|
|
150
|
+
k: round(v * 5, 2) for k, v in cpars_prediction["dimension_scores"].items()
|
|
151
|
+
}
|
|
152
|
+
cpars_assessments = list_assessments(contract_id).get("assessments", [])
|
|
153
|
+
except Exception:
|
|
154
|
+
cpars_prediction = {}
|
|
155
|
+
cpars_assessments = []
|
|
156
|
+
return render_template("cpmp/detail.html",
|
|
157
|
+
contract=contract, clins=clins, wbs_elements=wbs_elements,
|
|
158
|
+
deliverables=deliverables, subcontractors=subcontractors,
|
|
159
|
+
evm=evm, cpars_prediction=cpars_prediction,
|
|
160
|
+
cpars_assessments=cpars_assessments)
|
|
161
|
+
except Exception as e:
|
|
162
|
+
import traceback; traceback.print_exc()
|
|
163
|
+
return render_template("404.html", message=f"Error loading contract: {e}"), 500
|
|
164
|
+
|
|
165
|
+
@app.route("/cpmp/<contract_id>/deliverables/<deliverable_id>")
|
|
166
|
+
def cpmp_deliverable_detail_page(contract_id, deliverable_id):
|
|
167
|
+
"""CPMP Deliverable Detail — status pipeline, CDRL generation."""
|
|
168
|
+
try:
|
|
169
|
+
from icdev.tools.govcon.contract_manager import get_contract, get_deliverable
|
|
170
|
+
contract_result = get_contract(contract_id)
|
|
171
|
+
contract = contract_result.get("contract", contract_result) if contract_result.get("status") == "ok" else {}
|
|
172
|
+
deliv_result = get_deliverable(deliverable_id)
|
|
173
|
+
if deliv_result.get("status") == "error":
|
|
174
|
+
return render_template("404.html", message="Deliverable not found"), 404
|
|
175
|
+
deliverable = deliv_result.get("deliverable", deliv_result)
|
|
176
|
+
generations = deliverable.get("generations", []) if isinstance(deliverable, dict) else []
|
|
177
|
+
status_history = deliverable.get("status_history", []) if isinstance(deliverable, dict) else []
|
|
178
|
+
return render_template("cpmp/deliverable_detail.html",
|
|
179
|
+
contract=contract, deliverable=deliverable,
|
|
180
|
+
generations=generations, status_history=status_history)
|
|
181
|
+
except Exception as e:
|
|
182
|
+
import traceback; traceback.print_exc()
|
|
183
|
+
return render_template("404.html", message=f"Error loading deliverable: {e}"), 500
|
|
184
|
+
|
|
185
|
+
@app.route("/cpmp/cor")
|
|
186
|
+
def cpmp_cor_portal_page():
|
|
187
|
+
"""COR Portal — read-only government view of assigned contracts."""
|
|
188
|
+
user = getattr(g, "current_user", None)
|
|
189
|
+
cor_email = user.get("email", "") if user else ""
|
|
190
|
+
conn = _get_db()
|
|
191
|
+
try:
|
|
192
|
+
if cor_email:
|
|
193
|
+
rows = conn.execute(
|
|
194
|
+
"SELECT * FROM cpmp_contracts WHERE cor_email = ? ORDER BY created_at DESC",
|
|
195
|
+
(cor_email,),
|
|
196
|
+
).fetchall()
|
|
197
|
+
contracts = [dict(r) for r in rows]
|
|
198
|
+
else:
|
|
199
|
+
contracts = []
|
|
200
|
+
return render_template("cpmp/cor_portal.html", contracts=contracts, cor_email=cor_email)
|
|
201
|
+
except Exception as e:
|
|
202
|
+
import traceback; traceback.print_exc()
|
|
203
|
+
return render_template("cpmp/cor_portal.html", contracts=[], cor_email=cor_email)
|
|
204
|
+
finally:
|
|
205
|
+
conn.close()
|
|
206
|
+
|
|
207
|
+
@app.route("/cpmp/cor/<contract_id>")
|
|
208
|
+
def cpmp_cor_detail_page(contract_id):
|
|
209
|
+
"""COR Contract Detail — read-only, no internal cost data."""
|
|
210
|
+
user = getattr(g, "current_user", None)
|
|
211
|
+
cor_email = user.get("email", "") if user else ""
|
|
212
|
+
conn = _get_db()
|
|
213
|
+
try:
|
|
214
|
+
from icdev.tools.govcon.contract_manager import get_contract, list_deliverables
|
|
215
|
+
contract_result = get_contract(contract_id)
|
|
216
|
+
if contract_result.get("status") == "error":
|
|
217
|
+
return render_template("404.html", message="Contract not found"), 404
|
|
218
|
+
contract = contract_result.get("contract", contract_result)
|
|
219
|
+
deliverables = list_deliverables(contract_id).get("deliverables", [])
|
|
220
|
+
try:
|
|
221
|
+
from icdev.tools.govcon.evm_engine import aggregate_contract_evm
|
|
222
|
+
evm = aggregate_contract_evm(contract_id)
|
|
223
|
+
if "indicators" in evm and isinstance(evm["indicators"], dict):
|
|
224
|
+
evm.update(evm["indicators"])
|
|
225
|
+
if "total_bac" in evm:
|
|
226
|
+
evm.setdefault("bac", evm["total_bac"])
|
|
227
|
+
if "total_pv" in evm:
|
|
228
|
+
evm.setdefault("pv", evm["total_pv"])
|
|
229
|
+
if "total_ev" in evm:
|
|
230
|
+
evm.setdefault("ev", evm["total_ev"])
|
|
231
|
+
if "percent_complete" in evm:
|
|
232
|
+
evm.setdefault("percent_complete_schedule", evm["percent_complete"] / 100 if evm["percent_complete"] > 1 else evm["percent_complete"])
|
|
233
|
+
except Exception:
|
|
234
|
+
evm = {}
|
|
235
|
+
try:
|
|
236
|
+
from icdev.tools.govcon.cpars_predictor import list_assessments
|
|
237
|
+
cpars_assessments = list_assessments(contract_id).get("assessments", [])
|
|
238
|
+
except Exception:
|
|
239
|
+
cpars_assessments = []
|
|
240
|
+
try:
|
|
241
|
+
conn.execute(
|
|
242
|
+
"INSERT INTO cpmp_cor_access_log (id, user_id, contract_id, action, accessed_at, classification) "
|
|
243
|
+
"VALUES (?, ?, ?, ?, ?, ?)",
|
|
244
|
+
(str(uuid.uuid4()), cor_email, contract_id, "view_contract", datetime.now(timezone.utc).isoformat(), "CUI // SP-CTI"),
|
|
245
|
+
)
|
|
246
|
+
conn.commit()
|
|
247
|
+
except Exception:
|
|
248
|
+
pass
|
|
249
|
+
return render_template("cpmp/cor_detail.html",
|
|
250
|
+
contract=contract, deliverables=deliverables,
|
|
251
|
+
evm=evm, cpars_assessments=cpars_assessments, cor_email=cor_email)
|
|
252
|
+
except Exception as e:
|
|
253
|
+
return render_template("404.html", message=f"Error: {e}"), 500
|
|
254
|
+
finally:
|
|
255
|
+
conn.close()
|
|
256
|
+
|
|
257
|
+
@app.route("/proposals")
|
|
258
|
+
def proposals_list_page():
|
|
259
|
+
"""Proposal Opportunities — GovCon proposal writing lifecycle tracker."""
|
|
260
|
+
conn = _get_db()
|
|
261
|
+
try:
|
|
262
|
+
rows = conn.execute("SELECT * FROM proposal_opportunities ORDER BY due_date ASC").fetchall()
|
|
263
|
+
opportunities = [dict(r) for r in rows]
|
|
264
|
+
from datetime import date
|
|
265
|
+
today = date.today()
|
|
266
|
+
nearest_deadline = None
|
|
267
|
+
for opp in opportunities:
|
|
268
|
+
if opp.get("due_date") and opp["status"] not in ("submitted", "won", "lost", "cancelled", "no_bid"):
|
|
269
|
+
try:
|
|
270
|
+
dd = date.fromisoformat(opp["due_date"])
|
|
271
|
+
days_left = (dd - today).days
|
|
272
|
+
opp["days_left"] = days_left
|
|
273
|
+
if nearest_deadline is None or days_left < nearest_deadline:
|
|
274
|
+
nearest_deadline = days_left
|
|
275
|
+
except (ValueError, TypeError):
|
|
276
|
+
opp["days_left"] = None
|
|
277
|
+
else:
|
|
278
|
+
opp["days_left"] = None
|
|
279
|
+
return render_template("proposals/list.html", opportunities=opportunities, nearest_deadline=nearest_deadline)
|
|
280
|
+
finally:
|
|
281
|
+
conn.close()
|
|
282
|
+
|
|
283
|
+
@app.route("/proposals/<opp_id>")
|
|
284
|
+
def proposals_detail_page(opp_id):
|
|
285
|
+
"""Proposal Opportunity Detail — 6-tab view with sections, compliance, reviews."""
|
|
286
|
+
conn = _get_db()
|
|
287
|
+
try:
|
|
288
|
+
opp = conn.execute("SELECT * FROM proposal_opportunities WHERE id = ?", (opp_id,)).fetchone()
|
|
289
|
+
if not opp:
|
|
290
|
+
return render_template("404.html", message="Opportunity not found"), 404
|
|
291
|
+
opp = dict(opp)
|
|
292
|
+
sections = [dict(r) for r in conn.execute(
|
|
293
|
+
"""SELECT s.*, v.volume_number, v.title as volume_title
|
|
294
|
+
FROM proposal_sections s
|
|
295
|
+
LEFT JOIN proposal_volumes v ON s.volume_id = v.id
|
|
296
|
+
WHERE s.opportunity_id = ?
|
|
297
|
+
ORDER BY v.volume_number, s.section_number""", (opp_id,)
|
|
298
|
+
).fetchall()]
|
|
299
|
+
from datetime import date
|
|
300
|
+
today = date.today()
|
|
301
|
+
for s in sections:
|
|
302
|
+
s["overdue"] = False
|
|
303
|
+
if s.get("due_date") and s["status"] not in ("final", "submitted"):
|
|
304
|
+
try:
|
|
305
|
+
s["overdue"] = date.fromisoformat(s["due_date"]) < today
|
|
306
|
+
except (ValueError, TypeError):
|
|
307
|
+
pass
|
|
308
|
+
volumes = [dict(r) for r in conn.execute(
|
|
309
|
+
"SELECT * FROM proposal_volumes WHERE opportunity_id = ? ORDER BY volume_number", (opp_id,)
|
|
310
|
+
).fetchall()]
|
|
311
|
+
compliance_items = [dict(r) for r in conn.execute(
|
|
312
|
+
"SELECT * FROM proposal_compliance_matrix WHERE opportunity_id = ?", (opp_id,)
|
|
313
|
+
).fetchall()]
|
|
314
|
+
reviews = [dict(r) for r in conn.execute(
|
|
315
|
+
"SELECT * FROM proposal_reviews WHERE opportunity_id = ? ORDER BY scheduled_date", (opp_id,)
|
|
316
|
+
).fetchall()]
|
|
317
|
+
findings = [dict(r) for r in conn.execute(
|
|
318
|
+
"""SELECT f.*, r.review_type FROM proposal_review_findings f
|
|
319
|
+
JOIN proposal_reviews r ON f.review_id = r.id
|
|
320
|
+
WHERE r.opportunity_id = ?""", (opp_id,)
|
|
321
|
+
).fetchall()]
|
|
322
|
+
total_sections = len(sections)
|
|
323
|
+
completed_sections = len([s for s in sections if s["status"] in ("final", "submitted")])
|
|
324
|
+
total_compliance = len(compliance_items)
|
|
325
|
+
compliant_count = len([c for c in compliance_items if c.get("compliance_status") == "compliant"])
|
|
326
|
+
coverage_pct = (compliant_count / total_compliance * 100) if total_compliance > 0 else 0
|
|
327
|
+
open_findings = len([f for f in findings if f.get("status") in ("open", "in_progress")])
|
|
328
|
+
critical_findings = len([f for f in findings if f.get("severity") == "critical" and f.get("status") in ("open", "in_progress")])
|
|
329
|
+
section_status_dist = {}
|
|
330
|
+
for s in sections:
|
|
331
|
+
st = s.get("status", "not_started")
|
|
332
|
+
section_status_dist[st] = section_status_dist.get(st, 0) + 1
|
|
333
|
+
finding_severity_dist = {}
|
|
334
|
+
for f in findings:
|
|
335
|
+
if f.get("status") in ("open", "in_progress"):
|
|
336
|
+
sev = f.get("severity", "minor")
|
|
337
|
+
finding_severity_dist[sev] = finding_severity_dist.get(sev, 0) + 1
|
|
338
|
+
cm_compliant = len([c for c in compliance_items if c.get("compliance_status") == "compliant"])
|
|
339
|
+
cm_partial = len([c for c in compliance_items if c.get("compliance_status") == "partial"])
|
|
340
|
+
cm_non_compliant = len([c for c in compliance_items if c.get("compliance_status") == "non_compliant"])
|
|
341
|
+
cm_not_addressed = len([c for c in compliance_items if c.get("compliance_status") == "not_addressed"])
|
|
342
|
+
cm_not_applicable = len([c for c in compliance_items if c.get("compliance_status") == "not_applicable"])
|
|
343
|
+
cm_gap_pct = round(cm_not_addressed / total_compliance * 100) if total_compliance > 0 else 0
|
|
344
|
+
compliance_stats = {
|
|
345
|
+
"total": total_compliance, "compliant": cm_compliant, "partial": cm_partial,
|
|
346
|
+
"non_compliant": cm_non_compliant, "not_addressed": cm_not_addressed,
|
|
347
|
+
"not_applicable": cm_not_applicable, "gap_pct": cm_gap_pct,
|
|
348
|
+
}
|
|
349
|
+
findings_by_review = {}
|
|
350
|
+
for f in findings:
|
|
351
|
+
rid = f.get("review_id")
|
|
352
|
+
if rid:
|
|
353
|
+
findings_by_review.setdefault(rid, []).append(f)
|
|
354
|
+
reviews_data = []
|
|
355
|
+
for rev in reviews:
|
|
356
|
+
rd = dict(rev)
|
|
357
|
+
rd["findings"] = findings_by_review.get(rev["id"], [])
|
|
358
|
+
reviews_data.append(rd)
|
|
359
|
+
days_left = None
|
|
360
|
+
if opp.get("due_date"):
|
|
361
|
+
try:
|
|
362
|
+
days_left = (date.fromisoformat(opp["due_date"]) - today).days
|
|
363
|
+
except (ValueError, TypeError):
|
|
364
|
+
pass
|
|
365
|
+
stats = {
|
|
366
|
+
"sections_total": total_sections, "sections_complete": completed_sections,
|
|
367
|
+
"compliance_coverage_pct": round(coverage_pct), "open_findings": open_findings,
|
|
368
|
+
"critical_findings": critical_findings, "section_status_distribution": section_status_dist,
|
|
369
|
+
"finding_severity_distribution": finding_severity_dist,
|
|
370
|
+
}
|
|
371
|
+
questions = [dict(r) for r in conn.execute(
|
|
372
|
+
"SELECT * FROM proposal_questions WHERE opportunity_id = ? ORDER BY question_number ASC", (opp_id,),
|
|
373
|
+
).fetchall()]
|
|
374
|
+
question_stats = {
|
|
375
|
+
"total": len(questions),
|
|
376
|
+
"high_priority": len([q for q in questions if q.get("priority") == "high"]),
|
|
377
|
+
"draft": len([q for q in questions if q.get("status") == "draft"]),
|
|
378
|
+
"approved": len([q for q in questions if q.get("status") == "approved"]),
|
|
379
|
+
"submitted": len([q for q in questions if q.get("status") == "submitted"]),
|
|
380
|
+
"answered": len([q for q in questions if q.get("status") == "answered"]),
|
|
381
|
+
}
|
|
382
|
+
questions_days_left = None
|
|
383
|
+
if opp.get("questions_due_date"):
|
|
384
|
+
try:
|
|
385
|
+
questions_days_left = (date.fromisoformat(opp["questions_due_date"]) - today).days
|
|
386
|
+
except (ValueError, TypeError):
|
|
387
|
+
pass
|
|
388
|
+
amendments = [dict(r) for r in conn.execute(
|
|
389
|
+
"SELECT * FROM proposal_amendments WHERE opportunity_id = ? ORDER BY version_number ASC", (opp_id,),
|
|
390
|
+
).fetchall()]
|
|
391
|
+
responses = {}
|
|
392
|
+
for q in questions:
|
|
393
|
+
if q.get("status") == "answered":
|
|
394
|
+
resp = conn.execute(
|
|
395
|
+
"SELECT * FROM proposal_question_responses WHERE question_id = ? ORDER BY created_at DESC LIMIT 1",
|
|
396
|
+
(q["id"],),
|
|
397
|
+
).fetchone()
|
|
398
|
+
if resp:
|
|
399
|
+
responses[q["id"]] = dict(resp)
|
|
400
|
+
return render_template("proposals/detail.html",
|
|
401
|
+
opp=opp, sections=sections, volumes=volumes,
|
|
402
|
+
compliance_items=compliance_items, reviews=reviews_data, findings=findings,
|
|
403
|
+
stats=stats, compliance_stats=compliance_stats,
|
|
404
|
+
reviews_data=reviews_data, days_left=days_left,
|
|
405
|
+
questions=questions, question_stats=question_stats,
|
|
406
|
+
questions_days_left=questions_days_left,
|
|
407
|
+
amendments=amendments, responses=responses)
|
|
408
|
+
finally:
|
|
409
|
+
conn.close()
|
|
410
|
+
|
|
411
|
+
@app.route("/proposals/<opp_id>/sections/<sec_id>")
|
|
412
|
+
def proposals_section_detail_page(opp_id, sec_id):
|
|
413
|
+
"""Proposal Section Detail — status pipeline, notes, compliance, findings, history."""
|
|
414
|
+
conn = _get_db()
|
|
415
|
+
try:
|
|
416
|
+
section = conn.execute(
|
|
417
|
+
"""SELECT s.*, v.volume_number, v.title as volume_title
|
|
418
|
+
FROM proposal_sections s
|
|
419
|
+
LEFT JOIN proposal_volumes v ON s.volume_id = v.id
|
|
420
|
+
WHERE s.id = ? AND s.opportunity_id = ?""",
|
|
421
|
+
(sec_id, opp_id)).fetchone()
|
|
422
|
+
if not section:
|
|
423
|
+
return render_template("404.html", message="Section not found"), 404
|
|
424
|
+
section = dict(section)
|
|
425
|
+
opp = conn.execute("SELECT title FROM proposal_opportunities WHERE id = ?", (opp_id,)).fetchone()
|
|
426
|
+
opp_title = opp["title"] if opp else "Unknown"
|
|
427
|
+
from icdev.tools.dashboard.api.proposals import SECTION_TRANSITIONS
|
|
428
|
+
section["valid_transitions"] = SECTION_TRANSITIONS.get(section["status"], [])
|
|
429
|
+
from datetime import date
|
|
430
|
+
section["overdue"] = False
|
|
431
|
+
if section.get("due_date") and section["status"] not in ("final", "submitted"):
|
|
432
|
+
try:
|
|
433
|
+
section["overdue"] = date.fromisoformat(section["due_date"]) < date.today()
|
|
434
|
+
except (ValueError, TypeError):
|
|
435
|
+
pass
|
|
436
|
+
section["compliance_items"] = [dict(r) for r in conn.execute(
|
|
437
|
+
"SELECT * FROM proposal_compliance_matrix WHERE proposal_section_id = ?", (sec_id,)
|
|
438
|
+
).fetchall()]
|
|
439
|
+
section["findings"] = [dict(r) for r in conn.execute(
|
|
440
|
+
"""SELECT f.*, r.review_type FROM proposal_review_findings f
|
|
441
|
+
JOIN proposal_reviews r ON f.review_id = r.id
|
|
442
|
+
WHERE f.section_id = ?""", (sec_id,)
|
|
443
|
+
).fetchall()]
|
|
444
|
+
deps = conn.execute(
|
|
445
|
+
"""SELECT d.*, s.title as depends_on_title, s.status as depends_on_status
|
|
446
|
+
FROM proposal_section_dependencies d
|
|
447
|
+
JOIN proposal_sections s ON d.depends_on_section_id = s.id
|
|
448
|
+
WHERE d.section_id = ?""", (sec_id,)
|
|
449
|
+
).fetchall()
|
|
450
|
+
dep_list = []
|
|
451
|
+
for d in deps:
|
|
452
|
+
d = dict(d)
|
|
453
|
+
from icdev.tools.dashboard.api.proposals import SECTION_STATUS_ORDER
|
|
454
|
+
req_idx = SECTION_STATUS_ORDER.index(d["required_status"]) if d["required_status"] in SECTION_STATUS_ORDER else 0
|
|
455
|
+
cur_idx = SECTION_STATUS_ORDER.index(d["depends_on_status"]) if d["depends_on_status"] in SECTION_STATUS_ORDER else 0
|
|
456
|
+
d["met"] = cur_idx >= req_idx
|
|
457
|
+
dep_list.append(d)
|
|
458
|
+
section["dependencies"] = dep_list
|
|
459
|
+
section["history"] = [dict(r) for r in conn.execute(
|
|
460
|
+
"SELECT * FROM proposal_status_history WHERE entity_id = ? ORDER BY created_at DESC", (sec_id,)
|
|
461
|
+
).fetchall()]
|
|
462
|
+
return render_template("proposals/section_detail.html", section=section, opp_title=opp_title)
|
|
463
|
+
finally:
|
|
464
|
+
conn.close()
|
|
465
|
+
|
|
466
|
+
@app.route("/govcon")
|
|
467
|
+
def govcon_pipeline_page():
|
|
468
|
+
"""GovCon Intelligence — pipeline status, recent opportunities, domain distribution."""
|
|
469
|
+
conn = _get_db()
|
|
470
|
+
try:
|
|
471
|
+
from icdev.tools.govcon.govcon_engine import get_status
|
|
472
|
+
stats = get_status()
|
|
473
|
+
try:
|
|
474
|
+
opps = conn.execute("SELECT * FROM sam_gov_opportunities ORDER BY posted_date DESC LIMIT 25").fetchall()
|
|
475
|
+
opportunities = [dict(r) for r in opps]
|
|
476
|
+
except Exception:
|
|
477
|
+
opportunities = []
|
|
478
|
+
linked_opp_ids = set()
|
|
479
|
+
try:
|
|
480
|
+
linked = conn.execute("SELECT sam_gov_opportunity_id FROM proposal_opportunities WHERE sam_gov_opportunity_id IS NOT NULL").fetchall()
|
|
481
|
+
linked_opp_ids = {r["sam_gov_opportunity_id"] for r in linked}
|
|
482
|
+
except Exception:
|
|
483
|
+
pass
|
|
484
|
+
return render_template("govcon/pipeline.html", stats=stats, opportunities=opportunities, linked_opp_ids=linked_opp_ids)
|
|
485
|
+
except Exception:
|
|
486
|
+
stats = {"total_opportunities": 0, "total_requirements": 0, "total_patterns": 0,
|
|
487
|
+
"total_capability_maps": 0, "total_drafts": 0, "total_awards": 0,
|
|
488
|
+
"knowledge_blocks": 0, "linked_proposals": 0, "domain_distribution": {},
|
|
489
|
+
"last_pipeline_run": None}
|
|
490
|
+
return render_template("govcon/pipeline.html", stats=stats, opportunities=[], linked_opp_ids=set())
|
|
491
|
+
finally:
|
|
492
|
+
conn.close()
|
|
493
|
+
|
|
494
|
+
@app.route("/govcon/requirements")
|
|
495
|
+
def govcon_requirements_page():
|
|
496
|
+
"""GovCon Requirements — pattern frequency, domain heatmap, statement types."""
|
|
497
|
+
conn = _get_db()
|
|
498
|
+
try:
|
|
499
|
+
total_requirements = 0
|
|
500
|
+
try:
|
|
501
|
+
r = conn.execute("SELECT COUNT(*) as cnt FROM rfp_shall_statements").fetchone()
|
|
502
|
+
total_requirements = r["cnt"] if r else 0
|
|
503
|
+
except Exception:
|
|
504
|
+
pass
|
|
505
|
+
total_patterns = 0
|
|
506
|
+
try:
|
|
507
|
+
r = conn.execute("SELECT COUNT(*) as cnt FROM rfp_requirement_patterns").fetchone()
|
|
508
|
+
total_patterns = r["cnt"] if r else 0
|
|
509
|
+
except Exception:
|
|
510
|
+
pass
|
|
511
|
+
domain_stats = {}
|
|
512
|
+
try:
|
|
513
|
+
rows = conn.execute("SELECT domain_category, COUNT(*) as cnt FROM rfp_shall_statements GROUP BY domain_category ORDER BY cnt DESC").fetchall()
|
|
514
|
+
domain_stats = {r["domain_category"]: {"count": r["cnt"]} for r in rows}
|
|
515
|
+
except Exception:
|
|
516
|
+
pass
|
|
517
|
+
domain_count = len(domain_stats)
|
|
518
|
+
patterns = []
|
|
519
|
+
min_frequency = 3
|
|
520
|
+
try:
|
|
521
|
+
rows = conn.execute("SELECT * FROM rfp_requirement_patterns WHERE frequency >= ? ORDER BY frequency DESC LIMIT 30", (min_frequency,)).fetchall()
|
|
522
|
+
patterns = [dict(r) for r in rows]
|
|
523
|
+
except Exception:
|
|
524
|
+
pass
|
|
525
|
+
top_frequency = patterns[0]["frequency"] if patterns else 0
|
|
526
|
+
type_stats = {}
|
|
527
|
+
try:
|
|
528
|
+
rows = conn.execute("SELECT statement_type, COUNT(*) as cnt FROM rfp_shall_statements GROUP BY statement_type ORDER BY cnt DESC").fetchall()
|
|
529
|
+
type_stats = {r["statement_type"]: r["cnt"] for r in rows}
|
|
530
|
+
except Exception:
|
|
531
|
+
pass
|
|
532
|
+
return render_template("govcon/requirements.html",
|
|
533
|
+
total_requirements=total_requirements, total_patterns=total_patterns,
|
|
534
|
+
domain_stats=domain_stats, domain_count=domain_count,
|
|
535
|
+
patterns=patterns, top_frequency=top_frequency,
|
|
536
|
+
type_stats=type_stats, min_frequency=min_frequency)
|
|
537
|
+
finally:
|
|
538
|
+
conn.close()
|
|
539
|
+
|
|
540
|
+
@app.route("/govcon/capabilities")
|
|
541
|
+
def govcon_capabilities_page():
|
|
542
|
+
"""GovCon Capabilities — coverage by domain, gap list, enhancement recommendations."""
|
|
543
|
+
conn = _get_db()
|
|
544
|
+
try:
|
|
545
|
+
coverage = {"L": 0, "M": 0, "N": 0, "rate": 0}
|
|
546
|
+
try:
|
|
547
|
+
rows = conn.execute(
|
|
548
|
+
"""SELECT
|
|
549
|
+
SUM(CASE WHEN m.coverage_score >= 0.80 THEN 1 ELSE 0 END) as L,
|
|
550
|
+
SUM(CASE WHEN m.coverage_score >= 0.40 AND m.coverage_score < 0.80 THEN 1 ELSE 0 END) as M,
|
|
551
|
+
SUM(CASE WHEN m.coverage_score < 0.40 OR m.coverage_score IS NULL THEN 1 ELSE 0 END) as N,
|
|
552
|
+
COUNT(*) as total
|
|
553
|
+
FROM rfp_shall_statements s
|
|
554
|
+
LEFT JOIN icdev_capability_map m ON s.id = m.pattern_id"""
|
|
555
|
+
).fetchone()
|
|
556
|
+
if rows and rows["total"] > 0:
|
|
557
|
+
coverage["L"] = rows["L"] or 0
|
|
558
|
+
coverage["M"] = rows["M"] or 0
|
|
559
|
+
coverage["N"] = rows["N"] or 0
|
|
560
|
+
coverage["rate"] = round(coverage["L"] / rows["total"] * 100)
|
|
561
|
+
except Exception:
|
|
562
|
+
pass
|
|
563
|
+
domain_coverage = []
|
|
564
|
+
try:
|
|
565
|
+
rows = conn.execute(
|
|
566
|
+
"""SELECT s.domain_category as domain, COUNT(*) as total,
|
|
567
|
+
SUM(CASE WHEN m.coverage_score >= 0.80 THEN 1 ELSE 0 END) as L,
|
|
568
|
+
SUM(CASE WHEN m.coverage_score >= 0.40 AND m.coverage_score < 0.80 THEN 1 ELSE 0 END) as M,
|
|
569
|
+
SUM(CASE WHEN m.coverage_score < 0.40 OR m.coverage_score IS NULL THEN 1 ELSE 0 END) as N
|
|
570
|
+
FROM rfp_shall_statements s
|
|
571
|
+
LEFT JOIN icdev_capability_map m ON s.id = m.pattern_id
|
|
572
|
+
GROUP BY s.domain_category ORDER BY total DESC"""
|
|
573
|
+
).fetchall()
|
|
574
|
+
domain_coverage = [dict(r) for r in rows]
|
|
575
|
+
except Exception:
|
|
576
|
+
pass
|
|
577
|
+
gaps = []
|
|
578
|
+
total_gaps = 0
|
|
579
|
+
try:
|
|
580
|
+
rows = conn.execute(
|
|
581
|
+
"""SELECT p.pattern_name as requirement, p.domain_category as domain,
|
|
582
|
+
p.frequency, COALESCE(m.coverage_score, 0) as coverage,
|
|
583
|
+
p.frequency * (1 - COALESCE(m.coverage_score, 0)) as priority
|
|
584
|
+
FROM rfp_requirement_patterns p
|
|
585
|
+
LEFT JOIN icdev_capability_map m ON p.id = m.pattern_id
|
|
586
|
+
WHERE COALESCE(m.coverage_score, 0) < 0.40
|
|
587
|
+
ORDER BY priority DESC LIMIT 20"""
|
|
588
|
+
).fetchall()
|
|
589
|
+
gaps = [dict(r) for r in rows]
|
|
590
|
+
total_gaps = len(gaps)
|
|
591
|
+
except Exception:
|
|
592
|
+
pass
|
|
593
|
+
recommendations = []
|
|
594
|
+
try:
|
|
595
|
+
from icdev.tools.govcon.gap_analyzer import generate_recommendations
|
|
596
|
+
rec_result = generate_recommendations()
|
|
597
|
+
recommendations = rec_result.get("recommendations", [])[:15]
|
|
598
|
+
except Exception:
|
|
599
|
+
pass
|
|
600
|
+
return render_template("govcon/capabilities.html",
|
|
601
|
+
coverage=coverage, domain_coverage=domain_coverage,
|
|
602
|
+
gaps=gaps, total_gaps=total_gaps,
|
|
603
|
+
recommendations=recommendations)
|
|
604
|
+
finally:
|
|
605
|
+
conn.close()
|
|
606
|
+
|
|
607
|
+
|
|
608
|
+
# ---------------------------------------------------------------------------
|
|
609
|
+
# App factory
|
|
610
|
+
# ---------------------------------------------------------------------------
|
|
611
|
+
|
|
612
|
+
|
|
613
|
+
def create_app() -> Flask:
|
|
614
|
+
app = Flask(
|
|
615
|
+
__name__,
|
|
616
|
+
template_folder=str(Path(__file__).resolve().parent / "templates"),
|
|
617
|
+
static_folder=str(Path(__file__).resolve().parent / "static"),
|
|
618
|
+
)
|
|
619
|
+
|
|
620
|
+
# Register UX filters (glossary, timestamps, error recovery, quick paths)
|
|
621
|
+
register_ux_filters(app)
|
|
622
|
+
|
|
623
|
+
# Register dashboard auth middleware (D169-D172)
|
|
624
|
+
register_dashboard_auth(app)
|
|
625
|
+
|
|
626
|
+
# Initialize WebSocket (D170 — optional, graceful fallback)
|
|
627
|
+
init_socketio(app)
|
|
628
|
+
|
|
629
|
+
# Correlation ID middleware (D149)
|
|
630
|
+
try:
|
|
631
|
+
from icdev.tools.resilience.correlation import register_correlation_middleware
|
|
632
|
+
register_correlation_middleware(app)
|
|
633
|
+
except ImportError:
|
|
634
|
+
pass
|
|
635
|
+
|
|
636
|
+
# Role-based view configuration
|
|
637
|
+
ROLE_VIEWS = {
|
|
638
|
+
"pm": {
|
|
639
|
+
"label": "Program Manager",
|
|
640
|
+
"show_tabs": ["overview", "compliance", "deployments", "audit"],
|
|
641
|
+
"hide_columns": ["stig_id", "finding_id"],
|
|
642
|
+
},
|
|
643
|
+
"developer": {
|
|
644
|
+
"label": "Developer / Architect",
|
|
645
|
+
"show_tabs": ["overview", "security", "deployments", "audit"],
|
|
646
|
+
"hide_columns": [],
|
|
647
|
+
},
|
|
648
|
+
"isso": {
|
|
649
|
+
"label": "ISSO / Security Officer",
|
|
650
|
+
"show_tabs": ["overview", "compliance", "security", "audit"],
|
|
651
|
+
"hide_columns": [],
|
|
652
|
+
},
|
|
653
|
+
"co": {
|
|
654
|
+
"label": "Contracting Officer",
|
|
655
|
+
"show_tabs": ["overview", "compliance", "deployments"],
|
|
656
|
+
"hide_columns": ["stig_id", "finding_id", "source"],
|
|
657
|
+
},
|
|
658
|
+
"analyst": {
|
|
659
|
+
"label": "Analyst",
|
|
660
|
+
"show_tabs": ["overview", "compliance", "security", "audit"],
|
|
661
|
+
"hide_columns": [],
|
|
662
|
+
},
|
|
663
|
+
"solutions_architect": {
|
|
664
|
+
"label": "Solutions Architect",
|
|
665
|
+
"show_tabs": ["overview", "security", "deployments", "audit"],
|
|
666
|
+
"hide_columns": [],
|
|
667
|
+
},
|
|
668
|
+
"sales_engineer": {
|
|
669
|
+
"label": "Sales Engineer",
|
|
670
|
+
"show_tabs": ["overview", "compliance", "deployments"],
|
|
671
|
+
"hide_columns": ["stig_id", "finding_id"],
|
|
672
|
+
},
|
|
673
|
+
"innovator": {
|
|
674
|
+
"label": "Innovator",
|
|
675
|
+
"show_tabs": ["overview", "security", "deployments", "audit"],
|
|
676
|
+
"hide_columns": [],
|
|
677
|
+
},
|
|
678
|
+
"biz_dev": {
|
|
679
|
+
"label": "Business Development",
|
|
680
|
+
"show_tabs": ["overview", "compliance", "deployments"],
|
|
681
|
+
"hide_columns": ["stig_id", "finding_id", "source"],
|
|
682
|
+
},
|
|
683
|
+
"cor": {
|
|
684
|
+
"label": "Contracting Officer Representative",
|
|
685
|
+
"show_tabs": ["overview", "compliance"],
|
|
686
|
+
"hide_columns": ["stig_id", "finding_id", "source", "internal_cost_details"],
|
|
687
|
+
},
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
# Make CUI config, role, and user info available in all templates
|
|
691
|
+
@app.context_processor
|
|
692
|
+
def inject_cui():
|
|
693
|
+
role = flask_request.args.get("role", "")
|
|
694
|
+
role_config = ROLE_VIEWS.get(role, None)
|
|
695
|
+
current_user = getattr(g, "current_user", None)
|
|
696
|
+
return {
|
|
697
|
+
"cui_banner_top": CUI_BANNER_TOP,
|
|
698
|
+
"cui_banner_bottom": CUI_BANNER_BOTTOM,
|
|
699
|
+
"cui_banner_enabled": CUI_BANNER_ENABLED,
|
|
700
|
+
"cui_designation": CUI_DESIGNATION,
|
|
701
|
+
"current_role": role,
|
|
702
|
+
"role_config": role_config,
|
|
703
|
+
"ROLE_VIEWS": ROLE_VIEWS,
|
|
704
|
+
"current_user": current_user,
|
|
705
|
+
"byok_enabled": BYOK_ENABLED,
|
|
706
|
+
"govcon_enabled": _HAS_GOVCON,
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
# ---- Auto-register A2A agents from card files ----
|
|
710
|
+
try:
|
|
711
|
+
from icdev.tools.a2a.agent_registry import register_all_from_cards
|
|
712
|
+
registered = register_all_from_cards()
|
|
713
|
+
if registered:
|
|
714
|
+
app.logger.info("Auto-registered %d agents from card files", len(registered))
|
|
715
|
+
except Exception as exc:
|
|
716
|
+
app.logger.debug("Agent auto-registration skipped: %s", exc)
|
|
717
|
+
|
|
718
|
+
# ---- Register API blueprints ----
|
|
719
|
+
app.register_blueprint(projects_api)
|
|
720
|
+
app.register_blueprint(agents_api)
|
|
721
|
+
app.register_blueprint(compliance_api)
|
|
722
|
+
app.register_blueprint(audit_api)
|
|
723
|
+
app.register_blueprint(metrics_api)
|
|
724
|
+
app.register_blueprint(events_bp)
|
|
725
|
+
app.register_blueprint(nlq_bp)
|
|
726
|
+
app.register_blueprint(batch_api)
|
|
727
|
+
app.register_blueprint(diagrams_api)
|
|
728
|
+
app.register_blueprint(cicd_api)
|
|
729
|
+
app.register_blueprint(intake_api)
|
|
730
|
+
app.register_blueprint(admin_api)
|
|
731
|
+
app.register_blueprint(activity_api)
|
|
732
|
+
app.register_blueprint(usage_api)
|
|
733
|
+
app.register_blueprint(traces_api)
|
|
734
|
+
app.register_blueprint(provenance_api)
|
|
735
|
+
app.register_blueprint(xai_api)
|
|
736
|
+
app.register_blueprint(oscal_api)
|
|
737
|
+
app.register_blueprint(prod_audit_api)
|
|
738
|
+
app.register_blueprint(ai_transparency_api)
|
|
739
|
+
app.register_blueprint(ai_accountability_api)
|
|
740
|
+
app.register_blueprint(code_quality_api)
|
|
741
|
+
app.register_blueprint(fedramp_20x_api)
|
|
742
|
+
app.register_blueprint(evidence_api)
|
|
743
|
+
app.register_blueprint(lineage_api)
|
|
744
|
+
if _HAS_GOVCON:
|
|
745
|
+
app.register_blueprint(proposals_api)
|
|
746
|
+
app.register_blueprint(govcon_api)
|
|
747
|
+
app.register_blueprint(cpmp_api)
|
|
748
|
+
app.register_blueprint(orchestration_api)
|
|
749
|
+
if _HAS_CHAT_API:
|
|
750
|
+
app.register_blueprint(chat_api)
|
|
751
|
+
|
|
752
|
+
# ---- Convenience JSON routes that match the spec ----
|
|
753
|
+
|
|
754
|
+
@app.route("/api/alerts", methods=["GET"])
|
|
755
|
+
def api_alerts_shortcut():
|
|
756
|
+
"""Shortcut: GET /api/alerts -> delegates to metrics alerts."""
|
|
757
|
+
conn = _get_db()
|
|
758
|
+
try:
|
|
759
|
+
rows = conn.execute(
|
|
760
|
+
"SELECT * FROM alerts ORDER BY created_at DESC LIMIT 50"
|
|
761
|
+
).fetchall()
|
|
762
|
+
return jsonify({"alerts": [dict(r) for r in rows], "total": len(rows)})
|
|
763
|
+
finally:
|
|
764
|
+
conn.close()
|
|
765
|
+
|
|
766
|
+
@app.route("/api/notifications", methods=["GET"])
|
|
767
|
+
def api_notifications():
|
|
768
|
+
"""Return current notification-worthy items (firing alerts, overdue POAMs)."""
|
|
769
|
+
conn = _get_db()
|
|
770
|
+
try:
|
|
771
|
+
notifications = []
|
|
772
|
+
firing = conn.execute(
|
|
773
|
+
"SELECT COUNT(*) as cnt FROM alerts WHERE status = 'firing'"
|
|
774
|
+
).fetchone()["cnt"]
|
|
775
|
+
if firing > 0:
|
|
776
|
+
notifications.append({
|
|
777
|
+
"type": "error",
|
|
778
|
+
"message": f"{firing} alert{'s' if firing > 1 else ''} currently firing",
|
|
779
|
+
"link": "/monitoring",
|
|
780
|
+
})
|
|
781
|
+
open_poam = conn.execute(
|
|
782
|
+
"SELECT COUNT(*) as cnt FROM poam_items WHERE status = 'open'"
|
|
783
|
+
).fetchone()["cnt"]
|
|
784
|
+
if open_poam > 5:
|
|
785
|
+
notifications.append({
|
|
786
|
+
"type": "warning",
|
|
787
|
+
"message": f"{open_poam} open POA&M items need attention",
|
|
788
|
+
"link": "/projects",
|
|
789
|
+
})
|
|
790
|
+
inactive = conn.execute(
|
|
791
|
+
"SELECT COUNT(*) as cnt FROM agents WHERE status != 'active'"
|
|
792
|
+
).fetchone()["cnt"]
|
|
793
|
+
if inactive > 0:
|
|
794
|
+
notifications.append({
|
|
795
|
+
"type": "info",
|
|
796
|
+
"message": f"{inactive} agent{'s' if inactive > 1 else ''} inactive",
|
|
797
|
+
"link": "/agents",
|
|
798
|
+
})
|
|
799
|
+
return jsonify({"notifications": notifications})
|
|
800
|
+
finally:
|
|
801
|
+
conn.close()
|
|
802
|
+
|
|
803
|
+
@app.route("/api/charts/overview", methods=["GET"])
|
|
804
|
+
def api_charts_overview():
|
|
805
|
+
"""Aggregate chart data for the home dashboard."""
|
|
806
|
+
conn = _get_db()
|
|
807
|
+
try:
|
|
808
|
+
# Project status distribution (donut chart)
|
|
809
|
+
project_statuses = conn.execute(
|
|
810
|
+
"SELECT status, COUNT(*) as cnt FROM projects GROUP BY status"
|
|
811
|
+
).fetchall()
|
|
812
|
+
|
|
813
|
+
# Alert trend: last 7 days (line chart)
|
|
814
|
+
alert_trend = conn.execute(
|
|
815
|
+
"SELECT DATE(created_at) as day, COUNT(*) as cnt "
|
|
816
|
+
"FROM alerts WHERE created_at >= DATE('now', '-7 days') "
|
|
817
|
+
"GROUP BY DATE(created_at) ORDER BY day"
|
|
818
|
+
).fetchall()
|
|
819
|
+
|
|
820
|
+
# Compliance posture: open vs closed across POAM + STIG (bar chart)
|
|
821
|
+
poam_open = conn.execute(
|
|
822
|
+
"SELECT COUNT(*) as cnt FROM poam_items WHERE status = 'open'"
|
|
823
|
+
).fetchone()["cnt"]
|
|
824
|
+
poam_closed = conn.execute(
|
|
825
|
+
"SELECT COUNT(*) as cnt FROM poam_items WHERE status != 'open'"
|
|
826
|
+
).fetchone()["cnt"]
|
|
827
|
+
stig_open = conn.execute(
|
|
828
|
+
"SELECT COUNT(*) as cnt FROM stig_findings WHERE status = 'Open'"
|
|
829
|
+
).fetchone()["cnt"]
|
|
830
|
+
stig_closed = conn.execute(
|
|
831
|
+
"SELECT COUNT(*) as cnt FROM stig_findings WHERE status != 'Open'"
|
|
832
|
+
).fetchone()["cnt"]
|
|
833
|
+
|
|
834
|
+
# Deployment frequency: last 7 days (sparkline)
|
|
835
|
+
deploy_trend = conn.execute(
|
|
836
|
+
"SELECT DATE(created_at) as day, COUNT(*) as cnt "
|
|
837
|
+
"FROM deployments WHERE created_at >= DATE('now', '-7 days') "
|
|
838
|
+
"GROUP BY DATE(created_at) ORDER BY day"
|
|
839
|
+
).fetchall()
|
|
840
|
+
|
|
841
|
+
# Agent health (gauge: % active)
|
|
842
|
+
total_agents = conn.execute(
|
|
843
|
+
"SELECT COUNT(*) as cnt FROM agents"
|
|
844
|
+
).fetchone()["cnt"]
|
|
845
|
+
active_agents = conn.execute(
|
|
846
|
+
"SELECT COUNT(*) as cnt FROM agents WHERE status = 'active'"
|
|
847
|
+
).fetchone()["cnt"]
|
|
848
|
+
|
|
849
|
+
return jsonify({
|
|
850
|
+
"project_statuses": [dict(r) for r in project_statuses],
|
|
851
|
+
"alert_trend": [dict(r) for r in alert_trend],
|
|
852
|
+
"compliance": {
|
|
853
|
+
"poam": {"open": poam_open, "closed": poam_closed},
|
|
854
|
+
"stig": {"open": stig_open, "closed": stig_closed},
|
|
855
|
+
},
|
|
856
|
+
"deploy_trend": [dict(r) for r in deploy_trend],
|
|
857
|
+
"agent_health": {
|
|
858
|
+
"total": total_agents,
|
|
859
|
+
"active": active_agents,
|
|
860
|
+
"ratio": active_agents / total_agents if total_agents > 0 else 1.0,
|
|
861
|
+
},
|
|
862
|
+
})
|
|
863
|
+
finally:
|
|
864
|
+
conn.close()
|
|
865
|
+
|
|
866
|
+
@app.route("/api/charts/project/<project_id>", methods=["GET"])
|
|
867
|
+
def api_charts_project(project_id):
|
|
868
|
+
"""Chart data for a specific project detail page."""
|
|
869
|
+
conn = _get_db()
|
|
870
|
+
try:
|
|
871
|
+
# STIG by severity (donut)
|
|
872
|
+
stig_sev = conn.execute(
|
|
873
|
+
"SELECT severity, status, COUNT(*) as cnt "
|
|
874
|
+
"FROM stig_findings WHERE project_id = ? "
|
|
875
|
+
"GROUP BY severity, status",
|
|
876
|
+
(project_id,),
|
|
877
|
+
).fetchall()
|
|
878
|
+
|
|
879
|
+
# POAM by severity (bar)
|
|
880
|
+
poam_sev = conn.execute(
|
|
881
|
+
"SELECT severity, status, COUNT(*) as cnt "
|
|
882
|
+
"FROM poam_items WHERE project_id = ? "
|
|
883
|
+
"GROUP BY severity, status",
|
|
884
|
+
(project_id,),
|
|
885
|
+
).fetchall()
|
|
886
|
+
|
|
887
|
+
# Deployment history (line — status over time)
|
|
888
|
+
deploys = conn.execute(
|
|
889
|
+
"SELECT DATE(created_at) as day, status, COUNT(*) as cnt "
|
|
890
|
+
"FROM deployments WHERE project_id = ? "
|
|
891
|
+
"GROUP BY DATE(created_at), status ORDER BY day",
|
|
892
|
+
(project_id,),
|
|
893
|
+
).fetchall()
|
|
894
|
+
|
|
895
|
+
# Alert trend for project
|
|
896
|
+
alerts = conn.execute(
|
|
897
|
+
"SELECT DATE(created_at) as day, severity, COUNT(*) as cnt "
|
|
898
|
+
"FROM alerts WHERE project_id = ? "
|
|
899
|
+
"GROUP BY DATE(created_at), severity ORDER BY day",
|
|
900
|
+
(project_id,),
|
|
901
|
+
).fetchall()
|
|
902
|
+
|
|
903
|
+
return jsonify({
|
|
904
|
+
"stig_by_severity": [dict(r) for r in stig_sev],
|
|
905
|
+
"poam_by_severity": [dict(r) for r in poam_sev],
|
|
906
|
+
"deployment_history": [dict(r) for r in deploys],
|
|
907
|
+
"alert_trend": [dict(r) for r in alerts],
|
|
908
|
+
})
|
|
909
|
+
finally:
|
|
910
|
+
conn.close()
|
|
911
|
+
|
|
912
|
+
# ---- HTML page routes ----
|
|
913
|
+
|
|
914
|
+
@app.route("/")
|
|
915
|
+
def index():
|
|
916
|
+
"""Dashboard home page with Kanban board."""
|
|
917
|
+
conn = _get_db()
|
|
918
|
+
try:
|
|
919
|
+
# All projects for Kanban board
|
|
920
|
+
projects = conn.execute(
|
|
921
|
+
"SELECT id, name, type, status, classification "
|
|
922
|
+
"FROM projects ORDER BY updated_at DESC, created_at DESC"
|
|
923
|
+
).fetchall()
|
|
924
|
+
projects = [dict(r) for r in projects]
|
|
925
|
+
|
|
926
|
+
# Agent counts (stat bar)
|
|
927
|
+
total_agents = conn.execute("SELECT COUNT(*) as cnt FROM agents").fetchone()["cnt"]
|
|
928
|
+
active_agents = conn.execute(
|
|
929
|
+
"SELECT COUNT(*) as cnt FROM agents WHERE status = 'active'"
|
|
930
|
+
).fetchone()["cnt"]
|
|
931
|
+
inactive_agents = total_agents - active_agents
|
|
932
|
+
|
|
933
|
+
# Recent audit entries
|
|
934
|
+
recent_audit = conn.execute(
|
|
935
|
+
"SELECT * FROM audit_trail ORDER BY created_at DESC LIMIT 10"
|
|
936
|
+
).fetchall()
|
|
937
|
+
|
|
938
|
+
# Recent alerts
|
|
939
|
+
recent_alerts = conn.execute(
|
|
940
|
+
"SELECT * FROM alerts ORDER BY created_at DESC LIMIT 10"
|
|
941
|
+
).fetchall()
|
|
942
|
+
|
|
943
|
+
# Firing alert count (stat bar)
|
|
944
|
+
firing_alerts = conn.execute(
|
|
945
|
+
"SELECT COUNT(*) as cnt FROM alerts WHERE status = 'firing'"
|
|
946
|
+
).fetchone()["cnt"]
|
|
947
|
+
|
|
948
|
+
# Open POAM count (stat bar)
|
|
949
|
+
open_poam = conn.execute(
|
|
950
|
+
"SELECT COUNT(*) as cnt FROM poam_items WHERE status = 'open'"
|
|
951
|
+
).fetchone()["cnt"]
|
|
952
|
+
|
|
953
|
+
# Group projects by status for Kanban columns
|
|
954
|
+
kanban_columns = {
|
|
955
|
+
"planning": [],
|
|
956
|
+
"active": [],
|
|
957
|
+
"completed": [],
|
|
958
|
+
"inactive": [],
|
|
959
|
+
}
|
|
960
|
+
for p in projects:
|
|
961
|
+
status = p.get("status", "inactive")
|
|
962
|
+
if status in kanban_columns:
|
|
963
|
+
kanban_columns[status].append(p)
|
|
964
|
+
else:
|
|
965
|
+
kanban_columns["inactive"].append(p)
|
|
966
|
+
|
|
967
|
+
return render_template(
|
|
968
|
+
"index.html",
|
|
969
|
+
projects=projects,
|
|
970
|
+
kanban_columns=kanban_columns,
|
|
971
|
+
total_projects=len(projects),
|
|
972
|
+
total_agents=total_agents,
|
|
973
|
+
active_agents=active_agents,
|
|
974
|
+
inactive_agents=inactive_agents,
|
|
975
|
+
recent_audit=[dict(r) for r in recent_audit],
|
|
976
|
+
recent_alerts=[dict(r) for r in recent_alerts],
|
|
977
|
+
firing_alerts=firing_alerts,
|
|
978
|
+
open_poam=open_poam,
|
|
979
|
+
)
|
|
980
|
+
finally:
|
|
981
|
+
conn.close()
|
|
982
|
+
|
|
983
|
+
@app.route("/projects")
|
|
984
|
+
def projects_list():
|
|
985
|
+
"""Project listing page."""
|
|
986
|
+
conn = _get_db()
|
|
987
|
+
try:
|
|
988
|
+
projects = conn.execute(
|
|
989
|
+
"SELECT id, name, type, status, classification, created_at "
|
|
990
|
+
"FROM projects ORDER BY created_at DESC"
|
|
991
|
+
).fetchall()
|
|
992
|
+
return render_template("projects/list.html", projects=[dict(r) for r in projects])
|
|
993
|
+
finally:
|
|
994
|
+
conn.close()
|
|
995
|
+
|
|
996
|
+
@app.route("/projects/<project_id>")
|
|
997
|
+
def project_detail(project_id):
|
|
998
|
+
"""Project detail page with tabs."""
|
|
999
|
+
conn = _get_db()
|
|
1000
|
+
try:
|
|
1001
|
+
# Project info
|
|
1002
|
+
project = conn.execute("SELECT * FROM projects WHERE id = ?", (project_id,)).fetchone()
|
|
1003
|
+
if not project:
|
|
1004
|
+
return render_template("404.html", message="Project not found"), 404
|
|
1005
|
+
project = dict(project)
|
|
1006
|
+
|
|
1007
|
+
# SSP documents
|
|
1008
|
+
ssps = conn.execute(
|
|
1009
|
+
"SELECT * FROM ssp_documents WHERE project_id = ? ORDER BY created_at DESC",
|
|
1010
|
+
(project_id,),
|
|
1011
|
+
).fetchall()
|
|
1012
|
+
|
|
1013
|
+
# POAM items
|
|
1014
|
+
poams = conn.execute(
|
|
1015
|
+
"SELECT * FROM poam_items WHERE project_id = ? ORDER BY severity, created_at DESC",
|
|
1016
|
+
(project_id,),
|
|
1017
|
+
).fetchall()
|
|
1018
|
+
|
|
1019
|
+
# STIG findings
|
|
1020
|
+
stigs = conn.execute(
|
|
1021
|
+
"SELECT * FROM stig_findings WHERE project_id = ? ORDER BY severity, created_at DESC",
|
|
1022
|
+
(project_id,),
|
|
1023
|
+
).fetchall()
|
|
1024
|
+
|
|
1025
|
+
# SBOM records
|
|
1026
|
+
sboms = conn.execute(
|
|
1027
|
+
"SELECT * FROM sbom_records WHERE project_id = ? ORDER BY generated_at DESC",
|
|
1028
|
+
(project_id,),
|
|
1029
|
+
).fetchall()
|
|
1030
|
+
|
|
1031
|
+
# Deployments
|
|
1032
|
+
deployments = conn.execute(
|
|
1033
|
+
"SELECT * FROM deployments WHERE project_id = ? ORDER BY created_at DESC",
|
|
1034
|
+
(project_id,),
|
|
1035
|
+
).fetchall()
|
|
1036
|
+
|
|
1037
|
+
# Audit trail
|
|
1038
|
+
audit_entries = conn.execute(
|
|
1039
|
+
"SELECT * FROM audit_trail WHERE project_id = ? ORDER BY created_at DESC LIMIT 50",
|
|
1040
|
+
(project_id,),
|
|
1041
|
+
).fetchall()
|
|
1042
|
+
|
|
1043
|
+
# Alerts
|
|
1044
|
+
alerts = conn.execute(
|
|
1045
|
+
"SELECT * FROM alerts WHERE project_id = ? ORDER BY created_at DESC LIMIT 20",
|
|
1046
|
+
(project_id,),
|
|
1047
|
+
).fetchall()
|
|
1048
|
+
|
|
1049
|
+
# Summaries
|
|
1050
|
+
poam_open = sum(1 for p in poams if dict(p)["status"] == "open")
|
|
1051
|
+
stig_open = sum(1 for s in stigs if dict(s)["status"] == "Open")
|
|
1052
|
+
|
|
1053
|
+
stig_by_severity = {}
|
|
1054
|
+
for s in stigs:
|
|
1055
|
+
sd = dict(s)
|
|
1056
|
+
sev = sd.get("severity", "unknown")
|
|
1057
|
+
if sev not in stig_by_severity:
|
|
1058
|
+
stig_by_severity[sev] = {"open": 0, "closed": 0}
|
|
1059
|
+
if sd["status"] == "Open":
|
|
1060
|
+
stig_by_severity[sev]["open"] += 1
|
|
1061
|
+
else:
|
|
1062
|
+
stig_by_severity[sev]["closed"] += 1
|
|
1063
|
+
|
|
1064
|
+
return render_template(
|
|
1065
|
+
"projects/detail.html",
|
|
1066
|
+
project=project,
|
|
1067
|
+
ssps=[dict(r) for r in ssps],
|
|
1068
|
+
poams=[dict(r) for r in poams],
|
|
1069
|
+
poam_open=poam_open,
|
|
1070
|
+
stigs=[dict(r) for r in stigs],
|
|
1071
|
+
stig_open=stig_open,
|
|
1072
|
+
stig_by_severity=stig_by_severity,
|
|
1073
|
+
sboms=[dict(r) for r in sboms],
|
|
1074
|
+
deployments=[dict(r) for r in deployments],
|
|
1075
|
+
audit_entries=[dict(r) for r in audit_entries],
|
|
1076
|
+
alerts=[dict(r) for r in alerts],
|
|
1077
|
+
)
|
|
1078
|
+
finally:
|
|
1079
|
+
conn.close()
|
|
1080
|
+
|
|
1081
|
+
@app.route("/agents")
|
|
1082
|
+
def agents_list():
|
|
1083
|
+
"""Agent status page."""
|
|
1084
|
+
conn = _get_db()
|
|
1085
|
+
try:
|
|
1086
|
+
rows = conn.execute(
|
|
1087
|
+
"SELECT * FROM agents ORDER BY name"
|
|
1088
|
+
).fetchall()
|
|
1089
|
+
agents = []
|
|
1090
|
+
for r in rows:
|
|
1091
|
+
agent = dict(r)
|
|
1092
|
+
tc = conn.execute(
|
|
1093
|
+
"SELECT COUNT(*) as cnt FROM a2a_tasks "
|
|
1094
|
+
"WHERE target_agent_id = ? AND status IN ('submitted', 'working')",
|
|
1095
|
+
(agent["id"],),
|
|
1096
|
+
).fetchone()
|
|
1097
|
+
agent["active_task_count"] = tc["cnt"] if tc else 0
|
|
1098
|
+
agents.append(agent)
|
|
1099
|
+
|
|
1100
|
+
active = sum(1 for a in agents if a["status"] == "active")
|
|
1101
|
+
inactive = len(agents) - active
|
|
1102
|
+
|
|
1103
|
+
return render_template(
|
|
1104
|
+
"agents/list.html",
|
|
1105
|
+
agents=agents,
|
|
1106
|
+
active_count=active,
|
|
1107
|
+
inactive_count=inactive,
|
|
1108
|
+
)
|
|
1109
|
+
finally:
|
|
1110
|
+
conn.close()
|
|
1111
|
+
|
|
1112
|
+
@app.route("/monitoring")
|
|
1113
|
+
def monitoring_overview():
|
|
1114
|
+
"""Monitoring overview page."""
|
|
1115
|
+
conn = _get_db()
|
|
1116
|
+
try:
|
|
1117
|
+
# Recent alerts
|
|
1118
|
+
alerts = conn.execute(
|
|
1119
|
+
"SELECT * FROM alerts ORDER BY created_at DESC LIMIT 20"
|
|
1120
|
+
).fetchall()
|
|
1121
|
+
|
|
1122
|
+
# Self-healing events
|
|
1123
|
+
healing_events = conn.execute(
|
|
1124
|
+
"SELECT she.*, kp.description as pattern_description "
|
|
1125
|
+
"FROM self_healing_events she "
|
|
1126
|
+
"LEFT JOIN knowledge_patterns kp ON she.pattern_id = kp.id "
|
|
1127
|
+
"ORDER BY she.created_at DESC LIMIT 20"
|
|
1128
|
+
).fetchall()
|
|
1129
|
+
|
|
1130
|
+
# Health stats
|
|
1131
|
+
firing = conn.execute(
|
|
1132
|
+
"SELECT COUNT(*) as cnt FROM alerts WHERE status = 'firing'"
|
|
1133
|
+
).fetchone()["cnt"]
|
|
1134
|
+
resolved = conn.execute(
|
|
1135
|
+
"SELECT COUNT(*) as cnt FROM alerts WHERE status = 'resolved'"
|
|
1136
|
+
).fetchone()["cnt"]
|
|
1137
|
+
unresolved_failures = conn.execute(
|
|
1138
|
+
"SELECT COUNT(*) as cnt FROM failure_log WHERE resolved = 0"
|
|
1139
|
+
).fetchone()["cnt"]
|
|
1140
|
+
|
|
1141
|
+
health = "healthy"
|
|
1142
|
+
if firing > 0 or unresolved_failures > 5:
|
|
1143
|
+
health = "degraded"
|
|
1144
|
+
if firing > 5:
|
|
1145
|
+
health = "critical"
|
|
1146
|
+
|
|
1147
|
+
return render_template(
|
|
1148
|
+
"monitoring/overview.html",
|
|
1149
|
+
alerts=[dict(r) for r in alerts],
|
|
1150
|
+
healing_events=[dict(r) for r in healing_events],
|
|
1151
|
+
firing_count=firing,
|
|
1152
|
+
resolved_count=resolved,
|
|
1153
|
+
unresolved_failures=unresolved_failures,
|
|
1154
|
+
health_status=health,
|
|
1155
|
+
)
|
|
1156
|
+
finally:
|
|
1157
|
+
conn.close()
|
|
1158
|
+
|
|
1159
|
+
# ---- Events & NLQ page routes ----
|
|
1160
|
+
|
|
1161
|
+
@app.route("/events")
|
|
1162
|
+
def events_page():
|
|
1163
|
+
"""Real-time event timeline page (SSE-powered)."""
|
|
1164
|
+
conn = _get_db()
|
|
1165
|
+
try:
|
|
1166
|
+
recent_events = conn.execute(
|
|
1167
|
+
"SELECT * FROM hook_events ORDER BY created_at DESC LIMIT 50"
|
|
1168
|
+
).fetchall()
|
|
1169
|
+
return render_template(
|
|
1170
|
+
"events/timeline.html",
|
|
1171
|
+
recent_events=[dict(r) for r in recent_events],
|
|
1172
|
+
)
|
|
1173
|
+
except Exception:
|
|
1174
|
+
return render_template("events/timeline.html", recent_events=[])
|
|
1175
|
+
finally:
|
|
1176
|
+
conn.close()
|
|
1177
|
+
|
|
1178
|
+
@app.route("/activity")
|
|
1179
|
+
def activity_page():
|
|
1180
|
+
"""Activity feed — merged audit + hook events with real-time updates."""
|
|
1181
|
+
return render_template("activity.html")
|
|
1182
|
+
|
|
1183
|
+
@app.route("/usage")
|
|
1184
|
+
def usage_page():
|
|
1185
|
+
"""Usage tracking + cost dashboard."""
|
|
1186
|
+
return render_template("usage.html")
|
|
1187
|
+
|
|
1188
|
+
@app.route("/wizard")
|
|
1189
|
+
def wizard_page():
|
|
1190
|
+
"""Getting Started wizard — guides new users to the right workflow."""
|
|
1191
|
+
return render_template("wizard.html")
|
|
1192
|
+
|
|
1193
|
+
@app.route("/chat")
|
|
1194
|
+
def chat_new():
|
|
1195
|
+
"""Start a new requirements chat — wizard params set context."""
|
|
1196
|
+
goal = flask_request.args.get("goal", "build")
|
|
1197
|
+
role = flask_request.args.get("role", "developer")
|
|
1198
|
+
classification = flask_request.args.get("classification", "il4")
|
|
1199
|
+
frameworks = flask_request.args.get("frameworks", "")
|
|
1200
|
+
custom_role_name = flask_request.args.get("custom_role_name", "")
|
|
1201
|
+
custom_role_desc = flask_request.args.get("custom_role_desc", "")
|
|
1202
|
+
return render_template(
|
|
1203
|
+
"chat.html",
|
|
1204
|
+
session_id=None,
|
|
1205
|
+
messages=[],
|
|
1206
|
+
wizard_goal=goal,
|
|
1207
|
+
wizard_role=role,
|
|
1208
|
+
wizard_classification=classification,
|
|
1209
|
+
wizard_frameworks=frameworks,
|
|
1210
|
+
wizard_custom_role_name=custom_role_name,
|
|
1211
|
+
wizard_custom_role_desc=custom_role_desc,
|
|
1212
|
+
)
|
|
1213
|
+
|
|
1214
|
+
@app.route("/chat/<session_id>")
|
|
1215
|
+
def chat_session(session_id):
|
|
1216
|
+
"""Resume an existing requirements chat session."""
|
|
1217
|
+
conn = _get_db()
|
|
1218
|
+
try:
|
|
1219
|
+
try:
|
|
1220
|
+
session = conn.execute(
|
|
1221
|
+
"SELECT * FROM intake_sessions WHERE id = ?", (session_id,)
|
|
1222
|
+
).fetchone()
|
|
1223
|
+
except sqlite3.OperationalError:
|
|
1224
|
+
session = None
|
|
1225
|
+
if not session:
|
|
1226
|
+
return render_template("404.html", message="Session not found"), 404
|
|
1227
|
+
messages = conn.execute(
|
|
1228
|
+
"SELECT turn_number, role, content, content_type, created_at "
|
|
1229
|
+
"FROM intake_conversation WHERE session_id = ? ORDER BY turn_number",
|
|
1230
|
+
(session_id,),
|
|
1231
|
+
).fetchall()
|
|
1232
|
+
# Extract context for sidebar display
|
|
1233
|
+
import json as _json
|
|
1234
|
+
session_dict = dict(session)
|
|
1235
|
+
ctx = {}
|
|
1236
|
+
try:
|
|
1237
|
+
ctx = _json.loads(session_dict.get("context_summary") or "{}")
|
|
1238
|
+
except (ValueError, TypeError):
|
|
1239
|
+
pass
|
|
1240
|
+
return render_template(
|
|
1241
|
+
"chat.html",
|
|
1242
|
+
session_id=session_id,
|
|
1243
|
+
session=session_dict,
|
|
1244
|
+
messages=[dict(m) for m in messages],
|
|
1245
|
+
wizard_goal=None,
|
|
1246
|
+
wizard_role=None,
|
|
1247
|
+
wizard_classification=None,
|
|
1248
|
+
wizard_frameworks=",".join(ctx.get("selected_frameworks", [])),
|
|
1249
|
+
wizard_custom_role_name="",
|
|
1250
|
+
wizard_custom_role_desc="",
|
|
1251
|
+
session_context=ctx,
|
|
1252
|
+
)
|
|
1253
|
+
finally:
|
|
1254
|
+
conn.close()
|
|
1255
|
+
|
|
1256
|
+
@app.route("/quick-paths")
|
|
1257
|
+
def quick_paths_page():
|
|
1258
|
+
"""Quick Path workflow templates — pre-built shortcuts for common tasks."""
|
|
1259
|
+
return render_template("quick_paths.html")
|
|
1260
|
+
|
|
1261
|
+
@app.route("/batch")
|
|
1262
|
+
def batch_page():
|
|
1263
|
+
"""Batch operations — run multi-tool workflows from the dashboard."""
|
|
1264
|
+
return render_template("batch.html")
|
|
1265
|
+
|
|
1266
|
+
@app.route("/diagrams")
|
|
1267
|
+
def diagrams_page():
|
|
1268
|
+
"""Interactive Mermaid diagrams — catalog, viewer, and editor."""
|
|
1269
|
+
return render_template("diagrams.html")
|
|
1270
|
+
|
|
1271
|
+
@app.route("/cicd")
|
|
1272
|
+
def cicd_page():
|
|
1273
|
+
"""CI/CD pipeline status, conversations, and connector health."""
|
|
1274
|
+
return render_template("cicd.html")
|
|
1275
|
+
|
|
1276
|
+
@app.route("/gateway")
|
|
1277
|
+
def gateway_page():
|
|
1278
|
+
"""Remote Command Gateway admin — bindings, command log, channel status."""
|
|
1279
|
+
import yaml as _yaml
|
|
1280
|
+
|
|
1281
|
+
# Load gateway config
|
|
1282
|
+
gateway_config_path = BASE_DIR / "args" / "remote_gateway_config.yaml"
|
|
1283
|
+
gw_config = {}
|
|
1284
|
+
if gateway_config_path.exists():
|
|
1285
|
+
with open(gateway_config_path) as f:
|
|
1286
|
+
gw_config = _yaml.safe_load(f) or {}
|
|
1287
|
+
|
|
1288
|
+
env_mode = gw_config.get("environment", {}).get("mode", "connected")
|
|
1289
|
+
channels = gw_config.get("channels", {})
|
|
1290
|
+
|
|
1291
|
+
# Determine active channels
|
|
1292
|
+
active_channels = []
|
|
1293
|
+
for name, ch in channels.items():
|
|
1294
|
+
enabled = ch.get("enabled", False)
|
|
1295
|
+
req_internet = ch.get("requires_internet", False)
|
|
1296
|
+
available = enabled and not (env_mode == "air_gapped" and req_internet)
|
|
1297
|
+
active_channels.append({
|
|
1298
|
+
"name": name,
|
|
1299
|
+
"enabled": enabled,
|
|
1300
|
+
"available": available,
|
|
1301
|
+
"max_il": ch.get("max_il", "IL4"),
|
|
1302
|
+
"description": ch.get("description", ""),
|
|
1303
|
+
})
|
|
1304
|
+
|
|
1305
|
+
# Load bindings and recent commands
|
|
1306
|
+
conn = _get_db()
|
|
1307
|
+
try:
|
|
1308
|
+
bindings = conn.execute(
|
|
1309
|
+
"SELECT * FROM remote_user_bindings ORDER BY created_at DESC LIMIT 50"
|
|
1310
|
+
).fetchall()
|
|
1311
|
+
bindings = [dict(r) for r in bindings]
|
|
1312
|
+
except Exception:
|
|
1313
|
+
bindings = []
|
|
1314
|
+
|
|
1315
|
+
try:
|
|
1316
|
+
commands = conn.execute(
|
|
1317
|
+
"SELECT * FROM remote_command_log ORDER BY created_at DESC LIMIT 50"
|
|
1318
|
+
).fetchall()
|
|
1319
|
+
commands = [dict(r) for r in commands]
|
|
1320
|
+
except Exception:
|
|
1321
|
+
commands = []
|
|
1322
|
+
|
|
1323
|
+
conn.close()
|
|
1324
|
+
|
|
1325
|
+
return render_template(
|
|
1326
|
+
"gateway.html",
|
|
1327
|
+
environment_mode=env_mode,
|
|
1328
|
+
channels=active_channels,
|
|
1329
|
+
bindings=bindings,
|
|
1330
|
+
commands=commands,
|
|
1331
|
+
command_allowlist=gw_config.get("command_allowlist", []),
|
|
1332
|
+
)
|
|
1333
|
+
|
|
1334
|
+
@app.route("/query")
|
|
1335
|
+
def query_page():
|
|
1336
|
+
"""Natural language compliance query page."""
|
|
1337
|
+
conn = _get_db()
|
|
1338
|
+
try:
|
|
1339
|
+
recent_queries = conn.execute(
|
|
1340
|
+
"SELECT * FROM nlq_queries ORDER BY created_at DESC LIMIT 20"
|
|
1341
|
+
).fetchall()
|
|
1342
|
+
return render_template(
|
|
1343
|
+
"query/nlq.html",
|
|
1344
|
+
recent_queries=[dict(r) for r in recent_queries],
|
|
1345
|
+
)
|
|
1346
|
+
except Exception:
|
|
1347
|
+
return render_template("query/nlq.html", recent_queries=[])
|
|
1348
|
+
finally:
|
|
1349
|
+
conn.close()
|
|
1350
|
+
|
|
1351
|
+
# ---- Tour configuration ----
|
|
1352
|
+
|
|
1353
|
+
@app.route("/api/tour/steps", methods=["GET"])
|
|
1354
|
+
def api_tour_steps():
|
|
1355
|
+
"""Return tour step definitions for the onboarding walkthrough.
|
|
1356
|
+
|
|
1357
|
+
Steps are served from config so admins can customize content
|
|
1358
|
+
without modifying JavaScript source. tour.js fetches this
|
|
1359
|
+
endpoint on init and falls back to built-in defaults if
|
|
1360
|
+
the fetch fails (air-gap safe).
|
|
1361
|
+
"""
|
|
1362
|
+
steps = [
|
|
1363
|
+
{
|
|
1364
|
+
"selector": ".navbar",
|
|
1365
|
+
"title": "Navigation Bar",
|
|
1366
|
+
"desc": (
|
|
1367
|
+
"Navigate between pages: Home, Projects, Agents, "
|
|
1368
|
+
"Monitoring, Quick Paths, Batch Operations, and "
|
|
1369
|
+
"the Getting Started wizard."
|
|
1370
|
+
),
|
|
1371
|
+
},
|
|
1372
|
+
{
|
|
1373
|
+
"selector": ".kanban-board",
|
|
1374
|
+
"title": "Project Kanban Board",
|
|
1375
|
+
"desc": (
|
|
1376
|
+
"Projects organized by workflow stage: Planning, Active, "
|
|
1377
|
+
"Completed, and Inactive. Click any card to view details."
|
|
1378
|
+
),
|
|
1379
|
+
},
|
|
1380
|
+
{
|
|
1381
|
+
"selector": ".chart-grid",
|
|
1382
|
+
"title": "Visual Dashboards",
|
|
1383
|
+
"desc": (
|
|
1384
|
+
"Visual dashboards: compliance posture, alert trends, "
|
|
1385
|
+
"project status, and agent health charts."
|
|
1386
|
+
),
|
|
1387
|
+
},
|
|
1388
|
+
{
|
|
1389
|
+
"selector": ".table-container",
|
|
1390
|
+
"title": "Data Tables",
|
|
1391
|
+
"desc": (
|
|
1392
|
+
"Detailed data tables with search, sort, filter, "
|
|
1393
|
+
"and CSV export capabilities."
|
|
1394
|
+
),
|
|
1395
|
+
},
|
|
1396
|
+
{
|
|
1397
|
+
"selector": "#role-select",
|
|
1398
|
+
"title": "Role Selector",
|
|
1399
|
+
"desc": (
|
|
1400
|
+
"Switch views: Program Manager, Developer, ISSO, or "
|
|
1401
|
+
"Contracting Officer to see role-relevant information."
|
|
1402
|
+
),
|
|
1403
|
+
},
|
|
1404
|
+
{
|
|
1405
|
+
"selector": "a[href*='quick-paths'], a[href*='/quick-paths']",
|
|
1406
|
+
"title": "Quick Paths",
|
|
1407
|
+
"desc": (
|
|
1408
|
+
"Pre-built workflow shortcuts for common tasks like "
|
|
1409
|
+
"ATO generation, project creation, and security scanning."
|
|
1410
|
+
),
|
|
1411
|
+
},
|
|
1412
|
+
{
|
|
1413
|
+
"selector": "a[href*='/batch']",
|
|
1414
|
+
"title": "Batch Operations",
|
|
1415
|
+
"desc": (
|
|
1416
|
+
"Run multi-step batch operations: Full ATO Package, "
|
|
1417
|
+
"Security Scan Suite, Multi-Framework Check, or "
|
|
1418
|
+
"Build & Validate from a single click."
|
|
1419
|
+
),
|
|
1420
|
+
},
|
|
1421
|
+
{
|
|
1422
|
+
"selector": "a[href*='/events']",
|
|
1423
|
+
"title": "Live Events",
|
|
1424
|
+
"desc": (
|
|
1425
|
+
"Real-time event timeline showing hook events, "
|
|
1426
|
+
"agent activity, and system notifications with "
|
|
1427
|
+
"severity filtering."
|
|
1428
|
+
),
|
|
1429
|
+
},
|
|
1430
|
+
]
|
|
1431
|
+
return jsonify({
|
|
1432
|
+
"steps": steps,
|
|
1433
|
+
"version": 2,
|
|
1434
|
+
"classification": "CUI",
|
|
1435
|
+
})
|
|
1436
|
+
|
|
1437
|
+
# ---- Profile routes (D172, D175-D178) ----
|
|
1438
|
+
|
|
1439
|
+
@app.route("/profile")
|
|
1440
|
+
def profile_page():
|
|
1441
|
+
"""User profile page with BYOK key management."""
|
|
1442
|
+
return render_template("profile.html")
|
|
1443
|
+
|
|
1444
|
+
@app.route("/profile/api/keys")
|
|
1445
|
+
def profile_api_keys():
|
|
1446
|
+
"""List current user's dashboard API keys."""
|
|
1447
|
+
from icdev.tools.dashboard.auth import list_api_keys_for_user
|
|
1448
|
+
user = getattr(g, "current_user", None)
|
|
1449
|
+
if not user:
|
|
1450
|
+
return jsonify({"keys": []})
|
|
1451
|
+
keys = list_api_keys_for_user(user["id"])
|
|
1452
|
+
return jsonify({"keys": keys})
|
|
1453
|
+
|
|
1454
|
+
@app.route("/profile/api/llm-keys", methods=["GET"])
|
|
1455
|
+
def profile_llm_keys():
|
|
1456
|
+
"""List current user's BYOK LLM keys."""
|
|
1457
|
+
from icdev.tools.dashboard.byok import list_llm_keys
|
|
1458
|
+
user = getattr(g, "current_user", None)
|
|
1459
|
+
if not user:
|
|
1460
|
+
return jsonify({"keys": []})
|
|
1461
|
+
keys = list_llm_keys(user["id"])
|
|
1462
|
+
return jsonify({"keys": keys})
|
|
1463
|
+
|
|
1464
|
+
@app.route("/profile/api/llm-keys", methods=["POST"])
|
|
1465
|
+
def profile_add_llm_key():
|
|
1466
|
+
"""Store a new BYOK LLM key for the current user."""
|
|
1467
|
+
from icdev.tools.dashboard.byok import store_llm_key
|
|
1468
|
+
user = getattr(g, "current_user", None)
|
|
1469
|
+
if not user:
|
|
1470
|
+
return jsonify({"error": "Not authenticated"}), 401
|
|
1471
|
+
data = flask_request.get_json(force=True)
|
|
1472
|
+
provider = data.get("provider", "").strip()
|
|
1473
|
+
api_key = data.get("api_key", "").strip()
|
|
1474
|
+
label = data.get("label", "").strip()
|
|
1475
|
+
if not provider or not api_key:
|
|
1476
|
+
return jsonify({"error": "provider and api_key required"}), 400
|
|
1477
|
+
result = store_llm_key(user["id"], provider, api_key, key_label=label)
|
|
1478
|
+
return jsonify(result), 201
|
|
1479
|
+
|
|
1480
|
+
@app.route("/profile/api/llm-keys/<key_id>/revoke", methods=["POST"])
|
|
1481
|
+
def profile_revoke_llm_key(key_id):
|
|
1482
|
+
"""Revoke a BYOK LLM key."""
|
|
1483
|
+
from icdev.tools.dashboard.byok import revoke_llm_key
|
|
1484
|
+
revoke_llm_key(key_id)
|
|
1485
|
+
return jsonify({"status": "revoked"})
|
|
1486
|
+
|
|
1487
|
+
# ---- Phase roadmap route ----
|
|
1488
|
+
|
|
1489
|
+
@app.route("/phases")
|
|
1490
|
+
def phases_page():
|
|
1491
|
+
"""Phase roadmap — all ICDEV phases with status, categories, and progress."""
|
|
1492
|
+
from icdev.tools.dashboard.phase_loader import (
|
|
1493
|
+
load_phases, load_categories, load_statuses, get_phase_summary,
|
|
1494
|
+
)
|
|
1495
|
+
phases = load_phases()
|
|
1496
|
+
categories = load_categories()
|
|
1497
|
+
statuses = load_statuses()
|
|
1498
|
+
summary = get_phase_summary(phases)
|
|
1499
|
+
|
|
1500
|
+
# Optional category filter from query param
|
|
1501
|
+
cat_filter = flask_request.args.get("category", "")
|
|
1502
|
+
if cat_filter:
|
|
1503
|
+
phases = [p for p in phases if p.get("category") == cat_filter]
|
|
1504
|
+
|
|
1505
|
+
return render_template(
|
|
1506
|
+
"phases.html",
|
|
1507
|
+
phases=phases,
|
|
1508
|
+
categories=categories,
|
|
1509
|
+
statuses=statuses,
|
|
1510
|
+
summary=summary,
|
|
1511
|
+
category_filter=cat_filter,
|
|
1512
|
+
)
|
|
1513
|
+
|
|
1514
|
+
# ---- Dev profile routes (Phase 34, D183-D188) ----
|
|
1515
|
+
|
|
1516
|
+
@app.route("/dev-profiles")
|
|
1517
|
+
def dev_profiles_page():
|
|
1518
|
+
"""Dev profile management — list, create, view profiles."""
|
|
1519
|
+
return render_template("dev_profiles.html")
|
|
1520
|
+
|
|
1521
|
+
# ---- Child application routes (Phase 19 + Evolutionary Intelligence) ----
|
|
1522
|
+
|
|
1523
|
+
@app.route("/children")
|
|
1524
|
+
def children_page():
|
|
1525
|
+
"""Child application registry — health, genome, capabilities, heartbeats."""
|
|
1526
|
+
conn = _get_db()
|
|
1527
|
+
try:
|
|
1528
|
+
# Fetch all registered child applications
|
|
1529
|
+
try:
|
|
1530
|
+
children_rows = conn.execute(
|
|
1531
|
+
"SELECT * FROM child_app_registry ORDER BY created_at DESC"
|
|
1532
|
+
).fetchall()
|
|
1533
|
+
children_rows = [dict(r) for r in children_rows]
|
|
1534
|
+
except sqlite3.OperationalError:
|
|
1535
|
+
children_rows = []
|
|
1536
|
+
|
|
1537
|
+
# Fetch latest heartbeat per child from telemetry
|
|
1538
|
+
heartbeat_map = {}
|
|
1539
|
+
try:
|
|
1540
|
+
heartbeats = conn.execute(
|
|
1541
|
+
"SELECT child_id, MAX(reported_at) as last_heartbeat "
|
|
1542
|
+
"FROM child_telemetry GROUP BY child_id"
|
|
1543
|
+
).fetchall()
|
|
1544
|
+
for hb in heartbeats:
|
|
1545
|
+
hb_dict = dict(hb)
|
|
1546
|
+
heartbeat_map[hb_dict["child_id"]] = hb_dict["last_heartbeat"]
|
|
1547
|
+
except sqlite3.OperationalError:
|
|
1548
|
+
pass
|
|
1549
|
+
|
|
1550
|
+
# Fetch capability count per child
|
|
1551
|
+
capability_map = {}
|
|
1552
|
+
try:
|
|
1553
|
+
caps = conn.execute(
|
|
1554
|
+
"SELECT child_id, COUNT(*) as cnt FROM child_capabilities GROUP BY child_id"
|
|
1555
|
+
).fetchall()
|
|
1556
|
+
for c in caps:
|
|
1557
|
+
c_dict = dict(c)
|
|
1558
|
+
capability_map[c_dict["child_id"]] = c_dict["cnt"]
|
|
1559
|
+
except sqlite3.OperationalError:
|
|
1560
|
+
pass
|
|
1561
|
+
|
|
1562
|
+
# Enrich children with heartbeat and capability data
|
|
1563
|
+
children = []
|
|
1564
|
+
for child in children_rows:
|
|
1565
|
+
child["last_heartbeat"] = heartbeat_map.get(child.get("id"), child.get("last_heartbeat"))
|
|
1566
|
+
child["capability_count"] = capability_map.get(child.get("id"), child.get("capability_count", 0))
|
|
1567
|
+
child["pending_upgrades"] = child.get("pending_upgrades", 0)
|
|
1568
|
+
child["genome_version"] = child.get("genome_version", None)
|
|
1569
|
+
child["health_status"] = child.get("health_status", "unhealthy")
|
|
1570
|
+
children.append(child)
|
|
1571
|
+
|
|
1572
|
+
# Compute summary counts
|
|
1573
|
+
healthy_count = sum(1 for c in children if c["health_status"] == "healthy")
|
|
1574
|
+
degraded_count = sum(1 for c in children if c["health_status"] == "degraded")
|
|
1575
|
+
unhealthy_count = sum(1 for c in children if c["health_status"] not in ("healthy", "degraded"))
|
|
1576
|
+
|
|
1577
|
+
return render_template(
|
|
1578
|
+
"children.html",
|
|
1579
|
+
children=children,
|
|
1580
|
+
total_count=len(children),
|
|
1581
|
+
healthy_count=healthy_count,
|
|
1582
|
+
degraded_count=degraded_count,
|
|
1583
|
+
unhealthy_count=unhealthy_count,
|
|
1584
|
+
)
|
|
1585
|
+
finally:
|
|
1586
|
+
conn.close()
|
|
1587
|
+
|
|
1588
|
+
@app.route("/dev-profiles/api/list")
|
|
1589
|
+
def dev_profiles_api_list():
|
|
1590
|
+
"""List all dev profiles (JSON)."""
|
|
1591
|
+
conn = _get_db()
|
|
1592
|
+
try:
|
|
1593
|
+
rows = conn.execute(
|
|
1594
|
+
"""SELECT id, scope, scope_id, version, is_active, inherits_from,
|
|
1595
|
+
created_by, created_at, change_summary
|
|
1596
|
+
FROM dev_profiles WHERE is_active = 1
|
|
1597
|
+
ORDER BY created_at DESC LIMIT 50"""
|
|
1598
|
+
).fetchall()
|
|
1599
|
+
return jsonify({"profiles": [dict(r) for r in rows]})
|
|
1600
|
+
except Exception as e:
|
|
1601
|
+
return jsonify({"profiles": [], "error": str(e)})
|
|
1602
|
+
finally:
|
|
1603
|
+
conn.close()
|
|
1604
|
+
|
|
1605
|
+
@app.route("/dev-profiles/api/resolve/<scope>/<scope_id>")
|
|
1606
|
+
def dev_profiles_api_resolve(scope, scope_id):
|
|
1607
|
+
"""Resolve 5-layer cascade for a scope (JSON)."""
|
|
1608
|
+
try:
|
|
1609
|
+
from icdev.tools.builder.dev_profile_manager import resolve_profile
|
|
1610
|
+
result = resolve_profile(scope, scope_id)
|
|
1611
|
+
return jsonify(result)
|
|
1612
|
+
except (ImportError, Exception) as e:
|
|
1613
|
+
return jsonify({"error": str(e)})
|
|
1614
|
+
|
|
1615
|
+
@app.route("/dev-profiles/api/templates")
|
|
1616
|
+
def dev_profiles_api_templates():
|
|
1617
|
+
"""List available starter templates (JSON)."""
|
|
1618
|
+
templates = []
|
|
1619
|
+
templates_dir = Path(__file__).resolve().parent.parent.parent / "context" / "profiles"
|
|
1620
|
+
if templates_dir.exists():
|
|
1621
|
+
try:
|
|
1622
|
+
import yaml
|
|
1623
|
+
for f in sorted(templates_dir.glob("*.yaml")):
|
|
1624
|
+
with open(f, "r", encoding="utf-8") as fh:
|
|
1625
|
+
data = yaml.safe_load(fh)
|
|
1626
|
+
templates.append({
|
|
1627
|
+
"name": data.get("name", f.stem),
|
|
1628
|
+
"file": f.name,
|
|
1629
|
+
"description": data.get("description", ""),
|
|
1630
|
+
"impact_levels": data.get("impact_levels", []),
|
|
1631
|
+
})
|
|
1632
|
+
except Exception:
|
|
1633
|
+
pass
|
|
1634
|
+
return jsonify({"templates": templates})
|
|
1635
|
+
|
|
1636
|
+
@app.route("/dev-profiles/api/create", methods=["POST"])
|
|
1637
|
+
def dev_profiles_api_create():
|
|
1638
|
+
"""Create a dev profile from template or data (JSON)."""
|
|
1639
|
+
try:
|
|
1640
|
+
from icdev.tools.builder.dev_profile_manager import create_profile
|
|
1641
|
+
data = flask_request.get_json(silent=True) or {}
|
|
1642
|
+
result = create_profile(
|
|
1643
|
+
scope=data.get("scope", "project"),
|
|
1644
|
+
scope_id=data.get("scope_id", ""),
|
|
1645
|
+
template_name=data.get("template"),
|
|
1646
|
+
created_by=data.get("created_by", "dashboard"),
|
|
1647
|
+
)
|
|
1648
|
+
return jsonify(result), 201 if "error" not in result else 400
|
|
1649
|
+
except (ImportError, Exception) as e:
|
|
1650
|
+
return jsonify({"error": str(e)}), 500
|
|
1651
|
+
|
|
1652
|
+
# ---- Auth routes (D169-D172) ----
|
|
1653
|
+
|
|
1654
|
+
@app.route("/login", methods=["GET", "POST"])
|
|
1655
|
+
def login_page():
|
|
1656
|
+
"""Login page — accepts API key via form or header."""
|
|
1657
|
+
if flask_request.method == "POST":
|
|
1658
|
+
raw_key = flask_request.form.get("api_key", "").strip()
|
|
1659
|
+
user = validate_api_key(raw_key)
|
|
1660
|
+
if user:
|
|
1661
|
+
flask_session["user_id"] = user["id"]
|
|
1662
|
+
log_auth_event(
|
|
1663
|
+
user["id"], "login_success",
|
|
1664
|
+
ip_address=flask_request.remote_addr,
|
|
1665
|
+
user_agent=flask_request.headers.get("User-Agent", "")[:256],
|
|
1666
|
+
details="via_login_form",
|
|
1667
|
+
)
|
|
1668
|
+
return redirect(url_for("index"))
|
|
1669
|
+
else:
|
|
1670
|
+
log_auth_event(
|
|
1671
|
+
None, "login_failed",
|
|
1672
|
+
ip_address=flask_request.remote_addr,
|
|
1673
|
+
user_agent=flask_request.headers.get("User-Agent", "")[:256],
|
|
1674
|
+
details="via_login_form",
|
|
1675
|
+
)
|
|
1676
|
+
return render_template("login.html", error="Invalid API key. Please try again.")
|
|
1677
|
+
return render_template("login.html", error=None)
|
|
1678
|
+
|
|
1679
|
+
@app.route("/logout")
|
|
1680
|
+
def logout():
|
|
1681
|
+
"""Clear session and redirect to login."""
|
|
1682
|
+
user_id = flask_session.get("user_id")
|
|
1683
|
+
if user_id:
|
|
1684
|
+
log_auth_event(
|
|
1685
|
+
user_id, "logout",
|
|
1686
|
+
ip_address=flask_request.remote_addr,
|
|
1687
|
+
)
|
|
1688
|
+
flask_session.clear()
|
|
1689
|
+
return redirect(url_for("login_page"))
|
|
1690
|
+
|
|
1691
|
+
# ---- Error handlers ----
|
|
1692
|
+
|
|
1693
|
+
# ---- Cross-Language Translation routes (Phase 43) ----
|
|
1694
|
+
|
|
1695
|
+
@app.route("/translations")
|
|
1696
|
+
def translations_page():
|
|
1697
|
+
"""Translation jobs — list, status, validation scores."""
|
|
1698
|
+
conn = _get_db()
|
|
1699
|
+
try:
|
|
1700
|
+
try:
|
|
1701
|
+
jobs = conn.execute(
|
|
1702
|
+
"""SELECT id, project_id, source_language, target_language,
|
|
1703
|
+
status, total_units, translated_units, mocked_units,
|
|
1704
|
+
failed_units, gate_result, llm_model, llm_tokens_input,
|
|
1705
|
+
llm_tokens_output, elapsed_seconds, created_at
|
|
1706
|
+
FROM translation_jobs ORDER BY created_at DESC LIMIT 100"""
|
|
1707
|
+
).fetchall()
|
|
1708
|
+
jobs = [dict(r) for r in jobs]
|
|
1709
|
+
except sqlite3.OperationalError:
|
|
1710
|
+
jobs = []
|
|
1711
|
+
|
|
1712
|
+
# Summary stats
|
|
1713
|
+
total = len(jobs)
|
|
1714
|
+
completed = sum(1 for j in jobs if j.get("status") == "completed")
|
|
1715
|
+
in_progress = sum(1 for j in jobs if j.get("status") in ("pending", "extracting", "translating", "assembling", "validating"))
|
|
1716
|
+
failed = sum(1 for j in jobs if j.get("status") in ("failed", "partial"))
|
|
1717
|
+
|
|
1718
|
+
# Average API surface score from validations
|
|
1719
|
+
avg_api_score = None
|
|
1720
|
+
try:
|
|
1721
|
+
row = conn.execute(
|
|
1722
|
+
"""SELECT AVG(score) as avg_score FROM translation_validations
|
|
1723
|
+
WHERE check_type = 'api_surface' AND passed = 1"""
|
|
1724
|
+
).fetchone()
|
|
1725
|
+
if row and row["avg_score"]:
|
|
1726
|
+
avg_api_score = round(row["avg_score"] * 100, 1)
|
|
1727
|
+
except sqlite3.OperationalError:
|
|
1728
|
+
pass
|
|
1729
|
+
|
|
1730
|
+
return render_template(
|
|
1731
|
+
"translations.html",
|
|
1732
|
+
jobs=jobs,
|
|
1733
|
+
total=total,
|
|
1734
|
+
completed=completed,
|
|
1735
|
+
in_progress=in_progress,
|
|
1736
|
+
failed=failed,
|
|
1737
|
+
avg_api_score=avg_api_score,
|
|
1738
|
+
)
|
|
1739
|
+
finally:
|
|
1740
|
+
conn.close()
|
|
1741
|
+
|
|
1742
|
+
@app.route("/translations/<job_id>")
|
|
1743
|
+
def translation_detail_page(job_id):
|
|
1744
|
+
"""Translation job detail — units, validations, dependencies."""
|
|
1745
|
+
conn = _get_db()
|
|
1746
|
+
try:
|
|
1747
|
+
# Fetch job
|
|
1748
|
+
try:
|
|
1749
|
+
job = conn.execute(
|
|
1750
|
+
"SELECT * FROM translation_jobs WHERE id = ?", (job_id,)
|
|
1751
|
+
).fetchone()
|
|
1752
|
+
job = dict(job) if job else None
|
|
1753
|
+
except sqlite3.OperationalError:
|
|
1754
|
+
job = None
|
|
1755
|
+
|
|
1756
|
+
if not job:
|
|
1757
|
+
return render_template("404.html", message="Translation job not found"), 404
|
|
1758
|
+
|
|
1759
|
+
# Fetch units
|
|
1760
|
+
try:
|
|
1761
|
+
units = conn.execute(
|
|
1762
|
+
"""SELECT unit_name, unit_kind, source_file, status,
|
|
1763
|
+
source_complexity, target_complexity,
|
|
1764
|
+
repair_count, candidate_selected, created_at
|
|
1765
|
+
FROM translation_units WHERE job_id = ?
|
|
1766
|
+
ORDER BY created_at""", (job_id,)
|
|
1767
|
+
).fetchall()
|
|
1768
|
+
units = [dict(u) for u in units]
|
|
1769
|
+
except sqlite3.OperationalError:
|
|
1770
|
+
units = []
|
|
1771
|
+
|
|
1772
|
+
# Fetch validations
|
|
1773
|
+
try:
|
|
1774
|
+
validations = conn.execute(
|
|
1775
|
+
"""SELECT check_type, passed, score, findings, created_at
|
|
1776
|
+
FROM translation_validations WHERE job_id = ?
|
|
1777
|
+
ORDER BY created_at""", (job_id,)
|
|
1778
|
+
).fetchall()
|
|
1779
|
+
validations = [dict(v) for v in validations]
|
|
1780
|
+
except sqlite3.OperationalError:
|
|
1781
|
+
validations = []
|
|
1782
|
+
|
|
1783
|
+
# Fetch dependency mappings
|
|
1784
|
+
try:
|
|
1785
|
+
deps = conn.execute(
|
|
1786
|
+
"""SELECT source_import, target_import, mapping_source,
|
|
1787
|
+
confidence, domain
|
|
1788
|
+
FROM translation_dependency_mappings WHERE job_id = ?
|
|
1789
|
+
ORDER BY domain, source_import""", (job_id,)
|
|
1790
|
+
).fetchall()
|
|
1791
|
+
deps = [dict(d) for d in deps]
|
|
1792
|
+
except sqlite3.OperationalError:
|
|
1793
|
+
deps = []
|
|
1794
|
+
|
|
1795
|
+
return render_template(
|
|
1796
|
+
"translation_detail.html",
|
|
1797
|
+
job=job,
|
|
1798
|
+
units=units,
|
|
1799
|
+
validations=validations,
|
|
1800
|
+
deps=deps,
|
|
1801
|
+
)
|
|
1802
|
+
finally:
|
|
1803
|
+
conn.close()
|
|
1804
|
+
|
|
1805
|
+
@app.route("/api/charts/translations")
|
|
1806
|
+
def api_charts_translations():
|
|
1807
|
+
"""Chart data for translations page."""
|
|
1808
|
+
conn = _get_db()
|
|
1809
|
+
try:
|
|
1810
|
+
# Status distribution
|
|
1811
|
+
status_dist = {}
|
|
1812
|
+
try:
|
|
1813
|
+
rows = conn.execute(
|
|
1814
|
+
"SELECT status, COUNT(*) as cnt FROM translation_jobs GROUP BY status"
|
|
1815
|
+
).fetchall()
|
|
1816
|
+
for r in rows:
|
|
1817
|
+
r_dict = dict(r)
|
|
1818
|
+
status_dist[r_dict["status"]] = r_dict["cnt"]
|
|
1819
|
+
except sqlite3.OperationalError:
|
|
1820
|
+
pass
|
|
1821
|
+
|
|
1822
|
+
# Language pair frequency
|
|
1823
|
+
lang_pairs = {}
|
|
1824
|
+
try:
|
|
1825
|
+
rows = conn.execute(
|
|
1826
|
+
"""SELECT source_language || ' → ' || target_language as pair,
|
|
1827
|
+
COUNT(*) as cnt
|
|
1828
|
+
FROM translation_jobs GROUP BY pair ORDER BY cnt DESC LIMIT 10"""
|
|
1829
|
+
).fetchall()
|
|
1830
|
+
for r in rows:
|
|
1831
|
+
r_dict = dict(r)
|
|
1832
|
+
lang_pairs[r_dict["pair"]] = r_dict["cnt"]
|
|
1833
|
+
except sqlite3.OperationalError:
|
|
1834
|
+
pass
|
|
1835
|
+
|
|
1836
|
+
return jsonify({
|
|
1837
|
+
"status_distribution": status_dist,
|
|
1838
|
+
"language_pair_frequency": lang_pairs,
|
|
1839
|
+
})
|
|
1840
|
+
finally:
|
|
1841
|
+
conn.close()
|
|
1842
|
+
|
|
1843
|
+
# ---- Phase 46: Observability pages ----
|
|
1844
|
+
|
|
1845
|
+
@app.route("/traces")
|
|
1846
|
+
def traces_page():
|
|
1847
|
+
"""Trace explorer — distributed tracing across MCP, A2A, LLM."""
|
|
1848
|
+
return render_template("traces.html")
|
|
1849
|
+
|
|
1850
|
+
@app.route("/provenance")
|
|
1851
|
+
def provenance_page():
|
|
1852
|
+
"""Provenance graph — W3C PROV-AGENT artifact lineage."""
|
|
1853
|
+
return render_template("provenance.html")
|
|
1854
|
+
|
|
1855
|
+
@app.route("/xai")
|
|
1856
|
+
def xai_page():
|
|
1857
|
+
"""XAI dashboard — explainability, SHAP attribution, compliance."""
|
|
1858
|
+
return render_template("xai.html")
|
|
1859
|
+
|
|
1860
|
+
# ---- OSCAL & Production Audit pages ----
|
|
1861
|
+
|
|
1862
|
+
@app.route("/oscal")
|
|
1863
|
+
def oscal_page():
|
|
1864
|
+
"""OSCAL ecosystem — validation, catalog, format conversion (D302-D306)."""
|
|
1865
|
+
return render_template("oscal.html")
|
|
1866
|
+
|
|
1867
|
+
@app.route("/prod-audit")
|
|
1868
|
+
def prod_audit_page():
|
|
1869
|
+
"""Production readiness audit — 30 checks, 6 categories (D291-D300)."""
|
|
1870
|
+
return render_template("prod_audit.html")
|
|
1871
|
+
|
|
1872
|
+
@app.route("/ai-transparency")
|
|
1873
|
+
def ai_transparency_page():
|
|
1874
|
+
"""AI Transparency — OMB M-25-21, M-26-04, NIST AI 600-1, GAO-21-519SP (Phase 48, D307-D315)."""
|
|
1875
|
+
return render_template("ai_transparency.html")
|
|
1876
|
+
|
|
1877
|
+
@app.route("/ai-accountability")
|
|
1878
|
+
def ai_accountability_page():
|
|
1879
|
+
"""AI Accountability — oversight, appeals, CAIO, incidents, ethics (Phase 49, D316-D321)."""
|
|
1880
|
+
return render_template("ai_accountability.html")
|
|
1881
|
+
|
|
1882
|
+
@app.route("/code-quality")
|
|
1883
|
+
def code_quality_page():
|
|
1884
|
+
"""Code Quality Intelligence — AST analysis, smells, maintainability, runtime feedback (Phase 52, D331-D337)."""
|
|
1885
|
+
return render_template("code_quality.html")
|
|
1886
|
+
|
|
1887
|
+
@app.route("/fedramp-20x")
|
|
1888
|
+
def fedramp_20x_page():
|
|
1889
|
+
"""FedRAMP 20x KSI Dashboard — KSI evidence generation, maturity levels, authorization package (Phase 53, D338)."""
|
|
1890
|
+
return render_template("fedramp_20x.html")
|
|
1891
|
+
|
|
1892
|
+
@app.route("/evidence")
|
|
1893
|
+
def evidence_page():
|
|
1894
|
+
"""Evidence Collection — universal evidence auto-collection across all frameworks (Phase 56, D347)."""
|
|
1895
|
+
from icdev.tools.compliance.evidence_collector import FRAMEWORK_EVIDENCE_MAP, _get_connection, _table_exists
|
|
1896
|
+
stats = {"total_frameworks": len(FRAMEWORK_EVIDENCE_MAP), "required_frameworks": 0, "frameworks": []}
|
|
1897
|
+
try:
|
|
1898
|
+
conn = _get_connection()
|
|
1899
|
+
for fw_id, fw_config in FRAMEWORK_EVIDENCE_MAP.items():
|
|
1900
|
+
if fw_config["required"]:
|
|
1901
|
+
stats["required_frameworks"] += 1
|
|
1902
|
+
total = 0
|
|
1903
|
+
for table_name in fw_config["tables"]:
|
|
1904
|
+
if _table_exists(conn, table_name):
|
|
1905
|
+
row = conn.execute(f"SELECT COUNT(*) FROM {table_name}").fetchone()
|
|
1906
|
+
total += row[0]
|
|
1907
|
+
stats["frameworks"].append({
|
|
1908
|
+
"id": fw_id,
|
|
1909
|
+
"description": fw_config["description"],
|
|
1910
|
+
"required": fw_config["required"],
|
|
1911
|
+
"total_records": total,
|
|
1912
|
+
})
|
|
1913
|
+
conn.close()
|
|
1914
|
+
except Exception:
|
|
1915
|
+
pass
|
|
1916
|
+
return render_template("evidence.html", stats=stats)
|
|
1917
|
+
|
|
1918
|
+
@app.route("/lineage")
|
|
1919
|
+
def lineage_page():
|
|
1920
|
+
"""Artifact Lineage — unified DAG visualization of digital thread, provenance, audit trail, SBOM (Phase 56, D348)."""
|
|
1921
|
+
return render_template("lineage.html")
|
|
1922
|
+
|
|
1923
|
+
# ---- CPMP / Proposals / GovCon Pages (D-CHILD-6: guarded) ----
|
|
1924
|
+
if _HAS_GOVCON:
|
|
1925
|
+
_register_govcon_pages(app, _get_db)
|
|
1926
|
+
|
|
1927
|
+
# ---- Phase 61: Orchestration Dashboard ----
|
|
1928
|
+
|
|
1929
|
+
@app.route("/orchestration")
|
|
1930
|
+
def orchestration_dashboard():
|
|
1931
|
+
"""Real-time multi-agent orchestration dashboard — agent grid, DAG, mailbox (Phase 61)."""
|
|
1932
|
+
return render_template("orchestration/dashboard.html")
|
|
1933
|
+
|
|
1934
|
+
@app.errorhandler(401)
|
|
1935
|
+
def unauthorized(e):
|
|
1936
|
+
if flask_request.is_json or flask_request.path.startswith("/api/"):
|
|
1937
|
+
return jsonify({"error": "Unauthorized", "message": "Valid API key required"}), 401
|
|
1938
|
+
return redirect(url_for("login_page"))
|
|
1939
|
+
|
|
1940
|
+
@app.errorhandler(403)
|
|
1941
|
+
def forbidden(e):
|
|
1942
|
+
if flask_request.is_json or flask_request.path.startswith("/api/"):
|
|
1943
|
+
return jsonify({"error": "Forbidden", "message": "Insufficient permissions"}), 403
|
|
1944
|
+
return render_template("404.html", message="You do not have permission to access this page."), 403
|
|
1945
|
+
|
|
1946
|
+
@app.errorhandler(404)
|
|
1947
|
+
def not_found(e):
|
|
1948
|
+
return render_template("404.html", message="Page not found"), 404
|
|
1949
|
+
|
|
1950
|
+
return app
|
|
1951
|
+
|
|
1952
|
+
|
|
1953
|
+
# ---------------------------------------------------------------------------
|
|
1954
|
+
# Database helper
|
|
1955
|
+
# ---------------------------------------------------------------------------
|
|
1956
|
+
|
|
1957
|
+
|
|
1958
|
+
def _get_db():
|
|
1959
|
+
conn = sqlite3.connect(DB_PATH)
|
|
1960
|
+
conn.row_factory = sqlite3.Row
|
|
1961
|
+
return conn
|
|
1962
|
+
|
|
1963
|
+
|
|
1964
|
+
# ---------------------------------------------------------------------------
|
|
1965
|
+
# CLI entry point
|
|
1966
|
+
# ---------------------------------------------------------------------------
|
|
1967
|
+
|
|
1968
|
+
if __name__ == "__main__":
|
|
1969
|
+
parser = argparse.ArgumentParser(description="ICDEV Dashboard")
|
|
1970
|
+
parser.add_argument("--port", type=int, default=PORT, help="Port to run on (default: 5000)")
|
|
1971
|
+
parser.add_argument("--debug", action="store_true", default=DEBUG, help="Enable debug mode")
|
|
1972
|
+
args = parser.parse_args()
|
|
1973
|
+
|
|
1974
|
+
app = create_app()
|
|
1975
|
+
print(f"[ICDEV Dashboard] Starting on http://127.0.0.1:{args.port}")
|
|
1976
|
+
print(f"[ICDEV Dashboard] Database: {DB_PATH}")
|
|
1977
|
+
print(f"[ICDEV Dashboard] CUI Marking: {CUI_BANNER_TOP}")
|
|
1978
|
+
|
|
1979
|
+
# Use SocketIO runner if available (D170), otherwise plain Flask
|
|
1980
|
+
socketio = get_socketio()
|
|
1981
|
+
if socketio:
|
|
1982
|
+
print("[ICDEV Dashboard] WebSocket enabled (Flask-SocketIO)")
|
|
1983
|
+
socketio.run(app, host="0.0.0.0", port=args.port, debug=args.debug)
|
|
1984
|
+
else:
|
|
1985
|
+
print("[ICDEV Dashboard] WebSocket not available — using HTTP polling")
|
|
1986
|
+
app.run(host="0.0.0.0", port=args.port, debug=args.debug)
|