Skip to content

feat(#3996): gate workspace-escaping generated-media paths behind user confirmation - #4026

Draft
aheritier wants to merge 1 commit into
workspace-media-materializationfrom
workspace-media-escape-confirm
Draft

feat(#3996): gate workspace-escaping generated-media paths behind user confirmation#4026
aheritier wants to merge 1 commit into
workspace-media-materializationfrom
workspace-media-escape-confirm

Conversation

@aheritier

@aheritier aheritier commented Aug 22, 2026

Copy link
Copy Markdown
Collaborator

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 test

Request 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.

…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.
@aheritier aheritier added area/cli CLI commands, flags, output formatting area/runtime Runtime engine, agent loop execution, tool dispatch, loop detection area/sessions For features/issues/fixes related to session lifecycle (resume, persistence, export) area/tui For features/issues/fixes related to the TUI kind/feat PR adds a new feature (maps to feat:). Use on PRs only. labels Aug 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/cli CLI commands, flags, output formatting area/runtime Runtime engine, agent loop execution, tool dispatch, loop detection area/sessions For features/issues/fixes related to session lifecycle (resume, persistence, export) area/tui For features/issues/fixes related to the TUI kind/feat PR adds a new feature (maps to feat:). Use on PRs only.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant