From 1e2882973ba200c8bb6998da9d2e79cf6a73c394 Mon Sep 17 00:00:00 2001 From: Edouard Vanbelle Date: Tue, 30 Jun 2026 20:18:10 +0200 Subject: [PATCH] fix(test): correct due to commit 43cf4a2bg - MKCOL is now better protected - Webdav now handle 201 (created) 204 (overritten) --- tests/api/permissions.hurl | 38 +++++++++++++------- tests/webdav/test_dedup_webdav_multichunk.sh | 14 +++++--- tests/webdav/test_dedup_webdav_ref_count.sh | 13 ++++--- tests/webdav/test_native_webdav_lifecycle.sh | 23 ++++++------ 4 files changed, 56 insertions(+), 32 deletions(-) diff --git a/tests/api/permissions.hurl b/tests/api/permissions.hurl index 220489c4..9ffd5640 100644 --- a/tests/api/permissions.hurl +++ b/tests/api/permissions.hurl @@ -299,14 +299,25 @@ jsonpath "$.items[*].resource.name" not contains "bob-attack-2" # ───────────────────────────────────────────────────────────── # Step 16 – Bob crafts a path that looks like it targets admin's -# home. The WebDAV handler rewrites the path to live -# under bob's home, so the request succeeds (201) but -# the new folders land in BOB's tree — never admin's. +# home. Pre-43cf4a2b the WebDAV handler silently +# rewrote `My Folder - admin/...` into the caller's own +# home folder, so this MKCOL succeeded with 201 but the +# new folders landed in BOB's tree (defense via +# redirect). 43cf4a2b made MKCOL strictly RFC 4918 +# §9.3.1 compliant: 409 when the parent collection is +# missing, no auto-creation of ancestors. Bob's MKCOL +# now fails because `My Folder - admin` is not a folder +# bob can reach — defense via rejection rather than +# silent rewrite. The 4xx range allows for 403/404/409 +# depending on which gate fires first. # ───────────────────────────────────────────────────────────── MKCOL {{base_url}}/webdav/My%20Folder%20-%20admin/bob-webdav-attack Authorization: Bearer {{bob_token}} -HTTP 201 +HTTP * +[Asserts] +status >= 400 +status < 500 # ───────────────────────────────────────────────────────────── @@ -324,13 +335,16 @@ HTTP 201 # ───────────────────────────────────────────────────────────── -# Step 18 – Bob's home now contains: -# - "bob-webdav-own" (from Step 17, normal MKCOL) -# - "My Folder - admin" (from Step 16 — the prefix -# rewrite turned admin's home name into a literal -# sub-folder name inside bob's tree). -# This proves the path prefix re-rooted the attack -# into bob's own namespace. +# Step 18 – Bob's home contains "bob-webdav-own" (from Step 17's +# legitimate MKCOL) and does NOT contain "My Folder - +# admin". Pre-43cf4a2b the path-prefix rewrite would +# have created that name literally as a sub-folder in +# bob's tree (defense via redirect); post-43cf4a2b the +# MKCOL is rejected outright (defense via rejection), +# so no such folder exists in bob's namespace either. +# Both are correct security outcomes — the wire signal +# just changed from "succeeded but didn't reach admin" +# to "didn't succeed at all." # ───────────────────────────────────────────────────────────── GET {{base_url}}/api/folders/{{bob_home_id}}/resources?resource_types=folder Authorization: Bearer {{bob_token}} @@ -338,7 +352,7 @@ Authorization: Bearer {{bob_token}} HTTP 200 [Asserts] jsonpath "$.items[*].resource.name" contains "bob-webdav-own" -jsonpath "$.items[*].resource.name" contains "My Folder - admin" +jsonpath "$.items[*].resource.name" not contains "My Folder - admin" # ───────────────────────────────────────────────────────────── diff --git a/tests/webdav/test_dedup_webdav_multichunk.sh b/tests/webdav/test_dedup_webdav_multichunk.sh index 68e0b7af..31ad2b0e 100755 --- a/tests/webdav/test_dedup_webdav_multichunk.sh +++ b/tests/webdav/test_dedup_webdav_multichunk.sh @@ -116,18 +116,24 @@ for REMOTE in "$FILE_A" "$FILE_B"; do done # ── Step 1: Upload file A ───────────────────────────────────────────────────── +# Post commit 43cf4a2b, PUT distinguishes create (201) from overwrite (204) +# per RFC 7231 §4.3.4. Both files are NEW here (the purge_from_trash loop +# above wiped any leftover state), so we expect 201 on each PUT. echo " step 1: PUT $FILE_A..." STATUS=$(webdav_put "$FILE_A" "$FIXTURE" "video/mp4") -[[ "$STATUS" == "204" ]] || fail "PUT $FILE_A expected 204, got $STATUS" -pass "PUT $FILE_A → 204 (new manifest, 8 chunk blobs created)" +[[ "$STATUS" == "201" ]] || fail "PUT $FILE_A expected 201, got $STATUS" +pass "PUT $FILE_A → 201 (new manifest, 8 chunk blobs created)" # ── Step 2: Upload file B (same content, different name → dedup hit) ────────── +# File B is a distinct resource (new path), so PUT still emits 201 even though +# the underlying blob is dedup'd. 201 vs 204 reflects "is this a new HTTP +# resource at this URL", not "is the byte content novel". echo " step 2: PUT $FILE_B (same bytes → dedup hit)..." STATUS=$(webdav_put "$FILE_B" "$FIXTURE" "video/mp4") -[[ "$STATUS" == "204" ]] || fail "PUT $FILE_B expected 204, got $STATUS" -pass "PUT $FILE_B → 204 (dedup hit: manifest ref_count → 2, chunks unchanged)" +[[ "$STATUS" == "201" ]] || fail "PUT $FILE_B expected 201, got $STATUS" +pass "PUT $FILE_B → 201 (dedup hit: manifest ref_count → 2, chunks unchanged)" # ── Resolve file IDs ────────────────────────────────────────────────────────── diff --git a/tests/webdav/test_dedup_webdav_ref_count.sh b/tests/webdav/test_dedup_webdav_ref_count.sh index a8a9420e..dd2a47e7 100755 --- a/tests/webdav/test_dedup_webdav_ref_count.sh +++ b/tests/webdav/test_dedup_webdav_ref_count.sh @@ -122,18 +122,23 @@ for REMOTE in "$FILE_A" "$FILE_B"; do done # ── Step 1: Upload file A ───────────────────────────────────────────────────── +# Post commit 43cf4a2b, PUT distinguishes create (201) from overwrite (204) +# per RFC 7231 §4.3.4. The wipe loop above ensures A and B are NEW resources +# here, so we expect 201. Step 5 below tests the overwrite case (expects 204). echo " step 1: PUT $FILE_A (dedup-test.jpg)..." STATUS=$(webdav_put "$FILE_A" "$FIXTURE_A" "image/jpeg") -[[ "$STATUS" == "204" ]] || fail "PUT $FILE_A expected 204, got $STATUS" -pass "PUT $FILE_A → 204" +[[ "$STATUS" == "201" ]] || fail "PUT $FILE_A expected 201, got $STATUS" +pass "PUT $FILE_A → 201" # ── Step 2: Upload file B (identical content, different name) ───────────────── +# Distinct resource (new path), so PUT emits 201 even though the underlying +# blob dedup-hits. 201 vs 204 reflects URL freshness, not byte freshness. echo " step 2: PUT $FILE_B (dedup-test-2.jpg, same bytes)..." STATUS=$(webdav_put "$FILE_B" "$FIXTURE_B" "image/jpeg") -[[ "$STATUS" == "204" ]] || fail "PUT $FILE_B expected 204, got $STATUS" -pass "PUT $FILE_B → 204" +[[ "$STATUS" == "201" ]] || fail "PUT $FILE_B expected 201, got $STATUS" +pass "PUT $FILE_B → 201" # ── Step 3: Resolve file IDs and assert two distinct records ────────────────── diff --git a/tests/webdav/test_native_webdav_lifecycle.sh b/tests/webdav/test_native_webdav_lifecycle.sh index 48284d86..7660bba5 100755 --- a/tests/webdav/test_native_webdav_lifecycle.sh +++ b/tests/webdav/test_native_webdav_lifecycle.sh @@ -140,22 +140,21 @@ pass "M2: 5 responses, trailing-slash semantics correct on native /webdav/ surfa # the lifecycle (which the existing test_dedup_webdav_* scripts # also exercise at root) actually validates. -echo " M3: PUT /webdav/m3-sample.txt (pinned: native always 204, NC would be 201 on new)" +echo " M3: PUT /webdav/m3-sample.txt → 201 (new resource, post 43cf4a2b)" +# Post commit 43cf4a2b, the native WebDAV handler differentiates +# new-vs-overwrite per RFC 7231 §4.3.4: 201 Created for a fresh PUT, +# 204 No Content when replacing an existing resource. Aligns with the +# NC handler — there's no more native-vs-NC split on this point. +# (Prior to 43cf4a2b the native handler returned 204 for both; the M3 +# `case` block was a forward-looking trip-wire telling the next reader +# to update this pin once the split happened. That moment is now.) STATUS=$(dav_curl -o /dev/null -w "%{http_code}" -X PUT \ -H "Content-Type: text/plain" \ --data-binary 'sample contents — exactly 31 bytes' \ "$DAV_BASE/m3-sample.txt") -case "$STATUS" in - 204) - pass "M3: native PUT new → 204 (pinned current behaviour; differs from NC's 201/204 split)" - ;; - 201) - fail "M3: native PUT now returns 201 for new — handler differentiates new-vs-overwrite. Update pin if intentional." - ;; - *) - fail "M3: unexpected status $STATUS" - ;; -esac +[[ "$STATUS" == "201" ]] \ + || fail "M3: native PUT new expected 201, got $STATUS" +pass "M3: native PUT new → 201" # ───────────────────────────────────────────────────────────── # M4 — Range GET bytes=0-9 → 206 + 10 bytes