Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Keep the Docker build context small and secret-free.
target/
.git/
.worktrees/

# Never ship secrets or local config into an image.
keys/
config/local.toml
*.pem

# Editor / OS noise
.DS_Store
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

43 changes: 43 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# syntax=docker/dockerfile:1
#
# Multi-stage build for the coven-github webhook server.
#
# docker build -t coven-github .
# docker run --rm -p 3000:3000 \
# -v "$PWD/config:/config:ro" -v "$PWD/keys:/keys:ro" \
# coven-github serve --config /config/local.toml
#
# See docs/self-hosting.md for the full walkthrough and compose.yaml for a
# ready-to-edit Compose service.

# ── Builder ─────────────────────────────────────────────────────────────────
FROM rust:1.83-bookworm AS builder
WORKDIR /app

# Copy the whole workspace and build the release binary. (A cold build pulls the
# full dependency tree; subsequent builds reuse Docker's layer cache.)
COPY . .
RUN cargo build --release --locked -p coven-github

# ── Runtime ─────────────────────────────────────────────────────────────────
FROM debian:bookworm-slim AS runtime

# ca-certificates: TLS to api.github.com. git: clone target repos.
RUN apt-get update \
&& apt-get install -y --no-install-recommends ca-certificates git \
&& rm -rf /var/lib/apt/lists/*

# Run as an unprivileged user. Secrets are mounted read-only at runtime, never
# baked into the image (see the .dockerignore — keys/ and config/local.toml are
# excluded from the build context).
RUN useradd --system --create-home --uid 10001 coven
USER coven
WORKDIR /home/coven

COPY --from=builder /app/target/release/coven-github /usr/local/bin/coven-github

EXPOSE 3000

# `doctor` exits non-zero on a broken config, so it works as a preflight check.
ENTRYPOINT ["coven-github"]
CMD ["serve", "--config", "/config/local.toml"]
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,10 +136,16 @@ cp config/example.toml config/local.toml
# Then set in config/local.toml: github.app_id, github.private_key_path,
# github.webhook_secret, worker.coven_code_bin, and a [[familiars]] block.

# Validate the config (catches placeholder secrets, missing PEM/binary, etc.)
./target/release/coven-github doctor --config config/local.toml

# Run
./target/release/coven-github serve --config config/local.toml
```

Prefer containers? A multi-stage [`Dockerfile`](Dockerfile) and
[`compose.yaml`](compose.yaml) ship in the repo root.

See [docs/self-hosting.md](docs/self-hosting.md) for full setup including GitHub App registration. For a minimal familiar route, start from [`examples/familiar-github-starter`](examples/familiar-github-starter/).

---
Expand Down
69 changes: 69 additions & 0 deletions RELEASE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# Release checklist — coven-github

The first usable release (`v0.1.0`) ships only after every gate below passes.
Gates 1–5 are runnable from a clean checkout with no GitHub credentials. Gate 6
needs a disposable repo with the App installed and a live `coven-code` binary —
it is the human-in-the-loop step that authorizes the tag.

## Gates

```bash
# 1. Format
cargo fmt --all -- --check

# 2. Type/borrow check
cargo check --workspace

# 3. Lint (warnings are errors)
cargo clippy --workspace --all-targets -- -D warnings

# 4. Tests
cargo test --workspace

# 5. Docs smoke — config validation + webhook signature path
# (boot the server against a throwaway config, then:)
cargo build --release -p coven-github
./target/release/coven-github doctor --config config/local.toml
scripts/smoke-webhook.sh http://localhost:3000/webhook "$WEBHOOK_SECRET"
```

Gate 5 detail: `doctor` must exit `0` on a filled-in config, and
`scripts/smoke-webhook.sh` must report unsigned → 401, bad signature → 401,
valid signature → 200. See [docs/self-hosting.md](docs/self-hosting.md).

## 6. Disposable-repo end-to-end (human-gated)

On a throwaway repo with the GitHub App installed and `worker.coven_code_bin`
pointing at a real `coven-code`:

1. Open an issue and assign it to the configured bot user (or apply a
`trigger_labels` label such as `coven:fix`).
2. Confirm a Check Run appears and the familiar session starts.
3. Confirm a draft PR opens in the familiar's voice and links back to the issue.
4. Confirm the Check Run resolves to success/failure (not stuck).

Capture the issue/PR links in the release notes as evidence.

## Cut the tag

Only after gates 1–6 pass:

```bash
# Ensure the version in Cargo.toml ([workspace.package].version) is correct,
# the tree is clean, and you are on main.
git tag -s v0.1.0 -m "coven-github v0.1.0"
git push origin v0.1.0
```

> Tags are signed (`-s`). Do not push an unsigned release tag.

## Status of automatable gates (this branch)

| Gate | Result |
|---|---|
| 1. `cargo fmt --all -- --check` | ✅ clean |
| 2. `cargo check --workspace` | ✅ clean |
| 3. `cargo clippy … -D warnings` | ✅ clean |
| 4. `cargo test --workspace` | ✅ 18 passing |
| 5. docs smoke (`doctor` + `smoke-webhook.sh`) | ✅ verified locally |
| 6. disposable-repo E2E | ⏳ requires live App creds + `coven-code` |
32 changes: 32 additions & 0 deletions compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Docker Compose service for coven-github.
#
# 1. Copy config/example.toml → config/local.toml and fill it in.
# 2. Drop your GitHub App PEM into ./keys/ and point
# github.private_key_path at /keys/<your-key>.pem in local.toml.
# 3. Validate, then run:
# docker compose run --rm coven-github doctor --config /config/local.toml
# docker compose up
#
# coven-code must be reachable inside the container. Either bake it into a
# derived image and set worker.coven_code_bin to its path, or mount it via an
# extra read-only volume below.
services:
coven-github:
build: .
image: coven-github:local
command: ["serve", "--config", "/config/local.toml"]
ports:
- "3000:3000"
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:
1 change: 1 addition & 0 deletions crates/config/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ license.workspace = true
anyhow.workspace = true
serde.workspace = true
serde_json.workspace = true
toml.workspace = true
Loading
Loading