F5 — Watch / unwatch + automatic webhook lifecycle #486

Closed
opened 2026-04-27 21:43:28 +00:00 by claude-desktop · 0 comments
Collaborator

As an operator, I want clicking "Watch" on a repo in the picker to create the webhook on the active forge automatically.

Acceptance criteria

  • POST /watched-repos body { owner, name } (forge_type resolved server-side as the active forge). Generates a 32-byte random webhook_secret, writes the row with enabled=1, then calls ForgePort.createWebhook({ owner, name, url: '<public_base_url>/webhooks/<forge>', secret }). Stores the returned webhook_id.
  • DELETE /watched-repos/{owner}/{name}: calls ForgePort.deleteWebhook against the row's forge_type (operator can unwatch rows from any forge they have an OAuth row for, not only the active one — useful for cleanup after switching). Then deletes the row. 404 from the forge → still delete the row.
  • PATCH /watched-repos/{owner}/{name} body { enabled: bool }: toggles dispatch without deleting the webhook.
  • ForgePort extended with createWebhook / deleteWebhook / editWebhook / listWebhooks; each adapter (forgejo, github, gitlab) implements via its forge API.
  • Webhook events the server subscribes to are the same set per forge as documented in docs/multi-forge.md §"Subscribe to individual events".
  • public_base_url config key required; startup fails if missing AND any OAuth client is configured.
  • Endpoints rejected with 412 if no active forge.
  • Tests: create + delete + toggle round-trip per forge adapter.

Out of scope

  • Secret rotation (F5-rotate).
  • Repo picker UI (F6).

References

  • Spec: docs/specs/forge-auth-repo-selection.md §F5
  • docs/multi-forge.md

Dependencies

  • Blocked by F3 (Forgejo OAuth provider — first lit-up forge)
  • Blocked by F4 (watched_repos table)
As an operator, I want clicking "Watch" on a repo in the picker to create the webhook on the active forge automatically. ## Acceptance criteria - [ ] `POST /watched-repos` body `{ owner, name }` (forge_type resolved server-side as the active forge). Generates a 32-byte random `webhook_secret`, writes the row with `enabled=1`, then calls `ForgePort.createWebhook({ owner, name, url: '<public_base_url>/webhooks/<forge>', secret })`. Stores the returned `webhook_id`. - [ ] `DELETE /watched-repos/{owner}/{name}`: calls `ForgePort.deleteWebhook` against the row's `forge_type` (operator can unwatch rows from any forge they have an OAuth row for, not only the active one — useful for cleanup after switching). Then deletes the row. 404 from the forge → still delete the row. - [ ] `PATCH /watched-repos/{owner}/{name}` body `{ enabled: bool }`: toggles dispatch without deleting the webhook. - [ ] `ForgePort` extended with `createWebhook` / `deleteWebhook` / `editWebhook` / `listWebhooks`; each adapter (forgejo, github, gitlab) implements via its forge API. - [ ] Webhook events the server subscribes to are the same set per forge as documented in `docs/multi-forge.md` §"Subscribe to individual events". - [ ] `public_base_url` config key required; startup fails if missing AND any OAuth client is configured. - [ ] Endpoints rejected with 412 if no active forge. - [ ] Tests: create + delete + toggle round-trip per forge adapter. ## Out of scope - Secret rotation (F5-rotate). - Repo picker UI (F6). ## References - Spec: `docs/specs/forge-auth-repo-selection.md` §F5 - `docs/multi-forge.md` ## Dependencies - Blocked by F3 (Forgejo OAuth provider — first lit-up forge) - Blocked by F4 (watched_repos table)
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
charles/claude-hooks#486
No description provided.