# CI/CD Pipeline Guide ## Overview SF uses a three-stage promotion pipeline that automatically moves merged PRs through **Dev → Test → Prod** environments using npm dist-tags. ``` PR merged to main │ ▼ ┌─────────┐ ci.yml passes (build, test, typecheck) │ DEV │ → publishes sf-run@-dev. with @dev tag └────┬────┘ ▼ (automatic if green) ┌─────────┐ CLI smoke tests + LLM fixture replay │ TEST │ → promotes to @next tag └────┬────┘ → pushes Docker image as :next ▼ (manual approval required) ┌─────────┐ optional real-LLM integration tests │ PROD │ → promotes to @latest tag └─────────┘ → creates GitHub Release ``` ## For Contributors: Testing Your PR Before It Ships ### Install the Dev Build Every merged PR is immediately installable: ```bash # Latest dev build (bleeding edge, every merged PR) npx sf-run@dev # Test candidate (passed smoke + fixture tests) npx sf-run@next # Stable production release npx sf-run@latest # or just: npx sf-run ``` ### Using Docker ```bash # Test candidate docker run --rm -v $(pwd):/workspace ghcr.io/singularity-forge/sf-run:next --version # Stable docker run --rm -v $(pwd):/workspace ghcr.io/singularity-forge/sf-run:latest --version ``` ### Checking if a Fix Landed 1. Find the PR's merge commit SHA (first 7 chars) 2. Check if it's in `@dev`: `npm view sf-run@dev version` - If the version ends in `-dev.`, your PR is in dev 3. Check if it promoted to `@next`: `npm view sf-run@next version` 4. Check if it's in production: `npm view sf-run@latest version` ## For Maintainers ### Pipeline Workflows | Workflow | File | Trigger | Purpose | |----------|------|---------|---------| | CI | `ci.yml` | PR + push to main | Build, test, typecheck — **gate for all promotions** | | Release Pipeline | `pipeline.yml` | After CI succeeds on main | Three-stage promotion | | Native Binaries | `build-native.yml` | `v*` tags | Cross-compile platform binaries | | Dev Cleanup | `cleanup-dev-versions.yml` | Weekly (Monday 06:00 UTC) | Unpublish `-dev.` versions older than 30 days | | AI Triage | `triage.yml` | New issues + PRs | Automated classification via Claude Haiku (v2.36) | **CI optimization (v2.38):** GitHub Actions minutes were reduced ~60-70% (~10k → ~3-4k/month) through workflow consolidation and caching improvements. **Pipeline optimization (v2.41):** - **Shallow clones** — CI lint and build jobs use `fetch-depth: 1` or `fetch-depth: 2` instead of full history, saving ~30-60s per job - **npm cache in pipeline** — dev-publish, test-verify, and prod-release now use `cache: 'npm'` on setup-node, saving ~1-2 min per job on repeat runs - **Exponential backoff** — npm registry propagation waits in `build-native.yml` replaced hardcoded `sleep 30` + fixed 15s retries with exponential backoff (5s → 10s → 20s → 30s cap), typically finishing in <15s when the registry is fast - **Security hardening** — pipeline.yml moved `${{ }}` expressions from `run:` blocks to `env:` variables to prevent command injection vectors ### Docs-Only PR Detection (v2.41) CI automatically detects when a PR contains only documentation changes (`.md` files and `docs/` content). When docs-only: - **Skipped:** `build`, `windows-portability` (no code to compile or test) - **Still runs:** `lint` (secret scanning, `.sf/` check), `docs-check` (prompt injection scan) This saves CI minutes on documentation PRs while still enforcing security checks. ### Prompt Injection Scan (v2.41) The `docs-check` job runs `scripts/docs-prompt-injection-scan.sh` on every PR that touches markdown files. It scans documentation prose (excluding fenced code blocks) for patterns that could manipulate LLM behavior when docs are ingested as context: - **System prompt markers** — ``, `<|im_start|>system`, `[SYSTEM]:` - **Role/instruction overrides** — `ignore previous instructions`, `you are now`, `new instructions:` - **Hidden HTML directives** — `