release: authentication moves to Authelia (#5)
Authelia now runs in front of Traefik, so the app was asking for a second
password at the same door. This removes its own authentication entirely
rather than layering the two.
## Breaking — the server needs both files in this deploy
`compose.yaml` and `.env` are not pulled from this repository. The new image
ignores `PASSWORD`, and the old image refuses to start without it, so the
image and the compose file have to move together or the container dies at
startup.
| Variable | Change |
|---|---|
| `PASSWORD` | **removed** — the app no longer reads it |
| `AUTH` | **new, required** — the Traefik middleware that authenticates the app, e.g. `authelia@docker` |
| `CERTRESOLVER` | **new, required** — the resolver issuing the certificate for `HOST` |
The `tls=true` label is replaced by `tls.certresolver=${CERTRESOLVER}`.
Naming a resolver implies TLS, so it stays one label rather than two — and
the resolver had been carried by hand on the server since the first deploy.
## What was removed
- `auth()` and `challenge()` — HTTP Basic over a single shared password
- `throttle.go` and its tests — the per-IP guess limiter and the
`X-Forwarded-For` handling that fed it
- `golang.org/x/time`, which existed only for that limiter
- Sixty `-u` flags from the smoke script
`routes()` returns the bare mux and `/healthz` is an ordinary route on it.
159 insertions against 446 deletions; nothing was written to replace what
went.
## What holds the app up now
Both invariants live in `compose.yaml`, next to comments saying why:
- **The router names the Authelia middleware through `AUTH`.** Traefik takes
a router out of service when its middleware does not resolve, so an unset
or misspelt value fails shut rather than serving the app open.
- **The container publishes no ports.** It is reachable only over the shared
proxy network. Publishing `8080` would now bypass authentication outright,
not merely TLS.
`/healthz` returns the version and nothing else, so it is safe to exempt in
Authelia if a monitor needs to reach it.
## Why this is stronger, not weaker
The layer being deleted was one shared secret with no sessions, no second
factor and no way to revoke access for one person. Authelia does all three,
configured once for every service on the host instead of reimplemented per
app. The weaker of the two prompts was the one being kept.
## Tests
`TestAuth` and `TestHealthzSkipsAuth` are replaced by a single test asserting
every route answers without credentials — a 401 from the app would now mean
authentication had crept back in. `make check` green; CI green on `dev`.
## Note on the commit list
Nine of the ten commits below are already in `main` via #4, squash-merged
under a different SHA. They contribute nothing to the diff, which is the
auth removal alone.
---------
Co-authored-by: Esa Kataja <[email protected]>
Reviewed-on: #5
This commit was merged in pull request #5.
This commit is contained in:
+64
-65
@@ -1,7 +1,10 @@
|
||||
#!/bin/sh
|
||||
# End-to-end check of a running Foodster: auth, static assets and the bundle
|
||||
# import flow. Builds its own binary, uses a scratch database and a spare
|
||||
# port, and cleans up after itself, so it never touches a real instance.
|
||||
# End-to-end check of a running Foodster: static assets, the logger and the
|
||||
# bundle import flow. Builds its own binary, uses a scratch database and a
|
||||
# spare port, and cleans up after itself, so it never touches a real instance.
|
||||
#
|
||||
# There is nothing to authenticate as: the app is served behind Authelia and
|
||||
# has no login of its own.
|
||||
#
|
||||
# Run it with `make smoke`.
|
||||
|
||||
@@ -10,7 +13,6 @@ set -eu
|
||||
cd "$(dirname "$0")/.."
|
||||
|
||||
addr=127.0.0.1:8099
|
||||
pass=smoke
|
||||
|
||||
# Dates are relative, never literal. A hardcoded one turns into "some day in
|
||||
# the past" at the next midnight, and the assertions quietly start meaning
|
||||
@@ -22,7 +24,7 @@ trap 'kill ${srv:-0} 2>/dev/null || true; rm -rf "$tmp"' EXIT
|
||||
|
||||
go build -o "$tmp/foodster" ./cmd/foodster
|
||||
|
||||
PASSWORD="$pass" DB="$tmp/smoke.db" ADDR="$addr" \
|
||||
DB="$tmp/smoke.db" ADDR="$addr" \
|
||||
"$tmp/foodster" >"$tmp/server.log" 2>&1 &
|
||||
srv=$!
|
||||
|
||||
@@ -61,22 +63,19 @@ refute() {
|
||||
|
||||
echo "smoke: http://$addr"
|
||||
|
||||
check "unauthenticated request is refused" \
|
||||
"$(curl -s -o /dev/null -w '%{http_code}' "http://$addr/")" "401"
|
||||
|
||||
check "healthz needs no password" \
|
||||
check "healthz answers" \
|
||||
"$(curl -s -o /dev/null -w '%{http_code}' "http://$addr/healthz")" "200"
|
||||
|
||||
check "datastar client is served" \
|
||||
"$(curl -s -o /dev/null -w '%{http_code}' -u ":$pass" "http://$addr/static/datastar.js")" "200"
|
||||
"$(curl -s -o /dev/null -w '%{http_code}' "http://$addr/static/datastar.js")" "200"
|
||||
|
||||
check "favicon is served" \
|
||||
"$(curl -s -o /dev/null -w '%{http_code}' -u ":$pass" "http://$addr/static/favicon.svg")" "200"
|
||||
"$(curl -s -o /dev/null -w '%{http_code}' "http://$addr/static/favicon.svg")" "200"
|
||||
|
||||
check "theme script is served" \
|
||||
"$(curl -s -o /dev/null -w '%{http_code}' -u ":$pass" "http://$addr/static/theme.js")" "200"
|
||||
"$(curl -s -o /dev/null -w '%{http_code}' "http://$addr/static/theme.js")" "200"
|
||||
|
||||
home=$(curl -s -u ":$pass" "http://$addr/")
|
||||
home=$(curl -s "http://$addr/")
|
||||
check "the header carries the brand" "$home" "Foodster"
|
||||
# ENV is unset here, so this instance is production and unmarked.
|
||||
check "production tabs are not tagged" "$home" "<title>Foodster</title>"
|
||||
@@ -85,47 +84,47 @@ check "the theme toggle is present" "$home" "data-theme-toggle"
|
||||
check "both theme icons ship so CSS can pick one" "$home" 'class="i-moon"'
|
||||
|
||||
check "apple touch icon is served" \
|
||||
"$(curl -s -o /dev/null -w '%{http_code}' -u ":$pass" "http://$addr/static/apple-touch-icon.png")" "200"
|
||||
"$(curl -s -o /dev/null -w '%{http_code}' "http://$addr/static/apple-touch-icon.png")" "200"
|
||||
|
||||
# A manifest served as octet-stream is silently ignored by the browser.
|
||||
check "manifest has the right content type" \
|
||||
"$(curl -s -o /dev/null -w '%{content_type}' -u ":$pass" "http://$addr/static/manifest.webmanifest")" \
|
||||
"$(curl -s -o /dev/null -w '%{content_type}' "http://$addr/static/manifest.webmanifest")" \
|
||||
"application/manifest+json"
|
||||
|
||||
check "catalog starts empty" \
|
||||
"$(curl -s -u ":$pass" "http://$addr/ruuat")" "0 pääruokaa"
|
||||
"$(curl -s "http://$addr/ruuat")" "0 pääruokaa"
|
||||
|
||||
out=$(curl -s -u ":$pass" -F "tiedosto=@seeds/testi.json" "http://$addr/ruuat/tuonti")
|
||||
out=$(curl -s -F "tiedosto=@seeds/testi.json" "http://$addr/ruuat/tuonti")
|
||||
check "file upload imports the seed bundle" "$out" "Lisätty 22, ohitettu 0"
|
||||
check "counts update after import" "$out" "16 pääruokaa, 6 lisuketta"
|
||||
|
||||
check "re-import refuses duplicates" \
|
||||
"$(curl -s -u ":$pass" -F "tiedosto=@seeds/testi.json" "http://$addr/ruuat/tuonti")" \
|
||||
"$(curl -s -F "tiedosto=@seeds/testi.json" "http://$addr/ruuat/tuonti")" \
|
||||
"jo listalla"
|
||||
|
||||
check "pasted JSON imports" \
|
||||
"$(curl -s -u ":$pass" -F 'json={"mains":[],"sides":[{"name":"Perunasalaatti"}]}' \
|
||||
"$(curl -s -F 'json={"mains":[],"sides":[{"name":"Perunasalaatti"}]}' \
|
||||
"http://$addr/ruuat/tuonti")" "Lisätty 1"
|
||||
|
||||
check "unknown category is reported" \
|
||||
"$(curl -s -u ":$pass" -F 'json={"mains":[{"name":"Rikki","categories":["kana"]}],"sides":[]}' \
|
||||
"$(curl -s -F 'json={"mains":[{"name":"Rikki","categories":["kana"]}],"sides":[]}' \
|
||||
"http://$addr/ruuat/tuonti")" "tuntematon kategoria"
|
||||
|
||||
check "empty submit is explained" \
|
||||
"$(curl -s -u ":$pass" -F 'json=' "http://$addr/ruuat/tuonti")" "Ei tuotavaa"
|
||||
"$(curl -s -F 'json=' "http://$addr/ruuat/tuonti")" "Ei tuotavaa"
|
||||
|
||||
check "malformed JSON is explained" \
|
||||
"$(curl -s -u ":$pass" -F 'json={nope' "http://$addr/ruuat/tuonti")" "JSON ei kelpaa"
|
||||
"$(curl -s -F 'json={nope' "http://$addr/ruuat/tuonti")" "JSON ei kelpaa"
|
||||
|
||||
# ---- the log flow, against the dishes imported above --------------------
|
||||
|
||||
board=$(curl -s -u ":$pass" "http://$addr/")
|
||||
board=$(curl -s "http://$addr/")
|
||||
check "board lists imported dishes" "$board" "Lihapullat"
|
||||
|
||||
# Tähteet is loggable but is not food: on the board, never in the catalog.
|
||||
check "leftovers are on the board" "$board" "Tähteet"
|
||||
refute "leftovers are not in the catalog" \
|
||||
"$(curl -s -u ":$pass" "http://$addr/ruuat")" "Tähteet"
|
||||
"$(curl -s "http://$addr/ruuat")" "Tähteet"
|
||||
|
||||
# Pull a real dish id out of the board rather than assuming one.
|
||||
ruoka=$(printf '%s' "$board" | grep -o 'ruoka=[0-9]*' | head -n1 | cut -d= -f2)
|
||||
@@ -136,147 +135,147 @@ if [ -z "$ruoka" ]; then
|
||||
fi
|
||||
|
||||
check "picking a dish opens the sides step" \
|
||||
"$(curl -s -u ":$pass" "http://$addr/?ruoka=$ruoka")" "Tallenna"
|
||||
"$(curl -s "http://$addr/?ruoka=$ruoka")" "Tallenna"
|
||||
|
||||
check "saving redirects back to the day" \
|
||||
"$(curl -s -o /dev/null -w '%{http_code}' -u ":$pass" \
|
||||
"$(curl -s -o /dev/null -w '%{http_code}' \
|
||||
-d "pvm=$d0&ruoka=$ruoka" "http://$addr/kirjaa")" "303"
|
||||
|
||||
check "the saved day shows what was eaten" \
|
||||
"$(curl -s -u ":$pass" "http://$addr/?pvm=$d0")" "kirjattu"
|
||||
"$(curl -s "http://$addr/?pvm=$d0")" "kirjattu"
|
||||
|
||||
# The selected day expands inside the list rather than in a panel above it,
|
||||
# so the rows below do not shift when one is tapped.
|
||||
day=$(curl -s -u ":$pass" "http://$addr/?pvm=$d0")
|
||||
day=$(curl -s "http://$addr/?pvm=$d0")
|
||||
check "the selected day expands in place" "$day" 'class="open"'
|
||||
check "and stays in the list rather than being lifted out" "$day" "kirjattu"
|
||||
|
||||
# ---- the day list patches in place instead of navigating ----------------
|
||||
|
||||
dayp=$(curl -s -u ":$pass" -H 'Datastar-Request: true' "http://$addr/paiva?pvm=$d0")
|
||||
dayp=$(curl -s -H 'Datastar-Request: true' "http://$addr/paiva?pvm=$d0")
|
||||
check "opening a day patches the list" "$dayp" 'id="paivat"'
|
||||
refute "and returns a fragment, not a page" "$dayp" "<html"
|
||||
|
||||
check "picking a dish patches to the sides step" \
|
||||
"$(curl -s -u ":$pass" -H 'Datastar-Request: true' \
|
||||
"$(curl -s -H 'Datastar-Request: true' \
|
||||
"http://$addr/paiva?pvm=$d0&ruoka=$ruoka")" "Tallenna"
|
||||
|
||||
check "saving from Datastar patches back" \
|
||||
"$(curl -s -u ":$pass" -H 'Datastar-Request: true' \
|
||||
"$(curl -s -H 'Datastar-Request: true' \
|
||||
-d "pvm=$d1&ruoka=$ruoka" "http://$addr/kirjaa")" 'id="paivat"'
|
||||
|
||||
check "deleting from Datastar patches back" \
|
||||
"$(curl -s -u ":$pass" -H 'Datastar-Request: true' \
|
||||
"$(curl -s -H 'Datastar-Request: true' \
|
||||
-d "pvm=$d1" "http://$addr/poista")" 'id="paivat"'
|
||||
|
||||
# Without the header it must still redirect, for no JavaScript.
|
||||
check "a plain save still redirects to the day" \
|
||||
"$(curl -s -o /dev/null -w '%{redirect_url}' -u ":$pass" \
|
||||
"$(curl -s -o /dev/null -w '%{redirect_url}' \
|
||||
-d "pvm=$d1&ruoka=$ruoka" "http://$addr/kirjaa")" "pvm=$d1"
|
||||
|
||||
# Deleting a logged meal drops the row outright, so it asks first.
|
||||
saved=$(curl -s -u ":$pass" "http://$addr/?pvm=$d0&poista=1")
|
||||
saved=$(curl -s "http://$addr/?pvm=$d0&poista=1")
|
||||
check "deleting a meal asks first" "$saved" "Poistetaanko merkintä?"
|
||||
# Assert the entry is still shown, rather than that no gap row exists anywhere
|
||||
# on the page: other days are legitimately unlogged and render their own.
|
||||
check "and the entry is still there while asking" "$saved" "kirjattu"
|
||||
|
||||
check "deleting redirects back" \
|
||||
"$(curl -s -o /dev/null -w '%{http_code}' -u ":$pass" \
|
||||
"$(curl -s -o /dev/null -w '%{http_code}' \
|
||||
-d "pvm=$d0" "http://$addr/poista")" "303"
|
||||
|
||||
check "the day is empty again" \
|
||||
"$(curl -s -u ":$pass" "http://$addr/?pvm=$d0")" "Etsi"
|
||||
"$(curl -s "http://$addr/?pvm=$d0")" "Etsi"
|
||||
|
||||
check "search filters the board" \
|
||||
"$(curl -s -u ":$pass" "http://$addr/?haku=keitto")" "keitto"
|
||||
"$(curl -s "http://$addr/?haku=keitto")" "keitto"
|
||||
|
||||
# ---- live search: Datastar sends signals as JSON in ?datastar= -----------
|
||||
|
||||
live=$(curl -s -u ":$pass" --get --data-urlencode 'datastar={"haku":"keitto"}' "http://$addr/etsi")
|
||||
live=$(curl -s --get --data-urlencode 'datastar={"haku":"keitto"}' "http://$addr/etsi")
|
||||
check "live search returns the board fragment" "$live" 'id="lauta"'
|
||||
check "live search applies the term" "$live" "keitto"
|
||||
refute "live search excludes non-matches" "$live" "Lihapullat"
|
||||
refute "the fragment is not a whole page" "$live" "<html"
|
||||
|
||||
check "live search is served as html for Datastar to patch" \
|
||||
"$(curl -s -o /dev/null -w '%{content_type}' -u ":$pass" \
|
||||
"$(curl -s -o /dev/null -w '%{content_type}' \
|
||||
--get --data-urlencode 'datastar={"haku":"keitto"}' "http://$addr/etsi")" \
|
||||
"text/html"
|
||||
|
||||
cat_live=$(curl -s -u ":$pass" --get --data-urlencode 'datastar={"haku":"riisi"}' "http://$addr/ruuat/etsi")
|
||||
cat_live=$(curl -s --get --data-urlencode 'datastar={"haku":"riisi"}' "http://$addr/ruuat/etsi")
|
||||
check "catalog live search returns its fragment" "$cat_live" 'id="ruokalista"'
|
||||
check "catalog live search matches sides too" "$cat_live" "Riisi"
|
||||
refute "catalog live search excludes non-matches" "$cat_live" "Lihapullat"
|
||||
|
||||
# The plain form still works without JavaScript.
|
||||
check "catalog search works as a plain form too" \
|
||||
"$(curl -s -u ":$pass" "http://$addr/ruuat?haku=riisi")" "Riisi"
|
||||
"$(curl -s "http://$addr/ruuat?haku=riisi")" "Riisi"
|
||||
|
||||
# Nothing was eaten tomorrow. A future date is clamped rather than logged.
|
||||
future=$(date -d '+30 days' +%Y-%m-%d)
|
||||
check "a future date falls back to today" \
|
||||
"$(curl -s -u ":$pass" "http://$addr/?pvm=$future")" "$(date +%-d.%-m.%Y)"
|
||||
"$(curl -s "http://$addr/?pvm=$future")" "$(date +%-d.%-m.%Y)"
|
||||
|
||||
check "saving a future date is clamped too" \
|
||||
"$(curl -s -o /dev/null -w '%{redirect_url}' -u ":$pass" \
|
||||
"$(curl -s -o /dev/null -w '%{redirect_url}' \
|
||||
-d "pvm=$future&ruoka=$ruoka" "http://$addr/kirjaa")" "/"
|
||||
|
||||
check "tomorrow was not written to the log" \
|
||||
"$(curl -s -u ":$pass" "http://$addr/?pvm=$future")" "$(date +%-d.%-m.%Y)"
|
||||
"$(curl -s "http://$addr/?pvm=$future")" "$(date +%-d.%-m.%Y)"
|
||||
|
||||
# Clean up the entry that clamped onto today.
|
||||
curl -s -o /dev/null -u ":$pass" -d "pvm=$(date +%Y-%m-%d)" "http://$addr/poista"
|
||||
curl -s -o /dev/null -d "pvm=$(date +%Y-%m-%d)" "http://$addr/poista"
|
||||
|
||||
# ---- adding a dish without leaving Kirjaa --------------------------------
|
||||
|
||||
miss=$(curl -s -u ":$pass" "http://$addr/?haku=Poronkariste")
|
||||
miss=$(curl -s "http://$addr/?haku=Poronkariste")
|
||||
check "a search with no hits offers to add it" "$miss" "Ei osumia. Lisätäänkö?"
|
||||
check "the add form is prefilled with the search" "$miss" 'value="Poronkariste"'
|
||||
|
||||
check "quick add goes straight to the sides step" \
|
||||
"$(curl -s -o /dev/null -w '%{redirect_url}' -u ":$pass" \
|
||||
"$(curl -s -o /dev/null -w '%{redirect_url}' \
|
||||
-d 'nimi=Poronkariste&kategoria=meat&lisukkeita=1' "http://$addr/lisaa")" \
|
||||
"ruoka="
|
||||
|
||||
check "quick add rejects a dish with no category" \
|
||||
"$(curl -s -u ":$pass" -d 'nimi=Kategoriaton' "http://$addr/lisaa")" \
|
||||
"$(curl -s -d 'nimi=Kategoriaton' "http://$addr/lisaa")" \
|
||||
"Valitse vähintään yksi kategoria."
|
||||
|
||||
check "the quick-added dish is on the board" \
|
||||
"$(curl -s -u ":$pass" "http://$addr/")" "Poronkariste"
|
||||
"$(curl -s "http://$addr/")" "Poronkariste"
|
||||
|
||||
# ---- catalog CRUD from the UI -------------------------------------------
|
||||
|
||||
# Assert where it redirects, not just that it does: these pointed at the old
|
||||
# /ruoat spelling for a while and every 303-only check was happy.
|
||||
check "adding a main redirects back to the catalog" \
|
||||
"$(curl -s -o /dev/null -w '%{redirect_url}' -u ":$pass" \
|
||||
"$(curl -s -o /dev/null -w '%{redirect_url}' \
|
||||
-d 'nimi=uunikala&kategoria=fish&lisukkeita=1' "http://$addr/ruuat/paaruoka")" \
|
||||
"/ruuat"
|
||||
|
||||
catalog=$(curl -s -u ":$pass" "http://$addr/ruuat")
|
||||
catalog=$(curl -s "http://$addr/ruuat")
|
||||
check "the new main is listed, sentence-cased" "$catalog" "Uunikala"
|
||||
|
||||
check "a duplicate name is refused" \
|
||||
"$(curl -s -u ":$pass" -d 'nimi=UUNIKALA&kategoria=fish' "http://$addr/ruuat/paaruoka")" \
|
||||
"$(curl -s -d 'nimi=UUNIKALA&kategoria=fish' "http://$addr/ruuat/paaruoka")" \
|
||||
"Nimi on jo listalla."
|
||||
|
||||
check "a main with no category is refused" \
|
||||
"$(curl -s -u ":$pass" -d 'nimi=Kategoriaton' "http://$addr/ruuat/paaruoka")" \
|
||||
"$(curl -s -d 'nimi=Kategoriaton' "http://$addr/ruuat/paaruoka")" \
|
||||
"Valitse vähintään yksi kategoria."
|
||||
|
||||
check "a nameless dish is refused" \
|
||||
"$(curl -s -u ":$pass" -d 'nimi=+++&kategoria=fish' "http://$addr/ruuat/paaruoka")" \
|
||||
"$(curl -s -d 'nimi=+++&kategoria=fish' "http://$addr/ruuat/paaruoka")" \
|
||||
"Anna nimi."
|
||||
|
||||
check "adding a side redirects back to the catalog" \
|
||||
"$(curl -s -o /dev/null -w '%{redirect_url}' -u ":$pass" \
|
||||
"$(curl -s -o /dev/null -w '%{redirect_url}' \
|
||||
-d 'nimi=lohkoperunat' "http://$addr/ruuat/lisuke")" \
|
||||
"/ruuat"
|
||||
|
||||
check "the new side is listed" \
|
||||
"$(curl -s -u ":$pass" "http://$addr/ruuat")" "Lohkoperunat"
|
||||
"$(curl -s "http://$addr/ruuat")" "Lohkoperunat"
|
||||
|
||||
# The id of Uunikala specifically: the catalog is grouped and alphabetical, so
|
||||
# the first id on the page belongs to some other dish entirely.
|
||||
@@ -287,20 +286,20 @@ if [ -z "$uusi" ]; then
|
||||
uusi=0
|
||||
fi
|
||||
check "the edit form is prefilled" \
|
||||
"$(curl -s -u ":$pass" "http://$addr/ruuat?muokkaa=$uusi")" "Muokkaa pääruokaa"
|
||||
"$(curl -s "http://$addr/ruuat?muokkaa=$uusi")" "Muokkaa pääruokaa"
|
||||
|
||||
# A bin icon is easy to hit by accident, so the row asks before anything goes.
|
||||
check "the bin asks before deleting" \
|
||||
"$(curl -s -u ":$pass" "http://$addr/ruuat?poista=$uusi&tyyppi=paa")" "Poista?"
|
||||
"$(curl -s "http://$addr/ruuat?poista=$uusi&tyyppi=paa")" "Poista?"
|
||||
|
||||
check "the dish is still there while it asks" \
|
||||
"$(curl -s -u ":$pass" "http://$addr/ruuat?poista=$uusi&tyyppi=paa")" "Uunikala"
|
||||
"$(curl -s "http://$addr/ruuat?poista=$uusi&tyyppi=paa")" "Uunikala"
|
||||
|
||||
# ---- the catalog patches in place instead of navigating -----------------
|
||||
|
||||
# A delete confirmation halfway down a long list must not send the browser
|
||||
# back to the top, so these answer with a Datastar patch rather than a page.
|
||||
patch=$(curl -s -u ":$pass" -H 'Datastar-Request: true' \
|
||||
patch=$(curl -s -H 'Datastar-Request: true' \
|
||||
"http://$addr/ruuat/nayta?poista=$uusi&tyyppi=paa")
|
||||
check "asking to delete patches rather than navigates" "$patch" "event: datastar-patch-elements"
|
||||
check "the patch carries the list" "$patch" 'id="ruokalista"'
|
||||
@@ -308,26 +307,26 @@ check "and both forms, so an open one closes" "$patch" 'id="paaruoka"'
|
||||
check "the row it patches in is asking" "$patch" "Poista?"
|
||||
|
||||
check "patches are served as an event stream" \
|
||||
"$(curl -s -o /dev/null -w '%{content_type}' -u ":$pass" -H 'Datastar-Request: true' \
|
||||
"$(curl -s -o /dev/null -w '%{content_type}' -H 'Datastar-Request: true' \
|
||||
"http://$addr/ruuat/nayta")" "text/event-stream"
|
||||
|
||||
check "deleting from Datastar patches too" \
|
||||
"$(curl -s -u ":$pass" -H 'Datastar-Request: true' \
|
||||
"$(curl -s -H 'Datastar-Request: true' \
|
||||
-d "id=$uusi&tyyppi=paa" "http://$addr/ruuat/poista")" \
|
||||
"event: datastar-patch-elements"
|
||||
|
||||
refute "and the dish is gone from the patched list" \
|
||||
"$(curl -s -u ":$pass" -H 'Datastar-Request: true' "http://$addr/ruuat/nayta")" \
|
||||
"$(curl -s -H 'Datastar-Request: true' "http://$addr/ruuat/nayta")" \
|
||||
"Uunikala"
|
||||
|
||||
# Without the header it must still be an ordinary redirect, for no JavaScript.
|
||||
check "a plain form post still redirects" \
|
||||
"$(curl -s -o /dev/null -w '%{redirect_url}' -u ":$pass" \
|
||||
"$(curl -s -o /dev/null -w '%{redirect_url}' \
|
||||
-d 'nimi=Testiruoka&kategoria=fish' "http://$addr/ruuat/paaruoka")" \
|
||||
"/ruuat"
|
||||
|
||||
refute "the dish is gone once confirmed" \
|
||||
"$(curl -s -u ":$pass" "http://$addr/ruuat")" "Uunikala"
|
||||
"$(curl -s "http://$addr/ruuat")" "Uunikala"
|
||||
|
||||
if [ "$fail" -ne 0 ]; then
|
||||
echo "smoke: FAILED"
|
||||
|
||||
Reference in New Issue
Block a user