feat(scans): geheimen- en SAST-scan draaien nu bij elke PR en push #799

Merged
brenno merged 4 commits from feat/ci-scans-778-v2 into main 2026-07-24 15:35:25 +00:00
Owner

Sluit #778.

check-secrets (gitleaks + trufflehog, werkboom én volledige historie) en sast (semgrep) zaten alleen in check-full, en dat draait nergens automatisch. Of er ooit gescand was, hing af van wie het lokaal toevallig deed. Geen bekend lek — beide draaiden handmatig schoon op main — maar wel een gat in de controle.

Wat er anders is dan het issue voorstelde

Het issue vroeg om een tweede job in ci.yml, naast gate. Dat kan niet meer: on: geldt per workflow, en ci.yml is sinds #790 de uitbrengpoort die op een v*-tag vuurt. Een job daarin zou pas scannen als het geheim al op main stond mét een tag eromheen — precies te laat voor het enige wat bij een geheim telt.

Daarom een eigen scans.yml, die vuurt op elke PR en elke push naar main. De reden voor #790 was de klok (22 minuten per PR tegen een make check die toch al lokaal draaide); deze twee doen 17 en 2 seconden, dus dat argument reikt er niet tot.

En op de Linux-runner, niet op de Mac. De Mac heeft de drie scanners al staan, maar is sinds #797 zowel de uitbrengpoort als de werkmachine van de committer — en dit is de enige workflow die bij élke push vuurt, dus die zou kernen afnemen van de make check die op dat moment draait. De server staat sinds diezelfde verhuizing stil.

Twee dingen dragen het gewicht

fetch-depth: 0 — gemeten in plaats van beweerd. Op een wegwerprepo met een geheim dat gecommit en daarna verwijderd is:

kloon gitleaks trufflehog
volledig exit 1 exit 183
--depth 1 exit 0 exit 0

Zonder die regel meldt de historie-scan dus groen over vrijwel niets.

Gepinde versies met geverifieerde download. De test -n "$SHA" daarin is geen plichtpleging: grep … | sha256sum -c - slaagt stíl bij een lege treffer, dus één hernoemd release-asset zou de verificatie weghalen zonder een enkel rood vinkje.

Tegenproef

Een scan die niets ziet lijkt precies op een schone repo, dus beide richtingen getoetst met een willekeurig gegenereerd AWS-vormig sleutelpaar (nooit gecommit in deze repo; de historie-proef stond in een wegwerprepo):

  • in de werkboom → make check-secrets valt om en noemt de vondst;
  • alleen in de historie, werkboom schoon → beide historie-scans vallen alsnog om;
  • schone boom → groen.

Deze PR is zijn eigen bewijs: scans.yml vuurt op pull_request, dus de eerste run staat hieronder.

Verder in deze tak

De notitie bij nosemgrepBaseline rechtvaardigde die ratchet met "make sast draait niet automatisch". Dat klopt niet meer, en het echte argument stond er niet: semgrep telt zijn eigen onderdrukkingen niet, dus een repo die er twintig verzamelt heeft een groene make sast en geen enkel signaal.

make check groen. Geen Dart-wijziging op lib/, geen l10n, geen SBOM-gevolg.

Vervangt feat/ci-scans-778, die tegen de ci.yml van vóór #796/#797 was geschreven.

Nagekomen: de drie absolute beloftes

CONTRIBUTING.md, README.md en docs/BUILD.md kregen bij #790 alle drie een absolute formulering — "nothing runs it for you between your branch and main", "the only thing standing between a change and main", "the assurance before main is entirely the committer's local run". Die klopte toen precies, en klopt sinds deze tak niet meer helemaal. #790 schreef zelf op dat een belofte die niet meer waar is erger is dan geen belofte; dat geldt ook in deze richting. Alle drie hebben nu de uitzondering erbij, nadrukkelijk als aanvulling op de lokale run en niet als vervanging.

Sluit #778. `check-secrets` (gitleaks + trufflehog, werkboom én volledige historie) en `sast` (semgrep) zaten alleen in `check-full`, en dat draait nergens automatisch. Of er ooit gescand was, hing af van wie het lokaal toevallig deed. Geen bekend lek — beide draaiden handmatig schoon op main — maar wel een gat in de controle. ### Wat er anders is dan het issue voorstelde Het issue vroeg om een tweede job in `ci.yml`, naast `gate`. Dat kan niet meer: `on:` geldt per workflow, en `ci.yml` is sinds #790 de uitbrengpoort die op een `v*`-tag vuurt. Een job daarin zou pas scannen als het geheim al op main stond mét een tag eromheen — precies te laat voor het enige wat bij een geheim telt. Daarom een eigen `scans.yml`, die vuurt op **elke PR en elke push naar main**. De reden voor #790 was de klok (22 minuten per PR tegen een `make check` die toch al lokaal draaide); deze twee doen 17 en 2 seconden, dus dat argument reikt er niet tot. En op de **Linux**-runner, niet op de Mac. De Mac heeft de drie scanners al staan, maar is sinds #797 zowel de uitbrengpoort als de werkmachine van de committer — en dit is de enige workflow die bij élke push vuurt, dus die zou kernen afnemen van de `make check` die op dat moment draait. De server staat sinds diezelfde verhuizing stil. ### Twee dingen dragen het gewicht **`fetch-depth: 0`** — gemeten in plaats van beweerd. Op een wegwerprepo met een geheim dat gecommit en daarna verwijderd is: | kloon | gitleaks | trufflehog | | --- | ---: | ---: | | volledig | exit 1 | exit 183 | | `--depth 1` | exit 0 | exit 0 | Zonder die regel meldt de historie-scan dus groen over vrijwel niets. **Gepinde versies met geverifieerde download.** De `test -n "$SHA"` daarin is geen plichtpleging: `grep … | sha256sum -c -` slaagt stíl bij een lege treffer, dus één hernoemd release-asset zou de verificatie weghalen zonder een enkel rood vinkje. ### Tegenproef Een scan die niets ziet lijkt precies op een schone repo, dus beide richtingen getoetst met een willekeurig gegenereerd AWS-vormig sleutelpaar (nooit gecommit in deze repo; de historie-proef stond in een wegwerprepo): - in de werkboom → `make check-secrets` valt om en noemt de vondst; - alleen in de historie, werkboom schoon → beide historie-scans vallen alsnog om; - schone boom → groen. **Deze PR is zijn eigen bewijs**: `scans.yml` vuurt op `pull_request`, dus de eerste run staat hieronder. ### Verder in deze tak De notitie bij `nosemgrepBaseline` rechtvaardigde die ratchet met "`make sast` draait niet automatisch". Dat klopt niet meer, en het echte argument stond er niet: semgrep telt zijn eigen onderdrukkingen niet, dus een repo die er twintig verzamelt heeft een groene `make sast` en geen enkel signaal. `make check` groen. Geen Dart-wijziging op `lib/`, geen l10n, geen SBOM-gevolg. Vervangt `feat/ci-scans-778`, die tegen de `ci.yml` van vóór #796/#797 was geschreven. ### Nagekomen: de drie absolute beloftes `CONTRIBUTING.md`, `README.md` en `docs/BUILD.md` kregen bij #790 alle drie een absolute formulering — "nothing runs it for you between your branch and `main`", "the only thing standing between a change and `main`", "the assurance before `main` is entirely the committer's local run". Die klopte toen precies, en klopt sinds deze tak niet meer helemaal. #790 schreef zelf op dat een belofte die niet meer waar is erger is dan geen belofte; dat geldt ook in deze richting. Alle drie hebben nu de uitzondering erbij, nadrukkelijk als aanvulling op de lokale run en niet als vervanging.
check-secrets (gitleaks + trufflehog) en sast (semgrep) zaten alleen in
check-full, en dat draait nergens automatisch: of er ooit gescand was,
hing af van wie het lokaal toevallig deed.

Een eigen workflow en geen tweede job in ci.yml, want `on:` geldt per
workflow en ci.yml vuurt sinds #790 op een v*-tag — daar zou pas gescand
worden als het geheim al op main stond mét een tag eromheen. Deze vuurt
op elke PR en elke push: de reden voor #790 was de klok (22 minuten per
PR), en deze twee doen 17 en 2 seconden. Voor een geheim is het moment
bovendien niet inwisselbaar.

Op de Linux-runner en niet op de Mac. Die Mac heeft de scanners al
staan, maar is sinds #797 zowel de uitbrengpoort als de werkmachine van
de committer, en dit is de enige workflow die bij élke push vuurt — dan
neemt hij kernen af van de `make check` die op dat moment draait. De
server staat sinds diezelfde verhuizing stil.

De commando's zijn de Makefile-doelen zelf, niet overgetypte regels.

Twee dingen dragen het gewicht:

  * fetch-depth: 0. Gemeten in plaats van beweerd: op een repo met een
    gecommit-en-daarna-verwijderd geheim geeft de volledige kloon exit 1
    (gitleaks) en 183 (trufflehog), en de ondiepe kloon van diezelfde
    repo twee keer 0.
  * gepinde versies met een tegen het manifest geverifieerde download.
    De `test -n` daarin is geen plichtpleging: `grep | sha256sum -c -`
    slaagt stil bij een lege treffer.

Tegenproef gedraaid, want een scan die niets ziet lijkt precies op een
schone repo: met een willekeurig AWS-vormig sleutelpaar in de werkboom
valt `make check-secrets` om en noemt hij de vondst.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
De notitie zei dat deze ratchet in check_conventions telt omdat `make
sast` nergens automatisch draait, dus dat een onderdrukking anders alleen
zichtbaar zou zijn voor wie semgrep toevallig had staan. Sinds scans.yml
klopt dat niet meer.

Het argument dat wél overeind blijft is sterker en stond er niet: semgrep
telt zijn eigen onderdrukkingen niet. Een `// nosemgrep` haalt de
bevinding uit beeld, dus een repo die er twintig verzamelt heeft een
groene `make sast` en geen enkel signaal. Deze ratchet ís dat signaal, en
hoort daarom in de poort die bij élke `make check` draait.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
docs(poort): de scanworkflow, en wat er nu wél vóór een merge draait (#778)
All checks were successful
scans / scans (pull_request) Successful in 3m15s
b2e0d531ef
CHECKS.md beloofde tot nu toe dat er tussen `make check` en main niets
meer voor je draait. Dat klopt niet meer op één punt, en dat punt hoort
er hardop bij te staan in plaats van verstopt in een workflowbestand: de
geheimen- en SAST-scan zijn de enige twee controles uit de tabel die een
forge werkelijk vóór een merge draait.

Verder: de voetnoot onder de tabel, de inleiding van de CI-paragraaf (de
twee beveiligingsscans zijn nu de uitzondering op "check-full draait
alleen lokaal"), en een eigen paragraaf voor scans.yml met de vier
afwegingen — eigen workflow, per PR, Linux in plaats van de Mac, en wat
er load-bearing aan is.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
docs: de drie plekken die "niets draait vóór main" beloven (#778)
All checks were successful
scans / scans (pull_request) Successful in 3m13s
8e037a3ec0
CONTRIBUTING, README en BUILD kregen bij #790 alle drie een absolute
formulering: "nothing runs it for you between your branch and main", "the
only thing standing between a change and main", "the assurance before main
is entirely the committer's local run". Die klopte toen precies.

Sinds scans.yml klopt ze niet meer helemaal — de geheimen- en SAST-scan
draaien wél bij elke PR. #790 schreef zelf op dat een belofte die niet
meer waar is erger is dan geen belofte; dat geldt ook in deze richting,
en juist bij een absolute formulering is de uitzondering het hele punt.

Elk van de drie krijgt daarom de uitzondering erbij, met de reden: het
zijn seconden in plaats van minuten, en bij een geheim is het moment niet
inwisselbaar. Nadrukkelijk als aanvulling op de lokale run, niet als
vervanging ervan — dat is precies de lezing die #790 wilde voorkomen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
brenno merged commit ff9b8cc577 into main 2026-07-24 15:35:25 +00:00
Sign in to join this conversation.
No description provided.