4.7 KiB
4.7 KiB
QA procedure: serve_uploaded_images
Package: test (black-box, new file test/serve_uploaded_images_test.go).
Setup shared by every case
- Call
validator.InitValidator()once (harmless even though this handler does no validation). - Create a fresh
uploadDir := t.TempDir()per test/subtest. This handler has no domain repository to fake — it serves real files from a real directory on disk, which is standard for filesystem-serving code and is not the "real SQLite file" / "live server" / "real SMTP" the project convention rules out. - Build
staticimages.NewHandler(uploadDir)(api/handlers/staticimages). - Mount it on a fresh
chi.NewRouter()mirroringapi/router.go's shape after this slice:r.Mount("/static/uploadedImages", staticHandler)— nojwtauth.Verifier/jwtauth.Authenticatorwrapping.r.Mount("/", stubFrontend)wherestubFrontendis a trivialhttp.HandlerFuncthat writes a recognizable marker string, e.g."SPA-INDEX-MARKER", with status 200 — standing in for the real SPA fallback, just to prove routing order without needing the embeddeddist/build.
- Helper to seed a file:
os.WriteFile(filepath.Join(uploadDir, name), content, 0o644), creating parent directories withos.MkdirAllwhen a subdirectory case needs one.
HTTP checks
- Write
4b9e2f1a-1111-....png,.jpeg,.webpfiles with distinct non-empty byte content. For each,httptest.NewRequest("GET", "/static/uploadedImages/"+name, nil), no cookie. Assert status200;Content-Typeequals the expected value;Cache-Controlequals"public, no-cache";X-Content-Type-Optionsequals"nosniff";Content-Security-Policyheader is absent; body bytes equal what was written. - Write a
.svgfile whose content contains an inlineonloadhandler (content doesn't matter functionally, just needs to be non-empty and distinguishable). GET it. Assert status200,Content-Typeis"image/svg+xml",Content-Security-Policyequals"default-src 'none'; style-src 'unsafe-inline'; sandbox",X-Content-Type-Optionsis"nosniff", body equals the exact SVG bytes (not sanitized/altered). - Write
notes.txt. GET it. Assert status200,Content-Typeis"application/octet-stream", noContent-Security-Policyheader. - Don't create
missing.png. GET/static/uploadedImages/missing.png. Assert status404; assert the body does not contain"SPA-INDEX-MARKER"(proves the static mount, not the frontend fallback, produced the 404 — i.e. mount ordering in the test router matches the required ordering inapi/router.go). - Write a file, then
os.Removeit before the request. GET its old name. Assert status404. os.MkdirAll(filepath.Join(uploadDir, "nested"), 0o755)and write a file inside it. GET/static/uploadedImages/nested. Assert status404(a directory is never listed or served).- Write one real file inside
uploadDir, and separately write a marker file (e.g."sentinel-outside") to a location outsideuploadDir(a secondt.TempDir(), or a path one level aboveuploadDir) so a successful escape would be detectable. For each of the traversal paths"../"+sentinelName,"..%2f"+sentinelName(raw in the request path, sincehttptest.NewRequesttakes a literal target string and Go'snet/httpmux/handler must not decode-then-escape), and a triple-..%2fvariant: sendGET /static/uploadedImages/<path>. Assert status404for every case, and assert the response body never equals the sentinel file's content. - Write a
.webpfile. Sendhttptest.NewRequest("HEAD", ...). Assert status200, the sameContent-Type/Cache-Control/X-Content-Type-Optionsheaders as the GET case, and an empty response body (rec.Body.Len() == 0). - Repeat step 6's PNG case with explicitly no
Cookieheader set on the request (already true in step 6, but assert this once more as its own subtest/comment-free assertion block) and confirm status200, not a 3xx redirect and not401.
Manual verification (not exercised by the Go test)
- Real end-to-end mount order: run
task devor a builttask buildbinary, confirmGET /static/uploadedImages/<unknown>returns 404 from the real router (with the real embeddeddist/), notindex.html, since the Go test above stands in a stub for the frontend rather than the embedded SPA. - Browser-level CSP enforcement: open an uploaded SVG containing a script directly in a browser and confirm the CSP header actually blocks execution (header presence is asserted by the test; browser enforcement isn't).
- No SMTP involvement.