Files
stack/.woodpecker/deploy.yml
kert b8a98d6271
Some checks are pending
ci/woodpecker/push/deploy Pipeline is running
ci/woodpecker/push/infra-ci Pipeline was successful
coverage 99% coverage
ci/woodpecker/push/ci Pipeline was successful
fix deploy: install modern Docker CLI, use current token for rotation
- Install Docker 27.5.1 static binary + compose v2 plugin instead
  of ancient docker.io from apt (API 1.41 vs required 1.44)
- Read current GITEA_TOKEN from .env before rotation so the API
  call to change_admin_password uses a valid token, not the derived
  placeholder hash
- Set DOCKER_HOST for the static binary
2026-03-23 09:48:11 -04:00

305 lines
10 KiB
YAML

# ── Deploy ───────────────────────────────────────────────────────
# Builds the Python package, pushes it to Gitea's PyPI registry,
# builds, scans, and pushes container images, then updates the
# host working copy and restarts all changed services.
# Only runs on pushes to main (i.e. after PR merge).
#
# Image naming:
# gitea.homelab.fhirworx.io/homelab/<service>:sha-<8chars>
#
# Buildkit pushes via HTTP through Traefik (TLS terminated at edge).
# DNS resolved by CoreDNS via Traefik UDP on the CI network.
when:
- event: push
branch: main
variables:
- &buildx_image woodpeckerci/plugin-docker-buildx:5-insecure
- &buildx_base
buildkit_config: |
[registry."gitea.homelab.fhirworx.io"]
http = true
registry: gitea.homelab.fhirworx.io
username:
from_secret: registry_user
password:
from_secret: registry_pass
- &trivy_scan
image: aquasec/trivy:latest
- &diag_env
UV_PYTHON_PREFERENCE: only-system
UV_LINK_MODE: copy
UV_PROJECT_ENVIRONMENT: .venv
GITEA_TOKEN:
from_secret: gitea_token
steps:
# ── Python package ──────────────────────────────────────────
- name: build-package
image: ghcr.io/astral-sh/uv:python3.13-bookworm-slim
commands:
- BASE=$(grep '^version' pyproject.toml | head -1 | sed 's/.*"\(.*\)"/\1/')
- uv version "$BASE.dev${CI_PIPELINE_NUMBER}" --no-sync
- uv build --out-dir dist/
- ls -lh dist/
- name: publish-package
image: ghcr.io/astral-sh/uv:python3.13-bookworm-slim
environment:
REGISTRY_USER:
from_secret: registry_user
REGISTRY_PASS:
from_secret: registry_pass
commands:
- uv publish --publish-url http://gitea:3000/api/packages/homelab/pypi --username "$REGISTRY_USER" --password "$REGISTRY_PASS" dist/*
depends_on:
- build-package
# ── Notebooks image ─────────────────────────────────────────
- name: build-push-notebooks
image: *buildx_image
settings:
<<: *buildx_base
repo: gitea.homelab.fhirworx.io/homelab/notebooks
dockerfile: notebooks/Dockerfile
context: notebooks/
tags:
- "sha-${CI_COMMIT_SHA:0:8}"
- latest
- name: scan-notebooks
<<: *trivy_scan
commands:
- trivy image --image-src remote --insecure --severity HIGH,CRITICAL --exit-code 0 --format json
-o notebooks-scan.json
"gitea.homelab.fhirworx.io/homelab/notebooks:sha-${CI_COMMIT_SHA:0:8}"
depends_on:
- build-push-notebooks
# ── Zotero image ────────────────────────────────────────────
- name: build-push-zotero
image: *buildx_image
settings:
<<: *buildx_base
repo: gitea.homelab.fhirworx.io/homelab/zotero
dockerfile: zotero/Dockerfile
context: zotero/
tags:
- "sha-${CI_COMMIT_SHA:0:8}"
- latest
- name: scan-zotero
<<: *trivy_scan
commands:
- trivy image --image-src remote --insecure --severity HIGH,CRITICAL --exit-code 0 --format json
-o zotero-scan.json
"gitea.homelab.fhirworx.io/homelab/zotero:sha-${CI_COMMIT_SHA:0:8}"
depends_on:
- build-push-zotero
# ── Docs image ──────────────────────────────────────────────
- name: prep-docs-context
image: alpine:3
volumes:
- /home/kert/stack/data:/host-data:ro
commands:
- mkdir -p data
- cp /host-data/bib.sqlite data/ 2>/dev/null || true
- name: build-push-docs
image: *buildx_image
settings:
<<: *buildx_base
repo: gitea.homelab.fhirworx.io/homelab/docs
dockerfile: docs/Dockerfile
context: .
tags:
- "sha-${CI_COMMIT_SHA:0:8}"
- latest
depends_on:
- prep-docs-context
- name: scan-docs
<<: *trivy_scan
commands:
- trivy image --image-src remote --insecure --severity HIGH,CRITICAL --exit-code 0 --format json
-o docs-scan.json
"gitea.homelab.fhirworx.io/homelab/docs:sha-${CI_COMMIT_SHA:0:8}"
depends_on:
- build-push-docs
# ── API image ───────────────────────────────────────────────
- name: build-push-api
image: *buildx_image
settings:
<<: *buildx_base
repo: gitea.homelab.fhirworx.io/homelab/api
dockerfile: api/Dockerfile
context: .
tags:
- "sha-${CI_COMMIT_SHA:0:8}"
- latest
- name: scan-api
<<: *trivy_scan
commands:
- trivy image --image-src remote --insecure --severity HIGH,CRITICAL --exit-code 0 --format json
-o api-scan.json
"gitea.homelab.fhirworx.io/homelab/api:sha-${CI_COMMIT_SHA:0:8}"
depends_on:
- build-push-api
# ── MC (MinIO Client) sidecar ────────────────────────────────
- name: build-push-mc
image: *buildx_image
settings:
<<: *buildx_base
repo: gitea.homelab.fhirworx.io/homelab/mc
dockerfile: rustfs/Dockerfile.mc
context: rustfs/
tags:
- "sha-${CI_COMMIT_SHA:0:8}"
- latest
# ── Upload scan results ─────────────────────────────────────
- name: upload-notebooks-scan
image: woodpeckerci/plugin-s3
failure: ignore
settings:
endpoint: http://rustfs:9000
bucket: gitea
access_key:
from_secret: s3_access_key
secret_key:
from_secret: s3_secret_key
source: "notebooks-scan.json"
target: /ci/${CI_REPO}/${CI_COMMIT_SHA:0:8}/
path_style: true
depends_on:
- scan-notebooks
- name: upload-zotero-scan
image: woodpeckerci/plugin-s3
failure: ignore
settings:
endpoint: http://rustfs:9000
bucket: gitea
access_key:
from_secret: s3_access_key
secret_key:
from_secret: s3_secret_key
source: "zotero-scan.json"
target: /ci/${CI_REPO}/${CI_COMMIT_SHA:0:8}/
path_style: true
depends_on:
- scan-zotero
- name: upload-docs-scan
image: woodpeckerci/plugin-s3
failure: ignore
settings:
endpoint: http://rustfs:9000
bucket: gitea
access_key:
from_secret: s3_access_key
secret_key:
from_secret: s3_secret_key
source: "docs-scan.json"
target: /ci/${CI_REPO}/${CI_COMMIT_SHA:0:8}/
path_style: true
depends_on:
- scan-docs
- name: upload-api-scan
image: woodpeckerci/plugin-s3
failure: ignore
settings:
endpoint: http://rustfs:9000
bucket: gitea
access_key:
from_secret: s3_access_key
secret_key:
from_secret: s3_secret_key
source: "api-scan.json"
target: /ci/${CI_REPO}/${CI_COMMIT_SHA:0:8}/
path_style: true
depends_on:
- scan-api
# ── Report vulnerabilities ──────────────────────────────────
- name: report-vulns
image: ghcr.io/astral-sh/uv:python3.13-bookworm-slim
failure: ignore
environment:
<<: *diag_env
commands:
- uv sync --no-dev
- |
for f in notebooks-scan.json zotero-scan.json docs-scan.json api-scan.json; do
[ -f "$f" ] && uv run python -m api.diag.vuln "$f" || true
done
depends_on:
- scan-notebooks
- scan-zotero
- scan-docs
- scan-api
# ── Deploy + Provision (two-phase) ─────────────────────────────
# Phase 1: rotate backend passwords (ALTER ROLE, Gitea API)
# Phase 2: write .env + docker compose up (services read matching passwords)
# Phase 3: sync Woodpecker secrets + health check + rollback on failure
- name: deploy
image: ghcr.io/astral-sh/uv:python3.13-bookworm-slim
volumes:
- /run/user/1000/docker.sock:/var/run/docker.sock
- /home/kert/stack:/home/kert/stack
environment:
UV_PYTHON_PREFERENCE: only-system
UV_LINK_MODE: copy
UV_PROJECT_ENVIRONMENT: .venv
ROOT_KEY:
from_secret: root_key
commands:
# Install docker CLI (official static binary, matches host daemon)
- apt-get update -qq && apt-get install -y -qq curl git >/dev/null 2>&1
- curl -fsSL https://download.docker.com/linux/static/stable/x86_64/docker-27.5.1.tgz | tar xz -C /usr/local/bin --strip-components=1 docker/docker
- curl -fsSL -o /usr/local/bin/docker-compose https://github.com/docker/compose/releases/download/v2.35.1/docker-compose-linux-x86_64 && chmod +x /usr/local/bin/docker-compose
- mkdir -p /usr/local/lib/docker/cli-plugins && ln -sf /usr/local/bin/docker-compose /usr/local/lib/docker/cli-plugins/docker-compose
- export DOCKER_HOST=unix:///var/run/docker.sock
- cd /home/kert/stack
# Pull latest code, preserve .env
- cp .env .env.bak 2>/dev/null || true
- git fetch http://gitea:3000/homelab/stack.git main
- git reset --hard FETCH_HEAD
- cp .env.bak .env 2>/dev/null || true
# Retag registry images for compose
- TAG=sha-${CI_COMMIT_SHA:0:8}
- FQDN=gitea.homelab.fhirworx.io
- for SVC in notebooks zotero docs api mc; do
docker pull $FQDN/homelab/$SVC:$TAG &&
docker tag $FQDN/homelab/$SVC:$TAG fhirworx/$SVC:$TAG;
done
# Two-phase provision + restart + health check
- uv sync --no-dev
- uv run python -m api.auth deploy ${CI_COMMIT_SHA}
depends_on:
- publish-package
- scan-notebooks
- scan-zotero
- scan-docs
- scan-api
- build-push-mc
# ── Failure reporter ─────────────────────────────────────────
- name: report-failure
image: ghcr.io/astral-sh/uv:python3.13-bookworm-slim
failure: ignore
environment:
<<: *diag_env
commands:
- uv sync --no-dev
- uv run python -m api.diag
when:
- status: [failure]