Skip to content

Repository files navigation

tripwire

a firewall for your repo — a contribution gatekeeper that blocks, passes, or sends change requests to review before they reach a maintainer.

local development

the demo (no docker, one command)

bun run dev:demo

A fully seeded, presentable app at http://localhost:3000 — the web head only (no worker, no api, no queue). The database is embedded PGlite (in-process Postgres, WASM) at .demo/, running the same schema and migrations as prod. It seeds a realistic story (change requests across blocked / passed / sent-to-review, an ai-review block with findings, a pending moderation item) and drops you on a populated dashboard. Re-running resets to the same clean story.

In a dev build a persona switcher (bottom-left, and on /login) jumps between the product's real states — fresh maintainer, one repo, many repos, empty dashboard, active dashboard, and anonymous (the public-run stranger view). It is dev-only (compile-time excluded from production, refused for non-local hosts).

the full stack (docker + worker + api)

bun run db:up          # postgres in docker
bun run db:migrate     # apply migrations
bun run dev            # turbo: web (:3000) + api (:8787) + worker + cloudflared tunnel

bun run dev fans out through turbo — one interactive TUI, arrow keys switch between the web/api/worker/tunnel panes. The tunnel pane prints a https://<random>.trycloudflare.com URL routed to the api (:8787); point the GitHub App webhook at <that-url>/webhooks/github to receive local deliveries.

bun run dev:local      # same, minus the cloudflared tunnel (offline)
bun run dev:web        # web head only (:3000)
bun run dev:api        # api head only (:8787)
bun run dev:worker     # worker only (queue consumer)

Set BETTER_AUTH_SECRET to enable real GitHub sign-in and the auth gates; leave it unset for the gateless "open-dev" posture.

checks

bun run typecheck
bun run check              # biome
bun run check:boundaries   # §3 dependency arrows
bun test

live E2E (nightly / pre-release, not per-PR CI)

bun test (aka bun run test:suite) proves the logic against a fake adapter. One funnel-driven harness proves the real thing against GitHub — §11 "live E2E": it needs real credentials, a running worker, a tunnel routing the sacrificial repo's webhooks, and a pushing account that is not exempt (not an org member / maintainer) on the repo, or nothing trips.

bun run test                 # interactive funnel: axis → outcome → method
bun run test --list          # the scenario registry (~18 states)
bun run test --only gate-block --expect block   # headless, scriptable
bun run test --everything    # every scriptable scenario + a summary table

bun run test:run             # → --only gate-pass       (a fresh run lands + passes)
bun run test:lifecycle       # → --only comment-lifecycle

Three prompts reach ~18 scenarios across the gate, the comment, the contributor, the edge cases, and the hybrids (which hand off a human GitHub action mid-run). Scenarios are data (scripts/e2e/scenarios.ts) — adding a state is a new entry, not new menu code. Assertions read real GitHub state via gh api; the run exits non-zero on any failure, so it can gate a release. Full docs, the two accounts, and the degraded-floor hook: scripts/e2e/README.md.

comment-lifecycle is the regression guard for the incident where a block→pass resolution was edited in place and vanished (dither-kit#8). Cleanup is idempotent and fires on interrupt — re-running is a clean slate.

Not automated (by design): whether the copy READS well. The harness proves the mechanics — one comment vs. a struck-through supersede + a fresh resolution, the dismissed review, the flipped check. A human reads the thread once; taste stays human.

About

No description, website, or topics provided.

Resources

Security policy

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages