Summary
The content digest buffers a whole git diff --binary patch in memory before hashing it. A repository containing a large changed binary can therefore exhaust the workbench process during setup inspection, before any review begins.
Correction to an earlier version of this issue: I first wrote that both content-digest functions do this. On main there is only one git diff --binary call site, in worktree_content_digest_for_context. A committed base..head equivalent exists only in the unmerged PR #241, so if that lands it should adopt the same streaming helper.
Environment
@openai/codex-security 0.1.5, current main at ea19f24
- macOS 15 (Darwin 25.5.0), Python 3.14.5
Where it is
sdk/typescript/_bundled_plugin/scripts/workbench_target.py — worktree_content_digest_for_context obtains the tracked diff through git_bytes, which is subprocess.run(..., capture_output=True), so completed.stdout holds the entire patch. The digest is then computed from that single value.
Binary patches are larger than the underlying files: measured on a 20 MiB incompressible file, git diff --binary produced a 27 MB patch, about 1.29x.
Measured peak RSS in the Python process on that fixture: 145.8 MiB, against a 25.2 MiB floor for a clean worktree. Git's own peak was 165.6 MiB, which is inherent to producing the patch and not affected by this issue.
This runs on every setup inspection, so it is not confined to scan registration.
Why this is not a one-line change
update_digest_field frames each value with an 8-byte big-endian length prefix, so the total byte count must be known before any content is hashed. Streaming therefore needs either a second full git diff pass to learn the length — non-atomic, and double the work — or spooling the patch to a temporary file and hashing from it.
Whichever shape is chosen, the resulting digest must stay byte-identical to today's, because recorded digests are compared against freshly computed ones when a saved selection is revalidated.
Suggested direction
Add a streaming helper next to git_bytes that spools stdout to a temporary file, then feeds the framed length and the file contents into the digest. Apply it to both digest functions rather than only one, since the working-tree path dominates. A fixture asserting old and new produce the same digest for the same input would pin the compatibility requirement.
Summary
The content digest buffers a whole
git diff --binarypatch in memory before hashing it. A repository containing a large changed binary can therefore exhaust the workbench process during setup inspection, before any review begins.Correction to an earlier version of this issue: I first wrote that both content-digest functions do this. On
mainthere is only onegit diff --binarycall site, inworktree_content_digest_for_context. A committed base..head equivalent exists only in the unmerged PR #241, so if that lands it should adopt the same streaming helper.Environment
@openai/codex-security0.1.5, currentmainatea19f24Where it is
sdk/typescript/_bundled_plugin/scripts/workbench_target.py—worktree_content_digest_for_contextobtains the tracked diff throughgit_bytes, which issubprocess.run(..., capture_output=True), socompleted.stdoutholds the entire patch. The digest is then computed from that single value.Binary patches are larger than the underlying files: measured on a 20 MiB incompressible file,
git diff --binaryproduced a 27 MB patch, about 1.29x.Measured peak RSS in the Python process on that fixture: 145.8 MiB, against a 25.2 MiB floor for a clean worktree. Git's own peak was 165.6 MiB, which is inherent to producing the patch and not affected by this issue.
This runs on every setup inspection, so it is not confined to scan registration.
Why this is not a one-line change
update_digest_fieldframes each value with an 8-byte big-endian length prefix, so the total byte count must be known before any content is hashed. Streaming therefore needs either a second fullgit diffpass to learn the length — non-atomic, and double the work — or spooling the patch to a temporary file and hashing from it.Whichever shape is chosen, the resulting digest must stay byte-identical to today's, because recorded digests are compared against freshly computed ones when a saved selection is revalidated.
Suggested direction
Add a streaming helper next to
git_bytesthat spools stdout to a temporary file, then feeds the framed length and the file contents into the digest. Apply it to both digest functions rather than only one, since the working-tree path dominates. A fixture asserting old and new produce the same digest for the same input would pin the compatibility requirement.