Skip to content

[17.0-rc][疑似平台] script action 的 body 写库被 FORBIDDEN(admin 用户) #521

Description

@yinlianghui

现象

17.0.0-rc.0 下,对象级 script action(如工单的 close_case):确认框、参数弹窗均正常,执行时报
FORBIDDEN: insufficient privileges to update crm_case <id> —— 使用的是内置 admin 账号。

复现

  1. 工单详情 → 关闭工单 → 填写解决方案 → 确认
  2. UI 弹红色错误;服务端日志:
    • 审计行声称 body executes TRUSTED (context-less engine, RLS/FLS-bypassing)
    • 紧接着 [BodyRunner] sandboxed action threw ... FORBIDDEN: insufficient privileges

审计声明(TRUSTED、免 RLS/FLS)与实际行为(权限层全拒)自相矛盾,疑似 context-less 引擎没有用户身份导致权限检查一律拒绝。16.1 已有类似「sandbox 写库被 sharing 拦截」的怪癖,RC 未修复。

影响

所有带写库 body 的对象级 action(close_case / escalate_case / send_email / mass_update_stage / create_campaign 等)。升级阻断。

详见分支 upgrade/objectstack-17 的 docs/upgrade-17/test-report.md §3 P2。

Activity

  1. yinlianghui commented on Jul 29, 2026

    @yinlianghui
    CollaboratorAuthor

    源码确认:CONFIRMED,平台 bug。action body 的 ctx.api 回退到无 ExecutionContext/无 isSystem 的 facade(body-runner.ts:161-184),plugin-sharing 的 canEdit 在 !context.userId 直接拒(sharing-service.ts:255);hook body 却有 isSystem:true 兜底(engine.ts:978-981)。审计行描述的是 ctx.engine 不是 ctx.api。注意:public sharing / 无 owner 字段的对象会碰巧放行,掩盖问题。已上报平台:objectstack-ai/objectstack#3914

  2. yinlianghui commented on Jul 29, 2026

    @yinlianghui
    CollaboratorAuthor

    📎 分支 upgrade/objectstack-17 已推送至上游(仅分支,无 PR,勿合并——阻塞于 17.0 正式版与 objectstack#3912/#3913/#3914)。正文引用的文档现在可直接访问:测试报告 | 测试计划

  3. yinlianghui commented on Aug 5, 2026

    @yinlianghui
    CollaboratorAuthor

    rc.2 retest: 已解除 — script-body writes persist; zero FORBIDDEN across the whole run

    Retested on @objectstack/* 17.0.0-rc.2 (current main, commit 5a78f88), during the acceptance run's full action sweep (all 26 actions + flow executions).

    Evidence:

    • grep -c FORBIDDEN over the dev-server log for the entire run window: 0 occurrences of the caller-identity FORBIDDEN this issue tracked.
    • Direct write-persistence proof, three distinct shapes:
      • mark_primary script body UPDATE on crm_contact → {ok:true,is_primary:true} and the value persists on re-GET.
      • Activity-action body UPDATE on sharing-governed crm_case — first_response_date stamped by the first log_call and correctly not re-stamped by later ones. This is exactly the object class the rc.0 audit line warned about.
      • send_email body writes: sys_email row (status sent), sys_activity timeline row, plus recency bumps (contact.last_contacted_date, account.last_activity_date) — all persisted.
    • The canonical close_case from this issue's repro is now flow-typed (CRM-side change, runAs system) and closes a case end-to-end through the UI (resolution stored, closed_date + resolution_time_hours computed).

    Upstream objectstack#3914's fix is confirmed present in rc.2.

    One boundary worth stating so nobody reopens this on the wrong evidence: a different FORBIDDEN still exists — DELETE/UPDATE on rows whose owner_id is NULL (action-created crm_event rows) fails 403 even for admin. That is row-state-based, not caller-identity-based, and belongs to #548 (evidence posted there), not here.

    Recommend closing after owner confirmation (test-don't-fix mandate — reporting, not closing).


    Generated by Claude Code

  4. yinlianghui commented on Aug 5, 2026

    @yinlianghui
    CollaboratorAuthor

    [17.0-rc2验收复核] 结论:已不复现(独立环境复核,与今晨复测结论一致)

    证据:独立 dev server(端口 4091,全新种子库,admin token):

    # script action body UPDATE(sharing 治理下的 crm_contact)
    POST /api/v1/actions/crm_contact/mark_primary {"recordId":"-NdOYw…","params":{}}
    → 200 {"ok":true,"id":"-NdOYw…","is_primary":true};re-GET 确认 updated_at 变更持久
    
    # 活动 action body 三类写(crm_event INSERT + sys_activity INSERT + attendee ×2)
    POST /api/v1/actions/crm_contact/log_call → 200,三类行逐一 GET 核验落库
    
    # 整个测试会话的服务端日志
    grep -c FORBIDDEN server.log → 0
    

    审计行现为 [action-audit] REST action 'crm_contact/mark_primary' — body executes TRUSTED (system-elevated context, RLS/FLS-bypassing) for user '<admin id>' —— 与实际行为一致,rc.0 那种「审计声称 TRUSTED、执行被 FORBIDDEN」的自相矛盾已消失。原始复现用的 close_case 在当前 main 已是 flow 型(runAs system),走另一路径,同样端到端可用。上游 objectstack#3914 的修复在 rc.2 确认存在。

    环境:hotcrm@0899b4f + @objectstack 17.0.0-rc.2

    建议:前提已过时建议关闭。(边界提醒同今晨复测:owner_id 为 NULL 行的 403 是另一件事,归 #548 谱系,勿以其证据重开本单。)


    Generated by Claude Code

  5. hotlong commented on Aug 14, 2026

    @hotlong
    Contributor

    Closed on maintainer ruling (2026-08-14, verbatim: 「同意」, item 6 of the six-item list: 「#525 #524 #521 直接关闭」). Basis already on this card: two independent rc.2 retests (2026-08-05) — zero FORBIDDEN across the full action sweep, writes persist, audit line consistent with behavior; upstream mirror objectstack#3914 addressed; close was recommended on-card but never executed. The unrelated FORBIDDEN on owner_id-NULL rows was already routed to #548. Bookkeeping continues in #1150.


    Generated by Claude Code

  6. added
    priority:p0Critical: blocker, must ship before MVP
    and removed on Sep 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingpriority:p0Critical: blocker, must ship before MVPupstream:objectstackBlocked on / caused by the ObjectStack platform — tracked upstream

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions