audit work, fixed StellaOps.sln warnings/errors, fixed tests, sprints work, new advisories

This commit is contained in:
master
2026-01-07 18:49:59 +02:00
parent 04ec098046
commit 608a7f85c0
866 changed files with 56323 additions and 6231 deletions

View 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)

View 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.

View 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
View File

@@ -0,0 +1,353 @@
# StellaOps CI Recipes  (20250804)
## 0·Key variables (export these once)
| Variable | Meaning | Typical value |
| ------------- | --------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------- |
| `STELLA_URL` | Host that: ① stores the **CLI** & **SBOMbuilder** 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_shaabc12320250804T153050Z.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 isnt available)
*(keep this block if your pipeline already has an imagebuild step that you cant 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" \ # remotedaemon 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, cutandpaste snippets.
**Feel free to deleteOption 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 asis) ----------
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 # Circles “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 asis) ---
#- 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 asis) ---
#- 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 repos `tmp/docenv`
> interpreter) ship without `pip`/`ensurepip`. In that case download the purePython
> sdists (e.g. `Markdown-3.x.tar.gz`, `pygments-2.x.tar.gz`) and extract their
> packages directly into the virtualenvs `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 doesnt 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 cheatsheet
| 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 wasnt 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) |
| Nonzero scan exit | Blocking vuln/licence | Open project in Ops UI → triage or waive |
---
### Change log
* **20251018** Documented Docs CI toolchain (Ajv validation, static preview) and offline checklist.
* **20250804** Variable cleanup, removed Dockersocket & cache mounts, added Jenkins / CircleCI / Gitea examples, clarified Option B comment.

View 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 StellaOps 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** | StellaOps 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.

View 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

View 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)

View 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)

View 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)

View 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)

View 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)

View 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)