Skip to content

Let every Duly set read business units, so a unit shows its name - #183

Merged
os-warren merged 1 commit into
mainfrom
claude/project-thread-y42kg9
Nov 2, 2026
Merged

os-warren merged 1 commit into
mainfrom
claude/project-thread-y42kg9

Conversation

@os-warren

Copy link
Copy Markdown
Collaborator

Requested by Warren · project thread

Fixes #180

What was wrong (measured on main 358c2ca, 18.2.0, live pnpm demo)

  • duly_member, duly_manager and duly_admin all got 403 on sys_business_unit. ?expand=business_unit silently returned the raw id. A member's own task and duty pages showed BUSINESS UNIT ⓘ Pda7prUARyl9pj4e.
  • A duly_admin who is not a platform admin imported samples/duties.csv with 0/19 rows: Business unit: no record matches "Northgate Quality". The Import resolves the unit by name under the importer's own read.

The change

  • src/security/permission-sets.ts: sys_business_unit: { allowRead: true } in MEMBER_OBJECTS. Manager and admin inherit it through the existing spread. There is no write bit, no scope key and no fields map. The note says what the read discloses: every unit, every column, external_ref included, read only. It also says why there is no name-only mask (fix(plugin-security): an app permission set's readable:false on a sys_* field also masks platform admins who hold that set objectstack#29106): FLS readable:false also binds every admin who holds a Duly set. Measured: Setup → Business Units lost Kind, Head and Active, and the org chart went flat.
  • test/security.test.ts: the "five duly objects" and "nothing outside the duly namespace" invariants each get one named exception, PLATFORM_READS. The grant is pinned exactly as parsed: read only, every other bit false.
  • test/business-unit-read.test.ts (new) runs with real holders (buildContextForUser + SecurityPlugin + SharingServicePlugin): a member, a member + manager, and a member + duly_admin. For each it checks:
    • they list every unit and read their own unit by id;
    • they resolve a unit by name under their own read (the Import's lookup);
    • an expanded lookup on their own hand-made duty returns the unit's name;
    • create, edit and delete on a unit are refused;
    • no Duly set declares a field permission on sys_business_unit.
      Negative control: with the grant reverted, 13/26 fail (every read). The refusals still pass.
  • docs/deployment/security.md: one row in the model table.

Step 0 report with the prototype measurements: project file duly-180-unit-name/step0.md.

Gates

pnpm validate ✓ · pnpm typecheck ✓ · pnpm test 46 files / 1316 tests ✓ · pnpm build ✓

Browser pass in en-US and zh-CN will follow in a comment.


Generated by Claude Code

Members, managers and Duly admins got 403 on sys_business_unit, so the
unit lookup on a task or duty rendered as a raw id, and a duly_admin who
is not a platform admin could not Import samples/duties.csv (units
resolve by name under the importer's read: 0/19).

Grant read only, in MEMBER_OBJECTS, inherited by manager and admin. No
write bit, no scope key and no field map: a name-only FLS mask also binds
every admin who co-holds a Duly set and blanks Setup > Business Units
(objectstack#29106). The note names what the read discloses, external_ref
included.

security.test.ts names the one platform read as the exception to the
duly-namespace invariants; business-unit-read.test.ts drives it as real
member, manager and admin holders (list, by id, by name, expanded lookup,
writes refused, no fields entry on the object).

Fixes #180

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JQwxba8DtH3fgAAexeLs8H
@os-warren os-warren self-assigned this Nov 2, 2026

Copy link
Copy Markdown
Collaborator Author

Browser pass on head e6c77d7: fresh pnpm demo (en-US) and pnpm demo:zh (zh-CN), each on its own database. CI verify is green.

check en-US zh-CN
member list / get units 200, 6 / 200 200, 6 / 200
member create / edit / delete unit 403 / 403 / 403 403 / 403 / 403
manager list / get / create / edit / delete 200 / 200 / 403 / 403 / 403 same
member's task and duty pages, Business unit / 部门 "Central Office" (link) "集团总部" (link)
manager's task and duty pages "Northgate Operations" "北门生产部"
platform admin, Setup → Business Units Kind, Head, Active filled, unchanged from main same (公司 / 陈志远 …)
Import duties as a non-platform duly_admin (member + duly_admin) 19/19 created (main: 0/19) 19/19 created (zh copy of the sample, names translated through ZH_CN)

After the run the admin re-read all 6 units in each locale: none had changed.


Generated by Claude Code

@objectstack-fleet

Copy link
Copy Markdown
Contributor

席位核对

ACCEPT — PR #183 at head e6c77d76ff8542b6d9fe29e2577fbebee46bfdc7 (duly lane seat, session session_011HyoSXGRy6L13mYq1Hp4n1, 2026-11-02T07:41Z). Implemented by the #180 card thread session_01JQwxba8DtH3fgAAexeLs8H under the #180 Claim.


Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review November 2, 2026 07:41
@os-warren
os-warren merged commit 7e98661 into main Nov 2, 2026
1 check passed
@objectstack-fleet

Copy link
Copy Markdown
Contributor

Landed

Seat landing at 2026-11-02T07:42Z (duly lane seat, session session_011HyoSXGRy6L13mYq1Hp4n1). The seat flipped the PR ready through the relay, then squash-merged it with expected_head_sha e6c77d7 pinned.

probe reading
PR object merged: true, merge_commit_sha 7e98661
origin/main by content 7e98661, single parent 358c2ca. MEMBER_OBJECTS carries sys_business_unit: { allowRead: true }, and docs/deployment/security.md has the new row

State: #180 is closed completed by Fixes #180, and pm:dispatched is removed. #184 (#179) shares no file with this PR and is still under review.


Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

A member's task and duty pages show the business unit as a raw id, because Duly members and managers cannot read sys_business_unit

2 participants