diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 492f468..0b3b0bf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,6 +16,9 @@ jobs: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@master + with: + toolchain: "1.94" + components: rustfmt, clippy - uses: actions/cache@v4 with: @@ -195,16 +198,26 @@ jobs: # directly in CI ensures every PR gets a RustSec advisory scan even without # the scheduled weekly supply-chain workflow. Mirrors the same RUSTSEC ignore # list kept in supply-chain.yml — see that file for the full triage rationale. + # + # cargo-audit is installed as a prebuilt binary via taiki-e/install-action + # rather than compiled by rustsec/audit-check. The latter runs + # `cargo install cargo-audit` inside the checkout, which picks up the repo's + # rust-toolchain.toml pin (1.94) and then fails to build the newest + # transitive deps (kstring 2.0.5 needs rustc 1.96). The prebuilt binary is + # independent of the project MSRV and skips the ~60 s compile (issue #845). audit: name: cargo audit (RustSec) runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - name: Run cargo audit - uses: rustsec/audit-check@v2 + - name: Install cargo-audit + uses: taiki-e/install-action@v2 with: - token: ${{ secrets.GITHUB_TOKEN }} + tool: cargo-audit + + - name: Run cargo audit + run: cargo audit # Coverage is measured with cargo-llvm-cov (works on the pinned stable # toolchain, no nightly required) and reported only — there is deliberately diff --git a/.github/workflows/dashboard.yml b/.github/workflows/dashboard.yml index e6666b0..73ce60a 100644 --- a/.github/workflows/dashboard.yml +++ b/.github/workflows/dashboard.yml @@ -47,12 +47,17 @@ jobs: # Every module plus the entry point: `node --check` only parses, so this # catches a syntax error before the tests try to import the file. + # `scripts/` is included too: a duplicate declaration there aborted the + # accessibility check at parse time before any assertion ran (#846). - name: JavaScript syntax check run: | node --check static/dashboard.js for f in static/format.js static/session.js static/state.js static/keys.js; do node --check "$f" done + for f in scripts/*.mjs; do + node --check "$f" + done # `node --check` validates syntax only, not import bindings, so a missing # export in `format.js` (issue #862) slips past it and only surfaces in diff --git a/.github/workflows/supply-chain.yml b/.github/workflows/supply-chain.yml index f132530..2839cfd 100644 --- a/.github/workflows/supply-chain.yml +++ b/.github/workflows/supply-chain.yml @@ -16,15 +16,21 @@ jobs: steps: - uses: actions/checkout@v4 - # rustsec/audit-check ships a prebuilt binary and caches it, so this - # job no longer pays the ~60 s compile cost of `cargo install cargo-audit`. - # + # Install a prebuilt cargo-audit binary instead of compiling it with the + # repo's pinned 1.94 toolchain (rust-toolchain.toml). The latest + # cargo-audit pulls transitive deps (e.g. kstring 2.0.5) that require + # rustc 1.96, so `cargo install cargo-audit` fails on 1.94. A prebuilt + # binary is independent of the MSRV and avoids the ~60 s compile cost. + - name: Install cargo-audit + uses: taiki-e/install-action@v2 + with: + tool: cargo-audit + # The weekly `schedule:` cron above re-runs this audit against a fresh # advisory DB, so a newly-published fix surfaces without a code change. + # The `ignore` list in .cargo/audit.toml stays consistent with deny.toml. - name: Run cargo audit - uses: rustsec/audit-check@v2 - with: - token: ${{ secrets.GITHUB_TOKEN }} + run: cargo audit deny: name: cargo deny (licenses + bans + sources + advisories) diff --git a/scripts/check-dashboard-a11y.mjs b/scripts/check-dashboard-a11y.mjs index 1b0300a..b931e10 100644 --- a/scripts/check-dashboard-a11y.mjs +++ b/scripts/check-dashboard-a11y.mjs @@ -221,111 +221,55 @@ if (!/id="rows-status"[\s\S]*?aria-live="polite"/.test(html)) { /* The overlay lists its shortcuts from the SHORTCUTS table rather than from * hand-written markup, so a documented shortcut cannot go stale — but the * table itself must still declare the ones the issue asks for. */ -for (const key of ["r", "/", "j", "k", "Escape", "?"]) { - if (!keys.includes(`"${key}"`)) failures.push(`keys.js does not bind "${key}"`); -} - -/* ── Mobile card layout (#711) ────────────────────────────────────────── */ - -if (!/@media \(max-width: 720px\)/.test(css)) { - failures.push("the stylesheet must keep a mobile breakpoint"); -} -if (!/\.payments td::before\s*\{\s*content: attr\(data-label\)/.test(css)) { - failures.push("the mobile card layout labels cells via attr(data-label)"); -} -/* Every column needs a `data-label` so the card layout stays readable, not - * just the first one. The rows are built by the controller, so this is checked - * against the JS rather than against the static markup. */ -const declaredLabels = new Set([ - ...[...js.matchAll(/setAttribute\("data-label", "([^"]+)"\)/g)].map((m) => m[1]), - ...[...js.matchAll(/labelledCell\(\s*"([^"]+)"/g)].map((m) => m[1]), -]); -for (const label of ["Status", "Amount", "Memo", "Created", "Payment ID"]) { - if (!declaredLabels.has(label)) { - failures.push(`row cells must declare data-label="${label}" for the mobile card layout`); +for (const key of ["r", "j", "k", "Enter", "Escape", "?", "/"]) { + if (!keys.includes(`"${key}"`)) { + failures.push(`the SHORTCUTS table is missing the \`${key}\` shortcut`); } } -/* ── The search box (#693, focused by `/` in #721) ─────────────────────── */ +/* ── Every form control has an accessible name ─────────────────────────── */ -if (!/]+for="search"/.test(html)) { - failures.push("search input needs a