mirror of
https://github.com/ReCloudStudio/WebHooker.git
synced 2026-09-22 16:11:29 +00:00
docs: document admin groups, OAuth redirect, and API renames
This commit is contained in:
parent
8c8cfbf211
commit
8c9720b1b3
10 changed files with 324 additions and 142 deletions
|
|
@ -35,13 +35,19 @@ WebHooker ships with a built-in config console at `/admin` for managing routes i
|
|||
|
||||
### Endpoints
|
||||
|
||||
| Endpoint | Description |
|
||||
| ----------------------- | --------------------------- |
|
||||
| `GET /admin` | Config console UI |
|
||||
| `GET /admin/login` | Start GitHub OAuth sign-in |
|
||||
| `GET /admin/logout` | Destroy session |
|
||||
| `GET /admin/api/routes` | List routes (admin only) |
|
||||
| `PUT /admin/api/routes` | Replace routes (admin only) |
|
||||
| Endpoint | Description |
|
||||
| ---------------------------------- | --------------------------------------- |
|
||||
| `GET /admin` | Config console UI |
|
||||
| `GET /admin/login` | Start GitHub OAuth sign-in |
|
||||
| `GET /admin/logout` | Destroy session |
|
||||
| `GET /admin/api/me` | Current session, scope, and groups |
|
||||
| `GET /admin/api/routes` | List routes (admin only) |
|
||||
| `PUT /admin/api/routes` | Replace routes (admin only) |
|
||||
| `GET /admin/api/groups` | List groups (scoped to access) |
|
||||
| `PUT /admin/api/groups` | Replace groups (super admin only) |
|
||||
| `GET /admin/api/groups/:id/routes` | List a group's routes |
|
||||
| `PUT /admin/api/groups/:id/routes` | Replace a group's routes |
|
||||
| `GET /admin/api/logs` | Send logs (scoped to accessible routes) |
|
||||
|
||||
The console lets you add, edit, delete, and toggle routes. Saved routes are written to KV `config:routes` immediately and the config cache is invalidated so the webhook pipeline picks them up on the next run.
|
||||
|
||||
|
|
@ -58,6 +64,8 @@ There are **no default routes** — each route must define its own target. If no
|
|||
"id": "unique-route-id",
|
||||
"name": "Human-readable name",
|
||||
"enabled": true,
|
||||
"groupId": "my-group",
|
||||
"fallback": false,
|
||||
"filters": [
|
||||
{ "type": "event", "match": "push" },
|
||||
{ "type": "repo", "match": "org/repo", "exclude": false }
|
||||
|
|
@ -71,6 +79,14 @@ There are **no default routes** — each route must define its own target. If no
|
|||
|
||||
`target.channelId` is required and used as-is; there is no fallback to a default channel.
|
||||
|
||||
Other route fields:
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
| ---------- | ------- | -------- | ----------------------------------------------------------------------------------------------- |
|
||||
| `groupId` | string | Yes | Id of the [group](#groups) this route belongs to |
|
||||
| `fallback` | boolean | No | When `true`, fires only if no non-fallback route matched the event; its own filters are ignored |
|
||||
| `lang` | string | No | Message language override for this route (e.g. `en`, `zh`); defaults to the global setting |
|
||||
|
||||
### Custom Route Example
|
||||
|
||||
```json
|
||||
|
|
@ -79,6 +95,7 @@ There are **no default routes** — each route must define its own target. If no
|
|||
"id": "backend-prs",
|
||||
"name": "Backend PRs",
|
||||
"enabled": true,
|
||||
"groupId": "backend-team",
|
||||
"filters": [
|
||||
{ "type": "repo", "match": "myorg/backend" },
|
||||
{ "type": "event", "match": "pull_request" },
|
||||
|
|
@ -92,6 +109,35 @@ There are **no default routes** — each route must define its own target. If no
|
|||
]
|
||||
```
|
||||
|
||||
## Groups
|
||||
|
||||
Routes belong to groups. Groups scope admin access and can restrict which events flow into them. They are stored in Cloudflare KV under the key `config:groups` as a JSON array.
|
||||
|
||||
### Group Schema
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "backend-team",
|
||||
"name": "Backend Team",
|
||||
"adminIds": ["rhencloud"],
|
||||
"owners": ["myorg"]
|
||||
}
|
||||
```
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
| ---------- | -------- | -------- | ---------------------------------------------------------------------- |
|
||||
| `id` | string | Yes | Lowercase id (`a-z0-9`, `-`); referenced by each route's `groupId` |
|
||||
| `name` | string | Yes | Human-readable group name |
|
||||
| `adminIds` | string[] | Yes | GitHub user IDs or logins who may manage this group's routes |
|
||||
| `owners` | string[] | No | Org/user logins whose events are accepted into this group; empty = all |
|
||||
|
||||
### Access Model
|
||||
|
||||
- **Super admins** (`ADMIN_USER_IDS`) see and edit every group and all routes.
|
||||
- **Group admins** (`adminIds`) only see and edit the groups they manage; submitting a route outside their groups returns `403`.
|
||||
- Group admin endpoints operate on a single group at a time via `/admin/api/groups/:id/routes`; `groupId` is forced from the path parameter.
|
||||
- The `owners` list restricts which event actors (sender logins) the group's routes will dispatch at all.
|
||||
|
||||
## Filter Types
|
||||
|
||||
| Type | Matches | Example |
|
||||
|
|
@ -108,7 +154,7 @@ There are **no default routes** — each route must define its own target. If no
|
|||
- All filters in a route must match for the route to trigger (AND logic)
|
||||
- Set `"exclude": true` on any filter to invert it (NOT logic)
|
||||
- `keyword` filter supports regex patterns — falls back to substring match if regex is invalid
|
||||
- `branch` filter works for push, pull_request, create/delete, workflow_run, and code_scanning_alert events
|
||||
- `branch` filter works for push, pull_request, pull_request_review, pull_request_review_comment, create/delete, workflow_run, and code_scanning_alert events
|
||||
|
||||
### Match Values
|
||||
|
||||
|
|
@ -121,9 +167,14 @@ Filters accept either a single string or an array of strings:
|
|||
|
||||
## KV Storage Layout
|
||||
|
||||
| Key Pattern | Value | TTL |
|
||||
| ---------------- | --------------------------------- | ------------ |
|
||||
| `config:routes` | JSON array of routes | Permanent |
|
||||
| `session:{id}` | Admin session `{ userId, login }` | 7 days |
|
||||
| `token:{userId}` | `{ accessToken, expiresAt }` | Until expiry |
|
||||
| `state:{hex}` | `{ userId, createdAt }` | 600 seconds |
|
||||
| Key Pattern | Value | TTL |
|
||||
| ------------------------ | --------------------------------------------------- | ------------------ |
|
||||
| `config:routes` | JSON array of routes | Permanent |
|
||||
| `config:groups` | JSON array of groups | Permanent |
|
||||
| `session:{id}` | Admin session `{ userId, login }` | 7 days |
|
||||
| `token:{userId}` | `{ userId, accessToken, expiresAt, refreshToken? }` | 0.9 × token expiry |
|
||||
| `token-reverse:{sha256}` | User id for reverse lookup by token | 0.9 × token expiry |
|
||||
| `discord-link:{userId}` | GitHub user id linked to a Discord user | Permanent |
|
||||
| `state:{hex}` | `{ redirectTo, expiresAt, discordUserId? }` | 600 seconds |
|
||||
| `delivery:{id}` | Webhook delivery id (dedup marker) | 300 seconds |
|
||||
| `logs:send:{ts}-{hex}` | Send record | 1 hour |
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue