feat: hosted deployment stack — production compose, /healthz, image publish, ops runbook#71
Merged
Merged
Conversation
…ublish, ops runbook The operational half of the HOSTED.md beta gates (the six code gates are shipped). Single-VM architecture matching what the code wants: single-writer SQLite and a container worker backend that drives the host Docker daemon. - deploy/hosted/: production compose (adapter + Caddy TLS ingress + Litestream SQLite replication to Cloudflare R2), Caddyfile, litestream.yml, .env.example, and an idempotent provision.sh for Ubuntu 24.04 (Docker, firewall 22/80/443, layout, docker-gid + uid-10001 permissions). - /healthz: unauthenticated liveness/readiness route probing the store — compose healthcheck and uptime monitors point at it; leaks no tenant data. - Dockerfile: add curl for the container healthcheck. - .github/workflows/publish.yml: build/push ghcr.io/opencoven/coven-github (latest + SHA on main, semver on tags). - docs/hosted-deploy.md: first-deploy runbook, monitoring signals, backup and restore drill, upgrade and incident basics. Cross-linked from HOSTED.md. Validated: docker compose config, bash -n provision.sh, full CI gates. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Val Alexander <bunsthedev@gmail.com>
Contributor
There was a problem hiding this comment.
Pull request overview
Adds the operational “hosted” deployment stack for the coven-github GitHub App adapter (single-VM Docker Compose), plus a minimal /healthz probe and GHCR image publishing to support production rollouts and monitoring.
Changes:
- Introduces
deploy/hosted/production stack (Compose + Caddy TLS ingress + Litestream to Cloudflare R2) and an idempotent Ubuntu provisioning script. - Adds unauthenticated
GET /healthzand wires it into the server router (plus a small route test). - Adds a GH Actions workflow to publish images to GHCR and documents the end-to-end hosted deploy runbook.
Reviewed changes
Copilot reviewed 11 out of 13 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
HOSTED.md |
Cross-links the hosted operational runbook/stack into the beta gates section. |
docs/hosted-deploy.md |
Adds first-deploy + monitoring/backup/restore/upgrade incident runbook for the hosted VM stack. |
Dockerfile |
Installs curl to support container healthchecks against /healthz. |
deploy/hosted/provision.sh |
Adds host provisioning script for Docker, firewall, unattended upgrades, and /opt/coven-github layout. |
deploy/hosted/litestream.yml |
Configures Litestream replication to Cloudflare R2 with retention and sync interval. |
deploy/hosted/compose.yaml |
Defines production services (adapter, Caddy, Litestream) including healthcheck and docker-sock wiring. |
deploy/hosted/Caddyfile |
Adds TLS ingress config for the webhook domain via Caddy. |
deploy/hosted/.env.example |
Provides a template for required deployment secrets/config values. |
crates/webhook/src/routes.rs |
Implements /healthz route and adds a liveness “leaks nothing” test. |
crates/server/src/main.rs |
Wires /healthz into the axum router. |
.github/workflows/publish.yml |
Adds GHCR publish workflow for latest/SHA on main and semver tags on releases. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| let state = app_state(); | ||
| let response = healthz(State(state)).await.into_response(); | ||
| assert_eq!(response.status(), StatusCode::OK); | ||
| let bytes = axum::body::to_bytes(response.into_body(), usize::MAX) |
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Val Alexander <bunsthedev@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
The operational half of the HOSTED.md beta gates. Architecture: one VM + Docker Compose, because the store is single-writer SQLite and the container worker backend drives the host Docker daemon — a cluster buys nothing at beta scale, and Hosted Dedicated later is this same stack on a customer-dedicated VM.
deploy/hosted/— production compose (adapter + Caddy TLS ingress + Litestream → Cloudflare R2 SQLite replication, 10s sync / 30-day retention),.env.example, idempotentprovision.sh(Docker, ufw 22/80/443, unattended upgrades, uid-10001 dir ownership, docker-gid wiring for the unprivileged worker).GET /healthz— unauthenticated liveness/readiness probing the store; returns only{"ok": true}/503, no tenant data. Wired into the server router, compose healthcheck, and runbook monitoring.publish.yml— GHCR image publish (latest + SHA on main, semver on tags); Dockerfile gainscurlfor the healthcheck.docs/hosted-deploy.md— first-deploy runbook (target: gh.opencoven.ai on Hetzner), monitoring signals, backup/restore drill, upgrades, incident basics. Cross-linked from HOSTED.md's beta-gate section.Testing
cargo check --all-targets/clippy -- -D warnings/cargo test --all✅ (298 passed, incl. new healthz test)docker compose configvalidates;bash -n provision.shclean