Skip to content

feat(desktop): import browser cookies into a profile - #7255

Open
juliusmarminge wants to merge 58 commits into
shared-sqlite-clientfrom
browser-profile-import
Open

feat(desktop): import browser cookies into a profile#7255
juliusmarminge wants to merge 58 commits into
shared-sqlite-clientfrom
browser-profile-import

Conversation

@juliusmarminge

@juliusmarminge juliusmarminge commented Aug 16, 2026

Copy link
Copy Markdown
Member

Stacked on #7272 (shared-sqlite-client).

Imports cookies from Helium on macOS into a T3 Code browser profile. Saved passwords and browsing history remain out of scope.

The app requests the browser key through the in-process Keychain API, so consent belongs to T3 Code. Denial stops the import; there is no permission bypass. Source databases are opened read-only and snapshotted consistently with SQLite before extraction.

The wizard chooses a source and destination, prevents profile edits during an import, and reports imported/skipped counts and affected sites. Plaintext and encrypted cookie records are handled separately; domain-bound records are validated. Partitioned cookies are skipped when their partition semantics cannot be preserved by Electron.

Validation includes synthetic decryption records, plaintext and legacy records, domain-binding failures, partitioned-cookie rejection, WAL snapshot consistency, interrupted writes, and wizard state transitions, plus scoped typechecks/lint. Earlier Helium imports were verified in the desktop app; this audit did not request another live Keychain read.

Original implementation: Claude Code. Review fixes: GPT-5.6 Sol agents, coordinated through Codex.

Note

Add browser cookie import into desktop profiles

  • Introduces the BrowserImport service to read, decrypt, and import cookies from Chromium-based browsers (currently Helium on macOS) into a specific Electron session partition.
  • Adds a BrowserImportWizard component in the settings UI to select source and target profiles, handle browser running states, and display import results.
  • Registers IPC channels PREVIEW_IMPORT_SOURCES_CHANNEL and PREVIEW_IMPORT_COOKIES_CHANNEL, and updates the desktop build script to stage @napi-rs/keyring native binaries.
  • Implements a serialized persistence queue in useSettings.ts to prevent concurrent client settings write interleaving.
  • Risk: readChromiumCookies in ChromiumCookies.ts only supports macOS Keychain decryption; Windows/Linux will return unsupportedPlatform. Build requires correct @napi-rs/keyring binary staging or fails with KeyringNativePackageMissingError.

Macroscope summarized 683ca1b.


Note

High Risk
Reads third-party cookie databases and macOS Keychain secrets, writes session cookies into Electron partitions, and touches profile persistence and partition lifecycle—security- and data-sensitive paths with substantial new surface area.

Overview
Adds cookie import from installed Chromium-family browsers (initially Helium on macOS) into T3 Code desktop browser profiles, wired through new preview IPC, a main-process BrowserImport service, and settings UI.

On the desktop side, the app lists importable sources, blocks import while the source browser holds SingletonLock, reads cookies via SQLite snapshot + macOS Keychain (@napi-rs/keyring, no CLI bypass), decrypts Chromium storage with host-only vs domain-cookie handling, schema 24 domain binding, and skips partitioned (CHIPS) cookies when Electron cannot preserve them. Cookies are written sequentially into the same Electron partition the preview webview uses (resolvePartitionScope). Profile directory names from IPC are validated against listed profiles to block path traversal.

Integrations → Browser profiles gains an Add profile menu with blank profile and Import from entries, a multi-step BrowserImportWizard (quit browser, pick source/target, counts and skipped domains), per-profile actions (set default, clear data, remove), and persistClientSettingsUpdate so new profiles are persisted only after a successful import (with partition cleanup on failed registration). The separate default profile settings row is removed; default is set from the profile menu. Desktop artifacts stage @napi-rs/keyring native binaries like other native addons.

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

@coderabbitai

coderabbitai Bot commented Aug 16, 2026

Copy link
Copy Markdown

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.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: daf12449-bccc-4c49-a6df-572e284b0f18

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

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

@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XXL 1,000+ changed lines (additions + deletions). labels Aug 16, 2026

@macroscopeapp macroscopeapp Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the new BrowserImport service, its Chromium cookie helper, and the IPC/layer wiring against the Effect service conventions.

Service shape, module layout (Context.Service tag + inline interface, make, layer), namespace imports, and layer composition in main.ts all look correct. The findings below are about the error model: the new failure type is unstructured (reason: Schema.String) and every construction discards the underlying cause, including one that erases a structured BrowserSession error.

Posted via Macroscope — Effect Service Conventions

Comment thread apps/desktop/src/preview/BrowserImport/BrowserImport.ts
Comment thread apps/desktop/src/preview/BrowserImport/ChromiumCookies.ts Outdated
Comment thread apps/desktop/src/preview/BrowserImport/BrowserImport.ts Outdated
Comment thread apps/desktop/src/preview/BrowserImport/BrowserImport.ts
Comment thread apps/desktop/src/preview/BrowserImport/BrowserImport.ts Outdated
Comment thread apps/desktop/src/preview/BrowserImport/Sources.ts Outdated
@github-actions

github-actions Bot commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ℹ️ No successful main baseline artifact is available yet. This run establishes the initial measurement.

Provider Metric Main baseline This PR Impact PR ceiling
Codex Total thread wire 13.3 KiB 15.1 KiB
Codex Thread snapshot wire 6.9 KiB 7.3 KiB
Codex Live turn WebSocket wire 6.4 KiB 7.8 KiB
Codex Live turn WebSocket decoded 55.6 KiB 66.4 KiB
Codex Live turn messages 11 21
Claude Total thread wire 13.3 KiB 15.1 KiB
Claude Thread snapshot wire 6.9 KiB 7.3 KiB
Claude Live turn WebSocket wire 6.4 KiB 7.8 KiB
Claude Live turn WebSocket decoded 56.4 KiB 66.4 KiB
Claude Live turn messages 10 21

Baseline: unavailable · PR result: 683ca1b · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 109.4 KiB
  • Claude decoded thread snapshot: 110.1 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

@macroscopeapp macroscopeapp Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UI Consistency

One finding in the changed browser-profiles UI (apps/web/src/components/settings/IntegrationsSettings.tsx).

The menu/primitive usage itself looks consistent with the shared system: Menu/MenuPopup/MenuItem/MenuSub from components/ui/menu, MenuTrigger render={<Button …/>} matching the existing pattern in PreviewMoreMenu/ProjectScriptsControl, existing size="icon-sm" / variant="ghost-muted" Button variants, min-w-* on popups honouring MenuPopup's width-defaulting contract, and the bordered list container matching the convention already used in ConnectionsSettings. aria-labels are preserved on both the rename input and the new row trigger.

The issue is a state-display regression introduced by removing the default-profile Select while filtering Incognito out of the new list: a stored default of incognito (which the removed Select allowed a user to pick) now leaves the section with no "Default" badge on any row.

Posted via Macroscope — UI Consistency

Comment thread apps/web/src/components/settings/IntegrationsSettings.tsx Outdated
@juliusmarminge
juliusmarminge force-pushed the browser-profile-import branch from 757f025 to 5853095 Compare August 16, 2026 22:08
@github-actions github-actions Bot added the 📱 Native Change Changes the native fingerprint; merging blocks production OTAs until a new store build ships. label Aug 16, 2026
Comment thread apps/web/src/components/settings/IntegrationsSettings.tsx
@juliusmarminge
juliusmarminge marked this pull request as ready for review August 16, 2026 22:18
Comment thread apps/desktop/src/preview/BrowserImport/BrowserImport.ts Outdated
Comment thread apps/desktop/src/preview/BrowserImport/ChromiumCookies.ts
@macroscopeapp

macroscopeapp Bot commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR adds a substantial end-to-end browser-cookie import workflow involving Keychain access, native packaging, filesystem/database reads, and persistent Electron session writes. It also changes the browser-profile default settings surface, so the scope and data sensitivity warrant human review.

You can add or adjust custom eligibility rules. Learn more.

@juliusmarminge
juliusmarminge force-pushed the browser-profile-import branch from 5853095 to 23b22b9 Compare August 16, 2026 22:53
@juliusmarminge
juliusmarminge changed the base branch from browser-profiles to shared-sqlite-client August 16, 2026 22:54
Comment thread apps/desktop/src/preview/BrowserImport/ChromiumCookies.ts Outdated
Comment thread apps/web/src/components/settings/IntegrationsSettings.tsx Outdated
Comment thread apps/web/src/components/settings/IntegrationsSettings.tsx

@macroscopeapp macroscopeapp Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the new BrowserImport service, its Sources/ChromiumCookies helpers, the IPC method, and the layer wiring against the Effect service conventions. The service module follows the canonical shape (errors → Context.Service with inline interface → makelayer), dependencies are acquired from the environment, and the failure translations now keep a real cause. One remaining gap on error context.

Posted via Macroscope — Effect Service Conventions

Comment thread apps/desktop/src/preview/BrowserImport/ChromiumCookies.ts

@macroscopeapp macroscopeapp Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UI Consistency — 1 finding

The two issues flagged on earlier commits are addressed: loadSources now clears sources before each refresh, and resolvedDefaultId resolves against the rendered rows.

One consistency gap remains: with BrowserDefaultProfileSetting removed and Incognito no longer rendered as a row, the section can badge Default on a profile that is not the effective default (see inline comment).

Minor (not blocking): lines 507–529 now carry three consecutive doc comments for a single component — the "Create, rename, and remove browser profiles" and "Per-profile cookie import" blocks are leftovers from the removed/renamed pieces and could be folded into one.

Posted via Macroscope — UI Consistency

Comment thread apps/web/src/components/settings/IntegrationsSettings.tsx

@macroscopeapp macroscopeapp Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two findings in the reworked browser-profiles section. Both are about the settings UI now disagreeing with the runtime behaviour it configures, rather than styling.

Posted via Macroscope — UI Consistency

Comment thread apps/web/src/components/settings/IntegrationsSettings.tsx
Comment thread apps/web/src/components/settings/IntegrationsSettings.tsx Outdated
Comment thread apps/desktop/src/preview/BrowserImport/ChromiumCookies.ts Outdated
Comment thread apps/web/src/components/settings/IntegrationsSettings.tsx
@juliusmarminge
juliusmarminge force-pushed the browser-profile-import branch from 57fccc1 to ea2efcb Compare August 16, 2026 23:21
Comment thread apps/web/src/components/settings/IntegrationsSettings.tsx Outdated
@juliusmarminge
juliusmarminge force-pushed the browser-profile-import branch from 3264ff7 to 76fc9d2 Compare August 16, 2026 23:59
@juliusmarminge
juliusmarminge force-pushed the browser-profile-import branch from 81292ec to 9796604 Compare August 29, 2026 07:50
Comment thread apps/web/src/components/settings/IntegrationsSettings.tsx Outdated
Comment thread apps/web/src/components/settings/BrowserImportWizard.tsx
Comment thread apps/web/src/hooks/useSettings.ts Outdated

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is ON, but a cloud agent failed to start.

Reviewed by Cursor Bugbot for commit 3c41bf6. Configure here.

Comment thread apps/web/src/hooks/useSettings.ts

@macroscopeapp macroscopeapp Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One finding: the new selection tile in the import wizard misses the pointer cursor every other clickable surface in the app sets explicitly. Inline comment below.

Posted via Macroscope — UI Consistency

Comment thread apps/web/src/components/settings/BrowserImportWizard.tsx Outdated

@macroscopeapp macroscopeapp Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One finding: Sources.ts reads the host name from the node:os global instead of the shared HostProcessHostname reference the rest of the codebase injects.

Posted via Macroscope — Effect Service Conventions

Comment thread apps/desktop/src/preview/BrowserImport/Sources.ts Outdated

@macroscopeapp macroscopeapp Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One finding on the import wizard's result copy. (A previously flagged item — SelectableTile still missing cursor-pointer — remains open; not re-posted here.)

Posted via Macroscope — UI Consistency

Comment thread apps/web/src/components/settings/BrowserImportWizard.tsx Outdated

@macroscopeapp macroscopeapp Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One finding: the import wizard renders the primary environment's raw catalog label, which reads "Local environment" where every other surface calls the same machine "This device".

Posted via Macroscope — UI Consistency

Comment thread apps/web/src/components/settings/IntegrationsSettings.tsx Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

📱 Native Change Changes the native fingerprint; merging blocks production OTAs until a new store build ships. size:XXL 1,000+ changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant