Skip to content
Documentation GitHub
Reference

CI/CD System

Workflow Files: .github/workflows/ Platform: GitHub Actions Build Tool: tauri-apps/tauri-action@v0


Overview

The CI/CD pipeline consists of three GitHub Actions workflows that handle quality gates, database migrations, and desktop app releases. The pipeline enforces a main (staging) / production (release) branch model.

Workflow Files

WorkflowTriggerPurpose
deploy-app.ymlPR to main, push to main/productionQuality gates (lint, clippy, test, typecheck) + Supabase migration deployment
deploy-web.ymlPush to main/productionCloudflare Pages deployment
release.ymlVersion tag push (v*)Desktop app build + GitHub Release

Pipeline Overview

CI Quality Gates (deploy-app.yml)

Runs on every pull request to main and every push to main/production. These checks should be required in branch protection rules. Supabase migration deployment runs as an inline job after all checks pass (push only).

Job Graph

lint ─────────────┐
clippy ───────────┤ (parallel)
test ─────────────┤
└──> typescript (needs test — for generated types)
└──> deploy-supabase (needs all, push only)

Lint Job

Fast feedback with no compilation:

  • Rust formatting via cargo fmt --all --check
  • TypeScript linting via pnpm lint (oxlint)

Clippy Job

Rust static analysis:

  • Uses Swatinem/rust-cache for cargo registry + dependency artifacts (shared key ci-rust)
  • Uses sccache (GitHub Actions cache) for compilation output caching
  • Uses mold linker for faster linking on Linux
  • Frontend dist stub: Creates apps/desktop/dist/index.html so Tauri’s build validation passes without building the frontend
  • Excludes http-bridge crate (platform-specific)
  • Treats warnings as errors (-D warnings)

Test Job

Rust test suite:

  • Uses Swatinem/rust-cache for cargo registry + dependency artifacts (shared key ci-rust)
  • Uses sccache (GitHub Actions cache) for compilation output caching
  • Uses cargo-nextest for parallel test execution
  • Runs all tests including ignored tests (--run-ignored all)
  • Runs doc tests separately (cargo test --doc)
  • Uploads generated types as a GitHub Actions artifact for the TypeScript job

TypeScript Job

Frontend type safety (depends on Test job for generated types):

  • Downloads the generated-types artifact from the Test job
  • Runs pnpm typecheck on @inklings/contracts and desktop packages
  • Runs pnpm test (Vitest) for frontend unit tests

Python Sidecar

Python sidecar quality checks are handled by tools/precheck.sh, not by a dedicated CI job. When sidecar files are in the diff (or in --full mode), precheck runs:

  • ruff check — linting (pycodestyle, pyflakes, bugbear, etc.)
  • ruff format —check — formatting verification
  • mypy — strict type checking (Python 3.14)

The CI lint job installs uv via astral-sh/setup-uv@v6 to support these checks. In the release workflow, the sidecar is compiled to a standalone binary via tools/dev/build-python-sidecar.sh (PyInstaller) before tauri-action bundles it into the desktop installer.

Deploy Supabase Job

Supabase migration deployment (inline job with needs: on all check jobs):

  • Only runs on push events (not PRs)
  • Uses GitHub environments for branch-to-environment mapping
  • main → staging, production → production

Deploy Email Templates Job

Deploys Supabase Auth email templates after migrations succeed:

  • Runs after deploy-supabase on push events
  • Uses tools/provision/supabase/publish-email-templates.sh
  • Requires SUPABASE_ACCESS_TOKEN and SUPABASE_URL environment secrets

Notable Patterns

Concurrency control: Uses concurrency.group: deploy-app-${{ github.ref }} with cancel-in-progress: true to avoid wasting resources on superseded runs.

Configurable runner: Clippy and Test jobs use ${{ vars.RUST_RUNNER || 'ubuntu-latest' }}, allowing upgrade to a faster runner via repository variables without changing the workflow.

Frontend dist stub: Tauri’s build system expects apps/desktop/dist/ to exist (it embeds the frontend at compile time). CI creates a minimal stub (<!doctype html>) to satisfy this check without running the full Vite build.

Build optimizations: Debug info disabled (CARGO_PROFILE_DEV_DEBUG=0, CARGO_PROFILE_TEST_DEBUG=0) and incremental compilation disabled (CARGO_INCREMENTAL=0) to reduce CI build times and cache sizes.

Branch-to-Environment Mapping

BranchEnvironmentSupabase Target
mainstagingStaging database
productionproductionProduction database

Direct Postgres connection URLs (session pooler) are used instead of db.*.supabase.co to avoid IPv6 issues on GitHub Actions runners.

Release Workflow (release.yml)

Triggered by pushing a version tag (e.g., git tag v0.1.0 && git push origin v0.1.0). Creates a draft GitHub Release with platform installers.

Job Graph

verify ──> validate ──> build (matrix: macOS, Windows) ──> publish-templates

Verify Job

Ensures the tag exists on the production branch. Tags on other branches are rejected.

Validate Job

Checks that required secrets (SUPABASE_URL, SUPABASE_PUBLISHABLE_KEY) are configured. These values are baked into the binary at build time.

Build Job (Matrix)

Builds desktop installers using tauri-apps/tauri-action@v0:

PlatformRunnerArguments
macOSmacos-latest--target universal-apple-darwin (Intel + Apple Silicon)
Windowswindows-latest(default)

The build produces:

  • Platform installers (.dmg, .app.tar.gz for macOS; .msi, .nsis for Windows)
  • latest.json for tauri-plugin-updater auto-update checks
  • Draft GitHub Release with assets attached

Optional post-build steps upload debug symbols and source maps to Sentry (skipped when SENTRY_AUTH_TOKEN is not configured).

Publish Templates Job

After builds succeed, publishes workspace templates to Supabase Storage using tools/provision/supabase/publish-templates.sh. Requires SUPABASE_SERVICE_ROLE_KEY.

Build Optimization Stack

LayerToolWhat It CachesScope
Compilationsccache (GHA backend)rustc object filesCross-job, cross-workflow
DependenciesSwatinem/rust-cachecargo registry + target depsPer shared-key
FrontendTurboJS/CSS bundles (dist/)Per input hash
System packagescache-apt-pkgs-actionapt packagesPer job name

Local Development

  • sccache: Transparent via tools/dev/rustc-wrapper.sh (auto-delegates if installed)
  • cargo-sweep: Periodic cleanup of stale artifacts (cargo sweep --time 30)
  • Dev profile: line-tables-only debug info for speed; override with CARGO_PROFILE_DEV_DEBUG=2

Required Secrets and Variables

Deploy App (deploy-app.yml)

CI jobs require no secrets. Supabase deployment requires:

SecretScopePurpose
SUPABASE_DB_URLPer environmentDirect Postgres connection URL (session pooler)
SUPABASE_ACCESS_TOKENPer environmentSupabase Management API token (email template deployment)
SUPABASE_URLPer environmentSupabase project URL (email template deployment)

Release (release.yml)

SecretRequiredPurpose
SUPABASE_URLYesSupabase project URL (baked into binary)
SUPABASE_PUBLISHABLE_KEYYesSupabase anon key (baked into binary)
GITHUB_TOKENAutoGitHub Release creation
APPLE_CERTIFICATENomacOS code signing
APPLE_CERTIFICATE_PASSWORDNomacOS code signing
APPLE_SIGNING_IDENTITYNomacOS code signing
APPLE_IDNomacOS notarization
APPLE_PASSWORDNomacOS notarization
APPLE_TEAM_IDNomacOS notarization
TAURI_SIGNING_PRIVATE_KEYNoTauri updater signing
TAURI_SIGNING_PRIVATE_KEY_PASSWORDNoTauri updater signing
SENTRY_DSNNoBackend error reporting DSN
VITE_SENTRY_DSNNoFrontend error reporting DSN
SENTRY_AUTH_TOKENNoSentry CLI auth for symbol upload
SENTRY_ORGNoSentry organization slug
SUPABASE_SERVICE_ROLE_KEYNoTemplate publishing

Repository Variables

VariablePurpose
RUST_RUNNEROverride runner for Rust jobs (default: ubuntu-latest)

Infrastructure Automation

Scripts in tools/provision/ handle one-time provisioning and ongoing validation of external services (GitHub, Supabase, Sentry, Cloudflare, signing).

Bootstrap Orchestrator

Provisions all services for a target environment in dependency order:

Terminal window
# First-time setup — provision staging
cp tools/provision/.env.provision.example tools/provision/.env.provision
# Fill in .env.provision, then:
./tools/provision/bootstrap.sh --environment staging
# Preview changes without applying
./tools/provision/bootstrap.sh --environment staging --dry-run
# Run only specific steps
./tools/provision/bootstrap.sh --environment staging --only github-secrets,supabase-auth
# Skip optional steps
./tools/provision/bootstrap.sh --environment production --skip apple-signing,crabnebula

Steps run in order: sentrysupabase-authsupabase-smtpemail-templatestauri-keysgithub-envsgithub-secretscloudflare. Optional steps (apple-signing, windows-signing, crabnebula) are skipped gracefully when not yet provisioned.

Validation

Verifies all expected secrets, variables, and external service configurations:

Terminal window
# Check staging environment
./tools/provision/validate.sh --environment staging
# CI mode (non-interactive, exits with code 1 on any FAIL)
./tools/provision/validate.sh --environment production --ci

Produces a [PASS]/[WARN]/[FAIL]/[SKIP] report card covering GitHub secrets, Supabase auth config, Sentry projects, Cloudflare Pages, and signing readiness.

Email Template Deployment

Email templates (tools/provision/supabase/templates/) are deployed two ways:

  1. Manually: ./tools/provision/supabase/publish-email-templates.sh --environment staging
  2. Automatically via CI: The deploy-email-templates job in deploy-app.yml runs after every successful deploy-supabase job on push events.

Credentials File

All provisioning scripts read credentials from tools/provision/.env.provision (gitignored). See tools/provision/.env.provision.example for the full variable inventory with comments.

Was this page helpful?