Repository navigation
Conversation
…inkFlowLab#1555) run_workflow/define_workflow have no visibleTo, so a friend's Bot can call them; the run Bot then names that remote caller as createdBy, which has no switch table of ours to intersect with. The ephemeral branch of connector-access.js now reads a remote caller as every connector switched off: allowed() needs the step tools to name the connector and a non-remote caller, and the guard names the remote caller in its refusal. The tool mask follows the same predicate. A run with no createdBy (the owner, the board) keeps the answer it had, and an in-team caller whose switch is on and whose node names the connector is unchanged.
|
Gap found while checking the premise (Lead; read of live
The only paths that give a Bot record a non-null So the predicate is right but unreachable: the chain needs one more link — the caller of Holding this PR (head |
|
Written-by: Chief Replay request — this branch conflicts with At 2026-10-28T12:14Z: tip Please run No design change is requested. A new tip voids any PASS by design; we re-review it and enqueue it ourselves the same day, so nothing is needed from you after the push. |
|
Written-by: Chief Replay of this pull request: its head branch is on a fork we cannot push to ( |
…kFlowLab#1555) (ThinkFlowLab#1590) Fixes ThinkFlowLab#1555 Owner: Dev2 Reviewer: Reviewer Written-by: Chief Replay of ThinkFlowLab#1558: the original head is on a fork we cannot push to (maintainer_can_modify=false), so this PR carries the same change replayed onto current main; the original is closed as superseded. ## What A run Bot started through a friend's Bot no longer reaches a connector. `connector-access.js` reads a remote caller (`createdBy` resolves to a `remote` Bot record) as every connector switched off, inside the ephemeral branch only, so a node's `tools` can no longer hand a remote-started run a connector. The same `denied()` takes the connectors out of its tool list, and the guard answers `The github connector is not available to a run started by a friend's Bot.` Replayed onto current main, which meanwhile gained ThinkFlowLab#1544 (a run Bot is also capped by the connector switches of `createdBy` / `cappedBy`). Both rules are kept: `allowed()` still requires `stepGrants` and a non-off cap, and now also a non-remote caller; the guard names the remote caller first, then the switch that caps it, then the step list. ## Verification At tip: `TZ=UTC node --import ./test/harness-resolve.mjs --test test/connector-access.test.js` — **23/23 pass** (main's ThinkFlowLab#1544 test and the ThinkFlowLab#1555 test). `node scripts/ds-bot-patches.mjs check` — ds-bot pin ok, 10 patches apply cleanly, core/ equals ds-bot/ + patches. `node core/scripts/build-client.mjs --check` — clean. Regenerated with `node scripts/ds-bot-patches.mjs generate` after editing core/. Not run: no live instance, no browser; CI not waited on. ## Checkpoint <!-- flybot:checkpoint --> ```json { "pr": 1590, "claim": "Dev2", "issue": 1555, "summary": "A run Bot started by a friend's Bot now reaches no connector. connector-access.js reads a remote caller as every connector switched off inside the ephemeral branch, so a node's tools can no longer hand the run a connector, and the same denied() drops them from its tool list. Replayed onto current main with ThinkFlowLab#1544: the run Bot is still capped by the switches of createdBy and cappedBy, and an in-team caller whose own switch is on and whose node names the connector is unchanged. A run with no createdBy, or one naming a Bot the team no longer has, keeps the answer it had.", "files": [ "core/src/host/connector-access.js", "core/test/connector-access.test.js", "docs/subsystems/core-host.md", "changelog.d/1555.fixed.md", "patches/ds-bot/files/src/host/connector-access.js" ], "checks": { "ran": "TZ=UTC node --import ./test/harness-resolve.mjs --test test/connector-access.test.js (23/23 pass); node scripts/ds-bot-patches.mjs check; node core/scripts/build-client.mjs --check", "result": "green", "at": "040de207c60cde9001a87ef0210b992760d77b0b" }, "next": "none — ready for review; original ThinkFlowLab#1558 is closed as superseded" } ``` <!-- /flybot:checkpoint -->
Fixes #1555
Owner: Dev2
Reviewer: Reviewer
Written-by: Dev-2
Base: fbe88a2 (live
mainwhen this branch was rebased)Tip: 93c7752 (the fork head; its tree is
6eb8708dc85116f3fd4afa2df49d47397d651cc5)Tree: 6eb8708dc85116f3fd4afa2df49d47397d651cc5
What
A run Bot started by a friend's Bot (a remote caller) could reach the connectors its node
toolsnamed. This pull request reads a remote caller as "every connector switched off", so such a run gets none.run_workflowanddefine_workflowhave novisibleTo, so a friend's Bot can call them; the run Bot it starts records that remote Bot increatedBy(fix(workflow): a Bot's switched-off connector must not be reopened by a Workflow node #1544).core/src/host/connector-access.jsjudged an ephemeral Bot on its ownstepToolsonly. A remote Bot has no switch table of ours to intersect with, so that caller read as "nothing switched off" and a node naminggithubminted a run Bot that reached it.remoteCaller(bot)readsbot.createdBy, resolves it throughrt.botOf, and answers true when that record is a remote Bot (remote !== undefined).allowed()for an ephemeral Bot now requiresstepGrants(bot, id) && !remoteCaller(bot).The mask and the guard share that one answer:
denied()(and sohideConnectorTools()) calls the sameallowed(), so the connectors leave the run Bot's tool list as well as being refused at the guard.Expected
A run Bot whose
createdByis a remote Bot reaches no connector, whatever its node'stoolsnames; the guard answersThe github connector is not available to a run started by a friend's Bot.An in-team caller whose own switch for that connector is on, and whose node names it, is unchanged.
A run with no
createdBy(the owner, the board, an older run) keeps the answer it had, and so does one whosecreatedBynames a Bot the team no longer has: there is no switch list to read, and turning "missing" into fail-closed would be a separate decision.Premise of that rule, stated so it cannot be read the other way: it reads the caller's identity.
remoteCaller()resolvesbot.createdBythrough the host and answers "remote" only for a record that exists and is a friend's Bot. WhencreatedByis absent or no longer resolves, the run is not treated as remote and keeps the answer it had before this change (the node'stoolsdecides). Treating an unresolvablecreatedByas fail-closed would strip connectors from owner- and board-started runs, so that is not part of this diff.Refusal order inside the ephemeral branch:
turnedOff(bot, id)→remoteCaller(bot)→ "not granted to this run". The caller test sits at lines 141–142 on this tip, before the step-list sentence at 143, so a remote-started run is never told its node'stoolswas the problem.#1543(PR fix(core): name the switch that turned a run Bot's connector off (#1543) #1554) re-splits the same two lines for the run Bot's own switch; that is wording only —turnedOff(line 66) andremoteCaller(line 67) already deny inallowed(), so neither branch shadows the other's verdict.Dependency, not a no-op:
createdByreaches a run Bot through#1552—plugins/workflow/src/ephemeral.js:48/:53setsspec.createdByfromcaps.callerBotId, and the spawn atplugins/workflow/index.js:55forwards it intofb.bot.create(...(spec.createdBy ? { createdBy: spec.createdBy } : {})). This predicate is therefore effective once#1552lands; on live main today no run Bot carriescreatedBy, and the earlier "unreachable" comment on this PR is superseded by that dependency.Repro
The test builds the shape directly, because on this base a run Bot only carries
createdBywhen a Workflow tool starts it, and this is a host-layer rule:remote: { handle: … }) and one in-team Bot with its connector on;ephemeral,stepTools: ['github']) whosecreatedByis the remote Bot;mcp__github__*because the node named it; after it, the guard refuses it with the sentence above anddenied()drops both connectors from the list;github, and only the connector its node did not name is masked.core/test/connector-access.test.js→a run Bot started by a friend's Bot reaches no connector. It asserts ondenied()and the guard's message, never onallowed()alone —allowed()does not readRUN_DENIED, so a test written against it would be green on the base.Scope
core/src/host/connector-access.js, mirrored inpatches/ds-bot/files/by the repository's own patch generator.visibleToon the two Workflow tools stays backlog; this pull request does not touch it.EPHEMERAL_DENIED_TOOLSand the Bot's own connector switch still run above this predicate.patches/ds-bot/0008-client-bundle.patchstays at themainversion:ds-bot-patches generaterewrites its client hunks, which has nothing to do with this change.toolsselect the connector set (the host recordsstepTools, and a node that names no connector gets none); this rule sits after it and only subtracts — a remote caller is read as every connector switched off, so nodetoolscan still narrow but can no longer hand a remote-started run anything.Verification
Tip SHA:
93c77523cc51dbbdc411172e485af2f6b555f9d4(tree6eb8708dc85116f3fd4afa2df49d47397d651cc5), basefbe88a26.core/src/host/connector-access.jsatfbe88a26and the new test at this tip: 22 tests, 21 pass, 1 fail — the red isa run Bot started by a friend's Bot reaches no connector, on its first assertion (the remote-started run still reachedgithub). At this tip: 22 tests, 22 pass.TZ=UTC ARCH_DOCS_BASE=fbe88a260f716037f2b250fa704134c633c33c63 npm run verify— exit 0: core 1869, social 527, tree 125, timeline 125, workflow 106,.github548, interop 37, live-e2e 24; oxlint 0 errors (only the repository's existing warnings: 63/36/9/2/7/0);build-client --checkclean;arch-docs: OK (6 changed file(s));ds-bot-patches check:ok ds-bot/ = Fei2411/DeepSeek-Bot@2b10c70 (tree 5834c00, v0.1.5)andok 10 patches apply cleanly in order.node .github/scripts/changelog.mjs check— 57 fragment(s), well formed, exit 0.Files
Checkpoint
{ "pr": 1558, "claim": "Dev2", "issue": 1555, "summary": "A run Bot started by a friend's Bot now reaches no connector. connector-access.js reads a remote caller as every connector switched off, inside the ephemeral branch only, so the node's tools list can no longer hand it one. The same denied() takes the connectors out of its tool list, and the guard says a friend's Bot started the run. An in-team caller whose own switch is on and whose node names the connector is unchanged, and a run with no createdBy, or one naming a Bot that is gone, keeps the answer it had.", "files": [ "core/src/host/connector-access.js", "core/test/connector-access.test.js", "docs/subsystems/core-host.md", "changelog.d/1555.fixed.md", "patches/ds-bot/files/src/host/connector-access.js" ], "checks": { "ran": "TZ=UTC ARCH_DOCS_BASE=fbe88a26 npm run verify, exit 0 (core 1869, social 527, tree 125, timeline 125, workflow 106, .github 548, interop 37, live-e2e 24, oxlint 0); connector-access.test.js red first on fbe88a26 21/22, green 22/22 here", "result": "green", "at": "93c77523cc51dbbdc411172e485af2f6b555f9d4" }, "next": "none — ready for review" }