Simpl-Resultat/.forgejo/workflows/check-rust.yml
le king fu cf1da2bea0
All checks were successful
PR Check — Frontend / frontend (pull_request) Successful in 1m46s
PR Check — Rust / rust (pull_request) Successful in 9m37s
ci: restore the Rust cache with rust-cache and a weekly run on main (#234)
The runner's cache server is reachable again since the VPS fix of
2026-10-03 (cache proxy pinned to port 28100, ufw rule scoped to the
Docker job networks; diagnosed in #374). Bring caching back to check-rust
through Swatinem/rust-cache, as #232 deferred.

forgejo-runner v12.7.0 keeps what a pull_request run saves private to
that PR, so PR runs alone would only warm later pushes to the same PR. A
weekly scheduled run on main (Mondays 06:30 UTC) and workflow_dispatch
write the shared entries that every PR falls back to.

rust-cache v2.9+ declares node24 and the runner starts JavaScript actions
with the container's node, so the job now installs Node.js 24. zstd is
installed for faster, smaller cache archives.

No npm cache in check-frontend, by decision: with per-PR isolation it
would only serve later pushes of a PR, and npm ci takes 9s there. audit.yml
loses two comments this change makes false.

No CHANGELOG entry: CI configuration only.

Refs #234

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 15:09:00 -04:00

185 lines
8.7 KiB
YAML

name: PR Check — Rust
# Rust half of the former check.yml (split in #232).
#
# Runs on PRs that change Rust, plus once a week on main to refresh the shared
# cache (see the note on the triggers). The runner has capacity 1 — jobs queue
# instead of running in parallel, so every minute spent here is a minute the
# next PR waits.
#
# No `branches:` filter on purpose. `branches: [main]` never matched a PR
# stacked on top of another feature branch, which is what /autopilot produces:
# 4 of the 5 PRs in the feature-gating milestone ran no CI at all.
on:
pull_request:
paths:
- 'src-tauri/**'
- '.forgejo/workflows/check-rust.yml'
# Whole directory, not just audit.toml: a later .cargo/config.toml
# (rustflags, linker, target dir) would change the Rust build, and an
# exact-path entry would let it skip Rust CI unnoticed.
- '.cargo/**'
# The weekly run is what feeds the cache to pull requests (#234). The runner
# (forgejo-runner v12.7.0) isolates what a pull_request run writes to that
# PR's ref: later pushes to the same PR read it back, other PRs never see it.
# A PR run falls back to the shared, non-isolated entries only when nothing
# matches in its own scope. Scheduled and dispatched runs write to the shared
# scope, which makes them this workflow's only writers of it (a merged PR's
# `closed` event would be another, but this workflow does not subscribe to
# it).
#
# The runner deletes an entry unused for 7 days or created more than 30 days
# ago, and the next Monday run saves a fresh one. Cold runs that do not mean
# #234 is back: every new stable Rust until the next Monday (the toolchain
# floats on `stable`, and rustc is part of the cache key); PR runs once an
# entry that only got exact hits, hence never re-saved, reaches 30 days; and,
# after a week without any PR run, possibly the Monday run itself.
# workflow_dispatch re-seeds by hand.
schedule:
# Mondays 06:30 UTC, after audit.yml (06:00 UTC).
- cron: '30 6 * * 1'
workflow_dispatch:
# Cancel obsolete runs (e.g. on force-push) so only the latest commit runs.
# Distinct from the frontend group: a shared group would make the two
# workflows cancel each other on a PR that touches both.
concurrency:
group: ci-rust-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
rust:
runs-on: ubuntu
container: ubuntu:22.04
env:
PATH: /root/.cargo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
CARGO_TERM_COLOR: always
# rust-cache keeps the dependencies and drops this crate's own artifacts
# before saving, so incremental data would never be reused — pure
# overhead — and test debug info would only make the cached target/
# bigger.
CARGO_INCREMENTAL: 0
CARGO_PROFILE_TEST_DEBUG: 0
steps:
- name: Install system dependencies, Node.js and Rust
run: |
apt-get update
# zstd: the cache archives are compressed with it when present,
# faster and smaller than the gzip fallback.
apt-get install -y --no-install-recommends \
curl wget git ca-certificates build-essential pkg-config \
libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev libssl-dev \
libdbus-1-dev zstd
# Node.js runs the JavaScript actions: actions/checkout (node20) and
# Swatinem/rust-cache (node24 since v2.9). The runner starts them
# with whatever `node` the container has, so install the newest
# runtime they declare. taiki-e/install-action is a composite action.
curl -fsSL https://deb.nodesource.com/setup_24.x | bash -
apt-get install -y nodejs
# Rust toolchain
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable --profile minimal
node --version
rustc --version
cargo --version
- name: Checkout
uses: https://github.com/actions/checkout@v4
# Caches ~/.cargo (registry, git, bin) and src-tauri/target, keyed on the
# rustc version, the Cargo manifests and lockfile, and this job. Saved
# only when the job succeeds and the key was not an exact hit. Served by
# the runner's cache proxy on port 28100, which ufw opens to the Docker
# job networks only; until 2026-10-03 every restore and save timed out
# there (#234, la-compagnie-maximus docs/forgejo-ops.md). What a PR run
# saves stays private to that PR: see the note on the triggers.
- name: Rust cache
uses: https://github.com/Swatinem/rust-cache@v2
with:
workspaces: "src-tauri -> target"
- name: cargo check
run: cargo check --manifest-path src-tauri/Cargo.toml --all-targets
# Anti-rot guard for the suppressions in .cargo/audit.toml (#310). Each
# entry there is justified by its crate being absent from every shipped
# target's graph — a property of today's resolved graph, not a permanent
# one. rsa is currently reachable from nothing: its only parent in the
# lockfile is sqlx-mysql, which this SQLite project never compiles. If a
# dependency change ever pulls it into a shipped target, the suppression
# would silently hide a live advisory and the daily audit would stay
# green: the inverse of the permanent red #310 exists to kill.
#
# Such a change would itself touch src-tauri, which is exactly what
# triggers this workflow. Runs after cargo check so the registry index is
# already warm, and --locked so cargo tree cannot rewrite the lockfile the
# audit was taken against.
#
# CRATES must mirror the crates named in .cargo/audit.toml. Adding an
# entry there without adding its crate here leaves it unguarded.
#
# Every check echoes its result, including the passing ones. A guard that
# is silent on success cannot be told apart in the log from a guard that
# never ran — which is the same silent-skip failure mode this step exists
# to catch, one level up.
- name: Verify suppressed advisories are still unreachable
run: |
set -u
CRATES="rsa"
TARGETS="x86_64-unknown-linux-gnu x86_64-pc-windows-msvc"
rc=0
checks=0
for crate in $CRATES; do
for target in $TARGETS; do
# An absent crate exits 0 with empty stdout ("nothing to print"
# goes to stderr). A non-zero exit means cargo tree itself failed
# — treat that as a failure rather than as proof of absence.
out=$(cargo tree --manifest-path src-tauri/Cargo.toml --locked \
-i "$crate" --target "$target" 2>/dev/null) || {
echo "cargo tree failed for $crate / $target — cannot verify the suppression"
rc=1
continue
}
if [ -n "$out" ]; then
echo "FAIL: $crate is now compiled for $target — its .cargo/audit.toml suppression is no longer justified (see #310)."
rc=1
else
echo "ok: $crate absent from $target"
fi
checks=$((checks + 1))
done
done
# Canary: a crate known to be present. If this stops being found, the
# loop above is broken and its silence means nothing.
canary=$(cargo tree --manifest-path src-tauri/Cargo.toml --locked \
-i tar --target x86_64-unknown-linux-gnu 2>/dev/null) || true
if [ -z "$canary" ]; then
echo "FAIL: canary 'tar' was not found although it is a known dependency. The guard is not proving anything."
rc=1
else
echo "ok: canary 'tar' found for x86_64-unknown-linux-gnu"
fi
echo "Suppression guard: $checks checks, exit $rc"
exit $rc
- name: cargo test
run: cargo test --manifest-path src-tauri/Cargo.toml --all-targets
# Prebuilt binary. `cargo install --locked cargo-audit` recompiled the
# tool from source on every single run (~4m40s). No continue-on-error:
# a tooling failure should fail the job rather than be swallowed.
- name: Install cargo-audit
uses: https://github.com/taiki-e/install-action@v2
with:
tool: cargo-audit
# Advisories are informational — they can land on unrelated crates and
# would otherwise stall unrelated work — so the step is non-blocking.
# It no longer hides real failures behind `|| true` though. Daily
# RustSec coverage outside Rust PRs lives in audit.yml.
- name: cargo audit
continue-on-error: true
run: cargo audit --file src-tauri/Cargo.lock