Complete bounded browser and API product behavior

This commit is contained in:
ms2k 2026-07-19 01:12:29 +09:00
commit ea55108f44

View file

@ -233,7 +233,7 @@ spec:
sed -n '1,8p' "/tmp/callback-$suffix.body" >&2
exit 1
fi
test "$(header_value "/tmp/callback-$suffix.headers" Location)" = "/"
test "$(header_value "/tmp/callback-$suffix.headers" Location)" = "/app"
printf 'Application callback accepted %s\n' "$suffix" >&2
sed -n \
's/^\([Ss]et-[Cc]ookie: [^=]*\)=.*/\1=<redacted>/p' \
@ -362,6 +362,306 @@ spec:
exit 1
fi
if [ "${NUTHATCH_PRODUCT_MODE:-}" = timeout ]; then
curl --insecure --fail --silent --show-error \
--get \
--cookie "$cookies" \
--data-urlencode root=personal \
--data-urlencode q=timeout-probe \
"$base/api/browse" >/tmp/product-timeout.json
grep -F '"partial":true' /tmp/product-timeout.json
printf 'Timed search bound probe passed\n'
exit 0
fi
if [ "${NUTHATCH_PRODUCT_MODE:-}" = verify ]; then
product_upload() {
product_path="$1"
product_operation="$2"
product_body="$3"
printf '%s' "$product_body" >/tmp/product-body
product_size="$(wc -c </tmp/product-body | tr -d ' ')"
product_digest="$(
sha256sum /tmp/product-body | cut -d' ' -f1
)"
curl --insecure --fail --silent --show-error \
--cookie "$cookies" \
--header 'Content-Type: application/octet-stream' \
--header "X-Declared-Size: $product_size" \
--header "X-Content-SHA256: $product_digest" \
--header "X-CSRF-Token: $csrf" \
--data-binary @/tmp/product-body \
"$base/api/upload?root=personal&path=$product_path&operation_id=$product_operation"
}
curl --insecure --fail --silent --show-error \
--cookie "$cookies" \
"$base/api/session" >/tmp/product-session.json
grep -F '"user_id":' /tmp/product-session.json
grep -F "\"csrf\":\"$csrf\"" /tmp/product-session.json
curl --insecure --fail --silent --show-error \
--cookie "$cookies" \
--dump-header /tmp/product-app.headers \
"$base/app" >/tmp/product-app.html
grep -i '^content-security-policy:' /tmp/product-app.headers |
grep -F "default-src 'none'" |
grep -F "script-src 'self'" |
grep -F "frame-ancestors 'none'" >/dev/null
asset="$(
sed -n 's#.*src="/assets/\([^"]*\.js\)".*#\1#p' \
/tmp/product-app.html
)"
test -n "$asset"
curl --insecure --fail --silent --show-error \
--cookie "$cookies" \
--dump-header /tmp/product-asset.headers \
"$base/assets/$asset" >/tmp/product-asset.js
grep -i '^content-type:.*javascript' \
/tmp/product-asset.headers >/dev/null
grep -i '^x-content-type-options: *nosniff' \
/tmp/product-asset.headers >/dev/null
for marker in \
'Drop a file here' \
'Shared root' \
'Retry same upload' \
'Retry same delete' \
'nuthatch-recursive-delete' \
'URLSearchParams'; do
grep -F "$marker" /tmp/product-asset.js >/dev/null
done
test "$(
curl --insecure --silent --output /dev/null \
--write-out '%{http_code}' \
"$base/app"
)" = 303
test "$(
curl --insecure --silent --output /dev/null \
--write-out '%{http_code}' \
"$base/assets/$asset"
)" = 303
product_upload product-browse/Alpha.txt \
81000000-0000-4000-8000-000000000001 alpha \
>/tmp/product-upload.json
grep -F '"result":"succeeded"' /tmp/product-upload.json
product_upload product-browse/Alpha.txt \
81000000-0000-4000-8000-000000000001 alpha \
>/tmp/product-upload-replay.json
grep -F '"result":"succeeded"' \
/tmp/product-upload-replay.json
product_upload product-browse/beta.txt \
81000000-0000-4000-8000-000000000002 beta >/dev/null
product_upload product-browse/gamma.txt \
81000000-0000-4000-8000-000000000003 gamma >/dev/null
curl --insecure --fail --silent --show-error \
--get \
--cookie "$cookies" \
--data-urlencode root=personal \
--data-urlencode prefix=product-browse \
"$base/api/browse" >/tmp/product-page-one.json
grep -F '"path":"product-browse/Alpha.txt"' \
/tmp/product-page-one.json
grep -F '"path":"product-browse/beta.txt"' \
/tmp/product-page-one.json
if grep -F '"path":"product-browse/gamma.txt"' \
/tmp/product-page-one.json; then
exit 1
fi
continuation="$(
sed -n \
's/.*"continuation":"\([^"]*\)".*/\1/p' \
/tmp/product-page-one.json
)"
test -n "$continuation"
curl --insecure --fail --silent --show-error \
--get \
--cookie "$cookies" \
--data-urlencode root=personal \
--data-urlencode prefix=product-browse \
--data-urlencode "continuation=$continuation" \
"$base/api/browse" >/tmp/product-page-two.json
grep -F '"path":"product-browse/gamma.txt"' \
/tmp/product-page-two.json
product_upload 000-Needle-A.txt \
81000000-0000-4000-8000-000000000004 one >/dev/null
product_upload 001-needle-b.txt \
81000000-0000-4000-8000-000000000005 two >/dev/null
product_upload 002-filler.txt \
81000000-0000-4000-8000-000000000006 three >/dev/null
product_upload 003-needle-after-bound.txt \
81000000-0000-4000-8000-000000000007 four >/dev/null
curl --insecure --fail --silent --show-error \
--get \
--cookie "$cookies" \
--data-urlencode root=personal \
--data-urlencode q=NEEDLE \
"$base/api/browse" >/tmp/product-search.json
grep -F '"path":"000-Needle-A.txt"' /tmp/product-search.json
grep -F '"path":"001-needle-b.txt"' /tmp/product-search.json
grep -F '"partial":true' /tmp/product-search.json
if grep -F '003-needle-after-bound.txt' \
/tmp/product-search.json; then
exit 1
fi
printf 'Product asset, pagination, and search probes passed\n'
for invalid_url in \
"$base/api/browse?root=Personal" \
"$base/api/browse?root=personal&prefix=a//b" \
"$base/api/download?root=personal&path=./file"; do
invalid_status="$(
curl --insecure --silent --output /dev/null \
--write-out '%{http_code}' \
--cookie "$cookies" \
"$invalid_url"
)"
printf 'Canonical rejection status=%s url=%s\n' \
"$invalid_status" "$invalid_url"
test "$invalid_status" = 400
done
decomposed_path="$(printf 'cafe\314\201.txt')"
decomposed_status="$(
curl --insecure --silent --output /dev/null \
--write-out '%{http_code}' \
--get \
--cookie "$cookies" \
--data-urlencode root=personal \
--data-urlencode "path=$decomposed_path" \
"$base/api/download"
)"
printf 'NFC rejection status=%s\n' "$decomposed_status"
test "$decomposed_status" = 400
product_upload encoded%252Fname.txt \
81000000-0000-4000-8000-000000000008 encoded \
>/dev/null
curl --insecure --fail --silent --show-error \
--cookie "$cookies" \
"$base/api/download?root=personal&path=encoded%252Fname.txt" \
>/tmp/product-encoded
test "$(cat /tmp/product-encoded)" = encoded
product_upload caf%C3%A9.txt \
81000000-0000-4000-8000-000000000014 unicode \
>/dev/null
curl --insecure --fail --silent --show-error \
--cookie "$cookies" \
--dump-header /tmp/product-unicode.headers \
"$base/api/download?root=personal&path=caf%C3%A9.txt" \
>/tmp/product-unicode
test "$(cat /tmp/product-unicode)" = unicode
grep -i '^content-disposition:' /tmp/product-unicode.headers |
grep -F "filename*=UTF-8''caf%C3%A9.txt" >/dev/null
printf 'Product canonical path probes passed\n'
product_upload active.svg \
81000000-0000-4000-8000-000000000009 \
'<svg onload="alert(1)"></svg>' >/dev/null
test "$(
curl --insecure --silent --output /tmp/product-range.json \
--write-out '%{http_code}' \
--cookie "$cookies" \
--header 'Range: bytes=0-1' \
"$base/api/download?root=personal&path=active.svg"
)" = 416
grep -F '"error":"range_not_supported"' \
/tmp/product-range.json
curl --insecure --fail --silent --show-error \
--cookie "$cookies" \
--dump-header /tmp/product-download.headers \
"$base/api/download?root=personal&path=active.svg" \
>/tmp/product-download.svg
grep -i '^content-disposition: *attachment;' \
/tmp/product-download.headers |
grep -F "filename*=UTF-8''active.svg" >/dev/null
grep -i '^x-content-type-options: *nosniff' \
/tmp/product-download.headers >/dev/null
grep -i '^content-security-policy: *sandbox' \
/tmp/product-download.headers >/dev/null
grep -F '<svg onload="alert(1)"></svg>' \
/tmp/product-download.svg
printf 'Product safe download probes passed\n'
product_upload delete-tree/a.txt \
81000000-0000-4000-8000-000000000010 a >/dev/null
product_upload delete-tree/b.txt \
81000000-0000-4000-8000-000000000011 b >/dev/null
product_upload delete-tree/c.txt \
81000000-0000-4000-8000-000000000012 c >/dev/null
curl --insecure --fail --silent --show-error \
--get \
--cookie "$cookies" \
--data-urlencode root=personal \
--data-urlencode path=delete-tree \
"$base/api/delete-plan" >/tmp/product-plan-one.json
grep -F '"paths":["delete-tree/a.txt","delete-tree/b.txt"]' \
/tmp/product-plan-one.json
grep -F '"continuation":' /tmp/product-plan-one.json |
grep -v '"continuation":null' >/dev/null
delete_batch_one="$(
printf \
'{"root":"personal","csrf":"%s","items":[{"path":"delete-tree/a.txt","operation_id":"82000000-0000-4000-8000-000000000001"},{"path":"delete-tree/b.txt","operation_id":"82000000-0000-4000-8000-000000000002"}]}' \
"$csrf"
)"
curl --insecure --fail --silent --show-error \
--cookie "$cookies" \
--header 'Content-Type: application/json' \
--data "$delete_batch_one" \
"$base/api/delete-batch" >/tmp/product-batch-one.json
grep -F '"operation_id":"82000000-0000-4000-8000-000000000001"' \
/tmp/product-batch-one.json
test "$(
grep -o '"result":"succeeded"' /tmp/product-batch-one.json |
wc -l |
tr -d ' '
)" = 2
curl --insecure --fail --silent --show-error \
--cookie "$cookies" \
--header 'Content-Type: application/json' \
--data "$delete_batch_one" \
"$base/api/delete-batch" >/tmp/product-batch-replay.json
test "$(
grep -o '"result":"succeeded"' \
/tmp/product-batch-replay.json |
wc -l |
tr -d ' '
)" = 2
product_upload delete-tree/d-concurrent.txt \
81000000-0000-4000-8000-000000000013 d >/dev/null
curl --insecure --fail --silent --show-error \
--get \
--cookie "$cookies" \
--data-urlencode root=personal \
--data-urlencode path=delete-tree \
"$base/api/delete-plan" >/tmp/product-plan-restart.json
grep -F '"paths":["delete-tree/c.txt","delete-tree/d-concurrent.txt"]' \
/tmp/product-plan-restart.json
delete_batch_two="$(
printf \
'{"root":"personal","csrf":"%s","items":[{"path":"delete-tree/c.txt","operation_id":"82000000-0000-4000-8000-000000000003"},{"path":"delete-tree/d-concurrent.txt","operation_id":"82000000-0000-4000-8000-000000000004"}]}' \
"$csrf"
)"
curl --insecure --fail --silent --show-error \
--cookie "$cookies" \
--header 'Content-Type: application/json' \
--data "$delete_batch_two" \
"$base/api/delete-batch" >/tmp/product-batch-two.json
test "$(
grep -o '"result":"succeeded"' /tmp/product-batch-two.json |
wc -l |
tr -d ' '
)" = 2
curl --insecure --fail --silent --show-error \
--get \
--cookie "$cookies" \
--data-urlencode root=personal \
--data-urlencode path=delete-tree \
"$base/api/delete-plan" >/tmp/product-plan-empty.json
grep -F '"paths":[]' /tmp/product-plan-empty.json
grep -F '"continuation":null' /tmp/product-plan-empty.json
printf 'Product behavior probes passed\n'
exit 0
fi
if [ "${NUTHATCH_IDEMPOTENCY_MODE:-}" = verify ]; then
pod_curl() {
destination="$1"
@ -1162,6 +1462,12 @@ spec:
name: @@PROFILE_NAME@@
key: NUTHATCH_IDEMPOTENCY_MODE
optional: true
- name: NUTHATCH_PRODUCT_MODE
valueFrom:
configMapKeyRef:
name: @@PROFILE_NAME@@
key: NUTHATCH_PRODUCT_MODE
optional: true
- name: NUTHATCH_IDEMPOTENCY_IP_A
valueFrom:
configMapKeyRef: