You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
content/docs/automation/webhooks.mdx still documents custom headers as living in sys_webhook.definition_json, and omits headers_secret entirely — the doc points authors at the cleartext column #7986 moved them out of #9928
⛔ Unassigned; for triage to grade. Found while working #9756 (the enable block census) — out of scope there, and not touched by PR #9927, whose file surface is plugin-webhooks only.
Measured on origin/main @ b0300556d
#7986 moved sys_webhook's custom HTTP headers out of the definition_json blob and into headers_secret — a Field.secret() column the engine encrypts at rest into sys_secret, whose reads return a mask. The webhooks guide was not updated with it, and still describes the pre-#7986 world in three places:
line 87 — "The transport configuration (headers, timeout, method) is carried in ..." (definition_json)
line 104, the sys_webhook field table:
definition_json | textarea | Serialised Webhook JSON ... — carries the transport config: custom headers and timeoutMs. Not the signing secret.
line 110 — "the headers and per-attempt timeout are parsed out of definition_json when an event is enqueued"
⇒ and the field table has no headers_secret row at all, though the column ships and is admin-authorable. The table documents its sibling signing_secret correctly, so the omission reads as "this field does not exist" rather than as an obvious gap.
Why this is worth a card rather than a typo fix
The doc does not merely lag — it points an author at the wrong column, in the direction that reintroduces the defect. An author (or an AI author) following this table writes an Authorization: Bearer … into definition_json, which is an ordinary textarea returned in full by GET /api/v1/data/sys_webhook. The runtime still accepts that: readLegacyHeaders (packages/plugins/plugin-webhooks/src/auto-enqueuer.ts:579) reads such a map, delivers from it, and logs a warn naming it cleartext — so following the doc produces working deliveries and a warning nobody is looking for, not an error.
The same page already carries the pattern this needs, one section down: sys_http_delivery's table documents headers_json as internal with the read-path rule spelled out (line 159), and there is a Callout explaining the #7799 signing-secret move (line ~117) with no counterpart for the headers move.
Suggested shape (not a ruling — triage's call)
add a headers_secret row to the sys_webhook field table, mirroring the signing_secret row's wording (encrypted into sys_secret, reads return a mask, leave the mask untouched to keep the current value);
correct lines 87 / 104 / 110 so definition_json is described as carrying timeoutMs and the rest of the envelope, with the headers named as legacy-only — still read for un-migrated rows, migrated by the boot sweep;
⛔ No runtime defect is asserted. headers_secret and the legacy-read path both behave as their own cards specify; this is a documentation-vs-implementation drift only.
I did not audit the rest of the page; the three lines above are the whole of what I measured.
Refs: #7986 (moved the headers to headers_secret) · #7799 (the signing-secret sibling, whose callout this page does carry) · #8566 (the headers_secret plaintext shape gate) · #9756 / PR #9927 (where this was noticed)
⛔ Unassigned; for triage to grade. Found while working #9756 (the
enableblock census) — out of scope there, and not touched by PR #9927, whose file surface isplugin-webhooksonly.Measured on
origin/main@b0300556d#7986movedsys_webhook's custom HTTP headers out of thedefinition_jsonblob and intoheaders_secret— aField.secret()column the engine encrypts at rest intosys_secret, whose reads return a mask. The webhooks guide was not updated with it, and still describes the pre-#7986 world in three places:definition_json)sys_webhookfield table:definition_jsonwhen an event is enqueued"⇒ and the field table has no
headers_secretrow at all, though the column ships and is admin-authorable. The table documents its siblingsigning_secretcorrectly, so the omission reads as "this field does not exist" rather than as an obvious gap.Why this is worth a card rather than a typo fix
The doc does not merely lag — it points an author at the wrong column, in the direction that reintroduces the defect. An author (or an AI author) following this table writes an
Authorization: Bearer …intodefinition_json, which is an ordinarytextareareturned in full byGET /api/v1/data/sys_webhook. The runtime still accepts that:readLegacyHeaders(packages/plugins/plugin-webhooks/src/auto-enqueuer.ts:579) reads such a map, delivers from it, and logs awarnnaming it cleartext — so following the doc produces working deliveries and a warning nobody is looking for, not an error.The same page already carries the pattern this needs, one section down:
sys_http_delivery's table documentsheaders_jsonasinternalwith the read-path rule spelled out (line 159), and there is aCalloutexplaining the #7799 signing-secret move (line ~117) with no counterpart for the headers move.Suggested shape (not a ruling — triage's call)
headers_secretrow to thesys_webhookfield table, mirroring thesigning_secretrow's wording (encrypted intosys_secret, reads return a mask, leave the mask untouched to keep the current value);definition_jsonis described as carryingtimeoutMsand the rest of the envelope, with the headers named as legacy-only — still read for un-migrated rows, migrated by the boot sweep;sys_webhook.definition_json#7799 callout to cover the headers move, since the two landed as siblings.Not claimed
headers_secretand the legacy-read path both behave as their own cards specify; this is a documentation-vs-implementation drift only.headersare still cleartext in two JSON blobs — the sibling of #7799 that PR #7901 did not close #7986 or its PR — that card was about the storage move and did what its title said. This is the docs surface that was not in its scope.Refs: #7986 (moved the headers to
headers_secret) · #7799 (the signing-secret sibling, whose callout this page does carry) · #8566 (theheaders_secretplaintext shape gate) · #9756 / PR #9927 (where this was noticed)Generated by Claude Code