Compare commits

...
1 Commits
Author SHA1 Message Date
Latte 945e40b5d8 fix(ci): smoke-test the image from inside its own container via docker exec
CI / lint (pull_request) Successful in 56s
docker / lint (pull_request) Successful in 54s
CI / test (pull_request) Successful in 1m2s
CI / publish (pull_request) Has been skipped
docker / test (pull_request) Successful in 57s
docker / docker (pull_request) Successful in 41s
The smoke test probed the server over the network, which fails on the
self-hosted runner: the job step runs in a container that shares the host
Docker socket but sits on a different network, so it can reach neither a
published host port (-p lands on the runner host) nor the server
container's bridge IP (different network → curl connect hangs, so the job
looked stuck rather than failing).

Probe from inside the server container with `docker exec` instead: it goes
through the Docker socket and runs in the server's own netns, where
127.0.0.1:8080 always works regardless of runner topology. The image ships
python + httpx, so no curl or extra image pull is needed. Drop the now
unnecessary -p publish.
2026-07-05 13:42:40 +02:00
+21 -11
View File
@@ -74,28 +74,38 @@ jobs:
echo "container uid: $uid" echo "container uid: $uid"
[ "$uid" = "1000" ] || { echo "::error::image runs as uid $uid, expected 1000"; exit 1; } [ "$uid" = "1000" ] || { echo "::error::image runs as uid $uid, expected 1000"; exit 1; }
# 2. Boot the server and probe it over HTTP. # 2. Boot the server and probe it from *inside* its own container via
docker run -d --name familiar-smoke -e FAMILIAR_HTTP_TOKEN="$TOKEN" -p 18080:8080 "$IMG" # `docker exec`. On self-hosted runners the job step runs in a container
# that shares the host's Docker socket but sits on a different network,
# so it can reach neither a published host port (-p lands on the runner
# host, not this step's netns) nor the server container's bridge IP
# (different network → connect hangs). `docker exec` goes through the
# socket and runs the probe in the server's own netns, where
# 127.0.0.1:8080 always works regardless of runner topology. The image
# ships python + httpx, so no curl or extra pull is needed.
docker run -d --name familiar-smoke -e FAMILIAR_HTTP_TOKEN="$TOKEN" "$IMG"
# probe "<httpx call returning a Response>" -> prints the status code
probe() { docker exec familiar-smoke python -c "import httpx; print(($1).status_code)"; }
for i in $(seq 1 30); do for i in $(seq 1 30); do
if curl -fsS "http://127.0.0.1:18080/healthz" >/dev/null 2>&1; then break; fi if docker exec familiar-smoke python -c \
"import httpx; httpx.get('http://127.0.0.1:8080/healthz', timeout=5)" >/dev/null 2>&1; then
break
fi
sleep 1 sleep 1
done done
echo "== /healthz (expect 200) ==" echo "== /healthz (expect 200) =="
code=$(curl -s -o /dev/null -w '%{http_code}' "http://127.0.0.1:18080/healthz") code=$(probe "httpx.get('http://127.0.0.1:8080/healthz', timeout=10)")
[ "$code" = "200" ] || { echo "::error::/healthz returned $code"; docker logs familiar-smoke; exit 1; } [ "$code" = "200" ] || { echo "::error::/healthz returned $code"; docker logs familiar-smoke; exit 1; }
echo "== MCP without token (expect 401) ==" echo "== MCP without token (expect 401) =="
code=$(curl -s -o /dev/null -w '%{http_code}' -X POST "http://127.0.0.1:18080/mcp" \ code=$(probe "httpx.post('http://127.0.0.1:8080/mcp', timeout=10, headers={'Accept':'application/json, text/event-stream','Content-Type':'application/json'}, json={'jsonrpc':'2.0','id':1,'method':'initialize','params':{}})")
-H 'Accept: application/json, text/event-stream' -H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}')
[ "$code" = "401" ] || { echo "::error::unauthenticated MCP returned $code"; exit 1; } [ "$code" = "401" ] || { echo "::error::unauthenticated MCP returned $code"; exit 1; }
echo "== MCP with valid token (expect 200) ==" echo "== MCP with valid token (expect 200) =="
code=$(curl -s -o /dev/null -w '%{http_code}' -X POST "http://127.0.0.1:18080/mcp" \ code=$(probe "httpx.post('http://127.0.0.1:8080/mcp', timeout=10, headers={'Authorization':'Bearer $TOKEN','Accept':'application/json, text/event-stream','Content-Type':'application/json'}, json={'jsonrpc':'2.0','id':1,'method':'initialize','params':{'protocolVersion':'2025-06-18','capabilities':{},'clientInfo':{'name':'ci','version':'1'}}})")
-H "Authorization: Bearer $TOKEN" \
-H 'Accept: application/json, text/event-stream' -H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"ci","version":"1"}}}')
[ "$code" = "200" ] || { echo "::error::authenticated MCP returned $code"; docker logs familiar-smoke; exit 1; } [ "$code" = "200" ] || { echo "::error::authenticated MCP returned $code"; docker logs familiar-smoke; exit 1; }
echo "Image smoke-test passed." echo "Image smoke-test passed."