Complete bounded browser and API product behavior
This commit is contained in:
parent
619c2911d2
commit
ea55108f44
1 changed files with 2117 additions and 399 deletions
|
|
@ -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:
|
||||
|
|
|
|||
Loading…
Reference in a new issue