# trx-rs SDK image A single container image that is the canonical build environment for trx-rs, used **both** by CI and by developers. It bakes in the pinned Rust toolchain (matching `rust-toolchain.toml`) and every build dependency, so the compiler and `clippy` are identical everywhere — no "works on my machine". | File | Purpose | |------|---------| | `Containerfile` | The SDK image (Debian + build deps + pinned Rust + Node + git). | | `runner-config.example.yaml` | Example act_runner config for the CI VM (Docker executor). | ## Build and publish ```bash # from the repo root podman build -t git.haxx.space/sjg/trx-rs/sdk:latest container podman login git.haxx.space podman push git.haxx.space/sjg/trx-rs/sdk:latest ``` Tag with the Rust version too (e.g. `:1.97.1`) if you want reproducible pins. Make the package **public** (Gitea → Packages → the image → Settings) so the CI runner and developers can pull it without credentials. If you keep it private, add `credentials:` under the workflow's `container:` and log the runner into the registry. ## Developer use Reproducible one-off build, no local toolchain needed: ```bash podman run --rm -it -v "$PWD":/work -w /work \ git.haxx.space/sjg/trx-rs/sdk:latest \ cargo build --release ``` Or open the repo in the image via VS Code / JetBrains "Reopen in Container" (`.devcontainer/devcontainer.json` points at the same image). Building outside the container? `rust-toolchain.toml` pins the same rustc, so `rustup` installs the matching toolchain automatically. ## CI use `.gitea/workflows/ci.yml` runs the `lint`, `test` and `frontend` jobs *inside* this image via the `container:` key, so they skip all setup and go straight to `cargo` and `npm`. The frontend job needs three things from the image beyond Rust: Node.js for the toolchain, Chromium at `/usr/bin/chromium` for the browser smoke test, and `cargo` — `npm run verify-generated` regenerates the Rust wire contracts before checking for drift. The `reuse` job stays on the upstream `fsfe/reuse-action` (a Docker action the Docker executor launches as a sibling container) — nothing REUSE-related is baked into the SDK, and it lints the whole repository, so no job runs its own licence check. ## Compilation cache (sccache) The SDK image ships [`sccache`](https://github.com/mozilla/sccache). It is enabled via `RUSTC_WRAPPER=sccache` in CI and the devcontainer (not repo-wide, so plain `cargo` builds outside the SDK are unaffected). - **CI** persists the cache on the runner host — create the dir once: `mkdir -p /var/cache/sccache`. It is bind-mounted into each job container at `/sccache` (see `runner-config.example.yaml`), so cache survives across runs and is shared between the lint/test jobs and both projects. - **Devcontainer** uses a named volume (`trx-rs-sccache`). - Check effectiveness with `sccache --show-stats` (the CI jobs print it). `CARGO_INCREMENTAL=0` is set wherever sccache is on, since sccache cannot cache incremental artifacts. ## CI runner (Alpine / OpenRC) The runner uses the **Docker executor** (not the host executor): per-job container isolation and standard `ubuntu-latest` semantics. `act_runner` runs as an OpenRC service. Files provided: | File | Purpose | |------|---------| | `act_runner.openrc` | OpenRC init script (`supervise-daemon`, depends on docker). | | `act_runner.confd.example` | Per-instance `conf.d` settings for multi-runner hosts. | **Cap the thread budget.** In a VM, pin its vCPUs to specific host threads (libvirt/KVM): ```xml 2 ``` On bare metal, the `container.options: "--cpus=2"` and `capacity: 1` in `runner-config.example.yaml` already bound each runner. **Set it up:** ```bash # 1. Docker + a dedicated user with socket access apk add docker docker-cli rc-update add docker default && rc-service docker start adduser -S -D -H -h /var/lib/act_runner act addgroup act docker # 2. act_runner binary (static Go build, works on musl) curl -fsSL -o /usr/local/bin/act_runner \ https://gitea.com/gitea/act_runner/releases/download/v0.2.11/act_runner-0.2.11-linux-amd64 chmod +x /usr/local/bin/act_runner # 3. Config + register one runner per project (scope keeps their jobs apart) install -Dm644 container/runner-config.example.yaml /etc/act_runner/trx-rs.yaml install -d -o act /var/lib/act_runner/trx-rs su act -s /bin/sh -c 'cd /var/lib/act_runner/trx-rs && \ act_runner register --no-interactive \ --instance https://git.haxx.space --token \ --name trx-rs-ci \ --labels "ubuntu-latest:docker://catthehacker/ubuntu:act-latest"' # 4. OpenRC service (repeat the symlink+conf.d for the second project) install -m755 container/act_runner.openrc /etc/init.d/act_runner ln -s act_runner /etc/init.d/act_runner.trx-rs install -m644 container/act_runner.confd.example /etc/conf.d/act_runner.trx-rs rc-update add act_runner.trx-rs default rc-service act_runner.trx-rs start ``` Check it with `rc-service act_runner.trx-rs status` and `tail -f /var/log/act_runner.trx-rs.log`.