feat(#3996): gate workspace-escaping generated-media paths behind user confirmation - #4026
Draft
aheritier wants to merge 1 commit into
Draft
feat(#3996): gate workspace-escaping generated-media paths behind user confirmation#4026aheritier wants to merge 1 commit into
aheritier wants to merge 1 commit into
Conversation
…r confirmation A prompt-directed save target that is absolute, traverses above the workspace via "..", or is "~"-rooted is now refused by default and raised as a runtime-native elicitation (same waiter registry and ResumeElicitation plumbing as MCP elicitations, so every existing embedder surface can answer it). Confirmation is a schema-backed form (MediaEscapeDecisionSchema) whose safe "keep it in the workspace" choice is listed first and therefore the default selection: a bare Enter/submit never authorizes the write, and the runtime independently verifies the submitted value so a permissive client accepting with empty or free-form content cannot either. On an explicit affirmative choice the bytes are written to the confirmed external target with the same O_EXCL/dash-suffix/atomic mechanics as workspace writes, persisted as ArtifactRootExternal with the confirmed absolute path, and manifest-gated like any workspace file. A target that resolves to an existing directory means "save inside it": the generated filename (MIME-corrected extension included) is appended before the user confirms, so the confirmed path is always the exact file written; a directory appearing at the confirmed path after confirmation is rejected outright rather than dash-suffixed into an unconfirmed sibling. On decline/cancel or non-interactive/headless surfaces the bytes are redirected to the workspace root under the sanitized basename with a sanitized warning - already-generated bytes are never discarded, and no requested path, raw error, or reference internals leak into warnings. The non-JSON CLI declines the form (it has no form UI) but keeps draining the event stream, so the redirect warning and the assistant response still arrive and the turn persists. chat.MediaDelta.RequestedPath plus workspacemedia.ClassifyRequestedPath are the internal hooks for the upcoming response-marker extraction; no marker parsing ships in this slice, and provider display names keep the existing generic-name fallback.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Requires user confirmation before generated-media paths escape the workspace, including classification, CLI/runtime flow, session manifests, and TUI schema coverage.
Why
Prevents generated files from silently writing outside the configured workspace.
Validation
task test; workspace-media, runtime escape, CLI, session, and TUI tests.Test instructions
Run:
task testRequest generated-media output whose destination is outside the configured workspace. Expected: the operation asks for confirmation; approving writes to the requested destination, while denying it performs no outside-workspace write and reports the denial safely.