Skip to content

feat(release): M5 — config doctor, Docker assets, self-hosting smoke#28

Merged
BunsDev merged 1 commit into
mainfrom
feat/coven-github-m5-release
Jul 3, 2026
Merged

feat(release): M5 — config doctor, Docker assets, self-hosting smoke#28
BunsDev merged 1 commit into
mainfrom
feat/coven-github-m5-release

Conversation

@BunsDev

@BunsDev BunsDev commented Jul 3, 2026

Copy link
Copy Markdown
Member

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 into crates/server/src/main.rs).

Container + self-hosting

Smoke test

  • scripts/smoke-webhook.sh — end-to-end webhook smoke against a running instance.

Verification (local, matches CI)

  • cargo check --all-targets → clean
  • cargo clippy --all-targets -- -D warnings → clean

Context

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-4 subsumed by it, landing this leaves main as the single source of truth ahead of accepting external PRs tomorrow.

…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>
Copilot AI review requested due to automatic review settings July 3, 2026 13:22

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 into serve startup.
  • 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 thread crates/config/src/lib.rs
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 thread crates/config/src/lib.rs
Comment on lines +111 to +112
let secret = self.github.webhook_secret.trim();
if secret.is_empty() {
Comment thread crates/config/src/lib.rs
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 thread crates/config/src/lib.rs
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
}
@BunsDev BunsDev merged commit e9d5c00 into main Jul 3, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants