refs #94 #95 #96 #97 - Add rustfs/Dockerfile.mc: least-privilege mc sidecar (non-root, read-only fs, all caps dropped, tmpfs for config) - Add mc service to compose.yml with storage network access only - Add rclone WebDAV service using env-based S3 config, serving the zotero bucket with HTTP basic auth - Add Traefik route at webdav.homelab.fhirworx.io - Add zotero.json IAM policy for bucket access - Add mc image to deploy, infra-ci, and rebuild-all pipelines - Add WEBDAV_* env vars to .env.example
225 lines
7.4 KiB
YAML
225 lines
7.4 KiB
YAML
# ── Infrastructure quality gate ──────────────────────────────────
|
|
# Validates Dockerfiles, config files, and container builds for
|
|
# every service in the stack. Runs in parallel with ci.yml;
|
|
# path-filtered so only relevant steps execute.
|
|
|
|
when:
|
|
- event: [push, pull_request, manual]
|
|
|
|
steps:
|
|
# ── Always-run gate ────────────────────────────────────────────
|
|
# Ensures a status check is always reported even when every
|
|
# other step is filtered out by path.
|
|
- name: infra-gate
|
|
image: alpine:3
|
|
commands:
|
|
- echo "infra-ci gate passed"
|
|
|
|
# ── Notebooks image ────────────────────────────────────────────
|
|
- name: hadolint-notebooks
|
|
image: hadolint/hadolint:latest-debian
|
|
commands:
|
|
- hadolint notebooks/Dockerfile
|
|
when:
|
|
- path: "notebooks/**"
|
|
|
|
- name: build-notebooks
|
|
image: woodpeckerci/plugin-docker-buildx
|
|
settings:
|
|
dockerfile: notebooks/Dockerfile
|
|
context: notebooks/
|
|
tags: ["ci-test"]
|
|
daemon_off: true
|
|
dry_run: true
|
|
volumes:
|
|
- /run/user/1000/docker.sock:/var/run/docker.sock
|
|
depends_on:
|
|
- hadolint-notebooks
|
|
when:
|
|
- path: "notebooks/**"
|
|
|
|
# ── Zotero image ───────────────────────────────────────────────
|
|
- name: hadolint-zotero
|
|
image: hadolint/hadolint:latest-debian
|
|
commands:
|
|
- hadolint zotero/Dockerfile
|
|
when:
|
|
- path: "zotero/**"
|
|
|
|
- name: build-zotero
|
|
image: woodpeckerci/plugin-docker-buildx
|
|
settings:
|
|
dockerfile: zotero/Dockerfile
|
|
context: zotero/
|
|
tags: ["ci-test"]
|
|
daemon_off: true
|
|
dry_run: true
|
|
volumes:
|
|
- /run/user/1000/docker.sock:/var/run/docker.sock
|
|
depends_on:
|
|
- hadolint-zotero
|
|
when:
|
|
- path: "zotero/**"
|
|
|
|
# ── Docs image ────────────────────────────────────────────────
|
|
- name: hadolint-docs
|
|
image: hadolint/hadolint:latest-debian
|
|
commands:
|
|
- hadolint docs/Dockerfile
|
|
when:
|
|
- path: "docs/**"
|
|
|
|
- name: build-docs
|
|
image: woodpeckerci/plugin-docker-buildx
|
|
settings:
|
|
dockerfile: docs/Dockerfile
|
|
context: .
|
|
tags: ["ci-test"]
|
|
daemon_off: true
|
|
dry_run: true
|
|
volumes:
|
|
- /run/user/1000/docker.sock:/var/run/docker.sock
|
|
depends_on:
|
|
- hadolint-docs
|
|
when:
|
|
- path: "docs/**"
|
|
|
|
# ── MC (MinIO Client) sidecar ─────────────────────────────────
|
|
- name: hadolint-mc
|
|
image: hadolint/hadolint:latest-debian
|
|
commands:
|
|
- hadolint rustfs/Dockerfile.mc
|
|
when:
|
|
- path: "rustfs/**"
|
|
|
|
- name: build-mc
|
|
image: woodpeckerci/plugin-docker-buildx
|
|
settings:
|
|
dockerfile: rustfs/Dockerfile.mc
|
|
context: rustfs/
|
|
tags: ["ci-test"]
|
|
daemon_off: true
|
|
dry_run: true
|
|
volumes:
|
|
- /run/user/1000/docker.sock:/var/run/docker.sock
|
|
depends_on:
|
|
- hadolint-mc
|
|
when:
|
|
- path: "rustfs/**"
|
|
|
|
# ── API image ─────────────────────────────────────────────────
|
|
- name: hadolint-api
|
|
image: hadolint/hadolint:latest-debian
|
|
commands:
|
|
- hadolint api/Dockerfile
|
|
when:
|
|
- path:
|
|
- "api/**"
|
|
- "src/**"
|
|
- "pyproject.toml"
|
|
|
|
- name: build-api
|
|
image: woodpeckerci/plugin-docker-buildx
|
|
settings:
|
|
dockerfile: api/Dockerfile
|
|
context: .
|
|
tags: ["ci-test"]
|
|
daemon_off: true
|
|
dry_run: true
|
|
volumes:
|
|
- /run/user/1000/docker.sock:/var/run/docker.sock
|
|
depends_on:
|
|
- hadolint-api
|
|
when:
|
|
- path:
|
|
- "api/**"
|
|
- "src/**"
|
|
- "pyproject.toml"
|
|
|
|
# ── Nginx / Dashboard ─────────────────────────────────────────
|
|
- name: validate-nginx
|
|
image: nginx:alpine
|
|
commands:
|
|
- cp nginx/nginx.conf /etc/nginx/nginx.conf
|
|
- nginx -t
|
|
when:
|
|
- path: "nginx/**"
|
|
|
|
# ── Prometheus ─────────────────────────────────────────────────
|
|
- name: validate-prometheus
|
|
image: prom/prometheus:latest
|
|
commands:
|
|
- promtool check config prometheus/prometheus.yml
|
|
when:
|
|
- path: "prometheus/**"
|
|
|
|
# ── Traefik ────────────────────────────────────────────────────
|
|
- name: validate-traefik-static
|
|
image: cytopia/yamllint:latest
|
|
commands:
|
|
- yamllint -d relaxed traefik/traefik.yml
|
|
when:
|
|
- path: "traefik/traefik.yml"
|
|
|
|
- name: validate-traefik-template
|
|
image: traefik:v3.3
|
|
environment:
|
|
DOMAIN: ci-test.fhirworx.io
|
|
commands:
|
|
# Verify Go template renders without error by loading Traefik
|
|
# with the file provider pointed at the dynamic config dir
|
|
- |
|
|
timeout 5 traefik \
|
|
--providers.file.directory=traefik/dynamic \
|
|
--api.dashboard=false \
|
|
--log.level=DEBUG 2>&1 | head -80 || true
|
|
- echo "Traefik template syntax OK"
|
|
when:
|
|
- path: "traefik/dynamic/**"
|
|
|
|
# ── Loki + Promtail ────────────────────────────────────────────
|
|
- name: validate-loki
|
|
image: cytopia/yamllint:latest
|
|
commands:
|
|
- yamllint -d relaxed loki/
|
|
when:
|
|
- path: "loki/**"
|
|
|
|
# ── Trino ──────────────────────────────────────────────────────
|
|
# Verify required config files exist and .properties have valid
|
|
# key=value syntax. jvm.config uses -flag format (not checked).
|
|
- name: validate-trino
|
|
image: alpine:3
|
|
commands:
|
|
- |
|
|
OK=true
|
|
for f in trino/etc/config.properties trino/etc/node.properties trino/etc/jvm.config; do
|
|
if [ ! -f "$f" ]; then echo "MISSING: $f"; OK=false; fi
|
|
done
|
|
ls trino/etc/catalog/*.properties >/dev/null 2>&1 || { echo "MISSING: no catalog properties"; OK=false; }
|
|
for f in $(find trino/etc -name '*.properties'); do
|
|
while IFS= read -r line; do
|
|
case "$line" in ''|'#'*|'!'*) continue ;; esac
|
|
echo "$line" | grep -q '=' || { echo "BAD LINE in $f: $line"; OK=false; }
|
|
done < "$f"
|
|
done
|
|
$OK && echo "Trino config validation passed"
|
|
$OK
|
|
when:
|
|
- path: "trino/etc/**"
|
|
|
|
# ── Failure reporter ─────────────────────────────────────────
|
|
- name: report-failure
|
|
image: ghcr.io/astral-sh/uv:python3.13-bookworm-slim
|
|
environment:
|
|
UV_PYTHON_PREFERENCE: only-system
|
|
UV_LINK_MODE: copy
|
|
UV_PROJECT_ENVIRONMENT: .venv
|
|
GITEA_TOKEN:
|
|
from_secret: gitea_token
|
|
commands:
|
|
- uv sync --no-dev
|
|
- uv run python -m api.diag
|
|
when:
|
|
- status: [failure]
|