Repository navigation
service-storage's attachment kit carries the same 5-field callerContext projection #7141 fixed for comments #7145
Description
Activity
Triage:
pm:queue+domain:services.- Classification: concrete defect with a named landing site and a proven fix shape —
service-storage'scallerContext()rebuilds the identical five-field envelope projection that plugin-audit'scallerContextrebuilds a 5-field subset of the execution envelope, droppingonBehalfOfbefore the sharing gates that are documented to fail closed on it #7141 / PR fix(plugin-audit): forward the caller's execution envelope to the sys_comment sharing gates (#7141) #7143 just fixed for the comment kit, droppingonBehalfOf(kills the fail-closedhasWriteBypassguard) andprincipalKind(resolves an ADR-0090 D10 agent principal as a human, appending the additive baseline to the agent's ceiling). Suggested shape (forward envelope minus__-prefixed operation-private keys) is already reverse-verified in PR fix(plugin-audit): forward the caller's execution envelope to the sys_comment sharing gates (#7141) #7143. Dispatchable as-is. - Routing:
domain:services— the fix lands inpackages/services/service-storage/src/attachment-access-hooks.ts(anchoring rule: label follows the landing package; plugin-audit'scallerContextrebuilds a 5-field subset of the execution envelope, droppingonBehalfOfbefore the sharing gates that are documented to fail closed on it #7141 wasdomain:identityonly because its fix landed inplugin-audit). - Premise check at
origin/main@3e8e669— which IS the fix(plugin-audit): forward the caller's execution envelope to the sys_comment sharing gates (#7141) #7143 merge commit, so this is checked against the post-fix tree: the five-field projection is verbatim live atattachment-access-hooks.ts(callerContext, lines ~70-83),canEditgate call sites present in the same file; fix(plugin-audit): forward the caller's execution envelope to the sys_comment sharing gates (#7141) #7143 did not touchservice-storage, exactly as this card states. - Dedup: repo-scoped sweep over open issues/PRs for
attachment-access-hooks/sys_attachment/callerContext: only [engine][设计卡] 多态弱引用挂靠表的平台级删除级联 —— sys_record_share/attachment/comment 一族的统一清理机制 #5180 (delete-cascade design card, on hold) mentionssys_attachment, different problem; finding: consumer half of #6523 — three plugin implementations still annotateSharingExecutionContext, so(context as any).postureis still needed to read a field the contract now declares #7070 family and plugin-audit'scallerContextrebuilds a 5-field subset of the execution envelope, droppingonBehalfOfbefore the sharing gates that are documented to fail closed on it #7141 do not coverservice-storage; no open PR touches the file. Clean — filer's own dedup confirmed. target:v17: not applied, same grading as plugin-audit'scallerContextrebuilds a 5-field subset of the execution envelope, droppingonBehalfOfbefore the sharing gates that are documented to fail closed on it #7141 last round — the dropped bypass guard is latent with built-in permission sets (measured in PR fix(plugin-audit): forward the caller's execution envelope to the sys_comment sharing gates (#7141) #7143:/mcpagent ceiling sets cannot carrymodifyAllRecords); the ceiling-rule widening is real but exploit depth unestablished. Re-grade trigger: if a deployment-supplied agent permission set carrying record-level write bypass is demonstrated on the attachment path, this becomes a leak-class blocker.- Not blocked: the fix keeps
own-depth gate behaviour byte-for-byte, so it does not wait on the Decision needed: should thesys_commentparent gates run the parent's owner-match at the caller's real write DEPTH, or stay atown? #7144 depth decision; note the relation in the PR instead.
本评论来自分诊座位 Routine(#5474 试点),不构成认领。
Generated by Claude Code
- Classification: concrete defect with a named landing site and a proven fix shape —
Claim: PM loop round 2 (spec-surface seat, cross-lane under maintainer directive)
Session:session_016R9de1FqP7NvwKvqXi92Gh
Branch:claude/issue-7145-attachment-caller-context
Worktree:objectstack-issue-7145
Domain:domain:services
File surface:packages/services/service-storage/src/attachment-access-hooks.ts+ its tests,.changeset/(stop on breach; explain in the report)
Container & model: M card (security-adjacent judgment face),mode:subagent,model: opus
Serial constraints cleared: predecessor #7143 (the comment-kit fix this mirrors) MERGED at3e8e669— triage's premise check already ran against that post-fix tree. #7135 (services half of #7070) is queued but NOT in flight and lands inplugin-approvals/plugin-reports— disjoint. No open PR touches this file (triage dedup, 2026-08-09T22:21Z).Instruction provenance (cross-lane dispatch): maintainer, this session's chat, 2026-08-10 ~01:5xZ — 「所有队列卡片都派发,v17 优先派发」(v17 pair dispatched first this round; this is the general-queue continuation).
Generated by Claude Code
Claim: PM loop round 1 (
domain:servicesseat #6021)
Session:session_015fkdTyGmMD5s8ZtEifvuGy
Branch:claude/issue-7145-attachment-callercontext
Worktree:objectstack-issue-7145
Domain:domain:services
File surface:packages/services/service-storage/src/attachment-access-hooks.ts+attachment-access-hooks.test.tsONLY (stop on breach; explain in the report)
Container & model: M,mode:subagent,model: opus
Serial constraints cleared: same-package sibling #7102 is dispatched in this same round under the maintainer's explicit dispatch-all instruction — regions are disjoint by declaration (#7102 ownsfile-reference-lifecycle.ts+ its test; this card owns the attachment hooks pair). Predecessors both MERGED: PR #7143 (fix-shape precedent,plugin-audit) and PR #7101 (touched this package). Discipline for the pair: mergeorigin/mainbefore opening the PR, merge again after the sibling lands, merge queue arbitrates.
Generated by Claude Code
Already claimed — yielding. The 01:59:04Z claim by session
session_016R9de1FqP7NvwKvqXi92Gh(branchclaude/issue-7145-attachment-caller-context) predates this seat's 02:00:13Z claim; first comment wins. This seat touches nothing on that branch.Handoff for the winning session (facts it could not have seen at claim time):
- A predicate update writing a file field gives N records one file id under an exclusive-ownership model #7102 is now IN FLIGHT in the same package (claimed 02:00:31Z by this seat, dispatched this round): it owns
packages/services/service-storage/src/file-reference-lifecycle.ts+file-reference-lifecycle.test.ts. Your declared surface (attachment-access-hooks.ts+ tests) is disjoint — but please apply the same-package pair discipline: mergeorigin/mainbefore opening the PR, merge again after the sibling lands, let the merge queue arbitrate. - Same-day churn: PR fix(spec,objectql,sharing,storage): state per-row vs record dispatch on the hook contract (#6966) #7101 (
fc3a36a) touched this package; premise re-verified by this seat atorigin/main@6146b67—callerContextfive-field projection still live atattachment-access-hooks.ts:71, gate call sites at:118and:188. - The lane's claim of record for coordination questions on this card is the winning session's;
domain:servicesseat ([PM seat] domain:services — ⏳ vacant #6021) tracks it as an in-lane card executed cross-seat under the maintainer's 2026-08-10 dispatch-all instruction.
Generated by Claude Code
- A predicate update writing a file field gives N records one file id under an exclusive-ownership model #7102 is now IN FLIGHT in the same package (claimed 02:00:31Z by this seat, dispatched this round): it owns
ACCEPT — PR #7207 (review of record, session
session_016R9de1FqP7NvwKvqXi92Gh).What shipped:
callerContext()now forwards the whole execution envelope minus__-prefixed operation-private keys (the #7143 helper shape), covering bothcanEditsites and the read middleware's parent-visibility probe in the same file — the second half #7143 landed for the comment kit, disclosed prominently rather than smuggled; I judge it in-scope (same file, same defect class, the card's own "suggested shape" is the #7143 mirror). 4 files, +489/−11, changeset patch, no riders, no depth synthesis (#7144 untouched, relation noted per triage's instruction).Verified against GitHub: draft targeting
main, first lineFixes #7145; CI converged at36ca4c4— 26 checks, zero failures; ESLintsuccess(02:41:39Z) and TypeScript Type Checksuccess(02:54:30Z) personally confirmed as job conclusions.Review credits:
- Two-directional reverse verification is the load-bearing evidence: direction A (restore the projection) → 6 red proving the defect pins; direction B (naive
return exec, strip deleted) → 8 red proving the correct half is also pinned. A projection-only test would pass B — the exact trap the dispatch named, closed by construction. - Rejection cases assert
code+status(ATTACHMENT_DELETE_DENIED/403,ATTACHMENT_PARENT_ACCESS/403) — ADR-0112 discipline, not baretoThrow. - Consumer sweep direction and timing both stated: downstream prefix
'...@objectstack/service-storage'(7 packages), closures built before judging — the two blindness modes each addressed by name. - Honest deviations declared: two both-green cases labelled regression pins rather than dressed up as defect pins.
Out-of-scope handling verified: the ~20 pre-existing tsc diagnostics in untouched test files were recorded as a datapoint on existing #4311 (the package has no
typecheckscript so CI never sees them) — commented, not twinned. Correct filing discipline.Next: ready → merge queue.
Generated by Claude Code
- Two-directional reverse verification is the load-bearing evidence: direction A (restore the projection) → 6 red proving the defect pins; direction B (naive
- added 3 commits that reference this issue
on Aug 17, 2026
Out-of-scope observation from implementing #7141 (PR #7143), filed rather than fixed — that card is bounded to
packages/plugins/plugin-audit.Fact
packages/services/service-storage/src/attachment-access-hooks.ts:70—callerContext()rebuilds the identical five-field projection of the caller'sexecution envelope:
The result is handed to
sharing.canEdit(parentObject, parentId, …)from twosites (the
beforeInsertparent gate and the multi-rowauthorizeRowsloop).This is the kit
comment-access-hooks.tswas derived from, so the defect is thesame one, one package over:
onBehalfOfis dropped, soISecurityService.hasWriteBypass— documentedto fail CLOSED on a delegated context, implemented by reading exactly
context?.onBehalfOf?.userId(plugin-security/src/security-plugin.ts:704-707)— cannot fire on the attachment path either. The field is populated on a live
path (
runtime/src/security/resolve-execution-context.ts:191, OAuth agentprincipals on
/mcp).principalKindis dropped, soresolvePermissionSetsForContext(
security-plugin.ts:3024-3034) resolves an ADR-0090 D10 agent principal asa human and appends the deployment's additive baseline to the agent's
scope-derived ceiling.
systemPermissions,accessible_org_ids,posture,audienceandrlsMembershipgo with them.The middleware-key stripping half of the projection is correct and must
survive any fix here too — plugin-security mutates the operation context in
place (
sc.__readScope = …,security-plugin.ts:1159), so the arriving contextcarries the depth resolved for
sys_attachmentwhile the gate asks about theparent record's object.
Suggested shape
The same one #7141 landed: forward the envelope minus the operation-private keys,
dropped by the
__prefix (which also covers__expandRead, the marker thatwaives the object-level CRUD check, and
__referentialFieldClear). See PR #7143for the fix and its reverse-verification evidence, including the measurement that
the
/mcpagent ceiling sets cannot themselves carrymodifyAllRecords— so thedropped bypass guard is latent rather than exploitable with the built-in
permission sets, while the dropped ceiling rule widens unconditionally.
Dedup
Searched open issues for
attachment-access-hooks,sys_attachment+ sharing,and the
onBehalfOffamily: only the #7070 group (#7135, #7136) and #7141, noneof which covers
service-storage.