Replace every remaining reference to the old Gitea infrastructure with the new GitHub-hosted equivalents across all documentation, wiki pages, test files, and historical ticket summaries. - README.md: CI badge, clone URL, releases link, CI/CD section, project structure - docs/wiki/CICD-Pipeline.md: full rewrite for GitHub Actions + ghcr.io - docs/wiki/Home.md: CI badge, releases link, phase status, tech stack - docs/wiki/Troubleshooting.md: rewrite CI troubleshooting for GitHub Actions - docs/architecture/README.md: update CI/CD pipeline diagram - AGENTS.md: CI/CD section, environment references - PLAN.md: directory structure, pipeline table - SECURITY_AUDIT.md: mark C3 and L4 findings as resolved - ticket-git-cliff-changelog.md: workflow path updated - tickets/ci-runner-speed-optimization.md: image registry updated - 2026-hackathon_AgenticFeature.md: workflow path updated - tests: workflow path assertions updated in all three test files
9.8 KiB
CI/CD Pipeline
Infrastructure
| Component | URL | Notes |
|---|---|---|
| GitHub | https://github.com/msicie/apollo_nxt-trcaa |
Git server and CI/CD platform |
| GitHub Actions | Native to GitHub | Hosted runners (ubuntu-latest, macos-latest, macos-13) |
| ghcr.io | ghcr.io/msicie/ |
GitHub Container Registry for pre-baked CI images |
Pre-baked Builder Images
CI build and test jobs use pre-baked Docker images pushed to ghcr.io/msicie/. These images bake in all system dependencies (Tauri libs, Node.js, Rust toolchain, cross-compilers) so that CI jobs skip package installation entirely.
| Image | Used by jobs | Contents |
|---|---|---|
ghcr.io/msicie/trcaa-linux-amd64:rust1.88-node22 |
rust-test, build-linux-amd64 |
Rust 1.88 + rustfmt + clippy + Tauri amd64 libs + Node.js 22 |
ghcr.io/msicie/trcaa-windows-cross:rust1.88-node22 |
build-windows-amd64 |
Rust 1.88 + mingw-w64 + NSIS + Node.js 22 |
ghcr.io/msicie/trcaa-linux-arm64:rust1.88-node22 |
build-linux-arm64 |
Rust 1.88 + aarch64 cross-toolchain + arm64 multiarch libs + Node.js 22 |
Rebuild triggers: Rust toolchain version bump, webkit2gtk/gtk major version change, Node.js major version change.
How to rebuild images:
- Trigger
build-images.ymlvia Actions → Build CI Docker Images → Run workflow - Confirm all 3 images appear in
ghcr.io/msicie/ - Only then merge workflow changes that depend on the new image contents
Cargo and npm Caching
All Rust and build jobs use actions/cache@v4 to cache downloaded package artifacts.
Cargo cache (Rust jobs):
- name: Cache cargo registry
uses: actions/cache@v4
with:
path: |
~/.cargo/registry/index
~/.cargo/registry/cache
~/.cargo/git/db
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-
npm cache (frontend and build jobs):
- name: Cache npm
uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-npm-
Cache keys for cross-compile jobs use a suffix to avoid collisions:
- Windows build:
${{ runner.os }}-cargo-windows-${{ hashFiles('**/Cargo.lock') }} - arm64 build:
${{ runner.os }}-cargo-arm64-${{ hashFiles('**/Cargo.lock') }}
Test Pipeline (.github/workflows/test.yml)
Triggers: Every push to main, feature/**, bug/**, fix/** branches; pull requests targeting main.
Jobs (run in parallel):
rust-test → cargo fmt --check
→ cargo clippy -- -D warnings
→ cargo test (64 tests)
frontend-test → npx tsc --noEmit
→ npm run test:run (Vitest tests)
Docker image used:
ghcr.io/msicie/trcaa-linux-amd64:rust1.88-node22— both Rust and frontend steps
Job names rust-test and frontend-test must match exactly — these are the required status check names in branch protection on main.
Release Pipeline (.github/workflows/release.yml)
Triggers: Push to main (auto-tag job), then release build/upload jobs run after autotag completes on v* tags.
Auto-tags are created by the autotag job using git tag + git push. Release jobs depend on autotag and run in parallel.
Jobs (run in parallel after autotag):
build-linux-amd64 → image: ghcr.io/msicie/trcaa-linux-amd64:rust1.88-node22
→ cargo tauri build (x86_64-unknown-linux-gnu)
→ {.deb, .rpm, .AppImage} uploaded to GitHub Release
→ fails fast if no Linux artifacts are produced
build-windows-amd64 → image: ghcr.io/msicie/trcaa-windows-cross:rust1.88-node22
→ cargo tauri build (x86_64-pc-windows-gnu) via mingw-w64
→ {.exe, .msi} uploaded to GitHub Release
→ fails fast if no Windows artifacts are produced
build-linux-arm64 → image: ghcr.io/msicie/trcaa-linux-arm64:rust1.88-node22
→ cargo tauri build (aarch64-unknown-linux-gnu)
→ {.deb, .rpm, .AppImage} uploaded to GitHub Release
→ fails fast if no Linux artifacts are produced
build-macos-arm64 → runs-on: macos-latest (Apple Silicon)
→ cargo tauri build (aarch64-apple-darwin) natively
→ {.dmg} uploaded to GitHub Release
→ existing same-name assets are deleted before upload (rerun-safe)
→ unsigned; after install run: xattr -cr /Applications/TRCAA.app
build-macos-intel → runs-on: macos-13 (Intel x86_64)
→ cargo tauri build (x86_64-apple-darwin) natively
→ {.dmg} uploaded to GitHub Release
Windows cross-compile environment:
env:
TARGET: x86_64-pc-windows-gnu
CC_x86_64_pc_windows_gnu: x86_64-w64-mingw32-gcc
CARGO_TARGET_X86_64_PC_WINDOWS_GNU_LINKER: x86_64-w64-mingw32-gcc
OPENSSL_NO_VENDOR: "0"
OPENSSL_STATIC: "1"
Artifacts per platform:
- Linux amd64:
.deb,.rpm,.AppImage - Windows amd64:
.exe(NSIS installer),.msi - Linux arm64:
.deb,.rpm,.AppImage - macOS ARM64:
.dmg - macOS Intel:
.dmg
Build Images Workflow (.github/workflows/build-images.yml)
Triggers: Changes to .docker/** on main; manual workflow_dispatch.
Builds and pushes all three pre-baked CI images to ghcr.io/msicie/:
Jobs (all run on ubuntu-latest):
build-linux-amd64-image → .docker/Dockerfile.linux-amd64
→ ghcr.io/msicie/trcaa-linux-amd64:rust1.88-node22
build-windows-cross-image → .docker/Dockerfile.windows-cross
→ ghcr.io/msicie/trcaa-windows-cross:rust1.88-node22
build-linux-arm64-image → .docker/Dockerfile.linux-arm64
→ ghcr.io/msicie/trcaa-linux-arm64:rust1.88-node22
Authentication: docker login ghcr.io -u ${{ github.actor }} --password-stdin <<< "${{ secrets.GITHUB_TOKEN }}". Requires packages: write permission.
Branch Protection
main branch requires:
- All changes via PR
- 1 approving review
- CODEOWNER review (
@Shaun-Arman-VFK387_motoand@github-copilot) - Required status checks:
rust-test,frontend-test enforce_admins: false— owner and admins can bypass withgh pr merge --admin
Changelog Generation
Changelogs are generated automatically by git-cliff on every release.
Configuration lives in cliff.toml at the repo root.
How it works
A changelog job in release.yml runs in parallel with the build jobs, immediately
after autotag completes:
- Clones the full repo history with all tags (
--depth=2147483647— git-cliff needs every tag to compute version boundaries). - Downloads the git-cliff v2.7.0 static musl binary (~5 MB, no image change needed).
- Runs
git-cliff --output CHANGELOG.mdto regenerate the full cumulative changelog. - Runs
git-cliff --latest --strip allto produce release notes for the new tag only. - Updates the GitHub Release body with those notes via
gh release edit. - Commits
CHANGELOG.mdtomainwith[skip ci]appended to the message. The[skip ci]token preventsrelease.ymlfrom re-triggering on the CHANGELOG commit. - Uploads
CHANGELOG.mdas a release asset (replaces any previous version).
cliff.toml reference
| Setting | Value |
|---|---|
tag_pattern |
v[0-9].* |
ignore_tags |
rc|alpha|beta |
filter_unconventional |
true — non-conventional commits are dropped |
| Included types | feat, fix, perf, docs, refactor |
| Excluded types | ci, chore, build, test, style |
Loop prevention
The [skip ci] suffix on the CHANGELOG commit message is recognised by GitHub Actions
and causes the workflow to be skipped for that push. Without it, the CHANGELOG commit
would trigger release.yml again, incrementing the patch version forever.
Known Issues & Fixes
Debian Multiarch Breaks arm64 Cross-Compile (held broken packages)
When using rust:1.88-slim (Debian Bookworm) with dpkg --add-architecture arm64, apt
resolves amd64 and arm64 simultaneously against the same mirror. The binary-all package
index is duplicated and certain -dev package pairs cannot be co-installed because they
don't declare Multi-Arch: same. This produces E: Unable to correct problems, you have held broken packages and cannot be fixed by tweaking sources.list entries.
Fix: Use ubuntu:22.04 as the container image (see Dockerfile.linux-arm64). Ubuntu
routes arm64 through ports.ubuntu.com/ubuntu-ports — a separate mirror from
archive.ubuntu.com (amd64). There are no cross-arch index overlaps and the dependency
resolver succeeds. Rust must be installed manually via rustup.
CI=true Required by Tauri CLI
GitHub Actions sets CI=true by default — cargo tauri build accepts this without
modification. Prefix the command explicitly if your runner environment is unusual:
- run: CI=true cargo tauri build --target $TARGET
Windows DLL Export Ordinal Too Large
/usr/bin/x86_64-w64-mingw32-ld: error: export ordinal too large: 106290
Fix: src-tauri/.cargo/config.toml:
[target.x86_64-pc-windows-gnu]
rustflags = ["-C", "link-arg=-Wl,--exclude-all-symbols"]
Release Artifacts Not Uploaded
Cause: GITHUB_TOKEN needs contents: write permission in the workflow.
Verify the release.yml permissions block includes:
permissions:
contents: write
Runner Group Restrictions (Enterprise)
GitHub Enterprise organizations may restrict which repositories can use GitHub-hosted runners. If jobs are stuck in queue, contact your org admin to add the repository to the allowed runner group, or temporarily make the repo public for the bootstrap run.