name: Test on: workflow_call: jobs: build-and-test: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - name: Build Docker image run: docker build -t learning-platform . # The production Caddyfile is otherwise never exercised by CI — the test # image below swaps in Caddyfile.test — so a parse error only surfaced at # deploy time, after the broken container had already replaced the healthy # one (issue #20/#26). Validate it here, inside the freshly built image # where it lives at /etc/caddy/Caddyfile. This runs caddy against the # exact file that ships and needs no bind mount — a `-v "$PWD":...` mount # does not propagate to the sibling Docker daemon in the Gitea runner, # which is why the earlier mount-based step failed with # "open Caddyfile: no such file or directory" (#26). # Caddyfile.test needs no separate check: the "Test homepage" step below # runs the test image and fails if that config can't serve. - name: Validate production Caddyfile run: | docker run --rm --entrypoint caddy learning-platform \ validate --adapter caddyfile --config /etc/caddy/Caddyfile - name: Build test image run: | cat > Dockerfile.test <<'EOF' FROM learning-platform COPY Caddyfile.test /etc/caddy/Caddyfile EOF docker build -t learning-platform-test -f Dockerfile.test . - name: Start container run: | docker run -d --network gitea --name test-container learning-platform-test sleep 5 - name: Test homepage run: | status=$(curl -s -o /dev/null -w "%{http_code}" http://test-container) if [ "$status" != "200" ]; then echo "Homepage failed with status $status" exit 1 fi echo "✓ Homepage OK" - name: Test security headers run: | headers=$(curl -sI http://test-container) echo "$headers" | grep -q "X-Frame-Options" || (echo "Missing X-Frame-Options" && exit 1) echo "$headers" | grep -q "X-Content-Type-Options" || (echo "Missing X-Content-Type-Options" && exit 1) echo "✓ Security headers OK" - name: Cleanup if: always() run: docker stop test-container && docker rm test-container