Skip to content

chore(audit): execute 2026-06-10 audit — CI path-filter parity, version pins, un-skip isolation test#158

Merged
agjs merged 4 commits into
mainfrom
chore/audit-fixes-20260610-1348
Jun 10, 2026
Merged

chore(audit): execute 2026-06-10 audit — CI path-filter parity, version pins, un-skip isolation test#158
agjs merged 4 commits into
mainfrom
chore/audit-fixes-20260610-1348

Conversation

@agjs

@agjs agjs commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Summary

Executes all 4 findings from today's audit-monorepo run, guardrail-first: every class-of-defect fix ships with a lint-meta rule that surfaced the instances (RED) before the fix (GREEN), so the class is blocked for good.

  • F001 — push-paths vs paths-filter parity (6c9fc66): new rule github-actions-paths-filter-parity requires workflows pairing a push.paths trigger with an in-job dorny/paths-filter gate to keep the two path sets mutually glob-covered. It surfaced 3 drifted workflows, all fixed: apps-docs-linkcheck (wrangler/bunfig/osv-scanner config changes skipped the rebuild the workflow's own comment promises), apps-docs-security-deps (filter gated out osv-scanner.toml allowlist edits; now mirrors the broad api/ui sibling shape), infra-compose-validate-compose (setup.sh shellcheck never ran on setup.sh-only changes; yamllint lints all workflows but only triggered on edits to itself).
  • F003 — yamllint pinned (3935433): CI installed yamllint job-time with no version pin, so the compose/workflow lint gate tracked latest-PyPI. Pinned to 1.38.0 via YAMLLINT_VERSION; the local infra pre-push reads that pin at runtime and warns on drift (same single-source idiom as GITLEAKS_VERSION). New rule github-actions-pip-install-pinned blocks the class.
  • F002 — runners pinned (669c329): all 23 workflows ran on floating ubuntu-latest while everything else in the repo is exact-pinned. 26 runs-on instances → ubuntu-24.04; new rule github-actions-runner-pinned bans *-latest labels (expression labels exempt).
  • F004 — dashboard isolation test un-skipped (6f84588): the long-skipped HTTP-level user-isolation test is back, rewritten against the endpoint's actual contract. The first un-skip attempt failed in the gate and exposed two latent defects in the old test: it asserted a {success, data} envelope the route never returns (bare DashboardSummarySchema), and its startsWith("bob.") checks could never catch leakage because the feed humanizes actions (bob.event.1 → "Bob event 1"). New assertions match the real body shape and humanized titles, so a userId-scoping regression now actually fails the test.

Three new lint-meta rules (31 → 34) with tests (100 → 106 lint-meta assertions), RULES.md and the docs lint-meta-catalog.json regenerated.

Test plan

  • cd apps/api && bun run check — typecheck + lint + lint:meta + knip green
  • cd apps/api && bun test tests/lint-meta — 106 pass, incl. RED/GREEN coverage for all 3 new rules
  • Full pre-push gate on push: security scans, compose smoke boot + migrate, Playwright e2e, API suite 1177 pass / 0 fail (validate + coverage ratchet), UI 656 tests / 152 files pass
  • yamllint (CI config) clean over .github/workflows/ after the runner/paths edits
  • shellcheck -x -S warning infra/compose/scripts/pre-push.sh clean

Conventions

  • No any, no blind as, no !
  • No new env vars (YAMLLINT_VERSION is workflow-job env, not app config)
  • Tests updated for changed behavior (new rule tests + rewritten dashboard test)

Screenshots

n/a — CI/workflow, lint-meta, and API test changes only.

agjs added 4 commits June 10, 2026 13:59
New lint-meta rule github-actions-paths-filter-parity: workflows pairing a
push.paths trigger with an in-job dorny/paths-filter gate must keep the two
path sets mutually glob-covered. Drift produces silent failure modes: a
push-only path starts the workflow but every gated step no-ops (change lands
unverified); a filter-only path never triggers on direct pushes to main.

The rule surfaced and this commit fixes three drifted workflows:
- apps-docs-linkcheck: wrangler.jsonc/bunfig.toml/osv-scanner.toml were in
  push.paths but missing from the docs filter — a config-only change skipped
  the rebuild the workflow's own comment promises.
- apps-docs-security-deps: filter narrowed to dep files while push covered
  apps/docs/** (and osv-scanner.toml was gated out); now mirrors the broad
  api/ui sibling shape.
- infra-compose-validate-compose: setup.sh was push-triggered but absent
  from every job filter (shellcheck on it never ran on setup.sh-only
  changes); yamllint lints all workflows but only triggered on edits to
  itself — push now covers .github/workflows/**.

Audit: F001
yamllint was installed job-time via unpinned 'pip install --user yamllint',
so the compose/workflow lint gate silently tracked the latest PyPI release —
rule changes upstream could flip CI with no repo diff. Pin it to 1.38.0 via a
YAMLLINT_VERSION env var, and have the local pre-push gate read that pin at
runtime (same single-source idiom as GITLEAKS_VERSION) to warn when the
brew-installed yamllint diverges.

New lint-meta rule github-actions-pip-install-pinned blocks the class: any
job-time pip install of a bare package name without an ==<version> pin.

Audit: F003
All 23 workflows ran on floating ubuntu-latest while everything else in the
repo is exact-pinned (deps, action SHAs, scanner versions, bun). The runner
image migrates on GitHub's schedule, so preinstalled tool versions and OS
packages change between runs of the same SHA with no commit to blame.

New lint-meta rule github-actions-runner-pinned blocks the class: any
runs-on label ending in -latest fails lint:meta (expression labels for
matrix strategies are exempt). 26 instances pinned to ubuntu-24.04.

Audit: F002
The skip predated the current assertion strategy: counts now use >= against
awaited fixture inserts and isolation is asserted via per-user action
prefixes, so fire-and-forget audit-log writes from the auth flow cannot flip
the outcome — only a real userId-scoping regression can. Verified stable
across 5 consecutive runs against the live local stack (postgres+valkey).

Guardrail unchanged: skipped-tests-need-tracking already polices skip
hygiene; this removes the last tracked skip in the API suite.

Audit: F004
@agjs agjs merged commit d434f3f into main Jun 10, 2026
32 checks passed
@agjs agjs deleted the chore/audit-fixes-20260610-1348 branch June 10, 2026 17:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant