Skip to content

fix(approvals): guard self-service OOO delegation writes + i18n (#1322)#3255

Merged
os-zhuang merged 1 commit into
mainfrom
claude/enterprise-delegation-ooo-proxy-1v3m8l
Jul 19, 2026
Merged

fix(approvals): guard self-service OOO delegation writes + i18n (#1322)#3255
os-zhuang merged 1 commit into
mainfrom
claude/enterprise-delegation-ooo-proxy-1v3m8l

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Follow-up hardening on the merged OOO delegation feature (#1322 / #3235).

Security — delegator forge guard

sys_approval_delegation is apiEnabled CRUD so users can self-declare their out-of-office delegation. But it's a system object: it gets no owner_id anchor and (with no sharingModel) defaults to a public sharing model. Un-guarded, a member could create a delegation naming someone else as delegator_id and reroute that victim's individually-routed approvals to themselves.

bindDelegationWriteGuard (plugin-approvals beforeInsert/beforeUpdate, mirroring the ADR-0092 identity write-guard) forces a normal user's writes to name themselves as delegator:

  • system context (service / seed / import) → bypass;
  • admin (roles includes 'admin') → may set any delegator_id;
  • otherwise → stamped-to-self on insert, rejected on a foreign delegator_id (insert or update).

Row ownership on update/delete (you can only touch a delegation you created) is already enforced by member_default's wildcard created_by == current_user.id RLS — this guard adds the delegator-identity check RLS alone can't express. Reads stay public, consistent with the sibling sys_approval_request (a my_delegations list-view / read-scoping is a possible follow-up, matching platform convention for these optional-plugin system tables).

i18n

Registered sys_approval_delegation in the plugin's i18n extract config and added its object/field/view translations. zh-CN fully translated; en/ja-JP/es-ES carry the English baseline pending translation. Blocks were hand-added rather than via a full re-extract, because re-running extract here drifts and drops existing enum/view keys (recalled, escalate, My Pending, …) — the diff is pure additions, 0 deletions.

Tests

9 new guard cases: self-create allowed; forge rejected on insert and update; stamp-on-omit; unauthenticated non-system rejected; system + admin bypass; batch insert with one foreign row rejected. plugin-approvals 123 passed; package build + eslint clean.

Context

Community-core OOO delegation shipped in #3235 (#1322). Enterprise governance (act-as inbox, SoD, admin-over-others, compliance reporting) remains tracked in objectstack-ai/cloud#855.

🤖 Generated with Claude Code


Generated by Claude Code

Follow-up hardening on the merged OOO delegation feature (#3235).

Security — delegator forge guard:
sys_approval_delegation is apiEnabled CRUD, but as a system object it gets no
owner_id anchor and defaults to a `public` sharing model, so an unguarded
member could create a delegation naming SOMEONE ELSE as delegator and reroute
that victim's individually-routed approvals to themselves. bindDelegationWrite-
Guard (plugin-approvals beforeInsert/beforeUpdate, mirroring the ADR-0092
identity write-guard) forces a normal user's writes to name themselves as
delegator: system context bypasses, admins (roles include 'admin') may set any
delegator, everyone else is stamped-to-self on insert and rejected on a foreign
delegator. Row ownership on update/delete is already covered by member_default's
wildcard `created_by == current_user.id` RLS.

i18n:
Register sys_approval_delegation in the plugin's i18n extract config and add
its object/field/view translations. zh-CN fully translated; en/ja-JP/es-ES
carry the English baseline pending translation. (Blocks hand-added to avoid a
full re-extract dropping existing enum/view keys.)

Tests: 9 new guard cases (self-create, forge reject on insert/update, stamp on
omit, unauthenticated reject, system + admin bypass, batch). plugin-approvals
123 passed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016ypkQikZ55oWUHUnMebwXA
@vercel

vercel Bot commented Jul 19, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
spec Ready Ready Preview, Comment Jul 19, 2026 6:32am

Request Review

@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/plugin-approvals.

4 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/automation/approvals.mdx (via @objectstack/plugin-approvals)
  • content/docs/plugins/packages.mdx (via @objectstack/plugin-approvals)
  • content/docs/releases/implementation-status.mdx (via @objectstack/plugin-approvals)
  • content/docs/releases/v9.mdx (via @objectstack/plugin-approvals)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

@os-zhuang
os-zhuang marked this pull request as ready for review July 19, 2026 06:39
@os-zhuang
os-zhuang merged commit 611402f into main Jul 19, 2026
16 checks passed
@os-zhuang
os-zhuang deleted the claude/enterprise-delegation-ooo-proxy-1v3m8l branch July 19, 2026 06:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants