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
| Workflow | Trigger | Purpose |
|---|---|---|
deploy-app.yml | PR to main, push to main/production | Quality gates (lint, clippy, test, typecheck) + Supabase migration deployment |
deploy-web.yml | Push to main/production | Cloudflare Pages deployment |
release.yml | Version 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-cachefor cargo registry + dependency artifacts (shared keyci-rust) - Uses
sccache(GitHub Actions cache) for compilation output caching - Uses
moldlinker for faster linking on Linux - Frontend dist stub: Creates
apps/desktop/dist/index.htmlso Tauri’s build validation passes without building the frontend - Excludes
http-bridgecrate (platform-specific) - Treats warnings as errors (
-D warnings)
Test Job
Rust test suite:
- Uses
Swatinem/rust-cachefor cargo registry + dependency artifacts (shared keyci-rust) - Uses
sccache(GitHub Actions cache) for compilation output caching - Uses
cargo-nextestfor 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-typesartifact from the Test job - Runs
pnpm typecheckon@inklings/contractsanddesktoppackages - 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-supabaseon push events - Uses
tools/provision/supabase/publish-email-templates.sh - Requires
SUPABASE_ACCESS_TOKENandSUPABASE_URLenvironment 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
| Branch | Environment | Supabase Target |
|---|---|---|
main | staging | Staging database |
production | production | Production 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-templatesVerify 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:
| Platform | Runner | Arguments |
|---|---|---|
| macOS | macos-latest | --target universal-apple-darwin (Intel + Apple Silicon) |
| Windows | windows-latest | (default) |
The build produces:
- Platform installers (
.dmg,.app.tar.gzfor macOS;.msi,.nsisfor Windows) latest.jsonfor 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
| Layer | Tool | What It Caches | Scope |
|---|---|---|---|
| Compilation | sccache (GHA backend) | rustc object files | Cross-job, cross-workflow |
| Dependencies | Swatinem/rust-cache | cargo registry + target deps | Per shared-key |
| Frontend | Turbo | JS/CSS bundles (dist/) | Per input hash |
| System packages | cache-apt-pkgs-action | apt packages | Per 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-onlydebug info for speed; override withCARGO_PROFILE_DEV_DEBUG=2
Required Secrets and Variables
Deploy App (deploy-app.yml)
CI jobs require no secrets. Supabase deployment requires:
| Secret | Scope | Purpose |
|---|---|---|
SUPABASE_DB_URL | Per environment | Direct Postgres connection URL (session pooler) |
SUPABASE_ACCESS_TOKEN | Per environment | Supabase Management API token (email template deployment) |
SUPABASE_URL | Per environment | Supabase project URL (email template deployment) |
Release (release.yml)
| Secret | Required | Purpose |
|---|---|---|
SUPABASE_URL | Yes | Supabase project URL (baked into binary) |
SUPABASE_PUBLISHABLE_KEY | Yes | Supabase anon key (baked into binary) |
GITHUB_TOKEN | Auto | GitHub Release creation |
APPLE_CERTIFICATE | No | macOS code signing |
APPLE_CERTIFICATE_PASSWORD | No | macOS code signing |
APPLE_SIGNING_IDENTITY | No | macOS code signing |
APPLE_ID | No | macOS notarization |
APPLE_PASSWORD | No | macOS notarization |
APPLE_TEAM_ID | No | macOS notarization |
TAURI_SIGNING_PRIVATE_KEY | No | Tauri updater signing |
TAURI_SIGNING_PRIVATE_KEY_PASSWORD | No | Tauri updater signing |
SENTRY_DSN | No | Backend error reporting DSN |
VITE_SENTRY_DSN | No | Frontend error reporting DSN |
SENTRY_AUTH_TOKEN | No | Sentry CLI auth for symbol upload |
SENTRY_ORG | No | Sentry organization slug |
SUPABASE_SERVICE_ROLE_KEY | No | Template publishing |
Repository Variables
| Variable | Purpose |
|---|---|
RUST_RUNNER | Override 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:
# First-time setup — provision stagingcp 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,crabnebulaSteps run in order: sentry → supabase-auth → supabase-smtp → email-templates → tauri-keys → github-envs →
github-secrets → cloudflare. Optional steps (apple-signing, windows-signing, crabnebula) are skipped
gracefully when not yet provisioned.
Validation
Verifies all expected secrets, variables, and external service configurations:
# 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 --ciProduces 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:
- Manually:
./tools/provision/supabase/publish-email-templates.sh --environment staging - Automatically via CI: The
deploy-email-templatesjob indeploy-app.ymlruns after every successfuldeploy-supabasejob 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.
Related Documentation
- Development Guide — Local development setup and commands
- Getting Started — Prerequisites and first-time setup
Worktree Ownership Boundary: Never Remove Worktrees You Didn't Create Next
Python Sidecar IPC Reference
Was this page helpful?
Thanks for your feedback!