Add Docker support and Render Blueprint#2
Conversation
Multi-stage Dockerfile (Go builder → small Alpine runtime), non-root UID 65532, /data volume for the SQLite DB and hooks.yaml. Pure-Go build with BuildKit cache mounts; HEALTHCHECK honors HOOKS_LISTEN_ADDR so it matches whatever port the binary is bound to. Image is ~33 MB and ships both `hooks` and `hooksctl` so operators can manage tokens via `docker exec`. A `render.yaml` Blueprint provisions a Docker web service plus a 1 GiB persistent disk at /data. `numInstances: 1` enforces the single-writer SQLite invariant from CLAUDE.md. Tests live in `./dockertest`, gated by the `docker` build tag so `go test ./...` stays fast. Coverage: --help output, non-root UID, both binaries shipped, init scaffold on a mounted volume, /healthz + /readyz serve, Docker HEALTHCHECK directive reaches healthy, and restart-with- persisted-state survives across container lifetimes. README and docs/quickstart.md gain container + Render walkthroughs.
|
Warning Rate limit exceeded
You’ve run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
📝 WalkthroughWalkthroughThis PR adds Docker containerization to the hooks relay, enabling local container development and production deployment on Render. It includes a two-stage Dockerfile, Makefile targets for building and running containers, integration tests validating image correctness, a Render Blueprint for one-click deployment, and updated documentation. ChangesDocker Containerization of Hooks Relay
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@dockertest/docker_test.go`:
- Around line 104-113: The test currently prints raw command output from
exec.Command(...).CombinedOutput() in t.Fatalf calls (variables out and err)
which may leak one-time admin tokens; change the failure handling in the
docker_test.go block that runs "docker ... init" so it does not include raw out
in logs: on error call t.Fatalf with a generic message including err but not
out, and when asserting strings.Contains fails compute a safe digest (e.g.,
sha256.Sum256(out)) and include only a short, non-secret 4-byte hex prefix of
that digest in the failure message instead of the full output; update the two
t.Fatalf sites referencing out and err accordingly and keep the strings.Contains
check logic the same.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 4223db7e-6c56-4e4e-81aa-a681a809ff1a
📒 Files selected for processing (8)
.dockerignoreDockerfileMakefileREADME.mddockertest/doc.godockertest/docker_test.godocs/quickstart.mdrender.yaml
…l race Publish previously snapshotted the subscriber channels under the mutex, released it, then performed non-blocking sends. Between the unlock and the send, a concurrent Unsubscribe could close one of those channels — sending on a closed channel panics, even with select/default. The race detector flagged it on a busy CI runner running TestSubscribeReplayThenLive under -race. Hold the mutex for the duration of Publish. Each iteration is an O(1) non-blocking send, so the lock is held only for the time it takes to walk the subscriber map; the "publishers never block" semantics are preserved. Verified with `go test -race -count=20 ./internal/pubsub/... ./internal/subscribe/...`.
- Dockerfile: replace `COPY . .` with explicit `COPY cmd/` + `COPY internal/` (SonarQube docker:S6470 hotspot: defence-in-depth against shipping secrets/.git/state, beyond what .dockerignore filters). - dockertest/docker_test.go: redact `hooks init` output from t.Fatalf messages — the init command prints a one-time admin token and a bootstrap signup code, both of which would otherwise land in CI logs that are public on PRs (CodeRabbit feedback; matches the CLAUDE.md "no plaintext secrets in logs" policy). - dockertest/docker_test.go: inline the `uid := strings.TrimSpace(...)` short-decl since `uid` was used only in the comparison (SonarQube godre:S8193 code smell).
|
fix(config): honor $PORT directly (PR #2 follow-up)
test(docker): close SIGTERM, hooksctl-vs-server, 0o755 coverage gaps from PR #2



Summary
Dockerfile(Go builder → small Alpine runtime, non-root UID 65532, ~33 MB) with BuildKit cache mounts, pure-Go build (modernc.org/sqlite, no cgo), and a HEALTHCHECK that honorsHOOKS_LISTEN_ADDR.render.yamlBlueprint provisions a Docker web service plus a 1 GiB persistent disk at/data.numInstances: 1enforces the single-writer SQLite invariant../dockertestpackage, gated by thedockerbuild tag sogo test ./...stays fast — covers--help, non-root, both binaries, init scaffold, /healthz + /readyz, the Docker HEALTHCHECK directive, and restart-with-persisted-state.docs/quickstart.mdgain container and Render walkthroughs.Test plan
make docker-test(7 tests pass; ~10s with cache, ~50s cold)make test,make lint,go vet ./...hooks:devlocally; ran end-to-end with a real signed Render webhook (HTTP 202), bad signature (HTTP 401), replay dedupe (HTTP 200)hooksctlreachable viadocker execReview notes
A few things were surfaced by review and intentionally deferred:
PORTcontract.render.yamlhardcodesHOOKS_LISTEN_ADDR=:10000to match Render's current DockerPORTdefault. The cleaner fix is to teachinternal/configto honor$PORTdirectly — out of scope for this PR; happy to do as a follow-up.hooksctl-against-running-server, and the host-side0o755permissions edge case (operators following the README literally withoutchmod-ing their data dir).golang:1.26-alpineandalpine:3.20are pinned by tag, not by sha256 digest. Worth doing if reproducibility becomes a concern.tzdatanot installed. No callers oftime.LoadLocationin the tree; if a future feature needs IANA zones, add it back.Summary by CodeRabbit
New Features
Documentation
Tests