Skip to content

feat(upload): require approved account for log uploads - #1

Draft
dakejahl wants to merge 4 commits into
mainfrom
fix/restore-broken-uploads
Draft

feat(upload): require approved account for log uploads#1
dakejahl wants to merge 4 commits into
mainfrom
fix/restore-broken-uploads

Conversation

@dakejahl

@dakejahl dakejahl commented Jun 25, 2026

Copy link
Copy Markdown

Summary

Rejects anonymous uploads: a registered, admin-approved account is now required to upload logs. Supersedes the earlier approach on this branch of parsing anonymous uploads immediately.

Problem

Anonymous uploads fed attacker-controlled files into the log parser. The upload-time parse runs in a bounded worker process, but once a log is stored non-pending its plot page parses the file unbounded in the main server process — and the client-controlled source=CI field let an anonymous client store an unparsed, non-pending log and trigger exactly that via the plot URL. Deferred anonymous logs were also stranded: nothing ever un-defers a log with an empty uploader, so they sat pending forever.

Solution

Uploads are rejected with 403 in prepare(), before the request body is streamed, unless the client is logged in and the account is still approved (the re-check covers accounts revoked after their login cookie was issued). Since login already requires approval, every accepted upload is parsed immediately and the deferred/pending state is unreachable at upload time; the deferral branch is removed. Anonymous visitors to the upload form are redirected to the login page; viewing plots stays public. The backfill script is replaced by cleanup_pending_logs.py, which deletes stranded anonymous pending logs (list-only by default, --delete to act) and leaves named-uploader pending logs to be parsed on account approval. Run once after deploy: cd app && python cleanup_pending_logs.py --delete.

dakejahl added 3 commits June 25, 2026 13:10
The root Dockerfile ran setup_db.py only at build time, against the
throwaway image layer — never against the mounted persistent data
volume. A persistent prod DB therefore never received the ContentHash
(b66bb97) and Pending (2db03b1) columns, so every upload hit
"no such column: ContentHash" on the dedupe lookup and returned 500.
Run the idempotent migration at startup so the live DB is upgraded on
every deploy/restart.
Anonymous uploads are rejected with 403 in prepare(), before the request
body is streamed. Since login already requires an approved account, every
accepted upload is parsed immediately and the deferred/pending state is
no longer reachable at upload time. This also closes the client-controlled
source=CI path for anonymous users, which previously stored an unparsed,
non-pending log whose plot URL triggered an unbounded in-process parse.
Anonymous visitors to the upload form are redirected to the login page;
viewing plots stays public.
Anonymous pending logs predate the anonymous-upload ban and are never
parsed by policy; the script deletes them (list-only by default, --delete
to act). Pending logs with a named uploader are left alone — they are
parsed automatically when the account is approved.
@dakejahl
dakejahl force-pushed the fix/restore-broken-uploads branch from 20aa55d to 1a50ce2 Compare July 9, 2026 21:41
@dakejahl dakejahl changed the title fix(upload): restore broken log uploads feat(upload): require approved account for log uploads Jul 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant