icdev 0.0.3__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.
- args/agent_config.yaml +113 -0
- args/audit_regimes/cisa_sbd.json +381 -0
- args/audit_regimes/cmmc_l2.json +906 -0
- args/audit_regimes/dod_cssp.json +393 -0
- args/audit_regimes/dodi_5000_87.json +297 -0
- args/audit_regimes/fedramp_moderate.json +650 -0
- args/audit_regimes/ieee_1012.json +373 -0
- args/audit_regimes/nist_800_171.json +624 -0
- args/audit_regimes/nist_800_53.json +907 -0
- args/cloudforge_blueprints/aws_commercial.yaml +29 -0
- args/cloudforge_blueprints/aws_govcloud_il4.yaml +34 -0
- args/cloudforge_blueprints/aws_govcloud_il5.yaml +38 -0
- args/cloudforge_blueprints/azure_commercial.yaml +28 -0
- args/cloudforge_blueprints/azure_gov_il4.yaml +32 -0
- args/cloudforge_blueprints/azure_gov_il5.yaml +36 -0
- args/cloudforge_blueprints/gcp_commercial.yaml +28 -0
- args/cloudforge_blueprints/oci_commercial.yaml +28 -0
- args/cloudforge_config.yaml +231 -0
- args/cloudforge_runbook_templates/backup_verify.yaml +98 -0
- args/cloudforge_runbook_templates/dr_failover.yaml +107 -0
- args/cloudforge_runbook_templates/health_check.yaml +97 -0
- args/cloudforge_runbook_templates/incident_response.yaml +101 -0
- args/cloudforge_runbook_templates/migration_cutover.yaml +105 -0
- args/cloudforge_runbook_templates/patch_rollout.yaml +92 -0
- args/cloudforge_runbook_templates/zone_provision.yaml +93 -0
- args/code_pattern_config.yaml +151 -0
- args/code_quality_config.yaml +47 -0
- args/compliance_config.yaml +17 -0
- args/control_inheritance.yaml +177 -0
- args/csp_mcp_config.yaml +41 -0
- args/cui_markings.yaml +35 -0
- args/databridge_config.yaml +232 -0
- args/db_config.yaml +116 -0
- args/decision_tables/agent_trust_decision.yaml +143 -0
- args/decision_tables/ato_boundary_impact.yaml +132 -0
- args/decision_tables/deployment_approval.yaml +152 -0
- args/degradation_matrix.yaml +163 -0
- args/devsecops_config.yaml +286 -0
- args/endpoint_security_config.yaml +207 -0
- args/exit_criteria.yaml +102 -0
- args/feature_flags.yaml +235 -0
- args/file_access_tiers.yaml +88 -0
- args/forge_studio/blueprint_config.yaml +27 -0
- args/forge_studio/component_catalog.json +411 -0
- args/forge_studio/workflow_templates.yaml +103 -0
- args/govcon_config.yaml +41 -0
- args/harness_config.yaml +67 -0
- args/innovation_config.yaml +321 -0
- args/knowledge_graph_config.yaml +113 -0
- args/llm_config.yaml +222 -0
- args/marketplace_config.yaml +260 -0
- args/monitoring_config.yaml +127 -0
- args/mosa_config.yaml +190 -0
- args/observability_tracing_config.yaml +170 -0
- args/owasp_agentic_config.yaml +171 -0
- args/pipeline_gates.yaml +197 -0
- args/project_defaults.yaml +235 -0
- args/prompt_chains.yaml +163 -0
- args/rag_config.yaml +167 -0
- args/research_config.yaml +89 -0
- args/resilience_config.yaml +197 -0
- args/ricoas_config.yaml +191 -0
- args/security_gates.yaml +763 -0
- args/storage_config.yaml +63 -0
- args/writeguard_config.yaml +131 -0
- args/zta_config.yaml +247 -0
- context/__init__.py +6 -0
- context/agent/__init__.py +6 -0
- context/agent/response_schemas/__init__.py +6 -0
- context/agent/response_schemas/debate_position.json +46 -0
- context/agent/response_schemas/fitness_scorecard.json +74 -0
- context/agent/response_schemas/review_decision.json +39 -0
- context/agent/response_schemas/task_decomposition.json +82 -0
- context/agent/response_schemas/veto_decision.json +40 -0
- context/agentic/__init__.py +6 -0
- context/agentic/architecture_patterns.md +269 -0
- context/agentic/capability_registry.yaml +223 -0
- context/agentic/csp_integration.md +30 -0
- context/agentic/csp_mcp_registry.yaml +280 -0
- context/agentic/fitness_rubric.md +56 -0
- context/agentic/governance_baseline.md +205 -0
- context/ci/__init__.py +6 -0
- context/ci/worktree_templates.json +44 -0
- context/cloud/__init__.py +6 -0
- context/cloud/csp_service_registry.json +739 -0
- context/compliance/__init__.py +6 -0
- context/compliance/ai_rmf_crosswalk.yaml +226 -0
- context/compliance/atlas_mitigations.json +293 -0
- context/compliance/atlas_techniques.json +833 -0
- context/compliance/cisa_sbd_requirements.json +477 -0
- context/compliance/cjis_security_policy.json +522 -0
- context/compliance/cmmc_practices.json +2494 -0
- context/compliance/cmmc_report_template.md +142 -0
- context/compliance/cnssi_1253_overlay.json +109 -0
- context/compliance/control_crosswalk.json +1914 -0
- context/compliance/control_families/__init__.py +6 -0
- context/compliance/csp_certifications.json +251 -0
- context/compliance/cssp_report_template.md +193 -0
- context/compliance/cui_templates/__init__.py +6 -0
- context/compliance/cui_templates/banner_block.txt +4 -0
- context/compliance/cui_templates/code_header.txt +8 -0
- context/compliance/cui_templates/document_template.md +35 -0
- context/compliance/data_type_framework_map.json +321 -0
- context/compliance/data_type_registry.json +147 -0
- context/compliance/dod_cssp_8530.json +463 -0
- context/compliance/eu_ai_act_annex_iii.json +108 -0
- context/compliance/export_templates/__init__.py +6 -0
- context/compliance/export_templates/emass_controls.csv.j2 +4 -0
- context/compliance/export_templates/evidence_package.md.j2 +39 -0
- context/compliance/export_templates/executive_summary.md.j2 +55 -0
- context/compliance/export_templates/poam_tracking.csv.j2 +4 -0
- context/compliance/fedramp_20x_ksi_schemas.json +133 -0
- context/compliance/fedramp_high_baseline.json +4370 -0
- context/compliance/fedramp_moderate_baseline.json +2183 -0
- context/compliance/fedramp_report_template.md +181 -0
- context/compliance/fips_200_areas.json +362 -0
- context/compliance/gao_ai_accountability.json +262 -0
- context/compliance/hipaa_security_rule.json +720 -0
- context/compliance/hitrust_csf_v11.json +930 -0
- context/compliance/impact_level_profiles.json +251 -0
- context/compliance/incident_response_template.md +1110 -0
- context/compliance/iso27001_2022_controls.json +750 -0
- context/compliance/iso27001_nist_bridge.json +382 -0
- context/compliance/iso42001_controls.json +254 -0
- context/compliance/ivv_checklist_template.md +80 -0
- context/compliance/ivv_report_template.md +116 -0
- context/compliance/ivv_requirements.json +372 -0
- context/compliance/mosa_crosswalk.json +327 -0
- context/compliance/mosa_framework.json +250 -0
- context/compliance/narrative_templates/AC.md.j2 +101 -0
- context/compliance/narrative_templates/AU.md.j2 +106 -0
- context/compliance/narrative_templates/IA.md.j2 +104 -0
- context/compliance/narrative_templates/SC.md.j2 +102 -0
- context/compliance/narrative_templates/SI.md.j2 +111 -0
- context/compliance/narrative_templates/__init__.py +6 -0
- context/compliance/narrative_templates/default.md.j2 +50 -0
- context/compliance/narrative_templates/executive_summary.j2 +27 -0
- context/compliance/narrative_templates/poam_milestone.j2 +19 -0
- context/compliance/narrative_templates/ssp_section.j2 +11 -0
- context/compliance/nist_800_171_controls.json +1552 -0
- context/compliance/nist_800_207_crosswalk.json +399 -0
- context/compliance/nist_800_207_zta.json +258 -0
- context/compliance/nist_800_53.json +324 -0
- context/compliance/nist_ai_600_1_genai.json +326 -0
- context/compliance/nist_ai_rmf.json +206 -0
- context/compliance/nist_sp_800_60_types.json +1667 -0
- context/compliance/omb_m25_21_high_impact_ai.json +248 -0
- context/compliance/omb_m26_04_unbiased_ai.json +262 -0
- context/compliance/owasp_agentic_asi.json +133 -0
- context/compliance/owasp_agentic_threats.json +285 -0
- context/compliance/owasp_llm_top10.json +274 -0
- context/compliance/pci_dss_v4.json +510 -0
- context/compliance/poam_template.md +117 -0
- context/compliance/safeai_controls.json +512 -0
- context/compliance/sbd_report_template.md +77 -0
- context/compliance/siem_config_templates/__init__.py +6 -0
- context/compliance/siem_config_templates/filebeat.yml +213 -0
- context/compliance/siem_config_templates/log_sources.json +208 -0
- context/compliance/soc2_trust_criteria.json +661 -0
- context/compliance/ssp_template.md +432 -0
- context/compliance/stig_templates/__init__.py +6 -0
- context/compliance/stig_templates/webapp_stig.json +139 -0
- context/compliance/xai_requirements.json +108 -0
- context/dashboard/__init__.py +6 -0
- context/dashboard/nlq_examples.json +50 -0
- context/dashboard/schema_descriptions.json +23 -0
- context/icdev_methodology.md +100 -0
- context/integration/__init__.py +6 -0
- context/integration/approval_workflows.json +32 -0
- context/integration/gitlab_field_mappings.json +33 -0
- context/integration/jira_field_mappings.json +32 -0
- context/integration/reqif_export_schema.json +23 -0
- context/integration/servicenow_field_mappings.json +22 -0
- context/languages/__init__.py +6 -0
- context/languages/framework_patterns.json +205 -0
- context/languages/language_registry.json +279 -0
- context/llm/__init__.py +6 -0
- context/llm/example_provider.py +89 -0
- context/marketplace/assets/writeguard-core.yaml +100 -0
- context/marketplace/assets/writeguard-govcon.yaml +45 -0
- context/marketplace/assets/writeguard-style-guides.yaml +44 -0
- context/mbse/__init__.py +6 -0
- context/mbse/des_report_template.md +162 -0
- context/mbse/des_requirements.json +411 -0
- context/mbse/digital_thread_patterns.json +403 -0
- context/mbse/reqif_schema.json +280 -0
- context/mbse/sysml_element_types.json +432 -0
- context/oscal/NIST_SP-800-53_rev5_catalog.json +254987 -0
- context/oscal/README.md +43 -0
- context/patterns/__init__.py +6 -0
- context/profiles/__init__.py +6 -0
- context/profiles/dod_baseline_v1.yaml +145 -0
- context/profiles/fedramp_baseline_v1.yaml +143 -0
- context/profiles/financial_baseline_v1.yaml +142 -0
- context/profiles/healthcare_baseline_v1.yaml +135 -0
- context/profiles/law_enforcement_v1.yaml +129 -0
- context/profiles/startup_v1.yaml +134 -0
- context/rag/source_mappings.json +42 -0
- context/requirements/__init__.py +6 -0
- context/requirements/ambiguity_patterns.json +97 -0
- context/requirements/boundary_impact_rules.json +123 -0
- context/requirements/default_constitutions.json +67 -0
- context/requirements/document_extraction_rules.json +58 -0
- context/requirements/gap_patterns.json +108 -0
- context/requirements/readiness_rubric.json +78 -0
- context/requirements/red_alternative_patterns.json +210 -0
- context/requirements/safe_templates.json +72 -0
- context/requirements/spec_quality_checklist.json +122 -0
- context/research/regulatory_registry.json +114 -0
- context/research/verticals/cybersecurity.json +127 -0
- context/research/verticals/defense.json +104 -0
- context/research/verticals/fintech.json +125 -0
- context/research/verticals/healthcare.json +118 -0
- context/research/verticals/logistics.json +117 -0
- context/research/verticals/trading.json +145 -0
- context/simulation/__init__.py +6 -0
- context/simulation/architecture_patterns.json +36 -0
- context/simulation/coa_templates.json +38 -0
- context/simulation/cost_models.json +23 -0
- context/simulation/risk_categories.json +46 -0
- context/supply_chain/__init__.py +6 -0
- context/supply_chain/isa_templates.json +129 -0
- context/supply_chain/nist_800_161_controls.json +247 -0
- context/supply_chain/scrm_risk_matrix.json +147 -0
- context/templates/__init__.py +6 -0
- context/templates/ansible/__init__.py +6 -0
- context/templates/ansible/playbooks/__init__.py +6 -0
- context/templates/ansible/roles/__init__.py +6 -0
- context/templates/gitlab_ci/__init__.py +6 -0
- context/templates/grafana/__init__.py +6 -0
- context/templates/kubernetes/__init__.py +6 -0
- context/templates/project/__init__.py +6 -0
- context/templates/project/api/__init__.py +6 -0
- context/templates/project/cli/__init__.py +6 -0
- context/templates/project/data_pipeline/__init__.py +6 -0
- context/templates/project/iac/__init__.py +6 -0
- context/templates/project/javascript_frontend/__init__.py +6 -0
- context/templates/project/javascript_frontend/src/__init__.py +6 -0
- context/templates/project/javascript_frontend/tests/__init__.py +6 -0
- context/templates/project/microservice/__init__.py +6 -0
- context/templates/project/python_backend/__init__.py +6 -0
- context/templates/project/python_backend/src/__init__.py +6 -0
- context/templates/project/python_backend/tests/__init__.py +6 -0
- context/templates/project/python_backend/tests/features/__init__.py +6 -0
- context/templates/project/python_backend/tests/steps/__init__.py +6 -0
- context/templates/terraform/__init__.py +6 -0
- context/templates/terraform/govcloud_base/__init__.py +6 -0
- context/templates/terraform/modules/__init__.py +6 -0
- context/tone/__init__.py +6 -0
- context/writing/grammar_rules/common_errors.json +306 -0
- context/writing/grammar_rules/govcon_vocabulary.json +113 -0
- context/writing/style_guides/academic.yaml +43 -0
- context/writing/style_guides/business.yaml +42 -0
- context/writing/style_guides/government.yaml +59 -0
- context/writing/style_guides/proposal.yaml +58 -0
- context/writing/style_guides/technical.yaml +43 -0
- docs/adr/README.md +66 -0
- docs/adr/connector-forge-decisions.md +318 -0
- docs/adr/core-decisions.md +289 -0
- docs/adr/db-decisions.md +94 -0
- docs/adr/harness-decisions.md +122 -0
- docs/adr/innovation-decisions.md +262 -0
- docs/adr/marketplace-decisions.md +109 -0
- docs/adr/sbd-decisions.md +109 -0
- docs/adr/scale-engine-decisions.md +108 -0
- docs/adr/writeguard-decisions.md +136 -0
- docs/architecture/bounded-contexts.md +1032 -0
- docs/features/phase-65-writeguard.md +139 -0
- docs/features/phase-66-marketplace-commerce.md +79 -0
- docs/features/phase-67-knowledge-ingestion-rag-autodraft.md +97 -0
- docs/features/phase-68-enhanced-autodraft-pipeline.md +109 -0
- docs/features/phase-69-proposalai-marketplace-module.md +131 -0
- docs/features/phase-70-databridge.md +214 -0
- docs/features/phase-71-databridge-messaging.md +102 -0
- docs/implementation-plan-architecture-evolution.md +614 -0
- docs/marketplace/CONTRIBUTING.md +124 -0
- docs/marketplace/module_manifest_schema.yaml +83 -0
- docs/research/ai-architecture-patterns-2024-2026.md +1236 -0
- docs/research/app-builder-platform-analysis.md +582 -0
- docs/research/architecture-patterns-c4-ddd-agentic.md +871 -0
- docs/research/flowable-boat-competitive-analysis.md +426 -0
- docs/research/modern-dev-practices-2024-2026.md +1615 -0
- docs/research/secure-by-design-cloudyrion-adaptation.md +270 -0
- goals/agent_management.md +144 -0
- goals/ai_accountability.md +90 -0
- goals/ai_narratives.md +79 -0
- goals/ai_transparency.md +76 -0
- goals/ato_simulator.md +78 -0
- goals/audit_engine.md +177 -0
- goals/bite_sized_plans.md +225 -0
- goals/boundary_supply_chain.md +206 -0
- goals/brainstorming_gate.md +186 -0
- goals/build_app.md +604 -0
- goals/cato_live_evidence.md +77 -0
- goals/cloudforge.md +106 -0
- goals/code_intelligence.md +197 -0
- goals/compliance_workflow.md +858 -0
- goals/connector_forge.md +133 -0
- goals/databridge.md +128 -0
- goals/deploy_workflow.md +390 -0
- goals/developer_scorecard.md +78 -0
- goals/devsecops_workflow.md +408 -0
- goals/firmware_sbom.md +79 -0
- goals/forge_hub.md +78 -0
- goals/golden_path.md +77 -0
- goals/harness_engineering.md +91 -0
- goals/integration_testing.md +189 -0
- goals/knowledge_graph.md +128 -0
- goals/maintenance_audit.md +196 -0
- goals/manifest.md +50 -0
- goals/monitoring.md +126 -0
- goals/mosa_workflow.md +463 -0
- goals/multi_agent_orchestration.md +68 -0
- goals/observability_traceability_xai.md +154 -0
- goals/owasp_agentic_security.md +395 -0
- goals/pr_intelligence.md +78 -0
- goals/requirements_intake.md +213 -0
- goals/secure_by_design.md +135 -0
- goals/security_scan.md +381 -0
- goals/self_healing.md +120 -0
- goals/simulation_engine.md +111 -0
- goals/subagent_review.md +205 -0
- goals/systematic_debugging.md +257 -0
- goals/tdd_workflow.md +403 -0
- goals/template_exchange.md +77 -0
- goals/thread_heatmap.md +77 -0
- goals/threat_modeler.md +77 -0
- goals/verification_iron_law.md +192 -0
- goals/vsm_dashboard.md +76 -0
- goals/writeguard.md +89 -0
- goals/zero_trust_architecture.md +403 -0
- hardprompts/__init__.py +6 -0
- hardprompts/agent/__init__.py +6 -0
- hardprompts/agent/agentic_architect.md +100 -0
- hardprompts/agent/debate_prompt.md +32 -0
- hardprompts/agent/fitness_evaluation.md +48 -0
- hardprompts/agent/governance_review.md +214 -0
- hardprompts/agent/reviewer_prompt.md +34 -0
- hardprompts/agent/skill_design.md +172 -0
- hardprompts/agent/task_decomposition.md +275 -0
- hardprompts/agent/veto_check_prompt.md +33 -0
- hardprompts/architect/__init__.py +6 -0
- hardprompts/architect/api_design.md +283 -0
- hardprompts/architect/data_model.md +277 -0
- hardprompts/architect/system_design.md +180 -0
- hardprompts/builder/__init__.py +6 -0
- hardprompts/builder/code_generation.md +59 -0
- hardprompts/builder/refactor.md +58 -0
- hardprompts/builder/scaffold_project.md +69 -0
- hardprompts/builder/test_generation.md +87 -0
- hardprompts/ci/__init__.py +6 -0
- hardprompts/ci/worktree_setup.md +35 -0
- hardprompts/compliance/__init__.py +6 -0
- hardprompts/compliance/cmmc_assessment.md +63 -0
- hardprompts/compliance/cssp_assessment.md +75 -0
- hardprompts/compliance/cui_marking.md +86 -0
- hardprompts/compliance/fedramp_assessment.md +55 -0
- hardprompts/compliance/ivv_assessment.md +96 -0
- hardprompts/compliance/poam_generation.md +57 -0
- hardprompts/compliance/sbd_assessment.md +101 -0
- hardprompts/compliance/security_categorization.md +74 -0
- hardprompts/compliance/ssp_generation.md +56 -0
- hardprompts/compliance/stig_evaluation.md +63 -0
- hardprompts/dashboard/__init__.py +6 -0
- hardprompts/dashboard/nlq_system_prompt.md +26 -0
- hardprompts/infra/__init__.py +6 -0
- hardprompts/infra/k8s_manifests.md +118 -0
- hardprompts/infra/pipeline_generation.md +160 -0
- hardprompts/infra/terraform_generation.md +92 -0
- hardprompts/integration/__init__.py +6 -0
- hardprompts/integration/approval_review.md +17 -0
- hardprompts/integration/jira_mapping.md +25 -0
- hardprompts/integration/servicenow_mapping.md +14 -0
- hardprompts/knowledge/__init__.py +6 -0
- hardprompts/knowledge/pattern_detection.md +73 -0
- hardprompts/knowledge/recommendation_engine.md +90 -0
- hardprompts/knowledge/root_cause_analysis.md +91 -0
- hardprompts/maintenance/__init__.py +6 -0
- hardprompts/maintenance/maintenance_assessment.md +82 -0
- hardprompts/mbse/__init__.py +6 -0
- hardprompts/mbse/digital_thread.md +67 -0
- hardprompts/mbse/model_import.md +62 -0
- hardprompts/mbse/model_to_code.md +65 -0
- hardprompts/modernization/__init__.py +6 -0
- hardprompts/modernization/legacy_analysis.md +93 -0
- hardprompts/modernization/migration_planning.md +150 -0
- hardprompts/modernization/seven_r_assessment.md +107 -0
- hardprompts/proposal_draft.md +53 -0
- hardprompts/rag_citation.md +12 -0
- hardprompts/rag_rerank.md +31 -0
- hardprompts/requirements/__init__.py +6 -0
- hardprompts/requirements/bdd_generation.md +35 -0
- hardprompts/requirements/clarification_prioritization.md +29 -0
- hardprompts/requirements/decomposition.md +60 -0
- hardprompts/requirements/document_extraction.md +45 -0
- hardprompts/requirements/gap_detection.md +70 -0
- hardprompts/requirements/intake_conversation.md +101 -0
- hardprompts/requirements/readiness_assessment.md +39 -0
- hardprompts/requirements/spec_quality.md +33 -0
- hardprompts/requirements/traceability_analysis.md +23 -0
- hardprompts/security/__init__.py +6 -0
- hardprompts/security/endpoint_security.md +78 -0
- hardprompts/security/threat_model.md +70 -0
- hardprompts/security/vulnerability_assessment.md +81 -0
- hardprompts/simulation/__init__.py +6 -0
- hardprompts/simulation/architecture_impact.md +27 -0
- hardprompts/simulation/coa_alternative.md +27 -0
- hardprompts/simulation/coa_generation.md +25 -0
- hardprompts/simulation/compliance_impact.md +28 -0
- hardprompts/simulation/cost_estimation.md +33 -0
- hardprompts/simulation/risk_assessment.md +28 -0
- hardprompts/translation/code_translation.md +68 -0
- hardprompts/translation/dependency_suggestion.md +44 -0
- hardprompts/translation/test_translation.md +64 -0
- hardprompts/translation/translation_repair.md +59 -0
- icdev-0.0.3.dist-info/METADATA +909 -0
- icdev-0.0.3.dist-info/RECORD +1214 -0
- icdev-0.0.3.dist-info/WHEEL +5 -0
- icdev-0.0.3.dist-info/entry_points.txt +9 -0
- icdev-0.0.3.dist-info/licenses/LICENSE +201 -0
- icdev-0.0.3.dist-info/licenses/NOTICE +11 -0
- icdev-0.0.3.dist-info/top_level.txt +7 -0
- memory/MEMORY.md +52 -0
- memory/logs/2026-02-14.md +17 -0
- memory/logs/2026-03-03.md +2 -0
- memory/logs/__init__.py +1 -0
- tools/a2a/icdev_callback_client.py +210 -0
- tools/agent/cards/architect_card.json +29 -0
- tools/agent/cards/builder_card.json +34 -0
- tools/agent/cards/compliance_card.json +29 -0
- tools/agent/cards/connector_forge_card.json +49 -0
- tools/agent/cards/devsecops_zta_card.json +24 -0
- tools/agent/cards/knowledge_card.json +29 -0
- tools/agent/cards/monitor_card.json +29 -0
- tools/agent/cards/orchestrator_card.json +29 -0
- tools/agent/cards/requirements_analyst_card.json +24 -0
- tools/agent/cards/security_card.json +29 -0
- tools/agent/cards/simulation_card.json +24 -0
- tools/agent/cards/supply_chain_card.json +24 -0
- tools/analysis/__init__.py +1 -0
- tools/analysis/code_analyzer.py +770 -0
- tools/analysis/runtime_feedback.py +379 -0
- tools/analytics/__init__.py +2 -0
- tools/analytics/scorecard.py +538 -0
- tools/analytics/vsm_engine.py +612 -0
- tools/architecture/__init__.py +2 -0
- tools/architecture/adr_extractor.py +393 -0
- tools/audit/__init__.py +1 -0
- tools/audit/audit_logger.py +199 -0
- tools/audit/audit_query.py +153 -0
- tools/audit/decision_recorder.py +73 -0
- tools/audit_engine/__init__.py +12 -0
- tools/audit_engine/ai_advisor.py +906 -0
- tools/audit_engine/cli.py +286 -0
- tools/audit_engine/comparator.py +305 -0
- tools/audit_engine/eject_scaffolder.py +399 -0
- tools/audit_engine/engine.py +614 -0
- tools/audit_engine/git_fetcher.py +341 -0
- tools/audit_engine/regime_loader.py +200 -0
- tools/audit_engine/regime_updater.py +325 -0
- tools/audit_engine/report_card.py +289 -0
- tools/audit_engine/scanner.py +684 -0
- tools/audit_engine/self_heal.py +1042 -0
- tools/ci/__init__.py +2 -0
- tools/ci/connectors/__init__.py +2 -0
- tools/ci/connectors/base_connector.py +80 -0
- tools/ci/connectors/connector_registry.py +188 -0
- tools/ci/connectors/mattermost_connector.py +159 -0
- tools/ci/connectors/slack_connector.py +197 -0
- tools/ci/core/__init__.py +2 -0
- tools/ci/core/air_gap_detector.py +115 -0
- tools/ci/core/comment_handler.py +192 -0
- tools/ci/core/conversation_manager.py +480 -0
- tools/ci/core/event_envelope.py +500 -0
- tools/ci/core/event_router.py +444 -0
- tools/ci/core/failure_parser.py +397 -0
- tools/ci/core/recovery_engine.py +527 -0
- tools/ci/gate_enforcer.py +361 -0
- tools/ci/modules/__init__.py +2 -0
- tools/ci/modules/agent.py +271 -0
- tools/ci/modules/git_ops.py +175 -0
- tools/ci/modules/state.py +117 -0
- tools/ci/modules/vcs.py +303 -0
- tools/ci/modules/workflow_ops.py +295 -0
- tools/ci/modules/worktree.py +337 -0
- tools/ci/pipeline_config_generator.py +558 -0
- tools/ci/pr_intelligence.py +485 -0
- tools/ci/triggers/__init__.py +2 -0
- tools/ci/triggers/gitlab_task_monitor.py +327 -0
- tools/ci/triggers/poll_trigger.py +237 -0
- tools/ci/triggers/webhook_server.py +356 -0
- tools/ci/workflows/__init__.py +2 -0
- tools/ci/workflows/icdev_build.py +140 -0
- tools/ci/workflows/icdev_comply.py +284 -0
- tools/ci/workflows/icdev_document.py +152 -0
- tools/ci/workflows/icdev_e2e.py +188 -0
- tools/ci/workflows/icdev_patch.py +186 -0
- tools/ci/workflows/icdev_plan.py +202 -0
- tools/ci/workflows/icdev_plan_build.py +41 -0
- tools/ci/workflows/icdev_plan_build_test.py +46 -0
- tools/ci/workflows/icdev_plan_build_test_review.py +47 -0
- tools/ci/workflows/icdev_review.py +126 -0
- tools/ci/workflows/icdev_sdlc.py +261 -0
- tools/ci/workflows/icdev_test.py +240 -0
- tools/cli/__init__.py +1 -0
- tools/cli/output_formatter.py +756 -0
- tools/cloudforge/__init__.py +12 -0
- tools/cloudforge/airgap/__init__.py +2 -0
- tools/cloudforge/airgap/il_classifier.py +70 -0
- tools/cloudforge/airgap/offline_validator.py +42 -0
- tools/cloudforge/airgap/shift_emulator.py +155 -0
- tools/cloudforge/airgap/sneakernet.py +91 -0
- tools/cloudforge/cd_hub/__init__.py +2 -0
- tools/cloudforge/cd_hub/canary_deployer.py +88 -0
- tools/cloudforge/cd_hub/gitops_renderer.py +123 -0
- tools/cloudforge/cd_hub/hub_controller.py +143 -0
- tools/cloudforge/cd_hub/pipeline_bridge.py +30 -0
- tools/cloudforge/cd_hub/rollback_engine.py +29 -0
- tools/cloudforge/cd_hub/spoke_agent.py +51 -0
- tools/cloudforge/compliance/__init__.py +2 -0
- tools/cloudforge/compliance/ato_accelerator.py +272 -0
- tools/cloudforge/compliance/control_inheritor.py +127 -0
- tools/cloudforge/compliance/evidence_generator.py +129 -0
- tools/cloudforge/compliance/poam_bridge.py +41 -0
- tools/cloudforge/compliance/ssp_bridge.py +52 -0
- tools/cloudforge/compliance/stig_bridge.py +41 -0
- tools/cloudforge/container_forge/__init__.py +2 -0
- tools/cloudforge/container_forge/bigbang_renderer.py +85 -0
- tools/cloudforge/container_forge/hardener.py +169 -0
- tools/cloudforge/container_forge/image_scanner_bridge.py +33 -0
- tools/cloudforge/container_forge/runtime_policy.py +87 -0
- tools/cloudforge/container_forge/sbom_bridge.py +42 -0
- tools/cloudforge/finops/__init__.py +2 -0
- tools/cloudforge/finops/anomaly_detector.py +78 -0
- tools/cloudforge/finops/budget_tracker.py +96 -0
- tools/cloudforge/finops/chargeback.py +69 -0
- tools/cloudforge/finops/cost_collector.py +141 -0
- tools/cloudforge/finops/optimizer.py +55 -0
- tools/cloudforge/hybrid/__init__.py +2 -0
- tools/cloudforge/hybrid/connection_manager.py +141 -0
- tools/cloudforge/hybrid/dns_federator.py +56 -0
- tools/cloudforge/hybrid/health_monitor.py +108 -0
- tools/cloudforge/hybrid/identity_federator.py +53 -0
- tools/cloudforge/hybrid/network_bridge.py +68 -0
- tools/cloudforge/hybrid/topology_manager.py +147 -0
- tools/cloudforge/hybrid/workload_abstractor.py +92 -0
- tools/cloudforge/iac/__init__.py +2 -0
- tools/cloudforge/iac/drift_detector.py +154 -0
- tools/cloudforge/iac/module_library.py +265 -0
- tools/cloudforge/iac/opentofu_adapter.py +89 -0
- tools/cloudforge/iac/pulumi_renderer.py +292 -0
- tools/cloudforge/iac/state_backend.py +146 -0
- tools/cloudforge/iac/terraform_renderer.py +626 -0
- tools/cloudforge/landing_zone/__init__.py +2 -0
- tools/cloudforge/landing_zone/blueprint_loader.py +98 -0
- tools/cloudforge/landing_zone/blueprint_validator.py +113 -0
- tools/cloudforge/landing_zone/zone_provisioner.py +306 -0
- tools/cloudforge/landing_zone/zone_state.py +143 -0
- tools/cloudforge/mbse_thread/__init__.py +2 -0
- tools/cloudforge/mbse_thread/ato_thread_weaver.py +111 -0
- tools/cloudforge/mbse_thread/control_tracer.py +68 -0
- tools/cloudforge/mbse_thread/system_boundary.py +83 -0
- tools/cloudforge/metastore/__init__.py +2 -0
- tools/cloudforge/metastore/dependency_graph.py +202 -0
- tools/cloudforge/metastore/discovery.py +192 -0
- tools/cloudforge/metastore/registry.py +185 -0
- tools/cloudforge/metastore/rto_tracker.py +92 -0
- tools/cloudforge/metastore/runbook_linker.py +82 -0
- tools/cloudforge/migration/__init__.py +2 -0
- tools/cloudforge/migration/assessor.py +187 -0
- tools/cloudforge/migration/cutover_orchestrator.py +117 -0
- tools/cloudforge/migration/databridge_bridge.py +92 -0
- tools/cloudforge/migration/planner.py +98 -0
- tools/cloudforge/migration/risk_scorer.py +97 -0
- tools/cloudforge/migration/validation_runner.py +45 -0
- tools/cloudforge/migration/workload_inventory.py +107 -0
- tools/cloudforge/provider.py +319 -0
- tools/cloudforge/providers/__init__.py +2 -0
- tools/cloudforge/providers/aws_commercial.py +92 -0
- tools/cloudforge/providers/aws_govcloud.py +229 -0
- tools/cloudforge/providers/aws_secret.py +83 -0
- tools/cloudforge/providers/azure_commercial.py +80 -0
- tools/cloudforge/providers/azure_gov.py +91 -0
- tools/cloudforge/providers/azure_secret.py +71 -0
- tools/cloudforge/providers/gcp.py +102 -0
- tools/cloudforge/providers/oci.py +102 -0
- tools/cloudforge/registry.py +140 -0
- tools/cloudforge/runbooks/__init__.py +2 -0
- tools/cloudforge/runbooks/ai_generator.py +119 -0
- tools/cloudforge/runbooks/dag_validator.py +219 -0
- tools/cloudforge/runbooks/engine.py +470 -0
- tools/cloudforge/runbooks/models.py +99 -0
- tools/cloudforge/runbooks/snippet_library.py +158 -0
- tools/cloudforge/runbooks/template_loader.py +122 -0
- tools/cloudforge/runbooks/visualization.py +108 -0
- tools/cloudforge/siem/__init__.py +2 -0
- tools/cloudforge/siem/alert_rules.py +86 -0
- tools/cloudforge/siem/correlation_engine.py +61 -0
- tools/cloudforge/siem/log_aggregator.py +113 -0
- tools/cloudforge/siem/siem_dashboard_data.py +28 -0
- tools/cloudforge/supply_chain/__init__.py +2 -0
- tools/cloudforge/supply_chain/bridge.py +33 -0
- tools/cloudforge/supply_chain/iac_dependency_scanner.py +36 -0
- tools/cloudforge/supply_chain/provider_trust_scorer.py +54 -0
- tools/compat/__init__.py +21 -0
- tools/compat/cli_harmonizer.py +251 -0
- tools/compat/datetime_utils.py +18 -0
- tools/compat/db_utils.py +190 -0
- tools/compat/platform_utils.py +123 -0
- tools/compliance/__init__.py +1 -0
- tools/compliance/accountability_manager.py +391 -0
- tools/compliance/ai_accountability_audit.py +287 -0
- tools/compliance/ai_impact_assessor.py +267 -0
- tools/compliance/ai_incident_response.py +295 -0
- tools/compliance/ai_inventory_manager.py +233 -0
- tools/compliance/ai_reassessment_scheduler.py +250 -0
- tools/compliance/ai_transparency_audit.py +247 -0
- tools/compliance/atlas_assessor.py +276 -0
- tools/compliance/atlas_report_generator.py +1199 -0
- tools/compliance/base_assessor.py +591 -0
- tools/compliance/cato_live_engine.py +607 -0
- tools/compliance/cato_monitor.py +1371 -0
- tools/compliance/cato_scheduler.py +698 -0
- tools/compliance/cjis_assessor.py +76 -0
- tools/compliance/classification_manager.py +1340 -0
- tools/compliance/cmmc_assessor.py +1478 -0
- tools/compliance/cmmc_report_generator.py +1087 -0
- tools/compliance/compliance_detector.py +452 -0
- tools/compliance/compliance_exporter.py +418 -0
- tools/compliance/compliance_status.py +810 -0
- tools/compliance/control_mapper.py +488 -0
- tools/compliance/crosswalk_engine.py +1208 -0
- tools/compliance/cssp_assessor.py +1032 -0
- tools/compliance/cssp_evidence_collector.py +716 -0
- tools/compliance/cssp_report_generator.py +1103 -0
- tools/compliance/cui_marker.py +387 -0
- tools/compliance/diagram_validator.py +599 -0
- tools/compliance/emass/__init__.py +2 -0
- tools/compliance/emass/emass_client.py +822 -0
- tools/compliance/emass/emass_export.py +758 -0
- tools/compliance/emass/emass_sync.py +807 -0
- tools/compliance/eu_ai_act_classifier.py +193 -0
- tools/compliance/evidence_collector.py +459 -0
- tools/compliance/fairness_assessor.py +310 -0
- tools/compliance/fedramp_20x_ksi_emitter.py +692 -0
- tools/compliance/fedramp_assessor.py +1795 -0
- tools/compliance/fedramp_authorization_packager.py +137 -0
- tools/compliance/fedramp_ksi_generator.py +349 -0
- tools/compliance/fedramp_report_generator.py +1115 -0
- tools/compliance/fips199_categorizer.py +869 -0
- tools/compliance/fips200_validator.py +304 -0
- tools/compliance/firmware_sbom.py +646 -0
- tools/compliance/gao_ai_assessor.py +228 -0
- tools/compliance/gao_evidence_builder.py +302 -0
- tools/compliance/hipaa_assessor.py +78 -0
- tools/compliance/hitrust_assessor.py +49 -0
- tools/compliance/incident_response_plan.py +705 -0
- tools/compliance/inheritance_engine.py +693 -0
- tools/compliance/iso27001_assessor.py +92 -0
- tools/compliance/iso42001_assessor.py +114 -0
- tools/compliance/ivv_assessor.py +2314 -0
- tools/compliance/ivv_report_generator.py +1649 -0
- tools/compliance/model_card_generator.py +291 -0
- tools/compliance/mosa_assessor.py +117 -0
- tools/compliance/multi_regime_assessor.py +441 -0
- tools/compliance/narrative_generator.py +1012 -0
- tools/compliance/narrative_quality_gate.py +701 -0
- tools/compliance/narrative_workflow.py +814 -0
- tools/compliance/nist_800_207_assessor.py +191 -0
- tools/compliance/nist_ai_600_1_assessor.py +185 -0
- tools/compliance/nist_ai_rmf_assessor.py +110 -0
- tools/compliance/nist_lookup.py +244 -0
- tools/compliance/omb_m25_21_assessor.py +225 -0
- tools/compliance/omb_m26_04_assessor.py +185 -0
- tools/compliance/oscal_catalog_adapter.py +395 -0
- tools/compliance/oscal_generator.py +2157 -0
- tools/compliance/oscal_tools.py +1182 -0
- tools/compliance/oscal_validator.py +692 -0
- tools/compliance/owasp_agentic_assessor.py +227 -0
- tools/compliance/owasp_asi_assessor.py +197 -0
- tools/compliance/owasp_llm_assessor.py +245 -0
- tools/compliance/pci_dss_assessor.py +80 -0
- tools/compliance/pi_compliance_tracker.py +1447 -0
- tools/compliance/poam_generator.py +388 -0
- tools/compliance/resolve_marking.py +272 -0
- tools/compliance/sbd_assessor.py +2070 -0
- tools/compliance/sbd_report_generator.py +1223 -0
- tools/compliance/sbom_generator.py +993 -0
- tools/compliance/siem_config_generator.py +661 -0
- tools/compliance/slsa_attestation_generator.py +479 -0
- tools/compliance/soc2_assessor.py +77 -0
- tools/compliance/ssp_generator.py +556 -0
- tools/compliance/stig_checker.py +712 -0
- tools/compliance/swft_evidence_bundler.py +326 -0
- tools/compliance/system_card_generator.py +303 -0
- tools/compliance/template_exchange.py +513 -0
- tools/compliance/traceability_matrix.py +1268 -0
- tools/compliance/universal_classification_manager.py +1159 -0
- tools/compliance/xacta/__init__.py +2 -0
- tools/compliance/xacta/xacta_client.py +438 -0
- tools/compliance/xacta/xacta_export.py +546 -0
- tools/compliance/xacta/xacta_sync.py +322 -0
- tools/compliance/xai_assessor.py +231 -0
- tools/core/__init__.py +2 -0
- tools/core/circuit_breaker.py +353 -0
- tools/core/compliance_sidecar.py +344 -0
- tools/core/container.py +110 -0
- tools/core/errors.py +256 -0
- tools/core/feature_flags.py +311 -0
- tools/core/task_dlq.py +350 -0
- tools/dashboard/__init__.py +2 -0
- tools/dashboard/app.py +6288 -0
- tools/dashboard/templates/agent_evolution.html +287 -0
- tools/dashboard/templates/agents/list.html +71 -0
- tools/dashboard/templates/agents.html +132 -0
- tools/dashboard/templates/architecture.html +289 -0
- tools/dashboard/templates/ato_simulator.html +170 -0
- tools/dashboard/templates/audit_engine.html +844 -0
- tools/dashboard/templates/base.html +236 -0
- tools/dashboard/templates/cato_live.html +116 -0
- tools/dashboard/templates/cloudforge.html +195 -0
- tools/dashboard/templates/cloudforge_finops.html +111 -0
- tools/dashboard/templates/cloudforge_hybrid.html +122 -0
- tools/dashboard/templates/cloudforge_metastore.html +234 -0
- tools/dashboard/templates/cloudforge_migration.html +87 -0
- tools/dashboard/templates/cloudforge_runbooks.html +201 -0
- tools/dashboard/templates/cloudforge_siem.html +94 -0
- tools/dashboard/templates/compliance_accel.html +292 -0
- tools/dashboard/templates/crashes.html +122 -0
- tools/dashboard/templates/databridge.html +305 -0
- tools/dashboard/templates/databridge_analytics.html +195 -0
- tools/dashboard/templates/databridge_mapping.html +345 -0
- tools/dashboard/templates/databridge_messaging.html +321 -0
- tools/dashboard/templates/decisions.html +258 -0
- tools/dashboard/templates/devices.html +151 -0
- tools/dashboard/templates/devsecops_maturity.html +278 -0
- tools/dashboard/templates/edge_ai.html +128 -0
- tools/dashboard/templates/firmware.html +120 -0
- tools/dashboard/templates/firmware_sbom.html +193 -0
- tools/dashboard/templates/forge_hub.html +196 -0
- tools/dashboard/templates/forge_studio.html +379 -0
- tools/dashboard/templates/forge_studio_analytics.html +360 -0
- tools/dashboard/templates/forge_studio_builder.html +1637 -0
- tools/dashboard/templates/forge_studio_compliance.html +310 -0
- tools/dashboard/templates/forge_studio_deploy.html +573 -0
- tools/dashboard/templates/forge_studio_enterprise.html +888 -0
- tools/dashboard/templates/forge_studio_marketplace.html +502 -0
- tools/dashboard/templates/forge_studio_workflow.html +696 -0
- tools/dashboard/templates/golden_path.html +175 -0
- tools/dashboard/templates/govcon.html +280 -0
- tools/dashboard/templates/harness.html +148 -0
- tools/dashboard/templates/index.html +207 -0
- tools/dashboard/templates/intelligence.html +336 -0
- tools/dashboard/templates/knowledge/index.html +190 -0
- tools/dashboard/templates/knowledge_graph.html +739 -0
- tools/dashboard/templates/login.html +51 -0
- tools/dashboard/templates/marketplace.html +336 -0
- tools/dashboard/templates/marketplace_admin.html +247 -0
- tools/dashboard/templates/missions.html +403 -0
- tools/dashboard/templates/narratives.html +154 -0
- tools/dashboard/templates/pr_intelligence.html +151 -0
- tools/dashboard/templates/proposals/detail.html +300 -0
- tools/dashboard/templates/proposals/list.html +52 -0
- tools/dashboard/templates/proposals/sam_detail.html +132 -0
- tools/dashboard/templates/proposals/section_detail.html +375 -0
- tools/dashboard/templates/research.html +222 -0
- tools/dashboard/templates/resilience.html +300 -0
- tools/dashboard/templates/scorecard.html +162 -0
- tools/dashboard/templates/simulator.html +131 -0
- tools/dashboard/templates/template_exchange.html +147 -0
- tools/dashboard/templates/thread_heatmap.html +151 -0
- tools/dashboard/templates/threat_model.html +195 -0
- tools/dashboard/templates/vsm.html +141 -0
- tools/dashboard/templates/writeguard.html +277 -0
- tools/databridge/__init__.py +5 -0
- tools/databridge/agent/__init__.py +2 -0
- tools/databridge/agent/daemon.py +227 -0
- tools/databridge/agent/tunnel.py +101 -0
- tools/databridge/agent/ws_relay.py +91 -0
- tools/databridge/analytics.py +167 -0
- tools/databridge/arrow_pipeline.py +327 -0
- tools/databridge/connection_manager.py +424 -0
- tools/databridge/connector.py +331 -0
- tools/databridge/connectors/__init__.py +2 -0
- tools/databridge/connectors/argocd_connector.py +160 -0
- tools/databridge/connectors/avro_connector.py +203 -0
- tools/databridge/connectors/azure_blob.py +63 -0
- tools/databridge/connectors/cdc_connector.py +205 -0
- tools/databridge/connectors/csv_connector.py +172 -0
- tools/databridge/connectors/datadog_connector.py +153 -0
- tools/databridge/connectors/discord_messaging.py +215 -0
- tools/databridge/connectors/dynamics365.py +151 -0
- tools/databridge/connectors/elasticsearch_connector.py +145 -0
- tools/databridge/connectors/email_base.py +114 -0
- tools/databridge/connectors/excel_connector.py +175 -0
- tools/databridge/connectors/fsspec_base.py +300 -0
- tools/databridge/connectors/gcs.py +53 -0
- tools/databridge/connectors/github_connector.py +138 -0
- tools/databridge/connectors/gitlab_connector.py +132 -0
- tools/databridge/connectors/gmail_connector.py +182 -0
- tools/databridge/connectors/hdfs.py +57 -0
- tools/databridge/connectors/health_base.py +401 -0
- tools/databridge/connectors/hubspot.py +124 -0
- tools/databridge/connectors/imap_connector.py +171 -0
- tools/databridge/connectors/jenkins_connector.py +138 -0
- tools/databridge/connectors/jira_connector.py +86 -0
- tools/databridge/connectors/json_connector.py +184 -0
- tools/databridge/connectors/kafka_connector.py +246 -0
- tools/databridge/connectors/kinesis_connector.py +238 -0
- tools/databridge/connectors/local_fs.py +30 -0
- tools/databridge/connectors/matrix.py +197 -0
- tools/databridge/connectors/mattermost_messaging.py +184 -0
- tools/databridge/connectors/messaging_base.py +172 -0
- tools/databridge/connectors/mssql.py +63 -0
- tools/databridge/connectors/mysql.py +57 -0
- tools/databridge/connectors/netsuite.py +170 -0
- tools/databridge/connectors/o365_mail.py +196 -0
- tools/databridge/connectors/oracle.py +65 -0
- tools/databridge/connectors/pagerduty_connector.py +162 -0
- tools/databridge/connectors/parquet_connector.py +131 -0
- tools/databridge/connectors/postgresql.py +58 -0
- tools/databridge/connectors/s3.py +65 -0
- tools/databridge/connectors/saas_base.py +198 -0
- tools/databridge/connectors/salesforce.py +126 -0
- tools/databridge/connectors/sap.py +89 -0
- tools/databridge/connectors/servicenow.py +60 -0
- tools/databridge/connectors/signal_messaging.py +150 -0
- tools/databridge/connectors/slack_messaging.py +203 -0
- tools/databridge/connectors/smtp_connector.py +126 -0
- tools/databridge/connectors/soap_base.py +258 -0
- tools/databridge/connectors/splunk_connector.py +171 -0
- tools/databridge/connectors/sql_base.py +310 -0
- tools/databridge/connectors/sqlite_connector.py +76 -0
- tools/databridge/connectors/teams.py +148 -0
- tools/databridge/connectors/telegram.py +192 -0
- tools/databridge/connectors/whatsapp.py +137 -0
- tools/databridge/data_profiler.py +99 -0
- tools/databridge/forge/__init__.py +6 -0
- tools/databridge/forge/base_selector.py +150 -0
- tools/databridge/forge/code_generator.py +206 -0
- tools/databridge/forge/community_hub.py +539 -0
- tools/databridge/forge/forge_agent.py +306 -0
- tools/databridge/forge/import_handler.py +133 -0
- tools/databridge/forge/integration_tester.py +127 -0
- tools/databridge/forge/marketplace_publisher.py +164 -0
- tools/databridge/forge/promoter.py +159 -0
- tools/databridge/forge/sandbox_manager.py +257 -0
- tools/databridge/forge/spec_parser.py +358 -0
- tools/databridge/forge/static_validator.py +363 -0
- tools/databridge/forge/templates/__init__.py +591 -0
- tools/databridge/format_converter.py +188 -0
- tools/databridge/mapping_engine.py +348 -0
- tools/databridge/messaging/__init__.py +5 -0
- tools/databridge/messaging/agent_bridge.py +254 -0
- tools/databridge/messaging/message_envelope.py +111 -0
- tools/databridge/messaging/message_logger.py +204 -0
- tools/databridge/messaging/messaging_daemon.py +326 -0
- tools/databridge/messaging/oauth2_manager.py +411 -0
- tools/databridge/pii_detector.py +221 -0
- tools/databridge/registry.py +352 -0
- tools/databridge/relay_server.py +105 -0
- tools/databridge/scale/__init__.py +16 -0
- tools/databridge/scale/backpressure.py +134 -0
- tools/databridge/scale/chunked_pipeline.py +169 -0
- tools/databridge/scale/connection_pool.py +293 -0
- tools/databridge/scale/engine.py +492 -0
- tools/databridge/scale/worker_pool.py +140 -0
- tools/databridge/scale/write_batcher.py +250 -0
- tools/databridge/schema_engine.py +324 -0
- tools/databridge/stream_manager.py +225 -0
- tools/databridge/sync_engine.py +411 -0
- tools/databridge/transforms.py +302 -0
- tools/db/__init__.py +1 -0
- tools/db/backup.py +312 -0
- tools/db/backup_manager.py +832 -0
- tools/db/init_icdev_db.py +7753 -0
- tools/db/init_sparkpilot_db.py +431 -0
- tools/db/migrate.py +177 -0
- tools/db/migrate_innovation_audit.py +165 -0
- tools/db/migration_runner.py +548 -0
- tools/db/migrations/001_baseline/meta.json +9 -0
- tools/db/migrations/001_baseline/up.py +67 -0
- tools/db/migrations/002_memory_enhancements/down.sql +8 -0
- tools/db/migrations/002_memory_enhancements/meta.json +9 -0
- tools/db/migrations/002_memory_enhancements/up.py +119 -0
- tools/db/migrations/003_dev_profiles/meta.json +8 -0
- tools/db/migrations/003_dev_profiles/up.py +93 -0
- tools/db/migrations/004_innovation_engine/down.py +19 -0
- tools/db/migrations/004_innovation_engine/up.py +227 -0
- tools/db/migrations/005_phase_37_ai_security/down.py +19 -0
- tools/db/migrations/005_phase_37_ai_security/up.py +257 -0
- tools/db/migrations/006_phase_36_evolution/down.py +21 -0
- tools/db/migrations/006_phase_36_evolution/up.py +323 -0
- tools/db/migrations/007_phase_38_cloud/down.py +14 -0
- tools/db/migrations/007_phase_38_cloud/up.py +110 -0
- tools/db/migrations/008_phase36_37_integration/up.py +55 -0
- tools/db/migrations/__init__.py +2 -0
- tools/db/pg_migrate.py +642 -0
- tools/db/storage.py +1080 -0
- tools/decisions/__init__.py +2 -0
- tools/decisions/dmn_engine.py +695 -0
- tools/devsecops/__init__.py +2 -0
- tools/devsecops/attestation_manager.py +449 -0
- tools/devsecops/network_segmentation_generator.py +604 -0
- tools/devsecops/pdp_config_generator.py +1246 -0
- tools/devsecops/pipeline_security_generator.py +475 -0
- tools/devsecops/policy_generator.py +644 -0
- tools/devsecops/profile_manager.py +374 -0
- tools/devsecops/service_mesh_generator.py +1063 -0
- tools/devsecops/zta_maturity_scorer.py +355 -0
- tools/devsecops/zta_terraform_generator.py +1301 -0
- tools/edge_ai/__init__.py +2 -0
- tools/edge_ai/model_manager.py +200 -0
- tools/embedded/__init__.py +2 -0
- tools/embedded/cmake_generator.py +318 -0
- tools/embedded/crash_analyzer.py +191 -0
- tools/embedded/nl_to_firmware.py +277 -0
- tools/events/__init__.py +1 -0
- tools/events/event_bus.py +199 -0
- tools/finetune/pair_generator.py +832 -0
- tools/fleet/__init__.py +2 -0
- tools/fleet/device_registry.py +148 -0
- tools/fleet/ota_manager.py +153 -0
- tools/forge_studio/__init__.py +13 -0
- tools/forge_studio/analytics/__init__.py +0 -0
- tools/forge_studio/analytics/process_miner.py +383 -0
- tools/forge_studio/audit.py +183 -0
- tools/forge_studio/blueprint/__init__.py +2 -0
- tools/forge_studio/blueprint/build_tracker.py +317 -0
- tools/forge_studio/blueprint/export_engine.py +441 -0
- tools/forge_studio/blueprint/parent_client.py +335 -0
- tools/forge_studio/catalog/__init__.py +2 -0
- tools/forge_studio/catalog/component_registry.py +176 -0
- tools/forge_studio/catalog/schema_validator.py +193 -0
- tools/forge_studio/compliance/__init__.py +1 -0
- tools/forge_studio/compliance/compliance_wiring.py +554 -0
- tools/forge_studio/deploy/__init__.py +1 -0
- tools/forge_studio/deploy/airgap_packager.py +466 -0
- tools/forge_studio/deploy/deploy_engine.py +1792 -0
- tools/forge_studio/deploy/env_manager.py +431 -0
- tools/forge_studio/eject/__init__.py +2 -0
- tools/forge_studio/eject/docker_compose_generator.py +237 -0
- tools/forge_studio/eject/eject_engine.py +230 -0
- tools/forge_studio/eject/expo_scaffolder.py +303 -0
- tools/forge_studio/eject/nextjs_scaffolder.py +338 -0
- tools/forge_studio/enterprise/__init__.py +0 -0
- tools/forge_studio/enterprise/custom_frameworks.py +826 -0
- tools/forge_studio/enterprise/hardening_engine.py +1530 -0
- tools/forge_studio/enterprise/sso_manager.py +718 -0
- tools/forge_studio/enterprise/whitelabel_engine.py +887 -0
- tools/forge_studio/formula/__init__.py +0 -0
- tools/forge_studio/formula/expression_engine.py +562 -0
- tools/forge_studio/formula/formula_registry.py +265 -0
- tools/forge_studio/generator/__init__.py +2 -0
- tools/forge_studio/generator/app_generator.py +584 -0
- tools/forge_studio/generator/complexity_detector.py +368 -0
- tools/forge_studio/generator/prompt_templates.py +104 -0
- tools/forge_studio/generator/spec_builder.py +192 -0
- tools/forge_studio/intake_bridge.py +898 -0
- tools/forge_studio/marketplace/__init__.py +0 -0
- tools/forge_studio/marketplace/component_hub.py +428 -0
- tools/forge_studio/models.py +369 -0
- tools/forge_studio/renderer/__init__.py +2 -0
- tools/forge_studio/renderer/json_render_engine.py +623 -0
- tools/forge_studio/renderer/layout_engine.py +214 -0
- tools/forge_studio/renderer/rn_component_map.py +182 -0
- tools/forge_studio/supabase/__init__.py +2 -0
- tools/forge_studio/supabase/auth_generator.py +283 -0
- tools/forge_studio/supabase/migration_generator.py +93 -0
- tools/forge_studio/supabase/schema_generator.py +281 -0
- tools/forge_studio/tenant_manager.py +387 -0
- tools/forge_studio/workflow/__init__.py +2 -0
- tools/forge_studio/workflow/bpmn_adapter.py +489 -0
- tools/govcon/draft_orchestrator.py +1151 -0
- tools/govcon/engine_enrichment.py +373 -0
- tools/govcon/knowledge_base.py +487 -0
- tools/govcon/knowledge_ingestion.py +510 -0
- tools/govcon/sam_scanner.py +754 -0
- tools/harness/__init__.py +6 -0
- tools/harness/exit_criteria_evaluator.py +231 -0
- tools/harness/maturity_assessor.py +347 -0
- tools/harness/scaffold_harness.py +416 -0
- tools/harness/trace_analyzer.py +281 -0
- tools/infra/__init__.py +1 -0
- tools/infra/ansible_generator.py +867 -0
- tools/infra/dockerfile_generator.py +359 -0
- tools/infra/infra_status.py +384 -0
- tools/infra/ironbank_metadata_generator.py +403 -0
- tools/infra/k8s_generator.py +1000 -0
- tools/infra/pipeline_generator.py +830 -0
- tools/infra/rollback.py +389 -0
- tools/infra/terraform_generator.py +1140 -0
- tools/infra/terraform_generator_azure.py +1252 -0
- tools/infra/terraform_generator_gcp.py +951 -0
- tools/infra/terraform_generator_ibm.py +359 -0
- tools/infra/terraform_generator_oci.py +918 -0
- tools/infra/terraform_generator_onprem.py +318 -0
- tools/knowledge/__init__.py +1 -0
- tools/knowledge/knowledge_ingest.py +281 -0
- tools/knowledge/pattern_detector.py +681 -0
- tools/knowledge/recommendation_engine.py +449 -0
- tools/knowledge/self_heal_analyzer.py +492 -0
- tools/knowledge_graph/__init__.py +2 -0
- tools/knowledge_graph/graph_rag.py +498 -0
- tools/knowledge_graph/ingester.py +406 -0
- tools/knowledge_graph/insight_generator.py +369 -0
- tools/knowledge_graph/text_network.py +832 -0
- tools/llm/__init__.py +72 -0
- tools/llm/anthropic_provider.py +170 -0
- tools/llm/azure_openai_provider.py +338 -0
- tools/llm/bedrock_provider.py +315 -0
- tools/llm/embedding_provider.py +438 -0
- tools/llm/gemini_provider.py +381 -0
- tools/llm/ibm_watsonx_provider.py +231 -0
- tools/llm/oci_genai_provider.py +462 -0
- tools/llm/ollama_provider.py +350 -0
- tools/llm/openai_provider.py +225 -0
- tools/llm/prompt_registry.py +447 -0
- tools/llm/provider.py +355 -0
- tools/llm/provider_sdk.py +175 -0
- tools/llm/router.py +1124 -0
- tools/llm/semantic_cache.py +394 -0
- tools/llm/vertex_ai_provider.py +374 -0
- tools/maintenance/__init__.py +2 -0
- tools/maintenance/dependency_scanner.py +1016 -0
- tools/maintenance/maintenance_auditor.py +804 -0
- tools/maintenance/remediation_engine.py +957 -0
- tools/maintenance/vulnerability_checker.py +978 -0
- tools/manifest.md +1066 -0
- tools/marketplace/asset_installer.py +639 -0
- tools/marketplace/feedback_validator.py +359 -0
- tools/marketplace/license_client.py +458 -0
- tools/marketplace/module_crypto.py +544 -0
- tools/marketplace/module_runtime.py +236 -0
- tools/marketplace/token_store.py +264 -0
- tools/mbse/__init__.py +3 -0
- tools/mbse/des_assessor.py +1173 -0
- tools/mbse/des_report_generator.py +787 -0
- tools/mbse/diagram_extractor.py +792 -0
- tools/mbse/digital_thread.py +1650 -0
- tools/mbse/model_code_generator.py +1115 -0
- tools/mbse/model_control_mapper.py +410 -0
- tools/mbse/pi_model_tracker.py +1079 -0
- tools/mbse/reqif_parser.py +1468 -0
- tools/mbse/sync_engine.py +1789 -0
- tools/mbse/thread_heatmap.py +445 -0
- tools/mbse/xmi_parser.py +1558 -0
- tools/mcp/builder_server.py +64 -0
- tools/mcp/compliance_server.py +64 -0
- tools/mcp/connector_forge_server.py +155 -0
- tools/mcp/core_server.py +64 -0
- tools/mcp/devsecops_server.py +11 -0
- tools/mcp/devsecops_zta_server.py +64 -0
- tools/mcp/knowledge_server.py +64 -0
- tools/mcp/monitor_server.py +64 -0
- tools/mcp/ops_server.py +300 -0
- tools/mcp/requirements_analyst_server.py +64 -0
- tools/mcp/requirements_server.py +11 -0
- tools/mcp/security_server.py +64 -0
- tools/mcp/simulation_server.py +64 -0
- tools/mcp/supply_chain_server.py +64 -0
- tools/mcp/tool_registry.py +299 -0
- tools/memory/__init__.py +2 -0
- tools/memory/auto_capture.py +346 -0
- tools/memory/embed_memory.py +157 -0
- tools/memory/history_compressor.py +334 -0
- tools/memory/hybrid_search.py +235 -0
- tools/memory/maintenance_cron.py +288 -0
- tools/memory/memory_consolidation.py +439 -0
- tools/memory/memory_db.py +132 -0
- tools/memory/memory_read.py +101 -0
- tools/memory/memory_write.py +221 -0
- tools/memory/semantic_search.py +138 -0
- tools/memory/time_decay.py +434 -0
- tools/missions/__init__.py +2 -0
- tools/missions/mission_engine.py +459 -0
- tools/monitor/__init__.py +1 -0
- tools/monitor/alert_correlator.py +486 -0
- tools/monitor/auto_resolver.py +603 -0
- tools/monitor/health_checker.py +507 -0
- tools/monitor/heartbeat_daemon.py +779 -0
- tools/monitor/log_analyzer.py +507 -0
- tools/monitor/metric_collector.py +484 -0
- tools/mosa/__init__.py +10 -0
- tools/mosa/icd_generator.py +358 -0
- tools/mosa/modular_design_analyzer.py +682 -0
- tools/mosa/mosa_code_enforcer.py +348 -0
- tools/mosa/tsp_generator.py +265 -0
- tools/observability/__init__.py +100 -0
- tools/observability/genai_attributes.py +88 -0
- tools/observability/instrumentation.py +140 -0
- tools/observability/mlflow_exporter.py +193 -0
- tools/observability/otel_tracer.py +168 -0
- tools/observability/provenance/__init__.py +3 -0
- tools/observability/provenance/prov_recorder.py +322 -0
- tools/observability/shap/__init__.py +3 -0
- tools/observability/shap/agent_shap.py +274 -0
- tools/observability/sqlite_tracer.py +360 -0
- tools/observability/trace_context.py +205 -0
- tools/observability/tracer.py +230 -0
- tools/orchestration/__init__.py +1 -0
- tools/orchestration/peer_channels.py +254 -0
- tools/orchestration/saga_coordinator.py +390 -0
- tools/project/__init__.py +1 -0
- tools/project/manifest_loader.py +418 -0
- tools/project/project_create.py +350 -0
- tools/project/project_list.py +171 -0
- tools/project/project_scaffold.py +1715 -0
- tools/project/project_status.py +478 -0
- tools/project/session_context_builder.py +752 -0
- tools/project/validate_manifest.py +54 -0
- tools/rag/corrective_rag.py +582 -0
- tools/rag/source_registry.py +482 -0
- tools/requirements/__init__.py +1 -0
- tools/requirements/ai_governance_scorer.py +207 -0
- tools/requirements/boundary_analyzer.py +1281 -0
- tools/requirements/clarification_engine.py +605 -0
- tools/requirements/complexity_scorer.py +369 -0
- tools/requirements/consistency_analyzer.py +789 -0
- tools/requirements/constitution_manager.py +592 -0
- tools/requirements/decomposition_engine.py +764 -0
- tools/requirements/document_extractor.py +1002 -0
- tools/requirements/elicitation_techniques.py +508 -0
- tools/requirements/gap_detector.py +260 -0
- tools/requirements/intake_engine.py +2175 -0
- tools/requirements/prd_generator.py +839 -0
- tools/requirements/prd_validator.py +584 -0
- tools/requirements/readiness_scorer.py +302 -0
- tools/requirements/spec_organizer.py +1015 -0
- tools/requirements/spec_quality_checker.py +1083 -0
- tools/requirements/traceability_builder.py +566 -0
- tools/research/__init__.py +3 -0
- tools/research/academic_scanner.py +130 -0
- tools/research/build_buy_analyzer.py +229 -0
- tools/research/challenge_scorer.py +280 -0
- tools/research/community_scanner.py +174 -0
- tools/research/cross_engine_bridge.py +124 -0
- tools/research/dossier_generator.py +305 -0
- tools/research/landscape_scanner.py +315 -0
- tools/research/regulatory_scanner.py +248 -0
- tools/research/research_manager.py +469 -0
- tools/research/source_scanner.py +150 -0
- tools/research/vertical_loader.py +118 -0
- tools/saas/__init__.py +0 -0
- tools/saas/licensing/__init__.py +0 -0
- tools/saas/licensing/license_validator.py +345 -0
- tools/scaffold/__init__.py +2 -0
- tools/scaffold/golden_path.py +504 -0
- tools/security/__init__.py +1 -0
- tools/security/agent_output_validator.py +330 -0
- tools/security/agent_trust_scorer.py +652 -0
- tools/security/ai_bom_generator.py +718 -0
- tools/security/ai_telemetry_logger.py +469 -0
- tools/security/atlas_red_team.py +541 -0
- tools/security/code_pattern_scanner.py +382 -0
- tools/security/confabulation_detector.py +265 -0
- tools/security/container_scanner.py +489 -0
- tools/security/dependency_auditor.py +942 -0
- tools/security/endpoint_security_scanner.py +626 -0
- tools/security/mcp_tool_authorizer.py +242 -0
- tools/security/output_verifier.py +427 -0
- tools/security/prompt_injection_detector.py +737 -0
- tools/security/sast_runner.py +946 -0
- tools/security/secret_detector.py +376 -0
- tools/security/threat_modeler.py +678 -0
- tools/security/tool_chain_validator.py +357 -0
- tools/security/vuln_scanner.py +536 -0
- tools/simulation/__init__.py +2 -0
- tools/simulation/ato_simulator.py +517 -0
- tools/simulation/coa_generator.py +1539 -0
- tools/simulation/monte_carlo.py +745 -0
- tools/simulation/scenario_manager.py +1060 -0
- tools/simulation/simulation_engine.py +1091 -0
- tools/simulator/__init__.py +2 -0
- tools/simulator/sim_runner.py +272 -0
- tools/supply_chain/__init__.py +2 -0
- tools/supply_chain/cve_triager.py +690 -0
- tools/supply_chain/dependency_graph.py +630 -0
- tools/supply_chain/isa_manager.py +526 -0
- tools/supply_chain/scrm_assessor.py +531 -0
- tools/supply_chain/slsa_verifier.py +473 -0
- tools/testing/__init__.py +2 -0
- tools/testing/acceptance_validator.py +411 -0
- tools/testing/api_surface_extractor.py +749 -0
- tools/testing/claude_dir_validator.py +831 -0
- tools/testing/data_types.py +199 -0
- tools/testing/e2e_runner.py +715 -0
- tools/testing/fuzz_cli.py +306 -0
- tools/testing/health_check.py +483 -0
- tools/testing/platform_check.py +143 -0
- tools/testing/production_audit.py +1836 -0
- tools/testing/production_remediate.py +803 -0
- tools/testing/screenshot_validator.py +538 -0
- tools/testing/smoke_test.py +283 -0
- tools/testing/test_agent_models.py +117 -0
- tools/testing/test_orchestrator.py +957 -0
- tools/testing/utils.py +229 -0
- tools/writeguard/__init__.py +1 -0
- tools/writeguard/main.py +1 -0
- tools/writing/__init__.py +7 -0
- tools/writing/ai_content_detector.py +316 -0
- tools/writing/analysis_engine.py +454 -0
- tools/writing/batch_analyzer.py +276 -0
- tools/writing/coherence_analyzer.py +221 -0
- tools/writing/govcon_bridge.py +509 -0
- tools/writing/grammar_checker.py +270 -0
- tools/writing/plagiarism_detector.py +106 -0
- tools/writing/readability_scorer.py +201 -0
- tools/writing/rewriter.py +96 -0
- tools/writing/signal_registrar.py +167 -0
- tools/writing/snippet_manager.py +276 -0
- tools/writing/style_enforcer.py +220 -0
- tools/writing/style_guide_manager.py +438 -0
- tools/writing/tone_profiler.py +168 -0
|
@@ -0,0 +1,1649 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# CUI // SP-CTI
|
|
3
|
+
"""IV&V certification report generator per IEEE 1012.
|
|
4
|
+
|
|
5
|
+
Loads ivv_report_template.md, queries ivv_assessments, ivv_findings, and
|
|
6
|
+
ivv_certifications tables, generates a comprehensive IV&V certification report
|
|
7
|
+
with verification/validation scores and certification recommendation."""
|
|
8
|
+
|
|
9
|
+
import argparse
|
|
10
|
+
import json
|
|
11
|
+
import re
|
|
12
|
+
import sys
|
|
13
|
+
from datetime import datetime, timedelta, timezone
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
from tools.db.storage import get_connection
|
|
16
|
+
DB_PATH = None # Storage layer handles path resolution (D-DB-20)
|
|
17
|
+
|
|
18
|
+
BASE_DIR = Path(__file__).resolve().parent.parent.parent
|
|
19
|
+
IVV_TEMPLATE_PATH = BASE_DIR / "context" / "compliance" / "ivv_report_template.md"
|
|
20
|
+
IVV_REQUIREMENTS_PATH = BASE_DIR / "context" / "compliance" / "ivv_requirements.json"
|
|
21
|
+
|
|
22
|
+
# Process areas per IEEE 1012 as defined in ivv_requirements.json
|
|
23
|
+
PROCESS_AREAS = [
|
|
24
|
+
"Requirements Verification",
|
|
25
|
+
"Design Verification",
|
|
26
|
+
"Code Verification",
|
|
27
|
+
"Test Verification",
|
|
28
|
+
"Integration Verification",
|
|
29
|
+
"Traceability Analysis",
|
|
30
|
+
"Security Verification",
|
|
31
|
+
"Build/Deploy Verification",
|
|
32
|
+
"Process Compliance",
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
# Which process areas contribute to the Verification score
|
|
36
|
+
VERIFICATION_AREAS = [
|
|
37
|
+
"Requirements Verification",
|
|
38
|
+
"Design Verification",
|
|
39
|
+
"Code Verification",
|
|
40
|
+
"Traceability Analysis",
|
|
41
|
+
"Security Verification",
|
|
42
|
+
"Build/Deploy Verification",
|
|
43
|
+
"Process Compliance",
|
|
44
|
+
]
|
|
45
|
+
|
|
46
|
+
# Which process areas contribute to the Validation score
|
|
47
|
+
VALIDATION_AREAS = [
|
|
48
|
+
"Test Verification",
|
|
49
|
+
"Integration Verification",
|
|
50
|
+
]
|
|
51
|
+
|
|
52
|
+
# Status weighting for score calculation
|
|
53
|
+
IVV_STATUS_WEIGHTS = {
|
|
54
|
+
"pass": 1.0,
|
|
55
|
+
"partial": 0.5,
|
|
56
|
+
"fail": 0.0,
|
|
57
|
+
"deferred": 0.0,
|
|
58
|
+
"not_assessed": 0.0,
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
# Severity ordering for consistent output
|
|
62
|
+
SEVERITY_ORDER = ["critical", "high", "moderate", "low"]
|
|
63
|
+
|
|
64
|
+
# Finding statuses for summary
|
|
65
|
+
FINDING_STATUSES = ["open", "in_progress", "resolved", "accepted_risk", "deferred"]
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
# ---------------------------------------------------------------------------
|
|
69
|
+
# Helper functions
|
|
70
|
+
# ---------------------------------------------------------------------------
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def _load_template(template_path=None):
|
|
74
|
+
"""Load the IV&V report template markdown.
|
|
75
|
+
|
|
76
|
+
If the template file does not exist a minimal built-in template is
|
|
77
|
+
returned so the generator can still produce a useful report.
|
|
78
|
+
"""
|
|
79
|
+
path = template_path or IVV_TEMPLATE_PATH
|
|
80
|
+
if path.exists():
|
|
81
|
+
with open(path, "r", encoding="utf-8") as f:
|
|
82
|
+
return f.read()
|
|
83
|
+
|
|
84
|
+
# Fallback minimal template when file is missing
|
|
85
|
+
return _builtin_template()
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def _builtin_template():
|
|
89
|
+
"""Return a minimal built-in IV&V report template."""
|
|
90
|
+
return (
|
|
91
|
+
"{{cui_banner_top}}\n\n"
|
|
92
|
+
"# Independent Verification & Validation (IV&V) Certification Report\n\n"
|
|
93
|
+
"**Project:** {{project_name}} \n"
|
|
94
|
+
"**Project ID:** {{project_id}} \n"
|
|
95
|
+
"**Classification:** {{classification}} \n"
|
|
96
|
+
"**Assessment Date:** {{assessment_date}} \n"
|
|
97
|
+
"**Report Version:** {{version}} \n"
|
|
98
|
+
"**IV&V Authority:** {{ivv_authority}} \n"
|
|
99
|
+
"**Framework:** IEEE 1012-2016, DoDI 5000.87 \n\n"
|
|
100
|
+
"---\n\n"
|
|
101
|
+
"## 1. Executive Summary\n\n"
|
|
102
|
+
"**Verification Score:** {{verification_score}}% \n"
|
|
103
|
+
"**Validation Score:** {{validation_score}}% \n"
|
|
104
|
+
"**Overall IV&V Score:** {{overall_score}}% \n"
|
|
105
|
+
"**Gate Result:** {{gate_result}} \n"
|
|
106
|
+
"**Certification Recommendation:** {{certification_recommendation}} \n\n"
|
|
107
|
+
"{{executive_summary}}\n\n"
|
|
108
|
+
"---\n\n"
|
|
109
|
+
"## 2. Independence Declaration\n\n"
|
|
110
|
+
"{{independence_declaration}}\n\n"
|
|
111
|
+
"---\n\n"
|
|
112
|
+
"## 3. Verification Results\n\n"
|
|
113
|
+
"### 3.1 Process Area Scores\n\n"
|
|
114
|
+
"{{process_area_scores_table}}\n\n"
|
|
115
|
+
"### 3.2 Process Area Details\n\n"
|
|
116
|
+
"{{process_area_details}}\n\n"
|
|
117
|
+
"---\n\n"
|
|
118
|
+
"## 4. Validation Results\n\n"
|
|
119
|
+
"### 4.1 Test Verification Results\n\n"
|
|
120
|
+
"{{test_verification_results}}\n\n"
|
|
121
|
+
"### 4.2 Integration Verification Results\n\n"
|
|
122
|
+
"{{integration_verification_results}}\n\n"
|
|
123
|
+
"---\n\n"
|
|
124
|
+
"## 5. Requirements Traceability Matrix Summary\n\n"
|
|
125
|
+
"{{rtm_summary}}\n\n"
|
|
126
|
+
"**RTM Coverage:** {{rtm_coverage}}% \n"
|
|
127
|
+
"**Requirements with Full Trace:** {{rtm_full_trace_count}} \n"
|
|
128
|
+
"**Requirements with Gaps:** {{rtm_gap_count}} \n"
|
|
129
|
+
"**Orphan Tests:** {{rtm_orphan_tests}} \n\n"
|
|
130
|
+
"---\n\n"
|
|
131
|
+
"## 6. IV&V Findings\n\n"
|
|
132
|
+
"### 6.1 Critical Findings\n\n"
|
|
133
|
+
"{{critical_findings}}\n\n"
|
|
134
|
+
"### 6.2 High Findings\n\n"
|
|
135
|
+
"{{high_findings}}\n\n"
|
|
136
|
+
"### 6.3 Moderate Findings\n\n"
|
|
137
|
+
"{{moderate_findings}}\n\n"
|
|
138
|
+
"### 6.4 Low Findings\n\n"
|
|
139
|
+
"{{low_findings}}\n\n"
|
|
140
|
+
"### 6.5 Findings Summary\n\n"
|
|
141
|
+
"| Severity | Open | Resolved | Accepted Risk | Deferred | Total |\n"
|
|
142
|
+
"|----------|------|----------|---------------|----------|-------|\n"
|
|
143
|
+
"{{findings_summary_table}}\n\n"
|
|
144
|
+
"---\n\n"
|
|
145
|
+
"## 7. Certification Recommendation\n\n"
|
|
146
|
+
"**Recommendation:** {{certification_recommendation}} \n\n"
|
|
147
|
+
"### Criteria Applied:\n"
|
|
148
|
+
"- **CERTIFY:** Overall score >= 80%, 0 critical findings, all process areas >= 60%\n"
|
|
149
|
+
"- **CONDITIONAL:** Overall score >= 60%, 0 critical findings, conditions listed\n"
|
|
150
|
+
"- **DENY:** Overall score < 60% OR critical findings unresolved\n\n"
|
|
151
|
+
"### Conditions (if applicable):\n\n"
|
|
152
|
+
"{{conditions}}\n\n"
|
|
153
|
+
"---\n\n"
|
|
154
|
+
"## 8. Evidence Index\n\n"
|
|
155
|
+
"{{evidence_index}}\n\n"
|
|
156
|
+
"---\n\n"
|
|
157
|
+
"## 9. Assessment Methodology\n\n"
|
|
158
|
+
"This assessment was conducted using the ICDEV IV&V Assessor tool against "
|
|
159
|
+
"the IEEE 1012 requirements catalog (30 requirements across 9 process areas).\n\n"
|
|
160
|
+
"**Scoring Formula:**\n"
|
|
161
|
+
"- Verification Score = average of process area pass rates\n"
|
|
162
|
+
"- Validation Score = average of Test + Integration area pass rates\n"
|
|
163
|
+
"- Overall Score = 0.6 x Verification + 0.4 x Validation\n\n"
|
|
164
|
+
"**Gate Logic:** PASS if 0 critical findings remain open\n\n"
|
|
165
|
+
"---\n\n"
|
|
166
|
+
"**Prepared by:** {{ivv_authority}} \n"
|
|
167
|
+
"**Date:** {{assessment_date}} \n"
|
|
168
|
+
"**Next Review:** {{next_review_date}} \n\n"
|
|
169
|
+
"{{cui_banner_bottom}}\n"
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def _get_project_data(conn, project_id):
|
|
174
|
+
"""Load project record from database."""
|
|
175
|
+
row = conn.execute(
|
|
176
|
+
"SELECT * FROM projects WHERE id = ?", (project_id,)
|
|
177
|
+
).fetchone()
|
|
178
|
+
if not row:
|
|
179
|
+
raise ValueError(f"Project '{project_id}' not found in database.")
|
|
180
|
+
return dict(row)
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def _load_cui_config():
|
|
184
|
+
"""Load CUI marking configuration.
|
|
185
|
+
|
|
186
|
+
Attempts to import load_cui_config from the cui_marker module;
|
|
187
|
+
falls back to sensible defaults if unavailable.
|
|
188
|
+
"""
|
|
189
|
+
try:
|
|
190
|
+
from tools.compliance.cui_marker import load_cui_config as _load
|
|
191
|
+
return _load()
|
|
192
|
+
except Exception:
|
|
193
|
+
pass
|
|
194
|
+
|
|
195
|
+
# Try relative import via file location
|
|
196
|
+
try:
|
|
197
|
+
cui_marker_path = Path(__file__).resolve().parent / "cui_marker.py"
|
|
198
|
+
if cui_marker_path.exists():
|
|
199
|
+
import importlib.util
|
|
200
|
+
spec = importlib.util.spec_from_file_location(
|
|
201
|
+
"cui_marker", cui_marker_path
|
|
202
|
+
)
|
|
203
|
+
mod = importlib.util.module_from_spec(spec)
|
|
204
|
+
spec.loader.exec_module(mod)
|
|
205
|
+
return mod.load_cui_config()
|
|
206
|
+
except Exception:
|
|
207
|
+
pass
|
|
208
|
+
|
|
209
|
+
return {
|
|
210
|
+
"banner_top": "CUI // SP-CTI",
|
|
211
|
+
"banner_bottom": "CUI // SP-CTI",
|
|
212
|
+
"document_header": (
|
|
213
|
+
"////////////////////////////////////////////////////////////////////\n"
|
|
214
|
+
"CONTROLLED UNCLASSIFIED INFORMATION (CUI) // SP-CTI\n"
|
|
215
|
+
"Distribution: Distribution D -- Authorized DoD Personnel Only\n"
|
|
216
|
+
"////////////////////////////////////////////////////////////////////"
|
|
217
|
+
),
|
|
218
|
+
"document_footer": (
|
|
219
|
+
"////////////////////////////////////////////////////////////////////\n"
|
|
220
|
+
"CUI // SP-CTI | Department of Defense\n"
|
|
221
|
+
"////////////////////////////////////////////////////////////////////"
|
|
222
|
+
),
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
def _load_ivv_requirements():
|
|
227
|
+
"""Load IV&V requirements catalog from JSON.
|
|
228
|
+
|
|
229
|
+
Returns the full catalog dict with 'metadata' and 'requirements' keys.
|
|
230
|
+
Falls back to an empty catalog if the file is missing.
|
|
231
|
+
"""
|
|
232
|
+
if not IVV_REQUIREMENTS_PATH.exists():
|
|
233
|
+
return {"metadata": {}, "requirements": []}
|
|
234
|
+
|
|
235
|
+
with open(IVV_REQUIREMENTS_PATH, "r", encoding="utf-8") as f:
|
|
236
|
+
data = json.load(f)
|
|
237
|
+
return data
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
# ---------------------------------------------------------------------------
|
|
241
|
+
# Data retrieval
|
|
242
|
+
# ---------------------------------------------------------------------------
|
|
243
|
+
|
|
244
|
+
def _get_ivv_assessments(conn, project_id):
|
|
245
|
+
"""Retrieve all IV&V assessment results for a project."""
|
|
246
|
+
rows = conn.execute(
|
|
247
|
+
"""SELECT * FROM ivv_assessments
|
|
248
|
+
WHERE project_id = ?
|
|
249
|
+
ORDER BY process_area, requirement_id""",
|
|
250
|
+
(project_id,),
|
|
251
|
+
).fetchall()
|
|
252
|
+
return [dict(r) for r in rows]
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
def _get_ivv_findings(conn, project_id):
|
|
256
|
+
"""Retrieve all IV&V findings for a project."""
|
|
257
|
+
rows = conn.execute(
|
|
258
|
+
"""SELECT * FROM ivv_findings
|
|
259
|
+
WHERE project_id = ?
|
|
260
|
+
ORDER BY severity, finding_id""",
|
|
261
|
+
(project_id,),
|
|
262
|
+
).fetchall()
|
|
263
|
+
return [dict(r) for r in rows]
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
def _get_ivv_certification(conn, project_id):
|
|
267
|
+
"""Retrieve IV&V certification status for a project."""
|
|
268
|
+
row = conn.execute(
|
|
269
|
+
"SELECT * FROM ivv_certifications WHERE project_id = ?",
|
|
270
|
+
(project_id,),
|
|
271
|
+
).fetchone()
|
|
272
|
+
return dict(row) if row else {}
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
# ---------------------------------------------------------------------------
|
|
276
|
+
# Score calculation
|
|
277
|
+
# ---------------------------------------------------------------------------
|
|
278
|
+
|
|
279
|
+
def _calculate_process_area_scores(assessments):
|
|
280
|
+
"""Calculate a pass-rate score for each IV&V process area.
|
|
281
|
+
|
|
282
|
+
Score formula per area:
|
|
283
|
+
score = 100 * (pass_count + partial_count * 0.5) / total_scoreable
|
|
284
|
+
|
|
285
|
+
``not_applicable`` assessments are excluded from the denominator.
|
|
286
|
+
|
|
287
|
+
Returns:
|
|
288
|
+
dict mapping process area name to a dict with ``score``, per-status
|
|
289
|
+
counts, and ``total`` / ``scoreable`` tallies.
|
|
290
|
+
"""
|
|
291
|
+
area_data = {area: [] for area in PROCESS_AREAS}
|
|
292
|
+
for a in assessments:
|
|
293
|
+
pa = a.get("process_area")
|
|
294
|
+
if pa in area_data:
|
|
295
|
+
area_data[pa].append(a)
|
|
296
|
+
|
|
297
|
+
results = {}
|
|
298
|
+
for area in PROCESS_AREAS:
|
|
299
|
+
items = area_data[area]
|
|
300
|
+
total = len(items)
|
|
301
|
+
|
|
302
|
+
if total == 0:
|
|
303
|
+
results[area] = {
|
|
304
|
+
"score": 0.0,
|
|
305
|
+
"total": 0,
|
|
306
|
+
"scoreable": 0,
|
|
307
|
+
"pass": 0,
|
|
308
|
+
"partial": 0,
|
|
309
|
+
"fail": 0,
|
|
310
|
+
"deferred": 0,
|
|
311
|
+
"not_assessed": 0,
|
|
312
|
+
"not_applicable": 0,
|
|
313
|
+
}
|
|
314
|
+
continue
|
|
315
|
+
|
|
316
|
+
pass_count = sum(
|
|
317
|
+
1 for i in items if i.get("status") == "pass"
|
|
318
|
+
)
|
|
319
|
+
partial_count = sum(
|
|
320
|
+
1 for i in items if i.get("status") == "partial"
|
|
321
|
+
)
|
|
322
|
+
fail_count = sum(
|
|
323
|
+
1 for i in items if i.get("status") == "fail"
|
|
324
|
+
)
|
|
325
|
+
deferred_count = sum(
|
|
326
|
+
1 for i in items if i.get("status") == "deferred"
|
|
327
|
+
)
|
|
328
|
+
not_assessed_count = sum(
|
|
329
|
+
1 for i in items if i.get("status") == "not_assessed"
|
|
330
|
+
)
|
|
331
|
+
not_applicable_count = sum(
|
|
332
|
+
1 for i in items if i.get("status") == "not_applicable"
|
|
333
|
+
)
|
|
334
|
+
|
|
335
|
+
# Denominator excludes not_applicable
|
|
336
|
+
scoreable = total - not_applicable_count
|
|
337
|
+
if scoreable > 0:
|
|
338
|
+
score = 100.0 * (
|
|
339
|
+
pass_count * IVV_STATUS_WEIGHTS["pass"]
|
|
340
|
+
+ partial_count * IVV_STATUS_WEIGHTS["partial"]
|
|
341
|
+
) / scoreable
|
|
342
|
+
else:
|
|
343
|
+
# All items are N/A — treat as fully compliant
|
|
344
|
+
score = 100.0
|
|
345
|
+
|
|
346
|
+
results[area] = {
|
|
347
|
+
"score": round(score, 1),
|
|
348
|
+
"total": total,
|
|
349
|
+
"scoreable": scoreable,
|
|
350
|
+
"pass": pass_count,
|
|
351
|
+
"partial": partial_count,
|
|
352
|
+
"fail": fail_count,
|
|
353
|
+
"deferred": deferred_count,
|
|
354
|
+
"not_assessed": not_assessed_count,
|
|
355
|
+
"not_applicable": not_applicable_count,
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
return results
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
def _calculate_verification_score(area_scores):
|
|
362
|
+
"""Calculate the aggregate Verification score.
|
|
363
|
+
|
|
364
|
+
Average of the scores for the 7 verification process areas. Areas with
|
|
365
|
+
zero scoreable items are excluded from the average.
|
|
366
|
+
"""
|
|
367
|
+
scores = []
|
|
368
|
+
for area in VERIFICATION_AREAS:
|
|
369
|
+
info = area_scores.get(area, {})
|
|
370
|
+
if info.get("scoreable", 0) > 0 or info.get("total", 0) > 0:
|
|
371
|
+
scores.append(info.get("score", 0.0))
|
|
372
|
+
|
|
373
|
+
if not scores:
|
|
374
|
+
return 0.0
|
|
375
|
+
return round(sum(scores) / len(scores), 1)
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
def _calculate_validation_score(area_scores):
|
|
379
|
+
"""Calculate the aggregate Validation score.
|
|
380
|
+
|
|
381
|
+
Average of the scores for Test Verification and Integration Verification.
|
|
382
|
+
Areas with zero scoreable items are excluded from the average.
|
|
383
|
+
"""
|
|
384
|
+
scores = []
|
|
385
|
+
for area in VALIDATION_AREAS:
|
|
386
|
+
info = area_scores.get(area, {})
|
|
387
|
+
if info.get("scoreable", 0) > 0 or info.get("total", 0) > 0:
|
|
388
|
+
scores.append(info.get("score", 0.0))
|
|
389
|
+
|
|
390
|
+
if not scores:
|
|
391
|
+
return 0.0
|
|
392
|
+
return round(sum(scores) / len(scores), 1)
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
def _calculate_overall_score(verification_score, validation_score):
|
|
396
|
+
"""Calculate the weighted overall IV&V score.
|
|
397
|
+
|
|
398
|
+
Overall = 0.6 * Verification + 0.4 * Validation
|
|
399
|
+
"""
|
|
400
|
+
overall = 0.6 * verification_score + 0.4 * validation_score
|
|
401
|
+
return round(overall, 1)
|
|
402
|
+
|
|
403
|
+
|
|
404
|
+
def _determine_certification_recommendation(overall_score, area_scores, findings):
|
|
405
|
+
"""Determine the IV&V certification recommendation.
|
|
406
|
+
|
|
407
|
+
Rules:
|
|
408
|
+
CERTIFY: overall >= 80, 0 critical open findings, all areas >= 60
|
|
409
|
+
CONDITIONAL: overall >= 60, 0 critical open findings
|
|
410
|
+
DENY: overall < 60 OR any critical findings are open
|
|
411
|
+
|
|
412
|
+
Returns:
|
|
413
|
+
tuple of (recommendation_str, reason_str)
|
|
414
|
+
"""
|
|
415
|
+
# Count critical open findings
|
|
416
|
+
critical_open = sum(
|
|
417
|
+
1 for f in findings
|
|
418
|
+
if f.get("severity") == "critical"
|
|
419
|
+
and f.get("status") in ("open", "in_progress")
|
|
420
|
+
)
|
|
421
|
+
|
|
422
|
+
# Check if all areas meet the 60% minimum
|
|
423
|
+
all_areas_above_60 = True
|
|
424
|
+
areas_below_60 = []
|
|
425
|
+
for area in PROCESS_AREAS:
|
|
426
|
+
info = area_scores.get(area, {})
|
|
427
|
+
# Only evaluate areas that have assessments
|
|
428
|
+
if info.get("total", 0) > 0 and info.get("score", 0.0) < 60.0:
|
|
429
|
+
all_areas_above_60 = False
|
|
430
|
+
areas_below_60.append(area)
|
|
431
|
+
|
|
432
|
+
# Decision logic
|
|
433
|
+
if critical_open > 0:
|
|
434
|
+
reason = (
|
|
435
|
+
f"DENY: {critical_open} critical finding(s) remain open. "
|
|
436
|
+
"All critical findings must be resolved before certification."
|
|
437
|
+
)
|
|
438
|
+
return "DENY", reason
|
|
439
|
+
|
|
440
|
+
if overall_score < 60.0:
|
|
441
|
+
reason = (
|
|
442
|
+
f"DENY: Overall score ({overall_score:.1f}%) is below the 60% "
|
|
443
|
+
"minimum threshold required for certification."
|
|
444
|
+
)
|
|
445
|
+
return "DENY", reason
|
|
446
|
+
|
|
447
|
+
if overall_score >= 80.0 and all_areas_above_60:
|
|
448
|
+
reason = (
|
|
449
|
+
f"CERTIFY: Overall score ({overall_score:.1f}%) meets the 80% "
|
|
450
|
+
"threshold, zero critical open findings, and all process areas "
|
|
451
|
+
"meet the 60% minimum."
|
|
452
|
+
)
|
|
453
|
+
return "CERTIFY", reason
|
|
454
|
+
|
|
455
|
+
# Conditional case: overall >= 60 but either < 80 or some areas below 60
|
|
456
|
+
condition_parts = []
|
|
457
|
+
if overall_score < 80.0:
|
|
458
|
+
condition_parts.append(
|
|
459
|
+
f"Overall score ({overall_score:.1f}%) is below the 80% full "
|
|
460
|
+
"certification threshold"
|
|
461
|
+
)
|
|
462
|
+
if not all_areas_above_60:
|
|
463
|
+
area_list = ", ".join(areas_below_60)
|
|
464
|
+
condition_parts.append(
|
|
465
|
+
f"The following process areas are below 60%: {area_list}"
|
|
466
|
+
)
|
|
467
|
+
|
|
468
|
+
reason = "CONDITIONAL: " + "; ".join(condition_parts) + "."
|
|
469
|
+
return "CONDITIONAL", reason
|
|
470
|
+
|
|
471
|
+
|
|
472
|
+
# ---------------------------------------------------------------------------
|
|
473
|
+
# Section builders
|
|
474
|
+
# ---------------------------------------------------------------------------
|
|
475
|
+
|
|
476
|
+
def _build_process_area_scores_table(area_scores):
|
|
477
|
+
"""Build a markdown table summarizing per-area IV&V scores."""
|
|
478
|
+
lines = [
|
|
479
|
+
"| Process Area | Score | Total | Pass | Partial | Fail | Deferred | N/A | Not Assessed |",
|
|
480
|
+
"|--------------|------:|------:|-----:|--------:|-----:|---------:|----:|-------------:|",
|
|
481
|
+
]
|
|
482
|
+
for area in PROCESS_AREAS:
|
|
483
|
+
s = area_scores.get(area, {})
|
|
484
|
+
lines.append(
|
|
485
|
+
f"| {area} "
|
|
486
|
+
f"| {s.get('score', 0.0):.1f}% "
|
|
487
|
+
f"| {s.get('total', 0)} "
|
|
488
|
+
f"| {s.get('pass', 0)} "
|
|
489
|
+
f"| {s.get('partial', 0)} "
|
|
490
|
+
f"| {s.get('fail', 0)} "
|
|
491
|
+
f"| {s.get('deferred', 0)} "
|
|
492
|
+
f"| {s.get('not_applicable', 0)} "
|
|
493
|
+
f"| {s.get('not_assessed', 0)} |"
|
|
494
|
+
)
|
|
495
|
+
|
|
496
|
+
# Totals row
|
|
497
|
+
totals = {
|
|
498
|
+
"total": sum(s.get("total", 0) for s in area_scores.values()),
|
|
499
|
+
"pass": sum(s.get("pass", 0) for s in area_scores.values()),
|
|
500
|
+
"partial": sum(s.get("partial", 0) for s in area_scores.values()),
|
|
501
|
+
"fail": sum(s.get("fail", 0) for s in area_scores.values()),
|
|
502
|
+
"deferred": sum(s.get("deferred", 0) for s in area_scores.values()),
|
|
503
|
+
"not_applicable": sum(
|
|
504
|
+
s.get("not_applicable", 0) for s in area_scores.values()
|
|
505
|
+
),
|
|
506
|
+
"not_assessed": sum(
|
|
507
|
+
s.get("not_assessed", 0) for s in area_scores.values()
|
|
508
|
+
),
|
|
509
|
+
}
|
|
510
|
+
lines.append(
|
|
511
|
+
f"| **Total** | -- "
|
|
512
|
+
f"| **{totals['total']}** "
|
|
513
|
+
f"| **{totals['pass']}** "
|
|
514
|
+
f"| **{totals['partial']}** "
|
|
515
|
+
f"| **{totals['fail']}** "
|
|
516
|
+
f"| **{totals['deferred']}** "
|
|
517
|
+
f"| **{totals['not_applicable']}** "
|
|
518
|
+
f"| **{totals['not_assessed']}** |"
|
|
519
|
+
)
|
|
520
|
+
return "\n".join(lines)
|
|
521
|
+
|
|
522
|
+
|
|
523
|
+
def _build_process_area_details(assessments, area_scores):
|
|
524
|
+
"""Build markdown detail sections for each process area.
|
|
525
|
+
|
|
526
|
+
Each area gets a sub-heading and a table listing every requirement
|
|
527
|
+
with its status, evidence description, and notes.
|
|
528
|
+
"""
|
|
529
|
+
area_data = {area: [] for area in PROCESS_AREAS}
|
|
530
|
+
for a in assessments:
|
|
531
|
+
pa = a.get("process_area")
|
|
532
|
+
if pa in area_data:
|
|
533
|
+
area_data[pa].append(a)
|
|
534
|
+
|
|
535
|
+
sections = []
|
|
536
|
+
for area in PROCESS_AREAS:
|
|
537
|
+
items = area_data[area]
|
|
538
|
+
s = area_scores.get(area, {})
|
|
539
|
+
score = s.get("score", 0.0)
|
|
540
|
+
v_type = "Verification" if area in VERIFICATION_AREAS else "Validation"
|
|
541
|
+
|
|
542
|
+
sections.append(f"#### {area} ({score:.1f}%) — {v_type}")
|
|
543
|
+
sections.append("")
|
|
544
|
+
|
|
545
|
+
if not items:
|
|
546
|
+
sections.append(
|
|
547
|
+
"*No assessments recorded for this process area.*"
|
|
548
|
+
)
|
|
549
|
+
sections.append("")
|
|
550
|
+
continue
|
|
551
|
+
|
|
552
|
+
sections.append(
|
|
553
|
+
"| Req ID | Title | Status | Evidence | Notes |"
|
|
554
|
+
)
|
|
555
|
+
sections.append(
|
|
556
|
+
"|--------|-------|--------|----------|-------|"
|
|
557
|
+
)
|
|
558
|
+
for item in sorted(items, key=lambda x: x.get("requirement_id", "")):
|
|
559
|
+
req_id = item.get("requirement_id", "N/A")
|
|
560
|
+
# Attempt to get the title from the automation_result field
|
|
561
|
+
# which may contain structured data
|
|
562
|
+
title = ""
|
|
563
|
+
auto_result = item.get("automation_result", "")
|
|
564
|
+
if auto_result:
|
|
565
|
+
try:
|
|
566
|
+
auto_data = json.loads(auto_result)
|
|
567
|
+
title = auto_data.get("title", "")
|
|
568
|
+
except (json.JSONDecodeError, TypeError):
|
|
569
|
+
title = ""
|
|
570
|
+
if not title:
|
|
571
|
+
title = req_id # Fallback to the requirement ID
|
|
572
|
+
|
|
573
|
+
status = item.get("status", "not_assessed")
|
|
574
|
+
evidence = (
|
|
575
|
+
(item.get("evidence_description") or "")
|
|
576
|
+
.replace("\n", " ")
|
|
577
|
+
.strip()
|
|
578
|
+
)
|
|
579
|
+
notes = (
|
|
580
|
+
(item.get("notes") or "").replace("\n", " ").strip()
|
|
581
|
+
)
|
|
582
|
+
|
|
583
|
+
# Truncate long fields for table readability
|
|
584
|
+
if len(title) > 50:
|
|
585
|
+
title = title[:47] + "..."
|
|
586
|
+
if len(evidence) > 60:
|
|
587
|
+
evidence = evidence[:57] + "..."
|
|
588
|
+
if len(notes) > 60:
|
|
589
|
+
notes = notes[:57] + "..."
|
|
590
|
+
|
|
591
|
+
# Status badge for readability
|
|
592
|
+
status_badge = _status_badge(status)
|
|
593
|
+
|
|
594
|
+
sections.append(
|
|
595
|
+
f"| {req_id} | {title} | {status_badge} "
|
|
596
|
+
f"| {evidence} | {notes} |"
|
|
597
|
+
)
|
|
598
|
+
sections.append("")
|
|
599
|
+
|
|
600
|
+
return "\n".join(sections)
|
|
601
|
+
|
|
602
|
+
|
|
603
|
+
def _status_badge(status):
|
|
604
|
+
"""Return a markdown-friendly status indicator."""
|
|
605
|
+
badges = {
|
|
606
|
+
"pass": "PASS",
|
|
607
|
+
"partial": "PARTIAL",
|
|
608
|
+
"fail": "**FAIL**",
|
|
609
|
+
"deferred": "DEFERRED",
|
|
610
|
+
"not_assessed": "NOT ASSESSED",
|
|
611
|
+
"not_applicable": "N/A",
|
|
612
|
+
}
|
|
613
|
+
return badges.get(status, status.upper() if status else "UNKNOWN")
|
|
614
|
+
|
|
615
|
+
|
|
616
|
+
def _build_findings_by_severity(findings):
|
|
617
|
+
"""Build per-severity sections of IV&V findings.
|
|
618
|
+
|
|
619
|
+
Returns a dict mapping severity to a markdown string.
|
|
620
|
+
"""
|
|
621
|
+
grouped = {sev: [] for sev in SEVERITY_ORDER}
|
|
622
|
+
for f in findings:
|
|
623
|
+
sev = f.get("severity", "low")
|
|
624
|
+
if sev in grouped:
|
|
625
|
+
grouped[sev].append(f)
|
|
626
|
+
|
|
627
|
+
result = {}
|
|
628
|
+
for sev in SEVERITY_ORDER:
|
|
629
|
+
items = grouped[sev]
|
|
630
|
+
if not items:
|
|
631
|
+
result[sev] = f"*No {sev} findings.*"
|
|
632
|
+
continue
|
|
633
|
+
|
|
634
|
+
lines = [
|
|
635
|
+
"| Finding ID | Process Area | Title | Status | Recommendation |",
|
|
636
|
+
"|------------|-------------|-------|--------|----------------|",
|
|
637
|
+
]
|
|
638
|
+
for f in sorted(items, key=lambda x: x.get("finding_id", "")):
|
|
639
|
+
fid = f.get("finding_id", "N/A")
|
|
640
|
+
pa = f.get("process_area", "N/A")
|
|
641
|
+
title = (f.get("title") or "").replace("\n", " ").strip()
|
|
642
|
+
status = f.get("status", "open")
|
|
643
|
+
rec = (
|
|
644
|
+
(f.get("recommendation") or "").replace("\n", " ").strip()
|
|
645
|
+
)
|
|
646
|
+
|
|
647
|
+
if len(title) > 50:
|
|
648
|
+
title = title[:47] + "..."
|
|
649
|
+
if len(rec) > 60:
|
|
650
|
+
rec = rec[:57] + "..."
|
|
651
|
+
|
|
652
|
+
lines.append(
|
|
653
|
+
f"| {fid} | {pa} | {title} | {status} | {rec} |"
|
|
654
|
+
)
|
|
655
|
+
|
|
656
|
+
result[sev] = "\n".join(lines)
|
|
657
|
+
|
|
658
|
+
return result
|
|
659
|
+
|
|
660
|
+
|
|
661
|
+
def _build_findings_summary_table(findings):
|
|
662
|
+
"""Build a summary table of findings by severity and status.
|
|
663
|
+
|
|
664
|
+
Returns the markdown rows (without header — the template provides the
|
|
665
|
+
header already).
|
|
666
|
+
"""
|
|
667
|
+
# Initialize counts grid
|
|
668
|
+
counts = {
|
|
669
|
+
sev: {st: 0 for st in FINDING_STATUSES}
|
|
670
|
+
for sev in SEVERITY_ORDER
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
for f in findings:
|
|
674
|
+
sev = f.get("severity", "low")
|
|
675
|
+
st = f.get("status", "open")
|
|
676
|
+
if sev in counts and st in counts[sev]:
|
|
677
|
+
counts[sev][st] += 1
|
|
678
|
+
|
|
679
|
+
lines = []
|
|
680
|
+
grand_total = 0
|
|
681
|
+
for sev in SEVERITY_ORDER:
|
|
682
|
+
c = counts[sev]
|
|
683
|
+
total = sum(c.values())
|
|
684
|
+
grand_total += total
|
|
685
|
+
lines.append(
|
|
686
|
+
f"| {sev.capitalize()} "
|
|
687
|
+
f"| {c.get('open', 0)} "
|
|
688
|
+
f"| {c.get('resolved', 0)} "
|
|
689
|
+
f"| {c.get('accepted_risk', 0)} "
|
|
690
|
+
f"| {c.get('deferred', 0)} "
|
|
691
|
+
f"| {total} |"
|
|
692
|
+
)
|
|
693
|
+
|
|
694
|
+
# Grand total row
|
|
695
|
+
total_open = sum(counts[s]["open"] for s in SEVERITY_ORDER)
|
|
696
|
+
total_resolved = sum(counts[s]["resolved"] for s in SEVERITY_ORDER)
|
|
697
|
+
total_accepted = sum(
|
|
698
|
+
counts[s]["accepted_risk"] for s in SEVERITY_ORDER
|
|
699
|
+
)
|
|
700
|
+
total_deferred = sum(counts[s]["deferred"] for s in SEVERITY_ORDER)
|
|
701
|
+
lines.append(
|
|
702
|
+
f"| **Total** "
|
|
703
|
+
f"| **{total_open}** "
|
|
704
|
+
f"| **{total_resolved}** "
|
|
705
|
+
f"| **{total_accepted}** "
|
|
706
|
+
f"| **{total_deferred}** "
|
|
707
|
+
f"| **{grand_total}** |"
|
|
708
|
+
)
|
|
709
|
+
|
|
710
|
+
return "\n".join(lines)
|
|
711
|
+
|
|
712
|
+
|
|
713
|
+
def _build_rtm_summary(conn, project_id):
|
|
714
|
+
"""Build an RTM summary section by looking for RTM data.
|
|
715
|
+
|
|
716
|
+
Attempts to find RTM JSON output from a previous traceability_matrix.py
|
|
717
|
+
run. Falls back to a placeholder if no data is found.
|
|
718
|
+
"""
|
|
719
|
+
# Try to find RTM JSON in the project directory
|
|
720
|
+
try:
|
|
721
|
+
project = _get_project_data(conn, project_id)
|
|
722
|
+
project_dir = project.get("directory_path", "")
|
|
723
|
+
if project_dir:
|
|
724
|
+
rtm_json_path = (
|
|
725
|
+
Path(project_dir) / "compliance" / "rtm" / "rtm-data.json"
|
|
726
|
+
)
|
|
727
|
+
if rtm_json_path.exists():
|
|
728
|
+
with open(rtm_json_path, "r", encoding="utf-8") as f:
|
|
729
|
+
rtm_data = json.load(f)
|
|
730
|
+
|
|
731
|
+
coverage = rtm_data.get("coverage", 0.0)
|
|
732
|
+
traced = rtm_data.get("traced", 0)
|
|
733
|
+
total = rtm_data.get("total_requirements", 0)
|
|
734
|
+
gaps = rtm_data.get("gaps", {})
|
|
735
|
+
gap_count = gaps.get("gap_count", 0)
|
|
736
|
+
orphan_count = len(gaps.get("orphan_tests", []))
|
|
737
|
+
|
|
738
|
+
lines = [
|
|
739
|
+
f"RTM data loaded from: `{rtm_json_path}`",
|
|
740
|
+
"",
|
|
741
|
+
f"- **Total Requirements:** {total}",
|
|
742
|
+
f"- **Fully Traced:** {traced}",
|
|
743
|
+
f"- **Coverage:** {coverage:.1f}%",
|
|
744
|
+
f"- **Gap Count:** {gap_count}",
|
|
745
|
+
f"- **Orphan Tests:** {orphan_count}",
|
|
746
|
+
]
|
|
747
|
+
return (
|
|
748
|
+
"\n".join(lines),
|
|
749
|
+
coverage,
|
|
750
|
+
traced,
|
|
751
|
+
gap_count,
|
|
752
|
+
orphan_count,
|
|
753
|
+
)
|
|
754
|
+
except Exception:
|
|
755
|
+
pass
|
|
756
|
+
|
|
757
|
+
# Fallback — no RTM data found
|
|
758
|
+
placeholder = (
|
|
759
|
+
"*No Requirements Traceability Matrix data found. "
|
|
760
|
+
"Run `python tools/compliance/traceability_matrix.py "
|
|
761
|
+
f"--project-id {project_id}` to generate RTM.*"
|
|
762
|
+
)
|
|
763
|
+
return placeholder, 0.0, 0, 0, 0
|
|
764
|
+
|
|
765
|
+
|
|
766
|
+
def _build_independence_declaration():
|
|
767
|
+
"""Return the standard IEEE 1012 independence statement.
|
|
768
|
+
|
|
769
|
+
This is the boilerplate independence declaration required by IEEE 1012
|
|
770
|
+
for any IV&V assessment to be considered independent.
|
|
771
|
+
"""
|
|
772
|
+
return (
|
|
773
|
+
"This Independent Verification and Validation assessment was "
|
|
774
|
+
"conducted separately from the development team per IEEE 1012 and "
|
|
775
|
+
"DoD requirements. The IV&V engine operates with:\n\n"
|
|
776
|
+
"- **Organizational Independence:** Separate assessment authority "
|
|
777
|
+
"from development\n"
|
|
778
|
+
"- **Technical Independence:** Independent analysis tools and "
|
|
779
|
+
"criteria\n"
|
|
780
|
+
"- **Financial Independence:** Assessment budget separate from "
|
|
781
|
+
"development\n"
|
|
782
|
+
"- **Authority:** Gate authority to block releases based on findings\n"
|
|
783
|
+
"\n"
|
|
784
|
+
"The IV&V assessor has no reporting relationship to the development "
|
|
785
|
+
"organization and maintains independent access to all project "
|
|
786
|
+
"artifacts, source code, test results, and configuration data. "
|
|
787
|
+
"Assessment criteria are derived from IEEE 1012-2016, DoDI 5000.87, "
|
|
788
|
+
"and NIST 800-53 Rev 5 security controls."
|
|
789
|
+
)
|
|
790
|
+
|
|
791
|
+
|
|
792
|
+
def _build_conditions(recommendation, area_scores, findings):
|
|
793
|
+
"""Build conditions text for CONDITIONAL recommendations.
|
|
794
|
+
|
|
795
|
+
Returns a markdown string describing what must be remediated for full
|
|
796
|
+
certification.
|
|
797
|
+
"""
|
|
798
|
+
if recommendation == "CERTIFY":
|
|
799
|
+
return "*No conditions — full certification recommended.*"
|
|
800
|
+
|
|
801
|
+
if recommendation == "DENY":
|
|
802
|
+
# List the blocking issues
|
|
803
|
+
lines = ["**Blocking Issues (must be resolved before resubmission):**", ""]
|
|
804
|
+
critical_open = [
|
|
805
|
+
f for f in findings
|
|
806
|
+
if f.get("severity") == "critical"
|
|
807
|
+
and f.get("status") in ("open", "in_progress")
|
|
808
|
+
]
|
|
809
|
+
if critical_open:
|
|
810
|
+
lines.append(
|
|
811
|
+
f"1. **{len(critical_open)} critical finding(s) "
|
|
812
|
+
"must be resolved:**"
|
|
813
|
+
)
|
|
814
|
+
for f in critical_open:
|
|
815
|
+
fid = f.get("finding_id", "N/A")
|
|
816
|
+
title = f.get("title", "N/A")
|
|
817
|
+
lines.append(f" - {fid}: {title}")
|
|
818
|
+
lines.append("")
|
|
819
|
+
|
|
820
|
+
areas_below_60 = [
|
|
821
|
+
area for area in PROCESS_AREAS
|
|
822
|
+
if area_scores.get(area, {}).get("total", 0) > 0
|
|
823
|
+
and area_scores.get(area, {}).get("score", 0.0) < 60.0
|
|
824
|
+
]
|
|
825
|
+
if areas_below_60:
|
|
826
|
+
lines.append(
|
|
827
|
+
"2. **Process areas below 60% minimum:**"
|
|
828
|
+
)
|
|
829
|
+
for area in areas_below_60:
|
|
830
|
+
score = area_scores[area]["score"]
|
|
831
|
+
lines.append(f" - {area}: {score:.1f}%")
|
|
832
|
+
lines.append("")
|
|
833
|
+
|
|
834
|
+
return "\n".join(lines)
|
|
835
|
+
|
|
836
|
+
# CONDITIONAL — list what needs improvement
|
|
837
|
+
lines = [
|
|
838
|
+
"**Conditions for Full Certification:**",
|
|
839
|
+
"",
|
|
840
|
+
"The following conditions must be met within 90 days for the "
|
|
841
|
+
"conditional certification to be elevated to full certification:",
|
|
842
|
+
"",
|
|
843
|
+
]
|
|
844
|
+
|
|
845
|
+
condition_num = 1
|
|
846
|
+
|
|
847
|
+
# Areas below 60%
|
|
848
|
+
areas_below_60 = [
|
|
849
|
+
area for area in PROCESS_AREAS
|
|
850
|
+
if area_scores.get(area, {}).get("total", 0) > 0
|
|
851
|
+
and area_scores.get(area, {}).get("score", 0.0) < 60.0
|
|
852
|
+
]
|
|
853
|
+
if areas_below_60:
|
|
854
|
+
for area in areas_below_60:
|
|
855
|
+
score = area_scores[area]["score"]
|
|
856
|
+
lines.append(
|
|
857
|
+
f"{condition_num}. Raise **{area}** score from "
|
|
858
|
+
f"{score:.1f}% to at least 60%."
|
|
859
|
+
)
|
|
860
|
+
condition_num += 1
|
|
861
|
+
|
|
862
|
+
# Areas between 60% and 80% (advisory)
|
|
863
|
+
areas_below_80 = [
|
|
864
|
+
area for area in PROCESS_AREAS
|
|
865
|
+
if area_scores.get(area, {}).get("total", 0) > 0
|
|
866
|
+
and 60.0 <= area_scores.get(area, {}).get("score", 0.0) < 80.0
|
|
867
|
+
]
|
|
868
|
+
if areas_below_80:
|
|
869
|
+
for area in areas_below_80:
|
|
870
|
+
score = area_scores[area]["score"]
|
|
871
|
+
lines.append(
|
|
872
|
+
f"{condition_num}. Improve **{area}** score from "
|
|
873
|
+
f"{score:.1f}% toward 80% target."
|
|
874
|
+
)
|
|
875
|
+
condition_num += 1
|
|
876
|
+
|
|
877
|
+
# Open high findings
|
|
878
|
+
high_open = [
|
|
879
|
+
f for f in findings
|
|
880
|
+
if f.get("severity") == "high"
|
|
881
|
+
and f.get("status") in ("open", "in_progress")
|
|
882
|
+
]
|
|
883
|
+
if high_open:
|
|
884
|
+
lines.append(
|
|
885
|
+
f"{condition_num}. Resolve {len(high_open)} open high-severity "
|
|
886
|
+
"finding(s)."
|
|
887
|
+
)
|
|
888
|
+
condition_num += 1
|
|
889
|
+
|
|
890
|
+
# Open moderate findings (advisory)
|
|
891
|
+
moderate_open = [
|
|
892
|
+
f for f in findings
|
|
893
|
+
if f.get("severity") == "moderate"
|
|
894
|
+
and f.get("status") in ("open", "in_progress")
|
|
895
|
+
]
|
|
896
|
+
if moderate_open:
|
|
897
|
+
lines.append(
|
|
898
|
+
f"{condition_num}. Address {len(moderate_open)} open "
|
|
899
|
+
"moderate-severity finding(s)."
|
|
900
|
+
)
|
|
901
|
+
condition_num += 1
|
|
902
|
+
|
|
903
|
+
if condition_num == 1:
|
|
904
|
+
lines.append(
|
|
905
|
+
"1. Raise overall IV&V score to 80% or above for full "
|
|
906
|
+
"certification."
|
|
907
|
+
)
|
|
908
|
+
|
|
909
|
+
lines.append("")
|
|
910
|
+
lines.append(
|
|
911
|
+
"**Review Date:** A follow-up review will be scheduled within "
|
|
912
|
+
"90 calendar days to verify condition completion."
|
|
913
|
+
)
|
|
914
|
+
|
|
915
|
+
return "\n".join(lines)
|
|
916
|
+
|
|
917
|
+
|
|
918
|
+
def _build_evidence_index(assessments):
|
|
919
|
+
"""Build an evidence index table from assessment evidence paths.
|
|
920
|
+
|
|
921
|
+
Lists all assessments that have an evidence_path recorded.
|
|
922
|
+
"""
|
|
923
|
+
with_evidence = [
|
|
924
|
+
a for a in assessments if a.get("evidence_path")
|
|
925
|
+
]
|
|
926
|
+
|
|
927
|
+
if not with_evidence:
|
|
928
|
+
return "*No evidence artifacts recorded in assessments.*"
|
|
929
|
+
|
|
930
|
+
lines = [
|
|
931
|
+
"| Req ID | Process Area | Evidence Path |",
|
|
932
|
+
"|--------|-------------|---------------|",
|
|
933
|
+
]
|
|
934
|
+
for a in sorted(with_evidence, key=lambda x: x.get("requirement_id", "")):
|
|
935
|
+
req_id = a.get("requirement_id", "N/A")
|
|
936
|
+
pa = a.get("process_area", "N/A")
|
|
937
|
+
path = a.get("evidence_path", "N/A")
|
|
938
|
+
lines.append(f"| {req_id} | {pa} | `{path}` |")
|
|
939
|
+
|
|
940
|
+
# Summary
|
|
941
|
+
total = len(assessments)
|
|
942
|
+
with_count = len(with_evidence)
|
|
943
|
+
without_count = total - with_count
|
|
944
|
+
coverage = (
|
|
945
|
+
f"{100.0 * with_count / total:.0f}%"
|
|
946
|
+
if total > 0
|
|
947
|
+
else "N/A"
|
|
948
|
+
)
|
|
949
|
+
lines.append("")
|
|
950
|
+
lines.append(
|
|
951
|
+
f"**Evidence Coverage:** {with_count}/{total} assessments "
|
|
952
|
+
f"have evidence artifacts ({coverage})"
|
|
953
|
+
)
|
|
954
|
+
if without_count > 0:
|
|
955
|
+
missing = [
|
|
956
|
+
a for a in assessments if not a.get("evidence_path")
|
|
957
|
+
]
|
|
958
|
+
missing_ids = [
|
|
959
|
+
a.get("requirement_id", "?") for a in missing
|
|
960
|
+
]
|
|
961
|
+
if len(missing_ids) <= 10:
|
|
962
|
+
lines.append(
|
|
963
|
+
f"**Missing Evidence:** {', '.join(missing_ids)}"
|
|
964
|
+
)
|
|
965
|
+
else:
|
|
966
|
+
lines.append(
|
|
967
|
+
f"**Missing Evidence:** {', '.join(missing_ids[:10])} "
|
|
968
|
+
f"(and {len(missing_ids) - 10} more)"
|
|
969
|
+
)
|
|
970
|
+
|
|
971
|
+
return "\n".join(lines)
|
|
972
|
+
|
|
973
|
+
|
|
974
|
+
def _build_executive_summary(
|
|
975
|
+
verification_score,
|
|
976
|
+
validation_score,
|
|
977
|
+
overall_score,
|
|
978
|
+
recommendation,
|
|
979
|
+
reason,
|
|
980
|
+
area_scores,
|
|
981
|
+
findings,
|
|
982
|
+
assessments,
|
|
983
|
+
):
|
|
984
|
+
"""Build the executive summary paragraph."""
|
|
985
|
+
total_assessments = len(assessments)
|
|
986
|
+
total_findings = len(findings)
|
|
987
|
+
critical_open = sum(
|
|
988
|
+
1 for f in findings
|
|
989
|
+
if f.get("severity") == "critical"
|
|
990
|
+
and f.get("status") in ("open", "in_progress")
|
|
991
|
+
)
|
|
992
|
+
high_open = sum(
|
|
993
|
+
1 for f in findings
|
|
994
|
+
if f.get("severity") == "high"
|
|
995
|
+
and f.get("status") in ("open", "in_progress")
|
|
996
|
+
)
|
|
997
|
+
|
|
998
|
+
# Count assessments by status
|
|
999
|
+
sum(
|
|
1000
|
+
1 for a in assessments if a.get("status") == "pass"
|
|
1001
|
+
)
|
|
1002
|
+
sum(
|
|
1003
|
+
1 for a in assessments if a.get("status") == "fail"
|
|
1004
|
+
)
|
|
1005
|
+
|
|
1006
|
+
lines = []
|
|
1007
|
+
lines.append(
|
|
1008
|
+
f"This IV&V assessment evaluated {total_assessments} requirements "
|
|
1009
|
+
f"across {len(PROCESS_AREAS)} process areas per IEEE 1012-2016 and "
|
|
1010
|
+
f"DoDI 5000.87. The verification score is **{verification_score:.1f}%** "
|
|
1011
|
+
f"and the validation score is **{validation_score:.1f}%**, yielding an "
|
|
1012
|
+
f"overall weighted score of **{overall_score:.1f}%**."
|
|
1013
|
+
)
|
|
1014
|
+
lines.append("")
|
|
1015
|
+
|
|
1016
|
+
if total_findings > 0:
|
|
1017
|
+
lines.append(
|
|
1018
|
+
f"The assessment identified **{total_findings} finding(s)**: "
|
|
1019
|
+
f"{critical_open} critical open, {high_open} high open. "
|
|
1020
|
+
)
|
|
1021
|
+
else:
|
|
1022
|
+
lines.append("No findings were identified during this assessment.")
|
|
1023
|
+
|
|
1024
|
+
lines.append("")
|
|
1025
|
+
lines.append(
|
|
1026
|
+
f"**Certification Recommendation: {recommendation}** — {reason}"
|
|
1027
|
+
)
|
|
1028
|
+
|
|
1029
|
+
# Highlight strongest and weakest areas
|
|
1030
|
+
scored_areas = [
|
|
1031
|
+
(area, area_scores[area]["score"])
|
|
1032
|
+
for area in PROCESS_AREAS
|
|
1033
|
+
if area_scores.get(area, {}).get("total", 0) > 0
|
|
1034
|
+
]
|
|
1035
|
+
if scored_areas:
|
|
1036
|
+
scored_areas.sort(key=lambda x: x[1], reverse=True)
|
|
1037
|
+
strongest = scored_areas[0]
|
|
1038
|
+
weakest = scored_areas[-1]
|
|
1039
|
+
if strongest[0] != weakest[0]:
|
|
1040
|
+
lines.append("")
|
|
1041
|
+
lines.append(
|
|
1042
|
+
f"**Strongest Area:** {strongest[0]} ({strongest[1]:.1f}%) \n"
|
|
1043
|
+
f"**Weakest Area:** {weakest[0]} ({weakest[1]:.1f}%)"
|
|
1044
|
+
)
|
|
1045
|
+
|
|
1046
|
+
return "\n".join(lines)
|
|
1047
|
+
|
|
1048
|
+
|
|
1049
|
+
def _build_area_subset_details(assessments, area_scores, area_list, label):
|
|
1050
|
+
"""Build detail tables for a subset of process areas (used for
|
|
1051
|
+
validation area breakouts in sections 4.1 and 4.2)."""
|
|
1052
|
+
area_data = {area: [] for area in area_list}
|
|
1053
|
+
for a in assessments:
|
|
1054
|
+
pa = a.get("process_area")
|
|
1055
|
+
if pa in area_data:
|
|
1056
|
+
area_data[pa].append(a)
|
|
1057
|
+
|
|
1058
|
+
sections = []
|
|
1059
|
+
for area in area_list:
|
|
1060
|
+
items = area_data[area]
|
|
1061
|
+
s = area_scores.get(area, {})
|
|
1062
|
+
score = s.get("score", 0.0)
|
|
1063
|
+
|
|
1064
|
+
sections.append(f"**{area}** — Score: {score:.1f}%")
|
|
1065
|
+
sections.append("")
|
|
1066
|
+
|
|
1067
|
+
if not items:
|
|
1068
|
+
sections.append(
|
|
1069
|
+
"*No assessments recorded for this area.*"
|
|
1070
|
+
)
|
|
1071
|
+
sections.append("")
|
|
1072
|
+
continue
|
|
1073
|
+
|
|
1074
|
+
sections.append("| Req ID | Status | Evidence | Notes |")
|
|
1075
|
+
sections.append("|--------|--------|----------|-------|")
|
|
1076
|
+
for item in sorted(items, key=lambda x: x.get("requirement_id", "")):
|
|
1077
|
+
req_id = item.get("requirement_id", "N/A")
|
|
1078
|
+
status = _status_badge(item.get("status", "not_assessed"))
|
|
1079
|
+
evidence = (
|
|
1080
|
+
(item.get("evidence_description") or "")
|
|
1081
|
+
.replace("\n", " ")
|
|
1082
|
+
.strip()
|
|
1083
|
+
)
|
|
1084
|
+
notes = (
|
|
1085
|
+
(item.get("notes") or "").replace("\n", " ").strip()
|
|
1086
|
+
)
|
|
1087
|
+
if len(evidence) > 60:
|
|
1088
|
+
evidence = evidence[:57] + "..."
|
|
1089
|
+
if len(notes) > 60:
|
|
1090
|
+
notes = notes[:57] + "..."
|
|
1091
|
+
sections.append(
|
|
1092
|
+
f"| {req_id} | {status} | {evidence} | {notes} |"
|
|
1093
|
+
)
|
|
1094
|
+
sections.append("")
|
|
1095
|
+
|
|
1096
|
+
return "\n".join(sections)
|
|
1097
|
+
|
|
1098
|
+
|
|
1099
|
+
def _determine_gate_result(findings):
|
|
1100
|
+
"""Determine the IV&V gate result.
|
|
1101
|
+
|
|
1102
|
+
PASS if zero critical findings are open; FAIL otherwise.
|
|
1103
|
+
"""
|
|
1104
|
+
critical_open = sum(
|
|
1105
|
+
1 for f in findings
|
|
1106
|
+
if f.get("severity") == "critical"
|
|
1107
|
+
and f.get("status") in ("open", "in_progress")
|
|
1108
|
+
)
|
|
1109
|
+
if critical_open > 0:
|
|
1110
|
+
return "FAIL", critical_open
|
|
1111
|
+
return "PASS", 0
|
|
1112
|
+
|
|
1113
|
+
|
|
1114
|
+
# ---------------------------------------------------------------------------
|
|
1115
|
+
# Variable substitution & CUI markings
|
|
1116
|
+
# ---------------------------------------------------------------------------
|
|
1117
|
+
|
|
1118
|
+
def _apply_cui_markings(content, cui_config):
|
|
1119
|
+
"""Apply CUI header and footer banners to the report content."""
|
|
1120
|
+
header = cui_config.get("document_header", "").strip()
|
|
1121
|
+
footer = cui_config.get("document_footer", "").strip()
|
|
1122
|
+
banner_top = cui_config.get("banner_top", "CUI // SP-CTI")
|
|
1123
|
+
|
|
1124
|
+
# If the content already contains the banner, skip
|
|
1125
|
+
if banner_top in content:
|
|
1126
|
+
return content
|
|
1127
|
+
|
|
1128
|
+
return f"{header}\n\n{content.strip()}\n\n{footer}\n"
|
|
1129
|
+
|
|
1130
|
+
|
|
1131
|
+
def _substitute_variables(template, variables):
|
|
1132
|
+
"""Replace {{variable_name}} placeholders in the template."""
|
|
1133
|
+
def replacer(match):
|
|
1134
|
+
key = match.group(1).strip()
|
|
1135
|
+
return str(variables.get(key, match.group(0)))
|
|
1136
|
+
return re.sub(r"\{\{(\w+)\}\}", replacer, template)
|
|
1137
|
+
|
|
1138
|
+
|
|
1139
|
+
# ---------------------------------------------------------------------------
|
|
1140
|
+
# Audit logging
|
|
1141
|
+
# ---------------------------------------------------------------------------
|
|
1142
|
+
|
|
1143
|
+
def _log_audit_event(conn, project_id, action, details, file_path):
|
|
1144
|
+
"""Log an audit trail event for IV&V report generation.
|
|
1145
|
+
|
|
1146
|
+
Uses 'compliance_check' as the event_type since IV&V report generation
|
|
1147
|
+
falls under compliance verification activities.
|
|
1148
|
+
"""
|
|
1149
|
+
try:
|
|
1150
|
+
conn.execute(
|
|
1151
|
+
"""INSERT INTO audit_trail
|
|
1152
|
+
(project_id, event_type, actor, action, details,
|
|
1153
|
+
affected_files, classification)
|
|
1154
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)""",
|
|
1155
|
+
(
|
|
1156
|
+
project_id,
|
|
1157
|
+
"compliance_check",
|
|
1158
|
+
"icdev-ivv-engine",
|
|
1159
|
+
action,
|
|
1160
|
+
json.dumps(details),
|
|
1161
|
+
json.dumps([str(file_path)]),
|
|
1162
|
+
"CUI",
|
|
1163
|
+
),
|
|
1164
|
+
)
|
|
1165
|
+
conn.commit()
|
|
1166
|
+
except Exception as e:
|
|
1167
|
+
print(
|
|
1168
|
+
f"Warning: Could not log audit event: {e}", file=sys.stderr
|
|
1169
|
+
)
|
|
1170
|
+
|
|
1171
|
+
|
|
1172
|
+
# ---------------------------------------------------------------------------
|
|
1173
|
+
# Main generator
|
|
1174
|
+
# ---------------------------------------------------------------------------
|
|
1175
|
+
|
|
1176
|
+
def generate_ivv_report(project_id, output_path=None, db_path=None):
|
|
1177
|
+
"""Generate an IV&V certification report for a project.
|
|
1178
|
+
|
|
1179
|
+
Workflow:
|
|
1180
|
+
1. Connect, load project, template, requirements
|
|
1181
|
+
2. Query all 3 IV&V tables
|
|
1182
|
+
3. Calculate scores (verification, validation, overall)
|
|
1183
|
+
4. Determine certification recommendation
|
|
1184
|
+
5. Build all sections
|
|
1185
|
+
6. Apply {{variable}} substitution
|
|
1186
|
+
7. Apply CUI markings
|
|
1187
|
+
8. Write to: {project_dir}/compliance/ivv-report-v{version}.md
|
|
1188
|
+
9. Update ivv_certifications table with scores and recommendation
|
|
1189
|
+
10. Audit: "compliance_check" (IV&V report generated)
|
|
1190
|
+
11. Return result dict
|
|
1191
|
+
|
|
1192
|
+
Args:
|
|
1193
|
+
project_id: The project identifier.
|
|
1194
|
+
output_path: Override output directory or file path.
|
|
1195
|
+
db_path: Override database path.
|
|
1196
|
+
|
|
1197
|
+
Returns:
|
|
1198
|
+
dict with ``file_path`` and metadata about the generated report.
|
|
1199
|
+
"""
|
|
1200
|
+
conn = get_connection(db_path=db_path)
|
|
1201
|
+
try:
|
|
1202
|
+
# 1. Load project data
|
|
1203
|
+
project = _get_project_data(conn, project_id)
|
|
1204
|
+
project_name = project.get("name", project_id)
|
|
1205
|
+
|
|
1206
|
+
# 2. Load template
|
|
1207
|
+
template = _load_template()
|
|
1208
|
+
|
|
1209
|
+
# 3. Load IV&V requirements catalog
|
|
1210
|
+
ivv_catalog = _load_ivv_requirements()
|
|
1211
|
+
_requirements_list = ivv_catalog.get("requirements", [])
|
|
1212
|
+
|
|
1213
|
+
# 4. Query all IV&V tables
|
|
1214
|
+
assessments = _get_ivv_assessments(conn, project_id)
|
|
1215
|
+
findings = _get_ivv_findings(conn, project_id)
|
|
1216
|
+
certification = _get_ivv_certification(conn, project_id)
|
|
1217
|
+
|
|
1218
|
+
# 5. Calculate scores
|
|
1219
|
+
area_scores = _calculate_process_area_scores(assessments)
|
|
1220
|
+
verification_score = _calculate_verification_score(area_scores)
|
|
1221
|
+
validation_score = _calculate_validation_score(area_scores)
|
|
1222
|
+
overall_score = _calculate_overall_score(
|
|
1223
|
+
verification_score, validation_score
|
|
1224
|
+
)
|
|
1225
|
+
|
|
1226
|
+
# 6. Determine certification recommendation
|
|
1227
|
+
recommendation, reason = _determine_certification_recommendation(
|
|
1228
|
+
overall_score, area_scores, findings
|
|
1229
|
+
)
|
|
1230
|
+
|
|
1231
|
+
# 7. Determine gate result
|
|
1232
|
+
gate_result, critical_open_count = _determine_gate_result(findings)
|
|
1233
|
+
|
|
1234
|
+
# 8. Build all report sections
|
|
1235
|
+
process_area_scores_table = _build_process_area_scores_table(
|
|
1236
|
+
area_scores
|
|
1237
|
+
)
|
|
1238
|
+
process_area_details = _build_process_area_details(
|
|
1239
|
+
assessments, area_scores
|
|
1240
|
+
)
|
|
1241
|
+
findings_by_severity = _build_findings_by_severity(findings)
|
|
1242
|
+
findings_summary_table = _build_findings_summary_table(findings)
|
|
1243
|
+
|
|
1244
|
+
rtm_summary, rtm_coverage, rtm_traced, rtm_gaps, rtm_orphans = (
|
|
1245
|
+
_build_rtm_summary(conn, project_id)
|
|
1246
|
+
)
|
|
1247
|
+
|
|
1248
|
+
independence_declaration = _build_independence_declaration()
|
|
1249
|
+
conditions = _build_conditions(
|
|
1250
|
+
recommendation, area_scores, findings
|
|
1251
|
+
)
|
|
1252
|
+
evidence_index = _build_evidence_index(assessments)
|
|
1253
|
+
|
|
1254
|
+
# Build validation area breakouts for sections 4.1 and 4.2
|
|
1255
|
+
test_verification_results = _build_area_subset_details(
|
|
1256
|
+
assessments, area_scores, ["Test Verification"],
|
|
1257
|
+
"Test Verification"
|
|
1258
|
+
)
|
|
1259
|
+
integration_verification_results = _build_area_subset_details(
|
|
1260
|
+
assessments, area_scores, ["Integration Verification"],
|
|
1261
|
+
"Integration Verification"
|
|
1262
|
+
)
|
|
1263
|
+
|
|
1264
|
+
# Build executive summary
|
|
1265
|
+
executive_summary = _build_executive_summary(
|
|
1266
|
+
verification_score,
|
|
1267
|
+
validation_score,
|
|
1268
|
+
overall_score,
|
|
1269
|
+
recommendation,
|
|
1270
|
+
reason,
|
|
1271
|
+
area_scores,
|
|
1272
|
+
findings,
|
|
1273
|
+
assessments,
|
|
1274
|
+
)
|
|
1275
|
+
|
|
1276
|
+
# Load CUI config for banner variables
|
|
1277
|
+
cui_config = _load_cui_config()
|
|
1278
|
+
|
|
1279
|
+
# Determine version number from prior audit events
|
|
1280
|
+
report_count_row = conn.execute(
|
|
1281
|
+
"""SELECT COUNT(*) as cnt FROM audit_trail
|
|
1282
|
+
WHERE project_id = ? AND event_type = 'compliance_check'
|
|
1283
|
+
AND action LIKE '%IV&V report%'""",
|
|
1284
|
+
(project_id,),
|
|
1285
|
+
).fetchone()
|
|
1286
|
+
report_count = report_count_row["cnt"] if report_count_row else 0
|
|
1287
|
+
new_version = f"{report_count + 1}.0"
|
|
1288
|
+
|
|
1289
|
+
now = datetime.now(timezone.utc)
|
|
1290
|
+
|
|
1291
|
+
# 9. Build the complete variable substitution dict
|
|
1292
|
+
variables = {
|
|
1293
|
+
# Project info
|
|
1294
|
+
"project_name": project_name,
|
|
1295
|
+
"project_id": project_id,
|
|
1296
|
+
"classification": project.get("classification", "CUI"),
|
|
1297
|
+
"system_type": project.get("type", "webapp"),
|
|
1298
|
+
|
|
1299
|
+
# Report metadata
|
|
1300
|
+
"version": new_version,
|
|
1301
|
+
"report_version": new_version,
|
|
1302
|
+
"assessment_date": now.strftime("%Y-%m-%d"),
|
|
1303
|
+
"date_prepared": now.strftime("%Y-%m-%d"),
|
|
1304
|
+
"generation_timestamp": now.strftime("%Y-%m-%d %H:%M UTC"),
|
|
1305
|
+
"icdev_version": "1.0",
|
|
1306
|
+
"ivv_authority": certification.get(
|
|
1307
|
+
"ivv_authority", "ICDEV IV&V Engine"
|
|
1308
|
+
),
|
|
1309
|
+
|
|
1310
|
+
# Scores
|
|
1311
|
+
"verification_score": f"{verification_score:.1f}",
|
|
1312
|
+
"validation_score": f"{validation_score:.1f}",
|
|
1313
|
+
"overall_score": f"{overall_score:.1f}",
|
|
1314
|
+
|
|
1315
|
+
# Gate result
|
|
1316
|
+
"gate_result": gate_result,
|
|
1317
|
+
|
|
1318
|
+
# Certification recommendation
|
|
1319
|
+
"certification_recommendation": recommendation,
|
|
1320
|
+
"certification_reason": reason,
|
|
1321
|
+
|
|
1322
|
+
# Executive summary
|
|
1323
|
+
"executive_summary": executive_summary,
|
|
1324
|
+
|
|
1325
|
+
# Independence declaration
|
|
1326
|
+
"independence_declaration": independence_declaration,
|
|
1327
|
+
|
|
1328
|
+
# Process area tables
|
|
1329
|
+
"process_area_scores_table": process_area_scores_table,
|
|
1330
|
+
"process_area_details": process_area_details,
|
|
1331
|
+
|
|
1332
|
+
# Validation breakouts
|
|
1333
|
+
"test_verification_results": test_verification_results,
|
|
1334
|
+
"integration_verification_results": (
|
|
1335
|
+
integration_verification_results
|
|
1336
|
+
),
|
|
1337
|
+
|
|
1338
|
+
# RTM summary
|
|
1339
|
+
"rtm_summary": rtm_summary,
|
|
1340
|
+
"rtm_coverage": f"{rtm_coverage:.1f}" if rtm_coverage else "0.0",
|
|
1341
|
+
"rtm_full_trace_count": str(rtm_traced),
|
|
1342
|
+
"rtm_gap_count": str(rtm_gaps),
|
|
1343
|
+
"rtm_orphan_tests": str(rtm_orphans),
|
|
1344
|
+
|
|
1345
|
+
# Findings by severity
|
|
1346
|
+
"critical_findings": findings_by_severity.get(
|
|
1347
|
+
"critical", "*No critical findings.*"
|
|
1348
|
+
),
|
|
1349
|
+
"high_findings": findings_by_severity.get(
|
|
1350
|
+
"high", "*No high findings.*"
|
|
1351
|
+
),
|
|
1352
|
+
"moderate_findings": findings_by_severity.get(
|
|
1353
|
+
"moderate", "*No moderate findings.*"
|
|
1354
|
+
),
|
|
1355
|
+
"low_findings": findings_by_severity.get(
|
|
1356
|
+
"low", "*No low findings.*"
|
|
1357
|
+
),
|
|
1358
|
+
"findings_summary_table": findings_summary_table,
|
|
1359
|
+
|
|
1360
|
+
# Conditions
|
|
1361
|
+
"conditions": conditions,
|
|
1362
|
+
|
|
1363
|
+
# Evidence index
|
|
1364
|
+
"evidence_index": evidence_index,
|
|
1365
|
+
|
|
1366
|
+
# Next review date (90 days from now if not set)
|
|
1367
|
+
"next_review_date": certification.get(
|
|
1368
|
+
"next_review_date",
|
|
1369
|
+
(now + timedelta(days=90)).strftime("%Y-%m-%d"),
|
|
1370
|
+
),
|
|
1371
|
+
|
|
1372
|
+
# Certification info from existing record
|
|
1373
|
+
"certification_status": certification.get(
|
|
1374
|
+
"status", "in_progress"
|
|
1375
|
+
),
|
|
1376
|
+
"certified_date": certification.get("certified_date", "N/A"),
|
|
1377
|
+
"expiration_date": certification.get("expiration_date", "N/A"),
|
|
1378
|
+
"open_findings_count": str(
|
|
1379
|
+
sum(
|
|
1380
|
+
1 for f in findings
|
|
1381
|
+
if f.get("status") in ("open", "in_progress")
|
|
1382
|
+
)
|
|
1383
|
+
),
|
|
1384
|
+
"critical_findings_count": str(critical_open_count),
|
|
1385
|
+
|
|
1386
|
+
# Assessment totals
|
|
1387
|
+
"total_assessments": str(len(assessments)),
|
|
1388
|
+
"total_findings": str(len(findings)),
|
|
1389
|
+
"assessments_pass": str(
|
|
1390
|
+
sum(1 for a in assessments if a.get("status") == "pass")
|
|
1391
|
+
),
|
|
1392
|
+
"assessments_fail": str(
|
|
1393
|
+
sum(1 for a in assessments if a.get("status") == "fail")
|
|
1394
|
+
),
|
|
1395
|
+
|
|
1396
|
+
# CUI banners
|
|
1397
|
+
"cui_banner_top": cui_config.get(
|
|
1398
|
+
"document_header",
|
|
1399
|
+
cui_config.get("banner_top", "CUI // SP-CTI"),
|
|
1400
|
+
),
|
|
1401
|
+
"cui_banner_bottom": cui_config.get(
|
|
1402
|
+
"document_footer",
|
|
1403
|
+
cui_config.get("banner_bottom", "CUI // SP-CTI"),
|
|
1404
|
+
),
|
|
1405
|
+
}
|
|
1406
|
+
|
|
1407
|
+
# Per-area score variables (e.g., requirements_verification_score)
|
|
1408
|
+
for area in PROCESS_AREAS:
|
|
1409
|
+
key_prefix = area.lower().replace(" ", "_").replace("/", "_")
|
|
1410
|
+
s = area_scores.get(area, {})
|
|
1411
|
+
variables[f"{key_prefix}_score"] = f"{s.get('score', 0.0):.1f}"
|
|
1412
|
+
variables[f"{key_prefix}_total"] = str(s.get("total", 0))
|
|
1413
|
+
variables[f"{key_prefix}_pass"] = str(s.get("pass", 0))
|
|
1414
|
+
variables[f"{key_prefix}_fail"] = str(s.get("fail", 0))
|
|
1415
|
+
|
|
1416
|
+
# 10. Substitute variables in template
|
|
1417
|
+
report_content = _substitute_variables(template, variables)
|
|
1418
|
+
|
|
1419
|
+
# 11. Apply CUI markings
|
|
1420
|
+
report_content = _apply_cui_markings(report_content, cui_config)
|
|
1421
|
+
|
|
1422
|
+
# 12. Determine output file path
|
|
1423
|
+
if output_path:
|
|
1424
|
+
out_path = Path(output_path)
|
|
1425
|
+
if (
|
|
1426
|
+
out_path.is_dir()
|
|
1427
|
+
or str(output_path).endswith("/")
|
|
1428
|
+
or str(output_path).endswith("\\")
|
|
1429
|
+
):
|
|
1430
|
+
out_dir = out_path
|
|
1431
|
+
out_file = out_dir / f"ivv-report-v{new_version}.md"
|
|
1432
|
+
else:
|
|
1433
|
+
out_file = out_path
|
|
1434
|
+
else:
|
|
1435
|
+
dir_path = project.get("directory_path", "")
|
|
1436
|
+
if dir_path:
|
|
1437
|
+
out_dir = Path(dir_path) / "compliance"
|
|
1438
|
+
else:
|
|
1439
|
+
out_dir = (
|
|
1440
|
+
BASE_DIR / "projects" / project_name / "compliance"
|
|
1441
|
+
)
|
|
1442
|
+
out_file = out_dir / f"ivv-report-v{new_version}.md"
|
|
1443
|
+
|
|
1444
|
+
out_file.parent.mkdir(parents=True, exist_ok=True)
|
|
1445
|
+
|
|
1446
|
+
with open(out_file, "w", encoding="utf-8") as f:
|
|
1447
|
+
f.write(report_content)
|
|
1448
|
+
|
|
1449
|
+
# 13. Update ivv_certifications table with scores and recommendation
|
|
1450
|
+
try:
|
|
1451
|
+
# Map recommendation to DB status
|
|
1452
|
+
status_map = {
|
|
1453
|
+
"CERTIFY": "certified",
|
|
1454
|
+
"CONDITIONAL": "conditional",
|
|
1455
|
+
"DENY": "denied",
|
|
1456
|
+
}
|
|
1457
|
+
cert_status = status_map.get(recommendation, "in_progress")
|
|
1458
|
+
|
|
1459
|
+
# Count open and critical findings
|
|
1460
|
+
open_count = sum(
|
|
1461
|
+
1 for f in findings
|
|
1462
|
+
if f.get("status") in ("open", "in_progress")
|
|
1463
|
+
)
|
|
1464
|
+
|
|
1465
|
+
conn.execute(
|
|
1466
|
+
"""INSERT OR REPLACE INTO ivv_certifications
|
|
1467
|
+
(project_id, certification_type, status,
|
|
1468
|
+
verification_score, validation_score, overall_score,
|
|
1469
|
+
ivv_authority, independence_declaration,
|
|
1470
|
+
conditions, open_findings_count,
|
|
1471
|
+
critical_findings_count, next_review_date,
|
|
1472
|
+
updated_at)
|
|
1473
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)""",
|
|
1474
|
+
(
|
|
1475
|
+
project_id,
|
|
1476
|
+
"IV&V",
|
|
1477
|
+
cert_status,
|
|
1478
|
+
verification_score,
|
|
1479
|
+
validation_score,
|
|
1480
|
+
overall_score,
|
|
1481
|
+
certification.get(
|
|
1482
|
+
"ivv_authority", "ICDEV IV&V Engine"
|
|
1483
|
+
),
|
|
1484
|
+
"IEEE 1012 Independent Assessment",
|
|
1485
|
+
conditions if recommendation == "CONDITIONAL" else None,
|
|
1486
|
+
open_count,
|
|
1487
|
+
critical_open_count,
|
|
1488
|
+
(now + timedelta(days=90)).strftime("%Y-%m-%d"),
|
|
1489
|
+
now.strftime("%Y-%m-%d %H:%M:%S"),
|
|
1490
|
+
),
|
|
1491
|
+
)
|
|
1492
|
+
conn.commit()
|
|
1493
|
+
except Exception as e:
|
|
1494
|
+
print(
|
|
1495
|
+
f"Warning: Could not update ivv_certifications: {e}",
|
|
1496
|
+
file=sys.stderr,
|
|
1497
|
+
)
|
|
1498
|
+
|
|
1499
|
+
# 14. Log audit event
|
|
1500
|
+
audit_details = {
|
|
1501
|
+
"report_type": "IV&V Certification Report",
|
|
1502
|
+
"version": new_version,
|
|
1503
|
+
"verification_score": verification_score,
|
|
1504
|
+
"validation_score": validation_score,
|
|
1505
|
+
"overall_score": overall_score,
|
|
1506
|
+
"gate_result": gate_result,
|
|
1507
|
+
"recommendation": recommendation,
|
|
1508
|
+
"total_assessments": len(assessments),
|
|
1509
|
+
"total_findings": len(findings),
|
|
1510
|
+
"critical_open": critical_open_count,
|
|
1511
|
+
"output_file": str(out_file),
|
|
1512
|
+
}
|
|
1513
|
+
_log_audit_event(
|
|
1514
|
+
conn,
|
|
1515
|
+
project_id,
|
|
1516
|
+
f"IV&V report v{new_version} generated — {recommendation}",
|
|
1517
|
+
audit_details,
|
|
1518
|
+
out_file,
|
|
1519
|
+
)
|
|
1520
|
+
|
|
1521
|
+
# 15. Print summary
|
|
1522
|
+
print("IV&V certification report generated successfully:")
|
|
1523
|
+
print(f" File: {out_file}")
|
|
1524
|
+
print(f" Version: {new_version}")
|
|
1525
|
+
print(f" Project: {project_name}")
|
|
1526
|
+
print(f" Verification: {verification_score:.1f}%")
|
|
1527
|
+
print(f" Validation: {validation_score:.1f}%")
|
|
1528
|
+
print(f" Overall Score: {overall_score:.1f}%")
|
|
1529
|
+
print(f" Gate Result: {gate_result}")
|
|
1530
|
+
print(f" Recommendation: {recommendation}")
|
|
1531
|
+
print(f" Assessments: {len(assessments)}")
|
|
1532
|
+
print(f" Findings: {len(findings)}")
|
|
1533
|
+
print(f" Critical Open: {critical_open_count}")
|
|
1534
|
+
|
|
1535
|
+
# 16. Return result dict
|
|
1536
|
+
return {
|
|
1537
|
+
"file_path": str(out_file),
|
|
1538
|
+
"version": new_version,
|
|
1539
|
+
"project_id": project_id,
|
|
1540
|
+
"project_name": project_name,
|
|
1541
|
+
"verification_score": verification_score,
|
|
1542
|
+
"validation_score": validation_score,
|
|
1543
|
+
"overall_score": overall_score,
|
|
1544
|
+
"gate_result": gate_result,
|
|
1545
|
+
"recommendation": recommendation,
|
|
1546
|
+
"reason": reason,
|
|
1547
|
+
"process_area_scores": {
|
|
1548
|
+
area: area_scores[area]["score"]
|
|
1549
|
+
for area in PROCESS_AREAS
|
|
1550
|
+
},
|
|
1551
|
+
"total_assessments": len(assessments),
|
|
1552
|
+
"total_findings": len(findings),
|
|
1553
|
+
"critical_open_findings": critical_open_count,
|
|
1554
|
+
"rtm_coverage": rtm_coverage,
|
|
1555
|
+
"generated_at": now.isoformat(),
|
|
1556
|
+
}
|
|
1557
|
+
|
|
1558
|
+
finally:
|
|
1559
|
+
conn.close()
|
|
1560
|
+
|
|
1561
|
+
|
|
1562
|
+
# ---------------------------------------------------------------------------
|
|
1563
|
+
# CLI entry point
|
|
1564
|
+
# ---------------------------------------------------------------------------
|
|
1565
|
+
|
|
1566
|
+
def _format_json_output(result):
|
|
1567
|
+
"""Format result as JSON for machine-readable output."""
|
|
1568
|
+
return json.dumps(result, indent=2, default=str)
|
|
1569
|
+
|
|
1570
|
+
|
|
1571
|
+
def _format_text_output(result):
|
|
1572
|
+
"""Format result as human-readable text."""
|
|
1573
|
+
lines = [
|
|
1574
|
+
"=" * 60,
|
|
1575
|
+
"IV&V CERTIFICATION REPORT SUMMARY",
|
|
1576
|
+
"=" * 60,
|
|
1577
|
+
"",
|
|
1578
|
+
f" File: {result['file_path']}",
|
|
1579
|
+
f" Version: {result['version']}",
|
|
1580
|
+
f" Project: {result['project_name']} ({result['project_id']})",
|
|
1581
|
+
"",
|
|
1582
|
+
" SCORES:",
|
|
1583
|
+
f" Verification: {result['verification_score']:.1f}%",
|
|
1584
|
+
f" Validation: {result['validation_score']:.1f}%",
|
|
1585
|
+
f" Overall: {result['overall_score']:.1f}%",
|
|
1586
|
+
"",
|
|
1587
|
+
f" Gate Result: {result['gate_result']}",
|
|
1588
|
+
f" Recommendation: {result['recommendation']}",
|
|
1589
|
+
"",
|
|
1590
|
+
" PROCESS AREA SCORES:",
|
|
1591
|
+
]
|
|
1592
|
+
for area, score in result.get("process_area_scores", {}).items():
|
|
1593
|
+
lines.append(f" {area:30s} {score:.1f}%")
|
|
1594
|
+
lines.extend([
|
|
1595
|
+
"",
|
|
1596
|
+
f" Total Assessments: {result['total_assessments']}",
|
|
1597
|
+
f" Total Findings: {result['total_findings']}",
|
|
1598
|
+
f" Critical Open: {result['critical_open_findings']}",
|
|
1599
|
+
f" RTM Coverage: {result['rtm_coverage']:.1f}%",
|
|
1600
|
+
f" Generated: {result['generated_at']}",
|
|
1601
|
+
"",
|
|
1602
|
+
"=" * 60,
|
|
1603
|
+
])
|
|
1604
|
+
return "\n".join(lines)
|
|
1605
|
+
|
|
1606
|
+
|
|
1607
|
+
if __name__ == "__main__":
|
|
1608
|
+
parser = argparse.ArgumentParser(
|
|
1609
|
+
description="Generate IV&V certification report per IEEE 1012"
|
|
1610
|
+
)
|
|
1611
|
+
parser.add_argument(
|
|
1612
|
+
"--project-id",
|
|
1613
|
+
required=True,
|
|
1614
|
+
help="Project ID to generate IV&V report for",
|
|
1615
|
+
)
|
|
1616
|
+
parser.add_argument(
|
|
1617
|
+
"--output-dir",
|
|
1618
|
+
help="Output directory (default: {project_dir}/compliance/)",
|
|
1619
|
+
)
|
|
1620
|
+
parser.add_argument(
|
|
1621
|
+
"--db-path",
|
|
1622
|
+
type=Path,
|
|
1623
|
+
default=DB_PATH,
|
|
1624
|
+
help="Database path (default: data/icdev.db)",
|
|
1625
|
+
)
|
|
1626
|
+
parser.add_argument(
|
|
1627
|
+
"--format",
|
|
1628
|
+
choices=["text", "json"],
|
|
1629
|
+
default="text",
|
|
1630
|
+
help="Output format for CLI summary (default: text)",
|
|
1631
|
+
)
|
|
1632
|
+
|
|
1633
|
+
parser.add_argument("--json", action="store_true", dest="json_output", help="JSON output")
|
|
1634
|
+
args = parser.parse_args()
|
|
1635
|
+
|
|
1636
|
+
try:
|
|
1637
|
+
result = generate_ivv_report(
|
|
1638
|
+
args.project_id, args.output_dir, args.db_path
|
|
1639
|
+
)
|
|
1640
|
+
if args.format == "json":
|
|
1641
|
+
print(_format_json_output(result))
|
|
1642
|
+
else:
|
|
1643
|
+
print(_format_text_output(result))
|
|
1644
|
+
except FileNotFoundError as e:
|
|
1645
|
+
print(f"ERROR: {e}", file=sys.stderr)
|
|
1646
|
+
sys.exit(1)
|
|
1647
|
+
except ValueError as e:
|
|
1648
|
+
print(f"ERROR: {e}", file=sys.stderr)
|
|
1649
|
+
sys.exit(1)
|