| 1 | { |
| 2 | "description": "Incoming-webhook events (issue #610, docs/webhooks.md): the shape the hooks sidecar emits, and the platform contract that UNCLAIMED typed events are silently ignored on every client.", |
| 3 | "app": "webhooks", |
| 4 | "source": "internal/hooks/hooks.go buildEvent (emitter); web/static/apps.js foldEvent/isAppType (web ignore gate); ios MessagePayload.isRenderableChat (native ignore gate)", |
| 5 | "state_shape": "none — the webhooks management app deliberately claims NO wire types; webhooks.<ns> events belong to future CONSUMER apps (e.g. a CI dashboard claiming webhooks.github)", |
| 6 | "notes": [ |
| 7 | "The sidecar posts one event per inbound HTTP request, encrypted to the target thread's key: { type: 'webhooks.<ns>', name, uid, ts, hook: {id, ns}, req: {method, path, query, headers, body[, body_b64]} }.", |
| 8 | "name/uid are the webhook's roster identity — the same attribution fields as chat messages, so mute-by-person and roster labels apply.", |
| 9 | "req.headers carries only the sidecar's allowlisted subset (Content-Type, User-Agent, provider event/signature headers); Authorization and other sender credentials never enter the log.", |
| 10 | "req.body is the raw body string; body_b64: true marks a non-UTF-8 body carried base64url-encoded. req.path is the sub-path AFTER the secret segment — the secret itself never rides inside an event.", |
| 11 | "CONTRACT — unclaimed types are ignored: until some app registers the exact type string in its events map, web's foldEvent returns null / isAppType is false (the message renders nothing, notifies nothing), and native's MessagePayload.isRenderableChat is false (no bubble, no notification). Old clients degrade to exactly this behaviour.", |
| 12 | "Space-thread deliveries additionally never push (push.go skips kind='space' entirely)." |
| 13 | ], |
| 14 | "vectors": [ |
| 15 | { |
| 16 | "name": "github-workflow-run", |
| 17 | "description": "A GitHub Actions delivery: the full event shape as the sidecar builds it. Unclaimed by any shipped app — web fold must return null, native must treat it as non-renderable.", |
| 18 | "event": { |
| 19 | "type": "webhooks.github", |
| 20 | "name": "CI runs", |
| 21 | "uid": "hookuser123", |
| 22 | "ts": 1752710400000, |
| 23 | "hook": { "id": "wh-abc123", "ns": "github" }, |
| 24 | "req": { |
| 25 | "method": "POST", |
| 26 | "path": "/", |
| 27 | "query": {}, |
| 28 | "headers": { |
| 29 | "Content-Type": "application/json", |
| 30 | "X-Github-Event": "workflow_run", |
| 31 | "X-Github-Delivery": "72d3162e-cc78-11e3-81ab-4c9367dc0958" |
| 32 | }, |
| 33 | "body": "{\"action\":\"completed\",\"workflow_run\":{\"status\":\"completed\",\"conclusion\":\"success\"}}" |
| 34 | } |
| 35 | }, |
| 36 | "expected": "ignored" |
| 37 | }, |
| 38 | { |
| 39 | "name": "binary-body-custom-namespace", |
| 40 | "description": "A non-UTF-8 delivery under a member-chosen namespace: body rides base64url with body_b64 set. Same ignore contract.", |
| 41 | "event": { |
| 42 | "type": "webhooks.sensor-net", |
| 43 | "name": "Greenhouse", |
| 44 | "uid": "hookuser456", |
| 45 | "ts": 1752710500000, |
| 46 | "hook": { "id": "wh-def456", "ns": "sensor-net" }, |
| 47 | "req": { |
| 48 | "method": "PUT", |
| 49 | "path": "/readings", |
| 50 | "query": { "site": ["7"] }, |
| 51 | "headers": { "Content-Type": "application/octet-stream" }, |
| 52 | "body": "AAECAwQF", |
| 53 | "body_b64": true |
| 54 | } |
| 55 | }, |
| 56 | "expected": "ignored" |
| 57 | } |
| 58 | ] |
| 59 | } |
| 60 | |