Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 28 additions & 36 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,20 +1,13 @@
# CI — lint, build, and test Themis on every push.
#
# Runs on the self-hosted ARC pool `homeserver-pool` (ephemeral Linux pods,
# minRunners: 0 — a fresh container is spun up per job and torn down after).
# Runs on GitHub-hosted runners (Linux in the `rust-ci`-family container for
# toolchain parity; macOS natively on a hosted Apple Silicon image).
#
# There is intentionally NO `pull_request` trigger. Fork PRs fire only
# pull_request events (their push happened in the fork), so with
# push/workflow_dispatch-only triggers a fork PR can never schedule a job onto
# the self-hosted runners. If you later want CI for outside contributors' PRs,
# add a SEPARATE workflow with `on: pull_request` pinned to
# `runs-on: ubuntu-latest` (GitHub-hosted, free on public repos, fork-safe).
#
# Runner provisioning required on `homeserver-pool` (bake into the ARC image or
# install via ansible):
# - rustup (the pinned 1.95 toolchain + rustfmt/clippy install
# themselves from rust-toolchain.toml on first cargo call)
# - cc/gcc, git, make, pkg-config (make check shells out to all of these)
# push/workflow_dispatch-only triggers a fork PR can never schedule a job. If
# you later want CI for outside contributors' PRs, add a SEPARATE workflow with
# `on: pull_request` (already fork-safe here — the jobs run on hosted runners).
name: CI

on:
Expand All @@ -28,10 +21,10 @@ concurrency:

jobs:
check:
runs-on: homeserver-pool
# The ARC pod is a bare runner. This image (rust-web-ci = rust-ci + Node +
# prettier) bakes in rustup + the pinned toolchain + cc/make/git + prettier,
# so `make check` (which runs `prettier --check`) needs no per-job installs.
runs-on: ubuntu-latest
# Run inside our toolchain image (rust-web-ci = rust-ci + Node + prettier):
# it bakes in rustup + the pinned toolchain + cc/make/git + prettier, so
# `make check` (which runs `prettier --check`) needs no per-job installs.
# The Rust-only siblings use the leaner `rust-ci`.
container: ghcr.io/twowells/rust-web-ci:latest
# Inside a container job GitHub's default shell is sh (dash); force bash so
Expand Down Expand Up @@ -65,38 +58,37 @@ jobs:
- name: make check
run: make check

# macOS check — native on the self-hosted M2 Max (`ghost`: labels
# macos/arm64/self-hosted). No container: macOS runners can't use Linux
# container images, so the host carries the tools — rustup + the pinned
# toolchain (honored from rust-toolchain.toml), clang/make/git (Xcode CLT),
# and prettier 3.8.4. The cargo tools install per-job below, mirroring the
# Linux job.
# macOS check — native on a GitHub-hosted Apple Silicon runner (macos-14).
# No container: macOS runners can't use Linux container images, so the host
# carries the tools — rustup + cargo are already on PATH, clang/make/git ship
# in the image's Xcode CLT, and Node/npm are preinstalled (we install prettier
# below to match the Linux container). The cargo tools install per-job,
# mirroring the Linux job.
check-macos:
runs-on: [self-hosted, macos, arm64]
runs-on: macos-14
defaults:
run:
shell: bash
steps:
- uses: actions/checkout@v7

# `ghost` exposes the toolchain via rustup shims in ~/.cargo/bin, which
# proved unreliable here: `rustc` exited 127 (shell couldn't resolve it)
# while `rustup` itself worked. Derive the active toolchain's real bin dir
# from rustup and put it on PATH — independent of the shim layer. `rustup
# show` also materializes the pinned toolchain (rust-toolchain.toml) if the
# runner hasn't cached it yet.
- name: Put Rust toolchain on PATH
run: |
rustup show
cargo_bin="$(dirname "$(rustup which cargo)")"
echo "$cargo_bin" >> "$GITHUB_PATH"
# rustup reads rust-toolchain.toml (channel 1.95 + rustfmt/clippy) and
# materializes the pinned toolchain if the runner hasn't cached it yet.
- name: Materialize pinned Rust toolchain
run: rustup show
- name: Verify toolchain
run: rustc --version && cargo --version

- uses: Swatinem/rust-cache@v2

# Prebuilt binaries — the host runner is persistent, but installing here
# keeps the tool versions in lockstep with the Linux job.
# The hosted macOS image ships Node/npm but no global prettier, and `make
# check` → `lint` invokes `prettier` as a global binary. Install the same
# version the rust-web-ci container pins so macOS stays in lockstep with
# the Linux job.
- name: Install prettier (match the rust-web-ci container's pinned version)
run: npm install -g prettier@3.8.4

# Prebuilt binaries — keeps the tool versions in lockstep with the Linux job.
- name: Install cargo tools
uses: taiki-e/install-action@v2
with:
Expand Down
30 changes: 13 additions & 17 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,18 @@
#
# Two jobs:
# build builds `website/dist/` and uploads it as a Pages artifact. Runs on
# the self-hosted ARC pool `homeserver-pool` using the `rust-web-ci`
# image (it bakes in Node + npm). This job never touches the Pages
# deployment, so it cannot fail the deploy even while Pages is off.
# a GitHub-hosted runner inside the `rust-web-ci` image (it bakes in
# Node + npm). This job never touches the Pages deployment, so a
# build failure here can't half-apply a deploy.
# deploy publishes the uploaded artifact with the official `actions/deploy-pages`
# flow. This needs a GitHub-hosted runner and the `github-pages`
# environment, neither of which exists on the self-hosted pool.
# flow. This needs the `github-pages` environment (set up under
# Settings → Environments).
#
# --- TRIGGER: kept manual while the repo is PRIVATE -------------------------
# The repo is private and GitHub Pages is not enabled yet, so an automatic
# push-to-main deploy would run-and-fail and turn `main` red. Until the repo is
# flipped public AND Pages is enabled (Settings → Pages → Source: GitHub
# Actions), this workflow runs ONLY via manual `workflow_dispatch`.
#
# TO ACTIVATE AT THE PUBLIC FLIP: uncomment the single `push` block below.
# (One-line change — that's all that's needed once Pages is on.)
# --- TRIGGER ----------------------------------------------------------------
# The repo is public and GitHub Pages is enabled (Settings → Pages → Source:
# GitHub Actions, deploying from `main`), so this auto-deploys on every push to
# `main`; `workflow_dispatch` is also kept for manual re-runs. The published
# site is live at https://twowells.github.io/Themis/.
name: Docs

on:
Expand All @@ -39,7 +36,7 @@ concurrency:

jobs:
build:
runs-on: homeserver-pool
runs-on: ubuntu-latest
# rust-web-ci = rust-ci + Node + prettier. We only need Node + npm here.
container: ghcr.io/twowells/rust-web-ci:latest
# Inside a container job GitHub's default shell is sh (dash); force bash so
Expand Down Expand Up @@ -78,9 +75,8 @@ jobs:

deploy:
needs: build
# GitHub-hosted runner: actions/deploy-pages targets the Pages service and
# needs the `github-pages` environment, which the self-hosted pool can't
# provide. Free for public repos.
# actions/deploy-pages targets the Pages service and needs the
# `github-pages` environment (declared below). Free for public repos.
runs-on: ubuntu-latest
environment:
name: github-pages
Expand Down
45 changes: 25 additions & 20 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# Release — on a vX.Y.Z tag push:
# 1. verify the tag matches Cargo.toml's version
# 2. build the release binaries on the self-hosted fleet
# (Linux x86_64 on the ARC pool + macOS arm64 on ghost)
# 2. build the release binaries on GitHub-hosted runners
# (Linux x86_64 in a container + macOS arm64 on macos-14),
# each attested with build provenance at release time
# 3. publish-crate publish `themis-cli` to crates.io via Trusted Publishing
# (OIDC — no stored token); the installed binary stays `themis`
# 4. release cut a GitHub Release with the binary + SHA256 checksum
Expand Down Expand Up @@ -36,12 +37,13 @@ on:

permissions:
contents: write # create the GitHub Release
id-token: write # OIDC token for crates.io Trusted Publishing
id-token: write # OIDC token for crates.io Trusted Publishing + attestation
attestations: write # mint build-provenance attestations for the release assets

jobs:
# Guard: a pushed tag whose version disagrees with Cargo.toml is a mistake.
verify:
runs-on: homeserver-pool
runs-on: ubuntu-latest
outputs:
version: ${{ steps.v.outputs.version }}
steps:
Expand All @@ -59,22 +61,23 @@ jobs:
echo "version=$tag" >> "$GITHUB_OUTPUT"

# Native release build per platform. fail-fast: false so one platform's
# failure does not cancel the others. Linux x86_64 on the ARC pool +
# aarch64-apple-darwin natively on the self-hosted ghost runner.
# failure does not cancel the others. Linux x86_64 in a container on a hosted
# runner + aarch64-apple-darwin natively on a hosted Apple Silicon runner.
build:
needs: verify
strategy:
fail-fast: false
matrix:
include:
- target: x86_64-unknown-linux-gnu
runner: homeserver-pool
runner: ubuntu-latest
container: ghcr.io/twowells/rust-ci:latest
# Native build on the self-hosted M2 Max (`ghost`). container "" → the
# job runs on the host, not in a container (macOS can't use Linux
# images). `rustup target add` and both apple targets are already present.
# Native build on a GitHub-hosted Apple Silicon runner. container "" →
# the job runs on the host, not in a container (macOS can't use Linux
# images). rustup + cargo are already on PATH; `rustup target add`
# below ensures the apple target is installed.
- target: aarch64-apple-darwin
runner: [self-hosted, macos, arm64]
runner: macos-14
container: ""
runs-on: ${{ matrix.runner }}
container: ${{ matrix.container }}
Expand All @@ -83,13 +86,9 @@ jobs:
shell: bash
steps:
- uses: actions/checkout@v7
# `ghost`'s rustup shims (~/.cargo/bin) proved unreliable (rustc unresolved
# while rustup worked); derive the toolchain's real bin dir from rustup and
# put it on PATH. No-op on Linux (the container has cargo on PATH), so gate
# it to macOS.
- name: Put Rust toolchain on PATH (macOS native runner)
if: runner.os == 'macOS'
run: echo "$(dirname "$(rustup which cargo)")" >> "$GITHUB_PATH"
# rustup reads rust-toolchain.toml; `rustup target add` ensures the matrix
# target is installed. Works as-is on both the Linux container (cargo on
# PATH) and the hosted macOS runner (rustup + cargo preinstalled on PATH).
- name: Materialize Rust toolchain
run: |
rustup show
Expand Down Expand Up @@ -120,7 +119,7 @@ jobs:
# re-run (or a re-pushed tag) is a harmless no-op rather than a hard failure.
publish-crate:
needs: verify
runs-on: homeserver-pool
runs-on: ubuntu-latest
container: ghcr.io/twowells/rust-ci:latest
defaults:
run:
Expand Down Expand Up @@ -156,12 +155,18 @@ jobs:

release:
needs: [verify, build, publish-crate]
runs-on: homeserver-pool
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@v8
with:
path: dist
merge-multiple: true
# Mint a build-provenance attestation for the platform tarballs (the glob
# deliberately skips the .tar.gz.sha256 sidecars — no value attesting
# checksum files). Consumers can verify with `gh attestation verify`.
- uses: actions/attest-build-provenance@v4
with:
subject-path: dist/themis-*.tar.gz
- uses: softprops/action-gh-release@v3
with:
tag_name: ${{ github.ref_name }}
Expand Down