demo mode
deploy / deploy (push) Canceled after 0s

This commit is contained in:
Jens
2026-07-27 23:38:37 +02:00
parent d28fd05bf6
commit 7caea3a1ee
44 changed files with 1682 additions and 460 deletions
@@ -0,0 +1,52 @@
# Productie-audit — 27 juli 2026
## Samenvatting
VacatureRadar heeft al een volwassen functionele en visuele basis. De audit vond geen noodzaak voor een nieuwe frontendarchitectuur; de belangrijkste professionaliseringswinst zat in de grens tussen Django, Nginx Proxy Manager en de Unraid-runtime.
De gerapporteerde `DisallowedHost` was een symptoom van ontbrekende publieke hostconfiguratie. De publiek zichtbare Django-debugpagina maakte tegelijk duidelijk dat de runtime nog ontwikkelinstellingen gebruikte. Deze release behandelt daarom hostvalidatie, HTTPS-detectie, CSRF, gedeelde rate limiting, readiness en gasttoegang als één productiecontract.
## Bevindingen en herstel
| Prioriteit | Bevinding | Risico | Herstel |
|---|---|---|---|
| Kritiek | Publieke host ontbrak in `ALLOWED_HOSTS` | onbeschikbare publieke route | `PUBLIC_BASE_URL` leidt host en CSRF-origin af; configuratiehelper toegevoegd |
| Kritiek | `DEBUG=True` was publiek zichtbaar | lek van interne paden en implementatiedetails | productiehelper zet debug uit; productiecheck stopt bij onveilige configuratie |
| Hoog | HTTPS-origin kon de interne poort `1226` bevatten | CSRF-fouten achter poort 443 | publieke en interne poort zijn gescheiden in deployscripts |
| Hoog | Secure redirect kon interne healthchecks omleiden | container blijft unhealthy na HTTPS-hardening | alleen `/health/live/` en `/health/ready/` zijn intern vrijgesteld |
| Hoog | Loginrate-limiting gebruikte proceslokale cache | limiet verschilde per Gunicornworker | Redis-cache als gedeelde productiestandaard en readinessdependency |
| Hoog | `X-Forwarded-For` werd zonder proxyvertrouwen gebruikt | IP-spoofing en omzeilbare rate limiting | forwarded chain alleen bij expliciet vertrouwde proxy-CIDR |
| Hoog | Gedeelde demo kon mutaties uitvoeren | bezoekers beïnvloeden elkaars demo en persistente data | server-side read-only middleware, begrensde sessie en zichtbare UI-status |
| Middel | Unraid-documentatie wees naar een andere `.env` dan Compose | wijzigingen werden niet geladen | pad gestandaardiseerd op `source/.env`; override blijft mogelijk |
| Middel | Deployhelper schreef een custom `.env`, maar Compose kon alsnog de standaardfile lezen | productie-instellingen werden stil genegeerd | geselecteerd env-bestand wordt nu voor Compose-interpolatie én containeromgeving gebruikt |
| Middel | AIO Compose interpoleerde databasewachtwoord buiten `env_file` | custom env-pad kon een kapotte URL leveren | database-URL wordt uitsluitend in de containerentrypoint opgebouwd |
| Middel | Persoonlijke installatie kon geïndexeerd worden | onbedoelde vindbaarheid van login en productmetadata | `robots.txt` en `X-Robots-Tag` standaard op noindex |
| Middel | Runtime startte zonder Django deployment check | foutieve securityconfiguratie werd laat ontdekt | `manage.py check --deploy` vóór migraties en processtart |
| Laag | Project- en assetversies liepen uiteen | cache- en release-identiteit onduidelijk | releaseversie gecentraliseerd op `0.3.12` |
| Laag | Overdrachtsarchief bevatte lokale Windows/runtimeartefacten | onnodige omvang en risico op secrets of stale state | bestaande schone packager en integriteitsmanifest verplicht gebruikt |
## Bewust niet gewijzigd
- De server-rendered Django-architectuur blijft behouden.
- De Stitch Intelligence Cockpit blijft de productiefrontend; er is geen SPA of extern runtime-CDN toegevoegd.
- De containerpoort blijft op Unraid bereikbaar voor Nginx Proxy Manager. Netwerksegmentatie of firewalling blijft een live infrastructuurtaak.
- HSTS start conservatief op 300 seconden. Verhoog pas na een geslaagde publieke login-, CSRF- en subdomeincontrole.
- Zoekmachine-indexering blijft standaard uit omdat dit een persoonlijke installatie is.
## Live controles na deployment
1. Hermaak de container met de bestaande `.env`.
2. Controleer intern beide health-endpoints.
3. Controleer publiek dat HTTP naar HTTPS gaat.
4. Controleer login en logout.
5. Voer één echte CSRF-beschermde actie uit met het beheerdersaccount.
6. Controleer dat het demoaccount geen mutatie kan uitvoeren.
7. Controleer securityheaders en afwezigheid van een debugpagina.
8. Controleer in Nginx Proxy Manager dat alleen de proxy de hostpoort kan bereiken.
9. Maak een back-up en voer een herstel-smoke uit vóór verdere bronautomatisering.
## Resterende externe punten
- De echte Nginx Proxy Manager-configuratie en het proxy-IP/CIDR zijn niet in de repository zichtbaar.
- De live Unraid-container, database en Redis zijn in deze auditomgeving niet bereikbaar.
- Een volledige Dockerbuild, publieke TLS-smoke en hersteltest moeten daarom op de doelserver worden uitgevoerd.
+3 -1
View File
@@ -81,6 +81,8 @@ Django/Celery
| T-39 | Mol-/Kempenbron vermengt een andere werkgever, campus of vestiging | foutieve afstand, phishing of buitenregionale resultaten | exacte HTTPS-host/pad/GUID-routes; same-host details; expliciete plaatsfilters voor regionale en gedeelde lijsten; postcodecentra blijven als benadering herkenbaar; waaklijstbronnen worden niet gescand | `tests/unit/test_regional_adapters.py`, `tests/integration/test_tasks_and_more_views.py`, `VR-126/201` |
| T-40 | Verouderde lokale CA-store of ongeldige serverketen lokt een TLS-bypass uit | onderschepte vacature- of mailboxdata en credentialdiefstal | expliciet gepinde `certifi`-CA-bundel voor HTTP, robots en IMAP; hostnaamcontrole en `CERT_REQUIRED`; nooit `verify=False`; dependency- en negatieve TLS-tests bij update | `tests/unit/test_tls.py`, `tests/security/test_robots.py`, `apps/sources/services/tls.py`, `VR-201` |
| T-41 | Gemodificeerde `next`-parameter na vacaturefeedback | open redirect naar phishingdomein na een geldige gebruikersactie | terugkeer-URL moet dezelfde host en het actuele HTTPS-beleid respecteren; anders veilige detailfallback | `tests/integration/test_tasks_and_more_views.py`, `VR-206` |
| T-42 | Gespoofte proxyheaders of ontbrekende publieke hostconfiguratie | host-headerfouten, onjuiste HTTPS-detectie of omzeilde IP-rate-limiting | `PUBLIC_BASE_URL`, exacte host/CSRF-validatie, proxy moet headers overschrijven, forwarded client-IP alleen vanaf `TRUSTED_PROXY_CIDRS` | `tests/unit/test_public_configuration.py`, `tests/unit/test_network.py`, `VR-225` |
| T-43 | Gedeeld demoaccount wijzigt persistente data | bezoekers beïnvloeden elkaars ervaring of echte data | server-side read-only middleware, korte sessie, geen bruikbaar wachtwoord, zichtbare UI-status en productiecheck | `tests/integration/test_auth_login.py`, `tests/unit/test_settings_security.py`, `VR-225` |
## Misbruikscenario's
@@ -114,7 +116,7 @@ Een wijziging aan netwerk, mail, AI, rendering, auth, exports of uploads vereist
## Resterende risico's
- De fetcher controleert het werkelijk verbonden peer-IP wanneer httpcore dat exposeert. Een custom transport dat geen peerinformatie aanbiedt valt terug op DNS-set-overlap; volledige IP-pinning blijft een aanvullend egress-hardeningniveau.
- Brute-force of herhaalde foutieve mutatiepogingen blijven mogelijk, maar zijn beperkt door in-memory rate limiting en blokkades op login/manual-import.
- Brute-force of herhaalde foutieve mutatiepogingen blijven mogelijk, maar zijn in productie begrensd via gedeelde Redis-rate-limiting en blokkades op login/manual-import. Correcte individuele client-IPherkenning vereist het exacte proxy-CIDR.
- 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.
+4 -2
View File
@@ -56,7 +56,7 @@ Legenda: **I** = geïmplementeerd en getest in de huidige MVP; **P** = gedeeltel
| 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-001 | I | policy-, URL- en fetchersecuritytests plus publieke host-, proxyvertrouwen-, demo- en gedeelde rate-limit-hardening | `tests/unit/test_fetcher.py`, `tests/unit/test_rate_limit.py`, `tests/unit/test_settings_security.py`, `tests/unit/test_public_configuration.py`, `tests/unit/test_network.py`, `tests/integration/test_auth_login.py`, VR-225 |
| 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, skillvraag met expliciet veld-/tekstonderscheid en UI-copy | VR-109/208 uitgebreid evidence |
@@ -64,7 +64,7 @@ Legenda: **I** = geïmplementeerd en getest in de huidige MVP; **P** = gedeeltel
| 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 | volledige negen-schermen-Stitch-cockpit, acht viewports, dark/light, toetsenborddrawer, premium visuele hiërarchie, zelfstandig VacatureRadar-productmerk, lokale ITWorx-ontwikkelaarscredit, toegankelijke interactieve radarillustratie en actuele user-first productdocumentatie | `tests/e2e/test_vr114_browser_and_accessibility.py`, `tests/integration/test_intelligence_views.py`, `tests/integration/test_views.py`, `artifacts/visual-validation/`, `docs/screenshots/readme/`, VR-209224 |
| NFR-009 | I | lokale SQLite, configureerbare eigenaarbranding, Docker/Unraidconfig, gevalideerde SSH-deployalias, release-smoke en restore | `tests/unit/test_deployment_configuration.py`, VR-117, VR-217/218 afgerond |
| NFR-009 | I | lokale SQLite, configureerbare eigenaarbranding, Docker/Unraidconfig, publieke URL-helper, Nginx Proxy Manager-runbook, gevalideerde SSH-deployalias, release-smoke en restore | `tests/unit/test_deployment_configuration.py`, `tests/unit/test_public_configuration.py`, VR-117, VR-217/218/225 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
@@ -111,3 +111,5 @@ Iedere backlogtaak die een requirement wijzigt, werkt in dezelfde commit deze ma
- VR-220 vervangt die tijdelijke tekstlock-up door de aangeleverde officiële ITWorx.tech-wordmark en een exact daaruit afgeleid cloud-check-appicoon voor browser, shell en Dockerman; VacatureRadar blijft de productnaam.
- VR-221 corrigeert de merkarchitectuur: VacatureRadar krijgt een zelfstandig radar-/kansbeeldmerk voor alle productcontactpunten en ITWorx.tech blijft uitsluitend zichtbaar als officiële secundaire ontwikkelaarscredit.
- VR-224 maakt de repository-ingang user-first: de README volgt de dagelijkse productflow, bevat gecontroleerde lokale quickstarts en gebruikt vier actuele dark/light- en desktop/mobielscreenshots zonder secrets of externe assets.
- VR-225 hardent de publieke installatie met `PUBLIC_BASE_URL`, exacte host/CSRF-afleiding, veilige proxy-HTTPS-detectie, vertrouwde client-IPchains, gedeelde Redis-rate-limiting, cache-readiness en een server-side alleen-lezen gastdemo. Bewijs staat in de productie-audit, Nginx-runbook en de settings-, network-, health-, auth- en deploymenttests.