372 lines
8.6 KiB
Markdown
372 lines
8.6 KiB
Markdown
# CI/CD Integration
|
|
|
|
This example demonstrates how to integrate binary diff attestation into your CI/CD pipelines.
|
|
|
|
## GitHub Actions
|
|
|
|
### Basic Workflow
|
|
|
|
```yaml
|
|
# .github/workflows/binary-diff.yml
|
|
name: Binary Diff Attestation
|
|
|
|
on:
|
|
push:
|
|
tags:
|
|
- 'v*'
|
|
|
|
jobs:
|
|
binary-diff:
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: read
|
|
id-token: write # For keyless signing
|
|
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Setup Stella CLI
|
|
uses: stellaops/setup-stella@v1
|
|
with:
|
|
version: 'latest'
|
|
|
|
- name: Login to Registry
|
|
uses: docker/login-action@v3
|
|
with:
|
|
registry: ghcr.io
|
|
username: ${{ github.actor }}
|
|
password: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
- name: Get Previous Tag
|
|
id: prev-tag
|
|
run: |
|
|
PREV_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "")
|
|
echo "tag=$PREV_TAG" >> $GITHUB_OUTPUT
|
|
|
|
- name: Binary Diff
|
|
if: steps.prev-tag.outputs.tag != ''
|
|
run: |
|
|
stella scan diff \
|
|
--base ghcr.io/${{ github.repository }}:${{ steps.prev-tag.outputs.tag }} \
|
|
--target ghcr.io/${{ github.repository }}:${{ github.ref_name }} \
|
|
--mode=elf \
|
|
--emit-dsse=./attestations/ \
|
|
--format=json > diff.json
|
|
|
|
- name: Upload Attestations
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: binary-diff-attestations
|
|
path: |
|
|
attestations/
|
|
diff.json
|
|
|
|
- name: Attach Attestation to Image
|
|
run: |
|
|
# Using cosign to attach attestation
|
|
cosign attach attestation \
|
|
--attestation ./attestations/linux-amd64-binarydiff.dsse.json \
|
|
ghcr.io/${{ github.repository }}:${{ github.ref_name }}
|
|
```
|
|
|
|
### With Release Gate
|
|
|
|
```yaml
|
|
# .github/workflows/release-gate.yml
|
|
name: Release Gate with Binary Diff
|
|
|
|
on:
|
|
workflow_dispatch:
|
|
inputs:
|
|
base_version:
|
|
description: 'Base version to compare'
|
|
required: true
|
|
target_version:
|
|
description: 'Target version to release'
|
|
required: true
|
|
|
|
jobs:
|
|
binary-diff-gate:
|
|
runs-on: ubuntu-latest
|
|
outputs:
|
|
verdict: ${{ steps.analyze.outputs.verdict }}
|
|
|
|
steps:
|
|
- name: Setup Stella CLI
|
|
uses: stellaops/setup-stella@v1
|
|
|
|
- name: Binary Diff Analysis
|
|
id: diff
|
|
run: |
|
|
stella scan diff \
|
|
--base myapp:${{ inputs.base_version }} \
|
|
--target myapp:${{ inputs.target_version }} \
|
|
--format=json > diff.json
|
|
|
|
- name: Analyze Results
|
|
id: analyze
|
|
run: |
|
|
# Check for unknown verdicts
|
|
UNKNOWN_COUNT=$(jq '.summary.verdicts.unknown // 0' diff.json)
|
|
if [ "$UNKNOWN_COUNT" -gt "0" ]; then
|
|
echo "verdict=review-required" >> $GITHUB_OUTPUT
|
|
echo "::warning::Found $UNKNOWN_COUNT binaries with unknown verdicts"
|
|
else
|
|
echo "verdict=approved" >> $GITHUB_OUTPUT
|
|
fi
|
|
|
|
- name: Gate Decision
|
|
if: steps.analyze.outputs.verdict == 'review-required'
|
|
run: |
|
|
echo "Manual review required for unknown binary changes"
|
|
exit 1
|
|
```
|
|
|
|
## GitLab CI
|
|
|
|
### Basic Pipeline
|
|
|
|
```yaml
|
|
# .gitlab-ci.yml
|
|
stages:
|
|
- build
|
|
- analyze
|
|
- release
|
|
|
|
variables:
|
|
STELLA_VERSION: "latest"
|
|
|
|
binary-diff:
|
|
stage: analyze
|
|
image: stellaops/cli:${STELLA_VERSION}
|
|
script:
|
|
- |
|
|
# Get previous tag
|
|
PREV_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "")
|
|
|
|
if [ -n "$PREV_TAG" ]; then
|
|
stella scan diff \
|
|
--base ${CI_REGISTRY_IMAGE}:${PREV_TAG} \
|
|
--target ${CI_REGISTRY_IMAGE}:${CI_COMMIT_TAG} \
|
|
--mode=elf \
|
|
--emit-dsse=attestations/ \
|
|
--format=json > diff.json
|
|
|
|
# Upload to GitLab artifacts
|
|
echo "Binary diff completed"
|
|
else
|
|
echo "No previous tag found, skipping diff"
|
|
fi
|
|
artifacts:
|
|
paths:
|
|
- attestations/
|
|
- diff.json
|
|
expire_in: 30 days
|
|
only:
|
|
- tags
|
|
```
|
|
|
|
### With Security Gate
|
|
|
|
```yaml
|
|
# .gitlab-ci.yml
|
|
security-gate:
|
|
stage: analyze
|
|
image: stellaops/cli:latest
|
|
script:
|
|
- |
|
|
stella scan diff \
|
|
--base ${CI_REGISTRY_IMAGE}:${BASE_VERSION} \
|
|
--target ${CI_REGISTRY_IMAGE}:${TARGET_VERSION} \
|
|
--format=json > diff.json
|
|
|
|
# Fail if any unknown verdicts
|
|
UNKNOWN=$(jq '.summary.verdicts.unknown // 0' diff.json)
|
|
if [ "$UNKNOWN" -gt "0" ]; then
|
|
echo "Security gate failed: $UNKNOWN unknown binary changes"
|
|
jq '.findings[] | select(.verdict == "unknown")' diff.json
|
|
exit 1
|
|
fi
|
|
|
|
echo "Security gate passed"
|
|
allow_failure: false
|
|
```
|
|
|
|
## Jenkins Pipeline
|
|
|
|
```groovy
|
|
// Jenkinsfile
|
|
pipeline {
|
|
agent any
|
|
|
|
environment {
|
|
STELLA_VERSION = 'latest'
|
|
}
|
|
|
|
stages {
|
|
stage('Binary Diff') {
|
|
steps {
|
|
script {
|
|
def prevTag = sh(
|
|
script: 'git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo ""',
|
|
returnStdout: true
|
|
).trim()
|
|
|
|
if (prevTag) {
|
|
sh """
|
|
stella scan diff \\
|
|
--base ${REGISTRY}/${IMAGE}:${prevTag} \\
|
|
--target ${REGISTRY}/${IMAGE}:${TAG} \\
|
|
--mode=elf \\
|
|
--emit-dsse=attestations/ \\
|
|
--format=json > diff.json
|
|
"""
|
|
|
|
archiveArtifacts artifacts: 'attestations/*, diff.json'
|
|
|
|
// Parse and check results
|
|
def diff = readJSON file: 'diff.json'
|
|
if (diff.summary.verdicts.unknown > 0) {
|
|
unstable("Found ${diff.summary.verdicts.unknown} unknown binary changes")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
## Azure DevOps
|
|
|
|
```yaml
|
|
# azure-pipelines.yml
|
|
trigger:
|
|
tags:
|
|
include:
|
|
- v*
|
|
|
|
pool:
|
|
vmImage: 'ubuntu-latest'
|
|
|
|
steps:
|
|
- task: Bash@3
|
|
displayName: 'Install Stella CLI'
|
|
inputs:
|
|
targetType: 'inline'
|
|
script: |
|
|
curl -sSL https://get.stellaops.io | sh
|
|
stella --version
|
|
|
|
- task: Docker@2
|
|
displayName: 'Login to Registry'
|
|
inputs:
|
|
containerRegistry: 'myRegistry'
|
|
command: 'login'
|
|
|
|
- task: Bash@3
|
|
displayName: 'Binary Diff'
|
|
inputs:
|
|
targetType: 'inline'
|
|
script: |
|
|
PREV_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "")
|
|
if [ -n "$PREV_TAG" ]; then
|
|
stella scan diff \
|
|
--base $(REGISTRY)/$(IMAGE):${PREV_TAG} \
|
|
--target $(REGISTRY)/$(IMAGE):$(Build.SourceBranchName) \
|
|
--mode=elf \
|
|
--emit-dsse=$(Build.ArtifactStagingDirectory)/attestations/ \
|
|
--format=json > $(Build.ArtifactStagingDirectory)/diff.json
|
|
fi
|
|
|
|
- task: PublishBuildArtifacts@1
|
|
inputs:
|
|
pathToPublish: '$(Build.ArtifactStagingDirectory)'
|
|
artifactName: 'binary-diff'
|
|
```
|
|
|
|
## Best Practices
|
|
|
|
### 1. Always Use Digest References in Production
|
|
|
|
```bash
|
|
# Instead of tags
|
|
stella scan diff --base myapp:v1.0.0 --target myapp:v1.0.1
|
|
|
|
# Use digests for immutability
|
|
stella scan diff \
|
|
--base myapp@sha256:abc123... \
|
|
--target myapp@sha256:def456...
|
|
```
|
|
|
|
### 2. Store Attestations with Releases
|
|
|
|
Attach DSSE attestations to your container images or store them alongside release artifacts.
|
|
|
|
### 3. Set Appropriate Timeouts
|
|
|
|
```bash
|
|
# For large images, increase timeout
|
|
stella scan diff \
|
|
--base myapp:v1 \
|
|
--target myapp:v2 \
|
|
--timeout=600
|
|
```
|
|
|
|
### 4. Use Caching
|
|
|
|
```yaml
|
|
# GitHub Actions with caching
|
|
- uses: actions/cache@v4
|
|
with:
|
|
path: ~/.stella/cache
|
|
key: stella-${{ runner.os }}-${{ hashFiles('**/Dockerfile') }}
|
|
```
|
|
|
|
### 5. Fail Fast on Critical Issues
|
|
|
|
```bash
|
|
# Exit code indicates issues
|
|
stella scan diff --base old --target new --format=json > diff.json
|
|
if [ $? -ne 0 ]; then
|
|
echo "Diff failed"
|
|
exit 1
|
|
fi
|
|
|
|
# Check for critical verdicts
|
|
jq -e '.summary.verdicts.unknown == 0' diff.json || exit 1
|
|
```
|
|
|
|
## Troubleshooting
|
|
|
|
### Registry Authentication
|
|
|
|
```bash
|
|
# Use Docker config
|
|
stella scan diff \
|
|
--base myapp:v1 \
|
|
--target myapp:v2 \
|
|
--registry-auth=~/.docker/config.json
|
|
```
|
|
|
|
### Platform Issues
|
|
|
|
```bash
|
|
# Explicitly specify platform for multi-arch
|
|
stella scan diff \
|
|
--base myapp:v1 \
|
|
--target myapp:v2 \
|
|
--platform=linux/amd64
|
|
```
|
|
|
|
### Timeout Issues
|
|
|
|
```bash
|
|
# Increase timeout for slow registries
|
|
stella scan diff \
|
|
--base myapp:v1 \
|
|
--target myapp:v2 \
|
|
--timeout=900
|
|
```
|