From 3b1ed9018fb3e3448ec2da1edc8f4c96b2f12153 Mon Sep 17 00:00:00 2001 From: Daniel Liszka Date: Tue, 29 Jul 2025 14:48:03 +0200 Subject: [PATCH] chore(docs): Create quickstart and examples for policy devel CLI tools Signed-off-by: Daniel Liszka --- docs/examples/policies/quickstart/README.md | 121 ++++++++++++++++++ .../policies/quickstart/cdx-fresh.json | 25 ++++ .../policies/quickstart/cdx-fresh.yaml | 57 +++++++++ .../examples/policies/quickstart/cdx-old.json | 25 ++++ 4 files changed, 228 insertions(+) create mode 100644 docs/examples/policies/quickstart/README.md create mode 100644 docs/examples/policies/quickstart/cdx-fresh.json create mode 100644 docs/examples/policies/quickstart/cdx-fresh.yaml create mode 100644 docs/examples/policies/quickstart/cdx-old.json diff --git a/docs/examples/policies/quickstart/README.md b/docs/examples/policies/quickstart/README.md new file mode 100644 index 000000000..303060712 --- /dev/null +++ b/docs/examples/policies/quickstart/README.md @@ -0,0 +1,121 @@ +# Policy Development Quickstart + +This quickstart guide walks you through creating and validating a basic Chainloop policy that checks SBOM freshness (ensuring SBOMs are not older than 30 days). All steps are CLI-driven and can be run locally. + +## Documentation References + +- **CLI Reference**: [chainloop policy develop commands](https://docs.chainloop.dev/command-line-reference/cli-reference#chainloop-policy) +- **Policy Concepts**: [Understanding Chainloop Policies](https://docs.chainloop.dev/concepts/policies) +- **Custom Policy Guide**: [Writing Custom Policies](https://docs.chainloop.dev/guides/custom-policies) +- **Material Types**: [Available Material Types](https://docs.chainloop.dev/concepts/material-types#material-types) + +## Quick Test + +### Step 1: Download the Example Files + +```bash +# Download the policy and sample materials +curl -O https://raw.githubusercontent.com/chainloop-dev/chainloop/refs/heads/main/docs/examples/policies/quickstart/cdx-fresh.yaml +curl -O https://raw.githubusercontent.com/chainloop-dev/chainloop/refs/heads/main/docs/examples/policies/quickstart/cdx-old.json +curl -O https://raw.githubusercontent.com/chainloop-dev/chainloop/refs/heads/main/docs/examples/policies/quickstart/cdx-fresh.json +``` + +### Step 2: Lint the Policy + +Check your policy's structure and Rego syntax. Run it with `--format` flag to fix all formatting inconsistencies. + +```bash +chainloop policy develop lint --policy cdx-fresh.yaml --format +``` + +**Expected output:** +``` +INF policy is valid! +``` + +### Step 3: Evaluate the Policy + +Use your SBOM CycloneDX material to test your policy logic. + +```bash +# Test with old SBOM (should fail) +chainloop policy develop eval --policy cdx-fresh.yaml --material cdx-old.json --kind SBOM_CYCLONEDX_JSON + +# Test with fresh SBOM (should pass) +chainloop policy develop eval --policy cdx-fresh.yaml --material cdx-fresh.json --kind SBOM_CYCLONEDX_JSON +``` + +**Expected Results:** + +**Old SBOM (should fail):** +``` +INF - cdx-fresh: SBOM created at: 2024-06-15T10:30:00Z which is too old (freshness limit set to 30 days) +INF policy evaluation failed +``` + +**Fresh SBOM (should pass):** +``` +INF policy evaluation passed +``` + +## Create Your Own Policy + +### Step 1: Initialize a Policy Template + +Create a new policy with the embedded format (single YAML file): + +```bash +chainloop policy develop init --embedded --name my-policy --description "My custom policy description" +``` + +**Note**: This creates a file named `my-policy.yaml` (based on the `--name` parameter). Without `--embedded`, it creates separate `chainloop-policy.yaml` and `chainloop-policy.rego` files. + +### Step 2: Write Your Policy Rules + +Edit the generated YAML file and replace the placeholder code in the `embedded` section with your Rego logic. + +**Important**: Remove the `default violations := []` line to avoid conflicts with your `violations contains msg if` rules. + +### Step 3: Test Your Policy + +Follow steps 2-3 above with your own policy and materials. + +## Policy Logic Explained + +The SBOM freshness policy calculates a 30-day threshold in nanoseconds and compares it against the SBOM's `metadata.timestamp` field: + +1. **Converts 30 days to nanoseconds**: `30 * 24 * 60 * 60 * 1000 * 1000 * 1000` +2. **Parses the SBOM timestamp** using `time.parse_rfc3339_ns()` +3. **Checks if current time minus (SBOM time + threshold) is positive** +4. **If positive, the SBOM is too old** and a violation is raised + +## Available Material Types + +For the complete list of supported material types, see the [Material Types documentation](https://docs.chainloop.dev/concepts/material-types#material-types). + +Common material types for the `--kind` parameter: + +- `SBOM_CYCLONEDX_JSON` - CycloneDX SBOM files +- `SBOM_SPDX_JSON` - SPDX SBOM files +- `CONTAINER_IMAGE` - Container images +- `ATTESTATION` - Generic attestations +- `SARIF` - SARIF security scan results +- `SLSA_PROVENANCE` - SLSA provenance attestations + +Run `chainloop policy develop eval --help` for the complete list. + +## Common Issues + +1. **Rego type conflicts**: Remove `default violations := []` when using `violations contains msg if` rules +2. **Missing material kind**: Always specify `--kind` parameter in eval command +3. **File naming**: Policy files are named based on the `--name` parameter, not always `policy.yaml` +4. **Time calculations**: Use nanoseconds for time comparisons in Rego policies + +## Next Steps + +Once you've mastered the basics: + +1. Explore more complex examples in the [policy examples]](../) directory +2. Learn about policy inputs and annotations +3. Practice with different material types +4. Deploy policies to your Chainloop workflows \ No newline at end of file diff --git a/docs/examples/policies/quickstart/cdx-fresh.json b/docs/examples/policies/quickstart/cdx-fresh.json new file mode 100644 index 000000000..22cda5339 --- /dev/null +++ b/docs/examples/policies/quickstart/cdx-fresh.json @@ -0,0 +1,25 @@ +{ + "bomFormat": "CycloneDX", + "specVersion": "1.5", + "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b80", + "version": 1, + "metadata": { + "timestamp": "2025-07-27T10:30:00Z", + "tools": [ + { + "vendor": "chainloop", + "name": "chainloop", + "version": "0.1.0" + } + ] + }, + "components": [ + { + "type": "library", + "bom-ref": "pkg:npm/express@4.18.0", + "name": "express", + "version": "4.18.0", + "purl": "pkg:npm/express@4.18.0" + } + ] +} \ No newline at end of file diff --git a/docs/examples/policies/quickstart/cdx-fresh.yaml b/docs/examples/policies/quickstart/cdx-fresh.yaml new file mode 100644 index 000000000..6f9448795 --- /dev/null +++ b/docs/examples/policies/quickstart/cdx-fresh.yaml @@ -0,0 +1,57 @@ +apiVersion: workflowcontract.chainloop.dev/v1 +kind: Policy +metadata: + name: cdx-fresh + description: Checks that SBOM is maximum of 30 days old + annotations: + category: quickstart +spec: + policies: + - embedded: | + package main + + import rego.v1 + + ################################ + # Common section do NOT change # + ################################ + + result := { + "skipped": skipped, + "violations": violations, + "skip_reason": skip_reason, + "ignore": ignore, + } + + default skip_reason := "" + + skip_reason := m if { + not valid_input + m := "invalid input" + } + + default skipped := true + + skipped := false if valid_input + + default ignore := false + + ######################################## + # EO Common section, custom code below # + ######################################## + # Validates if the input is valid and can be understood by this policy + valid_input := true + + limit := 30 + nanosecs_per_second := (1000 * 1000) * 1000 + nanosecs_per_day := ((24 * 60) * 60) * nanosecs_per_second + maximum_age := limit * nanosecs_per_day + + # If the input is valid, check for any policy violation here + violations contains msg if { + sbom_ns = time.parse_rfc3339_ns(input.metadata.timestamp) + exceeding = time.now_ns() - (sbom_ns + maximum_age) + exceeding > 0 + msg := sprintf("SBOM created at: %s which is too old (freshness limit set to %d days)", [input.metadata.timestamp, limit]) + } + kind: SBOM_CYCLONEDX_JSON diff --git a/docs/examples/policies/quickstart/cdx-old.json b/docs/examples/policies/quickstart/cdx-old.json new file mode 100644 index 000000000..d251255bb --- /dev/null +++ b/docs/examples/policies/quickstart/cdx-old.json @@ -0,0 +1,25 @@ +{ + "bomFormat": "CycloneDX", + "specVersion": "1.5", + "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", + "version": 1, + "metadata": { + "timestamp": "2024-06-15T10:30:00Z", + "tools": [ + { + "vendor": "chainloop", + "name": "chainloop", + "version": "0.1.0" + } + ] + }, + "components": [ + { + "type": "library", + "bom-ref": "pkg:npm/express@4.18.0", + "name": "express", + "version": "4.18.0", + "purl": "pkg:npm/express@4.18.0" + } + ] +} \ No newline at end of file