This page covers all the manual validation commands and tools available for developing with the CoSAI Risk Map.
You can run edge validation and graph generation manually at any time:
# Validate only if components.yaml is staged for commit
python scripts/hooks/validate_riskmap.py
# Force validation regardless of git status
python scripts/hooks/validate_riskmap.py --force
# Generate component graph visualization
python scripts/hooks/validate_riskmap.py --to-graph ./my-graph.md --force
# Generate component graph with debug annotations
python scripts/hooks/validate_riskmap.py --to-graph ./debug-graph.md --debug --force
# Generate control-to-component relationship graph
python scripts/hooks/validate_riskmap.py --to-controls-graph ./controls-graph.md --forceThe validation script checks for:
- Bidirectional edge consistency: If Component A references Component B in its
toedges, Component B must have Component A in itsfromedges - No isolated components: Components should have at least one
toorfromedge - Valid component references: All components referenced in edges must exist
Automatic Graph Generation: The pre-commit framework invokes the regenerate-graphs hook (scripts/hooks/precommit/regenerate_graphs.py) when relevant files are staged. Each generated pair is staged with git add so it lands in the same commit (Mode B auto-stage):
- Component Graph: When
components.yamlis staged, generates./risk-map/diagrams/risk-map-graph.md- Uses Elk layout engine for automatic positioning and ranking
- Organizes components into category-based subgraphs with configurable styling
- Control Graph: When
components.yamlORcontrols.yamlis staged, generates./risk-map/diagrams/controls-graph.md- Shows control-to-component relationships with optimization
- Dynamic component clustering and multi-edge styling
- Risk Graph: When
components.yaml,controls.yamlORrisks.yamlis staged, generates./risk-map/diagrams/controls-to-risk-graph.md- Maps controls to risks they mitigate with component context
- Organizes risks into 5 color-coded category subgraphs
- Visualizes three-layer relationships: risks → controls → components
- All generated graphs are automatically staged for inclusion in your commit
See scripts documentation for more information on the git hooks and validation.
Beyond automatic generation, you can manually generate both types of graphs using the validation script:
# Generate component relationship graph
python scripts/hooks/validate_riskmap.py --to-graph ./components.md --force
# Generate control-to-component graph
python scripts/hooks/validate_riskmap.py --to-controls-graph ./controls-graph.md --force
# Generate control-to-risk relationship graph
python scripts/hooks/validate_riskmap.py --to-risk-graph ./risk-graph.md --force
# Generate all three graph types
python scripts/hooks/validate_riskmap.py --to-graph ./components.md --to-controls-graph ./controls.md --to-risk-graph ./risk.md --forceThe regenerate-tables framework hook (scripts/hooks/precommit/regenerate_tables.py) automatically generates markdown tables from YAML files for easy documentation viewing:
Automatic Generation:
- Triggered by: Staging
components.yaml,controls.yaml, orrisks.yaml - Output location:
risk-map/tables/ - Smart regeneration: Cross-reference tables regenerated when dependencies change
- Auto-staging: Generated tables added to commit automatically
Generation rules:
components.yaml→components-full.md,components-summary.md, and regeneratescontrols-xref-components.md(3 files)risks.yaml→risks-full.md,risks-summary.md, and regeneratescontrols-xref-risks.md(3 files)controls.yaml→ all 4 formats:controls-full.md,controls-summary.md,controls-xref-risks.md,controls-xref-components.md
Manual Generation:
# Generate all formats for one type
python3 scripts/hooks/yaml_to_markdown.py components --all-formats
python3 scripts/hooks/yaml_to_markdown.py controls --all-formats
# Generate all types and formats (8 files total)
python3 scripts/hooks/yaml_to_markdown.py --all --all-formats
# Generate to custom output directory
python3 scripts/hooks/yaml_to_markdown.py --all --all-formats --output-dir /tmp/tables
# Generate specific format
python3 scripts/hooks/yaml_to_markdown.py controls --format xref-risks
python3 scripts/hooks/yaml_to_markdown.py components --format summaryPre-push drift check:
# Verify committed tables match generated output without modifying the tree
./scripts/tools/validate-all.sh --check-generationThis strict mode generates tables in a temporary directory, compares them with
risk-map/tables/, and exits non-zero when drift is found. It does not update
tracked files or change the git index. Generator errors print to stdout
regardless of --quiet; only the generator's progress lines are suppressed.
Available formats:
full- Complete tables with all columns (default)summary- Condensed: ID, Title, Description, Categoryxref-risks- Control-to-risk cross-reference (controls only)xref-components- Control-to-component cross-reference (controls only)
Use cases:
- Review component definitions in table format
- Export risk catalog for documentation
- Generate control mappings for compliance reports
- Create cross-reference documentation
Control Graph Features:
- Dynamic Component Clustering: Automatically groups components that share multiple controls
- Category Optimization: Maps controls to entire categories when they apply to all components in that category
- Multi-Edge Styling: Uses different colors and patterns for controls with 3+ edges
- Consistent Styling: Color-coded categories and visual hierarchy
- Mermaid Format: Generates Mermaid-compatible diagrams ready for documentation
Example Control Graph Output: The generated graph shows controls (grouped by category) connected to the components they protect, with optimization applied to reduce visual complexity while maintaining accuracy.
You can run control-to-risk reference validation at any time:
# Validate control-to-risk references if at least on of controls.yaml or risks.yaml is staged
python scripts/hooks/validate_control_risk_references.py
# Force control-to-risk references validation regardless of git status
python scripts/hooks/validate_control_risk_references.py --forceThe control-to-risk validates cross-reference consistency between controls.yaml and risks.yaml:
- Bidirectional consistency: Ensures that if a control lists a risk, that risk also references the control
- Isolated entry detection: Finds controls with no risk references or risks with no control references
- all or none awareness: Will not flag controls that leverage the
allornonerisk mappings
You can run framework reference validation at any time:
# Validate framework references if frameworks.yaml, risks.yaml, or controls.yaml is staged
python scripts/hooks/validate_framework_references.py
# Force framework reference validation regardless of git status
python scripts/hooks/validate_framework_references.py --forceThe framework reference validator ensures consistency between framework definitions and their usage:
- Framework existence: Verifies all framework IDs used in
mappingsexist inframeworks.yaml - Schema consistency: Ensures framework IDs in YAML data match the enum in
frameworks.schema.json - Required fields: Validates that all framework definitions include required fields (
id,name,fullName,description,baseUri) - No duplicates: Detects duplicate framework IDs in framework definitions
- Backward compatibility: Passes validation for risks/controls without
mappingsfields
Example output:
🔍 Force checking framework references...
Found staged frameworks.yaml, risks.yaml, and/or controls.yaml
Validating framework references in: risk-map/yaml/frameworks.yaml, risk-map/yaml/risks.yaml, risk-map/yaml/controls.yaml
✅ Framework references are consistent
- Found 4 valid frameworks: mitre-atlas, nist-ai-rmf, owasp-top10-llm, stride
- Validated 16 risks with framework mappings
- Validated 8 controls with framework mappings
✅ Framework reference validation passed for all files.
Common validation errors:
Framework 'X' references framework 'Y' which does not exist in frameworks.yaml- The framework ID used in a mapping doesn't existDuplicate framework ID 'X' found in frameworks.yaml- Multiple frameworks have the same IDFramework 'X' is missing required field 'Y'- A framework definition is incomplete
See the Framework Guide for detailed information on adding and using frameworks.
You can run prettier formatting on YAML files manually:
# Format all YAML files in risk-map/yaml/
npx prettier --write risk-map/yaml/*.yaml
# Check formatting without modifying files
npx prettier --check risk-map/yaml/*.yamlPrettier ensures consistent formatting across all YAML files in the risk-map/yaml/ directory, automatically handling indentation, spacing, and other style conventions.
You can run ruff linting on Python files manually:
# Lint all Python files
ruff check .
# Lint specific directories
ruff check tools/ scripts/
# Auto-fix issues where possible
ruff check --fix .
# Check specific staged files
ruff check $(git diff --cached --name-only --diff-filter=ACM | grep '\.py$')Ruff enforces Python code quality and style standards, catching potential issues before they make it into the repository.
Related: See Graph Customization to customize the appearance of generated graphs, or CI/CD Validation to learn about automatic validation in pull requests.