ci / Web (lint, test, audit, build) (push) Successful in 1m1s
ci / Shell and licence headers (push) Successful in 7s
ci / Go (lint, test, vuln) (push) Failing after 2m40s
ci / Protobuf (push) Successful in 6s
ci / Release build (dry run) (push) Successful in 2m27s
ci / End-to-end (server, agents, BIND, Kea) (push) Failing after 1m26s
ci / Development environment (compose) (push) Successful in 13s
ci / Integration (real BIND and Kea) (push) Failing after 1m58s
test/e2e runs server, PostgreSQL, BIND and Kea with both agents in containers (make test-e2e, CI job End-to-end): enrollment with the command from the API, revision 1 and 2 applied and served by BIND and Kea, unchanged data creates no revision, revoking disconnects the agent while BIND keeps serving. Fixes from the first CI run: quote a spec description containing a comma, exempt the agent lock-out routes in the route protection test, whole-second certificate lifetimes, a push replacing queued pulls, the truncation marker containing the letter checked, and curl|grep -q under pipefail in the server smoke test. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
87 lines
3.2 KiB
Bash
Executable File
87 lines
3.2 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
#
|
|
# Starts the released server binary against a database and checks that it
|
|
# serves health, metrics, the API and the embedded web UI.
|
|
#
|
|
# Usage: scripts/ci/smoke-server.sh DIST_DIR
|
|
# Environment: DDI_DATABASE_URL (required), BIN_SERVER (default ddi-server)
|
|
|
|
set -euo pipefail
|
|
|
|
dist="${1:?usage: smoke-server.sh DIST_DIR}"
|
|
: "${DDI_DATABASE_URL:?DDI_DATABASE_URL must be set}"
|
|
bin_name="${BIN_SERVER:-ddi-server}"
|
|
|
|
work="$(mktemp -d)"
|
|
pid=""
|
|
cleanup() {
|
|
if [[ -n "$pid" ]]; then
|
|
kill "$pid" 2>/dev/null || true
|
|
wait "$pid" 2>/dev/null || true
|
|
fi
|
|
rm -rf "$work"
|
|
}
|
|
trap cleanup EXIT
|
|
|
|
arch="$(uname -m)"
|
|
case "$arch" in
|
|
x86_64) goarch=amd64 ;;
|
|
aarch64 | arm64) goarch=arm64 ;;
|
|
*) echo "unsupported architecture $arch" >&2; exit 1 ;;
|
|
esac
|
|
tarball="$(find "$dist" -maxdepth 1 -name "${bin_name}_*_linux_${goarch}.tar.gz" | head -n1)"
|
|
[[ -n "$tarball" ]] || { echo "no server tarball for linux/${goarch} in ${dist}" >&2; exit 1; }
|
|
tar -xzf "$tarball" -C "$work"
|
|
server="$(find "$work" -type f -name "$bin_name" | head -n1)"
|
|
|
|
"$server" version
|
|
"$server" gen-master-key -out "$work/master.key" >/dev/null
|
|
|
|
port=18443
|
|
export DDI_HTTP_LISTEN="127.0.0.1:${port}" DDI_AGENT_API_LISTEN="127.0.0.1:$((port + 1))" DDI_MASTER_KEY_FILE="$work/master.key" DDI_STATE_DIR="$work/state"
|
|
# An unreachable license server: the server must start anyway (trial).
|
|
export KEYGEN_URL="http://127.0.0.1:1"
|
|
|
|
"$server" bootstrap-admin >"$work/admin.txt"
|
|
grep -q '^password: ' "$work/admin.txt"
|
|
|
|
"$server" serve >"$work/server.log" 2>&1 &
|
|
pid=$!
|
|
base="http://127.0.0.1:${port}"
|
|
|
|
for _ in $(seq 1 60); do
|
|
if curl -fsS "$base/readyz" >/dev/null 2>&1; then break; fi
|
|
if ! kill -0 "$pid" 2>/dev/null; then cat "$work/server.log" >&2; exit 1; fi
|
|
sleep 0.5
|
|
done
|
|
|
|
fail() {
|
|
echo "FAIL: $*" >&2
|
|
cat "$work/server.log" >&2
|
|
exit 1
|
|
}
|
|
|
|
grep -q '"database":"ok"' <<<"$(curl -fsS "$base/readyz")" || fail "readyz"
|
|
grep -q '^ddi_license_writable 1' <<<"$(curl -fsS "$base/metrics")" || fail "metrics"
|
|
grep -q '"license_state":"trial"' <<<"$(curl -fsS "$base/api/v1/system/info")" || fail "system info"
|
|
|
|
# The web UI is embedded: index.html references hashed assets that load.
|
|
index="$(curl -fsS -D "$work/headers" "$base/")"
|
|
grep -q '<div id="root">' <<<"$index" || fail "index.html is not the built UI"
|
|
grep -qi '^content-security-policy:' "$work/headers" || fail "CSP header missing"
|
|
asset="$(grep -o 'src="/assets/[^"]*\.js"' <<<"$index" | head -n1 | sed 's/src="//; s/"$//')"
|
|
[[ -n "$asset" ]] || fail "no script asset in index.html"
|
|
curl -fsS -o /dev/null -D "$work/asset-headers" "$base$asset" || fail "asset $asset"
|
|
grep -qi '^cache-control: .*immutable' "$work/asset-headers" || fail "assets must be immutable"
|
|
# Client-side routes fall back to the UI.
|
|
grep -q '<div id="root">' <<<"$(curl -fsS "$base/addresses?q=x")" || fail "SPA fallback"
|
|
# Unknown API paths are JSON errors, not the UI.
|
|
code="$(curl -s -o /dev/null -w '%{http_code}' "$base/api/v1/nope")"
|
|
[[ "$code" == "401" || "$code" == "404" ]] || fail "unknown API path returned $code"
|
|
|
|
# The license trust anchor is embedded (configuration cannot replace it).
|
|
grep -q 'license trust anchor comes from configuration' "$work/server.log" && fail "trust anchor not embedded"
|
|
|
|
echo "server smoke test passed"
|