Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 121 additions & 0 deletions docs/examples/policies/quickstart/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
# Policy Development Quickstart
Comment thread
danlishka marked this conversation as resolved.

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
25 changes: 25 additions & 0 deletions docs/examples/policies/quickstart/cdx-fresh.json
Original file line number Diff line number Diff line change
@@ -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"
}
]
}
57 changes: 57 additions & 0 deletions docs/examples/policies/quickstart/cdx-fresh.yaml
Original file line number Diff line number Diff line change
@@ -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
25 changes: 25 additions & 0 deletions docs/examples/policies/quickstart/cdx-old.json
Original file line number Diff line number Diff line change
@@ -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"
}
]
}
Loading