From 263ebe14950bc36375e748bbda90ab78c747ed79 Mon Sep 17 00:00:00 2001 From: le king fu Date: Fri, 24 Jul 2026 20:26:35 -0400 Subject: [PATCH] ci: split check.yml, drop dead caches, prebuild cargo-audit (#232) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The rust job cost 21m44s on every PR while only ~1 PR in 40 touches src-tauri/, and the runner has capacity 1 — the frontend job queues behind it, so every PR paid ~24.5 min of feedback. Measured on run 326 (2026-07-21), 12m15s of that was pure waste: - 6m54s tarring target/ and the cargo registry for saves that time out against the runner's unreachable cache server (#234). The restore times out into a miss too, so nothing was ever cached at either end. - 4m41s recompiling cargo-audit from source on every run. - ~40s on the two doomed restores. Split check.yml into check-rust.yml (paths: src-tauri/**) and check-frontend.yml (paths-ignore denylist), drop every actions/cache step until #234 is fixed, and install cargo-audit as a prebuilt binary via taiki-e/install-action. The audit step keeps continue-on-error — advisories are informational and can land on unrelated crates — but loses the `|| true` that also hid tooling failures; the install step is blocking. The frontend filter is a denylist on purpose: that job costs ~2.5 min, so running it needlessly is cheap while silently not running it is not. The expensive job keeps a strict allowlist. Neither workflow filters on `branches:` anymore. `branches: [main]` never matched a PR stacked on another feature branch, which is what /autopilot produces: PRs #305-#308 of the feature-gating milestone ran no CI at all. Adds audit.yml for daily RustSec coverage, since check-rust.yml now only runs on Rust PRs. It skips the Rust toolchain entirely — cargo-audit only reads Cargo.lock — so it costs ~1-2 min rather than the ~22 a scheduled check-rust would burn daily on a capacity-1 runner. The GitHub mirror is left untouched (#233: it receives no PRs). Expected: Rust PR ~9-10 min, frontend-only PR ~2.5 min instead of ~24.5. Resolves #232 --- .forgejo/workflows/audit.yml | 58 +++++++++++++ .forgejo/workflows/check-frontend.yml | 63 ++++++++++++++ .forgejo/workflows/check-rust.yml | 88 ++++++++++++++++++++ .forgejo/workflows/check.yml | 115 -------------------------- CLAUDE.md | 8 +- docs/architecture.md | 29 +++++-- 6 files changed, 237 insertions(+), 124 deletions(-) create mode 100644 .forgejo/workflows/audit.yml create mode 100644 .forgejo/workflows/check-frontend.yml create mode 100644 .forgejo/workflows/check-rust.yml delete mode 100644 .forgejo/workflows/check.yml diff --git a/.forgejo/workflows/audit.yml b/.forgejo/workflows/audit.yml new file mode 100644 index 0000000..906a3fe --- /dev/null +++ b/.forgejo/workflows/audit.yml @@ -0,0 +1,58 @@ +name: Security audit + +# Daily RustSec coverage (#232). +# +# check-rust.yml only runs when src-tauri/ changes, which is roughly 1 PR in +# 40 — without this workflow a new advisory published against an unchanged +# dependency would go unnoticed for weeks. +# +# Runs without a Rust toolchain: cargo-audit only reads Cargo.lock, so the +# binary is invoked directly instead of as a `cargo` subcommand. That keeps +# this to ~1-2 min rather than the ~22 min a scheduled check-rust would cost +# every day on a capacity-1 runner. +# +# Note: PATH is deliberately NOT overridden at job level (unlike check-rust, +# which needs /root/.cargo/bin for the toolchain) so that the install dir +# taiki-e/install-action appends to $GITHUB_PATH stays effective. + +on: + schedule: + # 06:00 UTC daily + - cron: '0 6 * * *' + workflow_dispatch: + +concurrency: + group: ci-audit-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + audit: + runs-on: ubuntu + container: ubuntu:22.04 + steps: + - name: Install Node.js 20 + run: | + apt-get update + apt-get install -y --no-install-recommends \ + curl ca-certificates git tar gzip + # Node.js is required by actions/checkout and taiki-e/install-action + # (JavaScript actions need `node` in the container PATH). + curl -fsSL https://deb.nodesource.com/setup_20.x | bash - + apt-get install -y nodejs + node --version + + - name: Checkout + uses: https://github.com/actions/checkout@v4 + + - name: Install cargo-audit + uses: https://github.com/taiki-e/install-action@v2 + with: + tool: cargo-audit + + # Unlike the PR run in check-rust.yml, this one is meant to fail loudly: + # it IS the notification channel for a newly published advisory. + - name: cargo audit + run: cargo-audit audit --file src-tauri/Cargo.lock diff --git a/.forgejo/workflows/check-frontend.yml b/.forgejo/workflows/check-frontend.yml new file mode 100644 index 0000000..90f9d59 --- /dev/null +++ b/.forgejo/workflows/check-frontend.yml @@ -0,0 +1,63 @@ +name: PR Check — Frontend + +# Frontend half of the former check.yml (split in #232). +# +# Filtered with paths-ignore rather than an allowlist: this job costs ~2.5 min, +# so running it when it was not strictly needed is cheap, while silently NOT +# running it is not. A root-level config file added later would drop out of an +# allowlist without anyone noticing; here it fails safe. +# +# No `branches:` filter — see check-rust.yml. + +on: + pull_request: + paths-ignore: + - 'src-tauri/**' + - 'docs/**' + - 'reports/**' + - 'tasks/**' + - '.github/**' + - '.forgejo/workflows/check-rust.yml' + - '.forgejo/workflows/audit.yml' + - '.forgejo/workflows/release.yml' + - '*.md' + - 'LICENSE' + +# Distinct group from the rust workflow — see check-rust.yml. +concurrency: + group: ci-frontend-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + frontend: + runs-on: ubuntu + container: ubuntu:22.04 + steps: + - name: Install Node.js 20 + run: | + apt-get update + apt-get install -y --no-install-recommends curl ca-certificates git + curl -fsSL https://deb.nodesource.com/setup_20.x | bash - + apt-get install -y nodejs + node --version + npm --version + + - name: Checkout + uses: https://github.com/actions/checkout@v4 + + # No npm cache step here, deliberately — same reason as the cargo caches + # in check-rust.yml: the restore misses and the save times out against + # the runner's cache server (#234), which cost ~23s per run for nothing. + # Restore it together with rust-cache once #234 is fixed. + + - name: Install dependencies + run: npm ci + + - name: Build (tsc + vite) + run: npm run build + + - name: Tests (vitest) + run: npm test diff --git a/.forgejo/workflows/check-rust.yml b/.forgejo/workflows/check-rust.yml new file mode 100644 index 0000000..a1ab5be --- /dev/null +++ b/.forgejo/workflows/check-rust.yml @@ -0,0 +1,88 @@ +name: PR Check — Rust + +# Rust half of the former check.yml (split in #232). +# +# Only runs when Rust actually changes. On this repo roughly 1 PR in 40 touches +# src-tauri/, and 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' + +# 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 + # Nothing persists between runs (see the caching note below), so + # incremental artifacts get written and never reused — pure overhead. + # Test debug info is dead weight here for the same reason. + CARGO_INCREMENTAL: 0 + CARGO_PROFILE_TEST_DEBUG: 0 + steps: + - name: Install system dependencies, Node.js and Rust + run: | + apt-get update + 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 + # Node.js is required by actions/checkout and taiki-e/install-action + # (they are JavaScript actions and need `node` in the container PATH). + curl -fsSL https://deb.nodesource.com/setup_20.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 + + # No actions/cache step here, deliberately. The job container cannot + # reach the runner's cache server (#234): the restore times out into a + # miss AND the save times out, so the cache cost ~7 min per run and + # returned nothing. Bring caching back through Swatinem/rust-cache once + # #234 is fixed — not before, it shares the same backend. + + - name: cargo check + run: cargo check --manifest-path src-tauri/Cargo.toml --all-targets + + - 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 diff --git a/.forgejo/workflows/check.yml b/.forgejo/workflows/check.yml deleted file mode 100644 index 5757b87..0000000 --- a/.forgejo/workflows/check.yml +++ /dev/null @@ -1,115 +0,0 @@ -name: PR Check - -# Validates Rust + frontend on every PR opened against main. -# Goal: catch compile errors, type errors, and failing tests BEFORE merge, -# instead of waiting for the release tag (which is when release.yml runs). -# -# Trigger is `pull_request` only — the previous `push` trigger duplicated -# every run when a branch was pushed and immediately opened as a PR (#171). -# Trade-off: branches pushed without an open PR don't get CI feedback. Open -# a draft PR if you want feedback before requesting review. - -on: - pull_request: - branches: - - main - -# Cancel obsolete runs (e.g. on force-push) so only the latest commit runs. -concurrency: - group: ci-${{ github.ref }} - cancel-in-progress: true - -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 - steps: - - name: Install system dependencies, Node.js and Rust - run: | - apt-get update - 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 - # Node.js is required by actions/checkout and actions/cache (they - # are JavaScript actions and need `node` in the container PATH). - curl -fsSL https://deb.nodesource.com/setup_20.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 - - - name: Cache cargo registry and git - uses: https://github.com/actions/cache@v4 - with: - path: | - ~/.cargo/registry - ~/.cargo/git - key: ${{ runner.os }}-cargo-registry-${{ hashFiles('src-tauri/Cargo.lock') }} - restore-keys: | - ${{ runner.os }}-cargo-registry- - - - name: Cache cargo build target - uses: https://github.com/actions/cache@v4 - with: - path: src-tauri/target - key: ${{ runner.os }}-cargo-target-${{ hashFiles('src-tauri/Cargo.lock') }} - restore-keys: | - ${{ runner.os }}-cargo-target- - - - name: cargo check - run: cargo check --manifest-path src-tauri/Cargo.toml --all-targets - - - name: cargo test - run: cargo test --manifest-path src-tauri/Cargo.toml --all-targets - - # Informational audit of transitive dependencies. Failure does not - # block the CI (advisories can appear on unrelated crates and stall - # unrelated work); surface them in the job log so we see them on - # every PR run and can react in a follow-up. - - name: cargo audit - continue-on-error: true - run: | - cargo install --locked cargo-audit || true - cargo audit --file src-tauri/Cargo.lock || true - - frontend: - runs-on: ubuntu - container: ubuntu:22.04 - steps: - - name: Install Node.js 20 - run: | - apt-get update - apt-get install -y --no-install-recommends curl ca-certificates git - curl -fsSL https://deb.nodesource.com/setup_20.x | bash - - apt-get install -y nodejs - node --version - npm --version - - - name: Checkout - uses: https://github.com/actions/checkout@v4 - - - name: Cache npm cache - uses: https://github.com/actions/cache@v4 - with: - path: ~/.npm - key: ${{ runner.os }}-npm-${{ hashFiles('package-lock.json') }} - restore-keys: | - ${{ runner.os }}-npm- - - - name: Install dependencies - run: npm ci - - - name: Build (tsc + vite) - run: npm run build - - - name: Tests (vitest) - run: npm test diff --git a/CLAUDE.md b/CLAUDE.md index 8a2d716..952d063 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -159,9 +159,15 @@ Pour maintenir l'éligibilité aux crédits d'impôt R&D (RS&DE fédéral + CRIC ## CI/CD -- **`check.yml`** (Forgejo Actions + miroir GitHub) — déclenché sur chaque push de branche (sauf `main`) et chaque PR vers `main`. Lance `cargo check`, `cargo test`, `npm run build` (tsc + vite) et `npm test` (vitest). Doit être vert avant tout merge. +Workflows Forgejo Actions dans `.forgejo/workflows/`. Le runner est à **capacité 1** — les jobs se suivent, ils ne tournent pas en parallèle. + +- **`check-rust.yml`** — déclenché sur les PR touchant `src-tauri/**`. Lance `cargo check`, `cargo test` et un `cargo audit` informatif. Doit être vert avant tout merge. +- **`check-frontend.yml`** — déclenché sur les PR, sauf si tous les fichiers modifiés sont du Rust, de la doc ou du markdown. Lance `npm run build` (tsc + vite) et `npm test` (vitest). Doit être vert avant tout merge. +- **`audit.yml`** — audit RustSec quotidien (06:00 UTC) + `workflow_dispatch`, pour couvrir les avis de sécurité entre deux PR Rust. Échec bloquant. - **`release.yml`** — déclenché par les tags `v*`. Build Windows (NSIS `.exe`) + Linux (`.deb`, `.rpm`), signe les binaires et publie le JSON d'updater pour les mises à jour automatiques. +Aucun workflow `check-*` ne filtre sur `branches:` : une PR stackée sur une autre branche de feature déclenche donc bien la CI. Le cache Actions est retiré partout tant que [#234](https://git.lacompagniemaximus.com/maximus/simpl-resultat/issues/234) (connectivité du serveur de cache) n'est pas réglé — restore et save échouent tous les deux. Le miroir `.github/workflows/` est dormant (aucune PR côté GitHub). + --- ## Ressources clés diff --git a/docs/architecture.md b/docs/architecture.md index 1ca5851..969d36d 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -65,8 +65,12 @@ simpl-resultat/ │ │ └── main.rs │ ├── capabilities/ # Permissions Tauri │ └── Cargo.toml -├── .github/workflows/ # CI/CD +├── .forgejo/workflows/ # CI/CD (hôte primaire) +│ ├── check-rust.yml +│ ├── check-frontend.yml +│ ├── audit.yml │ └── release.yml +├── .github/workflows/ # Miroir GitHub (dormant) ├── docs/ # Documentation technique └── config/ # Configuration ``` @@ -414,16 +418,25 @@ Page spéciale : `ProfileSelectionPage` (affichée quand aucun profil n'est acti ## CI/CD -Deux workflows Forgejo Actions (avec miroir GitHub) dans `.forgejo/workflows/` : +Quatre workflows Forgejo Actions dans `.forgejo/workflows/`. Le runner est à **capacité 1** : les jobs se suivent, ils ne tournent pas en parallèle. -### `check.yml` — Vérifications sur branches et PR +### `check-rust.yml` — Vérifications Rust sur PR -Déclenché sur chaque push de branche (sauf `main`) et chaque PR vers `main`. Lance en parallèle : -- `cargo check` + `cargo test` (Rust) -- `npm run build` (tsc + vite) -- `npm test` (vitest) +Déclenché sur les PR qui touchent `src-tauri/**` (ou le workflow lui-même). Lance `cargo check` puis `cargo test`, et un `cargo audit` informatif (non bloquant, binaire pré-buildé via `taiki-e/install-action`). -Doit être vert avant tout merge. Évite de découvrir des régressions au moment du tag de release. +Aucun `branches:` : une PR stackée sur une autre branche de feature — ce que produit `/autopilot` — déclenche donc bien la CI. Aucune étape de cache non plus : le conteneur de job n'atteint pas le serveur de cache du runner ([#234](https://git.lacompagniemaximus.com/maximus/simpl-resultat/issues/234)), le restore et le save échouent tous les deux. Le cache reviendra via `Swatinem/rust-cache` une fois #234 réglé. + +### `check-frontend.yml` — Vérifications frontend sur PR + +Déclenché sur les PR, sauf si tous les fichiers modifiés sont du Rust, de la doc ou du markdown (`paths-ignore`). Lance `npm ci`, `npm run build` (tsc + vite) et `npm test` (vitest). Le cache npm est retiré pour la même raison que côté Rust. + +### `audit.yml` — Audit RustSec quotidien + +`schedule` quotidien (06:00 UTC) + `workflow_dispatch`. `check-rust.yml` ne tournant que sur les PR qui touchent le Rust — environ 1 PR sur 40 — ce workflow garantit qu'un avis de sécurité publié sur une dépendance inchangée ne passe pas inaperçu. Échec bloquant : c'est le canal de notification. + +Les deux workflows `check-*` doivent être verts avant tout merge. Ils évitent de découvrir des régressions au moment du tag de release. + +> Le miroir GitHub (`.github/workflows/check.yml`) est laissé tel quel : aucune PR n'est ouverte côté GitHub, un push-mirror ne déclenche pas d'événement `pull_request`. ### `release.yml` — Build et publication