CI/CD
All CI/CD is managed through GitHub Actions workflows in .github/workflows/.
CI Workflow
File: .github/workflows/ci.yml
Runs on every push to main/next and on pull requests targeting those branches.
Jobs
| Job | Runner | Description |
|---|---|---|
| rust-test | ubuntu-latest | Run Rust tests via Bazel (with PR-level impact analysis) |
| rust-build | ubuntu-latest | Build all Rust crates and apps via Bazel |
| clippy | ubuntu-latest | Run Clippy lints via Bazel rust_clippy_aspect |
| schemas | ubuntu-latest | Verify OpenAPI and GraphQL schemas are up to date |
| rustfmt | ubuntu-latest | Check Rust formatting (cargo fmt --check) |
| lint | ubuntu-latest | ESLint across all pnpm packages |
| build | ubuntu-latest | Build all pnpm packages (pnpm -r build) |
| done | ubuntu-latest | Gate job -- fails if any upstream job failed |
Impacted Target Detection (PR only)
For pull requests, the rust-test job uses bazel-diff to detect which targets changed:
- Generates hashes for the head commit and the base commit (via
git worktree) - Computes impacted targets
- Filters to
//crates/and//platform/targets - Only tests impacted targets, skipping unrelated code
On pushes to main/next, all targets are tested.
Schema Verification
The schemas job regenerates both API schemas and diffs them against the committed versions:
bazel run //platform/api:generate-openapi -- /tmp/schemas/openapi.json
bazel run //platform/api:generate-schema -- /tmp/schemas/schema.graphql
If either schema is outdated, the job fails with instructions to run just schemas.
Concurrency
concurrency:
group: ci-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.ref_type != 'tag' }}
Branch pushes cancel in-progress runs. Tag pushes are never cancelled.
Security Audit
File: .github/workflows/security-audit.yml
Runs nightly at 03:00 UTC and on manual dispatch.
Jobs
| Job | Tool | Scope |
|---|---|---|
| rust-audit | cargo audit | Rust dependencies (all severities) |
| npm-audit | pnpm audit | npm dependencies (high + critical only) |
| daily-summary | Discord webhook | Aggregated status notification |
Notifications
- Per-ecosystem alerts -- If vulnerabilities are found, a Discord webhook sends an embed with the advisory IDs and severities
- Daily summary -- Always sent (green for "all clear", yellow for "action required")
- Webhook secret:
DISCORD_SECURITY_WEBHOOK_URL
Release Images
File: .github/workflows/release-images.yml
Triggered by GitHub releases or manual dispatch.
Workflow
- Verify -- Runs Bazel tests to ensure the release is stable
- Build & Push -- Builds Docker images and pushes to GHCR
Tag Parsing
Release tags follow the format {app}@{version} (e.g., api@2026.6.1).
For manual dispatch, you select the app and provide the tag directly:
| App Selection | Builds |
|---|---|
all | All Rust + Web apps |
all-rust | All Rust apps |
all-web | All Web apps |
api | API binary only |
web | Web app only |
Image Tags
| Release Type | Tags Applied |
|---|---|
| Stable release | {version}, {major.minor}, latest, {short-sha}, {full-sha} |
| Pre-release (beta/alpha/rc) | {version}, beta, {short-sha}, {full-sha} |
Registry
Images are pushed to: ghcr.io/{owner}/apollon/{app}:{tag}
Schema Artifacts
For API releases, OpenAPI and GraphQL schema files are generated and attached to the GitHub release as downloadable assets.
Runtime Base Image
File: .github/workflows/build-runtime-base.yml
Builds the shared runtime-base Docker image:
- Trigger: Nightly (04:00 UTC), manual dispatch, or changes to
docker/runtime-base.Dockerfile - Platforms:
linux/amd64,linux/arm64(multi-arch viadocker buildx) - Tags:
{short-sha},{full-sha},{branch},latest(main only)
Docs Deployment
Documentation is deployed to Cloudflare Pages with a two-tier strategy:
| Branch/Trigger | Environment |
|---|---|
next branch | Staging (preview URL) |
20* tags (e.g., 2026.6.1) | Production |
Other Workflows
| Workflow | File | Trigger | Description |
|---|---|---|---|
| Sync Labels | sync-labels.yml | Push to main/next | Synchronize GitHub labels for issues/PRs |
| Clean Cache | clean-cache.yml | PR closed | Clean up GitHub Actions caches for the PR branch |
Required Secrets
| Secret | Used In | Purpose |
|---|---|---|
BUILDBUDDY_API_KEY | CI, Release Images | Bazel remote cache (BuildBuddy) |
DISCORD_SECURITY_WEBHOOK_URL | Security Audit | Discord notification webhook |
CF_DOCS_API_TOKEN | Deploy Docs | Cloudflare Pages API token |
CF_DOCS_ACCOUNT_ID | Deploy Docs | Cloudflare account ID |
GITHUB_TOKEN | Release Images | GHCR authentication (auto-provided) |