- Add speckit workflow infrastructure (.claude, .specify) - Create NixOS configuration skeleton (flake.nix, configuration.nix, hosts/ops-jrz1.nix) - Add sanitization scripts with 22 rules for personal info removal - Add validation scripts with gitleaks integration - Configure git hooks (pre-commit, pre-push) for security validation - Add project documentation (README, LICENSE) - Add comprehensive .gitignore for Nix, secrets, staging Phase 1 and Phase 2 complete. Foundation ready for module extraction from ops-base.
420 lines
12 KiB
YAML
420 lines
12 KiB
YAML
# CI/CD Validation Contract
|
|
# Defines automated checks that must pass before merging changes
|
|
|
|
version: "1.0"
|
|
description: "GitHub Actions CI validation requirements for nixos-matrix-platform-template"
|
|
|
|
# CI workflow configuration
|
|
workflow:
|
|
name: "CI"
|
|
file: ".github/workflows/ci.yml"
|
|
triggers:
|
|
- push
|
|
- pull_request
|
|
concurrency:
|
|
group: "${{ github.workflow }}-${{ github.ref }}"
|
|
cancel-in-progress: true
|
|
|
|
# Jobs and their contracts
|
|
jobs:
|
|
# Job 1: Nix validation and builds
|
|
validate:
|
|
name: "Nix Validation"
|
|
runs-on: "ubuntu-latest"
|
|
timeout-minutes: 10
|
|
failure_action: block-merge
|
|
|
|
steps:
|
|
- step: "checkout"
|
|
uses: "actions/checkout@v4"
|
|
contract:
|
|
must_succeed: true
|
|
failure_blocks_merge: true
|
|
|
|
- step: "install-nix"
|
|
uses: "cachix/install-nix-action@v25"
|
|
with:
|
|
nix_path: "nixpkgs=channel:nixos-24.05"
|
|
contract:
|
|
must_succeed: true
|
|
failure_blocks_merge: true
|
|
max_duration_seconds: 120
|
|
|
|
- step: "nix-flake-check"
|
|
name: "Run nix flake check"
|
|
command: "nix flake check --all-systems"
|
|
contract:
|
|
exit_code: 0
|
|
must_succeed: true
|
|
failure_blocks_merge: true
|
|
max_duration_seconds: 120
|
|
success_criteria:
|
|
- "All flake outputs validate successfully"
|
|
- "No syntax errors in Nix files"
|
|
- "All module options type-check correctly"
|
|
|
|
- step: "build-example-vps"
|
|
name: "Build example VPS configuration"
|
|
command: "nix build .#nixosConfigurations.example-vps.config.system.build.toplevel"
|
|
contract:
|
|
exit_code: 0
|
|
must_succeed: true
|
|
failure_blocks_merge: true
|
|
max_duration_seconds: 180
|
|
success_criteria:
|
|
- "example-vps.nix builds without errors"
|
|
- "All imported modules resolve correctly"
|
|
- "result symlink created"
|
|
|
|
- step: "build-example-dev"
|
|
name: "Build example dev configuration"
|
|
command: "nix build .#nixosConfigurations.example-dev.config.system.build.toplevel"
|
|
contract:
|
|
exit_code: 0
|
|
must_succeed: true
|
|
failure_blocks_merge: true
|
|
max_duration_seconds: 180
|
|
success_criteria:
|
|
- "example-dev.nix builds without errors"
|
|
- "All imported modules resolve correctly"
|
|
- "result symlink created"
|
|
|
|
# Job 2: Security scanning
|
|
security:
|
|
name: "Security Scanning"
|
|
runs-on: "ubuntu-latest"
|
|
timeout-minutes: 5
|
|
failure_action: block-merge
|
|
|
|
steps:
|
|
- step: "checkout"
|
|
uses: "actions/checkout@v4"
|
|
with:
|
|
fetch-depth: 0 # Full history for gitleaks
|
|
contract:
|
|
must_succeed: true
|
|
failure_blocks_merge: true
|
|
|
|
- step: "gitleaks-scan"
|
|
name: "Run gitleaks secret scanner"
|
|
uses: "gitleaks/gitleaks-action@v2"
|
|
env:
|
|
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
|
|
contract:
|
|
exit_code: 0
|
|
must_succeed: true
|
|
failure_blocks_merge: true
|
|
max_duration_seconds: 60
|
|
success_criteria:
|
|
- "Zero secrets detected"
|
|
- "No Matrix tokens (syt_)"
|
|
- "No Slack tokens (xox*)"
|
|
- "No age keys (AGE-SECRET-KEY-*)"
|
|
- "No personal emails or domains"
|
|
failure_message: |
|
|
Secret detected in commit! This is a CRITICAL security issue.
|
|
|
|
DO NOT MERGE until secrets are removed.
|
|
|
|
Steps to fix:
|
|
1. Identify the secret in the gitleaks report above
|
|
2. Remove or replace with placeholder (e.g., REPLACE_WITH_TOKEN)
|
|
3. If secret is in git history, consider force-push (if safe)
|
|
4. Re-run CI to verify fix
|
|
|
|
# Job 3: Documentation validation
|
|
docs:
|
|
name: "Documentation Validation"
|
|
runs-on: "ubuntu-latest"
|
|
timeout-minutes: 5
|
|
failure_action: warn # Non-blocking for docs-only changes
|
|
|
|
steps:
|
|
- step: "checkout"
|
|
uses: "actions/checkout@v4"
|
|
contract:
|
|
must_succeed: true
|
|
|
|
- step: "markdown-lint"
|
|
name: "Lint markdown files"
|
|
uses: "DavidAnson/markdownlint-cli2-action@v14"
|
|
with:
|
|
globs: "**/*.md"
|
|
contract:
|
|
exit_code: 0
|
|
must_succeed: false # Warnings only
|
|
max_duration_seconds: 30
|
|
success_criteria:
|
|
- "Markdown files follow style guide"
|
|
- "No broken relative links"
|
|
- "Headers properly formatted"
|
|
|
|
- step: "check-links"
|
|
name: "Check for broken links"
|
|
uses: "gaurav-nelson/github-action-markdown-link-check@v1"
|
|
with:
|
|
use-quiet-mode: "yes"
|
|
config-file: ".github/markdown-link-check.json"
|
|
contract:
|
|
exit_code: 0
|
|
must_succeed: false # Warnings only
|
|
max_duration_seconds: 60
|
|
success_criteria:
|
|
- "All internal links resolve"
|
|
- "External links return 200 OK"
|
|
|
|
# Branch protection rules (configured via GitHub settings)
|
|
branch_protection:
|
|
branches:
|
|
- name: "main"
|
|
protections:
|
|
require_pull_request: true
|
|
require_approvals: 0 # v1.0 single maintainer
|
|
require_status_checks: true
|
|
required_checks:
|
|
- "Nix Validation"
|
|
- "Security Scanning"
|
|
dismiss_stale_reviews: false
|
|
require_code_owner_reviews: false
|
|
restrict_pushes: false # Allow maintainer to push directly if needed
|
|
allow_force_pushes: false
|
|
allow_deletions: false
|
|
|
|
# Status check requirements
|
|
status_checks:
|
|
strict: true # Require branches to be up-to-date before merging
|
|
contexts:
|
|
- "validate" # Job: Nix Validation
|
|
- "security" # Job: Security Scanning
|
|
|
|
# Validation matrix for different scenarios
|
|
validation_scenarios:
|
|
# Scenario 1: New module added
|
|
new_module:
|
|
required_checks:
|
|
- "nix flake check passes"
|
|
- "Module builds successfully"
|
|
- "gitleaks finds no secrets"
|
|
- "Module imported by at least one example configuration"
|
|
- "Module documented in README or relevant doc"
|
|
additional_manual_review:
|
|
- "Module follows existing patterns"
|
|
- "Options are well-documented"
|
|
- "Security hardening applied (if applicable)"
|
|
- "No personal configuration remains"
|
|
|
|
# Scenario 2: Documentation change
|
|
docs_only:
|
|
required_checks:
|
|
- "markdown-lint passes (or warnings explained)"
|
|
- "link-check passes (or broken links justified)"
|
|
- "gitleaks still passes (no secrets in examples)"
|
|
additional_manual_review:
|
|
- "Technical accuracy verified"
|
|
- "No personal infrastructure references"
|
|
- "Examples use generic domains/IPs"
|
|
|
|
# Scenario 3: Example configuration change
|
|
config_change:
|
|
required_checks:
|
|
- "nix flake check passes"
|
|
- "Modified configuration builds successfully"
|
|
- "gitleaks finds no secrets"
|
|
- "No personal domains/IPs introduced"
|
|
additional_manual_review:
|
|
- "Configuration still demonstrates intended use case"
|
|
- "Comments explain key options"
|
|
- "Secrets properly templated"
|
|
|
|
# Scenario 4: CI/CD workflow change
|
|
ci_change:
|
|
required_checks:
|
|
- "Workflow syntax valid (GitHub validates)"
|
|
- "Test run completes successfully"
|
|
- "No secrets exposed in workflow logs"
|
|
additional_manual_review:
|
|
- "Change doesn't weaken security checks"
|
|
- "Timeout values reasonable"
|
|
- "Failure actions appropriate (block vs warn)"
|
|
|
|
# Failure handling
|
|
failure_policies:
|
|
nix_build_failure:
|
|
severity: critical
|
|
action: block-merge
|
|
notification: "PR author + maintainers"
|
|
auto_comment: |
|
|
## Build Failure
|
|
|
|
The Nix build failed for this PR. This prevents merging.
|
|
|
|
**Common causes:**
|
|
- Syntax error in .nix file
|
|
- Missing import or dependency
|
|
- Type error in module options
|
|
- Invalid configuration value
|
|
|
|
**To debug:**
|
|
1. Run `nix flake check` locally
|
|
2. Run `nix build .#nixosConfigurations.<config-name>` locally
|
|
3. Check the error message for file and line number
|
|
4. Fix the issue and push updated commit
|
|
|
|
CI will automatically re-run on push.
|
|
|
|
secret_detected:
|
|
severity: critical
|
|
action: block-merge
|
|
notification: "PR author + maintainers + security team"
|
|
auto_comment: |
|
|
## ⚠️ SECRET DETECTED ⚠️
|
|
|
|
gitleaks has detected a potential secret in this PR.
|
|
|
|
**CRITICAL: DO NOT MERGE until resolved.**
|
|
|
|
**Steps to fix:**
|
|
1. Review the gitleaks report in the CI logs
|
|
2. Identify the secret (token, password, key, etc.)
|
|
3. Replace with placeholder or remove entirely
|
|
4. If secret is in git history:
|
|
- Consider force-push to remove (if safe)
|
|
- Or add to .gitignore and create new commit
|
|
5. Ensure secret is listed in secrets.yaml.example with generation instructions
|
|
6. Re-run CI to verify fix
|
|
|
|
**If this is a false positive:**
|
|
- Add pattern to .gitleaksignore (with justification in comment)
|
|
- Document why this is safe in PR description
|
|
|
|
docs_link_failure:
|
|
severity: warning
|
|
action: warn
|
|
notification: "PR author"
|
|
auto_comment: |
|
|
## Documentation Link Check Warning
|
|
|
|
Some links in documentation may be broken.
|
|
|
|
This is a **warning** - the PR can still be merged if links will be fixed soon.
|
|
|
|
**Common causes:**
|
|
- Link to external site that's temporarily down
|
|
- Link to doc that hasn't been created yet
|
|
- Typo in relative path
|
|
|
|
**To fix:**
|
|
1. Check the link-check report in CI logs
|
|
2. Fix broken links or remove them
|
|
3. For external links, verify they're stable/permanent
|
|
|
|
# Performance budgets
|
|
performance:
|
|
ci_total_time:
|
|
target: "5 minutes"
|
|
warning: "8 minutes"
|
|
critical: "10 minutes"
|
|
|
|
nix_flake_check:
|
|
target: "1 minute"
|
|
warning: "2 minutes"
|
|
critical: "3 minutes"
|
|
|
|
nix_build_per_config:
|
|
target: "2 minutes"
|
|
warning: "3 minutes"
|
|
critical: "5 minutes"
|
|
|
|
gitleaks_scan:
|
|
target: "20 seconds"
|
|
warning: "40 seconds"
|
|
critical: "60 seconds"
|
|
|
|
# Notification channels
|
|
notifications:
|
|
on_failure:
|
|
- github-pr-comment
|
|
- github-pr-status
|
|
|
|
on_success:
|
|
- github-pr-status
|
|
|
|
on_critical_failure:
|
|
- github-pr-comment
|
|
- github-pr-status
|
|
- email # If configured
|
|
|
|
# Metrics to track (post-deployment)
|
|
metrics:
|
|
ci_success_rate:
|
|
target: "> 95%"
|
|
measurement: "successful CI runs / total CI runs"
|
|
|
|
false_positive_rate:
|
|
target: "< 5%"
|
|
measurement: "false secret detections / total gitleaks runs"
|
|
|
|
average_ci_duration:
|
|
target: "< 5 minutes"
|
|
measurement: "mean duration of all CI runs"
|
|
|
|
time_to_fix_failures:
|
|
target: "< 1 hour"
|
|
measurement: "time from failure to green CI"
|
|
|
|
# Integration with GitHub features
|
|
github_integrations:
|
|
status_checks:
|
|
enabled: true
|
|
required_for_merge: ["validate", "security"]
|
|
|
|
auto_merge:
|
|
enabled: false # Manual merge for v1.0
|
|
|
|
discussions:
|
|
enabled: true
|
|
categories: ["Q&A", "Ideas", "Show and Tell"]
|
|
|
|
issues:
|
|
templates:
|
|
- bug_report.yml
|
|
- feature_request.yml
|
|
|
|
code_owners:
|
|
file: ".github/CODEOWNERS"
|
|
content: |
|
|
# Code ownership for nixos-matrix-platform-template
|
|
* @maintainer-username
|
|
|
|
# Security-critical files require extra review
|
|
.github/workflows/ @maintainer-username
|
|
modules/matrix-secrets/ @maintainer-username
|
|
*.sops.yaml @maintainer-username
|
|
|
|
# Pre-commit hooks (optional for contributors)
|
|
pre_commit:
|
|
config_file: ".pre-commit-config.yaml"
|
|
hooks:
|
|
- id: "gitleaks"
|
|
name: "gitleaks"
|
|
entry: "gitleaks protect --staged"
|
|
language: "system"
|
|
pass_filenames: false
|
|
|
|
- id: "nix-flake-check"
|
|
name: "nix flake check"
|
|
entry: "nix flake check"
|
|
language: "system"
|
|
pass_filenames: false
|
|
stages: [commit]
|
|
|
|
# Success criteria for CI system itself
|
|
ci_success_criteria:
|
|
- All jobs complete within performance budgets
|
|
- Zero false negatives (secrets not detected)
|
|
- < 5% false positives (valid code flagged as secret)
|
|
- Status checks correctly block/warn as configured
|
|
- Auto-comments provide helpful guidance
|
|
- Notifications reach appropriate parties
|
|
- Metrics tracked and visible in repository insights
|