Keep PII out of default-level WTA logs#261
Conversation
There was a problem hiding this comment.
Pull request overview
This PR adjusts WTA delegate logging in tools/wta to avoid emitting the current working directory (cwd) at default log levels, moving that path to the existing trace-gated delegate.content channel to reduce PII exposure in shipped (info) logs.
Changes:
- In
run_delegate, removecwdfrom theinfo!log and include it only in thedelegate.contenttrace!log. - In
delegate_with_context, removecwdfrom thedebug!log (leavingcwdonly in thedelegate.contenttrace!log alongside the command line).
| // Log the prompt length, not the text — the prompt is user content. `cwd` | ||
| // is a filesystem path (carries the username / folder names), so it is | ||
| // personal data too: keep it on the trace-only content channel. | ||
| tracing::info!(prompt_chars = prompt.map(|p| p.chars().count()), agent = agent_cmd, "run_delegate started"); | ||
| tracing::trace!(target: "delegate.content", prompt = ?prompt, cwd, "run_delegate prompt"); |
There was a problem hiding this comment.
Good catch — you're right, the delegate logs were not the only default-level cwd leak. Rather than narrow the claim, I followed the second option and gated all of them in fef9dfa:
acp_load_session(the two you pointed at, ~2570/2578) plus the inboundload_sessionhandler at ~5422agents_viewdispatch_resume/dispatch_resume_in_agent_pane(warn + info, app.rs)masternew_session(mod.rs)
Each default-level line now logs has_cwd (bool) instead of the path; the full cwd moved to a sibling trace! on the matching *.content target. The two remaining cwd-in-log sites (coordinator_log, acp_log_built_prompt) are debug! level — dev-only, never the shipped info default — so left as-is. PR description updated.
run_delegate logged cwd at info! level. cwd is a filesystem path carrying the Windows username and folder names, so it is personal data, yet info is the shipped release default. Move cwd onto the existing trace-only delegate.content channel so nothing personal lands in wta-delegate.log at the default filter; the info line keeps only prompt_chars and the agent command name. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
27e904d to
9fa16d7
Compare
Addresses Copilot review on PR #261: the delegate path was not the only default-level cwd leak. run_delegate's acp_load_session, app.rs dispatch_resume / dispatch_resume_in_agent_pane (agents_view) and the inbound load_session handler, plus master's new_session, all emitted the full cwd path at info!/warn! — which the shipped info filter writes. Each default-level line now logs has_cwd (a bool) instead of the path; the full cwd moves to a sibling trace! on the matching *.content target (delegate.content / acp_load_session.content / agents_view.content / master.content), consistent with the repo convention that user/agent content only lands at trace. debug!-level cwd logs (coordinator_log, acp_log_built_prompt) are left as-is since debug is dev-only and never the shipped default. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Full sweep of info/warn/error logs for personal data (the previous commits only covered cwd). Three classes addressed: Tier 1 (user content / arbitrary files): master forwards fs/read|write_text_file and the on-disk session title at info!. The agent-controlled file path and the title (often derived from the user's prompt) now log only length/op at info; the full value moves to the trace-only master.content / session_hook.content channel. Tier 2 (fixed tool/runtime paths whose only PII is the Windows username): hooks-installer config/plugin/marketplace/bundle paths, the master-pipe discovery file, and the agent-pane origin record. New crate::logging::redact_user_path() rewrites the %LOCALAPPDATA%/%APPDATA%/%USERPROFILE% prefix to a placeholder, so these stay debuggable at info/warn without leaking the username. Tier 3 (captured subprocess output): the plugin-CLI stdout/stderr/args move to the agent_hooks.content trace; only exe + exit status stay at default. wtcli stdout/stderr were reviewed and left as-is (tool diagnostics: pane GUIDs / protocol errors, no user content). Out of scope: debug!-level logs (dev-only) and Tier 4 agent command lines (user-configured, not runtime PII). cargo build + logging unit tests pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
90d04ee to
ef54b3d
Compare
| if let Some(prefix) = std::env::var_os(var) { | ||
| let prefix = prefix.to_string_lossy(); | ||
| if prefix.is_empty() { | ||
| continue; | ||
| } | ||
| // `get(..len)` is None when `len` is not a char boundary, so this | ||
| // never panics on a non-ASCII username. | ||
| if let Some(head) = s.get(..prefix.len()) { | ||
| if head.eq_ignore_ascii_case(&prefix) { | ||
| return format!("{placeholder}{}", &s[prefix.len()..]); | ||
| } | ||
| } | ||
| } |
What
Audit and fix of WTA logs that emitted personal data at default log levels (
info!/warn!/error!). The shipped release default filter isinfo(tools/wta/src/logging.rs), so anything at info+ lands in users' on-disk logs out of the box.The repo convention is that user/agent content is logged only at
trace!(off by default), via*.contenttargets. This PR brings the stragglers in line.Findings & fixes
cwd (initial scope).
run_delegate,acp_load_session(boot-time + inbound),agents_viewresume dispatch, andmasternew_sessionlogged the full working directory at info/warn. Each default line now logshas_cwd/ length; the full path moves to the matching*.contenttrace!.Tier 1 — user content / arbitrary files.
masterforwardsfs/read_text_file/fs/write_text_file(the file the agent reads/writes) and the on-disk session title (often derived from the user's prompt) atinfo!. Default line now logslength+ op only; full path / title move tomaster.content/session_hook.contenttrace!.Tier 2 — fixed tool/runtime paths whose only PII is the Windows username. Hooks-installer config/plugin/marketplace/bundle paths, the master-pipe discovery file, and the agent-pane origin record. New
crate::logging::redact_user_path()rewrites the%LOCALAPPDATA%/%APPDATA%/%USERPROFILE%prefix to a placeholder, so these stay debuggable at info/warn without leaking the username.Tier 3 — captured subprocess output. Plugin-CLI
stdout/stderr/argsmove to theagent_hooks.contenttrace!; onlyexe+ exit status stay at default. (wtclistdout/stderr reviewed and left as-is — tool diagnostics: pane GUIDs / protocol errors, no user content.)Out of scope
debug!-level logs — dev-only, never the shippedinfodefault (e.g.coordinator_log,acp_log_built_prompt,delegate_with_context).app.rs,client.rs,master) — these are the user-configured agent invocation, not runtime user data.err/errorDisplay fields — diagnostic and essential; not reliably PII.Verification
cargo buildpasses (no new warnings). Newredact_user_pathunit tests + existing logging tests green. No behavior change atWTA_LOG=trace.Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com