test(e2e): pin security assertions + real cross-user IDOR coverage
Turn "accept-both-outcomes" documentation tests — which pass whether the app is secure or vulnerable — into assertions that pin the secure behavior, and replace fake-UUID authz tests that 404'd before ever reaching the ownership guard with real cross-user resources. file-upload-attacks: - SVG-with-<script> → pin 400 (infer returns None for text → stored-XSS defense); was [201,400], which accepted the vulnerable outcome. - zero-byte → pin 400; path-traversal → pin 201 with UUID-derived storage and a no-path-echo check (both were [201,400]). - Fix the application/octet-stream rationale (no "application bypass" exists — the handler ignores the declared type and keys off magic bytes). authorization-deep (IDOR): - B deleting A's comment: seed a real upload+comment as A, assert 403, assert the comment survives, and assert the owner (A) still gets 204 — proving the 403 is about identity, not a broken route. (Was a DELETE on the all-zeros UUID → 404 before the user_id guard, so authorization was never exercised.) - Add B-deletes-A's-upload (403, countUploads unchanged) and B-edits-A's-caption (403, caption intact) — the find_by_id_and_event + ownership guards. export: pin the ZIP-download 404 (was [404,200] — a 200 is a data-exposure regression) and split into the two real branches: not-yet-ready, and ready-but-file-missing (new db.setExportZipReady helper). All 21 assertions verified green against the live secure backend. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -68,6 +68,17 @@ export const db = {
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Flip the `export_zip_ready` gate directly. The download handler serves bytes
|
||||
* only when this boolean is true AND the file exists on disk, so setting it true
|
||||
* without a file lets tests exercise the "ready but file missing" 404 branch.
|
||||
*/
|
||||
async setExportZipReady(slug: string, ready: boolean) {
|
||||
await withClient((c) =>
|
||||
c.query(`UPDATE event SET export_zip_ready = $2 WHERE slug = $1`, [slug, ready])
|
||||
);
|
||||
},
|
||||
|
||||
/** Insert a pre-baked export job row to skip the (slow) real compression path. */
|
||||
async fakeExportJob(eventSlug: string, type: 'zip' | 'html', status: 'pending' | 'running' | 'done') {
|
||||
await withClient(async (c) => {
|
||||
|
||||
Reference in New Issue
Block a user