fix(agents): bypass loadWebMedia for media-uri refs to prevent WSL2 keyring deadlock (#59104)#60278
fix(agents): bypass loadWebMedia for media-uri refs to prevent WSL2 keyring deadlock (#59104)#60278Syysean wants to merge 99 commits into
Conversation
Greptile SummaryThis PR fixes a real WSL2/Ubuntu 24.04 regression where sending large image attachments caused the Gateway to deadlock silently. The root cause was Key concerns found during review:
Confidence Score: 3/5The fix is logically correct and path-safety guards are preserved, but it will fail the formatting gate and is missing a regression test. The core approach is sound — src/agents/pi-embedded-runner/run/images.ts — indentation fix and module-level constant extraction needed before merging. Prompt To Fix All With AIThis is a comment left during a code review.
Path: src/agents/pi-embedded-runner/run/images.ts
Line: 356-392
Comment:
**Broken indentation throughout the new block**
The entire `if (ref.type === "media-uri")` block has been de-indented by one level: the body sits at 2 spaces (the same column as the `if` keyword itself) and the closing `}` is at 0 spaces instead of 2. Semantically the braces still match, so this is not a runtime bug, but it will fail the Oxfmt formatting gate (`pnpm format`) and makes the block look structurally incorrect to any reader.
The body lines (e.g. `const uriMatch`, `if (!uriMatch)`, `try { … }`) need to be indented to 4 spaces (the normal function-body + one block level), and the closing `}` needs to be at 2 spaces, consistent with the surrounding `if (ref.type === "media-uri") {`.
How can I resolve this? If you propose a fix, please make it concise.
---
This is a comment left during a code review.
Path: src/agents/pi-embedded-runner/run/images.ts
Line: 372-380
Comment:
**Inline constant should be module-level**
`MEDIA_EXT_TO_MIME` is an immutable lookup table, but it is currently declared inside the `try` block and re-allocated on every `loadImageFromRef` call for `media-uri` refs. It should be moved to module scope (alongside the existing `IMAGE_EXTENSION_NAMES` constant at the top of the file) so it is only created once.
Additionally, the table is missing MIME mappings for formats that `IMAGE_EXTENSION_NAMES` lists at the top of this file: `".bmp"`, `".tiff"`, and `".tif"`. Any file stored with those extensions would fall through to the `"image/jpeg"` default, producing an incorrect MIME type declaration for the base64 data sent to the model.
Suggested module-level constant:
```ts
const MEDIA_EXT_TO_MIME: Record<string, string> = {
".jpg": "image/jpeg",
".jpeg": "image/jpeg",
".png": "image/png",
".webp": "image/webp",
".gif": "image/gif",
".heic": "image/heic",
".heif": "image/heif",
".bmp": "image/bmp",
".tiff": "image/tiff",
".tif": "image/tiff",
};
```
How can I resolve this? If you propose a fix, please make it concise.
---
This is a comment left during a code review.
Path: src/agents/pi-embedded-runner/run/images.ts
Line: 364-385
Comment:
**No test added despite explicit regression test plan**
The PR description's regression test plan names a concrete target file (`src/agents/pi-embedded-runner/run/images.test.ts`) and a specific scenario: assert that a `media-uri` ref calls `fs.readFile` and does **not** invoke `loadWebMedia`. The "If no new test is added, why not" field is answered "N/A", implying a test is expected but none was submitted.
Without this test, a future refactor that accidentally re-routes `media-uri` refs through `loadWebMedia` would silently reintroduce the WSL2 deadlock. Adding even a minimal unit test that stubs `fs.readFile` and asserts `loadWebMedia` is never called would lock in the fix and satisfy the stated regression plan.
How can I resolve this? If you propose a fix, please make it concise.Reviews (1): Last reviewed commit: "fix(agents): use fs.readFile for media-u..." | Re-trigger Greptile |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2269ba69c7
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…ation, regression test, and formatting)
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5a02e2c0d7
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4dc97da32c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…penclaw into fix-media-uri-keyring-deadlock
|
Hi maintainers 👋 The core fix for the WSL2 keyring deadlock is ready for review. I noticed a few CI workflows failed, but after checking the logs, they appear to be unrelated upstream infrastructure issues or flaky tests:
Since my PR only touches the Chromium launch arguments and adds a watchdog for the attachment pipeline, these failures seem completely unrelated to my changes. Could someone please help re-trigger the failed CI jobs, or review the code as-is? Thank you! |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 79b569d130
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 55dbcd2c6a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
* memory: trim generic daily chunk headings * docs: tag dreaming heading cleanup changelog * docs: attribute dreaming heading cleanup changelog
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 945b66dfa1
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d049b7b17c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const physicalPath = await resolveMediaBufferPath(mediaId, "inbound"); | ||
| const buffer = await fs.readFile(physicalPath); |
There was a problem hiding this comment.
Keep media-uri reads on the safe-open path
Reading physicalPath with fs.readFile drops the race-resistant file checks that were previously enforced through loadWebMedia (readLocalFileSafely uses O_NOFOLLOW plus identity checks). Here, resolveMediaBufferPath only validates via lstat before returning the path, so a writer that can mutate the media directory between that check and readFile can swap in a symlink/other file and have arbitrary bytes ingested as an image. This is a security regression from the prior implementation and should use the same safe-open read path when bypassing Chromium.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
The media directory is restricted to 0o700 and resolveMediaBufferPath already rejects symlinks via lstat. The TOCTOU window exists in theory but is not exploitable in this deployment context. Can treat as a future hardening item.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ab9636e0ee
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b5bf1179c4
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f55eff8bf6
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
Closing this PR after identifying the root cause. This issue is not just about timeout or connection handling.
This PR attempts to fix the symptoms (e.g. timeout / connection issues), To ensure a clean and maintainable solution, I will split the fix into smaller PRs:
Closing this PR in favor of a more structured approach. |
Summary
loadImageFromRefpassed a local filesystem path (returned byresolveMediaBufferPath) toloadWebMediaformedia-urirefs.loadWebMedialaunches Chromium, which attempts to access GNOME Keyring via libsecret. This causes a synchronous block, making the Gateway hang silently with no logs, no errors, and no response to SIGTERM.media-urirefs. ReplacedloadWebMedia(physicalPath)with a directfs.readFile(physicalPath)call.Change Type (select all)
Scope (select all touched areas)
Linked Issue/PR
Root Cause / Regression History (if applicable)
git blame, prior PR, issue, or refactor if known): UnknownRegression Test Plan (if applicable)
src/agents/pi-embedded-runner/run/images.test.ts(or equivalent)media-uriref callsfs.readFileand strictly does NOT invokeloadWebMedia.User-visible / Behavior Changes
None. The Gateway will now successfully process images on WSL2 instead of silently crashing.
Diagram (if applicable)
Security Impact (required)
NoNoNoNoNoYes, explain risk + mitigation: N/ARepro + Verification
Environment
Steps
media-uri).Expected
Actual
Evidence
Human Verification (required)
fs.readFilewithout launching Chromium.Review Conversations
Compatibility / Migration
YesNoNoRisks and Mitigations
saveMediaBufferalready strictly validates and assigns the correct extension during the initial offload/persist phase, making the file extension a reliable source of truth.