fix: resolve repeated input references and user-file destination collisions - #220
jacksonriding wants to merge 2 commits into
Conversation
b0da3e0 to
85d579f
Compare
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 85d579f543
ℹ️ 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".
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
2a23da9 to
263c24c
Compare
There was a problem hiding this comment.
Reviewed at 263c24c0649131332a2ade94b65a1db6640d0ddd. The core of this is right, and the two ordering decisions I checked hardest both hold up:
- Authorization runs over every reference before coalescing, so a superseded or echoed reference cannot smuggle an unauthorized scope through.
authorizes superseded user refs before selecting a destinationandstill rejects an unauthorized scope on a duplicate objectpin that, and the loop above is untouched. selectedUserFiles.get(file.name) === fileis object identity overuniqueReferences, whose elements are the fresh objectsvalidateRequestedFilesbuilds per input. Exact echoes are already gone by then, so an earlier echo cannot displace a later replacement.kindis validated againstKNOWN_KINDSbefore this point, sofile.kind === 'user'has no undefined-means-user hole, andvalidateFileRefNameforces canonical relative paths, which makes raw string equality onnamea sound proxy for the destination.
One finding, one note.
The workspace input-file cap still counts the repeats this PR removes
handleReplayInitial rejects on the raw request array, at service/src/service/programmatic-router.ts:512:
if (workspaceId != null && Array.isArray(files) && files.length > BRIDGE_WORKSPACE_PROGRAMMATIC_MAX_INPUT_FILES) {
throw new Error(`Selected-workspace execution allows at most ${...} input files; ...`);
}authorizeRequestedFiles does not run until line 591, so for selected-workspace execution the cap is measured before anything is coalesced. BRIDGE_WORKSPACE_PROGRAMMATIC_MAX_INPUT_FILES is 98 (packages/code/src/protocol.ts:26), so a request carrying 99 references that coalesce to, say, 40 distinct destinations is still rejected outright.
That is the same failure this PR sets out to remove, on the path the BYOM coding work depends on, so it seems in scope rather than a follow-up. Counting the cap against the authorized-and-coalesced list would need the cap check to move below line 591, which also changes which error wins when a request is both oversized and unauthorized. If you would rather keep the early rejection, deduplicating the count in place would do:
const distinct = new Set(files.map(f => `${f.storage_session_id}\0${f.id}\0${f.name}`)).size;Either way a regression test at the boundary would be worth having, since nothing currently fails if the two limits drift apart.
Note: handleBlocking has no equivalent cap
The other callsite (line 1631) has no input-file ceiling, and router.ts:246 assigns the coalesced list straight back onto body.files. Both are consistent with this change; recording it only because it means the cap gap above is specific to the replay/workspace path and not a general pattern.
Nothing else in the diff concerns me. With the cap ordering addressed, this looks good to merge.
Repeated input references and different user-file versions at the same destination can reject an entire execution. Authorize every reference, coalesce exact
(storage_session_id, id, name)repeats, then select the last distinct user reference per path in request order. Distinct aliases remain available; skill/agent conflicts retain sandbox validation.Validation: service build passed; 1,047 tests passed, 11 skipped, 0 failed. The new version-selection regression fails on the previous implementation. Existing typecheck diagnostics are unchanged. The squashed commit preserves the tested implementation and tests; subsequent edits only remove README text and shorten comments.