@@ -0,0 +1,58 @@
|
||||
# Benchmarks en kwaliteitsrapportage (VR-116)
|
||||
|
||||
## Doel
|
||||
|
||||
VR-116 levert een reproduceerbaar benchmarkpakket voor:
|
||||
|
||||
- parservelddekking;
|
||||
- deduplicatie-kwaliteit (precision/recall, false merges/missed merges);
|
||||
- rankingstabiliteit (top-N churn, onbekende-data ratio);
|
||||
- performance (p50/p95, querycount en memory peak).
|
||||
|
||||
De CLI werkt zonder live netwerk met de synthetische fixtures uit `fixtures/benchmark/`.
|
||||
|
||||
## Datasets
|
||||
|
||||
`fixtures/benchmark/quality_benchmark.json`
|
||||
|
||||
- bevat parsercases met verwachte parserkey/version en verwachte minima;
|
||||
- bevat dedupe seeds en querycases met verwachte matchlabels;
|
||||
- bevat geen echte broninhoud of persoonlijke gegevens.
|
||||
|
||||
## CLI
|
||||
|
||||
```bash
|
||||
uv run python scripts/benchmark.py --quick
|
||||
uv run python scripts/benchmark.py --jobs 25000 --top-n 25
|
||||
uv run python scripts/benchmark.py --jobs 25000 --json --top-n 25
|
||||
uv run python scripts/benchmark.py --skip-performance --quick
|
||||
```
|
||||
|
||||
## Rapportformat
|
||||
|
||||
De JSON-rapportage bevat minimaal:
|
||||
|
||||
- `parser`: dekking en onbekend-aandeel;
|
||||
- `dedupe`: precision, recall, false merges, missed merges;
|
||||
- `ranking`: top-N churn en unknown-data ratio;
|
||||
- `performance`: p50, p95, querycount, peak memory, totale duur;
|
||||
- `nfr_007`: gegraveerde metingstatus/passing van p95 < 1000 ms.
|
||||
|
||||
## Drempels en interpretatie
|
||||
|
||||
- Parser: standaard doel `coverage_ratio >= 0.90`.
|
||||
- Dedupe: standaard doel `precision >= 0.90` en `recall >= 0.90`.
|
||||
- Ranking: standaard doel `churn <= 0.35`.
|
||||
- NFR-007: enkel als `nfr_007.measured == true` wordt de p95-check als afgewerkt beoordeeld.
|
||||
|
||||
## Uitvoeringsmodus
|
||||
|
||||
- `--quick`: voert parser/dedupe/ranking uit met 250 ingestaste jobs.
|
||||
- standaardmodus: voert ook een performancepass uit op 25.000 jobs (mits runtime toelaatbaar).
|
||||
- `--skip-performance`: nuttig voor CI/quickvalidatie zonder de lange performance-run.
|
||||
|
||||
## Afwijkingen
|
||||
|
||||
Wanneer p95 of dedupe niet voldoet, rapporteert het script een status `failed` met detaildata per case.
|
||||
Die output is bedoeld als regressiebasis voor foutanalyse en threshold-sturing.
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
# Definition of Done
|
||||
|
||||
Een backlogtaak is alleen `done` wanneer alle toepasselijke punten hieronder zijn voldaan. “Code geschreven” of “werkt op mijn machine” is geen afronding.
|
||||
|
||||
## 1. Gedrag
|
||||
|
||||
- De taak voldoet aantoonbaar aan ieder acceptatiecriterium uit `docs/ai/BACKLOG.yaml`.
|
||||
- Succes-, lege-input-, fout- en herhaalpad zijn bewust ontworpen.
|
||||
- Imports, schedulertaken en notificaties zijn idempotent waar at-least-once uitvoering mogelijk is.
|
||||
- De wijziging respecteert de product-nongoals: geen platformloginbot, blokkadeomzeiling of automatische sollicitatie.
|
||||
- Ontbrekende externe services hebben een bruikbare fallback of duidelijke gedegradeerde toestand.
|
||||
|
||||
## 2. Architectuur
|
||||
|
||||
- Bedrijfslogica staat in een domeinservice; views/tasks blijven dun.
|
||||
- Adapters schrijven niet naar de database.
|
||||
- Modellen en querysets blijven user-scoped waar persoonsgegevens of gebruikersacties betrokken zijn.
|
||||
- Een nieuwe dependency heeft een concrete noodzaak, vaste versie, lockfilewijziging en operationele impactdocumentatie.
|
||||
- Een architectuurwijziging die een accepted ADR tegenspreekt krijgt eerst een nieuwe ADR.
|
||||
|
||||
## 3. Beveiliging en privacy
|
||||
|
||||
- Externe data wordt als onbetrouwbaar behandeld, gesanitized en niet als instructie uitgevoerd.
|
||||
- Netwerktoegang passeert policy- en SSRF-controle op iedere redirect.
|
||||
- Geen secret, echt persoonlijk gegeven, volledige mailboxpayload of gevoelige header staat in code, fixture, testoutput of log.
|
||||
- Autorisatie, CSRF en objectscoping zijn getest voor muterende webflows.
|
||||
- Retentie, verwijdering en back-upimpact zijn beoordeeld bij nieuwe opgeslagen data.
|
||||
- `docs/quality/THREAT_MODEL.md` is bijgewerkt voor nieuwe trust boundaries of mitigaties.
|
||||
|
||||
## 4. Datamodel en migraties
|
||||
|
||||
- `makemigrations --check --dry-run` is schoon.
|
||||
- Nieuwe migraties zijn handmatig beoordeeld en hebben een herstel-/rollbackstrategie.
|
||||
- Datamigraties zijn begrensd, herstartbaar of transactioneel waar passend.
|
||||
- Indexen en queryvormen zijn beoordeeld voor de verwachte schaal.
|
||||
- Historiek/provenance blijft behouden bij normalisatie- of dedupewijzigingen.
|
||||
|
||||
## 5. Tests
|
||||
|
||||
- Unit-tests dekken pure regels en randgevallen.
|
||||
- Integratietests dekken database-, pipeline- en idempotentiegedrag.
|
||||
- Securitytests dekken negatieve inputs voor securitykritieke wijzigingen.
|
||||
- Externe formaten hebben gesaneerde fixtures; standaardtests doen geen internetcall.
|
||||
- Bugs krijgen een regressietest die vóór de fix faalt.
|
||||
- Totale branch-aware dekking blijft minstens 70%; securitykritieke services streven naar 90%+ relevante paden.
|
||||
|
||||
## 6. UX en toegankelijkheid
|
||||
|
||||
- UI-copy is begrijpelijk Nederlands en maakt feit/inferentie/onbekend onderscheid.
|
||||
- Kernflow werkt met toetsenbord, zichtbare focus en zonder JavaScript.
|
||||
- Labels, foutmeldingen, headingstructuur en statusmeldingen zijn semantisch correct.
|
||||
- Layout blijft bruikbaar op 360 px breedte en gangbare desktopbreedte.
|
||||
- Reduced motion, contrast en niet-kleurgebonden statussignalen zijn behouden.
|
||||
|
||||
## 7. Documentatie en traceability
|
||||
|
||||
- Publieke/internal contracts, runbooks en configuratievoorbeelden zijn bijgewerkt.
|
||||
- Requirement- en acceptatie-ID's zijn gekoppeld in `TRACEABILITY_MATRIX.md`.
|
||||
- Backlogtaak bevat een korte resultaatnotitie en exacte verificatie.
|
||||
- `PROJECT_STATE.md` noemt de afgeronde taak, impact, gate-uitkomst en volgende taak.
|
||||
- Geen document claimt functionaliteit die alleen gepland is.
|
||||
|
||||
## 8. Verificatie
|
||||
|
||||
De volledige gate slaagt vanaf de repositoryroot:
|
||||
|
||||
```bash
|
||||
./scripts/codex_verify.sh
|
||||
```
|
||||
|
||||
Daarbij slagen minimaal:
|
||||
|
||||
- Ruff;
|
||||
- Django system check;
|
||||
- migratiecheck;
|
||||
- volledige testset met dekkingsdrempel;
|
||||
- backlogvalidatie;
|
||||
- documentlink-/configuratievalidatie voor zover in het script opgenomen.
|
||||
|
||||
## 9. Extern geblokkeerd
|
||||
|
||||
Een taak wordt niet `done` wanneer live verificatie noodzakelijk maar onmogelijk is. Het externe restpunt mag `blocked-external` worden nadat interface, mocks, tests, foutafhandeling, configuratie en een exact uitvoerchecklistje zijn afgemaakt. Onafhankelijke taken gaan daarna door.
|
||||
@@ -0,0 +1,60 @@
|
||||
# Releasechecklist
|
||||
|
||||
## Code en requirements
|
||||
|
||||
- [ ] alle voor de release geplande backlogtaken staan `done`;
|
||||
- [ ] geen `ready` taak is stilzwijgend overgeslagen;
|
||||
- [ ] `PROJECT_STATE.md`, changelog en traceability zijn actueel;
|
||||
- [ ] nieuwe/gewijzigde requirements hebben acceptatiecriteria en tests;
|
||||
- [ ] geen geplande functionaliteit wordt als geïmplementeerd beschreven.
|
||||
|
||||
## Quality gate
|
||||
|
||||
```bash
|
||||
./scripts/codex_verify.sh
|
||||
```
|
||||
|
||||
- [ ] Ruff schoon;
|
||||
- [ ] Django check schoon;
|
||||
- [ ] geen ontbrekende migraties;
|
||||
- [ ] alle tests geslaagd;
|
||||
- [ ] coverage boven drempel;
|
||||
- [ ] backlog en documentlinks geldig;
|
||||
- [ ] Compose YAML parseert;
|
||||
- [ ] containerbuild/smoke-test uitgevoerd op releaseomgeving.
|
||||
|
||||
## Security/privacy
|
||||
|
||||
- [ ] threat model en securitytests bijgewerkt;
|
||||
- [ ] dependency-/image-/secret-scan beoordeeld;
|
||||
- [ ] geen echte credentials of PII in repository, fixtures of artifact;
|
||||
- [ ] debug uit in productievoorbeeld;
|
||||
- [ ] source denylist en strict policy behouden;
|
||||
- [ ] retentie en back-upimpact gecontroleerd;
|
||||
- [ ] geen submit-, loginbot- of CAPTCHA-code toegevoegd.
|
||||
|
||||
## Database en upgrade
|
||||
|
||||
- [ ] migraties handmatig beoordeeld;
|
||||
- [ ] upgrade vanaf vorige ondersteunde release getest;
|
||||
- [ ] back-up vóór migratie gemaakt en checksum geverifieerd;
|
||||
- [ ] rollback/herstelpad getest of expliciet gedocumenteerd;
|
||||
- [ ] vorige immutable image beschikbaar.
|
||||
|
||||
## UX
|
||||
|
||||
- [ ] dashboard, lijst, detail, profiel, bronnen en sollicitaties gesmoked;
|
||||
- [ ] keyboard/focus en 360 px layout gecontroleerd;
|
||||
- [ ] foutmeldingen en lege toestanden begrijpelijk;
|
||||
- [ ] digest in tekst en HTML beoordeeld;
|
||||
- [ ] geen externe tracking of onverwachte third-party assets.
|
||||
|
||||
## Deployment
|
||||
|
||||
- [ ] image krijgt semantische tag en immutable digest;
|
||||
- [ ] release-notes noemen config/migratie/breaking changes;
|
||||
- [ ] healthchecks slagen;
|
||||
- [ ] precies één scheduler actief;
|
||||
- [ ] PostgreSQL, Redis en Ollama niet publiek bereikbaar;
|
||||
- [ ] monitoring en back-upjob actief;
|
||||
- [ ] live source/IMAP blijft uit tot credentials en bronreview gereed zijn.
|
||||
@@ -0,0 +1,145 @@
|
||||
# Teststrategie
|
||||
|
||||
## Doel
|
||||
|
||||
Tests bewijzen dat VacatureRadar veilig herhaalbaar verzamelt, betrouwbare canonieke data maakt, uitlegbaar scoort en zonder externe services blijft functioneren. De standaardtestset is snel, deterministisch en offline.
|
||||
|
||||
## Testpiramide
|
||||
|
||||
### Unit
|
||||
|
||||
Pure functies en begrensde services:
|
||||
|
||||
- URL-validatie en canonicalisatie;
|
||||
- source policy en denylist;
|
||||
- adapterextractie uit fixtures;
|
||||
- HTML-sanitization;
|
||||
- normalisatie van titel, contract, locatie en datums;
|
||||
- feature-extractie, distance fallback en scoring;
|
||||
- AI-schema/parsing/fallback;
|
||||
- profielgewichten en feedbackgrenzen.
|
||||
|
||||
Doel: veel kleine tests, geen echte netwerkcall en alleen database wanneer het objectgedrag zelf wordt getest.
|
||||
|
||||
### Integratie
|
||||
|
||||
Meerdere componenten met testdatabase:
|
||||
|
||||
- raw document → adapter → normalisatie → dedupe → provenance → score;
|
||||
- replay/idempotentie en vacatureversies;
|
||||
- IMAP/e-mailrecording via gesimuleerde berichten;
|
||||
- digest-outbox en mailbackend;
|
||||
- lifecycle en sollicitatiedossier;
|
||||
- Django-views, login, user-scoping en POST-acties;
|
||||
- Celerytasks in eager mode.
|
||||
|
||||
### Security
|
||||
|
||||
Negatieve tests voor trust boundaries:
|
||||
|
||||
- loopback, private, link-local, encoded/credentialed en onverwachte URL's;
|
||||
- redirecthercontrole;
|
||||
- denylistplatformen;
|
||||
- contenttype/grootte;
|
||||
- XSS/sanitization en onveilige links;
|
||||
- prompt-injectionachtige vacaturetekst;
|
||||
- cross-user objecttoegang;
|
||||
- secret-/payloadlekken in foutpaden waar praktisch testbaar.
|
||||
|
||||
### Browser/e2e
|
||||
|
||||
Gepland in backlogtaak `VR-114`. Gebruik een lokale testserver en seeded data, geen live bron. Minimale flows:
|
||||
|
||||
1. aanmelden;
|
||||
2. dashboard openen;
|
||||
3. profiel wijzigen en revisie zien;
|
||||
4. vacature zoeken/openen;
|
||||
5. interessant/verbergen/gesolliciteerd;
|
||||
6. sollicitatiedossier bijwerken;
|
||||
7. bronstatus bekijken;
|
||||
8. toetsenbord- en basisaccessibilityscan.
|
||||
|
||||
Browsertests zijn aanvullend; zij vervangen geen service- of autorisatietests.
|
||||
|
||||
### Release- en deploymenttests
|
||||
|
||||
- Dockerfile buildt zonder ontwikkelbestanden/secrets;
|
||||
- container start als niet-rootgebruiker;
|
||||
- migraties en `collectstatic` slagen;
|
||||
- liveness/readiness reageren correct;
|
||||
- Composeconfiguratie parseert;
|
||||
- PostgreSQL/Redisstack verwerkt één fixture en digest;
|
||||
- back-up en restore zijn op een tijdelijke omgeving getest.
|
||||
|
||||
Deze laag kan in CI of een releasejob draaien zodra een Dockerdaemon beschikbaar is.
|
||||
|
||||
## Fixtures
|
||||
|
||||
Directoryindeling:
|
||||
|
||||
```text
|
||||
fixtures/pages/ HTML/JSON-LD
|
||||
fixtures/feeds/ RSS/Atom/sitemaps
|
||||
fixtures/emails/ RFC822-berichten
|
||||
fixtures/golden/ verwachte gestructureerde output
|
||||
```
|
||||
|
||||
Regels:
|
||||
|
||||
- fictieve werkgevers/personen en `example.*`-domeinen;
|
||||
- alleen het minimum aan vacaturetekst;
|
||||
- geen cookies, tokens, echte Message-ID's of persoonlijke adressen;
|
||||
- bronvariant en doel van fixture in testnaam of korte comment;
|
||||
- grote regressiepayloads waar mogelijk reduceren tot minimale reproducer.
|
||||
|
||||
## Netwerkisolatie
|
||||
|
||||
Geen test mag standaard internet vereisen. Patch `httpx`, DNS-resolutie, IMAP, SMTP en Ollama aan de boundary. Een test die per ongeluk live netwerk gebruikt, is een testfout. Eventuele live smoke-tests krijgen een aparte marker, expliciete environmentflag en draaien nooit in de standaard-CI.
|
||||
|
||||
## Dekkingsbeleid
|
||||
|
||||
`pyproject.toml` vereist minimaal 70% branch-aware totaal. Dekking is een vangnet, geen doel op zich:
|
||||
|
||||
- fetcher, URL-security, policy, sanitization, authscoping en automatische acties: alle belangrijke negatieve paden;
|
||||
- parsers: iedere ondersteunde variant plus malformed/lege input;
|
||||
- scoring/dedupe: beslisdrempels en tie-breakers;
|
||||
- triviale adminregistratie en migratiecode mogen uit de meting blijven.
|
||||
|
||||
Verlaag de drempel niet voor een taak. Voeg tests toe of documenteer en verwijder aantoonbaar dode code.
|
||||
|
||||
## Testdata en tijd
|
||||
|
||||
- Gebruik timezone-aware vaste datums of `timezone.now()` relatief binnen de test.
|
||||
- Vermijd assertions die na middernacht lokale tijd flaken.
|
||||
- Randomized/propertytests gebruiken een vaste seed en melden die bij falen.
|
||||
- Volgorde-onafhankelijkheid: iedere test maakt eigen state via fixtures/factories.
|
||||
|
||||
## Performance
|
||||
|
||||
Voor `NFR-007` komt een reproduceerbaar benchmarkscript in `VR-116` met minstens:
|
||||
|
||||
- 25.000 canonieke vacatures;
|
||||
- meerdere aliassen en scoreruns;
|
||||
- dashboard/list/detailqueries;
|
||||
- importbatch en rescore;
|
||||
- p50/p95, querycount en geheugengebruik.
|
||||
|
||||
Een performanceclaim wordt alleen in documentatie opgenomen met hardwareprofiel, dataset en meetcommando.
|
||||
|
||||
## Uitvoercommando's
|
||||
|
||||
```bash
|
||||
uv run pytest tests/unit
|
||||
uv run pytest tests/integration
|
||||
uv run pytest tests/security
|
||||
uv run pytest --cov=apps --cov=config --cov-report=term-missing
|
||||
./scripts/codex_verify.sh
|
||||
```
|
||||
|
||||
## Bugworkflow
|
||||
|
||||
1. Reproduceer met kleinste betrouwbare fixture/test.
|
||||
2. Laat de test falen op de huidige code.
|
||||
3. Herstel bij de laag waar de regel hoort.
|
||||
4. Draai relevante tests en daarna de volledige gate.
|
||||
5. Werk threat model/runbook bij wanneer het een security- of operationeel defect was.
|
||||
@@ -0,0 +1,140 @@
|
||||
# Threat model
|
||||
|
||||
## Scope en assets
|
||||
|
||||
Te beschermen:
|
||||
|
||||
- gebruikersaccount, sessies en zoekvoorkeuren;
|
||||
- mailbox-, SMTP-, database- en registrycredentials;
|
||||
- sollicitatiedossiers, notities en eventuele documenten;
|
||||
- integriteit van vacatureclusters, scores en feedback;
|
||||
- beschikbaarheid van de Unraid-host en het thuisnetwerk;
|
||||
- bronbeleid en bewijs dat alleen toegestane bronnen worden benaderd.
|
||||
|
||||
Niet vertrouwd:
|
||||
|
||||
- iedere vacaturetekst, HTML, JSON-LD, feed en e-mail;
|
||||
- alle links en redirectdoelen;
|
||||
- externe DNS/HTTP/TLS-responses;
|
||||
- AI-modeloutput, ook lokaal;
|
||||
- browserinput en handmatige URL's;
|
||||
- logs of exports die buiten de applicatie worden geopend.
|
||||
|
||||
## Trust boundaries
|
||||
|
||||
```text
|
||||
Internet/mailbox
|
||||
-> URL/source policy + IMAP boundary
|
||||
-> raw document quarantine/retention
|
||||
-> parser + sanitizer
|
||||
-> normalized domain model
|
||||
-> deterministic rules/scoring
|
||||
-> authenticated UI / digest
|
||||
|
||||
User browser
|
||||
-> TLS/reverse proxy
|
||||
-> Django session + CSRF + object scoping
|
||||
-> database
|
||||
|
||||
Django/Celery
|
||||
-> Redis (queue, geen waarheid)
|
||||
-> PostgreSQL (bron van waarheid)
|
||||
-> optionele Ollama boundary
|
||||
```
|
||||
|
||||
## Belangrijkste dreigingen en mitigaties
|
||||
|
||||
| ID | Dreiging | Impact | Mitigaties | Verificatie |
|
||||
|---|---|---|---|---|
|
||||
| T-01 | SSRF via bron- of vacature-URL | toegang tot LAN, metadata of beheerinterfaces | schema/host/IP/poortcontrole, DNS-resolutie, redirecthercontrole, denylist, geen credentials in URL | `tests/security/test_url_security.py`, `test_policy.py`, fetchertests |
|
||||
| T-02 | DNS rebinding/tijd-van-controle | request bereikt ander IP dan beoordeeld | iedere fetch en redirect valideert opnieuw DNS-resolutie en vereist consistente IP-set-overlap | `VR-115`, `tests/unit/test_fetcher.py`, aanvullende fetcher negative tests |
|
||||
| T-03 | XSS/HTML-injectie | sessiediefstal of ongewenste navigatie | Bleach allowlist, platte tekst, template autoescaping, CSP/securityheaders | `tests/security/test_sanitize.py`, viewtests |
|
||||
| T-04 | Prompt injection in vacature | AI verandert beleid of voert tools uit | vacaturetekst in data-envelope, schema-output, evidence-validatie, cachefouten met foutcategorie, geen toolrechten, deterministische harde regels, AI optioneel | AI-tests, ADR-0003, `VR-109` evaluaties |
|
||||
| T-05 | Malafide/oversized document | geheugen/CPU/diskuitputting | contenttype-, byte-, timeout- en redirectlimieten; korte retentie | fetchertests, source-runmetrics |
|
||||
| T-06 | Crawlstorm of ban | externe overlast, IP-blokkade | expliciet allowbeleid, per-origin minimuminterval, concurrencylimiet, leasegebaseerde taakclaim met TTL + crash recovery, conditional requests, backoff, quarantaine | tasktests; `VR-103`, `VR-112` |
|
||||
| T-07 | Direct platformscrapen | voorwaarden-/blokkaderisico | centrale denylist, e-mailingress, geen loginbot/CAPTCHA | policytests, ADR-0002/0005 |
|
||||
| T-08 | E-mailparserlink naar phishing/private host | ongewenste fetch of gebruiker misleid | linkextractie slaat unsubscribe over, follow-up opnieuw door policy/SSRF, bronlabel zichtbaar | e-mail- en policytests |
|
||||
| T-09 | MIME/HTML-bom of malformed mail | resource-uitputting/parsercrash | IMAPbatchlimiet, bodylimiet bij vervolgtaak, robuuste parser, idempotente recordidentiteit | `VR-115`, e-mailfixtures |
|
||||
| T-10 | Cross-user objecttoegang | lek van sollicitaties/feedback | LoginRequired, user-scoped querysets/get_or_create, autorisatietests | integratie-viewtests |
|
||||
| T-11 | CSRF op feedback/profiel | ongewenste status- of profielmutatie | Django CSRF-middleware, POST-only acties, SameSitecookies | viewtests en frameworkcheck |
|
||||
| T-12 | Credentiallek in Git/logs | account- of infrastructuurcompromis | env-only secrets, gitignore, beperkte logs, voorbeeldwaarden, secretrotatierunbook | CI-secret scan gepland `VR-115`; review |
|
||||
| T-13 | Onveilige reverse proxy | sessie over HTTP, host-header-/originproblemen | TLS, exact ALLOWED_HOSTS/CSRF origins, secure cookies, proxychecklist | deployment smoke-test |
|
||||
| T-14 | Redis als waarheid behandeld | dataverlies/dubbele verwerking | PostgreSQL-state, idempotente taken/outbox, acks-late | integratietests |
|
||||
| T-15 | Dubbele Celery-uitvoering | dubbele vacatures/mails | unieke keys, transacties, message identity, outbox-uniciteit | pipeline/digesttests |
|
||||
| T-16 | Dedupe voegt verschillende jobs samen | gemiste kans/verkeerde data | exact vóór fuzzy, conservatieve drempel, bronaliassen/provenance, herstelbare clusterbeslissing gepland | dedupetests; `VR-116` evaluaties |
|
||||
| T-17 | AI hallucineert ontbrekend feit | foutieve ranking | onbekend blijft onbekend, evidence/confidence, geen hard exclusion door AI | scoring/AI-tests |
|
||||
| T-18 | Feedback poisoning/self-reinforcement | steeds smallere resultaten | begrensde gewichten, opt-in standaard uit, per-feature minimum samples, metadata-logging en resetpad | profieltests; `VR-110` |
|
||||
| T-19 | Automatisch solliciteren/massamail | reputatie/privacy/juridisch risico | geen submitendpoint/task, expliciete ADR en non-goal | codezoekreview, AC-043 |
|
||||
| T-20 | Kwaadaardig bestand in sollicitatiedossier | host/browsercompromis | uploads nog niet actief; vóór implementatie allowlist, sniffing, size limit, niet-uitvoerbare opslag vereist | `VR-113`, nieuwe threat review |
|
||||
| T-21 | Back-up bevat secrets/PII | langdurig datalek | encryptie, gescheiden opslag, korte retentie, herstelprocedure | runbook en hersteltest |
|
||||
| T-22 | Supply-chainpackage/image | code execution | exacte versies/lockfile, beperkte dependencies, pinned baseimages/digests en scans gepland | CI, `VR-115` |
|
||||
| T-23 | Onbevoegde admin op thuisnetwerk | volledige datatoegang | uniek wachtwoord, TLS/VPN, geen defaultcredentials, sessiebeveiliging | Unraidchecklist |
|
||||
| T-24 | Source terms wijzigen | ongewenste voortgezette crawling | reviewdatum, source health en policy expiry gepland | `VR-102`, `VR-112` |
|
||||
| T-31 | Sollicitatiedossier-export bevat niet-gewenste payload | data-lek of onbedoeld dossieroverdragen | export bevat alleen het gekozen dossier, ZIP-inhoud is beperkt tot snapshot/tijdlijn/print-HTML, bestandsnaam is geslugified zonder padseparators | `tests/integration/test_applications.py` |
|
||||
|
||||
## Misbruikscenario's
|
||||
|
||||
### Vacature zegt “negeer eerdere instructies”
|
||||
|
||||
De tekst wordt gesanitized en als veldwaarde doorgegeven. Een eventuele AI-call krijgt een vast schema en geen tools. De output kan geen bron activeren, URL openen, harde regel verwijderen, mail sturen of sollicitatie indienen.
|
||||
|
||||
### Publieke pagina redirect naar `192.168.1.1`
|
||||
|
||||
De redirectlocatie wordt opnieuw gevalideerd. Het request naar het private adres wordt niet uitgevoerd; de bronrun krijgt een policy/securityfout en de bron kan in quarantaine gaan.
|
||||
|
||||
### E-mailalert bevat een platformlink en uitschrijflink
|
||||
|
||||
De adapter herkent vacaturekandidaten, negeert bekende unsubscribepatronen en slaat de platformlink hoogstens als alias op. Automatisch volgen vereist opnieuw een toegestane source policy; denylistplatformen worden geweigerd.
|
||||
|
||||
### Aanvaller laat scheduler dezelfde job herhalen
|
||||
|
||||
Canonieke sleutels, databaseconstraints, transacties, idempotente message identity en outboxuniciteit beperken duplicaten. Taken zijn ontworpen voor at-least-once in plaats van exact-once aannames.
|
||||
|
||||
## Security gates bij nieuwe functionaliteit
|
||||
|
||||
Een wijziging aan netwerk, mail, AI, rendering, auth, exports of uploads vereist:
|
||||
|
||||
1. nieuwe/gewijzigde threat in deze tabel;
|
||||
2. negatieve test die de aanval representeert;
|
||||
3. begrensde input/output en foutcategorie;
|
||||
4. logreview op secrets/PII;
|
||||
5. runbook- en configuratie-update;
|
||||
6. volledige `codex_verify`-gate.
|
||||
|
||||
## Resterende risico's
|
||||
|
||||
- Een applicatielaag kan DNS rebinding niet volledig uitsluiten zonder transportniveau-IP-pinning; dit staat in `VR-115`.
|
||||
- Brute-force of herhaalde foutieve mutatiepogingen blijven mogelijk, maar zijn beperkt door in-memory rate limiting en blokkades op login/manual-import.
|
||||
- Bronvoorwaarden vereisen menselijke/externe review per domein; automatisering kan dat niet juridisch beslissen.
|
||||
- Fuzzy dedupe en featureheuristieken kunnen inhoudelijk verkeerd zijn; provenance, feedback en benchmarkevaluaties beperken maar elimineren dit niet.
|
||||
- Een persoonlijke Unraid-host blijft afhankelijk van correcte netwerksegmentatie, patching en back-ups door de beheerder.
|
||||
|
||||
- T-25: Verloren of verlopen policyreview
|
||||
- Impact: bron kan op onbedoelde wijze doorgaan met crawlen
|
||||
- Mitigatie: `SourcePolicyReview` met decision/expiry + policy gate in `assess_url`
|
||||
- Verificatie: security/integration tests rond verlopen review in fail-closed gedrag
|
||||
|
||||
- T-26: Handmatige URL/tekstimport
|
||||
- Impact: ongewild ophalen van geblokkeerde of niet-ingesteste informatie, XSS via ingevulde tekst of overschrijding van limieten
|
||||
- Mitigatie: CSRF-only import endpoint, allowlist-domeinvrije policy checks, sanitize op tekstveld, byte-limiet en max-size/timeout gedrag
|
||||
- Verificatie: integration/security tests rond rejectie van geblokkeerde URL's en overschrijding van paste-limiet
|
||||
|
||||
- T-27: Reminder-flood of dubbele reminder-mails
|
||||
- Impact: gebruiker ontvangt herhaalde of ongewenste herinneringen
|
||||
- Mitigatie: stabiele `dedupe_key`, idempotente outbox met statusmachine, `reminder_type`-types en task-driven verzending
|
||||
- Verificatie: `tests/integration/test_reminders.py`
|
||||
|
||||
- T-28: Onterecht verzenden zonder ontvanger/uitgeschakelde reminderinstelling
|
||||
- Impact: onnodige fout- of testmails, verwarring over afmeldgedrag
|
||||
- Mitigatie: master- en topmatchschakelaar per profiel, `SKIPPED`-status bij lege ontvanger en foutlogica met retries op taakniveau
|
||||
- Verificatie: `tests/integration/test_reminders.py`
|
||||
|
||||
- T-29: Bronhealth zet bronnen te vroeg in quarantaine bij incidentele netwerkruis
|
||||
- Impact: tijdelijke uitval of incidentele bronfouten blokkeren een gezonde bron
|
||||
- Mitigatie: duidelijke foutcategoriedrempels, gescheiden policy/security- en tijdelijke-foutlogica, en canaryherstel via trialpad
|
||||
- Verificatie: `tests/integration/test_source_health.py`
|
||||
|
||||
- T-30: Geautomatiseerde canaryherstel blijft onbegrensd draaien
|
||||
- Impact: herhaalde herstarts van dezelfde bron veroorzaken extra belasting
|
||||
- Mitigatie: cooldown plus metadataflag voor eenmalige canary, en trialstatus met beperkte runtrigger
|
||||
- Verificatie: `tests/integration/test_source_health.py`
|
||||
@@ -0,0 +1,91 @@
|
||||
# Traceabilitymatrix
|
||||
|
||||
Legenda: **I** = geïmplementeerd en getest in de huidige MVP; **P** = gedeeltelijk/volgende backlogtaak; **E** = alleen externe productieconfiguratie of bronreview ontbreekt. Bestandsnamen verwijzen naar de primaire implementatie; aanvullende tests kunnen in dezelfde testdirectory staan.
|
||||
|
||||
## Functionele requirements
|
||||
|
||||
| ID | Status | Primaire implementatie | Bewijs/tests | Vervolgtaak |
|
||||
|---|---|---|---|---|
|
||||
| PR-001 | I | `profiles/models.py`, forms/views | `test_profiles.py`, `test_views.py` | — |
|
||||
| PR-002 | I | `SearchProfile`, defaults/form, geocodeparser | `tests/unit/test_geocoding.py`, `tests/integration/test_import_geodata.py`, profiel- en viewtests | VR-105 verfijnt afstand |
|
||||
| PR-003 | I | `ProfileRevision`, profile services | `test_profiles.py` | — |
|
||||
| PR-004 | I | begrensde feedbackservice/velden | `tests/unit/test_feedback_learning.py`, `test_profiles.py` | VR-110 uitgevoerd |
|
||||
| PR-005 | I | `bootstrap_instance`, defaults | task/viewtests | — |
|
||||
| PR-010 | I | `sources/models.py` | `test_source_models.py` | VR-112 breidt health uit |
|
||||
| PR-011 | I | policy + fetch task | policy/fetch/tasktests | — |
|
||||
| PR-012 | I | denylist, e-mailadapter | policy/e-mailtests | — |
|
||||
| PR-013 | I | `url_security.py`, redirectfetcher | security URL/fetchtests | VR-115 transporthardening |
|
||||
| PR-014 | I | `fetcher.py` | `test_fetcher.py` | — |
|
||||
| PR-015 | I | `SourceLease`, `SourceOriginState`, `apps/sources/services/scheduling.py`, `apps/sources/tasks.py` | `test_scheduling.py`, `test_fetcher.py`, `test_tasks_and_more_views.py` | `VR-103` afgerond |
|
||||
| PR-016 | I | `email_import.py`, recordmodel | e-mailintegratietests | — |
|
||||
| PR-017 | I | candidate/status + basisdiscovery | `apps/sources/services/discovery.py`, `tests/unit/test_discovery_rss.py`, `tests/integration/test_discovery_command.py`, `tests/integration/test_tasks_and_more_views.py` | VR-101/102 |
|
||||
| PR-018 | I | `apps/sources/services/health.py`, `apps/sources/tasks.py` | `tests/integration/test_source_health.py` | VR-112 |
|
||||
| PR-020 | I | `JsonLdJobPostingAdapter` | JSON-LD-tests/fixtures | — |
|
||||
| PR-021 | I | HTML/RSS/e-mailadapters + apps/sources/adapters/ats.py + tests/unit/test_ats_adapters.py | adaptertests + tests/unit/test_ats_adapters.py | VR-106 afgerond |
|
||||
| PR-022 | I | `adapters/base.py` | contract via alle adaptertests | — |
|
||||
| PR-023 | I | `sanitize.py` | security sanitizationtests | — |
|
||||
| PR-024 | I | `ExtractedJob`, `CanonicalJobDraft`, models | pipeline/normalisatietests | — |
|
||||
| PR-025 | I | `JobVersion` in pipeline | dedupe/lifecycle-integratietest | — |
|
||||
| PR-026 | I | `RawDocument`, `apps/sources/tasks.py`, `config/settings.py` | `tests/integration/test_source_health.py` | VR-112/115 operationaliseert |
|
||||
| PR-027 | I | `FieldProvenance` | pipeline-integratietests | — |
|
||||
| PR-030 | I | `dedupe.py` | dedupetests | — |
|
||||
| PR-031 | I | conservatieve fuzzy dedupe | `tests/unit/test_dedupe_lifecycle_feedback.py`, `scripts/benchmark.py`, `tests/benchmark/test_benchmark.py` | VR-116 benchmark |
|
||||
| PR-032 | I | direct-sourcepreferentie/alias | pipeline- en dedupetests | VR-108 resolver |
|
||||
| PR-033 | I | canonical constraints/transacties | replaytests | — |
|
||||
| PR-040 | I | features/scoring | scoringtests | — |
|
||||
| PR-041 | I | scorecomponenten | `tests/unit/test_features_distance.py`, `tests/unit/test_scoring.py` | VR-105 afgerond |
|
||||
| PR-042 | I | unknown/confidencegedrag | `tests/unit/test_features_distance.py`, `tests/unit/test_scoring.py` | VR-105 |
|
||||
| PR-043 | I | `ScoreRun` | pipeline/scoringtests | — |
|
||||
| PR-044 | I | profiel/modelversievelden | scoring/profiletests | VR-109 promptversie |
|
||||
| PR-045 | I | optionele Ollamaservice/fallback | `test_ai.py` | VR-109 |
|
||||
| PR-046 | I | geen tools + guardrails | AI/securitytests | VR-109/115 evaluaties |
|
||||
| PR-050 | I | dashboard view/template | viewtests | VR-114 e2e/a11y |
|
||||
| PR-051 | I | detailview/template/provenance | viewtests | VR-114 |
|
||||
| PR-052 | I | feedbackendpoint/UI | feedback/viewtests | — |
|
||||
| PR-053 | I | applicationmodel/serviceflow | `tests/integration/test_dedupe_lifecycle_feedback.py`, `tests/integration/test_applications.py` | VR-113 uitgebreid dossier |
|
||||
| PR-054 | I | `notifications/models.py`, outbox/services/tasks | `tests/integration/test_email_import_notifications.py`, `tests/integration/test_reminders.py` | VR-111 |
|
||||
| PR-055 | I | lifecycle service/task | lifecycletests | — |
|
||||
| PR-056 | I | expliciete non-goal; geen submitcontract | AC-043 code review, ADR-0006 | — |
|
||||
| PR-060 | I | health views/service | view/healthtests | — |
|
||||
| PR-061 | I | `apps/sources/services/health.py`, `apps/sources/tasks.py` | `tests/integration/test_source_health.py` | VR-112 dashboard/metrics |
|
||||
| PR-062 | I | `scripts/release_verify.sh`, `scripts/release_smoke.py`, `docker-compose*.yml` | `release-verificatie-smoke`, `configdiff` en upgrade/rollbackartefacten | VR-117 afgerond |
|
||||
| PR-063 | I | AI standaard uit/fallback | volledige testset zonder Ollama | — |
|
||||
| PR-064 | I | settings/env-example/gitignore | configreview en CI | VR-115 secretscan |
|
||||
|
||||
## Niet-functionele requirements
|
||||
|
||||
| ID | Status | Bewijs | Vervolgtaak |
|
||||
|---|---|---|---|
|
||||
| NFR-001 | I | policy-, URL- en fetchersecuritytests + settings/rate-limit tests | `tests/unit/test_fetcher.py`, `tests/unit/test_rate_limit.py`, `tests/unit/test_settings_security.py`, `tests/integration/test_views.py`, `tests/integration/test_sources_manual_import.py` |
|
||||
| NFR-002 | P | raw-retentie, minimale modellen, privacyrunbooks | VR-113/115 |
|
||||
| NFR-003 | I/P | replay-, mail- en outboxtests; per-bronfouten | VR-103/112 |
|
||||
| NFR-004 | I | ScoreRun, provenance, UI-copy | VR-109 uitgebreid evidence |
|
||||
| NFR-005 | I | domeinapps/services/adapters/ADRs | continue review |
|
||||
| NFR-006 | I | offline pytest + coveragegate | VR-114 verbreedt e2e |
|
||||
| NFR-007 | P | `scripts/benchmark.py`, `tests/benchmark/test_benchmark.py` | VR-116 |
|
||||
| NFR-008 | I | semantische templates/designspec | `tests/e2e/test_vr114_browser_and_accessibility.py` |
|
||||
| NFR-009 | I | lokale SQLite en Docker/Unraidconfig, release-smoke en restore | VR-117 afgerond |
|
||||
| NFR-010 | I | `apps/sources/services/health.py`, `apps/sources/tasks.py`, `apps/core/views.py`, `config/settings.py` | `tests/integration/test_source_health.py` | VR-112 observability |
|
||||
|
||||
## Systeemacceptatie
|
||||
|
||||
| Criteria | Status | Primair bewijs |
|
||||
|---|---|---|
|
||||
| AC-001–004 | I | bootstrap, auth/UI, e-mailingress zonder platformlogin |
|
||||
| AC-010–015 | I | integration/security/adaptertests |
|
||||
| AC-020–025 | I | normalisatie-, dedupe-, scoring- en AI-fallbacktests |
|
||||
| AC-030–034 | I | notificatie- en lifecycletests |
|
||||
| AC-040–043 | I | application/feedback/user-scopingtests en ADR-0006 |
|
||||
| AC-050–054 | I | health/viewtests, verify-script, offline fixtures, coverage en ledger-validator |
|
||||
| AC-055 | I | `scripts/release_verify.sh` met release-smoke en restore-compare | VR-117 afgerond |
|
||||
|
||||
## Onderhoudsregel
|
||||
|
||||
Iedere backlogtaak die een requirement wijzigt, werkt in dezelfde commit deze matrix, relevante acceptatiecriteria en tests bij. Een status wordt alleen naar **I** gezet wanneer de code én het genoemde bewijs bestaan.
|
||||
|
||||
## Aanvullende traceability-opmerking
|
||||
- VR-102 is gerealiseerd met auditbare policyreviews (`SourcePolicyReview`), robotscache met TTL/size/SSRF-controles en fail-closed policy-gating op verlopen of conflicterende reviews.
|
||||
- VR-107 is gerealiseerd met `apps/sources/views.py`, `apps/sources/services/manual_import.py`, `templates/sources/list.html`, `static/js/manual_import.js` en bijhorende unit/integration-tests.
|
||||
- VR-115 is afgerond met productie-hardening voor `config/settings.py`, DNS-rebindmitigatie in `apps/sources/services/fetcher.py`, rate limiting op login en handmatige import, CI-secret- en kwetsbaarheidsscans, non-root/read-only containerhardening en bijbehorende security/unit/integration-tests.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user