Geheimen- en SAST-scan draaien nergens automatisch, terwijl de runner er nu is #778

Closed
opened 2026-07-23 22:36:24 +00:00 by brenno · 3 comments
Owner

Wat er speelt

Sinds #741 draait make check op de Forgejo-runner, per push en per PR. Dat is
de belangrijkste poort en die staat er nu goed op.

Wat er niet in CI draait: check-secrets (gitleaks + trufflehog, werkboom
én volledige historie) en sast (semgrep). Die zitten alleen in check-full,
en check-full draait nergens automatisch.

Gevolg: of er ooit gescand is, hangt af van wie het lokaal toevallig doet. Voor
een geheim geldt dat het pas telt als het vóór de merge gevonden wordt — daarna
staat het in de historie en is intrekken de enige echte remedie.

Dit is een gat in de controle, geen bekend lek. Op 23-07-2026 draaide ik
beide handmatig op main: gitleaks en trufflehog schoon, semgrep 0 bevindingen
over 690 bestanden. Er is nu dus niets te vinden. Het punt is dat niets
garandeert dat dat zo blijft.

Waarom de oude afweging niet meer geldt

De code schrijft zijn eigen rechtvaardiging op, in
tool/check_conventions.dart bij nosemgrepBaseline:

"make sast draait niet in make check (het vraagt een externe binary), dus
een onderdrukking zou anders alleen zichtbaar zijn voor wie semgrep toevallig
geïnstalleerd heeft."

Dat klopte toen het geschreven werd. De redenering rust op één aanname — "we
kunnen geen externe binary aannemen" — en die aanname ging over de máchine van
een bijdrager. Sinds 23-07-2026 is er een runner met een eigen container, en
daar bepaal je zelf wat erin zit. De ci.yml installeert nu al nodejs, make,
git, curl, jq en unzip, plus een sha256-geverifieerde Flutter-tarball.

Het is dus geen nieuwe afweging maar een vervallen beperking.

Dezelfde redenering raakt de nosemgrep-teller zelf: die bestaat als
check_conventions-ratchet omdat semgrep niet altijd draait. Draait semgrep
wel in CI, dan mag die omweg blijven (hij is goedkoop) maar hij is niet langer
het enige vangnet.

Voorstel

Een tweede job in .forgejo/workflows/ci.yml — naast gate, niet erin:

  • apart, zodat een trage scan de poort niet vertraagt. make check duurt
    ~3 minuten; trufflehog over de hele historie deed er lokaal ~10 seconden over,
    gitleaks vergelijkbaar, semgrep een halve minuut. Dat past, maar een eigen job
    houdt de faalreden leesbaar: "de poort viel" is iets anders dan "er is een
    sleutel gevonden".
  • geen --config auto bij semgrep. De lokale regels in
    semgrep/ocideck.yaml zijn de bron; auto haalt regels over het netwerk en
    stuurt metrics mee. Het sast-doel doet dit al goed — neem het commando
    ongewijzigd over.
  • --no-verification bij trufflehog laten staan. Zonder die vlag stuurt
    trufflehog kandidaat-sleutels naar de uitgevende dienst om te zien of ze leven.
    Dat is precies het soort uitgaand verkeer dat dit project niet wil, en al
    helemaal niet vanaf een buildmachine.
  • pin de scanners op een versie, zoals de Flutter-tarball al gepind is. Een
    scanner die zichzelf bijwerkt verandert stilletjes wat de poort betekent.

Wie de drie binaries in het ubuntu:24.04-image trekt, moet ze verifiëren zoals
de Flutter-stap dat doet (checksum tegen het release-manifest), anders verplaats
je het vertrouwensprobleem naar de download.

Wat hier expliciet buiten valt

DAST (ZAP) niet. Dat blijft advisory en ongeschikt: de webbundel is
CanvasKit, en een spider komt niet door een canvas heen. Zinvol voor het
gesérveerde oppervlak (headers, CSP), en dat dekt make check-web al.

check-full in zijn geheel in CI ook niet. deps-outdated en
catalogs-outdated zijn adviserend en horen niet rood te kunnen worden op een
PR van iemand anders; die verouderen buiten je schuld.

Kosten

Een dagdeel, vrijwel alles in de workflow. Geen Dart-wijziging, geen l10n, geen
SBOM-gevolg. Wel docs/CHECKS.md bij: dat beschrijft welke poort waar draait.

Randgeval om te toetsen: een PR met een geplant testgeheim moet rood worden.
Zonder die tegenproef weet je alleen dat de job draait, niet dat hij iets ziet —
dezelfde tweerichtingstoets die semgrep/ocideck.yaml zelf al voorschrijft.

## Wat er speelt Sinds #741 draait `make check` op de Forgejo-runner, per push en per PR. Dat is de belangrijkste poort en die staat er nu goed op. Wat er **niet** in CI draait: `check-secrets` (gitleaks + trufflehog, werkboom én volledige historie) en `sast` (semgrep). Die zitten alleen in `check-full`, en `check-full` draait nergens automatisch. Gevolg: of er ooit gescand is, hangt af van wie het lokaal toevallig doet. Voor een geheim geldt dat het pas telt als het vóór de merge gevonden wordt — daarna staat het in de historie en is intrekken de enige echte remedie. **Dit is een gat in de controle, geen bekend lek.** Op 23-07-2026 draaide ik beide handmatig op main: gitleaks en trufflehog schoon, semgrep 0 bevindingen over 690 bestanden. Er is nu dus niets te vinden. Het punt is dat niets garandeert dat dat zo blijft. ## Waarom de oude afweging niet meer geldt De code schrijft zijn eigen rechtvaardiging op, in `tool/check_conventions.dart` bij `nosemgrepBaseline`: > *"`make sast` draait niet in `make check` (het vraagt een externe binary), dus > een onderdrukking zou anders alleen zichtbaar zijn voor wie semgrep toevallig > geïnstalleerd heeft."* Dat klopte toen het geschreven werd. De redenering rust op één aanname — "we kunnen geen externe binary aannemen" — en die aanname ging over de máchine van een bijdrager. Sinds 23-07-2026 is er een runner met een eigen container, en daar bepaal je zelf wat erin zit. De `ci.yml` installeert nu al nodejs, make, git, curl, jq en unzip, plus een sha256-geverifieerde Flutter-tarball. Het is dus geen nieuwe afweging maar een vervallen beperking. Dezelfde redenering raakt de `nosemgrep`-teller zelf: die bestaat als `check_conventions`-ratchet *omdat* semgrep niet altijd draait. Draait semgrep wel in CI, dan mag die omweg blijven (hij is goedkoop) maar hij is niet langer het enige vangnet. ## Voorstel Een tweede job in `.forgejo/workflows/ci.yml` — naast `gate`, niet erin: - **apart, zodat een trage scan de poort niet vertraagt.** `make check` duurt ~3 minuten; trufflehog over de hele historie deed er lokaal ~10 seconden over, gitleaks vergelijkbaar, semgrep een halve minuut. Dat past, maar een eigen job houdt de faalreden leesbaar: "de poort viel" is iets anders dan "er is een sleutel gevonden". - **geen `--config auto` bij semgrep.** De lokale regels in `semgrep/ocideck.yaml` zijn de bron; `auto` haalt regels over het netwerk en stuurt metrics mee. Het `sast`-doel doet dit al goed — neem het commando ongewijzigd over. - **`--no-verification` bij trufflehog laten staan.** Zonder die vlag stuurt trufflehog kandidaat-sleutels naar de uitgevende dienst om te zien of ze leven. Dat is precies het soort uitgaand verkeer dat dit project niet wil, en al helemaal niet vanaf een buildmachine. - **pin de scanners op een versie**, zoals de Flutter-tarball al gepind is. Een scanner die zichzelf bijwerkt verandert stilletjes wat de poort betekent. Wie de drie binaries in het `ubuntu:24.04`-image trekt, moet ze verifiëren zoals de Flutter-stap dat doet (checksum tegen het release-manifest), anders verplaats je het vertrouwensprobleem naar de download. ## Wat hier expliciet buiten valt **DAST (ZAP) niet.** Dat blijft advisory en ongeschikt: de webbundel is CanvasKit, en een spider komt niet door een canvas heen. Zinvol voor het gesérveerde oppervlak (headers, CSP), en dat dekt `make check-web` al. **`check-full` in zijn geheel in CI ook niet.** `deps-outdated` en `catalogs-outdated` zijn adviserend en horen niet rood te kunnen worden op een PR van iemand anders; die verouderen buiten je schuld. ## Kosten Een dagdeel, vrijwel alles in de workflow. Geen Dart-wijziging, geen l10n, geen SBOM-gevolg. Wel `docs/CHECKS.md` bij: dat beschrijft welke poort waar draait. Randgeval om te toetsen: een PR met een geplant testgeheim moet rood worden. Zonder die tegenproef weet je alleen dat de job draait, niet dat hij iets ziet — dezelfde tweerichtingstoets die `semgrep/ocideck.yaml` zelf al voorschrijft.
Author
Owner

Opgepakt. Tak: feat/ci-scans-778. Reikwijdte: een tweede job scans in .forgejo/workflows/ci.yml naast gate — gitleaks, trufflehog en semgrep op gepinde versies met geverifieerde download, en het bestaande make check-secrets/make sast als commando zodat lokaal en CI hetzelfde draaien. Plus docs/CHECKS.md. DAST en de adviserende doelen blijven er bewust buiten.

Opgepakt. Tak: `feat/ci-scans-778`. Reikwijdte: een tweede job `scans` in `.forgejo/workflows/ci.yml` naast `gate` — gitleaks, trufflehog en semgrep op gepinde versies met geverifieerde download, en het bestaande `make check-secrets`/`make sast` als commando zodat lokaal en CI hetzelfde draaien. Plus `docs/CHECKS.md`. DAST en de adviserende doelen blijven er bewust buiten.
Author
Owner

Correctie op de claim hierboven: de tak is nu feat/ci-scans-778-v2, PR #799. De oude tak feat/ci-scans-778 was geschreven tegen de ci.yml van vóór #796/#797 en is daarmee achterhaald — die wordt opgeruimd.

Eén afwijking van het voorstel in dit issue, bewust: het vroeg om een tweede job ín ci.yml, en dat kan niet meer. on: geldt per workflow, en ci.yml is sinds #790 de uitbrengpoort op een v*-tag. Een job daar zou pas scannen als het geheim al op main stond mét een tag eromheen. Het is daarom een eigen scans.yml geworden die op elke PR en elke push naar main vuurt — de reden voor #790 was de klok (22 minuten per PR), en deze twee doen 17 en 2 seconden.

Correctie op de claim hierboven: de tak is nu `feat/ci-scans-778-v2`, PR #799. De oude tak `feat/ci-scans-778` was geschreven tegen de `ci.yml` van vóór #796/#797 en is daarmee achterhaald — die wordt opgeruimd. Eén afwijking van het voorstel in dit issue, bewust: het vroeg om een tweede job ín `ci.yml`, en dat kan niet meer. `on:` geldt per workflow, en `ci.yml` is sinds #790 de uitbrengpoort op een `v*`-tag. Een job daar zou pas scannen als het geheim al op main stond mét een tag eromheen. Het is daarom een eigen `scans.yml` geworden die op elke PR en elke push naar main vuurt — de reden voor #790 was de klok (22 minuten per PR), en deze twee doen 17 en 2 seconden.
Author
Owner

Klaar, op main in ff9b8cc5 (PR #799).

.forgejo/workflows/scans.yml draait make check-secrets en make sast — de Makefile-doelen zelf, niet overgetypte regels — op elke PR en elke push naar main, in een ubuntu:24.04-container op de Linux-runner.

Beide triggers zijn op main geverifieerd, niet alleen aangenomen:

trigger waar uitkomst
pull_request PR #799, twee commits groen
push naar main mergecommit ff9b8cc5 groen

Afwijkingen van het voorstel in dit issue, met de reden:

  1. Geen tweede job in ci.yml maar een eigen scans.yml. Het voorstel is geschreven vóór #790/#796/#797. on: geldt per workflow, en ci.yml is inmiddels de uitbrengpoort op een v*-tag — een job daarin zou pas scannen als het geheim al op main stond mét een tag eromheen, precies te laat. Daarom een eigen bestand, dat per PR en per push vuurt: de reden voor #790 was de klok (22 minuten per PR), en deze twee doen lokaal 17 en 2 seconden.
  2. 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.

Wat het issue vroeg en wat er gebeurd is:

  • gepinde versies (8.30.1 / 3.95.9 / 1.170.0) met sha256 tegen het gepubliceerde manifest — ja, inclusief een test -n "$SHA", want grep | sha256sum -c - slaagt stíl bij een lege treffer;
  • geen --config auto, --no-verification blijft staan — ja, allebei ongewijzigd overgenomen uit de Makefile-doelen;
  • DAST en de adviserende doelen erbuiten — ja;
  • docs/CHECKS.md bij — ja, plus CONTRIBUTING, README en BUILD: die beloofden alle drie absoluut dat er niets vóór main draait, en dat klopte niet meer.

De tegenproef die het issue vroeg, in beide richtingen (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.

Meteen daarbij de meting die fetch-depth: 0 draagt, want dat was een bewering: dezelfde repo met een gecommit-en-daarna-verwijderd geheim geeft bij een volledige kloon exit 1 (gitleaks) en 183 (trufflehog), en bij --depth 1 twee keer 0. Zonder die regel meldt de historie-scan dus groen over vrijwel niets.

Wat er níét in zit:

  • De rechtvaardiging bij nosemgrepBaseline is niet weggehaald maar herschreven. Het oude argument ("make sast draait niet automatisch") is vervallen; het argument dat overeind blijft stond er niet: semgrep telt zijn eigen onderdrukkingen niet, dus die ratchet hoort in de poort die bij élke make check draait.
  • De job duurt in CI ongeveer drie minuten, vrijwel geheel installatietijd. Dat staat nu gemeten in docs/CHECKS.md (PR #801), met de cache-optie erbij als bewust nog-niet.
  • .github/workflows/ci.yml (de spiegel, die niet draait) haalt de drie scanners nog ongepind binnen via curl | sh vanaf een branch-tip — precies het patroon dat dit issue afwijst. Apart opgepakt.
Klaar, op main in `ff9b8cc5` (PR #799). `.forgejo/workflows/scans.yml` draait `make check-secrets` en `make sast` — de Makefile-doelen zelf, niet overgetypte regels — op elke PR en elke push naar main, in een `ubuntu:24.04`-container op de Linux-runner. **Beide triggers zijn op main geverifieerd, niet alleen aangenomen:** | trigger | waar | uitkomst | | --- | --- | --- | | `pull_request` | PR #799, twee commits | groen | | `push` naar main | mergecommit `ff9b8cc5` | groen | **Afwijkingen van het voorstel in dit issue, met de reden:** 1. **Geen tweede job in `ci.yml` maar een eigen `scans.yml`.** Het voorstel is geschreven vóór #790/#796/#797. `on:` geldt per workflow, en `ci.yml` is inmiddels de uitbrengpoort op een `v*`-tag — een job daarin zou pas scannen als het geheim al op main stond mét een tag eromheen, precies te laat. Daarom een eigen bestand, dat per PR en per push vuurt: de reden voor #790 was de klok (22 minuten per PR), en deze twee doen lokaal 17 en 2 seconden. 2. **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. **Wat het issue vroeg en wat er gebeurd is:** - gepinde versies (8.30.1 / 3.95.9 / 1.170.0) met sha256 tegen het gepubliceerde manifest — ja, inclusief een `test -n "$SHA"`, want `grep | sha256sum -c -` slaagt stíl bij een lege treffer; - geen `--config auto`, `--no-verification` blijft staan — ja, allebei ongewijzigd overgenomen uit de Makefile-doelen; - DAST en de adviserende doelen erbuiten — ja; - `docs/CHECKS.md` bij — ja, plus CONTRIBUTING, README en BUILD: die beloofden alle drie absoluut dat er *niets* vóór main draait, en dat klopte niet meer. **De tegenproef die het issue vroeg, in beide richtingen** (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. Meteen daarbij de meting die `fetch-depth: 0` draagt, want dat was een bewering: dezelfde repo met een gecommit-en-daarna-verwijderd geheim geeft bij een volledige kloon exit 1 (gitleaks) en 183 (trufflehog), en bij `--depth 1` twee keer 0. Zonder die regel meldt de historie-scan dus groen over vrijwel niets. **Wat er níét in zit:** - De rechtvaardiging bij `nosemgrepBaseline` is niet weggehaald maar herschreven. Het oude argument ("`make sast` draait niet automatisch") is vervallen; het argument dat overeind blijft stond er niet: semgrep telt zijn eigen onderdrukkingen niet, dus die ratchet hoort in de poort die bij élke `make check` draait. - De job duurt in CI ongeveer drie minuten, vrijwel geheel installatietijd. Dat staat nu gemeten in `docs/CHECKS.md` (PR #801), met de cache-optie erbij als bewust nog-niet. - `.github/workflows/ci.yml` (de spiegel, die niet draait) haalt de drie scanners nog ongepind binnen via `curl | sh` vanaf een branch-tip — precies het patroon dat dit issue afwijst. Apart opgepakt.
brenno 2026-07-24 15:41:37 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
LibreKAT/Ocideck#778
No description provided.