Skip to content

Refuse a tracked build whose checkout is on another machine - #1

Merged
vburojevic merged 1 commit into
mainfrom
fix/tracked-builds-refuse-other-host
Aug 30, 2026
Merged

Refuse a tracked build whose checkout is on another machine#1
vburojevic merged 1 commit into
mainfrom
fix/tracked-builds-refuse-other-host

Conversation

@vburojevic

Copy link
Copy Markdown
Owner

The bug

Running a tracked build from a thread whose environment lives on an enrolled Mac (not the machine running bb) fails with:

ENOENT: no such file or directory, realpath '/Users/m1/.bb-machines/veki.getbb.app/worktrees/env_w4kuwbvdcu/TypeDock'

The directory plainly exists on the machine the user is looking at, and node -e 'fs.realpathSync(p)' succeeds there — so the message reads as a broken checkout rather than a topology mismatch.

bb xcode run --host <that machine> does not work around it: the path is resolved in the process where the plugin is hosted, not on the host named in the flag, so the flag is silently misleading.

Root cause

ThreadScope carried path but no host identity. ScopeSync took env.path at face value as a local path, and confinedBuildCwdrealpath then ran node:fs against another machine's filesystem.

Diagnosis evidence:

Probe Result
fs.realpathSync(path) on the owning host OK
bb file paths --host <owning host> lists the worktree
bb file paths --host <primary> empty
bb settings show primaryHostId = the primary, not the env's host
bb environment show --json already exposes hostId

The fix

src/sim/hostcheck.ts already states this exact rule for Stills — "a checkout on another host is a real refusal with a real sentence rather than a mysterious 'no such file'" — and already derives the server's own host id via the nonce + hosts.pathsExist trick. That rule just never reached tracked builds. This applies it there, reusing locateCheckout and resolveServerHostId instead of introducing a second mechanism.

  • ThreadScope gains hostId; ScopeSync reads it off the environment DTO. bb already returned it — the dep type had narrowed it away, so no server.ts data plumbing was needed.
  • checkoutHostMismatch() produces the sentence, and fails open when either host id is unknown, so no existing single-machine setup can be newly refused.
  • Both entry points — bb xcode run and the xcode_build tool — consult it before any filesystem work.

Scope

This refuses clearly; it does not route the build. Executing on the environment's host would also require the run tracking (a local lsof process probe, DerivedData scanning, the shim) to work cross-machine — a much larger change. Happy to follow up if that is wanted.

Verification

  • npm run check (typecheck + full suite): 67 files, 825 passed, 7 skipped, 0 failures
  • New test/checkout-host.test.ts covers same-host, other-host, unknown-host fallback, and the fail-open cases
  • Two new boundary tests in test/agent-scope-security.test.ts assert the agent tool refuses before touching the filesystem, and that a local checkout still passes the gate

Note: better-sqlite3 needs its native binary built for the suite to run (npm install-scripts approve better-sqlite3 && npm rebuild better-sqlite3); without it 126 tests fail for unrelated reasons.

🤖 Generated with Claude Code

bb supports a server with enrolled Macs, so a thread's environment can live on
a host that is not the one running this plugin. The tracked-build path never
knew that: `confinedBuildCwd` calls `realpath` with `node:fs` on THIS machine,
so a thread whose worktree lives on another Mac died with

  ENOENT: no such file or directory, realpath '/Users/<other>/.../Checkout'

naming a directory that plainly exists on the machine the user was looking at.
`bb xcode run --host <that machine>` did not help either, because the path is
resolved where the plugin is hosted, not on the host named in the flag.

`src/sim/hostcheck.ts` already states the rule for Stills — "a checkout on
another host is a real refusal with a real sentence rather than a mysterious
'no such file'" — and derives the server's own host id. That rule simply never
reached tracked builds. This applies it there, reusing `locateCheckout` and
`resolveServerHostId` rather than adding a second mechanism.

- `ThreadScope` carries `hostId`; `ScopeSync` reads it off the environment DTO
  (bb already returned it, the dep type just narrowed it away).
- `checkoutHostMismatch` turns the mismatch into the sentence, and fails OPEN
  when either host is unknown so single-machine setups are untouched.
- Both entry points — `bb xcode run` and the `xcode_build` tool — consult it
  before any filesystem work.

Note this refuses; it does not route the build. Executing on the environment's
host would need the run tracking (a local lsof process probe) to work
cross-machine too, which is a larger change.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@vburojevic
vburojevic merged commit 990c449 into main Aug 30, 2026
0 of 2 checks passed
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.

1 participant