diff --git a/.gitea/workflows/docker.yml b/.gitea/workflows/docker.yml index 5fea119..e906357 100644 --- a/.gitea/workflows/docker.yml +++ b/.gitea/workflows/docker.yml @@ -52,6 +52,9 @@ jobs: IMAGE="git.hiddenden.cafe/${GITHUB_REPOSITORY,,}" echo "image=${IMAGE}" >> "$GITHUB_OUTPUT" echo "sha_tag=${IMAGE}:sha-${GITHUB_SHA::12}" >> "$GITHUB_OUTPUT" + # Per-commit container name: the self-hosted runner shares the host + # Docker daemon, so a fixed name collides across concurrent/re-run jobs. + echo "container=familiar-smoke-${GITHUB_SHA::12}" >> "$GITHUB_OUTPUT" if [ "${GITHUB_REF_NAME}" = "main" ]; then echo "branch_tags=${IMAGE}:latest ${IMAGE}:main" >> "$GITHUB_OUTPUT" else @@ -67,8 +70,13 @@ jobs: run: | set -euo pipefail IMG="${{ steps.meta.outputs.sha_tag }}" + CONTAINER="${{ steps.meta.outputs.container }}" TOKEN="smoke-$(date +%s)" + # Remove any container left behind by a killed/re-run job before we + # reuse the name (shared host daemon → stale containers can survive). + docker rm -f "$CONTAINER" >/dev/null 2>&1 || true + # 1. Runs as a non-root user (uid 1000). uid=$(docker run --rm --entrypoint id "$IMG" -u) echo "container uid: $uid" @@ -83,13 +91,13 @@ jobs: # 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" + docker run -d --name "$CONTAINER" -e FAMILIAR_HTTP_TOKEN="$TOKEN" "$IMG" # probe "" -> prints the status code - probe() { docker exec familiar-smoke python -c "import httpx; print(($1).status_code)"; } + probe() { docker exec "$CONTAINER" python -c "import httpx; print(($1).status_code)"; } for i in $(seq 1 30); do - if docker exec familiar-smoke python -c \ + if docker exec "$CONTAINER" python -c \ "import httpx; httpx.get('http://127.0.0.1:8080/healthz', timeout=5)" >/dev/null 2>&1; then break fi @@ -98,7 +106,7 @@ jobs: echo "== /healthz (expect 200) ==" 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 "$CONTAINER"; exit 1; } echo "== MCP without token (expect 401) ==" 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':{}})") @@ -106,7 +114,7 @@ jobs: echo "== MCP with valid token (expect 200) ==" 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'}}})") - [ "$code" = "200" ] || { echo "::error::authenticated MCP returned $code"; docker logs familiar-smoke; exit 1; } + [ "$code" = "200" ] || { echo "::error::authenticated MCP returned $code"; docker logs "$CONTAINER"; exit 1; } echo "Image smoke-test passed." @@ -135,7 +143,7 @@ jobs: if: always() shell: bash run: | - docker rm -f familiar-smoke || true + docker rm -f ${{ steps.meta.outputs.container }} || true docker rmi -f ${{ steps.meta.outputs.sha_tag }} ${{ steps.meta.outputs.branch_tags }} || true docker image prune -f || true docker builder prune -f || true