Repository navigation
Description
Implementation: FlyBot (ours) — PR follows within 24h. Do not pick up without a pickup-ok comment on this issue.
Written-by: FlyBot Lead
Claimed-by: FlyBot Lead
Claim-Id: ae58f625925b42809f06801630075c4f
Branch: dev/2-project-board-authz
Base: 554d939
At: 2026-10-29T15:25:40Z
Written-by: FlyBot Lead
Two defects in the read model merged as #1703 (core/src/host/project-board.js, live main 554d939e64ad7833e66f1c7e72a3fddded14b763). Both were found by FlyBot Product reading that merge; both reproduce on that commit.
A. project-board is not in the authorisation allowlist, so a signed-in deployment cannot call it.
core/src/host/authz.js:60-72TASK_ENDPOINTScarriesprojects,project-create,project-read,project-bind,project-of(#1691's five) but not#1703's new read endpoint. The switch is wired (channel.js:674), the store is wired (store.js:440) and the module installs (project-board.js:56) — only the allowlist line is missing.- With
authzEnforced()true (anyone has signed in), the request falls to the default deny atauthz.js:406-414:project-board→bot/not-found: Unknown endpoint project-board, whileproject-read/project-of/project-bind/tasksall answer ALLOW under the same actor. Reproduced through the real channel with a signed-in member session:project-readanswersok {project:…},project-boardfails with that message. - Four reasons this is an omission rather than a design: the three wiring points are all present; the sibling endpoints read the same team state and are allowed; the refusal code is
bot/not-found(reads like a typo'd endpoint name) rather thanbot/forbidden/ a shared-state refusal; andcore/test/project-board.test.js:124("the project-board endpoint serves the same rows") only runs on the authz-off fixture, whereauthSessionsis empty — a false-green surface for exactly this path. - Docs leak the same way:
docs/subsystems/core-host.md:209lists only the five.
B. A run binding can pull another Project's card onto this board.
core/src/host/project-board.js:43asks only "is the card's own board this Project"; when the card's board belongs to a different Project it falls into therunProjectbranch and is reported as "brought by the run". The comment above it states the intent — a run carries only cards that have no Project of their own (board === null) — the code does not implement that.- Reproduced with a group card bound to Project 1 and a run bound to Project 2 holding that card: Project 1's board lists the card with Project 2's
runId, and Project 2's board lists a card that belongs to Project 1.
Expected
- A signed-in actor that may read the Project record may read its board:
project-boardallowed for the same actors asprojects/project-read, and a test that exercises it with a non-emptyauthSessionsso the allowlist path is actually covered (the shapecore/test/workflow-store.test.js:120-127uses forworkflow-save). - A card appears on exactly one Project board — the Project of its own board when it has one.
source:'workflow'andrunId/nodeIdonly when the card has no Project of its own and the run's Project is this one; a card whose own board belongs to another Project never appears here. docs/subsystems/core-host.md:209lists all six Project endpoints.
Scope — core/src/host/authz.js (one allowlist line), core/src/host/project-board.js (the source/run-binding condition, about four lines), core/test/project-board.test.js (the authz-on regression: an existing test asserts row shape with deepEqual, so keep those assertions in step), docs/subsystems/core-host.md:209, and the regenerated patches/ds-bot/** mirrors for the changed core files.
Acceptance
- Red first on
554d939e: withauthzEnforced()and a signed-in actor,project-boardis refused (assert the refusal code, not just that a call fails); and the cross-Project fixture shows Project 1's board carrying Project 2's run id while Project 2's board carries Project 1's card. - After the fix: the same actor is allowed; Project 1's board lists only its own rows; a card with no Project of its own still appears with
source:'workflow'and itsrunId(existing cases 1 and 4 depend on this and must keep passing). TZ=UTC ARCH_DOCS_BASE=<live main> npm run verifyexit 0 with counts reported;node scripts/ds-bot-patches.mjs checkgreen.
Duplicate check (before opening): searched open and closed issues for project-board, authz, allowlist, project board → #1703 (the merge this fixes, closed), #1710 (Stage 2.3 board view + role-gated actions, enhancement, different scope: UI and role decisions), #1701 (our client projection). No issue covers the allowlist line or the cross-Project leak; not a duplicate. Not folded into #1710 because that is an enhancement owned elsewhere and this is a shipped-defect fix.
Activity
HugoXK commentedon Oct 29, 2026
Release
Written-by: FlyBot Lead
Released: ae58f625925b42809f06801630075c4f
Reason: merged via #1716 (merge_commit f8e4943)
At: 2026-10-29T16:20:33Z
core: paint only the Project cards `tasks` would let a member open (T…