feat(devutils): add remote-build.sh to build and run rac on the MacBook Pro#42

merged5
main
feat/remote-build
opened14h agobyKKainoa Newton
View on GitHubTwo-way sync enabledPR last imported 6m ago

Problem. The shared MacBook Air is overloaded: load average around 125 on 8 cores and 16 GB, two Chromium builds plus about a dozen browser launches at once. The maintainer approved moving compiles and browser launches to their MacBook Pro (18 cores, 48 GB), which is also their daily-driver machine. Threads, git and reviews stay on the Air.

Change. devutils/rac/remote-build.sh runs everything over plain ssh, with every file under ~/rac-remote/ on the Pro:

  • setup-host: prints the Pro's cores, RAM, disk and tools, and compares both machines' Xcode build and SDK. It refuses on a mismatch, because a tree built with another SDK recompiles from scratch.
  • seed-base <sync worktree> <tag>: one resumable rsync of the 156 base's build/src. It rewrites siso's file state to the Pro path the same way worktree.sh setup does.
  • push <worktree>: committed state only, through a bare repo. It never copies build/. It then runs worktree.sh setup or sync on the Pro.
  • build <worktree> [-- targets]: runs through the Pro's own build queue under nice -n 10 and taskpolicy -c utility, with siso capped at cores minus 4. It streams output and returns the remote exit code.
  • run <worktree>: uses only worktree.sh run (the clone's own profile and Crashpad folder) with --rac-launch-in-background and a timeout. It kills only processes inside the clone. It refuses absolute or .. paths, any Application Support, real profile folder names, single-dash switches, --user-data-dir and --rac-window-screenshot-activate.
  • pull, status, and a --dry-run flag.
  • docs/operations/worktrees.md gets a short "Building on the MacBook Pro" section.

Verified.

  • 36 unit tests run against a fake ssh and rsync. bash -n and shellcheck -S warning are clean.
  • The real setup-host against the Pro printed this Mac: Xcode 27.1 (build 27A9275, SDK 27.0) and the Pro: Xcode 26.6 (build 17F113, SDK 26.5), then refused with exit 2. It created nothing on the Pro.
  • Devin SWE-2 wrote it in two hill-climb rounds (25/25). Claude Opus reviewed it and fixed 15 defects. The worst ones could write or delete outside ~/rac-remote, reuse a real profile, or kill another clone's browser.

Not verified. seed-base, push, build and run haven't run against the real Pro. They wait on the maintainer's Xcode choice: install Xcode 27.1 on the Pro, or do a native cold build there.

Patch surface (D17): no change, because this PR touches no patches.

πŸ€– Generated with Claude Code


Devin Review


Note

Medium Risk New remote orchestration runs git force-push, queued compiles, and targeted process teardown on a maintainer machine, though scope and argument validation are heavily constrained and covered by tests.

Overview Adds devutils/rac/remote-build.sh, a CLI that offloads Chromium compiles and screenshot browser runs to a maintainer MacBook Pro over non-interactive SSH, keeping work confined to ~/rac-remote (bare repos, base/, per-worktree clones in wt/, queue state, logs).

Base setup replaces Airβ†’Pro tree sync: build-base <ref> clones the ref on the Pro, bootstraps like a first local build (he presetup, merge, explicit quilt push, worktree.sh sync, he configure), then optionally queues a detached cold build only with --approved. seed-base is removed in favor of this native path. setup-host initializes bare repos and reports both machines’ Xcode/SDK (mismatch is informational, not a hard stop).

Day-to-day flow: push (committed state only, helium-chromium pin handling), build / run through the existing build-queue.sh with reserved cores and nice/taskpolicy, pull via rsync, plus log / status. Operations refuse unsafe states (dirty trees, queue/busy clones, Xcode/SDK drift vs base/.rac-toolchain copied into clones, symlink escapes, dangerous run args).

Ships a large darwin-only unittest suite (test_remote_build.py) using fake ssh/rsync, and documents the workflow in docs/operations/worktrees.md.

Reviewed by Cursor Bugbot for commit f968abbb692a9431062f7daf491b56ebe60afa90. Bugbot is set up for automated code reviews on this repo. Configure here.

Checks

2 failing Β· 7 successful Β· 2 neutral Β· 1 skipped
Some checks failed

Failing2

  • pullfrogGitHub
    Failed
  • VercelGitHub
    Failed
f968abb

Added 1 commit

  • feat(devutils): add remote-build.sh to build and run rac on the MacBook Proe890785
Synced from GitHub

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

External image Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: 888f34cd-7da5-46b6-a417-708ee7ae6804

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • πŸ” Trigger review
  • Autofix Β· Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❀️ Share

Comment @coderabbitai help to get the list of available commands.

Synced from GitHub

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: 718839b6-c21c-4fe1-a72f-cb63c4e931d3)

devutils/rac/remote-build.shline 584Outdated Β· e890785Open thread
……@@ -0,0 +1,633 @@
581+ *) dest=./$dest ;;
582+ esac
583+ # Pro to Air: the clone is only read.
584+ xrsync "$host:$rdir/wt/$name/$rel" "$dest"
Ddevin-ai-integrationBoton line 58414h ago

🟨 Pull paths can read beyond the clone

When an allowed pull path traverses a symlink inside the clone, rsync reads its external target. The lexical .. check cannot enforce the clone-only boundary.

Devin Review


Was this helpful? React with πŸ‘ or πŸ‘Ž to provide feedback.

devutils/rac/remote-build.shlines 532–534Outdated Β· e890785Open thread
……@@ -0,0 +1,633 @@
531+launcher=$!
532+end=$((SECONDS + timeout))
533+last=-1
534+while [ "$SECONDS" -lt "$end" ]; do
Ddevin-ai-integrationBoton lines 532–53414h ago

🟑 Queue wait consumes browser timeout

When run slots stay busy for the timeout, cmd_run kills the queued launcher before the browser starts. Screenshot runs fail without ever launching a browser.

Learn more

The build queue waits indefinitely until a run slot is free. Here SECONDS starts counting while that wait is still in progress, and the caller terminates the queue at the deadline. A screenshot request then reports failure even though no browser was started.

Example: With both Pro run slots held for 95 seconds, run feature -- --rac-window-screenshot=x.png times out at 90 seconds and produces no screenshot, even if the slots free at 95 seconds.

Recommended fix: Separate queue-acquisition time from the browser runtime limit, or start the runtime deadline when the queue confirms the run slot and launches the browser.

Devin Review


Was this helpful? React with πŸ‘ or πŸ‘Ž to provide feedback.

devutils/rac/remote-build.shlines 498–500Outdated Β· e890785Open thread
……@@ -0,0 +1,633 @@
497+ case "$arg" in
498+ --rac-window-screenshot=*)
499+ shot="$clone/build/shots/${arg#--rac-window-screenshot=}"
500+ arg="--rac-window-screenshot=$shot" ;;
Ddevin-ai-integrationBoton lines 498–50014h ago

πŸŸ₯ Relative screenshot paths can escape clone via symlinks

When build/shots contains a symlink to another directory, run writes screenshots through that symlink. Its lexical path check cannot keep screenshots inside the clone or protect the maintainer's files.

Devin Review


Was this helpful? React with πŸ‘ or πŸ‘Ž to provide feedback.

devutils/rac/remote-build.shlines 90–92Outdated Β· e890785Open thread
……@@ -0,0 +1,633 @@
89+only_patch_state() {
90+ [ -z "$(awk '/^\?\? "?patches\/rac\// { print; next }
91+ /^\?\? / || /^.?D "?patches\/series"?$/ { next }
92+ { print }')" ]
Ddevin-ai-integrationBoton lines 90–9214h ago

🟑 Untracked source files vanish from remote builds

When a worktree contains a new untracked source file, only_patch_state lets push proceed without sending it. The remote build then runs the committed tree instead of the local worktree's code.

Learn more

The local cmd_push checks this filter and sends only the current branch commit. This filter treats every ?? entry as expected merged-patch state, including new scripts and assets outside patches/. Git does not include those files in the push, so the remote clone differs from the worktree the developer requested.

Example: Add resources/new-icon.svg without staging it, then run push followed by build. Push succeeds; the remote checkout has no icon file even though it exists locally.

Recommended fix: Permit only known generated merged-patch files, and reject other untracked paths. Use untracked-file expansion when checking directories so an untracked patches/ directory cannot hide new rac patches.

Devin Review


Was this helpful? React with πŸ‘ or πŸ‘Ž to provide feedback.

devutils/rac/remote-build.shlines 304–307Outdated Β· e890785Open thread
……@@ -0,0 +1,633 @@
304+DEVELOPER_DIR=$xcode "$siso" fs export -C "$src/out/Default" \
305+ | python3 -c 'import sys; o, n = sys.argv[1:]; sys.stdout.write(sys.stdin.read().replace(o, n))' \
306+ "$1/" "$PWD/$src/" \
307+ | DEVELOPER_DIR=$xcode "$siso" fs import -C "$src/out/Default"
Ddevin-ai-integrationBoton lines 304–30714h ago

πŸ”΄ Failed export corrupts seeded build state

If siso fs export fails during seed-base, the pipeline can still succeed after importing empty state. The base loses its incremental build state, so subsequent clones can trigger full Chromium rebuilds.

Learn more

The remote seed-base script uses set -e, but a shell pipeline returns only its last command's status. If siso fs export or the Python rewrite fails, siso fs import can succeed on its remaining input. The caller then proceeds to GN and reports a seeded base despite losing the exported state. cmd_setup uses pipefail and explicitly rejects failed state transfers.

Example: If export exits 1 without producing data while import exits 0, seed-base finishes and reports success; the first feature clone inherits missing or invalid Siso state instead of the Air's completed build state.

Recommended fix: Enable pipefail in the remote seed script and propagate any export, rewrite, or import error before reporting success; also validate the imported state before cloning from it.

Devin Review


Was this helpful? React with πŸ‘ or πŸ‘Ž to provide feedback.

Synced from GitHub

RetriggerView in GreptileConfidence Score: 0/5

[Medium impact] The PR extends the maintainer's remote build and browser workflow to feature worktrees on the Pro.

Do not merge until remote screenshot paths are contained and pushes and runs are coordinated safely.

Findings

  1. P1Β SecurityΒ Requests bypass screenshot safety checks β–Ά
  2. P1Β Push changes an active build β–Ά
  3. P1Β Helium updates stay behind β–Ά
  4. P1Β Runs close each other's browser β–Ά
  5. P1Β Waiting runs can succeed silently β–Ά
Fix with agent prompt
markdown
1### Issue 1
2devutils/rac/remote-build.sh:440-449
3`check_run_arg` accepts `--rac-window-screenshot-requests=requests.txt`. Combined with `--rac-window-screenshot=x.png`, this makes the browser activate itself and read output paths from `requests.txt` without checking them. A file containing an absolute path or `../` can overwrite files outside the clone.
4
5Refuse this switch for remote runs unless both its foreground behavior and its requested output paths are made safe.
6
7**How this was verified:** The accepted relative request-file switch reaches code that activates the app and passes the file's contents to `Capture` and `WriteBytes` without a path check.
8
9### Issue 2
10devutils/rac/remote-build.sh:363-367
11Pushing another commit while the clone is compiling resets the checkout and runs `sync` without entering the queue or taking a shared lock. `sync` pops and reapplies source patches, so it can change files underneath the compiler and leave a failed or mixed build.
12
13Make updates and builds share a per-clone lock, held across the reset and sync.
14
15### Issue 3
16devutils/rac/remote-build.sh:364-367
17When a pushed commit changes the pinned `helium-chromium` commit, `push` transfers only the parent repository. `git reset --hard` changes the pin but leaves the submodule checkout at its old commit. `merge` then runs the old submodule's script and uses its old patches; `worktree.sh sync` does not update it either.
18
19Transfer and check out the pinned submodule commit before merging patches, or explicitly refuse unsupported pin changes.
20
21### Issue 4
22devutils/rac/remote-build.sh:514-519
23`stop_clone` kills every browser from the clone, not just the browser started by this call. The queue allows overlapping runs of the same worktree, and those runs share a browser profile. Whichever call finishes first can therefore kill the other's browser and lose its output.
24
25Hold a per-clone run lock before touching screenshots or launching, or limit cleanup to processes owned by this call.
26
27### Issue 5
28devutils/rac/remote-build.sh:529-534
29The timeout starts before the queue grants a slot. If both run slots stay busy for 90 seconds, the default call kills its waiting queue process without ever launching a browser. Without a screenshot argument, `status=0` then reports success. A slot granted late also leaves the browser only the remaining time.
30
31Start the browser timeout inside the queued command after it gets a slot. Return an error if a separate queue-wait limit expires.
32
33---
34
35For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Summary

Adds remote-build.sh to seed a remote base, push committed worktrees, queue builds and browser runs, and retrieve files.

  • A matching MacBook Pro can hold a reusable base tree for remote builds.
  • Committed feature worktrees get their own clones on the Pro.
  • Pro builds use the shared queue and leave cores free for other work.
  • Remote browser runs keep screenshots and processes inside their worktree clone.
  • Operators can pull files back and check the Pro's status after remote work.

Review used source inspection only; no runtime verification was performed.

Diagram

mermaid
1%%{init: {'theme': 'neutral'}}%%
2flowchart TD
3 Air[Air: remote-build.sh] -->|ssh and git push| Repos[Pro: bare repositories]
4 Air -->|rsync build/src| Base[Pro: seeded base]
5 Repos --> Push[Create or update worktree]
6 Base --> Push
7 Push --> Clone[Remote clone]
8 Clone --> Queue[Remote build queue]
9 Queue --> Build[Compile]
10 Queue --> Run[Launch browser]
11 Run --> Shots[Screenshots]
12 Shots -->|rsync pull| Air

Reviews (1) Β· Last reviewed commit: "feat(devutils): add remote-build.sh to b..." Β· Reviewed by Greptile

devutils/rac/remote-build.shlines 514–519Outdated Β· e890785Open thread
……@@ -0,0 +1,633 @@
516+ for i in 1 2 3 4 5 6 7 8 9 10; do
517+ pids=$(clone_pids)
518+ [ -n "$pids" ] || return 0
519+ kill $pids 2>/dev/null || true
Ggreptile-appsBoton lines 514–51914h ago

P1 Runs close each other's browser

stop_clone kills every browser from the clone, not just the browser started by this call. The queue allows overlapping runs of the same worktree, and those runs share a browser profile. Whichever call finishes first can therefore kill the other's browser and lose its output.

Hold a per-clone run lock before touching screenshots or launching, or limit cleanup to processes owned by this call.

Prompt To Fix With AI
markdown
1This is a comment left during a code review.
2Path: devutils/rac/remote-build.sh
3Line: 514-519
4
5Comment:
6**Runs close each other's browser**
7
8`stop_clone` kills every browser from the clone, not just the browser started by this call. The queue allows overlapping runs of the same worktree, and those runs share a browser profile. Whichever call finishes first can therefore kill the other's browser and lose its output.
9
10Hold a per-clone run lock before touching screenshots or launching, or limit cleanup to processes owned by this call.
11
12---
13
14For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.
devutils/rac/remote-build.shlines 529–534Outdated Β· e890785Open thread
……@@ -0,0 +1,633 @@
531+launcher=$!
532+end=$((SECONDS + timeout))
533+last=-1
534+while [ "$SECONDS" -lt "$end" ]; do
Ggreptile-appsBoton lines 529–53414h ago

P1 Waiting runs can succeed silently

The timeout starts before the queue grants a slot. If both run slots stay busy for 90 seconds, the default call kills its waiting queue process without ever launching a browser. Without a screenshot argument, status=0 then reports success. A slot granted late also leaves the browser only the remaining time.

Start the browser timeout inside the queued command after it gets a slot. Return an error if a separate queue-wait limit expires.

Prompt To Fix With AI
markdown
1This is a comment left during a code review.
2Path: devutils/rac/remote-build.sh
3Line: 529-534
4
5Comment:
6**Waiting runs can succeed silently**
7
8The timeout starts before the queue grants a slot. If both run slots stay busy for 90 seconds, the default call kills its waiting queue process without ever launching a browser. Without a screenshot argument, `status=0` then reports success. A slot granted late also leaves the browser only the remaining time.
9
10Start the browser timeout inside the queued command after it gets a slot. Return an error if a separate queue-wait limit expires.
11
12---
13
14For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.
devutils/rac/remote-build.shlines 363–367Outdated Β· e890785Open thread
……@@ -0,0 +1,633 @@
364+ git reset -q --hard "$3"
365+ devutils/update_patches.sh merge
366+ if [ -d build/src ]; then
367+ devutils/rac/worktree.sh sync
Ggreptile-appsBoton lines 363–36714h ago

P1 Push changes an active build

Pushing another commit while the clone is compiling resets the checkout and runs sync without entering the queue or taking a shared lock. sync pops and reapplies source patches, so it can change files underneath the compiler and leave a failed or mixed build.

Make updates and builds share a per-clone lock, held across the reset and sync.

Prompt To Fix With AI
markdown
1This is a comment left during a code review.
2Path: devutils/rac/remote-build.sh
3Line: 363-367
4
5Comment:
6**Push changes an active build**
7
8Pushing another commit while the clone is compiling resets the checkout and runs `sync` without entering the queue or taking a shared lock. `sync` pops and reapplies source patches, so it can change files underneath the compiler and leave a failed or mixed build.
9
10Make updates and builds share a per-clone lock, held across the reset and sync.
11
12---
13
14For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.
devutils/rac/remote-build.shlines 440–449Outdated Β· e890785Open thread
……@@ -0,0 +1,633 @@
446+ *=?*) ;;
447+ *) refuse "give the screenshot file as --rac-window-screenshot=<name>.png" ;;
448+ esac ;;
449+ esac ;;
Ggreptile-appsBoton lines 440–44914h ago

P1 security Requests bypass screenshot safety checks

check_run_arg accepts --rac-window-screenshot-requests=requests.txt. Combined with --rac-window-screenshot=x.png, this makes the browser activate itself and read output paths from requests.txt without checking them. A file containing an absolute path or ../ can overwrite files outside the clone.

Refuse this switch for remote runs unless both its foreground behavior and its requested output paths are made safe.

How this was verified: The accepted relative request-file switch reaches code that activates the app and passes the file's contents to Capture and WriteBytes without a path check.

Prompt To Fix With AI
markdown
1This is a comment left during a code review.
2Path: devutils/rac/remote-build.sh
3Line: 440-449
4
5Comment:
6**Requests bypass screenshot safety checks**
7
8`check_run_arg` accepts `--rac-window-screenshot-requests=requests.txt`. Combined with `--rac-window-screenshot=x.png`, this makes the browser activate itself and read output paths from `requests.txt` without checking them. A file containing an absolute path or `../` can overwrite files outside the clone.
9
10Refuse this switch for remote runs unless both its foreground behavior and its requested output paths are made safe.
11
12**How this was verified:** The accepted relative request-file switch reaches code that activates the app and passes the file's contents to `Capture` and `WriteBytes` without a path check.
13
14---
15
16For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.
devutils/rac/remote-build.shlines 364–367Outdated Β· e890785Open thread
……@@ -0,0 +1,633 @@
364+ git reset -q --hard "$3"
365+ devutils/update_patches.sh merge
366+ if [ -d build/src ]; then
367+ devutils/rac/worktree.sh sync
Ggreptile-appsBoton lines 364–36714h ago

P1 Helium updates stay behind

When a pushed commit changes the pinned helium-chromium commit, push transfers only the parent repository. git reset --hard changes the pin but leaves the submodule checkout at its old commit. merge then runs the old submodule's script and uses its old patches; worktree.sh sync does not update it either.

Transfer and check out the pinned submodule commit before merging patches, or explicitly refuse unsupported pin changes.

Prompt To Fix With AI
markdown
1This is a comment left during a code review.
2Path: devutils/rac/remote-build.sh
3Line: 364-367
4
5Comment:
6**Helium updates stay behind**
7
8When a pushed commit changes the pinned `helium-chromium` commit, `push` transfers only the parent repository. `git reset --hard` changes the pin but leaves the submodule checkout at its old commit. `merge` then runs the old submodule's script and uses its old patches; `worktree.sh sync` does not update it either.
9
10Transfer and check out the pinned submodule commit before merging patches, or explicitly refuse unsupported pin changes.
11
12---
13
14For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Added 1 commit

  • feat(devutils): keep remote builds going after errors, and say all Pro builds use the tooleb57ec4
Synced from GitHub

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: 33120521-2101-4921-82fd-e69a8636f730)

Added 1 commit

  • fix(devutils): harden remote-build.sh and build the Pro's base nativelyccdb670
Synced from GitHub

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: 86bee605-844d-4a82-ac1c-33966fb37890)

Added 1 commit

  • fix(devutils): check a screenshot path before creating its folders58cf98e
Synced from GitHub

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: f500ad57-19f1-4471-a1b7-5099b3b4bfe1)

Added 1 commit

  • docs: say an Xcode update invalidates a build machine's treesf968abb
CcursorBot8h ago
Synced from GitHub

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: 0ac8b748-caf1-4f82-876c-697059dd5701)