Repository navigation
Description
Written-by: Triage
Owner: Dev2(2026-10-27T04:12Z 改派:Dev4 今日两次被停、在 #1316 上卡死约 46 分钟后已改派走,手上无进展;#1322 的 copy picker 是 Dev2 做的,上下文最近。边界仍按已定的「same-owner only」:copyFrom 与 schedule-update 只许读本 actor 自己用户的 Session 任务,跨 owner 明确拒绝,数据层拒、不靠 UI 隐藏)
Decision: same-owner only (Owner decision: same-owner only, pinned in the comment below) — copyFrom and schedule-update both refuse a source whose owner differs from the actor's own. Scheduled on Dev2, no longer blocked: #1322 merged at 04:09:36Z (main 6d5743e8) and #1316 is now PR #1333 (cd4f3fe1, waiting on Reviewer2), which touches only core/src/shared/workflow-run.js and its test — no overlap with schedules.js. The three options under "Why this needs a decision" are now history: option 1 was chosen.
Follow-up from the PASS on #1307 at cdbe206b937007e738807d387ad4888a56c9967c (6432868685, 03:16:54Z, Written-by: Reviewer). The reviewer wrote it as "none of them a condition of this verdict"; this issue tracks exactly one of those four.
Wait for #1307 to merge first. Every line number below is on that PR's tip, not on main: the file it points at does not carry this code until #1307 lands. Branch from main after the merge; do not branch from dev3/1287-copy-schedule.
The gap
The reviewer wrote: "copyFrom reads any known Session's task. ownerOf(sessionId) resolves every chat/room/past part the host knows, and schedule-create does not scope the source to the caller the way view() does — with several members a signed-in actor can copy another member's task together with its prompt. schedule-update already resolves sources the same way, so this is not new, but copy is the first path that reads a foreign task's text into a new one."
Checked at the tip: ownerOf (core/src/host/schedules.js:163-168) resolves rt.chatOwners → rt.roomOf → rt.groupOwners → rt.pastOwners, i.e. every Session the host knows; copySchedule takes body.copyFrom.sessionId straight into it (:321-324) and then into the new task's title/prompt/timing (:327, :334). schedule-update resolves its source the same way (:399), so no new exposure was introduced by #1287 — what is new is that a copy carries the foreign task's text into a task the actor owns.
Why this needed a decision, not a patch (settled by the lead)
The right answer is a security boundary, and it changes what the feature can do:
- same user only (a copy may only read a task whose owner is the caller), or
- same team/room members too, or
- keep it as-is and accept that a signed-in member can copy a peer's task text.
Each answer changes the refusal sentence, the picker's roster, and possibly schedule-update (which resolves sources the same way and would then be inconsistent). That is a maintainer call, not something an agent should pick.
Scope once decided
- Narrow the source in
copyScheduleand inupdateSchedule(core/src/host/schedules.js:399, the sameownerOfresolution), with the refusal in the same voice as the existing ones — reuse an existing refusal sentence rather than inventing one. - One case per boundary: a foreign task is refused (or allowed) as decided, and the existing same-chat / unknown-target refusals stay green.
- No change to the row write or to Resume.
Out of scope
The other three follow-ups; any broader authz redesign.
Activity
Birfy commentedon Oct 27, 2026
Owner decision: same-owner only
Written-by: Triage — the lead made the call (the user's answer was "你看着办").
The boundary: copy only within the actor's own user.
copyFrommay only read a task whose Session belongs to the actor's own user. When the ownerownerOfresolves differs from the actor's owner, refuse with an explicit sentence — no silent success, no empty line pretending it worked.schedule-update(core/src/host/schedules.js:399, the sameownerOfresolution) is tightened in the same change: fixingcopyFromalone would leave the same read one endpoint over.Owner:
Dev4. Schedule: behind#1316, then#1322— do not dispatch this one before those are done.If no existing refusal sentence fits, reuse an existing refusal rather than inventing one (the dispatch will say the same).
Birfy commentedon Oct 27, 2026
Written-by: Dev2
Claimed #1321 — branch
dev2/1321-copyfrom-owner-scopefrommain@6d5743e8(the#1322/#1324work is merged;#1316is not a dependency of this one).First step: one guard in the data layer that both
copyFromandschedule-updatego through — when authz is enforced, the source Session's owner must be the actor's own user; otherwiseNo such task(the sentence already in this file for an unresolvable source, no second wording and no existence leak). Cross-owner is refused everywhere; same room / same team does not open the door; nothing is hidden in the UI.fix(schedules): a copy and an edit read only the caller's own task (#…
chore(patches): regenerate the ds-bot mirrors for the owner-scope cop…
docs(core-host): the owner-scope fix adds five cases, not three (#1321)
fix(schedules): a copy and an edit read only the caller's own task (T…