feat(domain): virus-scan and PDF-check uploaded diplomas with ClamAV (closes #192) #194

Open
not wants to merge 13 commits from feat/192-scan-uploads into main
13 Commits
Author SHA1 Message Date
notandClaude Opus 5.5 e39a46febc test(domain): cover clamd timeout, caller cancellation, null content and defaults (refs #192)
CI / k8s (pull_request) Successful in 18s
CI / build (pull_request) Successful in 5m23s
CI / lint (pull_request) Successful in 5m55s
CI / docs (pull_request) Successful in 1m3s
CI / unit (pull_request) Successful in 1m33s
CI / frontend (pull_request) Successful in 5m31s
CI / mutation (pull_request) Successful in 8m11s
CI / verify-stack (pull_request) Skipped
Domain mutation score 89.87% → 91.98%, back above the 90% break.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-02 09:53:23 +02:00
notandClaude Opus 5.5 940aac7d25 docs: demo note and backlog mirror for S-28/S-29 (refs #192)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-02 09:53:23 +02:00
notandClaude Opus 5.5 4e7e0526b2 feat(domain): scan before the PDF check so malware is always reported as infected (refs #192)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-02 09:53:23 +02:00
notandClaude Opus 5.5 c245182c87 test(domain): malware is reported infected even when the file is not a PDF (refs #192)
clamd matches EICAR only at the start of a file, so a %PDF- check ahead of the
scan made the infected path unreachable for the EICAR test file.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-02 09:53:23 +02:00
notandClaude Opus 5.5 38026879c7 fix(test): acceptance BFF fake returns the provide-documents result (refs #192)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-02 09:53:23 +02:00
notandClaude Opus 5.5 5ceace718a feat(portal-self-service): tell the citizen why a diploma upload was refused (refs #192)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-02 09:53:23 +02:00
notandClaude Opus 5.5 e15253487e test(portal-self-service): explain a refused or unscannable diploma upload (refs #192)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-02 09:53:23 +02:00
notandClaude Opus 5.5 da7813a84e feat(bff): relay refused diplomas as 422 with reason, scanner down as 503 (refs #192)
openapi.json and the generated portal client regenerated from the served spec.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-02 09:53:23 +02:00
notandClaude Opus 5.5 77de63bf8b test(bff): relay a refused diploma as 422 with its reason, a down scanner as 503 (refs #192)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-02 09:53:23 +02:00
notandClaude Opus 5.5 d2c035679b feat(domain): scan uploads with clamd over INSTREAM; 422 refused, 503 scanner down (refs #192)
Verified against a real clamd 1.4.6: clean → Clean, EICAR → Infected,
closed port → Unavailable.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-02 09:53:23 +02:00
notandClaude Opus 5.5 64dd5420d7 test(domain): clamd INSTREAM adapter maps replies to scan verdicts (refs #192)
Red: the stub adapter never connects and always answers Clean.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-02 09:53:23 +02:00
notandClaude Opus 5.5 764ae6e1be feat(domain): refuse non-PDF, infected or unscannable diplomas before storing (refs #192)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-02 09:53:23 +02:00
notandClaude Opus 5.5 eaef19747b test(domain): only a clean PDF diploma is stored and unblocks beoordeling (refs #192)
Red: ProvideDocuments takes the new IDocumentScanner port but ignores it, so
infected, non-PDF and scanner-unavailable uploads are still Accepted.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-02 09:53:23 +02:00