Repository navigation
[pending DataSpaceBackend#249] test(api): legacy media route 404s as JSON, not Django HTML - #200
saqibmanan wants to merge 1 commit into
Conversation
…end#249)
Covers the open DataSpaceBackend#249 (S3 migration): the old /public/<name>
static-file route is replaced by legacy_media_redirect, which 404s with a
small JSON body instead of Django's HTML debug page, for both a missing
file and a path-traversal name. Gated with pending_pr("DataSpaceBackend#249")
since the source PR hasn't merged; proven red against dev (which still
serves the pre-#249 code) and confirmed to skip correctly with the marker
in place. Green is UNVERIFIED: DataSpaceBackend cannot be deployed in this
sandbox, so the post-merge JSON-404 behaviour has not been executed.
|
The failure is No fix exists yet for this that I can port in. Leaving this for a human to look at Generated by Claude Code |
|
This run fired Not re-running manually: the rate-limit window is fixed and clears up to 60 minutes after it opened, not 60 minutes after the last request, so an immediate re-run would likely just hit the same throttling again. Leaving this for a later CI run (or a human) once the window has cleared — not something this test-sync PR should chase. Generated by Claude Code |
Pending: covers open CivicDataLab/DataSpaceBackend#249 (head
fa89bfa70595760581fca46aa4d93c06f4d54797). Skipped in CI until it merges. Safe to merge before it.Source PR
CivicDataLab/DataSpaceBackend#249 — "feat(storage): move media to S3 and remove DVC versioning"
dev, open, created 2026-10-19 (>72h old, no coverage yet)headRefOid:fa89bfa70595760581fca46aa4d93c06f4d54797What actually changed (from the diff, not the title)
This is a large PR (40 files); the slice this adds coverage for is the one piece that's both unauthenticated and testable without a real backend deployment: the legacy media route.
DataSpace/urls.py: the oldstatic(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)route (Django servingfiles/public/...off local disk, only ever live whenDEBUG=True) is replaced bylegacy_media.legacy_media_redirectat the same/public/<name>prefix.api/views/legacy_media.py(new): redirects a valid, existing public file's old link to its S3 URL; 404s with{"error": "Not found"}(JSON) for (a) a name that doesn't exist in public storage, and (b) a name whoseposixpath.normpathdiffers from itself (path traversal) — rejected before storage is even consulted.api/utils/storage.py(new):public_storage()/private_storage()wrappers and thefiles/public//files/legacy-prefix stripping used by the redirect.Confirmed directly against the PR diff in
DataSpaceBackend(DataSpace/urls.py,api/views/legacy_media.py,api/utils/storage.py), not from the PR title/description.Category chosen:
api+smokePure unauthenticated HTTP status/content-type checks against a REST-ish Django view, no GraphQL and no UI —
apifits.smokeis required alongsideapi/pending_prso CI'spull_requestmarker filter (-m "smoke") actually selects it;api-only would be silently deselected (this repo has no job that ever selectsregressioneither — SKILL.md §5). Neverreadonly, per §9: the gate opens on merge todev, but the prod-deploy gate runsreadonlytests, and this would fail every prod deploy until #249 actually ships.Test added
tests/api/smoke/test_api_028_legacy_media_redirect.py— two unauthenticated REST checks againstanon_api_client(no new fixtures needed):test_missing_public_file_404s_as_json_not_django_html—GET /public/<missing-name>must 404 withContent-Type: application/jsonand body{"error": "Not found"}.test_public_file_name_with_path_traversal_404s_as_json—GET /public/..%252f..%252fetc%252fpasswd(double-encoded, survives nginx to actually reach the Django view — confirmed separately that a single-encoded or bare../payload either gets blocked at nginx with a 400, or gets resolved by Django's own router before/public/, so neither reaches the view) must also 404 as JSON.Both carry
pytest.mark.pending_pr("DataSpaceBackend#249")(new file, viapytestmark), plusapiandsmoke.Red proof — against dev, which still serves the pre-#249 code
Today's dev backend answers both cases with Django's HTML "technical 404" page, not JSON:
Pytest run with the
pending_prmarker temporarily removed locally (reverted before commit, never pushed), against dev:Both fail at the intended content-type/body assertion, not a setup error — this is a genuine red, not a vacuous one.
Green — UNVERIFIED, not executed anywhere
UNVERIFIED: PR not deployed anywhere. DataSpaceBackend cannot be run in this sandbox (no Postgres, Redis, Elasticsearch, Keycloak or S3 available), so the post-#249 JSON-404 behaviour has only been read from the diff, never executed. Once #249 merges and is live on dev, re-run this file; both tests are expected to flip to passing with no changes needed here.
Skip-gating + collection proof
Marker present (as shipped), against dev:
Collected under both of CI's real marker filters:
Gaps / out of scope
migrate_media_to_s3, DVC removal, resource-file SHA256 hashing onlocal_copy()) all need either an authenticated write (upload a file) or a live backend with real S3 credentials — neither is available in this sandbox. UNVERIFIED — not executed, no credentials in this environment. A human withTEST_EMAIL_1/TEST_PASSWORD_1and a real backend deployment should extend this file (or add a sibling) to cover: a presigned private URL actually expiring after 5 minutes, an upload landing under the right<STORAGE_ENV>/publicor<STORAGE_ENV>/privateprefix, and the breaking-change migration steps in the PR body.Housekeeping
test-sync/DataSpaceBackend-pr249, based onorigin/CI(confirmed via recent merged test-repo PRs thatCI, notmain/dev, is where this repo's test work lands and where its workflows run —mainonly takes docs,devruns days behind).test-sync/DataSpaceBackend-pr249branch, no test-repo PR mentioningDataSpaceBackend#249or#249.test_api_028_*— confirmed free onorigin/CI(git ls-treeshowed 001–024, 027, nothing at 025–026/028+ before this; #224's and #420's pending PRs already claimed 025/026).Run context: scheduled cloud routine, no test credentials in this environment. Everything executed above against dev/public endpoints is real and was actually run — only the post-merge green and the rest of #249's authenticated/write surface are
UNVERIFIED.