7c2417f5a9
Add least-privilege 'permissions: contents: read' to quality, security and docker-ci workflows (actions/missing-workflow-permissions). Harden markdown table cell escaping in exportMarkdown: escape backslash before pipe and collapse newlines so untrusted values can't break the table (js/incomplete-sanitization). Add regression tests. ha-relevant: maybe
87 lines
3.4 KiB
YAML
87 lines
3.4 KiB
YAML
name: Docker CI
|
|
|
|
on:
|
|
push:
|
|
branches: [main]
|
|
pull_request:
|
|
branches: [main]
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
jobs:
|
|
smoke-and-integration:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
# ── Write a minimal .env required by env_file: .env in docker-compose.yml ─
|
|
# AUTH_PASSWORD_HASH is NOT set here — it's injected via docker-compose.ci.yml
|
|
# environment section using $$ escaping to avoid docker-compose $VAR expansion.
|
|
- name: Write .env
|
|
run: |
|
|
{
|
|
echo "SECRET_KEY=ci-only-secret-key-not-for-production"
|
|
echo "SQLITE_PATH=/app/data/homelab.db"
|
|
echo 'CORS_ORIGINS=["http://localhost:3000"]'
|
|
echo 'SCANNER_RANGES=["127.0.0.1/32"]'
|
|
echo "STATUS_CHECKER_INTERVAL=300"
|
|
echo "MCP_API_KEY=ci-mcp-key"
|
|
echo "MCP_SERVICE_KEY=ci-svc-key"
|
|
} > .env
|
|
|
|
# ── Build + start backend and frontend (skip mcp) ─────────────────────────
|
|
# docker-compose.ci.yml: exposes port 8000 + injects AUTH_* env vars
|
|
- name: Build images
|
|
run: docker compose -f docker-compose.yml -f docker-compose.ci.yml build backend frontend
|
|
|
|
- name: Start stack
|
|
run: docker compose -f docker-compose.yml -f docker-compose.ci.yml up -d backend frontend
|
|
|
|
# ── Wait for backend to be healthy (max 60 s) ─────────────────────────────
|
|
- name: Wait for backend health
|
|
run: |
|
|
echo "Waiting for backend..."
|
|
for i in $(seq 1 30); do
|
|
if curl -sf http://localhost:8000/api/v1/health > /dev/null 2>&1; then
|
|
echo "Backend is up after ${i}s"
|
|
exit 0
|
|
fi
|
|
sleep 2
|
|
done
|
|
echo "Backend did not become healthy in time" >&2
|
|
docker compose -f docker-compose.yml -f docker-compose.ci.yml logs backend
|
|
exit 1
|
|
|
|
# ── Smoke: frontend serves HTML ───────────────────────────────────────────
|
|
- name: Smoke — frontend returns 200
|
|
run: |
|
|
STATUS=$(curl -so /dev/null -w "%{http_code}" http://localhost:3000/)
|
|
[ "$STATUS" = "200" ] || { echo "Frontend returned $STATUS"; exit 1; }
|
|
|
|
# ── Tier 3: integration tests against the live stack ──────────────────────
|
|
- uses: actions/setup-python@v5
|
|
with:
|
|
python-version: '3.11'
|
|
|
|
- name: Install backend test deps
|
|
run: pip install --quiet -r backend/requirements.txt
|
|
|
|
- name: Run integration tests
|
|
env:
|
|
INTEGRATION_BASE_URL: http://localhost:8000
|
|
INTEGRATION_USERNAME: admin
|
|
INTEGRATION_PASSWORD: admin
|
|
run: |
|
|
cd backend
|
|
pytest tests/test_integration.py -v
|
|
|
|
# ── Teardown ──────────────────────────────────────────────────────────────
|
|
- name: Dump logs on failure
|
|
if: failure()
|
|
run: docker compose -f docker-compose.yml -f docker-compose.ci.yml logs
|
|
|
|
- name: Stop stack
|
|
if: always()
|
|
run: docker compose -f docker-compose.yml -f docker-compose.ci.yml down -v
|