fix(docker): copy profile to temp dir for cross-platform cookie bridge#150
Conversation
When native auth fails and a portable cookie file exists, copy the browser profile to a temp directory before restarting with imported cookies. This prevents Docker's Linux Chromium from corrupting the macOS profile by writing Linux-encrypted data back to the mounted dir. Also removes the encrypted Cookies DB from the copy since it can't be decrypted cross-platform, and bumps linkedin-scraper-patchright to 3.1.4 which fixes cookie domain normalization and auth-only import.
This stack of pull requests is managed by Graphite. Learn more about stacking. |
There was a problem hiding this comment.
Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.
There was a problem hiding this comment.
Pull request overview
This PR implements a cross-platform cookie bridge to fix authentication issues when running Docker's Linux Chromium with a macOS-generated browser profile. The solution copies the profile to a temporary directory before restarting the browser with imported cookies, preventing the Linux Chromium from corrupting the original macOS profile with Linux-encrypted data.
Changes:
- Updates linkedin-scraper-patchright dependency from 3.1.3 to 3.1.4 (includes cookie domain normalization and auth-only import fixes)
- Implements temp directory profile copying when native auth fails and portable cookies are available
- Removes encrypted Cookies database files from the temp copy before importing portable cookies
Reviewed changes
Copilot reviewed 2 out of 3 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
| uv.lock | Updates linkedin-scraper-patchright dependency lock information to version 3.1.4 |
| pyproject.toml | Bumps linkedin-scraper-patchright minimum version requirement to 3.1.4 |
| linkedin_mcp_server/drivers/browser.py | Implements cross-platform cookie bridge with temp directory profile copying and cookie import logic |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| await browser.start() | ||
|
|
||
| # First nav establishes session cookies (bcookie, JSESSIONID, etc.) | ||
| await browser.page.goto("https://www.linkedin.com/feed/") | ||
| if await is_logged_in(browser.page): | ||
| logger.info("Authentication recovered via portable cookies") | ||
| _apply_browser_settings(browser) | ||
| _browser = browser | ||
| return _browser | ||
| # Import auth cookies (li_at, li_rm) from the portable file | ||
| if await browser.import_cookies(cookie_path): | ||
| await browser.page.goto("https://www.linkedin.com/feed/") |
There was a problem hiding this comment.
The browser.start() call at line 131 could fail (e.g., due to issues with the temp profile), leaving the temporary directory in an inconsistent state. If browser.start() throws an exception, the temp directory will not be cleaned up and the function will propagate the exception without cleanup.
Consider adding try-except around the browser initialization and navigation logic to ensure temp directory cleanup on any failure.
| _browser = browser | ||
| return _browser |
There was a problem hiding this comment.
When the cookie bridge succeeds and the browser is stored in the global _browser variable (line 141), the browser is using a temporary profile directory. However, the close_browser() function at line 151 doesn't know about or clean up this temp directory. When the server shuts down and close_browser() is called, the temp directory will be leaked.
To fix this, consider storing the temp_dir path in a module-level variable when the cookie bridge path is taken, and add cleanup logic in close_browser() to remove it if it exists.
| temp_dir = Path(tempfile.mkdtemp(prefix="linkedin-mcp-")) | ||
| temp_profile = temp_dir / "profile" | ||
| shutil.copytree(user_data_dir, temp_profile) |
There was a problem hiding this comment.
The temporary directory created here is never cleaned up, causing a resource leak. Each time authentication fails and the cookie bridge is attempted, a new temporary directory is created but never removed. This will accumulate over time and consume disk space.
Consider one of these approaches:
- Track the temp_dir path in a module-level variable and clean it up in the close_browser() function
- Use tempfile.TemporaryDirectory() as a context manager (though this requires refactoring the flow)
- Use atexit.register() to ensure cleanup happens on process exit
- Clean up the temp directory when the BrowserManager is closed (if using the temp profile)
| shutil.copytree(user_data_dir, temp_profile) | ||
|
|
||
| # Remove encrypted Cookies DB (can't be decrypted cross-platform) | ||
| (temp_profile / "Default" / "Cookies").unlink(missing_ok=True) | ||
| (temp_profile / "Default" / "Cookies-journal").unlink(missing_ok=True) |
There was a problem hiding this comment.
Missing error handling for file operations that could fail. The shutil.copytree() operation could fail if there are permission issues, disk space constraints, or if the source directory is in use. The unlink() operations have missing_ok=True which is good, but if copytree fails, the browser will remain in an inconsistent state.
Consider wrapping these operations in a try-except block and cleaning up the temp directory if any operation fails before starting the new browser.
| # Auth failed — clean up and fail fast | ||
| await browser.close() |
There was a problem hiding this comment.
If the cookie import or login check fails (lines 136-142), the temporary browser instance is closed at line 145, but the temp directory created at line 115 is never cleaned up. This compounds the resource leak issue - even when authentication fails, the temp directory persists.
#150) When native auth fails and a portable cookie file exists, copy the browser profile to a temp directory before restarting with imported cookies. This prevents Docker's Linux Chromium from corrupting the macOS profile by writing Linux-encrypted data back to the mounted dir. Also removes the encrypted Cookies DB from the copy since it can't be decrypted cross-platform, and bumps linkedin-scraper-patchright to 3.1.4 which fixes cookie domain normalization and auth-only import.
#150) When native auth fails and a portable cookie file exists, copy the browser profile to a temp directory before restarting with imported cookies. This prevents Docker's Linux Chromium from corrupting the macOS profile by writing Linux-encrypted data back to the mounted dir. Also removes the encrypted Cookies DB from the copy since it can't be decrypted cross-platform, and bumps linkedin-scraper-patchright to 3.1.4 which fixes cookie domain normalization and auth-only import.
stickerdaniel#150) When native auth fails and a portable cookie file exists, copy the browser profile to a temp directory before restarting with imported cookies. This prevents Docker's Linux Chromium from corrupting the macOS profile by writing Linux-encrypted data back to the mounted dir. Also removes the encrypted Cookies DB from the copy since it can't be decrypted cross-platform, and bumps linkedin-scraper-patchright to 3.1.4 which fixes cookie domain normalization and auth-only import.

When native auth fails and a portable cookie file exists, copy the
browser profile to a temp directory before restarting with imported
cookies. This prevents Docker's Linux Chromium from corrupting the
macOS profile by writing Linux-encrypted data back to the mounted dir.
Also removes the encrypted Cookies DB from the copy since it can't be
decrypted cross-platform, and bumps linkedin-scraper-patchright to
3.1.4 which fixes cookie domain normalization and auth-only import.