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
pull from: feat/192-scan-uploads
merge into: :main
:main
:docs/195-stale-outdated-pr
:feat/192-scan-uploads
:build/191-clamav
:feat/186-otel-endpoint
:ci/173-mkdocs-build
:docs/177-adr-labs-caddy
:ci/verify-stack-main-only
:fix/keycloak-proxy-headers
:feat/demo-otp-autofill
:fix/182-celery-concurrency
:feat/public-host-caddy
:ci/175-deploy-on-merge
:feat/177-public-tls-edge
:ci/168-helm-chart-ci-gate
:docs/169-mkdocs-nav
:feat/25-helm-kubernetes-caddy
:fix/161-e2e-bounded-and-diagnosable
:feat/162-werkbak-live-refresh
:feat/132-medewerker-mfa
:fix/156-tempo-ingester-healthcheck
:feat/153-projection-sourced-from-objecten
:feat/152-objecten-publishes-to-nrc
:feat/149-acl-writes-registerrecord
:feat/141-registerrecord-objecttype
:perf/verify-stack-uwsgi-oz-nrc
:fix/144-verify-stack-uwsgi
:feat/140-objecten-up
:feat/139-objecttypen-up
:feat/131-default-fill-crud
:chore/136-ci-job-summaries
:fix/134-verify-stack-scheduling
:feat/130-beheer-catalogi
:feat/124-metrics-dashboards
:ci/127-parallel-jobs
:feat/123-distributed-traces
:feat/111-self-service-resume
:feat/113-acl-zaaktype-by-identificatie
:fix/110-compose-local-flow
:fix/115-e2e-single-worker
:docs/111-backlog-s26
:feat/106-close-zaak-on-timeout
:feat/103-diploma-upload-documenten
:feat/102-document-wait-timeout
:feat/14-dmn-diploma-eligibility
:feat/15-beoordeling-escalation
:fix/portal-nginx-resolver
:fix/local-eventsubscriber-acl
:feat/12-withdrawal-portal
:fix/91-local-compose-parity
:feat/12-withdrawal-bff
:feat/12-withdrawal-workflow
:feat/12-withdrawal
:feat/13-behandel-portal
:feat/13-behandel-decide
:feat/13-behandel-bff-auth-werkbak
:feat/13-workflow-user-tasks
:feat/13-behandel-decision-model
:chore/release-2026.07.0
:feat/78-reference-correlation
:feat/75-approval-flow
:feat/10-openbaar-portal
:chore/73-ci-speedups
:feat/68-e2e
:feat/67-self-service-form
:feat/66-api-client
:feat/65-nx-workspace
:feat/8-bff
:feat/6-domain-service
:feat/7-event-subscriber-projection
:feat/56-nrc-notification-wiring
:test/46-acl-openzaak-integration
:feat/47-acl-mutation-baseline
:ci/30-gitea-actions-ci
:feat/5-acl-open-zaak
:feat/4-flowable
:feat/3-keycloak
:feat/2-opennotificaties
:feat/2-catalogus-seed
:feat/10-openzaak-compose
:feat/32-docs-scaffold
:feat/31-contributor-workflow
:feat/30-gitea-actions-ci
:feat/29-bff-docker-compose
:chore/remove-bootstrap-scripts
:feat/28-bff-health
:docs/split-s00
No Reviewers
Milestone
No items
No Milestone
Iteration 6 — Production Posture
Projects
Clear projects
No projects
Assignees
eho (Edwin van den Houdt)
Clear assignees
No Assignees
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: eho/register-referentie#194
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Uploaded diplomas are now virus-scanned and type-checked before they reach OpenZaak (ADR-0036). Builds on #193 (clamd infra, merged).
What changes
IDocumentScannerport, implemented byClamdDocumentScanner(clamd INSTREAM overTcpClient, no NuGet package).ProvideDocumentschecks ownership, then scans, then checks for%PDF-, and only then stores the file and completes the wait. New outcomes:Infected,NotAPdf,ScannerUnavailable. The API answers 422{reason}or 503.Unavailable. The upload is refused, nothing is stored and the wait stays open.%PDF-1.4\n+ EICAR scansOK), so a PDF check in front of the scan would report malware as "not a PDF".openapi.jsonand the generated client are regenerated.role="alert"message for infected, not-a-PDF and scanner-unavailable.EenDiplomaAanleveren.featurehas four scenarios (clean, infected, not a PDF, scanner down).Verified locally: every .NET unit and acceptance suite is green, as are the self-service vitest + axe tests and
dotnet format. The adapter was run against a real clamd 1.4.6: clean gives Clean, EICAR gives Infected, a closed port gives Unavailable. The existing e2e and local-flow uploads begin with%PDF-and are clean, so the happy path is unchanged.Not run: the full verify-stack (main only) and a Playwright e2e for the infected path. That path is covered by unit, BFF, portal and acceptance tests, plus
verify-clamavfor the live engine.closes #192
🤖 Generated with Claude Code
e39a46febcto254b1796dcView command line instructions
Checkout
From your project repository, check out a new branch and test the changes.