Skip to content

Commit f5dd057

Browse files
docs(service-messaging): name the sys_webhook edit check behind the redeliver door (#27776)
<!-- claude-projects-attribution: {"github_login":"os-elon-musk"} --> _Requested by **Elon** · [project thread](https://claude.ai/code/project/chan_01WedDzV26nniwxv7jC88B9D?thread=cmsg_01WedDzV26nniwxv7jC88B9D9b2XhMFsspWMmP1eQ3G4mk)_ domain:server#3 · os-elon-musk · session_016WV4cyh2cxBQ2LKn2VVfxq Fixes #27706 ## What changes Comments only, in `packages/services/service-messaging`: - `src/http-outbox.ts`, doc comment of `assertHttpRedeliverable` ("Why this is a security refusal and not a tidiness one"): the sentence "`POST /api/v1/webhooks/redeliver` is reachable by any authenticated user" and the "that user" clause after it now name the current check: edit (`update`) access to `sys_webhook`, as decided by `packages/plugins/plugin-webhooks/src/redeliver-entitlement.ts`. The refusal's own reason (a parked row carries no signature) is unchanged. - `src/http-outbox-parked-record.integration.test.ts`, header comment: the same clause ("which any authenticated user can reach") is corrected the same way. No code and no assertion changed. ## Why After #27474 the redeliver door admits only a caller with edit access to `sys_webhook`. A security doc comment that names the wrong check misleads the next person deciding what the door allows. ## Verification - `git diff origin/main`: 2 files, +7 / -3, all inside comment blocks. - All 53 gate families derived by `dispatch-gates --commands` plus `pnpm lint` were run. 46 exit 0, plus `pnpm lint`. - `check:dispatcher-error-vocabulary` and `check:query-options-erasure` went red on the first pass only because the gitignored, generated `packages/spec/src/migrations/registry.ts` did not yet exist in the fresh worktree. Re-run after it was generated: both exit 0. - Exit 3 (prerequisite not met, needs a whole-tree build), NOT MEASURED locally: `check:dts-closure`, `check:dual-build-cjs-loads`, `check:i18n`, `check:lean-entry-closure`, `check:sourcemap-no-sources-content`. A comment-only diff cannot move them; CI measures them. - `check:commit-card-trailers --range origin/main..HEAD`: pass. Out of scope, reported and not edited: `src/messaging-service.ts:389-391` (the `redeliver` doc comment, #10740 paragraph) still says the door "is open to any authenticated user". The package `CHANGELOG.md` has the same historical phrase, which is a release record and is not hand-edited. No changeset: comments only (`skip-changeset` requested from the seat). Clause-②: no Metadata-protocol: none ## Human Minimum - [x] 1. Schemas start as Zod; `packages/spec` holds no runtime logic. - [x] 2. Every name I added uses the casing for its kind. - [x] 3. No formatter ran; `pnpm lint` passes. - [x] 4. One issue, one branch off an up-to-date `main`, one pull request. - [x] 5. A change that publishes carries a changeset, and both declaration lines are filled in here and in the changeset. - [x] 6. `packages/spec` touched: its generated artifacts are regenerated and committed. - [x] 7. No hand edits to `content/docs/references/`, `packages/*/CHANGELOG.md` or `content/docs/releases/`. - [x] 8. Title, body and comments are in English. - [x] The *Before Submitting* list in CONTRIBUTING.md is done. ## 维护者速读 - 改了什么:webhook 重投递入口的两处代码注释,改为写明现行权限(对 sys_webhook 有编辑权)。 - 为什么改:#27474 后权限已收紧,注释还写着"任何登录用户可达",会误导后来判断安全面的人。 - 风险与回滚:只改注释,无行为变化;回滚即 revert。 - 先看:http-outbox.ts 中 assertHttpRedeliverable 的注释段。 - 两分钟验证:看 diff,只有注释行变动。 - 需要你做的:无。 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_016WV4cyh2cxBQ2LKn2VVfxq --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 194e66c commit f5dd057

3 files changed

Lines changed: 11 additions & 5 deletions

File tree

‎packages/services/service-messaging/src/http-outbox-parked-record.integration.test.ts‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@
1111
* nothing. The obvious fix (write the discarded event as a `dead` row) is
1212
* *actively unsafe on its own*: `redeliver()` reset ANY terminal row to
1313
* `pending` with no signature check, behind `POST /api/v1/webhooks/redeliver`
14-
* which any authenticated user can reach. A parked row has no signature —
14+
* (admitted to a caller with edit access to `sys_webhook`, as decided by
15+
* `packages/plugins/plugin-webhooks/src/redeliver-entitlement.ts`). A parked
16+
* row has no signature —
1517
* the signature is computed at enqueue from the very secret that could not be
1618
* resolved — so redelivering one would put the payload on the wire UNSIGNED,
1719
* reopening #7799 through a door nobody would think to audit.

‎packages/services/service-messaging/src/http-outbox.ts‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -487,8 +487,10 @@ export class HttpRedeliverError extends Error {
487487
* ## Why this is a security refusal and not a tidiness one
488488
* A parked row has no {@link HttpDelivery.signature}, because the signature is
489489
* computed at enqueue from the very secret that could not be resolved (#7722,
490-
* #7799). `POST /api/v1/webhooks/redeliver` is reachable by any authenticated
491-
* user. Without this refusal, making the drop durable would hand that user a
490+
* #7799). `POST /api/v1/webhooks/redeliver` admits a caller with edit
491+
* (`update`) access to `sys_webhook`, as decided by
492+
* `packages/plugins/plugin-webhooks/src/redeliver-entitlement.ts`. Without this
493+
* refusal, making the drop durable would hand any such webhook administrator a
492494
* button that delivers the webhook UNSIGNED — reopening #7799 through a door
493495
* nobody would think to audit. **An unsigned redelivery is strictly worse than
494496
* an unrecorded drop**, which is why this guard lands with — and logically

‎packages/services/service-messaging/src/messaging-service.ts‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -387,8 +387,10 @@ export class MessagingService {
387387
*
388388
* [#10740] `options.tenantId` is the REQUESTING caller's organization, and
389389
* it is the whole reason this method takes a second argument: the door in
390-
* front of it (`POST /api/v1/webhooks/redeliver`) is open to any
391-
* authenticated user, and `sys_http_delivery` is tenant-scoped. The
390+
* front of it (`POST /api/v1/webhooks/redeliver`) admits any caller with
391+
* edit (`update`) access to `sys_webhook`, as decided by
392+
* `packages/plugins/plugin-webhooks/src/redeliver-entitlement.ts` — a caller
393+
* in any organization — and `sys_http_delivery` is tenant-scoped. The
392394
* outbox applies it to the rows it reads and the row it writes, so a
393395
* caller can only replay deliveries in its own organization; a row
394396
* elsewhere is `RESOURCE_NOT_FOUND`. ⛔ There is no tenant-audit bypass

0 commit comments

Comments
 (0)