archive audit attempts

This commit is contained in:
master
2026-02-19 22:00:31 +02:00
parent c2f13fe588
commit b5829dce5c
19638 changed files with 6366 additions and 7 deletions

View File

@@ -0,0 +1,177 @@
# CI SBOM Attestation Pipeline Guide
## Overview
This guide explains how to integrate Stella Ops' SBOM canonicalization, DSSE attestation, and VEX mapping checks into your CI/CD pipeline using Gitea Actions workflow templates.
The pipeline consists of three stages:
1. **SBOM Canonicalization** - Validate schema and compute deterministic canonical_id
2. **DSSE Attest + Verify** - Sign attestation and verify transparency log inclusion
3. **VEX Mapping** - Validate VEX documents and verify artifact targeting
## Prerequisites
- Gitea Actions runner with the Stella Ops CI image (`devops/docker/Dockerfile.ci`)
- Tools: `sbom-utility`, `cosign`, `rekor-cli`, `python3`, `ajv-cli` (all included in CI image)
- For keyless signing: OIDC token provider (Gitea Actions built-in)
- For keyed signing: `COSIGN_PRIVATE_KEY_B64` secret configured
## Quick Start
### Stage 1: SBOM Canonicalization Check
Add to your workflow:
```yaml
jobs:
sbom-check:
uses: ./.gitea/workflows/templates/sbom-canonicalization-check.yml
with:
bom_path: sbom.json
# Optional: pin to a known canonical_id for regression testing
# expected_canonical_id: 'sha256:abc123...'
```
**What it does:**
- Validates the SBOM against the CycloneDX 1.7 JSON schema
- Computes `canonical_id := sha256(JCS(sbom.json))` per RFC 8785
- Verifies canonicalization is deterministic (computes twice, asserts match)
- Optionally checks against a known `expected_canonical_id` for regression
**Outputs:**
- `canonical_id` - The computed canonical identifier (e.g., `sha256:abc123...`)
- `validation_result` - Schema validation result (`pass` or `fail`)
### Stage 2: DSSE Attestation + Verification
```yaml
jobs:
attest:
needs: sbom-check
uses: ./.gitea/workflows/templates/dsse-attest-verify-check.yml
with:
subject_ref: 'ghcr.io/org/repo@sha256:...'
predicate_path: sbom.json
signing_mode: keyless # or 'key'
predicate_type: 'https://cyclonedx.org/bom'
# skip_rekor: true # For air-gapped environments
```
**What it does:**
- Signs the SBOM as a DSSE/in-toto attestation using cosign
- Verifies the attestation signature
- Validates Rekor transparency log inclusion proof
**Signing Modes:**
| Mode | Description | When to Use |
|------|-------------|-------------|
| `keyless` | Fulcio/OIDC ephemeral certificate | CI runners with OIDC (default) |
| `key` | Cosign key pair (PEM) | Air-gapped, self-managed keys |
### Stage 3: VEX Mapping Check
```yaml
jobs:
vex-check:
needs: sbom-check
uses: ./.gitea/workflows/templates/vex-mapping-check.yml
with:
vex_path: vex.json
vex_format: openvex # or 'cyclonedx'
canonical_id: ${{ needs.sbom-check.outputs.canonical_id }}
```
**What it does:**
- Validates the VEX document against its schema (OpenVEX or CycloneDX VEX)
- Asserts required fields: `status`, `vulnerability`, `product`
- Verifies the VEX targets match the expected `canonical_id`
## Complete Pipeline Example
```yaml
name: SBOM Evidence Pipeline
on:
push:
branches: [main]
pull_request:
jobs:
build-and-scan:
runs-on: ubuntu-latest
outputs:
sbom_path: sbom.json
image_ref: ${{ steps.build.outputs.image_ref }}
steps:
- uses: actions/checkout@v4
- name: Build image
id: build
run: |
# Build your container image
docker build -t myapp .
echo "image_ref=ghcr.io/org/myapp@sha256:..." >> $GITHUB_OUTPUT
- name: Generate SBOM
run: stella scan --image myapp --output-sbom sbom.json --format cyclonedx-1.7
- uses: actions/upload-artifact@v4
with:
name: evidence
path: sbom.json
canonicalize:
needs: build-and-scan
uses: ./.gitea/workflows/templates/sbom-canonicalization-check.yml
with:
bom_path: sbom.json
attest:
needs: [build-and-scan, canonicalize]
if: github.event_name != 'pull_request'
uses: ./.gitea/workflows/templates/dsse-attest-verify-check.yml
with:
subject_ref: ${{ needs.build-and-scan.outputs.image_ref }}
predicate_path: sbom.json
signing_mode: keyless
vex-check:
needs: canonicalize
if: hashFiles('vex.json') != ''
uses: ./.gitea/workflows/templates/vex-mapping-check.yml
with:
vex_path: vex.json
vex_format: openvex
canonical_id: ${{ needs.canonicalize.outputs.canonical_id }}
```
## Air-Gap Mode
For environments without internet access:
1. **Skip Rekor**: Set `skip_rekor: true` in the attestation workflow
2. **Use keyed signing**: Pre-distribute cosign keys, use `signing_mode: key`
3. **Bundle schemas locally**: Schemas are already in `docs/schemas/` (no network fetch)
4. **Verification**: Use bundled checkpoints for offline Rekor verification:
```bash
stella attest verify --offline --checkpoint-bundle /path/to/checkpoints
```
## Failure Modes
| Assertion | Failure | What to Do |
|-----------|---------|------------|
| Schema validation | Invalid CycloneDX | Check SBOM generator version; validate against `docs/schemas/cyclonedx-bom-1.7.schema.json` |
| Determinism check | Hash differs between runs | Non-deterministic SBOM generation; check for timestamps, random values, unstable ordering |
| Regression check | canonical_id changed | SBOM content changed; update `expected_canonical_id` or investigate drift |
| Attestation signing | Cosign error | Check signing key/OIDC token; verify registry access |
| Attestation verification | Signature invalid | Key mismatch or tampered attestation; re-sign |
| Rekor proof | Entry not found | May be pending; retry after 30s; check Rekor connectivity |
| VEX schema | Invalid document | Check VEX format matches `vex_format` input; validate manually |
| VEX field assertions | Missing status | VEX statements must have `status` field; check VEX generator |
| Target mismatch | canonical_id not in VEX | VEX document targets different artifact; verify PURL/product matching |
## Related Documentation
- Contract: `docs/contracts/canonical-sbom-id-v1.md` - Canonical ID computation rules
- Contract: `docs/contracts/artifact-canonical-record-v1.md` - Unified evidence record
- Module: `docs/modules/attestor/architecture.md` - Attestor DSSE pipeline
- Module: `docs/modules/signer/architecture.md` - Signing modes and configuration