tftsr-devops_investigation/docs/wiki/CICD-Pipeline.md
Shaun Arman d5e180740e
Some checks failed
Test / rust-test (push) Failing after 6s
Test / frontend-test (push) Failing after 54s
docs: remove all Gitea/Gogs/172.0.0.29 references; update to GitHub
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
2026-06-01 16:18:34 -05:00

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:

  1. Trigger build-images.yml via Actions → Build CI Docker Images → Run workflow
  2. Confirm all 3 images appear in ghcr.io/msicie/
  3. 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_moto and @github-copilot)
  • Required status checks: rust-test, frontend-test
  • enforce_admins: false — owner and admins can bypass with gh 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:

  1. Clones the full repo history with all tags (--depth=2147483647 — git-cliff needs every tag to compute version boundaries).
  2. Downloads the git-cliff v2.7.0 static musl binary (~5 MB, no image change needed).
  3. Runs git-cliff --output CHANGELOG.md to regenerate the full cumulative changelog.
  4. Runs git-cliff --latest --strip all to produce release notes for the new tag only.
  5. Updates the GitHub Release body with those notes via gh release edit.
  6. Commits CHANGELOG.md to main with [skip ci] appended to the message. The [skip ci] token prevents release.yml from re-triggering on the CHANGELOG commit.
  7. Uploads CHANGELOG.md as 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.