audit work, fixed StellaOps.sln warnings/errors, fixed tests, sprints work, new advisories
This commit is contained in:
329
docs/technical/cicd/README.md
Normal file
329
docs/technical/cicd/README.md
Normal file
@@ -0,0 +1,329 @@
|
||||
# CI/CD Infrastructure Overview
|
||||
|
||||
> **Sprint:** CI/CD Enhancement - Documentation
|
||||
> **Last Updated:** 2025-12-28
|
||||
> **Workflow Count:** 100 workflows
|
||||
|
||||
## Quick Links
|
||||
|
||||
- [Workflow Triggers & Dependencies](./workflow-triggers.md)
|
||||
- [Release Pipelines](./release-pipelines.md)
|
||||
- [Security Scanning](./security-scanning.md)
|
||||
- [Test Strategy](./test-strategy.md)
|
||||
- [Troubleshooting Guide](../.gitea/docs/troubleshooting.md)
|
||||
|
||||
---
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
The StellaOps CI/CD infrastructure uses **Gitea Actions** (GitHub Actions compatible) with a sophisticated multi-tier triggering strategy designed for:
|
||||
|
||||
- **Determinism & Reproducibility** - Identical builds across runs
|
||||
- **Offline-First Operation** - Air-gap compatible pipelines
|
||||
- **Supply Chain Security** - SLSA Level 2-3 compliance
|
||||
- **Developer Velocity** - Fast PR feedback with comprehensive nightly testing
|
||||
|
||||
### Pipeline Tiers
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────────┐
|
||||
│ TRIGGER HIERARCHY │
|
||||
├─────────────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ TIER 1: PR GATING (Every Pull Request) │
|
||||
│ ├── test-matrix.yml (Unit, Architecture, Contract, Integration, │
|
||||
│ │ Security, Golden) │
|
||||
│ ├── build-test-deploy.yml (Build verification) │
|
||||
│ ├── policy-lint.yml (Policy file validation) │
|
||||
│ ├── sast-scan.yml (Static security analysis) │
|
||||
│ └── docs.yml (Documentation validation) │
|
||||
│ │
|
||||
│ TIER 2: MAIN BRANCH (Post-Merge) │
|
||||
│ ├── All Tier 1 workflows │
|
||||
│ ├── build-test-deploy.yml → Deploy stage (staging environment) │
|
||||
│ ├── integration-tests-gate.yml → Extended coverage │
|
||||
│ └── coverage-report (Full coverage analysis) │
|
||||
│ │
|
||||
│ TIER 3: SCHEDULED (Nightly/Weekly) │
|
||||
│ ├── nightly-regression.yml (2:00 AM UTC daily) │
|
||||
│ ├── test-matrix.yml → Extended tests (5:00 AM UTC daily) │
|
||||
│ ├── dependency-security-scan.yml (2:00 AM UTC Sunday) │
|
||||
│ ├── renovate.yml (3:00 AM & 3:00 PM UTC daily) │
|
||||
│ ├── sast-scan.yml (3:30 AM UTC Monday) │
|
||||
│ └── migration-test.yml (4:30 AM UTC daily) │
|
||||
│ │
|
||||
│ TIER 4: RELEASE (Tag-Triggered) │
|
||||
│ ├── release-suite.yml (suite-YYYY.MM tags) │
|
||||
│ ├── release.yml (v* tags) │
|
||||
│ └── module-publish.yml (module-*-v* tags) │
|
||||
│ │
|
||||
│ TIER 5: MANUAL (On-Demand) │
|
||||
│ ├── cli-build.yml, scanner-determinism.yml │
|
||||
│ ├── rollback.yml, promote.yml │
|
||||
│ └── 20+ specialized test/debug workflows │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Workflow Categories
|
||||
|
||||
### 1. Core Build & Test (12 workflows)
|
||||
|
||||
| Workflow | Purpose | Triggers |
|
||||
|----------|---------|----------|
|
||||
| `build-test-deploy.yml` | Main build pipeline | PR, main push, daily, manual |
|
||||
| `test-matrix.yml` | Unified test execution | PR, main push, daily, manual |
|
||||
| `integration-tests-gate.yml` | Extended integration testing | PR, main push, manual |
|
||||
| `nightly-regression.yml` | Comprehensive nightly suite | Daily 2 AM UTC |
|
||||
| `migration-test.yml` | Database migration validation | PR (migrations), daily |
|
||||
|
||||
### 2. Release Automation (8 workflows)
|
||||
|
||||
| Workflow | Purpose | Triggers |
|
||||
|----------|---------|----------|
|
||||
| `release-suite.yml` | Ubuntu-style suite releases | `suite-*` tags, manual |
|
||||
| `release.yml` | Version bundle releases | `v*` tags, manual |
|
||||
| `module-publish.yml` | Per-module publishing | `module-*-v*` tags, manual |
|
||||
| `cli-build.yml` | Multi-platform CLI builds | Manual only |
|
||||
| `promote.yml` | Environment promotion | Manual only |
|
||||
| `rollback.yml` | Emergency rollback | Manual only |
|
||||
|
||||
### 3. Security Scanning (6 workflows)
|
||||
|
||||
| Workflow | Purpose | Triggers |
|
||||
|----------|---------|----------|
|
||||
| `sast-scan.yml` | Static code analysis | PR, main push, weekly |
|
||||
| `secrets-scan.yml` | Credential detection | PR, main push |
|
||||
| `container-scan.yml` | Image vulnerability scanning | Dockerfile changes, daily |
|
||||
| `dependency-security-scan.yml` | NuGet/npm vulnerability audit | Weekly, PR (deps) |
|
||||
| `dependency-license-gate.yml` | License compliance | PR (deps) |
|
||||
|
||||
### 4. Quality Assurance (15 workflows)
|
||||
|
||||
| Workflow | Purpose | Triggers |
|
||||
|----------|---------|----------|
|
||||
| `policy-lint.yml` | Policy file validation | PR, main push |
|
||||
| `docs.yml` | Documentation linting | docs/** changes |
|
||||
| `scanner-determinism.yml` | Output reproducibility | Manual only |
|
||||
| `determinism-gate.yml` | Build determinism | Manual only |
|
||||
| `cross-platform-determinism.yml` | Multi-OS verification | Manual only |
|
||||
|
||||
### 5. Module-Specific (30+ workflows)
|
||||
|
||||
Specialized workflows for individual modules (Scanner, Concelier, Authority, etc.)
|
||||
|
||||
---
|
||||
|
||||
## Trigger Quick Reference
|
||||
|
||||
### Branch Patterns
|
||||
|
||||
| Pattern | Example | Workflows Triggered |
|
||||
|---------|---------|---------------------|
|
||||
| Push to `main` | Direct commit or merge | All Tier 1 + Tier 2 |
|
||||
| Push to `develop` | Feature integration | Selected gating workflows |
|
||||
| Pull Request | Any PR to main/develop | All Tier 1 (gating) |
|
||||
| Push to `feature/*` | Feature branches | None (PR required) |
|
||||
| Push to `release/*` | Release prep branches | Selected validation |
|
||||
|
||||
### Tag Patterns
|
||||
|
||||
| Pattern | Example | Workflow |
|
||||
|---------|---------|----------|
|
||||
| `v*` | `v2025.12.1` | `release.yml` |
|
||||
| `suite-*` | `suite-2026.04` | `release-suite.yml` |
|
||||
| `module-*-v*` | `module-authority-v1.2.3` | `module-publish.yml` |
|
||||
|
||||
### Schedule Summary
|
||||
|
||||
| Time (UTC) | Frequency | Workflow |
|
||||
|------------|-----------|----------|
|
||||
| 2:00 AM | Daily | `nightly-regression.yml` |
|
||||
| 2:00 AM | Sunday | `dependency-security-scan.yml` |
|
||||
| 3:00 AM | Daily | `renovate.yml` |
|
||||
| 3:30 AM | Monday | `sast-scan.yml` |
|
||||
| 4:30 AM | Daily | `migration-test.yml` |
|
||||
| 5:00 AM | Daily | `build-test-deploy.yml`, `test-matrix.yml` |
|
||||
| 3:00 PM | Daily | `renovate.yml` |
|
||||
|
||||
---
|
||||
|
||||
## Environment Flow
|
||||
|
||||
```
|
||||
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
|
||||
│ PR │───▶│ Staging │───▶│ Stable │───▶│ LTS │
|
||||
│ (Preview)│ │ (Edge) │ │ (Tested) │ │(Long-Term)│
|
||||
└──────────┘ └──────────┘ └──────────┘ └──────────┘
|
||||
│ │ │ │
|
||||
│ │ │ │
|
||||
▼ ▼ ▼ ▼
|
||||
PR tests Auto-deploy promote.yml promote.yml
|
||||
(gating) on main merge (manual) (manual)
|
||||
```
|
||||
|
||||
### Environment Matrix
|
||||
|
||||
| Environment | Branch/Tag | Auto-Deploy | Rollback |
|
||||
|-------------|------------|-------------|----------|
|
||||
| Preview | PR | Yes (ephemeral) | N/A |
|
||||
| Staging (Edge) | `main` | Yes | `rollback.yml` |
|
||||
| Stable | `v*` tags | Manual | `rollback.yml` |
|
||||
| LTS | `suite-*` tags | Manual | `rollback.yml` |
|
||||
|
||||
---
|
||||
|
||||
## Key Features
|
||||
|
||||
### 1. PR-Gating Tests
|
||||
|
||||
Required tests that must pass before merge:
|
||||
|
||||
- **Unit Tests** - Fast, isolated tests
|
||||
- **Architecture Tests** - Dependency rule enforcement
|
||||
- **Contract Tests** - API compatibility
|
||||
- **Integration Tests** - PostgreSQL integration
|
||||
- **Security Tests** - Security-focused assertions
|
||||
- **Golden Tests** - Corpus-based validation
|
||||
|
||||
### 2. Determinism Verification
|
||||
|
||||
All builds produce identical outputs:
|
||||
|
||||
- Binary checksums compared across runs
|
||||
- UTC timezone enforcement (`TZ: UTC`)
|
||||
- Stable JSON serialization
|
||||
- Reproducible SBOM generation
|
||||
|
||||
### 3. Supply Chain Security
|
||||
|
||||
- **SBOM Generation** - Syft for CycloneDX/SPDX
|
||||
- **Artifact Signing** - Cosign/Sigstore integration
|
||||
- **Provenance** - in-toto/DSSE attestations
|
||||
- **Dependency Scanning** - Automated vulnerability detection
|
||||
|
||||
### 4. Rollback Automation
|
||||
|
||||
Emergency rollback via `rollback.yml`:
|
||||
- Target: < 5 minute SLA
|
||||
- Helm-based deployment rollback
|
||||
- Health check verification
|
||||
- Notification integration
|
||||
|
||||
---
|
||||
|
||||
## Directory Structure
|
||||
|
||||
```
|
||||
.gitea/
|
||||
├── workflows/ # 100 workflow files
|
||||
│ ├── build-test-deploy.yml
|
||||
│ ├── test-matrix.yml
|
||||
│ ├── release-suite.yml
|
||||
│ └── ...
|
||||
├── scripts/ # CI/CD scripts
|
||||
│ ├── build/ # Build orchestration
|
||||
│ ├── test/ # Test execution
|
||||
│ ├── release/ # Release automation
|
||||
│ ├── sign/ # Signing operations
|
||||
│ └── validate/ # Validation scripts
|
||||
└── docs/ # CI-specific docs
|
||||
├── architecture.md
|
||||
├── scripts.md
|
||||
└── troubleshooting.md
|
||||
|
||||
devops/
|
||||
├── scripts/
|
||||
│ └── lib/ # Shared bash libraries
|
||||
│ ├── logging.sh
|
||||
│ ├── exit-codes.sh
|
||||
│ ├── git-utils.sh
|
||||
│ ├── path-utils.sh
|
||||
│ └── hash-utils.sh
|
||||
├── compose/ # Docker Compose profiles
|
||||
├── helm/ # Helm charts
|
||||
└── docker/ # Dockerfiles
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Getting Started
|
||||
|
||||
### Running Workflows Locally
|
||||
|
||||
```bash
|
||||
# Run test matrix locally
|
||||
./devops/scripts/test-local.sh
|
||||
|
||||
# Validate compose files
|
||||
./devops/scripts/validate-compose.sh
|
||||
|
||||
# Run a specific test category
|
||||
./.gitea/scripts/test/run-test-category.sh Unit
|
||||
```
|
||||
|
||||
### Triggering Manual Workflows
|
||||
|
||||
```bash
|
||||
# Via Gitea UI: Actions → Workflow → Run workflow
|
||||
|
||||
# Or via API:
|
||||
curl -X POST \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
"$GITEA_URL/api/v1/repos/owner/repo/actions/workflows/rollback.yml/dispatches" \
|
||||
-d '{"ref":"main","inputs":{"environment":"staging","version":"v2025.12.0"}}'
|
||||
```
|
||||
|
||||
### Creating a Release
|
||||
|
||||
1. **Module Release:**
|
||||
```bash
|
||||
git tag module-authority-v1.2.3
|
||||
git push origin module-authority-v1.2.3
|
||||
```
|
||||
|
||||
2. **Suite Release:**
|
||||
```bash
|
||||
git tag suite-2026.04
|
||||
git push origin suite-2026.04
|
||||
```
|
||||
|
||||
3. **Bundle Release:**
|
||||
```bash
|
||||
git tag v2025.12.1
|
||||
git push origin v2025.12.1
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Workflow Triggers Deep Dive](./workflow-triggers.md)
|
||||
- [Release Pipeline Details](./release-pipelines.md)
|
||||
- [Security Scanning Guide](./security-scanning.md)
|
||||
- [Test Strategy](./test-strategy.md)
|
||||
- [CI Quality Gates](../testing/ci-quality-gates.md)
|
||||
- [Troubleshooting](../.gitea/docs/troubleshooting.md)
|
||||
- [Script Reference](../.gitea/docs/scripts.md)
|
||||
|
||||
---
|
||||
|
||||
## Metrics & Monitoring
|
||||
|
||||
### Key Metrics Tracked
|
||||
|
||||
| Metric | Target | Measurement |
|
||||
|--------|--------|-------------|
|
||||
| PR Build Time | < 15 min | Workflow duration |
|
||||
| Main Build Time | < 20 min | Workflow duration |
|
||||
| Test Flakiness | < 1% | Flaky test detection |
|
||||
| Security Scan Coverage | 100% | SAST/DAST coverage |
|
||||
| Rollback SLA | < 5 min | Rollback workflow duration |
|
||||
|
||||
### Dashboard Links
|
||||
|
||||
- [Workflow Runs](../../.gitea/workflows/) (Gitea Actions UI)
|
||||
- [Test Results](./test-results/) (TRX/JUnit artifacts)
|
||||
- [Coverage Reports](./coverage/) (Generated nightly)
|
||||
34
docs/technical/cicd/ci-AGENTS.md
Normal file
34
docs/technical/cicd/ci-AGENTS.md
Normal file
@@ -0,0 +1,34 @@
|
||||
# CI Recipes agent guide
|
||||
|
||||
## Mission
|
||||
CI module collects reproducible pipeline recipes for builds, tests, and release promotion across supported platforms.
|
||||
|
||||
## Key docs
|
||||
- [Module README](./README.md)
|
||||
- [Architecture](./architecture.md)
|
||||
- [Implementation plan](./implementation_plan.md)
|
||||
- [Task board](./TASKS.md)
|
||||
|
||||
## How to get started
|
||||
1. Open sprint file `/docs/implplan/SPRINT_*.md` and locate the stories referencing this module.
|
||||
2. Review ./TASKS.md for local follow-ups and confirm status transitions (TODO → DOING → DONE/BLOCKED).
|
||||
3. Read the architecture and README for domain context before editing code or docs.
|
||||
4. Coordinate cross-module changes in the main /AGENTS.md description and through the sprint plan.
|
||||
|
||||
## Guardrails
|
||||
- Honour the Aggregation-Only Contract where applicable (see ../../aoc/aggregation-only-contract.md).
|
||||
- Preserve determinism: sort outputs, normalise timestamps (UTC ISO-8601), and avoid machine-specific artefacts.
|
||||
- Keep Offline Kit parity in mind—document air-gapped workflows for any new feature.
|
||||
- Update runbooks/observability assets when operational characteristics change.
|
||||
## Required Reading
|
||||
- `docs/modules/ci/README.md`
|
||||
- `docs/modules/ci/architecture.md`
|
||||
- `docs/modules/ci/implementation_plan.md`
|
||||
- `docs/modules/platform/architecture-overview.md`
|
||||
|
||||
## Working Agreement
|
||||
- 1. Update task status to `DOING`/`DONE` in both correspoding sprint file `/docs/implplan/SPRINT_*.md` and the local `TASKS.md` when you start or finish work.
|
||||
- 2. Review this charter and the Required Reading documents before coding; confirm prerequisites are met.
|
||||
- 3. Keep changes deterministic (stable ordering, timestamps, hashes) and align with offline/air-gap expectations.
|
||||
- 4. Coordinate doc updates, tests, and cross-guild communication whenever contracts or workflows change.
|
||||
- 5. Revert to `TODO` if you pause the task without shipping changes; leave notes in commit/PR descriptions for context.
|
||||
30
docs/technical/cicd/ci-architecture.md
Normal file
30
docs/technical/cicd/ci-architecture.md
Normal file
@@ -0,0 +1,30 @@
|
||||
# CI Recipes architecture
|
||||
|
||||
## Scope & responsibilities
|
||||
- Curate deterministic CI pipeline templates for ingestion, scanning, policy evaluation, export, and notifications.
|
||||
- Capture provenance for each recipe (inputs, pinned tool versions, checksum manifests) and keep offline/air-gap parity.
|
||||
- Provide reusable fragments (YAML/JSON) plus guardrails (AOC checks, DSSE attestation hooks, Rekor/Transparency toggles).
|
||||
|
||||
## Components
|
||||
- **Recipe catalogue (`recipes.md`)** — Source of truth for pipeline snippets; sorted deterministically and annotated with required secrets/scopes.
|
||||
- **Guardrail hooks** — Inline steps for schema validation, SBOM/VEX signing, and attestation verification; reuse Authority/Signer/Export Center helpers.
|
||||
- **Observability shim** — Optional steps to emit structured logs/metrics to Telemetry Core when allowed; defaults to no-op in sealed/offline mode.
|
||||
- **Offline bundle path** — Scripts/guides to package recipes and pinned tool archives for air-gapped runners; hashes recorded in release notes.
|
||||
|
||||
## Data & determinism
|
||||
- All generated artifacts (templates, manifests, example outputs) must sort keys and lists, emit UTC ISO-8601 timestamps, and avoid host-specific paths.
|
||||
- DSSE/attestation helpers should target the platform trust roots defined in Authority/Sigstore docs; prefer BLAKE3 hashing where compatible.
|
||||
- Keep retry/backoff logic deterministic for reproducible CI runs; avoid time-based jitter unless explicitly documented.
|
||||
|
||||
## Integration points
|
||||
- Authority/Signer for DSSE + Rekor publication; Export Center for bundle assembly; Notify for preview hooks; Telemetry Core for optional metrics.
|
||||
- Recipes must remain compatible with CLI/SDK surface referenced in `docs/modules/cli/guides/` and devportal snippets.
|
||||
|
||||
## Testing lanes and catalog
|
||||
- CI lane filters are defined by `docs/technical/testing/TEST_CATALOG.yml` and aligned with `docs/technical/testing/testing-strategy-models.md`.
|
||||
- Standard categories: Unit, Contract, Integration, Security, Performance, Live (opt-in only).
|
||||
- Any new test gate or lane must update `docs/technical/testing/TEST_SUITE_OVERVIEW.md` and `docs/technical/testing/ci-quality-gates.md`.
|
||||
|
||||
## Change process
|
||||
- Track active work in `docs/implplan/SPRINT_0315_0001_0001_docs_modules_ci.md` and mirror statuses in `./TASKS.md`.
|
||||
- When adding new recipes, include offline notes, determinism checks, and minimal test harness references in `docs/benchmarks` or `tests/**` as applicable.
|
||||
353
docs/technical/cicd/ci-recipes.md
Executable file
353
docs/technical/cicd/ci-recipes.md
Executable file
@@ -0,0 +1,353 @@
|
||||
# Stella Ops CI Recipes — (2025‑08‑04)
|
||||
|
||||
## 0 · Key variables (export these once)
|
||||
|
||||
| Variable | Meaning | Typical value |
|
||||
| ------------- | --------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------- |
|
||||
| `STELLA_URL` | Host that: ① stores the **CLI** & **SBOM‑builder** images under `/registry` **and** ② receives API calls at `https://$STELLA_URL` | `stella-ops.ci.acme.example` |
|
||||
| `DOCKER_HOST` | How containers reach your Docker daemon (because we no longer mount `/var/run/docker.sock`) | `tcp://docker:2375` |
|
||||
| `WORKSPACE` | Directory where the pipeline stores artefacts (SBOM file) | `$(pwd)` |
|
||||
| `IMAGE` | The image you are building & scanning | `acme/backend:sha-${COMMIT_SHA}` |
|
||||
| `SBOM_FILE` | Immutable SBOM name – `<image-ref>‑YYYYMMDDThhmmssZ.sbom.json` | `acme_backend_sha‑abc123‑20250804T153050Z.sbom.json` |
|
||||
|
||||
> **Authority graph scopes note (2025-10-27):** CI stages that spin up the Authority compose profile now rely on the checked-in `etc/authority.yaml`. Before running integration smoke jobs, inject real secrets for every `etc/secrets/*.secret` file (Cartographer, Graph API, Policy Engine, Concelier, Excititor). The repository defaults contain `*-change-me` placeholders and Authority will reject tokens if those secrets are not overridden. Reissue CI tokens that previously used `policy:write`/`policy:submit`/`policy:edit` scopes—new bundles must request `policy:read`, `policy:author`, `policy:review`, `policy:simulate`, and (`policy:approve`/`policy:operate`/`policy:activate` when pipelines promote policies).
|
||||
|
||||
```bash
|
||||
export STELLA_URL="stella-ops.ci.acme.example"
|
||||
export DOCKER_HOST="tcp://docker:2375" # Jenkins/Circle often expose it like this
|
||||
export WORKSPACE="$(pwd)"
|
||||
export IMAGE="acme/backend:sha-${COMMIT_SHA}"
|
||||
export SBOM_FILE="$(echo "${IMAGE}" | tr '/:+' '__')-$(date -u +%Y%m%dT%H%M%SZ).sbom.json"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 1 · SBOM creation strategies
|
||||
|
||||
### Option A – **Buildx attested SBOM** (preferred if you can use BuildKit)
|
||||
|
||||
You pass **two build args** so the Dockerfile can run the builder and copy the result out of the build context.
|
||||
|
||||
```bash
|
||||
docker buildx build \
|
||||
--build-arg STELLA_SBOM_BUILDER="$STELLA_URL/registry/stella-sbom-builder:latest" \
|
||||
--provenance=true --sbom=true \
|
||||
--build-arg SBOM_FILE="$SBOM_FILE" \
|
||||
-t "$IMAGE" .
|
||||
```
|
||||
|
||||
**If you **cannot** use Buildx, use Option B below.** The older “run a builder stage inside the Dockerfile” pattern is unreliable for producing an SBOM of the final image.
|
||||
|
||||
```Dockerfile
|
||||
|
||||
ARG STELLA_SBOM_BUILDER
|
||||
ARG SBOM_FILE
|
||||
|
||||
FROM $STELLA_SBOM_BUILDER as sbom
|
||||
ARG IMAGE
|
||||
ARG SBOM_FILE
|
||||
RUN $STELLA_SBOM_BUILDER build --image $IMAGE --output /out/$SBOM_FILE
|
||||
|
||||
# ---- actual build stages … ----
|
||||
FROM alpine:3.20
|
||||
COPY --from=sbom /out/$SBOM_FILE / # (optional) keep or discard
|
||||
|
||||
# (rest of your Dockerfile)
|
||||
```
|
||||
|
||||
### Option B – **External builder step** (works everywhere; recommended baseline if Buildx isn’t available)
|
||||
|
||||
*(keep this block if your pipeline already has an image‑build step that you can’t modify)*
|
||||
|
||||
```bash
|
||||
docker run --rm \
|
||||
-e DOCKER_HOST="$DOCKER_HOST" \ # let builder reach the daemon remotely
|
||||
-v "$WORKSPACE:/workspace" \ # place SBOM beside the source code
|
||||
"$STELLA_URL/registry/stella-sbom-builder:latest" \
|
||||
build --image "$IMAGE" --output "/workspace/${SBOM_FILE}"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2 · Scan the image & upload results
|
||||
|
||||
```bash
|
||||
docker run --rm \
|
||||
-e DOCKER_HOST="$DOCKER_HOST" \ # remote‑daemon pointer
|
||||
-v "$WORKSPACE/${SBOM_FILE}:/${SBOM_FILE}:ro" \ # mount SBOM under same name at container root
|
||||
-e STELLA_OPS_URL="https://${STELLA_URL}" \ # where the CLI posts findings
|
||||
"$STELLA_URL/registry/stella-cli:latest" \
|
||||
scan --sbom "/${SBOM_FILE}" "$IMAGE"
|
||||
```
|
||||
|
||||
The CLI returns **exit 0** if policies pass, **>0** if blocked — perfect for failing the job.
|
||||
|
||||
---
|
||||
|
||||
## 3 · CI templates
|
||||
|
||||
Below are minimal, cut‑and‑paste snippets.
|
||||
**Feel free to delete Option B** if you adopt Option A.
|
||||
|
||||
### 3.1 Jenkins (Declarative Pipeline)
|
||||
|
||||
```groovy
|
||||
pipeline {
|
||||
agent { docker { image 'docker:25' args '--privileged' } } // gives us /usr/bin/docker
|
||||
environment {
|
||||
STELLA_URL = 'stella-ops.ci.acme.example'
|
||||
DOCKER_HOST = 'tcp://docker:2375'
|
||||
IMAGE = "acme/backend:${env.BUILD_NUMBER}"
|
||||
SBOM_FILE = "acme_backend_${env.BUILD_NUMBER}-${new Date().format('yyyyMMdd\'T\'HHmmss\'Z\'', TimeZone.getTimeZone('UTC'))}.sbom.json"
|
||||
}
|
||||
stages {
|
||||
stage('Build image + SBOM (Option A)') {
|
||||
steps {
|
||||
sh '''
|
||||
docker build \
|
||||
--build-arg STELLA_SBOM_BUILDER="$STELLA_URL/registry/stella-sbom-builder:latest" \
|
||||
--build-arg SBOM_FILE="$SBOM_FILE" \
|
||||
-t "$IMAGE" .
|
||||
'''
|
||||
}
|
||||
}
|
||||
/* ---------- Option B fallback (when you must keep the existing build step as‑is) ----------
|
||||
stage('SBOM builder (Option B)') {
|
||||
steps {
|
||||
sh '''
|
||||
docker run --rm -e DOCKER_HOST="$DOCKER_HOST" \
|
||||
-v "$WORKSPACE:/workspace" \
|
||||
"$STELLA_URL/registry/stella-sbom-builder:latest" \
|
||||
build --image "$IMAGE" --output "/workspace/${SBOM_FILE}"
|
||||
'''
|
||||
}
|
||||
}
|
||||
------------------------------------------------------------------------------------------ */
|
||||
stage('Scan & upload') {
|
||||
steps {
|
||||
sh '''
|
||||
docker run --rm -e DOCKER_HOST="$DOCKER_HOST" \
|
||||
-v "$WORKSPACE/${SBOM_FILE}:/${SBOM_FILE}:ro" \
|
||||
-e STELLA_OPS_URL="https://$STELLA_URL" \
|
||||
"$STELLA_URL/registry/stella-cli:latest" \
|
||||
scan --sbom "/${SBOM_FILE}" "$IMAGE"
|
||||
'''
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3.2 CircleCI `.circleci/config.yml`
|
||||
|
||||
```yaml
|
||||
version: 2.1
|
||||
jobs:
|
||||
stella_scan:
|
||||
docker:
|
||||
- image: cimg/base:stable # baremetal image with Docker CLI
|
||||
environment:
|
||||
STELLA_URL: stella-ops.ci.acme.example
|
||||
DOCKER_HOST: tcp://docker:2375 # Circle’s “remote Docker” socket
|
||||
steps:
|
||||
- checkout
|
||||
|
||||
- run:
|
||||
name: Compute vars
|
||||
command: |
|
||||
echo 'export IMAGE="acme/backend:${CIRCLE_SHA1}"' >> $BASH_ENV
|
||||
echo 'export SBOM_FILE="$(echo acme/backend:${CIRCLE_SHA1} | tr "/:+" "__")-$(date -u +%Y%m%dT%H%M%SZ).sbom.json"' >> $BASH_ENV
|
||||
- run:
|
||||
name: Build image + SBOM (Option A)
|
||||
command: |
|
||||
docker build \
|
||||
--build-arg STELLA_SBOM_BUILDER="$STELLA_URL/registry/stella-sbom-builder:latest" \
|
||||
--build-arg SBOM_FILE="$SBOM_FILE" \
|
||||
-t "$IMAGE" .
|
||||
# --- Option B fallback (when you must keep the existing build step as‑is) ---
|
||||
#- run:
|
||||
# name: SBOM builder (Option B)
|
||||
# command: |
|
||||
# docker run --rm -e DOCKER_HOST="$DOCKER_HOST" \
|
||||
# -v "$PWD:/workspace" \
|
||||
# "$STELLA_URL/registry/stella-sbom-builder:latest" \
|
||||
# build --image "$IMAGE" --output "/workspace/${SBOM_FILE}"
|
||||
- run:
|
||||
name: Scan
|
||||
command: |
|
||||
docker run --rm -e DOCKER_HOST="$DOCKER_HOST" \
|
||||
-v "$PWD/${SBOM_FILE}:/${SBOM_FILE}:ro" \
|
||||
-e STELLA_OPS_URL="https://$STELLA_URL" \
|
||||
"$STELLA_URL/registry/stella-cli:latest" \
|
||||
scan --sbom "/${SBOM_FILE}" "$IMAGE"
|
||||
workflows:
|
||||
stella:
|
||||
jobs: [stella_scan]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3.3 Gitea Actions `.gitea/workflows/stella.yml`
|
||||
|
||||
*(Gitea 1.22+ ships native Actions compatible with GitHub syntax)*
|
||||
|
||||
```yaml
|
||||
name: Stella Scan
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
stella:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
STELLA_URL: ${{ secrets.STELLA_URL }}
|
||||
DOCKER_HOST: tcp://docker:2375 # provided by the docker:dind service
|
||||
services:
|
||||
docker:
|
||||
image: docker:dind
|
||||
options: >-
|
||||
--privileged
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Compute vars
|
||||
id: vars
|
||||
run: |
|
||||
echo "IMAGE=ghcr.io/${{ gitea.repository }}:${{ gitea.sha }}" >> $GITEA_OUTPUT
|
||||
echo "SBOM_FILE=$(echo ghcr.io/${{ gitea.repository }}:${{ gitea.sha }} | tr '/:+' '__')-$(date -u +%Y%m%dT%H%M%SZ).sbom.json" >> $GITEA_OUTPUT
|
||||
|
||||
- name: Build image + SBOM (Option A)
|
||||
run: |
|
||||
docker build \
|
||||
--build-arg STELLA_SBOM_BUILDER="${STELLA_URL}/registry/stella-sbom-builder:latest" \
|
||||
--build-arg SBOM_FILE="${{ steps.vars.outputs.SBOM_FILE }}" \
|
||||
-t "${{ steps.vars.outputs.IMAGE }}" .
|
||||
|
||||
# --- Option B fallback (when you must keep the existing build step as‑is) ---
|
||||
#- name: SBOM builder (Option B)
|
||||
# run: |
|
||||
# docker run --rm -e DOCKER_HOST="$DOCKER_HOST" \
|
||||
# -v "$(pwd):/workspace" \
|
||||
# "${STELLA_URL}/registry/stella-sbom-builder:latest" \
|
||||
# build --image "${{ steps.vars.outputs.IMAGE }}" --output "/workspace/${{ steps.vars.outputs.SBOM_FILE }}"
|
||||
|
||||
- name: Scan
|
||||
run: |
|
||||
docker run --rm -e DOCKER_HOST="$DOCKER_HOST" \
|
||||
-v "$(pwd)/${{ steps.vars.outputs.SBOM_FILE }}:/${{ steps.vars.outputs.SBOM_FILE }}:ro" \
|
||||
-e STELLA_OPS_URL="https://${STELLA_URL}" \
|
||||
"${STELLA_URL}/registry/stella-cli:latest" \
|
||||
scan --sbom "/${{ steps.vars.outputs.SBOM_FILE }}" "${{ steps.vars.outputs.IMAGE }}"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4 · Docs CI (Gitea Actions & Offline Mirror)
|
||||
|
||||
StellaOps ships a dedicated Docs workflow at `.gitea/workflows/docs.yml`. When mirroring the pipeline offline or running it locally, install the same toolchain so markdown linting, schema validation, and HTML preview stay deterministic.
|
||||
|
||||
### 4.1 Toolchain bootstrap
|
||||
|
||||
```bash
|
||||
# Node.js 20.x is required; install once per runner
|
||||
npm install --no-save \
|
||||
markdown-link-check \
|
||||
remark-cli \
|
||||
remark-preset-lint-recommended \
|
||||
ajv \
|
||||
ajv-cli \
|
||||
ajv-formats
|
||||
|
||||
# Python 3.11+ powers the preview renderer
|
||||
python -m pip install --upgrade pip
|
||||
python -m pip install markdown pygments
|
||||
```
|
||||
|
||||
> **No `pip` available?** Some hardened Python builds (including the repo’s `tmp/docenv`
|
||||
> interpreter) ship without `pip`/`ensurepip`. In that case download the pure‑Python
|
||||
> sdists (e.g. `Markdown-3.x.tar.gz`, `pygments-2.x.tar.gz`) and extract their
|
||||
> packages directly into the virtualenv’s `lib/python*/site-packages/` folder.
|
||||
> This keeps the renderer working even when package managers are disabled.
|
||||
|
||||
**Offline tip.** Add the packages above to your artifact mirror (for example `ops/devops/offline-kit.json`) so runners can install them via `npm --offline` / `pip --no-index`.
|
||||
|
||||
### 4.2 Schema validation step
|
||||
|
||||
Ajv compiles every event schema to guard against syntax or format regressions. The workflow uses `ajv-formats` for UUID/date-time support.
|
||||
|
||||
```bash
|
||||
for schema in docs/modules/signals/events/*.json; do
|
||||
npx ajv compile -c ajv-formats -s "$schema"
|
||||
done
|
||||
```
|
||||
|
||||
Run this loop before committing schema changes. For new references, append `-r additional-file.json` so CI and local runs stay aligned.
|
||||
|
||||
### 4.3 Preview build
|
||||
|
||||
```bash
|
||||
python scripts/render_docs.py --source docs --output artifacts/docs-preview --clean
|
||||
```
|
||||
|
||||
Host the resulting bundle via any static file server for review (for example `python -m http.server`).
|
||||
|
||||
### 4.4 Publishing checklist
|
||||
|
||||
- [ ] Toolchain installs succeed without hitting the public internet (mirror or cached tarballs).
|
||||
- [ ] Ajv validation passes for `scanner.report.ready@1`, `scheduler.rescan.delta@1`, `attestor.logged@1`.
|
||||
- [ ] Markdown link check (`npx markdown-link-check`) reports no broken references.
|
||||
- [ ] Preview bundle archived (or attached) for stakeholders.
|
||||
|
||||
### 4.5 Policy DSL lint stage
|
||||
|
||||
Policy Engine v2 pipelines now fail fast if policy documents are malformed. After checkout and dotnet restore, run:
|
||||
|
||||
```bash
|
||||
dotnet run \
|
||||
--project src/Tools/PolicyDslValidator/PolicyDslValidator.csproj \
|
||||
-- \
|
||||
--strict docs/modules/policy/samples/*.yaml
|
||||
```
|
||||
|
||||
- `--strict` treats warnings as errors so missing metadata doesn’t slip through.
|
||||
- The validator accepts globs, so you can point it at tenant policy directories later (`policies/**/*.yaml`).
|
||||
- Exit codes follow UNIX conventions: `0` success, `1` parse/errors, `2` warnings when `--strict` is set, `64` usage mistakes.
|
||||
|
||||
Capture the validator output as part of your build logs; Support uses it when triaging policy rollout issues.
|
||||
|
||||
### 4.6 Policy simulation smoke
|
||||
|
||||
Catch unexpected policy regressions by exercising a small set of golden SBOM findings via the simulation smoke tool:
|
||||
|
||||
```bash
|
||||
dotnet run \
|
||||
--project src/Tools/PolicySimulationSmoke/PolicySimulationSmoke.csproj \
|
||||
-- \
|
||||
--scenario-root samples/policy/simulations \
|
||||
--output artifacts/policy-simulations
|
||||
```
|
||||
|
||||
- The tool loads each `scenario.json` under `samples/policy/simulations`, evaluates the referenced policy, and fails the build if projected verdicts change.
|
||||
- In CI the command runs twice (to `run1/` and `run2/`) and `diff -u` compares the summaries—any mismatch signals a determinism regression.
|
||||
- Artifacts land in `artifacts/policy-simulations/policy-simulation-summary.json`; upload them for later inspection (see CI workflow).
|
||||
- Expand scenarios by copying real-world findings into the samples directory—ensure expected statuses are recorded so regressions trip the pipeline.
|
||||
|
||||
---
|
||||
|
||||
## 5 · Troubleshooting cheat‑sheet
|
||||
|
||||
| Symptom | Root cause | First things to try |
|
||||
| ------------------------------------- | --------------------------- | --------------------------------------------------------------- |
|
||||
| `no such host $STELLA_URL` | DNS typo or VPN outage | `ping $STELLA_URL` from runner |
|
||||
| `connection refused` when CLI uploads | Port 443 blocked | open firewall / check ingress |
|
||||
| `failed to stat /<sbom>.json` | SBOM wasn’t produced | Did Option A actually run builder? If not, enable Option B |
|
||||
| `registry unauthorized` | Runner lacks registry creds | `docker login $STELLA_URL/registry` (store creds in CI secrets) |
|
||||
| Non‑zero scan exit | Blocking vuln/licence | Open project in Ops UI → triage or waive |
|
||||
|
||||
---
|
||||
|
||||
### Change log
|
||||
|
||||
* **2025‑10‑18** – Documented Docs CI toolchain (Ajv validation, static preview) and offline checklist.
|
||||
* **2025‑08‑04** – Variable clean‑up, removed Docker‑socket & cache mounts, added Jenkins / CircleCI / Gitea examples, clarified Option B comment.
|
||||
283
docs/technical/cicd/dsse-build-flow.md
Normal file
283
docs/technical/cicd/dsse-build-flow.md
Normal file
@@ -0,0 +1,283 @@
|
||||
# Build-Time DSSE Attestation Walkthrough
|
||||
|
||||
> **Status:** Complete — implements the November 2025 advisory "Embed in-toto attestations (DSSE-wrapped) into .NET 10/C# builds." Updated 2025-11-27 with CLI verification commands (`DSSE-CLI-401-021`).
|
||||
> **Owners:** Attestor Guild · DevOps Guild · Docs Guild.
|
||||
|
||||
This guide shows how to emit signed, in-toto compliant DSSE envelopes for every container build step (scan → package → push) using Stella Ops Authority keys. The same primitives power our Signer/Attestor services, but this walkthrough targets developer pipelines (GitHub/GitLab, dotnet builds, container scanners).
|
||||
|
||||
---
|
||||
|
||||
## 1. Concepts refresher
|
||||
|
||||
| Term | Meaning |
|
||||
|------|---------|
|
||||
| **In-toto Statement** | JSON document describing what happened (predicate) to which artifact (subject). |
|
||||
| **DSSE** | Dead Simple Signing Envelope: wraps the statement, base64 payload, and signatures. |
|
||||
| **Authority Signer** | Stella Ops client that signs data via file-based keys, HSM/KMS, or keyless Fulcio certs. |
|
||||
| **PAE** | Pre-Authentication Encoding: canonical “DSSEv1 <len> <payloadType> <len> <payload>” byte layout that is signed. |
|
||||
|
||||
Requirements:
|
||||
|
||||
1. .NET 10 SDK (preview) for C# helper code.
|
||||
2. Authority key material (dev: file-based Ed25519; prod: Authority/KMS signer).
|
||||
3. Artifact digest (e.g., `pkg:docker/registry/app@sha256:...`) per step.
|
||||
|
||||
---
|
||||
|
||||
## 2. Helpers (drop-in library)
|
||||
|
||||
Create `src/StellaOps.Attestation` with:
|
||||
|
||||
```csharp
|
||||
public sealed record InTotoStatement(
|
||||
string _type,
|
||||
IReadOnlyList<Subject> subject,
|
||||
string predicateType,
|
||||
object predicate);
|
||||
|
||||
public sealed record Subject(string name, IReadOnlyDictionary<string,string> digest);
|
||||
|
||||
public sealed record DsseEnvelope(
|
||||
string payloadType,
|
||||
string payload,
|
||||
IReadOnlyList<Signature> signatures);
|
||||
|
||||
public sealed record Signature(string keyid, string sig);
|
||||
|
||||
public interface IAuthoritySigner
|
||||
{
|
||||
Task<string> GetKeyIdAsync(CancellationToken ct = default);
|
||||
Task<byte[]> SignAsync(ReadOnlyMemory<byte> pae, CancellationToken ct = default);
|
||||
}
|
||||
```
|
||||
|
||||
DSSE helper:
|
||||
|
||||
```csharp
|
||||
public static class DsseHelper
|
||||
{
|
||||
public static async Task<DsseEnvelope> WrapAsync(
|
||||
InTotoStatement statement,
|
||||
IAuthoritySigner signer,
|
||||
string payloadType = "application/vnd.in-toto+json",
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
var payloadBytes = JsonSerializer.SerializeToUtf8Bytes(statement,
|
||||
new JsonSerializerOptions { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull });
|
||||
var pae = PreAuthEncode(payloadType, payloadBytes);
|
||||
|
||||
var signature = await signer.SignAsync(pae, ct).ConfigureAwait(false);
|
||||
var keyId = await signer.GetKeyIdAsync(ct).ConfigureAwait(false);
|
||||
|
||||
return new DsseEnvelope(
|
||||
payloadType,
|
||||
Convert.ToBase64String(payloadBytes),
|
||||
new[] { new Signature(keyId, Convert.ToBase64String(signature)) });
|
||||
}
|
||||
|
||||
private static byte[] PreAuthEncode(string payloadType, byte[] payload)
|
||||
{
|
||||
static byte[] Cat(params byte[][] parts)
|
||||
{
|
||||
var len = parts.Sum(p => p.Length);
|
||||
var buf = new byte[len];
|
||||
var offset = 0;
|
||||
foreach (var part in parts)
|
||||
{
|
||||
Buffer.BlockCopy(part, 0, buf, offset, part.Length);
|
||||
offset += part.Length;
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
var header = Encoding.UTF8.GetBytes("DSSEv1");
|
||||
var pt = Encoding.UTF8.GetBytes(payloadType);
|
||||
var lenPt = Encoding.UTF8.GetBytes(pt.Length.ToString(CultureInfo.InvariantCulture));
|
||||
var lenPayload = Encoding.UTF8.GetBytes(payload.Length.ToString(CultureInfo.InvariantCulture));
|
||||
var space = Encoding.UTF8.GetBytes(" ");
|
||||
|
||||
return Cat(header, space, lenPt, space, pt, space, lenPayload, space, payload);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Authority signer examples:
|
||||
|
||||
/dev (file Ed25519):
|
||||
```csharp
|
||||
public sealed class FileEd25519Signer : IAuthoritySigner, IDisposable
|
||||
{
|
||||
private readonly Ed25519 _ed;
|
||||
private readonly string _keyId;
|
||||
|
||||
public FileEd25519Signer(byte[] privateKeySeed, string keyId)
|
||||
{
|
||||
_ed = new Ed25519(privateKeySeed);
|
||||
_keyId = keyId;
|
||||
}
|
||||
|
||||
public Task<string> GetKeyIdAsync(CancellationToken ct) => Task.FromResult(_keyId);
|
||||
|
||||
public Task<byte[]> SignAsync(ReadOnlyMemory<byte> pae, CancellationToken ct)
|
||||
=> Task.FromResult(_ed.Sign(pae.Span.ToArray()));
|
||||
|
||||
public void Dispose() => _ed.Dispose();
|
||||
}
|
||||
```
|
||||
|
||||
Prod (Authority KMS):
|
||||
|
||||
Reuse the existing `StellaOps.Signer.KmsSigner` adapter—wrap it behind `IAuthoritySigner`.
|
||||
|
||||
---
|
||||
|
||||
## 3. Emitting attestations per step
|
||||
|
||||
Subject helper:
|
||||
```csharp
|
||||
static Subject ImageSubject(string imageDigest) => new(
|
||||
name: imageDigest,
|
||||
digest: new Dictionary<string,string>{{"sha256", imageDigest.Replace("sha256:", "", StringComparison.Ordinal)}});
|
||||
```
|
||||
|
||||
### 3.1 Scan
|
||||
|
||||
```csharp
|
||||
var scanStmt = new InTotoStatement(
|
||||
_type: "https://in-toto.io/Statement/v1",
|
||||
subject: new[]{ ImageSubject(imageDigest) },
|
||||
predicateType: "https://stella.ops/predicates/scanner-evidence/v1",
|
||||
predicate: new {
|
||||
scanner = "StellaOps.Scanner 0.9.0",
|
||||
findingsSha256 = scanResultsHash,
|
||||
startedAt = startedIso,
|
||||
finishedAt = finishedIso,
|
||||
rulePack = "lattice:default@2025-11-01"
|
||||
});
|
||||
|
||||
var scanEnvelope = await DsseHelper.WrapAsync(scanStmt, signer);
|
||||
await File.WriteAllTextAsync("artifacts/attest-scan.dsse.json", JsonSerializer.Serialize(scanEnvelope));
|
||||
```
|
||||
|
||||
### 3.2 Package (SLSA provenance)
|
||||
|
||||
```csharp
|
||||
var pkgStmt = new InTotoStatement(
|
||||
"https://in-toto.io/Statement/v1",
|
||||
new[]{ ImageSubject(imageDigest) },
|
||||
"https://slsa.dev/provenance/v1",
|
||||
new {
|
||||
builder = new { id = "stella://builder/dockerfile" },
|
||||
buildType = "dockerfile/v1",
|
||||
invocation = new { configSource = repoUrl, entryPoint = dockerfilePath },
|
||||
materials = new[] { new { uri = repoUrl, digest = new { git = gitSha } } }
|
||||
});
|
||||
|
||||
var pkgEnvelope = await DsseHelper.WrapAsync(pkgStmt, signer);
|
||||
await File.WriteAllTextAsync("artifacts/attest-package.dsse.json", JsonSerializer.Serialize(pkgEnvelope));
|
||||
```
|
||||
|
||||
### 3.3 Push
|
||||
|
||||
```csharp
|
||||
var pushStmt = new InTotoStatement(
|
||||
"https://in-toto.io/Statement/v1",
|
||||
new[]{ ImageSubject(imageDigest) },
|
||||
"https://stella.ops/predicates/push/v1",
|
||||
new { registry = registryUrl, repository = repoName, tags, pushedAt = DateTimeOffset.UtcNow });
|
||||
|
||||
var pushEnvelope = await DsseHelper.WrapAsync(pushStmt, signer);
|
||||
await File.WriteAllTextAsync("artifacts/attest-push.dsse.json", JsonSerializer.Serialize(pushEnvelope));
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. CI integration
|
||||
|
||||
### 4.1 GitLab example
|
||||
|
||||
```yaml
|
||||
.attest-template: &attest
|
||||
image: mcr.microsoft.com/dotnet/sdk:10.0-preview
|
||||
before_script:
|
||||
- dotnet build src/StellaOps.Attestation/StellaOps.Attestation.csproj
|
||||
variables:
|
||||
AUTHORITY_KEY_FILE: "$CI_PROJECT_DIR/secrets/ed25519.key"
|
||||
IMAGE_DIGEST: "$CI_REGISTRY_IMAGE@${CI_COMMIT_SHA}"
|
||||
|
||||
attest:scan:
|
||||
stage: scan
|
||||
script:
|
||||
- dotnet run --project tools/StellaOps.Attestor.Tool -- step scan --subject "$IMAGE_DIGEST" --out artifacts/attest-scan.dsse.json
|
||||
artifacts:
|
||||
paths: [artifacts/attest-scan.dsse.json]
|
||||
|
||||
attest:package:
|
||||
stage: package
|
||||
script:
|
||||
- dotnet run --project tools/StellaOps.Attestor.Tool -- step package --subject "$IMAGE_DIGEST" --out artifacts/attest-package.dsse.json
|
||||
|
||||
attest:push:
|
||||
stage: push
|
||||
script:
|
||||
- dotnet run --project tools/StellaOps.Attestor.Tool -- step push --subject "$IMAGE_DIGEST" --registry "$CI_REGISTRY" --tags "$CI_COMMIT_REF_NAME"
|
||||
```
|
||||
|
||||
### 4.2 GitHub Actions snippet
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
attest:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-dotnet@v4
|
||||
with: { dotnet-version: '10.0.x' }
|
||||
- name: Build attestor helpers
|
||||
run: dotnet build src/StellaOps.Attestation/StellaOps.Attestation.csproj
|
||||
- name: Emit scan attestation
|
||||
run: dotnet run --project tools/StellaOps.Attestor.Tool -- step scan --subject "${{ env.IMAGE_DIGEST }}" --out artifacts/attest-scan.dsse.json
|
||||
env:
|
||||
AUTHORITY_KEY_REF: ${{ secrets.AUTHORITY_KEY_REF }}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Verification
|
||||
|
||||
* `stella attest verify --envelope artifacts/attest-scan.dsse.json` — offline verification using the CLI.
|
||||
* Additional verification options:
|
||||
* `--policy policy.json` — apply custom verification policy
|
||||
* `--root keys/root.pem` — specify trusted root certificate
|
||||
* `--transparency-checkpoint checkpoint.json` — verify against Rekor checkpoint
|
||||
* Manual validation:
|
||||
1. Base64 decode payload → ensure `_type` = `https://in-toto.io/Statement/v1`, `subject[].digest.sha256` matches artifact.
|
||||
2. Recompute PAE and verify signature with the Authority public key.
|
||||
3. Attach envelope to Rekor (optional) via existing Attestor API.
|
||||
|
||||
---
|
||||
|
||||
## 6. Storage conventions
|
||||
|
||||
Store DSSE files next to build outputs:
|
||||
|
||||
```
|
||||
artifacts/
|
||||
attest-scan.dsse.json
|
||||
attest-package.dsse.json
|
||||
attest-push.dsse.json
|
||||
```
|
||||
|
||||
Include the SHA-256 digest of each envelope in promotion manifests (`docs/release/promotion-attestations.md`) so downstream verifiers can trace chain of custody.
|
||||
|
||||
---
|
||||
|
||||
## 7. References
|
||||
|
||||
- [In-toto Statement v1](https://in-toto.io/spec/v1)
|
||||
- [DSSE specification](https://github.com/secure-systems-lab/dsse)
|
||||
- `docs/modules/signer/architecture.md`
|
||||
- `docs/modules/attestor/architecture.md`
|
||||
- `docs/release/promotion-attestations.md`
|
||||
|
||||
This file was updated as part of `DSSE-LIB-401-020` and `DSSE-CLI-401-021` (completed 2025-11-27). See `docs/modules/cli/guides/attest.md` for CI/CD workflow snippets.
|
||||
414
docs/technical/cicd/path-filters.md
Normal file
414
docs/technical/cicd/path-filters.md
Normal file
@@ -0,0 +1,414 @@
|
||||
# Path Filters Reference
|
||||
|
||||
> Complete reference for path filter patterns used in CI/CD workflows.
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
Path filters determine which workflows run based on changed files. This ensures:
|
||||
- **Efficiency**: Only relevant tests run for each change
|
||||
- **Speed**: Module-specific changes don't trigger full builds
|
||||
- **Cascading**: Shared library changes trigger dependent module tests
|
||||
|
||||
---
|
||||
|
||||
## Configuration Location
|
||||
|
||||
Centralized path filter definitions are maintained in:
|
||||
|
||||
```
|
||||
.gitea/config/path-filters.yml
|
||||
```
|
||||
|
||||
This file serves as the source of truth for all path filter patterns.
|
||||
|
||||
---
|
||||
|
||||
## Path Filter Categories
|
||||
|
||||
### 1. Infrastructure Files (Trigger FULL CI)
|
||||
|
||||
Changes to these files trigger all tests and full build validation:
|
||||
|
||||
```yaml
|
||||
infrastructure:
|
||||
- 'Directory.Build.props' # Root MSBuild properties
|
||||
- 'Directory.Build.rsp' # MSBuild response file
|
||||
- 'Directory.Packages.props' # Central package versions
|
||||
- 'src/Directory.Build.props' # Source directory properties
|
||||
- 'src/Directory.Packages.props'
|
||||
- 'nuget.config' # NuGet feed configuration
|
||||
- 'StellaOps.sln' # Solution file
|
||||
- '.gitea/workflows/**' # CI/CD workflow changes
|
||||
```
|
||||
|
||||
**When to use:** All PR-gating and integration workflows should include these paths.
|
||||
|
||||
### 2. Documentation Paths (Skip CI)
|
||||
|
||||
These paths should use `paths-ignore` to skip builds:
|
||||
|
||||
```yaml
|
||||
docs_ignore:
|
||||
- 'docs/**' # All documentation
|
||||
- '*.md' # Root markdown files
|
||||
- 'etc/**' # Configuration samples
|
||||
- 'LICENSE' # License file
|
||||
- '.gitignore' # Git ignore
|
||||
- '.editorconfig' # Editor configuration
|
||||
```
|
||||
|
||||
**Exceptions:** These markdown files SHOULD trigger CI:
|
||||
- `CLAUDE.md` - Agent instructions (affects behavior)
|
||||
- `AGENTS.md` - Module-specific guidance
|
||||
|
||||
### 3. Shared Library Paths (Trigger Cascading)
|
||||
|
||||
Changes to shared libraries trigger tests in dependent modules:
|
||||
|
||||
#### Cryptography (CRITICAL - affects security)
|
||||
|
||||
```yaml
|
||||
cryptography:
|
||||
paths:
|
||||
- 'src/__Libraries/StellaOps.Cryptography*/**'
|
||||
- 'src/Cryptography/**'
|
||||
cascades_to:
|
||||
- Scanner tests
|
||||
- Attestor tests
|
||||
- Authority tests
|
||||
- EvidenceLocker tests
|
||||
- Signer tests
|
||||
- AirGap tests
|
||||
- Security test suite
|
||||
- Offline E2E tests
|
||||
```
|
||||
|
||||
#### Evidence & Provenance
|
||||
|
||||
```yaml
|
||||
evidence:
|
||||
paths:
|
||||
- 'src/__Libraries/StellaOps.Evidence*/**'
|
||||
- 'src/__Libraries/StellaOps.Provenance/**'
|
||||
cascades_to:
|
||||
- Scanner tests
|
||||
- Attestor tests
|
||||
- EvidenceLocker tests
|
||||
- ExportCenter tests
|
||||
- SbomService tests
|
||||
```
|
||||
|
||||
#### Infrastructure & Database
|
||||
|
||||
```yaml
|
||||
infrastructure:
|
||||
paths:
|
||||
- 'src/__Libraries/StellaOps.Infrastructure*/**'
|
||||
- 'src/__Libraries/StellaOps.DependencyInjection/**'
|
||||
cascades_to:
|
||||
- ALL integration tests
|
||||
```
|
||||
|
||||
#### Replay & Determinism
|
||||
|
||||
```yaml
|
||||
replay:
|
||||
paths:
|
||||
- 'src/__Libraries/StellaOps.Replay*/**'
|
||||
- 'src/__Libraries/StellaOps.Testing.Determinism/**'
|
||||
cascades_to:
|
||||
- Scanner determinism tests
|
||||
- Determinism gate
|
||||
- Replay module tests
|
||||
```
|
||||
|
||||
#### Verdict & Policy Primitives
|
||||
|
||||
```yaml
|
||||
verdict:
|
||||
paths:
|
||||
- 'src/__Libraries/StellaOps.Verdict/**'
|
||||
- 'src/__Libraries/StellaOps.DeltaVerdict/**'
|
||||
cascades_to:
|
||||
- Policy engine tests
|
||||
- RiskEngine tests
|
||||
- ReachGraph tests
|
||||
```
|
||||
|
||||
#### Plugin Framework
|
||||
|
||||
```yaml
|
||||
plugin:
|
||||
paths:
|
||||
- 'src/__Libraries/StellaOps.Plugin/**'
|
||||
cascades_to:
|
||||
- Authority tests (plugin-based auth)
|
||||
- Scanner tests (analyzer plugins)
|
||||
- Concelier tests (connector plugins)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Module-Specific Paths
|
||||
|
||||
Each module has defined source and test paths:
|
||||
|
||||
### Core Platform
|
||||
|
||||
| Module | Source Paths | Test Paths |
|
||||
|--------|--------------|------------|
|
||||
| Authority | `src/Authority/**` | `src/Authority/__Tests/**` |
|
||||
| Gateway | `src/Gateway/**` | `src/Gateway/__Tests/**` |
|
||||
| Router | `src/Router/**` | `src/Router/__Tests/**` |
|
||||
|
||||
### Scanning & Analysis
|
||||
|
||||
| Module | Source Paths | Test Paths |
|
||||
|--------|--------------|------------|
|
||||
| Scanner | `src/Scanner/**`, `src/BinaryIndex/**` | `src/Scanner/__Tests/**`, `src/BinaryIndex/__Tests/**` |
|
||||
| AdvisoryAI | `src/AdvisoryAI/**` | `src/AdvisoryAI/__Tests/**` |
|
||||
| ReachGraph | `src/ReachGraph/**` | `src/ReachGraph/__Tests/**` |
|
||||
|
||||
### Data Ingestion
|
||||
|
||||
| Module | Source Paths | Test Paths |
|
||||
|--------|--------------|------------|
|
||||
| Concelier | `src/Concelier/**` | `src/Concelier/__Tests/**` |
|
||||
| Excititor | `src/Excititor/**` | `src/Excititor/__Tests/**` |
|
||||
| VexLens | `src/VexLens/**` | `src/VexLens/__Tests/**` |
|
||||
| VexHub | `src/VexHub/**` | `src/VexHub/__Tests/**` |
|
||||
|
||||
### Artifacts & Evidence
|
||||
|
||||
| Module | Source Paths | Test Paths |
|
||||
|--------|--------------|------------|
|
||||
| Attestor | `src/Attestor/**` | `src/Attestor/__Tests/**` |
|
||||
| SbomService | `src/SbomService/**` | `src/SbomService/__Tests/**` |
|
||||
| EvidenceLocker | `src/EvidenceLocker/**` | `src/EvidenceLocker/__Tests/**` |
|
||||
| ExportCenter | `src/ExportCenter/**` | `src/ExportCenter/__Tests/**` |
|
||||
| Findings | `src/Findings/**` | `src/Findings/__Tests/**` |
|
||||
|
||||
### Policy & Risk
|
||||
|
||||
| Module | Source Paths | Test Paths |
|
||||
|--------|--------------|------------|
|
||||
| Policy | `src/Policy/**` | `src/Policy/__Tests/**` |
|
||||
| RiskEngine | `src/RiskEngine/**` | `src/RiskEngine/__Tests/**` |
|
||||
|
||||
### Operations
|
||||
|
||||
| Module | Source Paths | Test Paths |
|
||||
|--------|--------------|------------|
|
||||
| Notify | `src/Notify/**`, `src/Notifier/**` | `src/Notify/__Tests/**` |
|
||||
| Orchestrator | `src/Orchestrator/**` | `src/Orchestrator/__Tests/**` |
|
||||
| Scheduler | `src/Scheduler/**` | `src/Scheduler/__Tests/**` |
|
||||
| PacksRegistry | `src/PacksRegistry/**` | `src/PacksRegistry/__Tests/**` |
|
||||
| Replay | `src/Replay/**` | `src/Replay/__Tests/**` |
|
||||
|
||||
### Infrastructure
|
||||
|
||||
| Module | Source Paths | Test Paths |
|
||||
|--------|--------------|------------|
|
||||
| Cryptography | `src/Cryptography/**` | `src/__Libraries/__Tests/StellaOps.Cryptography*/**` |
|
||||
| Telemetry | `src/Telemetry/**` | `src/Telemetry/__Tests/**` |
|
||||
| Signals | `src/Signals/**` | `src/Signals/__Tests/**` |
|
||||
| AirGap | `src/AirGap/**` | `src/AirGap/__Tests/**` |
|
||||
| AOC | `src/Aoc/**` | `src/Aoc/__Tests/**` |
|
||||
|
||||
### Integration
|
||||
|
||||
| Module | Source Paths | Test Paths |
|
||||
|--------|--------------|------------|
|
||||
| CLI | `src/Cli/**` | `src/Cli/__Tests/**` |
|
||||
| Web | `src/Web/**` | `src/Web/**/*.spec.ts` |
|
||||
|
||||
---
|
||||
|
||||
## DevOps & CI/CD Paths
|
||||
|
||||
### Docker & Containers
|
||||
|
||||
```yaml
|
||||
docker:
|
||||
- 'devops/docker/**'
|
||||
- '**/Dockerfile'
|
||||
- '**/Dockerfile.*'
|
||||
```
|
||||
|
||||
### Compose Profiles
|
||||
|
||||
```yaml
|
||||
compose:
|
||||
- 'devops/compose/**'
|
||||
- 'docker-compose*.yml'
|
||||
```
|
||||
|
||||
### Helm Charts
|
||||
|
||||
```yaml
|
||||
helm:
|
||||
- 'devops/helm/**'
|
||||
- 'devops/helm/stellaops/**'
|
||||
```
|
||||
|
||||
### Database
|
||||
|
||||
```yaml
|
||||
database:
|
||||
- 'devops/database/**'
|
||||
- 'devops/database/postgres/**'
|
||||
```
|
||||
|
||||
### CI/CD Scripts
|
||||
|
||||
```yaml
|
||||
scripts:
|
||||
- '.gitea/scripts/**'
|
||||
- 'devops/scripts/**'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Test Infrastructure Paths
|
||||
|
||||
### Global Test Suites
|
||||
|
||||
```yaml
|
||||
global_tests:
|
||||
- 'src/__Tests/**'
|
||||
- 'src/__Tests/Integration/**'
|
||||
- 'src/__Tests/architecture/**'
|
||||
- 'src/__Tests/security/**'
|
||||
- 'src/__Tests/chaos/**'
|
||||
- 'src/__Tests/e2e/**'
|
||||
```
|
||||
|
||||
### Shared Test Libraries
|
||||
|
||||
```yaml
|
||||
test_libraries:
|
||||
- 'src/__Tests/__Libraries/**'
|
||||
- 'src/__Tests/__Libraries/StellaOps.TestKit/**'
|
||||
- 'src/__Tests/__Libraries/StellaOps.Infrastructure.Postgres.Testing/**'
|
||||
```
|
||||
|
||||
### Test Datasets
|
||||
|
||||
```yaml
|
||||
datasets:
|
||||
- 'src/__Tests/__Datasets/**'
|
||||
- 'src/__Tests/__Benchmarks/**'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Example Workflow Configurations
|
||||
|
||||
### PR-Gating Workflow (Skip Docs)
|
||||
|
||||
```yaml
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- '*.md'
|
||||
- 'etc/**'
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- '*.md'
|
||||
- 'etc/**'
|
||||
```
|
||||
|
||||
### Module-Specific Workflow (With Cascading)
|
||||
|
||||
```yaml
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
# Direct module paths
|
||||
- 'src/Scanner/**'
|
||||
- 'src/BinaryIndex/**'
|
||||
# Shared library cascades
|
||||
- 'src/__Libraries/StellaOps.Evidence*/**'
|
||||
- 'src/__Libraries/StellaOps.Cryptography*/**'
|
||||
- 'src/__Libraries/StellaOps.Replay*/**'
|
||||
- 'src/__Libraries/StellaOps.Provenance/**'
|
||||
# Infrastructure cascades
|
||||
- 'Directory.Build.props'
|
||||
- 'Directory.Packages.props'
|
||||
# Self-reference
|
||||
- '.gitea/workflows/scanner-*.yml'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'src/Scanner/**'
|
||||
- 'src/BinaryIndex/**'
|
||||
- 'src/__Libraries/StellaOps.Evidence*/**'
|
||||
- 'src/__Libraries/StellaOps.Cryptography*/**'
|
||||
```
|
||||
|
||||
### Documentation-Only Workflow
|
||||
|
||||
```yaml
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'docs/**'
|
||||
- '*.md'
|
||||
- 'scripts/render_docs.py'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'docs/**'
|
||||
- '*.md'
|
||||
```
|
||||
|
||||
### Docker/Container Workflow
|
||||
|
||||
```yaml
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- '**/Dockerfile'
|
||||
- '**/Dockerfile.*'
|
||||
- 'devops/docker/**'
|
||||
schedule:
|
||||
- cron: '0 4 * * *' # Also run daily for vulnerability updates
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Validation Checklist
|
||||
|
||||
When adding or modifying path filters:
|
||||
|
||||
- [ ] Does the workflow skip docs-only changes? (Use `paths-ignore`)
|
||||
- [ ] Does the workflow include dependent shared library paths? (Cascading)
|
||||
- [ ] Does the workflow include infrastructure files for full builds?
|
||||
- [ ] Are glob patterns correct? (`**` for recursive, `*` for single level)
|
||||
- [ ] Is the workflow self-referenced? (e.g., `.gitea/workflows/module-*.yml`)
|
||||
|
||||
---
|
||||
|
||||
## Glob Pattern Reference
|
||||
|
||||
| Pattern | Matches |
|
||||
|---------|---------|
|
||||
| `src/**` | All files under src/ recursively |
|
||||
| `src/*` | Direct children of src/ only |
|
||||
| `**/*.cs` | All .cs files anywhere |
|
||||
| `*.md` | Markdown files in root only |
|
||||
| `src/**/*.csproj` | All .csproj files under src/ |
|
||||
| `!src/**/*.md` | Exclude markdown in src/ |
|
||||
| `**/Dockerfile*` | Dockerfile, Dockerfile.prod, etc. |
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Workflow Triggers](./workflow-triggers.md) - Complete trigger reference
|
||||
- [Test Strategy](./test-strategy.md) - Test categories and execution
|
||||
- [CI/CD Overview](./README.md) - Architecture overview
|
||||
509
docs/technical/cicd/release-pipelines.md
Normal file
509
docs/technical/cicd/release-pipelines.md
Normal file
@@ -0,0 +1,509 @@
|
||||
# Release Pipelines
|
||||
|
||||
> Complete guide to StellaOps release automation including suite releases, module publishing, and promotion workflows.
|
||||
|
||||
---
|
||||
|
||||
## Release Strategy Overview
|
||||
|
||||
StellaOps uses a **dual-versioning strategy**:
|
||||
|
||||
1. **Suite Releases** - Ubuntu-style `YYYY.MM` versioning with codenames
|
||||
2. **Module Releases** - Semantic versioning `MAJOR.MINOR.PATCH` per module
|
||||
|
||||
### Release Channels
|
||||
|
||||
| Channel | Purpose | Stability | Update Frequency |
|
||||
|---------|---------|-----------|------------------|
|
||||
| **Edge** | Latest features, early adopters | Beta | Every merge to main |
|
||||
| **Stable** | Production-ready, tested | Production | Bi-weekly |
|
||||
| **LTS** | Long-term support, enterprise | Enterprise | Quarterly |
|
||||
|
||||
---
|
||||
|
||||
## Suite Release Pipeline
|
||||
|
||||
### Trigger
|
||||
|
||||
```bash
|
||||
# Tag-based trigger
|
||||
git tag suite-2026.04
|
||||
git push origin suite-2026.04
|
||||
|
||||
# Or manual trigger via Gitea Actions UI
|
||||
# Workflow: release-suite.yml
|
||||
# Inputs: version, codename, channel, skip_tests, dry_run
|
||||
```
|
||||
|
||||
### Workflow: `release-suite.yml`
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ SUITE RELEASE PIPELINE │
|
||||
│ │
|
||||
│ ┌──────────────┐ │
|
||||
│ │ parse-tag │ (if triggered by tag push) │
|
||||
│ │ or validate │ (if triggered manually) │
|
||||
│ └──────┬───────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌──────────────┐ │
|
||||
│ │ test-gate │ (optional, skipped with skip_tests=true) │
|
||||
│ └──────┬───────┘ │
|
||||
│ │ │
|
||||
│ ┌────┴────────────────────────────────────────┐ │
|
||||
│ │ BUILD PHASE │ │
|
||||
│ │ │ │
|
||||
│ │ ┌─────────────────┐ ┌─────────────────┐ │ │
|
||||
│ │ │ build-modules │ │ build-containers│ │ │
|
||||
│ │ │ (9 in parallel)│ │ (9 in parallel)│ │ │
|
||||
│ │ └─────────────────┘ └─────────────────┘ │ │
|
||||
│ │ │ │
|
||||
│ │ ┌─────────────────┐ ┌─────────────────┐ │ │
|
||||
│ │ │ build-cli │ │ build-helm │ │ │
|
||||
│ │ │ (5 platforms) │ │ │ │ │
|
||||
│ │ └─────────────────┘ └─────────────────┘ │ │
|
||||
│ │ │ │
|
||||
│ └─────────────────────┬────────────────────────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌───────────────────────────────────────────────┐ │
|
||||
│ │ release-manifest │ │
|
||||
│ │ - Binary manifest with SHA256 checksums │ │
|
||||
│ │ - SBOM generation (CycloneDX, SPDX) │ │
|
||||
│ │ - Provenance attestation (in-toto/DSSE) │ │
|
||||
│ └───────────────────────┬────────────────────────┘ │
|
||||
│ │ │
|
||||
│ ┌─────────────────────┴─────────────────────────┐ │
|
||||
│ │ │ │
|
||||
│ ▼ ▼ ▼ │
|
||||
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
||||
│ │ changelog │ │ suite-docs │ │ compose │ │
|
||||
│ │ generation │ │ generation │ │ generation │ │
|
||||
│ └──────────────┘ └──────────────┘ └──────────────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌───────────────────────────────────────────────┐ │
|
||||
│ │ create-release │ │
|
||||
│ │ - Upload artifacts to Gitea Releases │ │
|
||||
│ │ - Sign with Cosign (keyless Sigstore) │ │
|
||||
│ │ - Publish to container registry │ │
|
||||
│ └───────────────────────┬────────────────────────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌───────────────────────────────────────────────┐ │
|
||||
│ │ commit-docs │ │
|
||||
│ │ - Update docs/releases/ │ │
|
||||
│ │ - Update devops/compose/ │ │
|
||||
│ └───────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Suite Versioning
|
||||
|
||||
| Component | Format | Example |
|
||||
|-----------|--------|---------|
|
||||
| Suite Version | `YYYY.MM` | `2026.04` |
|
||||
| Codename | Alpha name | `Nova`, `Orion`, `Phoenix` |
|
||||
| Full Tag | `suite-YYYY.MM` | `suite-2026.04` |
|
||||
| Docker Tag | `YYYY.MM-channel` | `2026.04-stable` |
|
||||
|
||||
### Modules Built
|
||||
|
||||
| Module | NuGet Package | Container Image |
|
||||
|--------|---------------|-----------------|
|
||||
| Authority | `StellaOps.Authority` | `stellaops/authority` |
|
||||
| Scanner | `StellaOps.Scanner` | `stellaops/scanner` |
|
||||
| Concelier | `StellaOps.Concelier` | `stellaops/concelier` |
|
||||
| Excititor | `StellaOps.Excititor` | `stellaops/excititor` |
|
||||
| SbomService | `StellaOps.SbomService` | `stellaops/sbom-service` |
|
||||
| EvidenceLocker | `StellaOps.EvidenceLocker` | `stellaops/evidence-locker` |
|
||||
| Policy | `StellaOps.Policy` | `stellaops/policy` |
|
||||
| Attestor | `StellaOps.Attestor` | `stellaops/attestor` |
|
||||
| VexLens | `StellaOps.VexLens` | `stellaops/vexlens` |
|
||||
|
||||
### CLI Platforms
|
||||
|
||||
| Runtime ID | OS | Architecture | Binary Name |
|
||||
|------------|-----|--------------|-------------|
|
||||
| `linux-x64` | Linux | x86_64 | `stellaops-linux-x64` |
|
||||
| `linux-arm64` | Linux | ARM64 | `stellaops-linux-arm64` |
|
||||
| `win-x64` | Windows | x86_64 | `stellaops-win-x64.exe` |
|
||||
| `osx-x64` | macOS | Intel | `stellaops-osx-x64` |
|
||||
| `osx-arm64` | macOS | Apple Silicon | `stellaops-osx-arm64` |
|
||||
|
||||
---
|
||||
|
||||
## Module Release Pipeline
|
||||
|
||||
### Trigger
|
||||
|
||||
```bash
|
||||
# Tag-based trigger
|
||||
git tag module-authority-v1.2.3
|
||||
git push origin module-authority-v1.2.3
|
||||
|
||||
# Or manual trigger via Gitea Actions UI
|
||||
# Workflow: module-publish.yml
|
||||
# Inputs: module, version, publish_nuget, publish_container, prerelease
|
||||
```
|
||||
|
||||
### Workflow: `module-publish.yml`
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ MODULE PUBLISH PIPELINE │
|
||||
│ │
|
||||
│ ┌──────────────┐ │
|
||||
│ │ parse-tag │ Extract module name and version from tag │
|
||||
│ │ or validate │ Normalize manual inputs │
|
||||
│ └──────┬───────┘ │
|
||||
│ │ │
|
||||
│ ┌────┴────────────────────────────────────────┐ │
|
||||
│ │ │ │
|
||||
│ ▼ ▼ │
|
||||
│ ┌──────────────┐ ┌──────────────┐ │
|
||||
│ │publish-nuget │ (if flag set) │publish-cont. │ │
|
||||
│ │ │ │ (if flag set)│ │
|
||||
│ │ - Pack │ │ - Build │ │
|
||||
│ │ - Sign │ │ - Scan │ │
|
||||
│ │ - Push │ │ - Sign │ │
|
||||
│ └──────────────┘ │ - Push │ │
|
||||
│ └──────────────┘ │
|
||||
│ │ │
|
||||
│ OR (if module=CLI) │ │
|
||||
│ ▼ │
|
||||
│ ┌──────────────────────────────────────────────────┐ │
|
||||
│ │ publish-cli │ │
|
||||
│ │ - Build for 5 platforms │ │
|
||||
│ │ - Native AOT compilation │ │
|
||||
│ │ - Code sign binaries │ │
|
||||
│ │ - Generate checksums │ │
|
||||
│ │ - Upload to release │ │
|
||||
│ └──────────────────────────────────────────────────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌──────────────────────────────────────────────────┐ │
|
||||
│ │ summary │ │
|
||||
│ │ - Release notes │ │
|
||||
│ │ - Artifact links │ │
|
||||
│ │ - SBOM references │ │
|
||||
│ └──────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Module Tag Format
|
||||
|
||||
```
|
||||
module-<name>-v<semver>
|
||||
|
||||
Examples:
|
||||
module-authority-v1.2.3
|
||||
module-scanner-v2.0.0
|
||||
module-cli-v3.1.0-beta.1
|
||||
```
|
||||
|
||||
### Available Modules
|
||||
|
||||
| Module Name | NuGet | Container | CLI |
|
||||
|-------------|-------|-----------|-----|
|
||||
| `authority` | Yes | Yes | No |
|
||||
| `scanner` | Yes | Yes | No |
|
||||
| `concelier` | Yes | Yes | No |
|
||||
| `excititor` | Yes | Yes | No |
|
||||
| `sbomservice` | Yes | Yes | No |
|
||||
| `evidencelocker` | Yes | Yes | No |
|
||||
| `policy` | Yes | Yes | No |
|
||||
| `attestor` | Yes | Yes | No |
|
||||
| `vexlens` | Yes | Yes | No |
|
||||
| `cli` | No | No | Yes (multi-platform) |
|
||||
|
||||
---
|
||||
|
||||
## Bundle Release Pipeline
|
||||
|
||||
### Trigger
|
||||
|
||||
```bash
|
||||
# Tag-based trigger
|
||||
git tag v2025.12.1
|
||||
git push origin v2025.12.1
|
||||
|
||||
# Channel-specific tags
|
||||
git tag v2025.12.0-edge
|
||||
git tag v2025.12.0-stable
|
||||
git tag v2025.12.0-lts
|
||||
```
|
||||
|
||||
### Workflow: `release.yml`
|
||||
|
||||
Creates deterministic release bundles with:
|
||||
- Signed container images
|
||||
- SBOM generation
|
||||
- Provenance attestations
|
||||
- CLI parity verification
|
||||
|
||||
---
|
||||
|
||||
## Rollback Pipeline
|
||||
|
||||
### Trigger
|
||||
|
||||
```bash
|
||||
# Manual trigger only via Gitea Actions UI
|
||||
# Workflow: rollback.yml
|
||||
# Inputs: environment, service, version, reason
|
||||
```
|
||||
|
||||
### Workflow: `rollback.yml`
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ ROLLBACK PIPELINE │
|
||||
│ (SLA Target: < 5 min) │
|
||||
│ │
|
||||
│ ┌──────────────┐ │
|
||||
│ │ validate │ Verify inputs and permissions │
|
||||
│ └──────┬───────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌──────────────┐ │
|
||||
│ │ fetch-prev │ Download previous version artifacts │
|
||||
│ │ version │ │
|
||||
│ └──────┬───────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌──────────────┐ │
|
||||
│ │ execute │ Run rollback via Helm/kubectl │
|
||||
│ │ rollback │ │
|
||||
│ └──────┬───────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌──────────────┐ │
|
||||
│ │health-check │ Verify service health post-rollback │
|
||||
│ └──────┬───────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌──────────────┐ │
|
||||
│ │ notify │ Send notification (Slack/Teams/Webhook) │
|
||||
│ └──────────────┘ │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Rollback Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
|-----------|------|-------------|
|
||||
| `environment` | choice | `staging`, `production` |
|
||||
| `service` | choice | Service to rollback (or `all`) |
|
||||
| `version` | string | Target version to rollback to |
|
||||
| `reason` | string | Reason for rollback (audit log) |
|
||||
| `dry_run` | boolean | Simulate without executing |
|
||||
|
||||
---
|
||||
|
||||
## Promotion Pipeline
|
||||
|
||||
### Trigger
|
||||
|
||||
```bash
|
||||
# Manual trigger only via Gitea Actions UI
|
||||
# Workflow: promote.yml
|
||||
# Inputs: from_environment, to_environment, version
|
||||
```
|
||||
|
||||
### Promotion Flow
|
||||
|
||||
```
|
||||
┌─────────────┐
|
||||
│ Edge │ (Automatic on main merge)
|
||||
└──────┬──────┘
|
||||
│
|
||||
│ promote.yml (manual)
|
||||
▼
|
||||
┌─────────────┐
|
||||
│ Stable │ (After testing period)
|
||||
└──────┬──────┘
|
||||
│
|
||||
│ promote.yml (manual)
|
||||
▼
|
||||
┌─────────────┐
|
||||
│ LTS │ (After extended validation)
|
||||
└─────────────┘
|
||||
```
|
||||
|
||||
### Promotion Checklist (Automated)
|
||||
|
||||
1. **Pre-Flight Checks**
|
||||
- All tests passing in source environment
|
||||
- No critical vulnerabilities
|
||||
- Performance SLOs met
|
||||
- Documentation complete
|
||||
|
||||
2. **Promotion Steps**
|
||||
- Re-tag containers with new channel
|
||||
- Update Helm chart values
|
||||
- Deploy to target environment
|
||||
- Run smoke tests
|
||||
|
||||
3. **Post-Promotion**
|
||||
- Health check verification
|
||||
- Update release documentation
|
||||
- Notify stakeholders
|
||||
|
||||
---
|
||||
|
||||
## Artifact Signing
|
||||
|
||||
### Cosign Integration
|
||||
|
||||
All release artifacts are signed using Cosign with Sigstore keyless signing:
|
||||
|
||||
```bash
|
||||
# Verify container signature
|
||||
cosign verify \
|
||||
--certificate-identity-regexp=".*github.com/stellaops.*" \
|
||||
--certificate-oidc-issuer="https://token.actions.githubusercontent.com" \
|
||||
ghcr.io/stellaops/scanner:2026.04
|
||||
|
||||
# Verify SBOM
|
||||
cosign verify-attestation \
|
||||
--type spdxjson \
|
||||
--certificate-identity-regexp=".*github.com/stellaops.*" \
|
||||
ghcr.io/stellaops/scanner:2026.04
|
||||
```
|
||||
|
||||
### Signature Artifacts
|
||||
|
||||
| Artifact Type | Signature Location |
|
||||
|---------------|-------------------|
|
||||
| Container Image | OCI registry (same repo) |
|
||||
| CLI Binary | `.sig` file alongside binary |
|
||||
| SBOM | Attestation on OCI image |
|
||||
| Provenance | Attestation on OCI image |
|
||||
|
||||
---
|
||||
|
||||
## Release Artifacts
|
||||
|
||||
### Per-Release Artifacts
|
||||
|
||||
| Artifact | Format | Location |
|
||||
|----------|--------|----------|
|
||||
| Release Notes | Markdown | Gitea Release |
|
||||
| Changelog | `CHANGELOG.md` | Gitea Release, `docs/releases/` |
|
||||
| Binary Checksums | `SHA256SUMS.txt` | Gitea Release |
|
||||
| SBOM (CycloneDX) | JSON | Gitea Release, OCI attestation |
|
||||
| SBOM (SPDX) | JSON | Gitea Release |
|
||||
| Provenance | in-toto/DSSE | OCI attestation |
|
||||
| Docker Compose | YAML | `devops/compose/` |
|
||||
| Helm Chart | TGZ | OCI registry |
|
||||
|
||||
### Artifact Retention
|
||||
|
||||
| Environment | Retention Period |
|
||||
|-------------|------------------|
|
||||
| PR/Preview | 7 days |
|
||||
| Edge | 30 days |
|
||||
| Stable | 1 year |
|
||||
| LTS | 3 years |
|
||||
|
||||
---
|
||||
|
||||
## Creating a Release
|
||||
|
||||
### Suite Release
|
||||
|
||||
```bash
|
||||
# 1. Ensure main is stable
|
||||
git checkout main
|
||||
git pull
|
||||
|
||||
# 2. Create and push tag
|
||||
git tag suite-2026.04
|
||||
git push origin suite-2026.04
|
||||
|
||||
# 3. Monitor release pipeline
|
||||
# Gitea Actions → release-suite.yml
|
||||
|
||||
# 4. Verify artifacts
|
||||
# - Check Gitea Releases page
|
||||
# - Verify container images pushed
|
||||
# - Validate SBOM and signatures
|
||||
```
|
||||
|
||||
### Module Release
|
||||
|
||||
```bash
|
||||
# 1. Update module version
|
||||
# Edit src/<Module>/version.txt or .csproj
|
||||
|
||||
# 2. Create and push tag
|
||||
git tag module-authority-v1.2.3
|
||||
git push origin module-authority-v1.2.3
|
||||
|
||||
# 3. Monitor release pipeline
|
||||
# Gitea Actions → module-publish.yml
|
||||
```
|
||||
|
||||
### Hotfix Release
|
||||
|
||||
```bash
|
||||
# 1. Create hotfix branch from release tag
|
||||
git checkout -b hotfix/v2025.12.1 v2025.12.0
|
||||
|
||||
# 2. Apply fix
|
||||
# ... make changes ...
|
||||
git commit -m "Fix: critical security issue"
|
||||
|
||||
# 3. Create hotfix tag
|
||||
git tag v2025.12.1
|
||||
git push origin hotfix/v2025.12.1 v2025.12.1
|
||||
|
||||
# 4. Fast-track through pipeline
|
||||
# Workflow will run with reduced test scope
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting Releases
|
||||
|
||||
### Release Pipeline Failed
|
||||
|
||||
1. **Check build logs** - Gitea Actions → failed job
|
||||
2. **Verify tag format** - Must match expected pattern
|
||||
3. **Check secrets** - Registry credentials, signing keys
|
||||
4. **Review test failures** - May need to skip with `skip_tests=true`
|
||||
|
||||
### Container Not Published
|
||||
|
||||
1. **Check registry authentication** - `REGISTRY_TOKEN` secret
|
||||
2. **Verify image name** - Check for typos in workflow
|
||||
3. **Check rate limits** - May need to wait and retry
|
||||
4. **Review scan results** - Image may be blocked by vulnerability scan
|
||||
|
||||
### Signature Verification Failed
|
||||
|
||||
1. **Check Sigstore availability** - May have temporary outage
|
||||
2. **Verify certificate identity** - Workflow must match expected pattern
|
||||
3. **Check OIDC issuer** - Must be GitHub/Gitea Actions
|
||||
|
||||
### Rollback Failed
|
||||
|
||||
1. **Verify target version exists** - Check artifact storage
|
||||
2. **Check Helm/kubectl access** - Cluster credentials
|
||||
3. **Review health check** - Service may need manual intervention
|
||||
4. **Check resource constraints** - May need to scale down first
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [README - CI/CD Overview](./README.md)
|
||||
- [Workflow Triggers](./workflow-triggers.md)
|
||||
- [Versioning Guide](../releases/VERSIONING.md)
|
||||
- [Container Registry Guide](../operations/container-registry.md)
|
||||
- [Helm Deployment Guide](../operations/helm-deployment.md)
|
||||
250
docs/technical/cicd/sarif-integration.md
Normal file
250
docs/technical/cicd/sarif-integration.md
Normal file
@@ -0,0 +1,250 @@
|
||||
# SARIF Integration Guide
|
||||
|
||||
**Sprint:** SPRINT_3500_0004_0001
|
||||
**Task:** SDIFF-BIN-032 - Documentation for SARIF integration
|
||||
|
||||
## Overview
|
||||
|
||||
StellaOps Scanner supports SARIF (Static Analysis Results Interchange Format) 2.1.0 output for seamless integration with CI/CD platforms including GitHub, GitLab, and Azure DevOps.
|
||||
|
||||
## Supported Platforms
|
||||
|
||||
| Platform | Integration Method | Native Support |
|
||||
|----------|-------------------|----------------|
|
||||
| GitHub Actions | Code Scanning API | ✅ Yes |
|
||||
| GitLab CI | SAST Reports | ✅ Yes |
|
||||
| Azure DevOps | SARIF Viewer Extension | ✅ Yes |
|
||||
| Jenkins | SARIF Plugin | ✅ Yes |
|
||||
| Other | File upload | ✅ Yes |
|
||||
|
||||
## Quick Start
|
||||
|
||||
### API Endpoint
|
||||
|
||||
```bash
|
||||
# Get SARIF output for a scan
|
||||
curl -H "Authorization: Bearer $TOKEN" \
|
||||
"https://scanner.example.com/api/v1/smart-diff/scans/{scanId}/sarif"
|
||||
|
||||
# With pretty printing
|
||||
curl -H "Authorization: Bearer $TOKEN" \
|
||||
"https://scanner.example.com/api/v1/smart-diff/scans/{scanId}/sarif?pretty=true"
|
||||
```
|
||||
|
||||
### CLI Usage
|
||||
|
||||
```bash
|
||||
# Scan with SARIF output
|
||||
stellaops scan image:tag --output-format sarif > results.sarif
|
||||
|
||||
# Smart-diff with SARIF output
|
||||
stellaops smart-diff --base image:v1 --target image:v2 --output-format sarif
|
||||
```
|
||||
|
||||
## SARIF Rule Definitions
|
||||
|
||||
StellaOps emits the following rule categories in SARIF output:
|
||||
|
||||
| Rule ID | Name | Description |
|
||||
|---------|------|-------------|
|
||||
| SDIFF001 | ReachabilityChange | Vulnerability reachability status changed |
|
||||
| SDIFF002 | VexStatusFlip | VEX status changed (affected/not_affected/fixed) |
|
||||
| SDIFF003 | HardeningRegression | Binary hardening flag regressed |
|
||||
| SDIFF004 | IntelligenceSignal | EPSS/KEV status changed |
|
||||
|
||||
## GitHub Actions Integration
|
||||
|
||||
```yaml
|
||||
name: Security Scan
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
security:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Run StellaOps Scanner
|
||||
run: |
|
||||
stellaops scan ${{ github.repository }} \
|
||||
--output-format sarif \
|
||||
--output results.sarif
|
||||
|
||||
- name: Upload SARIF
|
||||
uses: github/codeql-action/upload-sarif@v3
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
category: stellaops
|
||||
```
|
||||
|
||||
## GitLab CI Integration
|
||||
|
||||
```yaml
|
||||
security_scan:
|
||||
stage: test
|
||||
image: stellaops/cli:latest
|
||||
script:
|
||||
- stellaops scan $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA --output-format sarif > gl-sast-report.sarif
|
||||
artifacts:
|
||||
reports:
|
||||
sast: gl-sast-report.sarif
|
||||
```
|
||||
|
||||
## Azure DevOps Integration
|
||||
|
||||
```yaml
|
||||
trigger:
|
||||
- main
|
||||
|
||||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
|
||||
steps:
|
||||
- task: Bash@3
|
||||
displayName: 'Run StellaOps Scanner'
|
||||
inputs:
|
||||
targetType: 'inline'
|
||||
script: |
|
||||
stellaops scan $(containerImage) --output-format sarif > $(Build.ArtifactStagingDirectory)/results.sarif
|
||||
|
||||
- task: PublishBuildArtifacts@1
|
||||
inputs:
|
||||
pathToPublish: '$(Build.ArtifactStagingDirectory)/results.sarif'
|
||||
artifactName: 'security-results'
|
||||
```
|
||||
|
||||
## SARIF Schema Details
|
||||
|
||||
### Result Levels
|
||||
|
||||
| SARIF Level | StellaOps Severity | Description |
|
||||
|-------------|-------------------|-------------|
|
||||
| `error` | Critical, High | Requires immediate attention |
|
||||
| `warning` | Medium | Should be reviewed |
|
||||
| `note` | Low, Info | For awareness |
|
||||
|
||||
### Result Kinds
|
||||
|
||||
| Kind | Meaning |
|
||||
|------|---------|
|
||||
| `fail` | Finding indicates a problem |
|
||||
| `pass` | Check passed (for VEX suppressed) |
|
||||
| `notApplicable` | Finding does not apply |
|
||||
| `informational` | Advisory information |
|
||||
|
||||
### Location Information
|
||||
|
||||
SARIF results include:
|
||||
- **Physical location**: File path and line numbers (when available)
|
||||
- **Logical location**: Component PURL, function name
|
||||
- **URI**: OCI artifact digest or SBOM reference
|
||||
|
||||
## Example SARIF Output
|
||||
|
||||
```json
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/main/sarif-2.1/schema/sarif-schema-2.1.0.json",
|
||||
"version": "2.1.0",
|
||||
"runs": [
|
||||
{
|
||||
"tool": {
|
||||
"driver": {
|
||||
"name": "StellaOps Scanner",
|
||||
"version": "1.0.0",
|
||||
"informationUri": "https://stellaops.io",
|
||||
"rules": [
|
||||
{
|
||||
"id": "SDIFF001",
|
||||
"name": "ReachabilityChange",
|
||||
"shortDescription": {
|
||||
"text": "Vulnerability reachability changed"
|
||||
},
|
||||
"defaultConfiguration": {
|
||||
"level": "warning"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"results": [
|
||||
{
|
||||
"ruleId": "SDIFF001",
|
||||
"level": "warning",
|
||||
"message": {
|
||||
"text": "CVE-2024-1234 became reachable in pkg:npm/lodash@4.17.20"
|
||||
},
|
||||
"locations": [
|
||||
{
|
||||
"physicalLocation": {
|
||||
"artifactLocation": {
|
||||
"uri": "package-lock.json"
|
||||
}
|
||||
},
|
||||
"logicalLocations": [
|
||||
{
|
||||
"name": "pkg:npm/lodash@4.17.20",
|
||||
"kind": "package"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"vulnerability": "CVE-2024-1234",
|
||||
"tier": "executed",
|
||||
"direction": "increased"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Filtering Results
|
||||
|
||||
### By Tier
|
||||
|
||||
```bash
|
||||
# Only tainted_sink findings
|
||||
stellaops scan image:tag --output-format sarif --tier tainted_sink
|
||||
|
||||
# Executed and tainted_sink
|
||||
stellaops scan image:tag --output-format sarif --tier executed,tainted_sink
|
||||
```
|
||||
|
||||
### By Priority
|
||||
|
||||
```bash
|
||||
# Only high priority changes
|
||||
stellaops smart-diff --output-format sarif --min-priority 0.7
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### SARIF Validation Errors
|
||||
|
||||
If your CI platform rejects the SARIF output:
|
||||
|
||||
1. Validate against schema:
|
||||
```bash
|
||||
stellaops validate-sarif results.sarif
|
||||
```
|
||||
|
||||
2. Check for required fields:
|
||||
- `$schema` must be present
|
||||
- `version` must be `"2.1.0"`
|
||||
- Each result must have `ruleId` and `message`
|
||||
|
||||
### Empty Results
|
||||
|
||||
If SARIF contains no results:
|
||||
- Check scan completed successfully
|
||||
- Verify image has vulnerability data
|
||||
- Ensure feed snapshots are current
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Smart-Diff Detection Rules](../modules/scanner/smart-diff-rules.md)
|
||||
- [Scanner API Reference](../api/scanner-api.md)
|
||||
- [CLI Reference](../API_CLI_REFERENCE.md)
|
||||
- [Scoring Configuration](./scoring-configuration.md)
|
||||
292
docs/technical/cicd/scoring-configuration.md
Normal file
292
docs/technical/cicd/scoring-configuration.md
Normal file
@@ -0,0 +1,292 @@
|
||||
# Smart-Diff Scoring Configuration Guide
|
||||
|
||||
**Sprint:** SPRINT_3500_0004_0001
|
||||
**Task:** SDIFF-BIN-031 - Documentation for scoring configuration
|
||||
|
||||
## Overview
|
||||
|
||||
Smart-Diff uses configurable scoring weights to prioritize material risk changes. This guide explains how to customize scoring for your organization's risk appetite.
|
||||
|
||||
## Configuration Location
|
||||
|
||||
Smart-Diff scoring can be configured via:
|
||||
1. **PolicyScoringConfig** - Integrated with policy engine
|
||||
2. **SmartDiffScoringConfig** - Standalone configuration
|
||||
3. **Environment variables** - Runtime overrides
|
||||
4. **API** - Dynamic configuration
|
||||
|
||||
## Default Configuration
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "default",
|
||||
"version": "1.0",
|
||||
"reachabilityFlipUpWeight": 1.0,
|
||||
"reachabilityFlipDownWeight": 0.8,
|
||||
"vexFlipToAffectedWeight": 0.9,
|
||||
"vexFlipToNotAffectedWeight": 0.7,
|
||||
"vexFlipToFixedWeight": 0.6,
|
||||
"vexFlipToUnderInvestigationWeight": 0.3,
|
||||
"rangeEntryWeight": 0.8,
|
||||
"rangeExitWeight": 0.6,
|
||||
"kevAddedWeight": 1.0,
|
||||
"epssThreshold": 0.1,
|
||||
"epssThresholdCrossWeight": 0.5,
|
||||
"hardeningRegressionWeight": 0.7,
|
||||
"hardeningImprovementWeight": 0.3,
|
||||
"hardeningRegressionThreshold": 0.1
|
||||
}
|
||||
```
|
||||
|
||||
## Weight Categories
|
||||
|
||||
### Reachability Weights (R1)
|
||||
|
||||
Controls scoring for reachability status changes.
|
||||
|
||||
| Parameter | Default | Description |
|
||||
|-----------|---------|-------------|
|
||||
| `reachabilityFlipUpWeight` | 1.0 | Unreachable → Reachable (risk increase) |
|
||||
| `reachabilityFlipDownWeight` | 0.8 | Reachable → Unreachable (risk decrease) |
|
||||
| `useLatticeConfidence` | true | Factor in reachability confidence |
|
||||
|
||||
**Example scenarios:**
|
||||
- Vulnerability becomes reachable after code refactoring → weight = 1.0
|
||||
- Dependency removed, vulnerability no longer reachable → weight = 0.8
|
||||
|
||||
### VEX Status Weights (R2)
|
||||
|
||||
Controls scoring for VEX statement changes.
|
||||
|
||||
| Parameter | Default | Description |
|
||||
|-----------|---------|-------------|
|
||||
| `vexFlipToAffectedWeight` | 0.9 | Status changed to "affected" |
|
||||
| `vexFlipToNotAffectedWeight` | 0.7 | Status changed to "not_affected" |
|
||||
| `vexFlipToFixedWeight` | 0.6 | Status changed to "fixed" |
|
||||
| `vexFlipToUnderInvestigationWeight` | 0.3 | Status changed to "under_investigation" |
|
||||
|
||||
**Rationale:**
|
||||
- "affected" is highest weight as it confirms exploitability
|
||||
- "fixed" is lower as it indicates remediation
|
||||
- "under_investigation" is lowest as status is uncertain
|
||||
|
||||
### Version Range Weights (R3)
|
||||
|
||||
Controls scoring for affected version range changes.
|
||||
|
||||
| Parameter | Default | Description |
|
||||
|-----------|---------|-------------|
|
||||
| `rangeEntryWeight` | 0.8 | Version entered affected range |
|
||||
| `rangeExitWeight` | 0.6 | Version exited affected range |
|
||||
|
||||
### Intelligence Signal Weights (R4)
|
||||
|
||||
Controls scoring for external intelligence changes.
|
||||
|
||||
| Parameter | Default | Description |
|
||||
|-----------|---------|-------------|
|
||||
| `kevAddedWeight` | 1.0 | Vulnerability added to CISA KEV |
|
||||
| `epssThreshold` | 0.1 | EPSS score threshold for significance |
|
||||
| `epssThresholdCrossWeight` | 0.5 | Weight when EPSS crosses threshold |
|
||||
|
||||
### Binary Hardening Weights (R5)
|
||||
|
||||
Controls scoring for binary hardening flag changes.
|
||||
|
||||
| Parameter | Default | Description |
|
||||
|-----------|---------|-------------|
|
||||
| `hardeningRegressionWeight` | 0.7 | Security flag disabled (e.g., NX removed) |
|
||||
| `hardeningImprovementWeight` | 0.3 | Security flag enabled (e.g., PIE added) |
|
||||
| `hardeningRegressionThreshold` | 0.1 | Minimum score drop to flag regression |
|
||||
|
||||
## Presets
|
||||
|
||||
### Default Preset
|
||||
|
||||
Balanced configuration suitable for most organizations.
|
||||
|
||||
```csharp
|
||||
SmartDiffScoringConfig.Default
|
||||
```
|
||||
|
||||
### Strict Preset
|
||||
|
||||
Higher weights for regressions, recommended for security-critical applications.
|
||||
|
||||
```csharp
|
||||
SmartDiffScoringConfig.Strict
|
||||
```
|
||||
|
||||
Configuration:
|
||||
```json
|
||||
{
|
||||
"name": "strict",
|
||||
"reachabilityFlipUpWeight": 1.2,
|
||||
"vexFlipToAffectedWeight": 1.1,
|
||||
"kevAddedWeight": 1.5,
|
||||
"hardeningRegressionWeight": 1.0,
|
||||
"hardeningRegressionThreshold": 0.05
|
||||
}
|
||||
```
|
||||
|
||||
### Lenient Preset
|
||||
|
||||
Lower weights for alerts, suitable for development/staging environments.
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "lenient",
|
||||
"reachabilityFlipUpWeight": 0.7,
|
||||
"vexFlipToAffectedWeight": 0.6,
|
||||
"kevAddedWeight": 0.8,
|
||||
"hardeningRegressionWeight": 0.4,
|
||||
"epssThreshold": 0.2
|
||||
}
|
||||
```
|
||||
|
||||
## Policy Integration
|
||||
|
||||
Smart-Diff scoring integrates with `PolicyScoringConfig`:
|
||||
|
||||
```csharp
|
||||
var config = new PolicyScoringConfig(
|
||||
Version: "1.0",
|
||||
SeverityWeights: severityWeights,
|
||||
QuietPenalty: 0.1,
|
||||
WarnPenalty: 0.5,
|
||||
IgnorePenalty: 0.0,
|
||||
TrustOverrides: trustOverrides,
|
||||
ReachabilityBuckets: reachabilityBuckets,
|
||||
UnknownConfidence: unknownConfig,
|
||||
SmartDiff: new SmartDiffPolicyScoringConfig(
|
||||
ReachabilityFlipUpWeight: 1.0,
|
||||
VexFlipToAffectedWeight: 0.9,
|
||||
KevAddedWeight: 1.2
|
||||
)
|
||||
);
|
||||
```
|
||||
|
||||
## Environment Variable Overrides
|
||||
|
||||
```bash
|
||||
# Override reachability weights
|
||||
export STELLAOPS_SMARTDIFF_REACHABILITY_FLIP_UP_WEIGHT=1.2
|
||||
export STELLAOPS_SMARTDIFF_REACHABILITY_FLIP_DOWN_WEIGHT=0.7
|
||||
|
||||
# Override KEV weight
|
||||
export STELLAOPS_SMARTDIFF_KEV_ADDED_WEIGHT=1.5
|
||||
|
||||
# Override hardening threshold
|
||||
export STELLAOPS_SMARTDIFF_HARDENING_REGRESSION_THRESHOLD=0.05
|
||||
```
|
||||
|
||||
## API Configuration
|
||||
|
||||
### Get Current Configuration
|
||||
|
||||
```bash
|
||||
GET /api/v1/config/smart-diff/scoring
|
||||
|
||||
Response:
|
||||
{
|
||||
"name": "default",
|
||||
"version": "1.0",
|
||||
"weights": { ... }
|
||||
}
|
||||
```
|
||||
|
||||
### Update Configuration
|
||||
|
||||
```bash
|
||||
PUT /api/v1/config/smart-diff/scoring
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"reachabilityFlipUpWeight": 1.2,
|
||||
"kevAddedWeight": 1.5
|
||||
}
|
||||
```
|
||||
|
||||
## Score Calculation Formula
|
||||
|
||||
The final priority score is calculated as:
|
||||
|
||||
```
|
||||
priority_score = base_severity × Σ(change_weight × rule_match)
|
||||
```
|
||||
|
||||
Where:
|
||||
- `base_severity` is the CVSS/severity normalized to 0-1
|
||||
- `change_weight` is the configured weight for the change type
|
||||
- `rule_match` is 1 if the rule triggered, 0 otherwise
|
||||
|
||||
### Example Calculation
|
||||
|
||||
Given:
|
||||
- CVE-2024-1234 with CVSS 7.5 (base_severity = 0.75)
|
||||
- Became reachable (reachabilityFlipUpWeight = 1.0)
|
||||
- Added to KEV (kevAddedWeight = 1.0)
|
||||
|
||||
```
|
||||
priority_score = 0.75 × (1.0 + 1.0) = 1.5 → capped at 1.0
|
||||
```
|
||||
|
||||
## Tuning Recommendations
|
||||
|
||||
### For CI/CD Pipelines
|
||||
|
||||
```json
|
||||
{
|
||||
"kevAddedWeight": 1.5,
|
||||
"hardeningRegressionWeight": 1.2,
|
||||
"epssThreshold": 0.05
|
||||
}
|
||||
```
|
||||
|
||||
Focus on blocking builds for known exploited vulnerabilities and hardening regressions.
|
||||
|
||||
### For Alert Fatigue Reduction
|
||||
|
||||
```json
|
||||
{
|
||||
"reachabilityFlipDownWeight": 0.3,
|
||||
"vexFlipToNotAffectedWeight": 0.2,
|
||||
"rangeExitWeight": 0.2
|
||||
}
|
||||
```
|
||||
|
||||
Lower weights for positive changes to reduce noise.
|
||||
|
||||
### For Compliance Focus
|
||||
|
||||
```json
|
||||
{
|
||||
"kevAddedWeight": 2.0,
|
||||
"vexFlipToAffectedWeight": 1.2,
|
||||
"hardeningRegressionThreshold": 0.02
|
||||
}
|
||||
```
|
||||
|
||||
Higher weights for regulatory-relevant changes.
|
||||
|
||||
## Monitoring and Metrics
|
||||
|
||||
Track scoring effectiveness with:
|
||||
|
||||
```sql
|
||||
-- Average priority score by rule type
|
||||
SELECT
|
||||
change_type,
|
||||
AVG(priority_score) as avg_score,
|
||||
COUNT(*) as count
|
||||
FROM smart_diff_changes
|
||||
WHERE created_at > now() - interval '30 days'
|
||||
GROUP BY change_type
|
||||
ORDER BY avg_score DESC;
|
||||
```
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Smart-Diff Detection Rules](../modules/scanner/smart-diff-rules.md)
|
||||
- [Policy Engine Configuration](../modules/policy/architecture.md)
|
||||
- [SARIF Integration](./sarif-integration.md)
|
||||
508
docs/technical/cicd/security-scanning.md
Normal file
508
docs/technical/cicd/security-scanning.md
Normal file
@@ -0,0 +1,508 @@
|
||||
# Security Scanning
|
||||
|
||||
> Complete guide to security scanning workflows in the StellaOps CI/CD pipeline.
|
||||
|
||||
---
|
||||
|
||||
## Security Scanning Overview
|
||||
|
||||
StellaOps implements a **defense-in-depth** security scanning strategy:
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ SECURITY SCANNING LAYERS │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ Layer 1: PRE-COMMIT │
|
||||
│ └── Secrets scanning (pre-commit hook) │
|
||||
│ │
|
||||
│ Layer 2: PULL REQUEST │
|
||||
│ ├── SAST (Static Application Security Testing) │
|
||||
│ ├── Secrets scanning │
|
||||
│ ├── Dependency vulnerability audit │
|
||||
│ └── License compliance check │
|
||||
│ │
|
||||
│ Layer 3: MAIN BRANCH │
|
||||
│ ├── All Layer 2 scans │
|
||||
│ ├── Container image scanning │
|
||||
│ └── Extended SAST analysis │
|
||||
│ │
|
||||
│ Layer 4: SCHEDULED │
|
||||
│ ├── Weekly deep SAST scan (Monday) │
|
||||
│ ├── Weekly dependency audit (Sunday) │
|
||||
│ ├── Daily container scanning │
|
||||
│ └── Nightly regression security tests │
|
||||
│ │
|
||||
│ Layer 5: RELEASE │
|
||||
│ ├── Final vulnerability gate │
|
||||
│ ├── SBOM generation and signing │
|
||||
│ ├── Provenance attestation │
|
||||
│ └── Container signing │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Scanning Workflows
|
||||
|
||||
### 1. SAST Scanning (`sast-scan.yml`)
|
||||
|
||||
**Purpose:** Detect security vulnerabilities in source code through static analysis.
|
||||
|
||||
**Triggers:**
|
||||
- Pull requests (source code changes)
|
||||
- Push to main/develop
|
||||
- Weekly Monday 3:30 AM UTC
|
||||
- Manual dispatch
|
||||
|
||||
**Scanned Languages:**
|
||||
- C# / .NET
|
||||
- JavaScript / TypeScript
|
||||
- Python
|
||||
- YAML
|
||||
- Dockerfile
|
||||
|
||||
**Checks Performed:**
|
||||
|
||||
| Check | Tool | Scope |
|
||||
|-------|------|-------|
|
||||
| Code vulnerabilities | Semgrep/CodeQL (placeholder) | All source |
|
||||
| .NET security analyzers | Built-in Roslyn | C# code |
|
||||
| Dependency vulnerabilities | `dotnet list --vulnerable` | NuGet packages |
|
||||
| Dockerfile best practices | Hadolint | Dockerfiles |
|
||||
|
||||
**Configuration:**
|
||||
|
||||
```yaml
|
||||
# sast-scan.yml inputs
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
scan_level:
|
||||
type: choice
|
||||
options:
|
||||
- quick # Fast scan, critical issues only
|
||||
- standard # Default, balanced coverage
|
||||
- comprehensive # Full scan, all rules
|
||||
fail_on_findings:
|
||||
type: boolean
|
||||
default: true # Block on findings
|
||||
```
|
||||
|
||||
**.NET Security Analyzer Rules:**
|
||||
|
||||
The workflow enforces these security-critical CA rules as errors:
|
||||
|
||||
| Category | Rules | Description |
|
||||
|----------|-------|-------------|
|
||||
| SQL Injection | CA2100 | Review SQL queries for vulnerabilities |
|
||||
| Cryptography | CA5350-5403 | Weak crypto, insecure algorithms |
|
||||
| Deserialization | CA2300-2362 | Unsafe deserialization |
|
||||
| XML Security | CA3001-3012 | XXE, XPath injection |
|
||||
| Web Security | CA3061, CA5358-5398 | XSS, CSRF, CORS |
|
||||
|
||||
---
|
||||
|
||||
### 2. Secrets Scanning (`secrets-scan.yml`)
|
||||
|
||||
**Purpose:** Detect hardcoded credentials, API keys, and secrets in code.
|
||||
|
||||
**Triggers:**
|
||||
- Pull requests
|
||||
- Push to main/develop
|
||||
- Manual dispatch
|
||||
|
||||
**Detection Patterns:**
|
||||
|
||||
| Secret Type | Example Pattern |
|
||||
|-------------|-----------------|
|
||||
| API Keys | `sk_live_[a-zA-Z0-9]+` |
|
||||
| AWS Keys | `AKIA[0-9A-Z]{16}` |
|
||||
| Private Keys | `-----BEGIN RSA PRIVATE KEY-----` |
|
||||
| Connection Strings | `Password=.*;User ID=.*` |
|
||||
| JWT Tokens | `eyJ[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+` |
|
||||
| GitHub Tokens | `gh[ps]_[A-Za-z0-9]{36}` |
|
||||
|
||||
**Tool Options (Placeholder):**
|
||||
|
||||
```yaml
|
||||
# Choose one by uncommenting in sast-scan.yml:
|
||||
|
||||
# Option 1: TruffleHog (recommended for open source)
|
||||
# - name: TruffleHog Scan
|
||||
# uses: trufflesecurity/trufflehog@main
|
||||
# with:
|
||||
# extra_args: --only-verified
|
||||
|
||||
# Option 2: Gitleaks
|
||||
# - name: Gitleaks Scan
|
||||
# uses: gitleaks/gitleaks-action@v2
|
||||
# env:
|
||||
# GITLEAKS_LICENSE: ${{ secrets.GITLEAKS_LICENSE }}
|
||||
|
||||
# Option 3: Semgrep
|
||||
# - name: Semgrep Secrets
|
||||
# uses: returntocorp/semgrep-action@v1
|
||||
# with:
|
||||
# config: p/secrets
|
||||
```
|
||||
|
||||
**Allowlist Configuration:**
|
||||
|
||||
Create `.gitleaksignore` or `.secretsignore` for false positives:
|
||||
|
||||
```
|
||||
# Ignore test fixtures
|
||||
src/__Tests/**/*
|
||||
docs/modules/**/samples/**/*
|
||||
|
||||
# Ignore specific files
|
||||
path/to/test-credentials.json
|
||||
|
||||
# Ignore by rule ID
|
||||
[allowlist]
|
||||
regexes = ["test_api_key_[a-z]+"]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3. Container Scanning (`container-scan.yml`)
|
||||
|
||||
**Purpose:** Scan container images for OS and application vulnerabilities.
|
||||
|
||||
**Triggers:**
|
||||
- Dockerfile changes
|
||||
- Daily schedule (4 AM UTC)
|
||||
- Manual dispatch
|
||||
|
||||
**Scan Targets:**
|
||||
|
||||
| Image | Built From | Scanned Components |
|
||||
|-------|------------|-------------------|
|
||||
| `stellaops/authority` | `src/Authority/Dockerfile` | OS packages, .NET runtime |
|
||||
| `stellaops/scanner` | `src/Scanner/Dockerfile` | OS packages, .NET runtime, analyzers |
|
||||
| `stellaops/concelier` | `src/Concelier/Dockerfile` | OS packages, .NET runtime |
|
||||
| (9 total images) | ... | ... |
|
||||
|
||||
**Vulnerability Severity Levels:**
|
||||
|
||||
| Severity | Action | Example |
|
||||
|----------|--------|---------|
|
||||
| CRITICAL | Block release | Remote code execution |
|
||||
| HIGH | Block release (configurable) | Privilege escalation |
|
||||
| MEDIUM | Warning | Information disclosure |
|
||||
| LOW | Log only | Minor issues |
|
||||
| UNKNOWN | Log only | Unclassified |
|
||||
|
||||
**Tool Options (Placeholder):**
|
||||
|
||||
```yaml
|
||||
# Choose one by uncommenting in container-scan.yml:
|
||||
|
||||
# Option 1: Trivy (recommended)
|
||||
# - name: Trivy Scan
|
||||
# uses: aquasecurity/trivy-action@master
|
||||
# with:
|
||||
# image-ref: ${{ steps.build.outputs.image }}
|
||||
# format: sarif
|
||||
# output: trivy-results.sarif
|
||||
# severity: CRITICAL,HIGH
|
||||
|
||||
# Option 2: Grype
|
||||
# - name: Grype Scan
|
||||
# uses: anchore/scan-action@v3
|
||||
# with:
|
||||
# image: ${{ steps.build.outputs.image }}
|
||||
# fail-build: true
|
||||
# severity-cutoff: high
|
||||
|
||||
# Option 3: Snyk Container
|
||||
# - name: Snyk Container
|
||||
# uses: snyk/actions/docker@master
|
||||
# env:
|
||||
# SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 4. Dependency Security Scanning (`dependency-security-scan.yml`)
|
||||
|
||||
**Purpose:** Audit NuGet and npm packages for known vulnerabilities.
|
||||
|
||||
**Triggers:**
|
||||
- Weekly Sunday 2 AM UTC
|
||||
- Pull requests (dependency file changes)
|
||||
- Manual dispatch
|
||||
|
||||
**Scanned Files:**
|
||||
|
||||
| Ecosystem | Files |
|
||||
|-----------|-------|
|
||||
| NuGet | `src/Directory.Packages.props`, `**/*.csproj` |
|
||||
| npm | `**/package.json`, `**/package-lock.json` |
|
||||
|
||||
**Vulnerability Sources:**
|
||||
|
||||
- GitHub Advisory Database
|
||||
- NVD (National Vulnerability Database)
|
||||
- OSV (Open Source Vulnerabilities)
|
||||
- Vendor security advisories
|
||||
|
||||
**Scan Process:**
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ DEPENDENCY SECURITY SCAN │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ┌──────────────┐ │
|
||||
│ │ scan-nuget │ dotnet list package --vulnerable │
|
||||
│ └──────┬───────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌──────────────┐ │
|
||||
│ │ scan-npm │ npm audit --json │
|
||||
│ └──────┬───────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌──────────────┐ │
|
||||
│ │ summary │ Aggregate results, generate report │
|
||||
│ └──────────────┘ │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Example Output:**
|
||||
|
||||
```
|
||||
## Dependency Vulnerability Audit
|
||||
|
||||
### NuGet Packages
|
||||
| Package | Installed | Vulnerable | Severity | Advisory |
|
||||
|---------|-----------|------------|----------|----------|
|
||||
| Newtonsoft.Json | 12.0.1 | < 13.0.1 | HIGH | GHSA-xxxx |
|
||||
|
||||
### npm Packages
|
||||
| Package | Installed | Vulnerable | Severity | Advisory |
|
||||
|---------|-----------|------------|----------|----------|
|
||||
| lodash | 4.17.15 | < 4.17.21 | CRITICAL | npm:lodash:1 |
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 5. License Compliance (`dependency-license-gate.yml`)
|
||||
|
||||
**Purpose:** Ensure all dependencies use approved licenses.
|
||||
|
||||
**Approved Licenses:**
|
||||
|
||||
| License | SPDX ID | Status |
|
||||
|---------|---------|--------|
|
||||
| MIT | MIT | Approved |
|
||||
| Apache 2.0 | Apache-2.0 | Approved |
|
||||
| BSD 2-Clause | BSD-2-Clause | Approved |
|
||||
| BSD 3-Clause | BSD-3-Clause | Approved |
|
||||
| ISC | ISC | Approved |
|
||||
| MPL 2.0 | MPL-2.0 | Review Required |
|
||||
| LGPL 2.1+ | LGPL-2.1-or-later | Review Required |
|
||||
| GPL 2.0+ | GPL-2.0-or-later | Blocked (copyleft) |
|
||||
| AGPL 3.0 | AGPL-3.0 | Blocked (copyleft) |
|
||||
|
||||
**Blocked on Violation:**
|
||||
- GPL-licensed runtime dependencies
|
||||
- Unknown/proprietary licenses without explicit approval
|
||||
|
||||
---
|
||||
|
||||
## Scan Results & Reporting
|
||||
|
||||
### GitHub Step Summary
|
||||
|
||||
All security scans generate GitHub Step Summary reports:
|
||||
|
||||
```markdown
|
||||
## SAST Scan Summary
|
||||
|
||||
| Check | Status |
|
||||
|-------|--------|
|
||||
| SAST Analysis | ✅ Pass |
|
||||
| .NET Security | ⚠️ 3 warnings |
|
||||
| Dependency Check | ✅ Pass |
|
||||
| Dockerfile Lint | ✅ Pass |
|
||||
|
||||
### .NET Security Warnings
|
||||
- CA5350: Weak cryptographic algorithm (src/Crypto/Legacy.cs:42)
|
||||
- CA2100: SQL injection risk (src/Data/Query.cs:78)
|
||||
```
|
||||
|
||||
### SARIF Integration
|
||||
|
||||
Scan results are uploaded in SARIF format for IDE integration:
|
||||
|
||||
```yaml
|
||||
- name: Upload SARIF
|
||||
uses: github/codeql-action/upload-sarif@v3
|
||||
with:
|
||||
sarif_file: scan-results.sarif
|
||||
```
|
||||
|
||||
### Artifact Retention
|
||||
|
||||
| Artifact | Retention |
|
||||
|----------|-----------|
|
||||
| SARIF files | 30 days |
|
||||
| Vulnerability reports | 90 days |
|
||||
| License audit logs | 1 year |
|
||||
|
||||
---
|
||||
|
||||
## Security Gates
|
||||
|
||||
### PR Merge Requirements
|
||||
|
||||
| Gate | Threshold | Block Merge? |
|
||||
|------|-----------|--------------|
|
||||
| SAST Critical | 0 | Yes |
|
||||
| SAST High | 0 | Configurable |
|
||||
| Secrets Found | 0 | Yes |
|
||||
| Vulnerable Dependencies (Critical) | 0 | Yes |
|
||||
| Vulnerable Dependencies (High) | 5 | Warning |
|
||||
| License Violations | 0 | Yes |
|
||||
|
||||
### Release Requirements
|
||||
|
||||
| Gate | Threshold | Block Release? |
|
||||
|------|-----------|----------------|
|
||||
| Container Scan (Critical) | 0 | Yes |
|
||||
| Container Scan (High) | 0 | Yes |
|
||||
| SBOM Generation | Success | Yes |
|
||||
| Signature Verification | Valid | Yes |
|
||||
|
||||
---
|
||||
|
||||
## Remediation Workflows
|
||||
|
||||
### Dependency Vulnerability Fix
|
||||
|
||||
1. **Renovate Auto-Fix:**
|
||||
```yaml
|
||||
# renovate.json
|
||||
{
|
||||
"vulnerabilityAlerts": {
|
||||
"enabled": true,
|
||||
"labels": ["security"],
|
||||
"automerge": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
2. **Manual Override:**
|
||||
```bash
|
||||
# Update specific package
|
||||
dotnet add package Newtonsoft.Json --version 13.0.3
|
||||
|
||||
# Audit and fix npm
|
||||
npm audit fix
|
||||
```
|
||||
|
||||
### False Positive Suppression
|
||||
|
||||
**.NET Analyzer Suppression:**
|
||||
|
||||
```csharp
|
||||
// Suppress specific instance
|
||||
#pragma warning disable CA2100 // Review SQL queries for vulnerability
|
||||
var query = $"SELECT * FROM {tableName}";
|
||||
#pragma warning restore CA2100
|
||||
|
||||
// Or in .editorconfig
|
||||
[*.cs]
|
||||
dotnet_diagnostic.CA2100.severity = none # NOT RECOMMENDED
|
||||
```
|
||||
|
||||
**Semgrep/SAST Suppression:**
|
||||
|
||||
```csharp
|
||||
// nosemgrep: sql-injection
|
||||
var query = $"SELECT * FROM {tableName}";
|
||||
```
|
||||
|
||||
**Container Scan Ignore:**
|
||||
|
||||
```yaml
|
||||
# .trivyignore
|
||||
CVE-2021-44228 # Log4j - not applicable (no Java)
|
||||
CVE-2022-12345 # Accepted risk with mitigation
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Configuration Files
|
||||
|
||||
### Location
|
||||
|
||||
| File | Purpose | Location |
|
||||
|------|---------|----------|
|
||||
| `.gitleaksignore` | Secrets scan allowlist | Repository root |
|
||||
| `.trivyignore` | Container scan ignore list | Repository root |
|
||||
| `.semgrepignore` | SAST ignore patterns | Repository root |
|
||||
| `renovate.json` | Dependency update config | Repository root |
|
||||
| `.editorconfig` | Analyzer severity | Repository root |
|
||||
|
||||
### Example `.trivyignore`
|
||||
|
||||
```
|
||||
# Ignore by CVE ID
|
||||
CVE-2021-44228
|
||||
|
||||
# Ignore by package
|
||||
pkg:npm/lodash@4.17.15
|
||||
|
||||
# Ignore with expiration
|
||||
CVE-2022-12345 exp:2025-06-01
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Scheduled Scan Summary
|
||||
|
||||
| Day | Time (UTC) | Workflow | Focus |
|
||||
|-----|------------|----------|-------|
|
||||
| Daily | 2:00 AM | `nightly-regression.yml` | Security tests |
|
||||
| Daily | 4:00 AM | `container-scan.yml` | Image vulnerabilities |
|
||||
| Sunday | 2:00 AM | `dependency-security-scan.yml` | Package audit |
|
||||
| Monday | 3:30 AM | `sast-scan.yml` | Deep code analysis |
|
||||
|
||||
---
|
||||
|
||||
## Monitoring & Alerts
|
||||
|
||||
### Notification Channels
|
||||
|
||||
Configure notifications for security findings:
|
||||
|
||||
```yaml
|
||||
# In workflow
|
||||
- name: Notify on Critical
|
||||
if: steps.scan.outputs.critical_count > 0
|
||||
run: |
|
||||
curl -X POST "${{ secrets.SLACK_WEBHOOK }}" \
|
||||
-d '{"text":"🚨 Critical security finding in '${{ github.repository }}'"}'
|
||||
```
|
||||
|
||||
### Dashboard Integration
|
||||
|
||||
Security scan results can be exported to:
|
||||
- Grafana dashboards (via OTLP metrics)
|
||||
- Security Information and Event Management (SIEM)
|
||||
- Vulnerability management platforms
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [README - CI/CD Overview](./README.md)
|
||||
- [Workflow Triggers](./workflow-triggers.md)
|
||||
- [Release Pipelines](./release-pipelines.md)
|
||||
- [Dependency Management](../operations/dependency-management.md)
|
||||
- [SBOM Guide](../sbom/guide.md)
|
||||
461
docs/technical/cicd/test-strategy.md
Normal file
461
docs/technical/cicd/test-strategy.md
Normal file
@@ -0,0 +1,461 @@
|
||||
# Test Strategy
|
||||
|
||||
> Complete guide to the StellaOps testing strategy and CI/CD integration.
|
||||
|
||||
---
|
||||
|
||||
## Test Category Overview
|
||||
|
||||
StellaOps uses a **tiered testing strategy** with 13 test categories:
|
||||
|
||||
### PR-Gating Tests (Required for Merge)
|
||||
|
||||
| Category | Purpose | Timeout | Parallelism |
|
||||
|----------|---------|---------|-------------|
|
||||
| **Unit** | Isolated component tests | 20 min | High |
|
||||
| **Architecture** | Dependency rule enforcement | 15 min | High |
|
||||
| **Contract** | API compatibility | 15 min | High |
|
||||
| **Integration** | Database/service integration | 45 min | Medium |
|
||||
| **Security** | Security-focused assertions | 25 min | High |
|
||||
| **Golden** | Corpus-based validation | 25 min | High |
|
||||
|
||||
### Extended Tests (Scheduled/On-Demand)
|
||||
|
||||
| Category | Purpose | Timeout | Trigger |
|
||||
|----------|---------|---------|---------|
|
||||
| **Performance** | Latency/throughput benchmarks | 45 min | Daily, Manual |
|
||||
| **Benchmark** | BenchmarkDotNet profiling | 60 min | Daily, Manual |
|
||||
| **AirGap** | Offline operation validation | 45 min | Manual |
|
||||
| **Chaos** | Resilience testing | 45 min | Manual |
|
||||
| **Determinism** | Reproducibility verification | 45 min | Manual |
|
||||
| **Resilience** | Failure recovery testing | 45 min | Manual |
|
||||
| **Observability** | Telemetry validation | 30 min | Manual |
|
||||
|
||||
---
|
||||
|
||||
## Test Discovery
|
||||
|
||||
### Automatic Discovery
|
||||
|
||||
The `test-matrix.yml` workflow automatically discovers all test projects:
|
||||
|
||||
```bash
|
||||
# Discovery pattern
|
||||
find src \( \
|
||||
-name "*.Tests.csproj" \
|
||||
-o -name "*UnitTests.csproj" \
|
||||
-o -name "*SmokeTests.csproj" \
|
||||
-o -name "*FixtureTests.csproj" \
|
||||
-o -name "*IntegrationTests.csproj" \
|
||||
\) -type f \
|
||||
! -path "*/node_modules/*" \
|
||||
! -path "*/bin/*" \
|
||||
! -path "*/obj/*" \
|
||||
! -name "StellaOps.TestKit.csproj" \
|
||||
! -name "*Testing.csproj"
|
||||
```
|
||||
|
||||
### Test Category Trait
|
||||
|
||||
Tests are categorized using xUnit traits:
|
||||
|
||||
```csharp
|
||||
[Trait("Category", "Unit")]
|
||||
public class MyUnitTests
|
||||
{
|
||||
[Fact]
|
||||
public void Should_Do_Something()
|
||||
{
|
||||
// ...
|
||||
}
|
||||
}
|
||||
|
||||
[Trait("Category", "Integration")]
|
||||
public class MyIntegrationTests
|
||||
{
|
||||
[Fact]
|
||||
public void Should_Connect_To_Database()
|
||||
{
|
||||
// ...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Running Specific Categories
|
||||
|
||||
```bash
|
||||
# Run Unit tests only
|
||||
dotnet test --filter "Category=Unit"
|
||||
|
||||
# Run multiple categories
|
||||
dotnet test --filter "Category=Unit|Category=Integration"
|
||||
|
||||
# Run excluding a category
|
||||
dotnet test --filter "Category!=Performance"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Test Infrastructure
|
||||
|
||||
### Shared Libraries
|
||||
|
||||
| Library | Purpose | Location |
|
||||
|---------|---------|----------|
|
||||
| `StellaOps.TestKit` | Common test utilities | `src/__Tests/__Libraries/` |
|
||||
| `StellaOps.Infrastructure.Postgres.Testing` | PostgreSQL fixtures | `src/__Tests/__Libraries/` |
|
||||
| `StellaOps.Concelier.Testing` | Concelier test fixtures | `src/Concelier/__Tests/` |
|
||||
|
||||
### Testcontainers
|
||||
|
||||
Integration tests use Testcontainers for isolated dependencies:
|
||||
|
||||
```csharp
|
||||
public class PostgresFixture : IAsyncLifetime
|
||||
{
|
||||
private readonly PostgreSqlContainer _container = new PostgreSqlBuilder()
|
||||
.WithImage("postgres:16")
|
||||
.WithDatabase("test_db")
|
||||
.Build();
|
||||
|
||||
public string ConnectionString => _container.GetConnectionString();
|
||||
|
||||
public Task InitializeAsync() => _container.StartAsync();
|
||||
public Task DisposeAsync() => _container.DisposeAsync().AsTask();
|
||||
}
|
||||
```
|
||||
|
||||
### Ground Truth Corpus
|
||||
|
||||
Golden tests use a corpus of known-good outputs:
|
||||
|
||||
```
|
||||
src/__Tests/__Datasets/
|
||||
├── scanner/
|
||||
│ ├── golden/
|
||||
│ │ ├── npm-package.expected.json
|
||||
│ │ ├── dotnet-project.expected.json
|
||||
│ │ └── container-image.expected.json
|
||||
│ └── fixtures/
|
||||
│ ├── npm-package/
|
||||
│ ├── dotnet-project/
|
||||
│ └── container-image/
|
||||
└── concelier/
|
||||
├── golden/
|
||||
└── fixtures/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## CI/CD Integration
|
||||
|
||||
### Test Matrix Workflow
|
||||
|
||||
```yaml
|
||||
# Simplified test-matrix.yml structure
|
||||
jobs:
|
||||
discover:
|
||||
# Find all test projects
|
||||
outputs:
|
||||
test-projects: ${{ steps.find.outputs.projects }}
|
||||
|
||||
pr-gating-tests:
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- category: Unit
|
||||
timeout: 20
|
||||
- category: Architecture
|
||||
timeout: 15
|
||||
- category: Contract
|
||||
timeout: 15
|
||||
- category: Security
|
||||
timeout: 25
|
||||
- category: Golden
|
||||
timeout: 25
|
||||
steps:
|
||||
- run: .gitea/scripts/test/run-test-category.sh "${{ matrix.category }}"
|
||||
|
||||
integration:
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:16
|
||||
steps:
|
||||
- run: .gitea/scripts/test/run-test-category.sh Integration
|
||||
|
||||
summary:
|
||||
needs: [discover, pr-gating-tests, integration]
|
||||
```
|
||||
|
||||
### Test Results
|
||||
|
||||
All tests produce TRX (Visual Studio Test Results) files:
|
||||
|
||||
```bash
|
||||
# Output structure
|
||||
TestResults/
|
||||
├── Unit/
|
||||
│ ├── src_Scanner___Tests_StellaOps.Scanner.Tests-unit.trx
|
||||
│ └── src_Authority___Tests_StellaOps.Authority.Tests-unit.trx
|
||||
├── Integration/
|
||||
│ └── ...
|
||||
└── Combined/
|
||||
└── test-results-combined.trx
|
||||
```
|
||||
|
||||
### Coverage Collection
|
||||
|
||||
```yaml
|
||||
# Collect coverage for Unit tests
|
||||
- run: |
|
||||
.gitea/scripts/test/run-test-category.sh Unit --collect-coverage
|
||||
```
|
||||
|
||||
Coverage reports are generated in Cobertura format and converted to HTML.
|
||||
|
||||
---
|
||||
|
||||
## Test Categories Deep Dive
|
||||
|
||||
### Unit Tests
|
||||
|
||||
**Purpose:** Test isolated components without external dependencies.
|
||||
|
||||
**Characteristics:**
|
||||
- No I/O (database, network, file system)
|
||||
- No async waits or delays
|
||||
- Fast execution (< 100ms per test)
|
||||
- High parallelism
|
||||
|
||||
**Example:**
|
||||
|
||||
```csharp
|
||||
[Trait("Category", "Unit")]
|
||||
public class VexPolicyBinderTests
|
||||
{
|
||||
[Fact]
|
||||
public void Bind_WithValidPolicy_ReturnsSuccess()
|
||||
{
|
||||
var binder = new VexPolicyBinder();
|
||||
var policy = new VexPolicy { /* ... */ };
|
||||
|
||||
var result = binder.Bind(policy);
|
||||
|
||||
Assert.True(result.IsSuccess);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Architecture Tests
|
||||
|
||||
**Purpose:** Enforce architectural rules and dependency constraints.
|
||||
|
||||
**Rules Enforced:**
|
||||
- Layer dependencies (UI → Application → Domain → Infrastructure)
|
||||
- Namespace conventions
|
||||
- Circular dependency prevention
|
||||
- Interface segregation
|
||||
|
||||
**Example:**
|
||||
|
||||
```csharp
|
||||
[Trait("Category", "Architecture")]
|
||||
public class DependencyTests
|
||||
{
|
||||
[Fact]
|
||||
public void Domain_Should_Not_Depend_On_Infrastructure()
|
||||
{
|
||||
var result = Types.InAssembly(typeof(DomainMarker).Assembly)
|
||||
.That().ResideInNamespace("StellaOps.Domain")
|
||||
.ShouldNot().HaveDependencyOn("StellaOps.Infrastructure")
|
||||
.GetResult();
|
||||
|
||||
Assert.True(result.IsSuccessful);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Contract Tests
|
||||
|
||||
**Purpose:** Validate API contracts are maintained.
|
||||
|
||||
**Checks:**
|
||||
- Request/response schemas
|
||||
- OpenAPI specification compliance
|
||||
- Backward compatibility
|
||||
|
||||
**Example:**
|
||||
|
||||
```csharp
|
||||
[Trait("Category", "Contract")]
|
||||
public class VulnerabilityApiContractTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task GetVulnerability_ReturnsExpectedSchema()
|
||||
{
|
||||
var response = await _client.GetAsync("/api/v1/vulnerabilities/CVE-2024-1234");
|
||||
|
||||
await Verify(response)
|
||||
.UseDirectory("Snapshots")
|
||||
.UseMethodName("GetVulnerability");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Integration Tests
|
||||
|
||||
**Purpose:** Test component integration with real dependencies.
|
||||
|
||||
**Dependencies:**
|
||||
- PostgreSQL (via Testcontainers)
|
||||
- Valkey/Redis (via Testcontainers)
|
||||
- File system
|
||||
|
||||
**Example:**
|
||||
|
||||
```csharp
|
||||
[Trait("Category", "Integration")]
|
||||
public class VulnerabilityRepositoryTests : IClassFixture<PostgresFixture>
|
||||
{
|
||||
private readonly PostgresFixture _fixture;
|
||||
|
||||
[Fact]
|
||||
public async Task Save_AndRetrieve_Vulnerability()
|
||||
{
|
||||
var repo = new VulnerabilityRepository(_fixture.ConnectionString);
|
||||
var vuln = new Vulnerability { Id = "CVE-2024-1234" };
|
||||
|
||||
await repo.SaveAsync(vuln);
|
||||
var retrieved = await repo.GetAsync("CVE-2024-1234");
|
||||
|
||||
Assert.Equal(vuln.Id, retrieved.Id);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Security Tests
|
||||
|
||||
**Purpose:** Validate security controls and assertions.
|
||||
|
||||
**Checks:**
|
||||
- Input validation
|
||||
- Authorization enforcement
|
||||
- Cryptographic operations
|
||||
- Secrets handling
|
||||
|
||||
**Example:**
|
||||
|
||||
```csharp
|
||||
[Trait("Category", "Security")]
|
||||
public class AuthorizationTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task Unauthorized_User_Cannot_Access_Admin_Endpoint()
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
client.DefaultRequestHeaders.Authorization = null;
|
||||
|
||||
var response = await client.GetAsync("/api/admin/settings");
|
||||
|
||||
Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Golden Tests
|
||||
|
||||
**Purpose:** Verify output matches known-good corpus.
|
||||
|
||||
**Example:**
|
||||
|
||||
```csharp
|
||||
[Trait("Category", "Golden")]
|
||||
public class ScannerGoldenTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData("npm-package")]
|
||||
[InlineData("dotnet-project")]
|
||||
public async Task Scan_MatchesGoldenOutput(string fixture)
|
||||
{
|
||||
var scanner = new ContainerScanner();
|
||||
var result = await scanner.ScanAsync($"fixtures/{fixture}");
|
||||
|
||||
await Verify(result)
|
||||
.UseDirectory("golden")
|
||||
.UseFileName(fixture);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Performance Testing
|
||||
|
||||
### BenchmarkDotNet
|
||||
|
||||
```csharp
|
||||
[Trait("Category", "Benchmark")]
|
||||
[MemoryDiagnoser]
|
||||
public class ScannerBenchmarks
|
||||
{
|
||||
[Benchmark]
|
||||
public async Task ScanSmallImage()
|
||||
{
|
||||
await _scanner.ScanAsync(_smallImage);
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public async Task ScanLargeImage()
|
||||
{
|
||||
await _scanner.ScanAsync(_largeImage);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Performance SLOs
|
||||
|
||||
| Metric | Target | Action on Breach |
|
||||
|--------|--------|------------------|
|
||||
| Unit test P95 | < 100ms | Warning |
|
||||
| Integration test P95 | < 5s | Warning |
|
||||
| Scan time P95 | < 5 min | Block |
|
||||
| Memory peak | < 2GB | Block |
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Tests Fail in CI but Pass Locally
|
||||
|
||||
1. **Check timezone** - CI uses `TZ=UTC`
|
||||
2. **Check parallelism** - CI runs tests in parallel
|
||||
3. **Check container availability** - Testcontainers requires Docker
|
||||
4. **Check file paths** - Case sensitivity on Linux
|
||||
|
||||
### Flaky Tests
|
||||
|
||||
1. **Add retry logic** for network operations
|
||||
2. **Use proper async/await** - no `Task.Run` for async operations
|
||||
3. **Isolate shared state** - use fresh fixtures per test
|
||||
4. **Increase timeouts** for integration tests
|
||||
|
||||
### Missing Test Category
|
||||
|
||||
Ensure your test class has the correct trait:
|
||||
|
||||
```csharp
|
||||
[Trait("Category", "Unit")] // Add this!
|
||||
public class MyTests
|
||||
{
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [README - CI/CD Overview](./README.md)
|
||||
- [Workflow Triggers](./workflow-triggers.md)
|
||||
- [CI Quality Gates](../testing/ci-quality-gates.md)
|
||||
- [Test Catalog](../testing/TEST_CATALOG.yml)
|
||||
719
docs/technical/cicd/workflow-triggers.md
Normal file
719
docs/technical/cicd/workflow-triggers.md
Normal file
@@ -0,0 +1,719 @@
|
||||
# Workflow Triggers & Dependencies
|
||||
|
||||
> Complete reference for CI/CD workflow triggering rules and dependency chains.
|
||||
|
||||
---
|
||||
|
||||
## Trigger Types Overview
|
||||
|
||||
### 1. Push Triggers
|
||||
|
||||
Workflows triggered by commits pushed to branches.
|
||||
|
||||
```yaml
|
||||
on:
|
||||
push:
|
||||
branches: [main, develop] # Branch filter
|
||||
paths: # Path filter (optional)
|
||||
- 'src/**'
|
||||
paths-ignore: # Exclude paths (optional)
|
||||
- 'docs/**'
|
||||
tags: # Tag filter (for releases)
|
||||
- 'v*'
|
||||
```
|
||||
|
||||
### 2. Pull Request Triggers
|
||||
|
||||
Workflows triggered by PR events.
|
||||
|
||||
```yaml
|
||||
on:
|
||||
pull_request:
|
||||
branches: [main, develop] # Target branch filter
|
||||
types: [opened, synchronize, reopened] # Event types
|
||||
paths:
|
||||
- 'src/**'
|
||||
```
|
||||
|
||||
### 3. Schedule Triggers
|
||||
|
||||
Cron-based scheduled execution.
|
||||
|
||||
```yaml
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 5 * * *' # Daily at 5 AM UTC
|
||||
- cron: '0 2 * * 0' # Weekly Sunday at 2 AM UTC
|
||||
```
|
||||
|
||||
### 4. Manual Triggers
|
||||
|
||||
On-demand workflow execution with inputs.
|
||||
|
||||
```yaml
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
environment:
|
||||
type: choice
|
||||
options: [staging, production]
|
||||
dry_run:
|
||||
type: boolean
|
||||
default: false
|
||||
```
|
||||
|
||||
### 5. Workflow Call (Reusable)
|
||||
|
||||
Called by other workflows.
|
||||
|
||||
```yaml
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
category:
|
||||
type: string
|
||||
required: true
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Complete Trigger Matrix
|
||||
|
||||
### PR-Gating Workflows (Always Run on PR)
|
||||
|
||||
| Workflow | Branches | Path Filters | Purpose |
|
||||
|----------|----------|--------------|---------|
|
||||
| `test-matrix.yml` | main | `!docs/**`, `!*.md` | Unit, Architecture, Contract, Integration, Security, Golden tests |
|
||||
| `build-test-deploy.yml` | main, develop | `src/**`, `docs/**`, `scripts/**` | Build verification |
|
||||
| `policy-lint.yml` | main | `docs/policy/**`, `src/Cli/**` | Policy file validation |
|
||||
| `sast-scan.yml` | main, develop | `src/**`, `*.cs`, `*.ts`, `Dockerfile*` | Static security analysis |
|
||||
| `docs.yml` | - | `docs/**`, `scripts/render_docs.py` | Documentation validation |
|
||||
| `integration-tests-gate.yml` | main, develop | `src/**`, `src/__Tests/**` | Extended integration |
|
||||
|
||||
### Main Branch Only Workflows
|
||||
|
||||
| Workflow | Trigger Condition | Purpose |
|
||||
|----------|-------------------|---------|
|
||||
| `build-test-deploy.yml` → deploy | `github.ref == 'refs/heads/main'` | Deploy to staging |
|
||||
| `integration-tests-gate.yml` → corpus-validation | `github.ref == 'refs/heads/main'` | Ground truth validation |
|
||||
| `coverage-report` | After integration tests on main | Full coverage analysis |
|
||||
|
||||
### Tag-Triggered Workflows
|
||||
|
||||
| Workflow | Tag Pattern | Example | Purpose |
|
||||
|----------|-------------|---------|---------|
|
||||
| `release-suite.yml` | `suite-*` | `suite-2026.04` | Ubuntu-style suite release |
|
||||
| `release.yml` | `v*` | `v2025.12.1`, `v2025.12.0-edge` | Version bundle release |
|
||||
| `module-publish.yml` | `module-*-v*` | `module-authority-v1.2.3` | Per-module publishing |
|
||||
|
||||
### Scheduled Workflows
|
||||
|
||||
| Workflow | Schedule (UTC) | Frequency | Purpose |
|
||||
|----------|----------------|-----------|---------|
|
||||
| `nightly-regression.yml` | `0 2 * * *` | Daily 2 AM | Full regression suite |
|
||||
| `dependency-security-scan.yml` | `0 2 * * 0` | Sunday 2 AM | Vulnerability audit |
|
||||
| `renovate.yml` | `0 3,15 * * *` | Daily 3 AM & 3 PM | Dependency updates |
|
||||
| `sast-scan.yml` | `30 3 * * 1` | Monday 3:30 AM | Weekly deep scan |
|
||||
| `migration-test.yml` | `30 4 * * *` | Daily 4:30 AM | Migration validation |
|
||||
| `build-test-deploy.yml` | `0 5 * * *` | Daily 5 AM | Extended build tests |
|
||||
| `test-matrix.yml` | `0 5 * * *` | Daily 5 AM | Extended test categories |
|
||||
|
||||
### Manual-Only Workflows
|
||||
|
||||
| Workflow | Inputs | Purpose |
|
||||
|----------|--------|---------|
|
||||
| `cli-build.yml` | rids, config, sign | Multi-platform CLI builds |
|
||||
| `scanner-determinism.yml` | - | Verify scanner reproducibility |
|
||||
| `cross-platform-determinism.yml` | - | Cross-OS build verification |
|
||||
| `rollback.yml` | environment, service, version | Emergency rollback |
|
||||
| `promote.yml` | from_env, to_env, version | Environment promotion |
|
||||
|
||||
---
|
||||
|
||||
## Dependency Chains
|
||||
|
||||
### Build → Test → Deploy Pipeline
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ build-test-deploy.yml │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ profile-validation ─────────────────────────────────┐ │
|
||||
│ │ │ │
|
||||
│ ▼ │ │
|
||||
│ build-test ─────────────────────────────────────────┤ │
|
||||
│ │ (CLI, Concelier, Authority, Scanner, etc.) │ │
|
||||
│ │ │ │
|
||||
│ ▼ │ │
|
||||
│ quality-gates ──────────────────────────────────────┤ │
|
||||
│ │ (Reachability, TTFS, Performance SLOs) │ │
|
||||
│ │ │ │
|
||||
│ ▼ │ │
|
||||
│ security-testing (PR label or schedule) ────────────┤ │
|
||||
│ │ │ │
|
||||
│ ▼ │ │
|
||||
│ sealed-mode-ci ─────────────────────────────────────┤ │
|
||||
│ │ │ │
|
||||
│ ▼ │ │
|
||||
│ docs ───────────────────────────────────────────────┤ │
|
||||
│ │ │ │
|
||||
│ ▼ │ │
|
||||
│ scanner-perf ───────────────────────────────────────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ deploy (main branch only OR workflow_dispatch) │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ summary │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Test Matrix Pipeline
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ test-matrix.yml │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ discover ─────────────────────────────────────────────────┐ │
|
||||
│ │ (Find all *.Tests.csproj files) │ │
|
||||
│ │ │ │
|
||||
│ ├───▶ pr-gating-tests (Matrix: 5 categories) │ │
|
||||
│ │ ├── Unit │ │
|
||||
│ │ ├── Architecture │ │
|
||||
│ │ ├── Contract │ │
|
||||
│ │ ├── Security │ │
|
||||
│ │ └── Golden │ │
|
||||
│ │ │ │
|
||||
│ ├───▶ integration (PostgreSQL service) │ │
|
||||
│ │ │ │
|
||||
│ └───▶ extended-tests (schedule or manual) │ │
|
||||
│ ├── Performance │ │
|
||||
│ ├── Benchmark │ │
|
||||
│ ├── AirGap │ │
|
||||
│ ├── Chaos │ │
|
||||
│ ├── Determinism │ │
|
||||
│ ├── Resilience │ │
|
||||
│ └── Observability │ │
|
||||
│ │ │ │
|
||||
│ ◀────────────────────────────────────────────┘ │ │
|
||||
│ │ │ │
|
||||
│ ▼ │ │
|
||||
│ summary ◀─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Suite Release Pipeline
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ release-suite.yml │
|
||||
│ (suite-* tag OR manual) │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ parse-tag (if push event) ────────────────────────────────┐ │
|
||||
│ │ │ │
|
||||
│ ▼ │ │
|
||||
│ validate ─────────────────────────────────────────────────┤ │
|
||||
│ │ │ │
|
||||
│ ▼ │ │
|
||||
│ test-gate (optional, skip with skip_tests=true) ──────────┤ │
|
||||
│ │ │ │
|
||||
│ ├───▶ build-modules (Matrix: 9 modules) │ │
|
||||
│ │ ├── Authority │ │
|
||||
│ │ ├── Scanner │ │
|
||||
│ │ ├── Concelier │ │
|
||||
│ │ ├── Excititor │ │
|
||||
│ │ ├── SbomService │ │
|
||||
│ │ ├── EvidenceLocker │ │
|
||||
│ │ ├── Policy │ │
|
||||
│ │ ├── Attestor │ │
|
||||
│ │ └── VexLens │ │
|
||||
│ │ │ │
|
||||
│ ├───▶ build-containers (Matrix: 9 images) │ │
|
||||
│ │ │ │
|
||||
│ ├───▶ build-cli (Matrix: 5 runtimes) │ │
|
||||
│ │ ├── linux-x64 │ │
|
||||
│ │ ├── linux-arm64 │ │
|
||||
│ │ ├── win-x64 │ │
|
||||
│ │ ├── osx-x64 │ │
|
||||
│ │ └── osx-arm64 │ │
|
||||
│ │ │ │
|
||||
│ └───▶ build-helm │ │
|
||||
│ │ │
|
||||
│ ◀────────────────────────────────────────────────────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ release-manifest ─────────────────────────────────────────┐ │
|
||||
│ │ │ │
|
||||
│ ├───▶ generate-changelog │ │
|
||||
│ ├───▶ generate-suite-docs │ │
|
||||
│ └───▶ generate-compose │ │
|
||||
│ │ │
|
||||
│ ◀────────────────────────────────────────────────────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ create-release ───────────────────────────────────────────┐ │
|
||||
│ │ │ │
|
||||
│ ▼ │ │
|
||||
│ commit-docs ──────────────────────────────────────────────┤ │
|
||||
│ │ │ │
|
||||
│ ▼ │ │
|
||||
│ summary ◀─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Conditional Execution Patterns
|
||||
|
||||
### Branch-Based Conditions
|
||||
|
||||
```yaml
|
||||
# Deploy only on main branch
|
||||
deploy:
|
||||
if: github.ref == 'refs/heads/main'
|
||||
|
||||
# Run on main or develop
|
||||
if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/develop'
|
||||
|
||||
# Skip on release branches
|
||||
if: "!startsWith(github.ref, 'refs/heads/release/')"
|
||||
```
|
||||
|
||||
### Event-Based Conditions
|
||||
|
||||
```yaml
|
||||
# Different behavior based on trigger
|
||||
steps:
|
||||
- name: Full scan (schedule)
|
||||
if: github.event_name == 'schedule'
|
||||
run: ./scan.sh --full
|
||||
|
||||
- name: Quick scan (PR)
|
||||
if: github.event_name == 'pull_request'
|
||||
run: ./scan.sh --quick
|
||||
```
|
||||
|
||||
### Input-Based Conditions
|
||||
|
||||
```yaml
|
||||
# Run extended tests if requested
|
||||
extended-tests:
|
||||
if: >-
|
||||
github.event_name == 'schedule' ||
|
||||
github.event.inputs.include_performance == 'true' ||
|
||||
github.event.inputs.include_benchmark == 'true'
|
||||
```
|
||||
|
||||
### Failure-Based Conditions
|
||||
|
||||
```yaml
|
||||
# Run cleanup on failure
|
||||
cleanup:
|
||||
if: failure()
|
||||
|
||||
# Run notification always
|
||||
notify:
|
||||
if: always()
|
||||
|
||||
# Run only on success
|
||||
deploy:
|
||||
if: success()
|
||||
```
|
||||
|
||||
### Complex Conditions
|
||||
|
||||
```yaml
|
||||
# Deploy gate: multiple conditions
|
||||
deploy:
|
||||
if: >-
|
||||
needs.build-test.result == 'success' &&
|
||||
needs.docs.result == 'success' &&
|
||||
needs.scanner-perf.result == 'success' &&
|
||||
((github.event_name == 'push' && github.ref == 'refs/heads/main') ||
|
||||
github.event_name == 'workflow_dispatch')
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Path Filters Reference
|
||||
|
||||
### Common Path Patterns
|
||||
|
||||
| Pattern | Matches | Example Files |
|
||||
|---------|---------|---------------|
|
||||
| `src/**` | All source code | `src/Scanner/Program.cs` |
|
||||
| `docs/**` | All documentation | `docs/api/openapi.yaml` |
|
||||
| `*.md` | Root markdown | `README.md`, `CHANGELOG.md` |
|
||||
| `**/*.csproj` | All project files | `src/Cli/StellaOps.Cli.csproj` |
|
||||
| `devops/**` | DevOps config | `devops/helm/values.yaml` |
|
||||
| `.gitea/workflows/**` | Workflow files | `.gitea/workflows/test-matrix.yml` |
|
||||
|
||||
### Path Filter Examples
|
||||
|
||||
```yaml
|
||||
# Source code changes only
|
||||
paths:
|
||||
- 'src/**'
|
||||
- '!src/**/*.md' # Exclude markdown in src
|
||||
|
||||
# Documentation only
|
||||
paths:
|
||||
- 'docs/**'
|
||||
- '*.md'
|
||||
- 'scripts/render_docs.py'
|
||||
|
||||
# Security-relevant files
|
||||
paths:
|
||||
- 'src/**/*.cs'
|
||||
- 'src/**/*.csproj'
|
||||
- '**/Dockerfile*'
|
||||
- '.gitea/workflows/sast-scan.yml'
|
||||
|
||||
# Dependency files
|
||||
paths:
|
||||
- 'src/Directory.Packages.props'
|
||||
- '**/package.json'
|
||||
- '**/package-lock.json'
|
||||
- '**/*.csproj'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Tag Patterns Reference
|
||||
|
||||
### Semantic Version Tags
|
||||
|
||||
```yaml
|
||||
# Standard releases
|
||||
tags:
|
||||
- 'v*' # v1.0.0, v2025.12.1, v2025.12.0-edge
|
||||
|
||||
# Channel-specific
|
||||
tags:
|
||||
- 'v*-edge' # v2025.12.0-edge
|
||||
- 'v*-stable' # v2025.12.0-stable
|
||||
- 'v*-lts' # v2025.12.0-lts
|
||||
```
|
||||
|
||||
### Suite Tags
|
||||
|
||||
```yaml
|
||||
tags:
|
||||
- 'suite-*' # suite-2026.04, suite-2026.10
|
||||
```
|
||||
|
||||
### Module Tags
|
||||
|
||||
```yaml
|
||||
tags:
|
||||
- 'module-*-v*' # module-authority-v1.2.3
|
||||
# module-scanner-v2.0.0
|
||||
# module-cli-v3.1.0
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Workflow Inputs Reference
|
||||
|
||||
### Common Input Types
|
||||
|
||||
```yaml
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
# String input
|
||||
version:
|
||||
description: 'Version to release'
|
||||
required: true
|
||||
type: string
|
||||
|
||||
# Choice input
|
||||
environment:
|
||||
description: 'Target environment'
|
||||
type: choice
|
||||
options:
|
||||
- staging
|
||||
- production
|
||||
default: staging
|
||||
|
||||
# Boolean input
|
||||
dry_run:
|
||||
description: 'Run without making changes'
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
# Multi-select (via string)
|
||||
rids:
|
||||
description: 'Runtime identifiers (comma-separated)'
|
||||
type: string
|
||||
default: 'linux-x64,linux-arm64,win-x64'
|
||||
```
|
||||
|
||||
### Accessing Inputs
|
||||
|
||||
```yaml
|
||||
steps:
|
||||
- name: Use input
|
||||
run: |
|
||||
echo "Version: ${{ github.event.inputs.version }}"
|
||||
echo "Environment: ${{ inputs.environment }}"
|
||||
|
||||
if [[ "${{ inputs.dry_run }}" == "true" ]]; then
|
||||
echo "Dry run mode"
|
||||
fi
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. Minimize PR Workflow Duration
|
||||
|
||||
```yaml
|
||||
# Use path filters to skip irrelevant runs
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- '*.md'
|
||||
- 'LICENSE'
|
||||
|
||||
# Use concurrency to cancel outdated runs
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
```
|
||||
|
||||
### 2. Fail Fast for Critical Issues
|
||||
|
||||
```yaml
|
||||
strategy:
|
||||
fail-fast: true # Stop all jobs if one fails
|
||||
matrix:
|
||||
category: [Unit, Integration, Security]
|
||||
```
|
||||
|
||||
### 3. Use Matrix for Parallel Execution
|
||||
|
||||
```yaml
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- category: Unit
|
||||
timeout: 20
|
||||
- category: Integration
|
||||
timeout: 45
|
||||
```
|
||||
|
||||
### 4. Preserve Artifacts
|
||||
|
||||
```yaml
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: test-results-${{ matrix.category }}
|
||||
path: ./TestResults
|
||||
retention-days: 14 # PR artifacts
|
||||
# retention-days: 90 # Release artifacts
|
||||
```
|
||||
|
||||
### 5. Use Conditional Steps
|
||||
|
||||
```yaml
|
||||
- name: Deploy (main only)
|
||||
if: github.ref == 'refs/heads/main'
|
||||
run: ./deploy.sh
|
||||
|
||||
- name: Notify on failure
|
||||
if: failure()
|
||||
run: ./notify-slack.sh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting Triggers
|
||||
|
||||
### Workflow Not Running
|
||||
|
||||
1. **Check branch protection rules** - Ensure workflow runs are allowed
|
||||
2. **Verify path filters** - File changes must match `paths` patterns
|
||||
3. **Check `if` conditions** - Job may be skipped by condition
|
||||
4. **Review concurrency settings** - May be cancelled by concurrent run
|
||||
|
||||
### Workflow Running Unexpectedly
|
||||
|
||||
1. **Check `paths-ignore`** - May need to exclude more paths
|
||||
2. **Review schedule** - Cron schedule may overlap with events
|
||||
3. **Check tag patterns** - Tag may match unexpected pattern
|
||||
|
||||
### Schedule Not Triggering
|
||||
|
||||
1. **Verify cron syntax** - Use [crontab.guru](https://crontab.guru/)
|
||||
2. **Check workflow file location** - Must be on default branch
|
||||
3. **Review repository activity** - Inactive repos may have schedules disabled
|
||||
|
||||
---
|
||||
|
||||
## Trigger Decision Tree
|
||||
|
||||
Use this decision tree to determine which workflows run for each event:
|
||||
|
||||
```
|
||||
On PUSH to branch:
|
||||
│
|
||||
├── Is branch main/develop?
|
||||
│ ├── YES → Run Category A (PR-Gating) + B (Main-Only) + affected C (Module)
|
||||
│ └── NO (feature branch) → Skip CI (rely on PR workflow)
|
||||
│
|
||||
On PULL REQUEST:
|
||||
│
|
||||
├── Check changed paths
|
||||
│ ├── docs/** only → Skip all (or run docs.yml only)
|
||||
│ ├── src/** changed → Run Category A + affected C modules
|
||||
│ └── *.csproj or *.props changed → Run Category A + B (full infrastructure)
|
||||
│
|
||||
On TAG push:
|
||||
│
|
||||
├── Match tag pattern
|
||||
│ ├── suite-* → release-suite.yml
|
||||
│ ├── module-*-v* → module-publish.yml
|
||||
│ ├── service-*-v* → service-release.yml
|
||||
│ ├── v*.*.* → containers-multiarch.yml + cli-build.yml
|
||||
│ └── Other → Ignore
|
||||
│
|
||||
On SCHEDULE:
|
||||
│
|
||||
└── Run Category E pipelines per cron schedule
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Smart Dependency Cascading
|
||||
|
||||
When shared libraries change, dependent module tests must also run:
|
||||
|
||||
### Dependency Graph
|
||||
|
||||
```
|
||||
SHARED LIBRARY TRIGGERS TESTS FOR
|
||||
─────────────────────────────────────────────────────────────────
|
||||
StellaOps.Cryptography* → ALL modules (security-critical)
|
||||
- Scanner, Attestor, Authority
|
||||
- EvidenceLocker, Signer
|
||||
- AirGap, Offline tests
|
||||
- Security test suite
|
||||
|
||||
StellaOps.Evidence* → Scanner, Attestor, EvidenceLocker
|
||||
StellaOps.Provenance → ExportCenter, SbomService
|
||||
|
||||
StellaOps.Infrastructure.* → ALL integration tests
|
||||
StellaOps.Postgres* (database-dependent modules)
|
||||
|
||||
StellaOps.Replay* → Scanner, Determinism tests
|
||||
StellaOps.Determinism Replay module tests
|
||||
|
||||
StellaOps.Verdict → Policy, RiskEngine, ReachGraph
|
||||
StellaOps.DeltaVerdict
|
||||
|
||||
StellaOps.Plugin → Authority, Scanner, Concelier
|
||||
(plugin-based modules)
|
||||
|
||||
Directory.Build.props → ALL modules (build config)
|
||||
Directory.Packages.props ALL tests
|
||||
nuget.config
|
||||
```
|
||||
|
||||
### Cascade Implementation
|
||||
|
||||
Each workflow includes paths from its dependencies:
|
||||
|
||||
```yaml
|
||||
# Example: scanner-ci.yml with cascading
|
||||
name: Scanner CI
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
# Direct module paths
|
||||
- 'src/Scanner/**'
|
||||
- 'src/BinaryIndex/**'
|
||||
# Shared library dependencies (cascading)
|
||||
- 'src/__Libraries/StellaOps.Evidence*/**'
|
||||
- 'src/__Libraries/StellaOps.Cryptography*/**'
|
||||
- 'src/__Libraries/StellaOps.Replay*/**'
|
||||
- 'src/__Libraries/StellaOps.Provenance/**'
|
||||
# Infrastructure (triggers full test)
|
||||
- 'Directory.Build.props'
|
||||
- 'Directory.Packages.props'
|
||||
```
|
||||
|
||||
### Cascade Matrix Quick Reference
|
||||
|
||||
| When This Changes | Run These Tests |
|
||||
|-------------------|-----------------|
|
||||
| `src/__Libraries/StellaOps.Cryptography*/**` | Scanner, Attestor, Authority, Evidence, Signer, AirGap, Security |
|
||||
| `src/__Libraries/StellaOps.Evidence*/**` | Scanner, Attestor, EvidenceLocker, Export |
|
||||
| `src/__Libraries/StellaOps.Infrastructure*/**` | ALL integration tests |
|
||||
| `src/__Libraries/StellaOps.Replay*/**` | Scanner, Determinism, Replay |
|
||||
| `src/__Libraries/StellaOps.Verdict/**` | Policy, RiskEngine, ReachGraph |
|
||||
| `src/__Libraries/StellaOps.Plugin/**` | Authority, Scanner, Concelier |
|
||||
| `Directory.Build.props` | ALL modules |
|
||||
|
||||
---
|
||||
|
||||
## Master Trigger Configuration
|
||||
|
||||
### Complete Workflow Trigger Table
|
||||
|
||||
| Workflow | Feature Branch | PR | Main Push | Tag | Schedule |
|
||||
|----------|:--------------:|:--:|:---------:|:---:|:--------:|
|
||||
| **Category A: PR-Gating** |||||
|
||||
| build-test-deploy.yml | ❌ | ✅ | ✅ | ❌ | ✅ Daily |
|
||||
| test-matrix.yml | ❌ | ✅ | ✅ | ❌ | ✅ Daily |
|
||||
| determinism-gate.yml | ❌ | ✅ | ✅ | ❌ | ❌ |
|
||||
| policy-lint.yml | ❌ | ✅* | ✅* | ❌ | ❌ |
|
||||
| sast-scan.yml | ❌ | ✅ | ✅ | ❌ | ✅ Weekly |
|
||||
| secrets-scan.yml | ❌ | ✅ | ✅ | ❌ | ❌ |
|
||||
| dependency-license-gate.yml | ❌ | ✅* | ❌ | ❌ | ❌ |
|
||||
| **Category B: Main-Only** |||||
|
||||
| container-scan.yml | ❌ | ❌ | ✅* | ❌ | ✅ Daily |
|
||||
| integration-tests-gate.yml | ❌ | ❌ | ✅ | ❌ | ❌ |
|
||||
| api-governance.yml | ❌ | ✅* | ✅* | ❌ | ❌ |
|
||||
| aoc-guard.yml | ❌ | ✅* | ✅* | ❌ | ❌ |
|
||||
| provenance-check.yml | ❌ | ❌ | ✅ | ❌ | ❌ |
|
||||
| **Category C: Module-Specific** |||||
|
||||
| scanner-*.yml | ❌ | ✅* | ✅* | ❌ | ❌ |
|
||||
| concelier-*.yml | ❌ | ✅* | ✅* | ❌ | ❌ |
|
||||
| authority-*.yml | ❌ | ✅* | ✅* | ❌ | ❌ |
|
||||
| findings-ledger-ci.yml | ❌ | ✅* | ✅* | ❌ | ❌ |
|
||||
| evidence-locker.yml | ❌ | ❌ | ❌ | ❌ | ❌ (manual) |
|
||||
| [all module-*.yml] | ❌ | ✅* | ✅* | ❌ | ❌ |
|
||||
| **Category D: Release** |||||
|
||||
| release-suite.yml | ❌ | ❌ | ❌ | ✅ suite-* | ❌ |
|
||||
| module-publish.yml | ❌ | ❌ | ❌ | ✅ module-*-v* | ❌ |
|
||||
| service-release.yml | ❌ | ❌ | ❌ | ✅ service-*-v* | ❌ |
|
||||
| release.yml | ❌ | ❌ | ❌ | ✅ v* | ❌ |
|
||||
| cli-build.yml | ❌ | ❌ | ❌ | ❌ | ❌ (manual) |
|
||||
| containers-multiarch.yml | ❌ | ❌ | ❌ | ❌ | ❌ (manual) |
|
||||
| rollback.yml | ❌ | ❌ | ❌ | ❌ | ❌ (manual) |
|
||||
| promote.yml | ❌ | ❌ | ❌ | ❌ | ❌ (manual) |
|
||||
| **Category E: Scheduled** |||||
|
||||
| nightly-regression.yml | ❌ | ❌ | ❌ | ❌ | ✅ 2AM |
|
||||
| dependency-security-scan.yml | ❌ | ✅* | ❌ | ❌ | ✅ Sun 2AM |
|
||||
| container-scan.yml | ❌ | ❌ | ✅* | ❌ | ✅ 4AM |
|
||||
| renovate.yml | ❌ | ❌ | ❌ | ❌ | ✅ 3AM/3PM |
|
||||
| migration-test.yml | ❌ | ❌ | ❌ | ❌ | ✅ 4:30AM |
|
||||
|
||||
*Legend: ✅* = with path filter, ✅ = always, ❌ = never*
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [README - CI/CD Overview](./README.md)
|
||||
- [Release Pipelines](./release-pipelines.md)
|
||||
- [Test Strategy](./test-strategy.md)
|
||||
- [Path Filters Reference](./path-filters.md)
|
||||
- [Troubleshooting](../../.gitea/docs/troubleshooting.md)
|
||||
Reference in New Issue
Block a user