Skip to content
Cockpit0.29.0
A snapshot: read at commit 707a04c7ce8 on 2026-10-18T00:06:01Z by majordomus 0.29.0. Nothing on this page is read again. See it live

test/cases/84_web_surfaces.sh

An object of kind test

What it is

URI
majordomus://test/test/cases/84_web_surfaces.sh
Kind
test
Identity
test/cases/84_web_surfaces.sh
Path
test/cases/84_web_surfaces.sh
Provenance
declared
Media type
text/plain
As a capability
test.test/cases/84_web_surfaces.sh

Front matter

{}

Content

# The web surfaces of a repository: discovered from their producers, validated as one
# topology, composed into one publishable tree, and served from the running executable.
#
# The case this exists for is the last one: a surface nobody has written yet. A directory
# under the generated web root with a declaration beside it becomes a surface — listed,
# validated, composed and served — without a line changing in the router, the command line,
# the publication or this case's own fixtures. If that ever stops being true, the
# architecture has leaked and this case says so.
. "$ROOT/test/lib.sh"
"$MJ" init >/dev/null
"$MJ" update >/dev/null
git add -A >/dev/null; git commit -qm base
BIN="$(rust_bin)" || skip "no toolchain"
# the executable reads its kinds and schemas from the distribution it was built beside
MAJORDOMUS_SHARE="$ROOT/share"; export MAJORDOMUS_SHARE

# ---------------------------------------------------------------- what a bare repository has
"$BIN" web list > list.txt
expect_grep '^ID +KIND +MOUNT +CATEGORY +WHERE +SOURCE$' list.txt
expect_grep '^api +native +/api/v1' list.txt
expect_grep '^swagger +native +/swagger ' list.txt
# and never at /docs: that prefix is the documentation's, and a native route there would take
# every page under it (project.web-surface-declared-once)
expect_no_grep '^swagger +native +/docs' list.txt
# a repository with no site and nothing generated has no static surface at all
expect_no_grep '^app +static' list.txt
expect_exit 0 "$BIN" web validate

# ---------------------------------------------------------------- a surface nobody wrote code for
mkdir -p target/web/example-report
cat > target/web/example-report/surface.json <<'JSON'
{
  "schema": "web-surface/v1",
  "id": "example-report",
  "mount": "/example-report",
  "title": "An example report",
  "producer": "the fixture of test/cases/84_web_surfaces.sh"
}
JSON
printf '<!DOCTYPE html><title>example</title><h1>example report</h1>\n' > target/web/example-report/index.html

# it is discovered, described and valid, with nothing registered anywhere
"$BIN" web list > list.txt
expect_grep '^example-report +static +/example-report +.*target/web/example-report$' list.txt
expect_exit 0 "$BIN" web validate --artifacts
"$BIN" web explain example-report > explain.txt
expect_grep 'came from producer declaration target/web/example-report/surface.json' explain.txt
expect_grep 'producer   the fixture of' explain.txt

# it is selectable by the id it declared, and an id nothing declared is refused
expect_exit 0 "$BIN" web list --only example-report
expect_grep 'example-report'
expect_exit 10 "$BIN" web list --only nothing-declares-this

# it is composed into the publication under its mount, and nothing else is
expect_exit 0 "$BIN" web compose --destination target/site
[ -f target/site/example-report/index.html ] || { echo "    the surface was not composed under its mount"; exit 1; }
grep -q 'example report' target/site/example-report/index.html

# and it is served, by the same server, from the same resolution
"$BIN" serve --port 0 --idle 60 > serve.log 2>&1 &
serve_pid=$!
url=""
for _ in $(seq 1 50); do
  url="$(sed -n 's/.*listening on \(http:[^ ]*\).*/\1/p' serve.log | head -1)"
  [ -n "$url" ] && break
  sleep 0.2
done
[ -n "$url" ] || { echo "    the server never logged its address:"; cat serve.log; kill $serve_pid 2>/dev/null; exit 1; }
status() { curl -s -o /dev/null -w '%{http_code}' "$url$1"; }
[ "$(status /example-report/)" = 200 ] || { echo "    /example-report/ answered $(status /example-report/)"; kill $serve_pid 2>/dev/null; exit 1; }
[ "$(status /example-report/index.html)" = 200 ] || { echo "    the file answered $(status /example-report/index.html)"; kill $serve_pid 2>/dev/null; exit 1; }
# the routes the executable answers itself are not taken by a static surface
[ "$(status /openapi.json)" = 200 ] || { echo "    /openapi.json answered $(status /openapi.json)"; kill $serve_pid 2>/dev/null; exit 1; }
# and nothing escapes the surface's own directory
[ "$(status /example-report/../../../etc/passwd)" = 404 ] || { echo "    a traversal was answered"; kill $serve_pid 2>/dev/null; exit 1; }
kill $serve_pid 2>/dev/null; wait $serve_pid 2>/dev/null || true

# ---------------------------------------------------------------- and every way it can be wrong
# two surfaces claiming one mount
mkdir -p target/web/second-claim
sed 's/example-report/second-claim/; s|"mount": "/second-claim"|"mount": "/example-report"|' \
  target/web/example-report/surface.json > target/web/second-claim/surface.json
printf '<!DOCTYPE html><title>x</title>\n' > target/web/second-claim/index.html
expect_exit 10 "$BIN" web validate
expect_grep 'surface.mount-collision'
rm -rf target/web/second-claim

# a surface mounted inside another's subtree
mkdir -p target/web/nested
printf '{"schema":"web-surface/v1","id":"nested","mount":"/example-report/nested"}\n' > target/web/nested/surface.json
printf '<!DOCTYPE html><title>x</title>\n' > target/web/nested/index.html
expect_exit 10 "$BIN" web validate
expect_grep 'surface.nested-mount'
rm -rf target/web/nested

# a declaration with a key the contract does not have
printf '{"schema":"web-surface/v1","id":"typo","mount":"/typo","moutn":"/oops"}\n' > target/web/example-report/surface.json
expect_exit 10 "$BIN" web list
rm -rf target/web/example-report

# ---------------------------------------------------------------- and it leaves no trace
"$BIN" web list > list.txt
expect_no_grep 'example-report' list.txt
expect_exit 0 "$BIN" web validate
expect_exit 0 "$BIN" web compose --destination target/site
[ -e target/site/example-report ] && { echo "    a removed surface left files in the publication"; exit 1; }
exit 0