# CI/CD & Release Automation Design

**Date:** 2026-06-19
**Status:** Draft
**Scope:** GitHub Actions CI pipeline + cargo-dist release automation

## Overview

Add two GitHub Actions workflows to Quartermaster: a CI pipeline that validates code quality on every PR and push to main, and a release workflow (via cargo-dist) that builds optimized Linux x86_64 binaries, publishes GitHub Releases with artifacts, and publishes to crates.io.

## CI Workflow (`.github/workflows/ci.yml`)

### Triggers

- `push` to `main`
- `pull_request` targeting `main`

### Jobs

All four jobs run **in parallel** on `ubuntu-latest` with Rust stable toolchain.

Each job uses `Swatinem/rust-cache` for dependency caching, keyed per job name to avoid cache invalidation across jobs.

#### 1. `fmt`

```yaml
- uses: dtolnay/rust-toolchain@stable
  with:
    components: rustfmt
- run: cargo fmt --check
```

Fastest check — catches formatting drift in seconds.

#### 2. `clippy`

```yaml
- uses: dtolnay/rust-toolchain@stable
  with:
    components: clippy
- run: cargo clippy -- -D warnings
```

Treats all Clippy warnings as errors, matching the existing `just clippy` target.

#### 3. `test`

```yaml
- uses: dtolnay/rust-toolchain@stable
- run: cargo test
```

Runs the full test suite. No `QUMA_SPT_DIR` is set in CI — tests that require a real SPT directory should be gated behind `#[ignore]` or a feature flag (existing tests already handle this).

#### 4. `audit`

```yaml
- uses: rustsec/audit-check@v2
  with:
    token: ${{ secrets.GITHUB_TOKEN }}
```

Uses the official RustSec audit action. **Blocks the PR** if known advisories are found. Accepted risks can be ignored via an `audit.toml` file at the repo root:

```toml
[advisories]
ignore = [
    # "RUSTSEC-YYYY-NNNN",  # reason for accepting
]
```

## Release Workflow (cargo-dist)

### Setup

Run `dist init` to generate the release workflow. The generated workflow lives at `.github/workflows/release.yml` and is managed by cargo-dist — re-run `dist init` to update it when upgrading cargo-dist versions.

### Cargo.toml Additions

```toml
[profile.dist]
inherits = "release"
lto = "thin"

[profile.release]
strip = true
codegen-units = 1

[workspace.metadata.dist]
cargo-dist-version = "0.31.0"
ci = "github"
installers = []
targets = ["x86_64-unknown-linux-gnu"]
dispatch-releases = true
```

- **`[profile.dist]`** — cargo-dist's build profile. Inherits from `release` with thin LTO (cargo-dist default; full LTO is slower with marginal size gains for a tool like this).
- **`[profile.release]`** — strip debug symbols and use single codegen unit for better optimization.
- **`dispatch-releases = true`** — enables manual workflow dispatch in addition to tag-triggered releases.
- **`installers = []`** — no shell/powershell installers for v1. Can be added later.
- **Single target** — `x86_64-unknown-linux-gnu` only, matching v1 Linux-only scope.

### Triggers

1. **Tag push** — push a tag matching `v*` (e.g., `v0.2.0`) to trigger a release build.
2. **Manual workflow dispatch** — trigger from the GitHub Actions tab.

### Artifacts

For each release, cargo-dist produces:

- `quma-v{version}-x86_64-unknown-linux-gnu.tar.gz` — compressed archive containing the `quma` binary
- `quma-v{version}-x86_64-unknown-linux-gnu.tar.gz.sha256` — SHA256 checksum
- `dist-manifest.json` — machine-readable release manifest

All artifacts are attached to the GitHub Release.

### crates.io Publish

A `publish` job runs after the build succeeds, executing `cargo publish`. Requires a `CARGO_REGISTRY_TOKEN` repository secret configured in GitHub.

The cargo-dist workflow handles ordering — publish happens after artifacts are built and the GitHub Release is created.

### Release Flow

1. Bump `version` in `Cargo.toml`
2. Commit: `git commit -am "release: v0.2.0"`
3. Push to main: `git push`
4. Tag and push: `git tag v0.2.0 && git push --tags`
5. CI builds, creates GitHub Release with artifacts, publishes crate

Or: trigger manually from the Actions tab (workflow dispatch).

## Justfile Updates

Add convenience targets for the new workflows:

```just
audit:
    cargo audit

release-dry-run:
    dist build
```

- `just audit` — run dependency audit locally before CI catches it.
- `just release-dry-run` — test the release build locally without publishing.

## Repository Secrets Required

| Secret | Purpose |
|--------|---------|
| `CARGO_REGISTRY_TOKEN` | crates.io API token for `cargo publish` |

`GITHUB_TOKEN` is provided automatically by GitHub Actions.

## Files Created/Modified

| File | Action |
|------|--------|
| `.github/workflows/ci.yml` | Create — CI pipeline |
| `.github/workflows/release.yml` | Generated by `dist init` |
| `Cargo.toml` | Add `[profile.dist]`, `[profile.release]`, `[workspace.metadata.dist]` |
| `Justfile` | Add `audit` and `release-dry-run` targets |
| `audit.toml` | Create — empty advisory ignore list (placeholder for accepted risks) |

## Out of Scope

- Containerization of quma (future work)
- Deployment automation (future work)
- Multi-platform builds (future work — add targets to cargo-dist config)
- Shell/PowerShell installers (add to `installers` list when ready)
- Homebrew formula generation
- README.md or other public documentation
