save progress
This commit is contained in:
465
docs/flows/10-cicd-gate-flow.md
Normal file
465
docs/flows/10-cicd-gate-flow.md
Normal file
@@ -0,0 +1,465 @@
|
||||
# CI/CD Gate Flow
|
||||
|
||||
## Overview
|
||||
|
||||
The CI/CD Gate Flow describes how StellaOps integrates into continuous integration and deployment pipelines to provide automated security gates. The flow covers CLI-based scanning, policy evaluation, and pass/fail decisions that control pipeline progression.
|
||||
|
||||
**Business Value**: Shift-left security by catching vulnerabilities before deployment, with deterministic, reproducible verdicts that integrate into existing DevOps workflows.
|
||||
|
||||
## Actors
|
||||
|
||||
| Actor | Type | Role |
|
||||
|-------|------|------|
|
||||
| CI Pipeline | System | GitHub Actions, GitLab CI, Jenkins, etc. |
|
||||
| StellaOps CLI | Tool | Executes scans from pipeline |
|
||||
| Gateway | Service | API entry point |
|
||||
| Scanner | Service | Performs image analysis |
|
||||
| Policy Engine | Service | Evaluates security policies |
|
||||
| Attestor | Service | Signs scan results |
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- StellaOps CLI installed in CI environment
|
||||
- API credentials configured (token or OIDC)
|
||||
- Policy set defined for the pipeline
|
||||
- Container image built and available
|
||||
|
||||
## Supported CI/CD Platforms
|
||||
|
||||
| Platform | Integration Method | Credentials |
|
||||
|----------|-------------------|-------------|
|
||||
| GitHub Actions | Action + CLI | OIDC or PAT |
|
||||
| GitLab CI | Job template + CLI | CI_JOB_TOKEN or PAT |
|
||||
| Azure DevOps | Task + CLI | Service connection |
|
||||
| Jenkins | Plugin + CLI | Credentials binding |
|
||||
| CircleCI | Orb + CLI | Context variables |
|
||||
| Tekton | Task + CLI | Kubernetes secrets |
|
||||
|
||||
## Flow Diagram
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ CI/CD Gate Flow │
|
||||
└─────────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
┌────────────┐ ┌───────────┐ ┌─────────┐ ┌─────────┐ ┌────────┐ ┌─────────┐
|
||||
│ CI Pipeline│ │StellaOps │ │ Gateway │ │ Scanner │ │ Policy │ │ Attestor│
|
||||
│ │ │ CLI │ │ │ │ │ │ │ │ │
|
||||
└─────┬──────┘ └─────┬─────┘ └────┬────┘ └────┬────┘ └───┬────┘ └────┬────┘
|
||||
│ │ │ │ │ │
|
||||
│ docker build │ │ │ │ │
|
||||
│───────┐ │ │ │ │ │
|
||||
│ │ │ │ │ │ │
|
||||
│<──────┘ │ │ │ │ │
|
||||
│ │ │ │ │ │
|
||||
│ stellaops │ │ │ │ │
|
||||
│ scan │ │ │ │ │
|
||||
│ --policy=prod │ │ │ │ │
|
||||
│──────────────>│ │ │ │ │
|
||||
│ │ │ │ │ │
|
||||
│ │ POST /scans │ │ │ │
|
||||
│ │────────────>│ │ │ │
|
||||
│ │ │ │ │ │
|
||||
│ │ │ Dispatch │ │ │
|
||||
│ │ │───────────>│ │ │
|
||||
│ │ │ │ │ │
|
||||
│ │ │ │ Analyze │ │
|
||||
│ │ │ │ image │ │
|
||||
│ │ │ │───┐ │ │
|
||||
│ │ │ │ │ │ │
|
||||
│ │ │ │<──┘ │ │
|
||||
│ │ │ │ │ │
|
||||
│ │ │ │ Evaluate │ │
|
||||
│ │ │ │──────────>│ │
|
||||
│ │ │ │ │ │
|
||||
│ │ │ │ │ Apply │
|
||||
│ │ │ │ │ rules │
|
||||
│ │ │ │ │───┐ │
|
||||
│ │ │ │ │ │ │
|
||||
│ │ │ │ │<──┘ │
|
||||
│ │ │ │ │ │
|
||||
│ │ │ │ Verdict │ │
|
||||
│ │ │ │<──────────│ │
|
||||
│ │ │ │ │ │
|
||||
│ │ │ │ Sign │ │
|
||||
│ │ │ │──────────────────────>│
|
||||
│ │ │ │ │ │
|
||||
│ │ │ │ DSSE │ │
|
||||
│ │ │ │<──────────────────────│
|
||||
│ │ │ │ │ │
|
||||
│ │ │ Result │ │ │
|
||||
│ │ │<───────────│ │ │
|
||||
│ │ │ │ │ │
|
||||
│ │ Verdict │ │ │ │
|
||||
│ │<────────────│ │ │ │
|
||||
│ │ │ │ │ │
|
||||
│ Exit code │ │ │ │ │
|
||||
│ (0=pass, │ │ │ │ │
|
||||
│ 1=fail) │ │ │ │ │
|
||||
│<──────────────│ │ │ │ │
|
||||
│ │ │ │ │ │
|
||||
│ [if pass] │ │ │ │ │
|
||||
│ docker push │ │ │ │ │
|
||||
│───────┐ │ │ │ │ │
|
||||
│ │ │ │ │ │ │
|
||||
│<──────┘ │ │ │ │ │
|
||||
│ │ │ │ │ │
|
||||
```
|
||||
|
||||
## Step-by-Step
|
||||
|
||||
### 1. Pipeline Configuration
|
||||
|
||||
#### GitHub Actions Example
|
||||
|
||||
```yaml
|
||||
name: Build and Scan
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
build-and-scan:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write # For OIDC
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Build Docker image
|
||||
run: |
|
||||
docker build -t myapp:${{ github.sha }} .
|
||||
|
||||
- name: Install StellaOps CLI
|
||||
run: |
|
||||
curl -sSL https://get.stellaops.io/cli | sh
|
||||
echo "$HOME/.stellaops/bin" >> $GITHUB_PATH
|
||||
|
||||
- name: Authenticate with OIDC
|
||||
run: |
|
||||
stellaops auth login --oidc \
|
||||
--issuer ${{ secrets.STELLAOPS_OIDC_ISSUER }} \
|
||||
--client-id ${{ secrets.STELLAOPS_CLIENT_ID }}
|
||||
|
||||
- name: Scan image
|
||||
id: scan
|
||||
run: |
|
||||
stellaops scan myapp:${{ github.sha }} \
|
||||
--policy production \
|
||||
--format sarif \
|
||||
--output results.sarif \
|
||||
--attestation \
|
||||
--fail-on violation
|
||||
|
||||
- name: Upload SARIF to GitHub Security
|
||||
if: always()
|
||||
uses: github/codeql-action/upload-sarif@v2
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
|
||||
- name: Push to registry
|
||||
if: steps.scan.outcome == 'success'
|
||||
run: |
|
||||
docker tag myapp:${{ github.sha }} ghcr.io/org/myapp:${{ github.sha }}
|
||||
docker push ghcr.io/org/myapp:${{ github.sha }}
|
||||
```
|
||||
|
||||
#### GitLab CI Example
|
||||
|
||||
```yaml
|
||||
stages:
|
||||
- build
|
||||
- scan
|
||||
- deploy
|
||||
|
||||
variables:
|
||||
STELLAOPS_API_URL: https://api.stellaops.local
|
||||
|
||||
build:
|
||||
stage: build
|
||||
script:
|
||||
- docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
|
||||
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
|
||||
|
||||
scan:
|
||||
stage: scan
|
||||
image: stellaops/cli:latest
|
||||
script:
|
||||
- stellaops auth login --token $STELLAOPS_TOKEN
|
||||
- stellaops scan $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
|
||||
--policy production
|
||||
--fail-on violation
|
||||
artifacts:
|
||||
reports:
|
||||
sast: gl-sast-report.json
|
||||
|
||||
deploy:
|
||||
stage: deploy
|
||||
needs: [scan]
|
||||
script:
|
||||
- kubectl set image deployment/myapp app=$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
|
||||
```
|
||||
|
||||
### 2. CLI Authentication
|
||||
|
||||
The CLI supports multiple authentication methods:
|
||||
|
||||
| Method | Command | Use Case |
|
||||
|--------|---------|----------|
|
||||
| Token | `stellaops auth login --token $TOKEN` | CI/CD with secrets |
|
||||
| OIDC | `stellaops auth login --oidc` | GitHub/GitLab OIDC |
|
||||
| Interactive | `stellaops auth login` | Local development |
|
||||
| Keyless | `stellaops auth login --keyless` | Sigstore OIDC |
|
||||
|
||||
### 3. Scan Execution
|
||||
|
||||
CLI submits scan request and waits for completion:
|
||||
|
||||
```bash
|
||||
stellaops scan docker.io/myorg/myapp:v1.2.3 \
|
||||
--policy production \
|
||||
--format json \
|
||||
--output scan-results.json \
|
||||
--attestation \
|
||||
--timeout 5m \
|
||||
--fail-on violation
|
||||
```
|
||||
|
||||
#### CLI Options
|
||||
|
||||
| Option | Description | Default |
|
||||
|--------|-------------|---------|
|
||||
| `--policy` | Policy set to evaluate against | `default` |
|
||||
| `--format` | Output format (json, sarif, table) | `table` |
|
||||
| `--output` | Write results to file | stdout |
|
||||
| `--attestation` | Generate DSSE attestation | false |
|
||||
| `--timeout` | Maximum wait time | 10m |
|
||||
| `--fail-on` | Exit 1 on: `violation`, `warning`, `any` | `violation` |
|
||||
| `--quiet` | Suppress progress output | false |
|
||||
|
||||
### 4. Policy Evaluation
|
||||
|
||||
Policy engine evaluates findings against CI-specific rules:
|
||||
|
||||
```yaml
|
||||
# Policy Set: production
|
||||
version: "stella-dsl@1"
|
||||
name: production
|
||||
|
||||
rules:
|
||||
- name: block-critical
|
||||
condition: severity == 'critical' AND vex_status != 'not_affected'
|
||||
action: FAIL
|
||||
|
||||
- name: block-high-unfixed
|
||||
condition: severity == 'high' AND fixed_version == null
|
||||
action: FAIL
|
||||
|
||||
- name: block-known-exploited
|
||||
condition: kev == true
|
||||
action: FAIL
|
||||
|
||||
- name: require-sbom
|
||||
condition: sbom_complete == false
|
||||
action: FAIL
|
||||
message: "SBOM must cover all detected packages"
|
||||
|
||||
gates:
|
||||
ci:
|
||||
max_critical: 0
|
||||
max_high_unfixed: 0
|
||||
require_attestation: true
|
||||
```
|
||||
|
||||
### 5. Verdict and Exit Code
|
||||
|
||||
CLI translates verdict to exit code:
|
||||
|
||||
| Verdict | Exit Code | Pipeline Result |
|
||||
|---------|-----------|-----------------|
|
||||
| PASS | 0 | Continue |
|
||||
| WARN | 0 (or 1 if `--fail-on warning`) | Continue with warning |
|
||||
| FAIL | 1 | Block deployment |
|
||||
| ERROR | 2 | Pipeline failure |
|
||||
|
||||
### 6. SARIF Integration
|
||||
|
||||
CLI outputs SARIF for IDE and GitHub integration:
|
||||
|
||||
```json
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json",
|
||||
"version": "2.1.0",
|
||||
"runs": [
|
||||
{
|
||||
"tool": {
|
||||
"driver": {
|
||||
"name": "StellaOps",
|
||||
"version": "2.1.0",
|
||||
"informationUri": "https://stellaops.io"
|
||||
}
|
||||
},
|
||||
"results": [
|
||||
{
|
||||
"ruleId": "CVE-2024-1234",
|
||||
"level": "error",
|
||||
"message": {
|
||||
"text": "Critical vulnerability in lodash@4.17.20"
|
||||
},
|
||||
"locations": [
|
||||
{
|
||||
"physicalLocation": {
|
||||
"artifactLocation": {
|
||||
"uri": "package-lock.json"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 7. Attestation Storage
|
||||
|
||||
If `--attestation` is specified, CLI stores attestation:
|
||||
|
||||
```bash
|
||||
# View attestation
|
||||
stellaops attestation show --scan $SCAN_ID
|
||||
|
||||
# Verify attestation
|
||||
stellaops attestation verify --image myapp:v1.2.3 --policy production
|
||||
```
|
||||
|
||||
Attestation is stored as DSSE envelope:
|
||||
```json
|
||||
{
|
||||
"payloadType": "application/vnd.in-toto+json",
|
||||
"payload": "eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjEi...",
|
||||
"signatures": [
|
||||
{
|
||||
"keyid": "sha256:abc123...",
|
||||
"sig": "MEQCI..."
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Gate Behaviors
|
||||
|
||||
### Soft Gate (Warning Only)
|
||||
|
||||
```yaml
|
||||
# .stellaops.yaml
|
||||
gates:
|
||||
ci:
|
||||
mode: soft # Report but don't fail
|
||||
notify:
|
||||
- slack://security-channel
|
||||
```
|
||||
|
||||
### Hard Gate (Blocking)
|
||||
|
||||
```yaml
|
||||
gates:
|
||||
ci:
|
||||
mode: hard # Fail pipeline on violations
|
||||
exceptions:
|
||||
- CVE-2024-9999 # Known false positive
|
||||
```
|
||||
|
||||
### Progressive Gate
|
||||
|
||||
```yaml
|
||||
gates:
|
||||
ci:
|
||||
mode: progressive
|
||||
thresholds:
|
||||
- branch: main
|
||||
max_critical: 0
|
||||
max_high: 5
|
||||
- branch: develop
|
||||
max_critical: 2
|
||||
max_high: 20
|
||||
- branch: feature/*
|
||||
mode: soft # Warn only on feature branches
|
||||
```
|
||||
|
||||
## Data Contracts
|
||||
|
||||
### CLI Scan Output Schema
|
||||
|
||||
```typescript
|
||||
interface CliScanOutput {
|
||||
scan_id: string;
|
||||
image: string;
|
||||
digest: string;
|
||||
verdict: 'PASS' | 'WARN' | 'FAIL';
|
||||
confidence: number;
|
||||
summary: {
|
||||
critical: number;
|
||||
high: number;
|
||||
medium: number;
|
||||
low: number;
|
||||
};
|
||||
violations: Array<{
|
||||
cve: string;
|
||||
severity: string;
|
||||
package: string;
|
||||
rule: string;
|
||||
message: string;
|
||||
}>;
|
||||
attestation?: {
|
||||
digest: string;
|
||||
rekor_log_index?: number;
|
||||
};
|
||||
timing: {
|
||||
queued_ms: number;
|
||||
scan_ms: number;
|
||||
policy_ms: number;
|
||||
total_ms: number;
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Error | Exit Code | Recovery |
|
||||
|-------|-----------|----------|
|
||||
| Auth failure | 2 | Check credentials |
|
||||
| Image not found | 2 | Verify image reference |
|
||||
| API timeout | 2 | Retry with --timeout |
|
||||
| Policy not found | 2 | Check policy name |
|
||||
| Network error | 2 | Check connectivity |
|
||||
|
||||
## Observability
|
||||
|
||||
### Metrics
|
||||
|
||||
| Metric | Type | Labels |
|
||||
|--------|------|--------|
|
||||
| `cli_scan_total` | Counter | `verdict`, `ci_platform` |
|
||||
| `cli_scan_duration_seconds` | Histogram | `ci_platform` |
|
||||
| `cli_gate_blocked_total` | Counter | `policy`, `reason` |
|
||||
|
||||
### CI/CD Annotations
|
||||
|
||||
GitHub Actions annotations:
|
||||
```
|
||||
::error file=package-lock.json::CVE-2024-1234: Critical vulnerability in lodash@4.17.20
|
||||
::warning file=Dockerfile::Using outdated base image
|
||||
```
|
||||
|
||||
## Related Flows
|
||||
|
||||
- [Scan Submission Flow](02-scan-submission-flow.md) - Underlying scan mechanics
|
||||
- [Policy Evaluation Flow](04-policy-evaluation-flow.md) - Policy rule details
|
||||
- [Binary Delta Attestation Flow](15-binary-delta-attestation-flow.md) - Attestation details
|
||||
Reference in New Issue
Block a user