This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
This repository contains built-in policies for Chainloop. Use the chainloop policy devel CLI tool for policy development workflows.
-
Create policy directory: Create a new directory for your policy:
mkdir policy-name cd policy-name -
Initialize policy: Run the init command inside the directory:
chainloop policy develop init --name policy-name --description "Policy description" -
Rename YAML file: The init command creates a YAML file named after the policy. Rename it to
policy.yaml:mv policy-name.yaml policy.yaml
chainloop policy develop lint --policy policy.yaml --formatValidates YAML structure, Rego code, enforces best practices, and formats the code.
chainloop policy develop eval \
--policy policy.yaml \
--material sample.json \
--kind MATERIAL_TYPEKey flags:
--debug: Show detailed evaluation output with complete input data and execution path results--material: Input file to test against--kind: Specify material type (e.g., SBOM_CYCLONEDX_JSON, SARIF)
The --debug flag provides comprehensive evaluation information including:
-
Complete Input Structure: Shows the full input data passed to the policy evaluation:
{ "args": { "threshold": "80", "counter": "INSTRUCTION" }, "chainloop_metadata": { "annotations": {...}, "content": "base64-encoded-content", "digest": {...}, "name": "material-filename" }, // ... processed input data } -
Execution Path Results: Detailed results from each execution path that was evaluated:
{ "raw_results": [ { "data.policy_package": { "result": { "violations": [...], "skip_reason": "...", "skipped": false }, // ... internal policy variables and calculations } } ] } -
Skip Reasons: When execution paths are skipped, debug mode shows exactly why:
"SARIF CWE taxonomy only supported for SpotBugs, KICS and Zap""No matching execution path"
Usage Examples:
# Debug basic evaluation
chainloop policy develop eval --policy policy.yaml --material sample.json --kind SARIF --debug
# Debug with parameters
chainloop policy develop eval --policy policy.yaml --material jacoco.xml --kind JACOCO_XML threshold=80 --debug
# Debug to understand why a policy is being skipped
chainloop policy develop eval --policy policy.yaml --material unsupported.json --kind SARIF --debugEach policy lives in its own directory with this structure:
./policy-name/
├── policy.yaml # Policy configuration (required)
└── policy-name.rego # Rego implementation (optional)
Note: Unit tests (*_test.rego files) are not necessary and should not be created. All testing is done through integration tests.
Basic structure:
apiVersion: workflowcontract.chainloop.dev/v1
kind: Policy
metadata:
name: policy-name
description: Policy description
annotations:
category: security,compliance
spec:
policies:
- kind: SBOM_CYCLONEDX_JSON
path: policy-name.rego
- kind: SARIF
path: policy-name-sarif.regoDefine input parameters for flexible policies:
spec:
inputs:
- name: threshold
description: Maximum allowed threshold
required: true
- name: severity
description: Minimum severity level
required: false
policies:
- kind: SBOM_CYCLONEDX_JSON
path: policy-name.regoAccess parameters in Rego with input.args.threshold and input.args.severity.
Support different material types with separate Rego files:
spec:
policies:
- kind: SBOM_CYCLONEDX_JSON
path: cves-cyclonedx.rego
- kind: CSAF_SECURITY_ADVISORY
path: cves-csaf-sa.rego
- kind: SARIF
path: cves-sarif.regoCRITICAL: When creating multiple Rego files for the same policy, each file must use a unique package name to avoid OPA conflicts:
// sast-polaris-sarif.rego
package sast
// sast-gitlab-sonarqube.rego
package sast_gitlab_sonarqubePackage naming conventions:
- Use descriptive names like
policy_formatorpolicy_format_tool - Examples:
vulns_bd,sarif_vulns,sast_gitlab_sonarqube - Never use the same package name across different Rego files in the same policy directory
All testing is done through integration tests only. Unit tests are not required.
Run the comprehensive integration test suite:
./integration-tests/run_tests.shOptions:
--update-golden: Update golden files with current CLI output (use this when creating new tests)--debug: Show the eval commands being executed during test runs
The integration test system uses three components:
- Test Materials (
integration-tests/materials/): Sample input files to test against - Expected Outputs (
integration-tests/outputs/): Golden files with expected policy evaluation results - Test Definitions: Array entries in
run_tests.sh
Tests are defined as array entries in run_tests.sh:
HAPPY_TESTS=(
policy-name MATERIAL_TYPE materials/input.json outputs/expected-output.json "parameters"
)Elements:
policy-name: Name of the policy directoryMATERIAL_TYPE: Type of material (SBOM_CYCLONEDX_JSON, SARIF, etc.)materials/input.json: Input file to evaluateoutputs/expected-output.json: Expected evaluation result"parameters": Optional policy parameters (e.g.,"threshold=80")
- Add or reuse test material: Place sample input file in
integration-tests/materials/or reuse existing materials - Add test definition: Add entry to
HAPPY_TESTSarray inrun_tests.sh - Generate expected output: Run with
--update-goldento create the golden file:./integration-tests/run_tests.sh --update-golden
- Verify tests pass: CRITICAL - Always run tests without
--update-goldento actually test them:Note:./integration-tests/run_tests.sh
--update-goldenupdates files instead of testing them. You must run without this flag to verify tests actually pass.
Note: Materials and outputs can be reused across multiple policies. The same input material can test different policies, and the same expected output can be shared when policies should produce identical results.
- HAPPY_TESTS: Expected to pass (exit code 0)
- UNHAPPY_TESTS: Expected to fail or have no matching execution path
For effective policy development, you can set up a Test-Driven Development environment:
-
Add example files: Place your sample input files in
../integration-tests/materials/# Add your test material cp my-sample.json ../integration-tests/materials/ -
Add test definition: Edit
../integration-tests/run_tests.shand add your test to theHAPPY_TESTSarray:HAPPY_TESTS=( # ... existing tests ... policy-name MATERIAL_TYPE materials/my-sample.json outputs/expected-output.json "parameters" )
-
Generate initial output: Use
--update-goldento create the expected output file:cd ../integration-tests ./run_tests.sh --update-golden -
Run your specific test: Filter tests during development:
./run_tests.sh --debug | grep "policy-name"
- Write/modify policy logic in your Rego file
- Lint and format:
chainloop policy develop lint --policy policy.yaml --format - Test individual samples:
chainloop policy develop eval --kind TYPE --material ../integration-tests/materials/sample.json --policy policy.yaml --debug - Run integration tests:
../integration-tests/run_tests.sh(without--update-goldento actually test!) - Update expected outputs if needed:
../integration-tests/run_tests.sh --update-golden - Verify tests pass again:
../integration-tests/run_tests.sh(critical step to ensure golden files are correct) - Iterate until tests pass
This allows rapid iteration and ensures your policy works correctly with real data.
- Create new policy directory:
mkdir policy-name && cd policy-name - Initialize policy with
chainloop policy develop init --name policy-name --description "..." - Rename YAML file:
mv policy-name.yaml policy.yaml - Set up development tests (see TDD section above)
- Implement Rego logic with TDD loop
- Final validation with
chainloop policy develop lint --policy policy.yaml --format - CRITICAL: Verify all tests pass with
../integration-tests/run_tests.sh(without--update-golden!)
Important Testing Notes:
- Always run
./run_tests.sh(without flags) to actually test your implementation - Only use
--update-goldenwhen you need to create/update expected output files - After using
--update-golden, always run tests again without it to verify correctness