[PR #3471] [MERGED] fix(electron): block moveToApplicationsFolder during active capture #5761

Closed
opened 2026-10-31 01:09:14 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/3471
Author: @keeponlight
Created: 10/14/2026
Status: ✅ Merged
Merged: 10/21/2026
Merged by: @morluto

Base: main ← Head: fix/electron-move-to-applications-folder


📝 Commits (2)

  • 10b17b1 fix(electron): block moveToApplicationsFolder during active capture
  • 6f4a810 Merge remote-tracking branch 'origin/main' into fix/electron-move-to-applications-folder

📊 Changes

2 files changed (+33 additions, -4 deletions)

View changed files

📝 scripts/electron-active-hook-boundaries.cjs (+10 -2)
📝 tests/boundary/browser/electronActiveHook.test.ts (+23 -2)

📄 Description

Summary

Blocks app.moveToApplicationsFolder in the Electron active hook boundary so targets launched via capture_electron_scenario cannot relocate the operator's Electron bundle into /Applications during startup.

Fixes #3452

Problem and expected behavior

scripts/electron-active-hook-boundaries.cjs patched app.relaunch, app.setAsDefaultProtocolClient, and app.setLoginItemSettings, but did not intercept app.moveToApplicationsFolder. When a macOS Electron target called app.moveToApplicationsFolder(...) from a non-/Applications scratch directory, Electron moved the runtime bundle into /Applications/Electron.app and quit, closing the Playwright target without recording a blocked timeline event.

docs/electron-observation.md specifies that the active hook blocks and records updater and OS-integration effects. app.moveToApplicationsFolder should be blocked without invoking the original method or any supplied conflictHandler, recorded in the timeline (kind: "app-lifecycle", event: "moveToApplicationsFolder", phase: "blocked"), and return false so the application stays in place.

Change and scope

  • Added "moveToApplicationsFolder" to patchApplicationEffects in scripts/electron-active-hook-boundaries.cjs.
  • Classified blocked moveToApplicationsFolder calls under the existing "app-lifecycle" timeline event kind (preserving "updater" exclusively for relaunch and "protocol" for protocol/login-item methods) with phase: "blocked" and error: true, returning false per Electron's synchronous boolean contract.
  • Extended tests/boundary/browser/electronActiveHook.test.ts on top of the current staged-fixture harness (writeElectronFixture / runNode) with throwing negative-oracle stubs on both app.moveToApplicationsFolder and the passed conflictHandler callback, verifying non-invocation, move_result === false, and separate retained timeline events for both moveToApplicationsFolder (app-lifecycle) and relaunch (updater).

Contribution scope: not applicable (ordinary fix within existing boundaries).

Contract and boundary impact

  • Semantic owner and earliest changed stage: Electron active hook boundary (scripts/electron-active-hook-boundaries.cjs)
  • Contribution scope fit and linked maintainer decision: not applicable
  • CLI and MCP/tool-catalog contract: none
  • Provider, bridge, target-format, or platform compatibility: none; timeline event kind uses existing "app-lifecycle" schema literal
  • Evidence, artifact, provenance, or reconstruction contract: blocked moveToApplicationsFolder attempts are now preserved in the active timeline alongside argument_shapes and error: true
  • Target selection, authority, upstream behavior, and cleanup details (if applicable): prevents target-initiated bundle relocation outside the scratch root during active capture
  • Generated metadata (docs/public/product-catalog.json), package, or installation impact: none

Expected effects:

  • Read existing files or captured data.
  • Launch or attach to a process.
  • Inject instrumentation or run scripts/code.
  • Change process memory, registers, files, or configuration.
  • Contact network services.
  • Recover protected code or work around protections.
  • Documentation or usability only; no target interaction.
  • Not sure yet; investigation or maintainer guidance needed.

Evidence and regression coverage

  • Tests added or updated: tests/boundary/browser/electronActiveHook.test.ts stubs app.moveToApplicationsFolder and conflictHandler to throw if invoked, exercises electron.app.moveToApplicationsFolder({ conflictHandler }), and asserts move_result === false, { kind: "app-lifecycle", event: "moveToApplicationsFolder", phase: "blocked", argument_shapes: ["object"], error: true }, and separate { kind: "updater", event: "relaunch", phase: "blocked" } retention.
  • Base reproduction or other evidence: executed via npx vitest run tests/boundary/browser/electronActiveHook.test.ts on macOS Darwin arm64 (Node v24.14.1); without the boundary patch, the throwing stub aborts the child process.
  • User-visible CLI/MCP output (if applicable): timeline includes the blocked moveToApplicationsFolder event.
  • Remaining proof gaps: verified with the boundary hook harness rather than a packaged macOS .app bundle calling native NSFileManager move APIs.

For evidence-bearing changes:

  • Observed, derived, and inferred claims remain distinguishable.
  • Artifact identity, source provenance, and failed attempts remain preserved.
  • Unsupported, incomplete, unavailable, or uncertain outcomes remain visible.

Validation performed

  • npx vitest run tests/boundary/browser/electronActiveHook.test.ts — 4 passed (542ms)
  • npm run check:fast — typecheck and lint passed
  • node scripts/scan-todos.mjs — No tech-debt markers found.

Compatibility, safety, and release

  • Breaking changes or migration steps: none
  • Real Hopper/Ghidra, browser, or OS coverage: macOS arm64 Node boundary harness
  • Package or release metadata impact: none
  • Security, privacy, process, or containment review: improves host containment by preventing the inspected Electron app from moving the operator's Electron binary into /Applications.

Author readiness

Human owner: @keeponlight

  • I reviewed the final diff and relevant existing code, understand the change and its edge cases, and take responsibility for the complete PR, including AI-assisted work.
  • I checked the evidence above, confirmed it supports the current change, and recorded meaningful validation gaps.
  • I declare this PR ready for initial maintainer review.

Before merge

  • This PR addresses a concrete problem or an agreed enhancement.
  • Material scope and authority questions are resolved, and any required maintainer scope decision covers the final diff.
  • The PR has one focused outcome and the title follows type(scope): outcome.
  • Related issue is linked, or the reason for not linking one is stated above.
  • Tests cover changed observable behavior and meaningful failure paths.
  • Owning docs, contracts, and generated metadata are updated where needed.
  • User-visible CLI/MCP changes include representative output.
  • I checked the final diff for secrets, unrelated cleanup, and unsupported claims.

🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/morluto/rea/pull/3471 **Author:** [@keeponlight](https://github.com/keeponlight) **Created:** 10/14/2026 **Status:** ✅ Merged **Merged:** 10/21/2026 **Merged by:** [@morluto](https://github.com/morluto) **Base:** `main` ← **Head:** `fix/electron-move-to-applications-folder` --- ### 📝 Commits (2) - [`10b17b1`](https://github.com/morluto/rea/commit/10b17b17b77768090fc579a294038d68b947a0c1) fix(electron): block moveToApplicationsFolder during active capture - [`6f4a810`](https://github.com/morluto/rea/commit/6f4a81097d96e1077d81432cd0b7afb473cfbc61) Merge remote-tracking branch 'origin/main' into fix/electron-move-to-applications-folder ### 📊 Changes **2 files changed** (+33 additions, -4 deletions) <details> <summary>View changed files</summary> 📝 `scripts/electron-active-hook-boundaries.cjs` (+10 -2) 📝 `tests/boundary/browser/electronActiveHook.test.ts` (+23 -2) </details> ### 📄 Description ## Summary Blocks `app.moveToApplicationsFolder` in the Electron active hook boundary so targets launched via `capture_electron_scenario` cannot relocate the operator's Electron bundle into `/Applications` during startup. Fixes #3452 ## Problem and expected behavior `scripts/electron-active-hook-boundaries.cjs` patched `app.relaunch`, `app.setAsDefaultProtocolClient`, and `app.setLoginItemSettings`, but did not intercept `app.moveToApplicationsFolder`. When a macOS Electron target called `app.moveToApplicationsFolder(...)` from a non-`/Applications` scratch directory, Electron moved the runtime bundle into `/Applications/Electron.app` and quit, closing the Playwright target without recording a blocked timeline event. `docs/electron-observation.md` specifies that the active hook blocks and records updater and OS-integration effects. `app.moveToApplicationsFolder` should be blocked without invoking the original method or any supplied `conflictHandler`, recorded in the timeline (`kind: "app-lifecycle"`, `event: "moveToApplicationsFolder"`, `phase: "blocked"`), and return `false` so the application stays in place. ## Change and scope - Added `"moveToApplicationsFolder"` to `patchApplicationEffects` in `scripts/electron-active-hook-boundaries.cjs`. - Classified blocked `moveToApplicationsFolder` calls under the existing `"app-lifecycle"` timeline event kind (preserving `"updater"` exclusively for `relaunch` and `"protocol"` for protocol/login-item methods) with `phase: "blocked"` and `error: true`, returning `false` per Electron's synchronous boolean contract. - Extended `tests/boundary/browser/electronActiveHook.test.ts` on top of the current staged-fixture harness (`writeElectronFixture` / `runNode`) with throwing negative-oracle stubs on both `app.moveToApplicationsFolder` and the passed `conflictHandler` callback, verifying non-invocation, `move_result === false`, and separate retained timeline events for both `moveToApplicationsFolder` (`app-lifecycle`) and `relaunch` (`updater`). Contribution scope: not applicable (ordinary fix within existing boundaries). ## Contract and boundary impact - Semantic owner and earliest changed stage: Electron active hook boundary (`scripts/electron-active-hook-boundaries.cjs`) - Contribution scope fit and linked maintainer decision: not applicable - CLI and MCP/tool-catalog contract: none - Provider, bridge, target-format, or platform compatibility: none; timeline event kind uses existing `"app-lifecycle"` schema literal - Evidence, artifact, provenance, or reconstruction contract: blocked `moveToApplicationsFolder` attempts are now preserved in the active timeline alongside `argument_shapes` and `error: true` - Target selection, authority, upstream behavior, and cleanup details (if applicable): prevents target-initiated bundle relocation outside the scratch root during active capture - Generated metadata (`docs/public/product-catalog.json`), package, or installation impact: none Expected effects: - [ ] Read existing files or captured data. - [ ] Launch or attach to a process. - [x] Inject instrumentation or run scripts/code. - [ ] Change process memory, registers, files, or configuration. - [ ] Contact network services. - [ ] Recover protected code or work around protections. - [ ] Documentation or usability only; no target interaction. - [ ] Not sure yet; investigation or maintainer guidance needed. ## Evidence and regression coverage - Tests added or updated: `tests/boundary/browser/electronActiveHook.test.ts` stubs `app.moveToApplicationsFolder` and `conflictHandler` to throw if invoked, exercises `electron.app.moveToApplicationsFolder({ conflictHandler })`, and asserts `move_result === false`, `{ kind: "app-lifecycle", event: "moveToApplicationsFolder", phase: "blocked", argument_shapes: ["object"], error: true }`, and separate `{ kind: "updater", event: "relaunch", phase: "blocked" }` retention. - Base reproduction or other evidence: executed via `npx vitest run tests/boundary/browser/electronActiveHook.test.ts` on macOS Darwin arm64 (Node v24.14.1); without the boundary patch, the throwing stub aborts the child process. - User-visible CLI/MCP output (if applicable): timeline includes the blocked `moveToApplicationsFolder` event. - Remaining proof gaps: verified with the boundary hook harness rather than a packaged macOS `.app` bundle calling native `NSFileManager` move APIs. For evidence-bearing changes: - [x] Observed, derived, and inferred claims remain distinguishable. - [x] Artifact identity, source provenance, and failed attempts remain preserved. - [x] Unsupported, incomplete, unavailable, or uncertain outcomes remain visible. ## Validation performed - `npx vitest run tests/boundary/browser/electronActiveHook.test.ts` — 4 passed (542ms) - `npm run check:fast` — typecheck and lint passed - `node scripts/scan-todos.mjs` — `No tech-debt markers found.` ## Compatibility, safety, and release - Breaking changes or migration steps: none - Real Hopper/Ghidra, browser, or OS coverage: macOS arm64 Node boundary harness - Package or release metadata impact: none - Security, privacy, process, or containment review: improves host containment by preventing the inspected Electron app from moving the operator's Electron binary into `/Applications`. ## Author readiness Human owner: @keeponlight - [x] I reviewed the final diff and relevant existing code, understand the change and its edge cases, and take responsibility for the complete PR, including AI-assisted work. - [x] I checked the evidence above, confirmed it supports the current change, and recorded meaningful validation gaps. - [x] I declare this PR ready for initial maintainer review. ## Before merge - [x] This PR addresses a concrete problem or an agreed enhancement. - [x] Material scope and authority questions are resolved, and any required maintainer scope decision covers the final diff. - [x] The PR has one focused outcome and the title follows `type(scope): outcome`. - [x] Related issue is linked, or the reason for not linking one is stated above. - [x] Tests cover changed observable behavior and meaningful failure paths. - [x] Owning docs, contracts, and generated metadata are updated where needed. - [x] User-visible CLI/MCP changes include representative output. - [x] I checked the final diff for secrets, unrelated cleanup, and unsupported claims. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-10-31 01:09:14 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#5761
No description provided.