feat: per-group webhook ingress, custom webhooks, GitHub App tenant isolation

Add POST /webhook/{groupId} with per-group secrets (KV tenant:{groupId}), a custom provider (X-WebHooker-Signature HMAC, arbitrary JSON -> custom events through the route pipeline), and GitHub App installation isolation (Group.installationId) with automatic provisioning on installation.created (inst-{id} groups or binding matching owners groups). Includes WebhookPanel admin UI, custom route template, docs and 157 passing tests.
This commit is contained in:
RhenCloud 2026-08-13 09:24:50 +08:00
parent 0b078d938b
commit b600f02027
No known key found for this signature in database
GPG key ID: A574A617378C4E0B
34 changed files with 1711 additions and 183 deletions

View file

@ -1,6 +1,7 @@
import type { Provider } from "./types";
import { githubProvider } from "./github";
import { giteaProvider } from "./gitea";
import { customProvider } from "./custom";
export type { Provider } from "./types";
export { verifySignature } from "./github/verify";
@ -9,9 +10,10 @@ export { verifySignature } from "./github/verify";
* Detection order matters: Gitea webhooks also send GitHub-compatible headers
* (`X-GitHub-Event`, `X-Hub-Signature-256`, ...), so a Gitea request would
* match the GitHub provider too. Check Gitea first real GitHub requests
* never send `X-Gitea-Event`.
* never send `X-Gitea-Event`. Custom requests carry none of the forge headers,
* only `X-WebHooker-Signature`, so they are checked last.
*/
const providers: Provider[] = [giteaProvider, githubProvider];
const providers: Provider[] = [giteaProvider, githubProvider, customProvider];
/**
* Pick the webhook provider for a request based on its headers (e.g.