feat(release): M5 — config doctor, Docker assets, self-hosting smoke#28
Merged
Conversation
…or M5 Closes the executable gaps in the M5 self-hosting/release-readiness pass: - config: add `Config::load` + `Config::check` validation surfacing placeholder secrets, missing PEM/coven-code binary, empty/duplicate familiars; covered by unit tests. - server: add `doctor` subcommand (exit-coded preflight) and make `serve` fail fast on config errors instead of crashing mid-request. - docker: real multi-stage Dockerfile (non-root, secret-free), compose.yaml, and .dockerignore replacing the inline doc snippet. - scripts: smoke-webhook.sh exercising unsigned/bad/valid HMAC paths; verified locally against a booted server (401/401/200). - docs: self-hosting guide wired to the committed Docker assets, doctor step, and signed-webhook smoke; README literal-\n fix + doctor/docker steps. - RELEASE.md: gate checklist (fmt/check/clippy/test/docs-smoke green; disposable-repo E2E remains human-gated before tagging). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Adds a release-ops “M5” slice to support clean self-hosting: a config “doctor” validator (also enforced at server startup), container assets (Dockerfile/Compose/.dockerignore), and an end-to-end webhook signature smoke script, plus documentation/runbook updates.
Changes:
- Introduce
coven-github doctor --config <path>and wire semantic config validation intoservestartup. - Add production-shaped Docker/Compose assets for self-hosting and document the workflow.
- Add a webhook signature smoke test script and incorporate it into docs/release gates.
Reviewed changes
Copilot reviewed 10 out of 11 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| scripts/smoke-webhook.sh | Adds a local script to smoke-test webhook signature enforcement end-to-end. |
| RELEASE.md | Adds a release gate checklist including doctor + webhook smoke validation. |
| README.md | Documents running doctor before serving and points to container assets. |
| docs/self-hosting.md | Expands self-hosting docs: doctor usage, smoke test, and updated Docker guidance. |
| Dockerfile | Adds a multi-stage container build and unprivileged runtime image for the server. |
| crates/server/src/main.rs | Adds doctor CLI subcommand and runs config validation on serve startup. |
| crates/config/src/lib.rs | Implements config loading + semantic validation diagnostics and tests. |
| crates/config/Cargo.toml | Adds toml dependency for config parsing in the config crate. |
| compose.yaml | Adds a Compose service definition for running the server and mounting config/keys. |
| Cargo.lock | Locks new dependency additions (toml). |
| .dockerignore | Excludes build outputs and sensitive files (keys, local config, PEMs) from build context. |
Comments suppressed due to low confidence (1)
compose.yaml:33
- The container runs as an unprivileged user (uid 10001), but the named volume mounted at /tmp/coven-github-tasks will typically be owned by root inside the container. The worker creates per-task directories under workspace_root, so this can fail with EACCES at runtime. Prefer a tmpfs mount for truly-ephemeral workspaces, or document/chown a writable path for uid 10001.
volumes:
# Config and secrets are mounted read-only — never baked into the image.
- ./config:/config:ro
- ./keys:/keys:ro
# Ephemeral per-task workspaces. Keep worker.workspace_root pointed here.
- coven-workspaces:/tmp/coven-github-tasks
environment:
# Adjust log verbosity, e.g. RUST_LOG=coven_github=debug
RUST_LOG: "coven_github=info"
restart: unless-stopped
volumes:
coven-workspaces:
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+101
to
+108
| PathStatus::Ok => { | ||
| if !pem_looks_valid(&self.github.private_key_path) { | ||
| out.push(Diagnostic::warning( | ||
| "github.private_key_path", | ||
| "file does not start with a PEM header ('-----BEGIN') — confirm it is the downloaded private key.", | ||
| )); | ||
| } | ||
| } |
Comment on lines
+111
to
+112
| let secret = self.github.webhook_secret.trim(); | ||
| if secret.is_empty() { |
Comment on lines
+277
to
+278
| /// True if `bin` resolves to an executable: either an existing file at the given | ||
| /// path, or (for a bare name) a file found on `PATH`. |
Comment on lines
+362
to
+369
| fn tmpdir() -> PathBuf { | ||
| // Unique-enough temp dir without pulling in an extra dependency. | ||
| let base = | ||
| std::env::temp_dir().join(format!("coven-github-cfg-test-{}", std::process::id())); | ||
| let dir = base.join(format!("{:p}", &base)); | ||
| std::fs::create_dir_all(&dir).unwrap(); | ||
| dir | ||
| } |
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 M5 release-ops slice — everything needed to self-host coven-github cleanly. Rebased onto current main so it's purely additive (779+/16−); no overlap with the headless-contract/worker work from #27.
Config doctor
coven-github doctor --config <path>validates config before you serve: catches placeholder secrets, missing PEM / coven-code binary, malformed[[familiars]], etc. (crates/config+416, wired intocrates/server/src/main.rs).Container + self-hosting
Dockerfile+compose.yaml+.dockerignoreRELEASE.mdrelease runbookdocs/self-hosting.mdSmoke test
scripts/smoke-webhook.sh— end-to-end webhook smoke against a running instance.Verification (local, matches CI)
cargo check --all-targets→ cleancargo clippy --all-targets -- -D warnings→ cleanContext
This is the last of the three in-flight coven-github branches. With #27 (contract + worker resilience) already merged and
feat/github-correctness-issues-8-9-4subsumed by it, landing this leavesmainas the single source of truth ahead of accepting external PRs tomorrow.