feat: laat de privacy-projectiegrens zijn eigen oppervlakken vinden (#516) #561

Merged
brenno merged 1 commit from sec/projectiegrens-generiek into main 2026-07-22 14:40:36 +00:00
Owner

Het laatste bouwbare punt uit #516: audienceBoundary generiek maken.

Wat het probleem was

SECURITY_DESIGN §8 belooft een compile-time garantie — dia-inhoud bereikt een
ontvanger alleen als AudienceDeck, en dat type is alleen via
PrivacyProjection te maken. De compiler houdt die belofte, maar alleen voor de
functies die het type ook echt eisen. Wélke functies dat zijn stond als vier
hard-gecodeerde namen. Een vijfde uitvoerkanaal werd niet gezien: precies het
fail-open dat OCIWACHT §6.0 als het te vermijden ontwerp beschrijft.

Waarom de voor de hand liggende omkering niet werkt

Verdenk elke functie die een rauwe Deck aanneemt, en je krijgt 208 parameters
over 67 bestanden. Dat is geen signaal.

Sleutelen op uitvoer levert er dertien: een functie die dia-inhoud aanneemt
én in zijn eigen body een artefact-primitief raakt (FilePicker.saveFile,
Clipboard.setData, toImage/toByteData, de atomaire schrijvers).

De kern: de poort classificeert niet, hij dwingt classificatie af

Een .ocideck-pakket draagt de bron één op één, en redigeren zou daar juist
fout zijn — §6.0 zegt met zoveel woorden dat het deck 1-op-1 naar de .md gaat.
Een PDF draagt een projectie, en een rauwe Deck zou daar een lek zijn.
Dezelfde vorm, tegengestelde eis, en geen enkele statische regel leidt dat
verschil af.

Dus doet de poort dat ook niet. Elk gevonden oppervlak moet in _registry
staan als audience of source, mét een geschreven reden. Een nieuw
uitvoerkanaal breekt de bouw tot iemand opschrijft aan welke kant het staat.
Dat is de winst tegenover vier vaste namen: niet dat de poort het antwoord
weet, maar dat hij de vraag niet meer laat overslaan.

Wat dat opleverde

Twaalf bron-getrouwe kanalen die nergens geclassificeerd stonden: het pakket,
het auditdossier, de vier sidecars, de grafiekdata, het projectbestand. Geen
van alle een lek
— ze horen de bron te dragen — maar wel twaalf plekken waar
de volgende bouwer moest raden aan welke kant hij stond.

De blinde vlek, expliciet

Een oppervlak dat het schrijven twee lagen verderop uitbesteedt en zelf alleen
strings doorgeeft, wordt niet gezien: de analyse kijkt binnen één declaratie,
niet door de aanroepgraaf heen. De laag die het primitief uiteindelijk aanraakt
wordt wél gezien, zolang die de dia-inhoud nog in handen heeft. Dat staat zo in
de kop van de poort en in docs/CHECKS.md, want een poort waarvan de reikwijdte
niet opgeschreven staat, wordt gelezen als een poort die alles ziet.

Getoetst in vier richtingen

Zoals de SAST-regels: nul op de schone repo, én alarm op een geplante
overtreding — drie soorten.

  1. Een geplant, ongeregistreerd uitvoeroppervlak → faalt.
  2. Een audience-instappunt dat een rauwe Deck terugkrijgt → faalt, met beide
    redenen apart.
  3. Een registratie die verouderd raakt door een hernoeming → faalt aan beide
    kanten (het nieuwe pad ongeregistreerd, het oude niet meer te vinden).
  4. Schone repo → 13 gevonden, 16 geclassificeerd.

Opgeruimd

audienceBoundary en zijn helpers zijn uit check_conventions.dart weg — twee
overlappende poorten is slechter dan één. Dat scheelt daar ook 89 regels.
make check, check-full, het CI-workflowbestand, CHECKS.md (eigen sectie
plus de tabel), SECURITY_DESIGN.md, ARCHITECTURE.md en
API_DOCUMENTATION.md wijzen nu allemaal naar de nieuwe poort; er staat nergens
meer een verwijzing naar de oude.

Poorten

make check groen (5622 tests, dekking 86,2%), inclusief de nieuwe poort.

Refs #516

Het laatste bouwbare punt uit #516: `audienceBoundary` generiek maken. ## Wat het probleem was SECURITY_DESIGN §8 belooft een compile-time garantie — dia-inhoud bereikt een ontvanger alleen als `AudienceDeck`, en dat type is alleen via `PrivacyProjection` te maken. De compiler houdt die belofte, maar alleen voor de functies die het type ook echt eisen. Wélke functies dat zijn stond als vier hard-gecodeerde namen. Een vijfde uitvoerkanaal werd niet gezien: precies het fail-open dat OCIWACHT §6.0 als het te vermijden ontwerp beschrijft. ## Waarom de voor de hand liggende omkering niet werkt Verdenk elke functie die een rauwe `Deck` aanneemt, en je krijgt 208 parameters over 67 bestanden. Dat is geen signaal. Sleutelen op **uitvoer** levert er dertien: een functie die dia-inhoud aanneemt én in zijn eigen body een artefact-primitief raakt (`FilePicker.saveFile`, `Clipboard.setData`, `toImage`/`toByteData`, de atomaire schrijvers). ## De kern: de poort classificeert niet, hij dwingt classificatie af Een `.ocideck`-pakket draagt de bron één op één, en redigeren zou daar juist fout zijn — §6.0 zegt met zoveel woorden dat het deck 1-op-1 naar de `.md` gaat. Een PDF draagt een projectie, en een rauwe `Deck` zou daar een lek zijn. Dezelfde vorm, tegengestelde eis, en geen enkele statische regel leidt dat verschil af. Dus doet de poort dat ook niet. Elk gevonden oppervlak moet in `_registry` staan als `audience` of `source`, mét een geschreven reden. Een nieuw uitvoerkanaal breekt de bouw tot iemand opschrijft aan welke kant het staat. Dat is de winst tegenover vier vaste namen: niet dat de poort het antwoord weet, maar dat hij de vraag niet meer laat overslaan. ## Wat dat opleverde Twaalf bron-getrouwe kanalen die nergens geclassificeerd stonden: het pakket, het auditdossier, de vier sidecars, de grafiekdata, het projectbestand. **Geen van alle een lek** — ze horen de bron te dragen — maar wel twaalf plekken waar de volgende bouwer moest raden aan welke kant hij stond. ## De blinde vlek, expliciet Een oppervlak dat het schrijven twee lagen verderop uitbesteedt en zelf alleen strings doorgeeft, wordt niet gezien: de analyse kijkt binnen één declaratie, niet door de aanroepgraaf heen. De laag die het primitief uiteindelijk aanraakt wordt wél gezien, zolang die de dia-inhoud nog in handen heeft. Dat staat zo in de kop van de poort en in `docs/CHECKS.md`, want een poort waarvan de reikwijdte niet opgeschreven staat, wordt gelezen als een poort die alles ziet. ## Getoetst in vier richtingen Zoals de SAST-regels: nul op de schone repo, én alarm op een geplante overtreding — drie soorten. 1. Een geplant, ongeregistreerd uitvoeroppervlak → faalt. 2. Een audience-instappunt dat een rauwe `Deck` terugkrijgt → faalt, met beide redenen apart. 3. Een registratie die verouderd raakt door een hernoeming → faalt aan beide kanten (het nieuwe pad ongeregistreerd, het oude niet meer te vinden). 4. Schone repo → 13 gevonden, 16 geclassificeerd. ## Opgeruimd `audienceBoundary` en zijn helpers zijn uit `check_conventions.dart` weg — twee overlappende poorten is slechter dan één. Dat scheelt daar ook 89 regels. `make check`, `check-full`, het CI-workflowbestand, `CHECKS.md` (eigen sectie plus de tabel), `SECURITY_DESIGN.md`, `ARCHITECTURE.md` en `API_DOCUMENTATION.md` wijzen nu allemaal naar de nieuwe poort; er staat nergens meer een verwijzing naar de oude. ## Poorten `make check` groen (5622 tests, dekking 86,2%), inclusief de nieuwe poort. Refs #516
feat(poort): laat de projectiegrens zijn eigen oppervlakken vinden
Some checks failed
CI / Gate (Linux) · Format · Analyze · Coverage (push) Failing after 4s
CI / Web hardening (push) Failing after 4s
CI / Docs links (push) Failing after 4s
CI / Supply-chain (Trivy · advisory) (push) Failing after 5s
CI / Gate (Linux) · Format · Analyze · Coverage (pull_request) Failing after 4s
CI / Web hardening (pull_request) Failing after 4s
CI / Docs links (pull_request) Failing after 4s
CI / Supply-chain (Trivy · advisory) (pull_request) Failing after 5s
CI / Test (macos-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Test (macos-latest) (pull_request) Has been cancelled
CI / Test (windows-latest) (pull_request) Has been cancelled
31eaeb5db9
SECURITY_DESIGN §8 belooft een compile-time garantie, en de compiler houdt
die — maar alleen voor de functies die een AudienceDeck ook echt eisen. Welke
functies dat zijn stond als vier hard-gecodeerde namen in
check_conventions.dart. Een vijfde uitvoerkanaal werd niet gezien: precies het
fail-open dat OCIWACHT §6.0 als het te vermijden ontwerp beschrijft.

De naïeve omkering levert ruis — 208 rauwe Deck-parameters over 67 bestanden.
Sleutelen op UITVOER levert er dertien: een functie die dia-inhoud aanneemt én
in zijn eigen body een artefact-primitief raakt.

De kern is dat de poort niet kan classificeren en dat ook niet probeert. Een
`.ocideck`-pakket draagt de bron één op één, en redigeren zou daar juist fout
zijn; een PDF draagt een projectie, en een rauwe Deck zou daar een lek zijn.
Dezelfde vorm, tegengestelde eis. Dus dwingt de poort de classificatie af in
plaats van hem te raden: een nieuw kanaal breekt de bouw tot iemand opschrijft
aan welke kant het staat, mét de reden.

Dat bracht twaalf bron-getrouwe kanalen aan het licht die nergens
geclassificeerd stonden — pakket, dossier, de sidecars, de projectdata. Geen
van alle een lek; wel twaalf plekken waar de volgende bouwer moest raden.

De blinde vlek staat er expliciet bij: een oppervlak dat het schrijven twee
lagen verderop uitbesteedt en zelf alleen strings doorgeeft, wordt niet gezien.

Getoetst in drie richtingen — een geplant ongeregistreerd oppervlak, een
audience-instappunt dat een rauwe Deck terugkrijgt, en een registratie die
verouderd raakt door een hernoeming — plus nul op de schone repo.

Refs #516
brenno merged commit 4234968003 into main 2026-07-22 14:40:36 +00:00
Sign in to join this conversation.
No description provided.