Files
git.stella-ops.org/docs/cicd/workflow-triggers.md

720 lines
27 KiB
Markdown

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