Skip to content

fix(local-cloak): match profile processes on an exact --user-data-dir boundary - #243

Open
Kaushik2003 wants to merge 1 commit into
agentrhq:mainfrom
Kaushik2003:fix/cloak-profile-process-boundary-match
Open

fix(local-cloak): match profile processes on an exact --user-data-dir boundary#243
Kaushik2003 wants to merge 1 commit into
agentrhq:mainfrom
Kaushik2003:fix/cloak-profile-process-boundary-match

Conversation

@Kaushik2003

Copy link
Copy Markdown

Description

On macOS, terminateProfile picked the Chromium processes to SIGTERM with a bare
substring test on the ps command line
(darwin-background-launch.ts:42-50). Profiles are siblings under
~/.webcmd/cloak/profiles/<id> and ids may contain - and ., so
--user-data-dir=…/profiles/work matched …/profiles/work-2 as well: tearing down
one background profile killed a healthy concurrent one. With no CloakBrowser binary
check, a user's own Chrome on a matching --user-data-dir was killed too. The
victim only ever surfaced Target page, context or browser has been closed.

Lock recovery in session-manager.ts already matched profile processes correctly —
requiring the flag value to end at an argument boundary, resolving realpath aliases,
and restricting matches to CloakBrowser binaries. This moves that matching into a
new profile-processes.ts and routes both call sites through it, so there is one
implementation instead of two that disagree.

The helpers cannot live in either existing module: session-manager.ts already
imports darwin-background-launch.ts, so either direction would create a cycle.
The new module is a straight move — no behavior change on the recovery path.

Teardown on the context-close path is now best-effort like the launch-failure path
beside it, so a ps or kill failure no longer replaces the outcome of
browser.close().

Files in the commit:

  • src/browser/runtime/local-cloak/profile-processes.ts — new; profile process
    discovery and signalling, moved from session-manager.ts.
  • src/browser/runtime/local-cloak/session-manager.ts — imports the moved helpers.
  • src/browser/runtime/local-cloak/darwin-background-launch.tsterminateProfile
    uses the shared matching; teardown made best-effort.
  • src/browser/runtime/local-cloak/profile-processes.test.ts — new; regression
    coverage.

Related issue: #242

Type of Change

  • 🐛 Bug fix
  • ✨ New feature
  • 🌐 New site adapter
  • 📝 Documentation
  • ♻️ Refactor
  • 🔧 CI / build / tooling

Checklist

  • I ran the checks relevant to this PR — npm run typecheck, plus the affected
    src/browser/runtime/local-cloak suites (see below)
  • I updated tests or docs if needed — added profile-processes.test.ts; no
    user-facing surface changed, so no docs or skills update
  • I included output or screenshots when useful

Adapter Notes

Not an adapter change — this touches the local CloakBrowser runtime only.

  • Updated generated or lean docs when command discoverability changed
  • Used positional args for the command's primary subject unless a named flag is clearly better
  • Normalized expected adapter failures to CliError subclasses instead of raw Error

Screenshots / Output

The two boundary tests fail against the previous matching and pass with this
change, so they are genuine regression coverage.

$ npx vitest run src/browser/runtime/local-cloak/profile-processes.test.ts --reporter=verbose

 ✓ commandUsesProfileDir > does not match a profile dir that is a prefix of another
 ✓ commandUsesProfileDir > matches the flag at the end of the command line
 ✓ isCloakBrowserCommand > ignores a Chromium that is not the Cloak build
 ✓ findCloakProfileProcesses > returns only the Cloak process owning the exact profile dir
 ✓ findCloakProfileProcesses > reports no processes when ps fails

 Test Files  1 passed (1)
      Tests  5 passed (5)

Reverting commandUsesProfileDir to the old substring test reproduces the bug in
those tests:

FAIL  commandUsesProfileDir > does not match a profile dir that is a prefix of another
      AssertionError: expected true to be false

FAIL  findCloakProfileProcesses > returns only the Cloak process owning the exact profile dir
      AssertionError: expected [ 32818, 32819, 32820 ] to deeply equal [ 32818 ]
                               (sibling profile and the user's own Chrome also matched)

The neighbouring suites still pass, confirming the move did not change recovery
behaviour:

$ npx vitest run src/browser/runtime/local-cloak/{profile-processes,session-manager,darwin-background-launch}.test.ts

 Test Files  3 passed (3)
      Tests  38 passed (38)

$ npm run typecheck
(clean)

Note on CI: these tests live under src/browser/**, which the vitest unit
project excludes — see #231 and PR #238. Until that lands they need a local vitest
config to run; CI will not report them.

Note on #225: distinct root cause (that one is in the CloakBrowser launch
layer), but it produces the same opaque
Target page, context or browser has been closed in concurrent-profile workflows,
so it may be a second contributing cause of what #225 describes.

… boundary

Background-profile teardown found the Chromium to kill with a bare substring
test on the process command line. Because profile ids may share a prefix
(`work` / `work-2`, `default` / `default-2`), `--user-data-dir=<dir>` matched
sibling profiles too, so closing one background context sent SIGTERM to a
healthy concurrent profile's browser. The victim surfaced only the opaque
"Target page, context or browser has been closed". The same match had no
Cloak-binary check, so a user's own Chrome on a matching profile dir was
killed as well.

Launch recovery in session-manager.ts already did this correctly. Its process
matching moves to profile-processes.ts and is reused by terminateProfile, so
both paths agree on which processes belong to a profile. The helpers cannot
live in either existing module without an import cycle, since session-manager
already imports darwin-background-launch.

Teardown on the success path is now best-effort as well, so a ps or kill
failure no longer replaces the outcome of browser.close(). The launch-failure
path was already guarded this way.
@github-actions

github-actions Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

🟢 No documentation gap found — medium confidence

The automated review found no documentation gap in the supplied changes.

This review is advisory and does not block merging.

@Kaushik2003

Copy link
Copy Markdown
Author

@ngaurav - Tagging you for visibility. Happy to adjust this fix if it doesn't align with the vision for the project.

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.

2 participants