feat(tracking): honour tracking.enabled and redact sensitive args#1987
Open
YOMXXX wants to merge 1 commit into
Open
feat(tracking): honour tracking.enabled and redact sensitive args#1987YOMXXX wants to merge 1 commit into
YOMXXX wants to merge 1 commit into
Conversation
Two RTK security findings (rtk-ai#1875 Findings 2 + 3) share the same call site in Tracker::record: 1. tracking.enabled = false was parsed but never enforced — the field was dead code. Now Tracker::record and Tracker::record_parse_failure return Ok(()) silently when the flag is false. A new RTK_TRACK=0 env var provides an additional one-shot opt-out (matches existing RTK_TEE=0 / RTK_DB_PATH). 2. original_cmd and project_path were stored verbatim, capturing inline tokens, URL userinfo, and private filesystem layout. The new src/core/redact.rs module (shared with the upcoming tee redaction PR) scrubs known credential shapes via a lazy_static regex bundle, and project paths are stored as <basename>#<8-hex-sha256> by default (gated by tracking.hash_project_paths, default true). A one-shot migration runs on Tracker::new() and rewrites rows from the last 90 days. Existing rtk gain output stays semantically identical because aggregation reads input_tokens/output_tokens, not the command string. Also exposes RTK_CONFIG_PATH for tests / containers that need to point Config::load() at a deterministic file without mutating HOME, mirroring the existing RTK_DB_PATH override. Refs rtk-ai#1875 (Findings 2, 3)
5 tasks
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.
Summary
This is the second of three security PRs landing the RTK security &
privacy remediation design.
It closes Findings 2 + 3, which share the same call site
(
Tracker::recordinsrc/core/tracking.rs:402-437).now scrubbed before INSERT via a new
src/core/redact.rsmodule(shared with the upcoming tee redaction PR). Project paths default to
<basename>#<8-hex-sha256>, gated by a newtracking.hash_project_pathsfield (defaulttrue, forward-compatvia
#[serde(default)]).tracking.enabledis dead code):Tracker::recordandTracker::record_parse_failurenow early-returnOk(())when the flag isfalse. A newRTK_TRACK=0env var mirrorsthe existing
RTK_TEE=0one-shot opt-out.A one-shot migration runs on
Tracker::new()to rewrite rows from thelast 90 days. It is gated by
PRAGMA user_versionso it runs once perbinary version.
Reproduction
Finding 2
Finding 3
Root cause
Finding 2
Tracker::recordboundoriginal_cmdandcurrent_project_path_string()straight into a SQLite
INSERT. The DB is reached from 200+ call sitesvia
TimedExecution::start(), so the fix had to live insideTracker::recorditself, not at the call sites.Finding 3
grep -rn tracking\.enabled src/showed zero matches outsideconfig.rs.The field was parsed, defaulted to
true, and never read. BothTracker::new()andTracker::record(…)proceeded unconditionally.Fix approach
src/core/redact.rs(pub(crate)) — single-pass, lazy_staticregex bundle:
https://user:pass@host→https://****:****@host)Authorization: Bearer …/Basic …/Token …--token=…,--password …,--api-key=…,--secret …,--auth=…,--access-token …,--refresh-token …(
AWS_SECRET_ACCESS_KEY,GH_TOKEN,OPENAI_API_KEY, …)ghp_,gho_,sk-,sk_live_,xoxb-,AKIA,ASIA,glpat-, …)redact_project_pathreturns<basename>#<8-hex-sha256>;empty paths stay empty so the existing
project_path != ''filterin
projects_count()keeps working; already-hashed paths passthrough unchanged (idempotent).
Tracker::recordandTracker::record_parse_failureon ashared
tracking_enabled()helper.RTK_TRACK=0short-circuitswithout touching disk; otherwise
Config::load()decides; onmissing/corrupt config we fall open (
unwrap_or(true)).Tracker::new()— reads rows newer than90 days, redacts in-Rust,
UPDATEs by id, bumpsPRAGMA user_versionfrom 0/1 to 2. Errors are logged to stderr butnever block tracker creation (
rtk gainkeeps working onhalf-broken DBs).
TrackingConfig::hash_project_paths(defaulttrue,#[serde(default = "default_true")]) so configs predating this PRstill parse.
RTK_CONFIG_PATHoverride added toConfig::get_config_path().This is a pure test/CI/container convenience that mirrors the
existing
RTK_DB_PATHpattern — required becausedirs::config_dir()resolves via
$HOME/Library/Application Supporton macOS, and ourgating tests cannot safely mutate
HOMEwhile other parallel testsare calling
Tracker::new().Behavior changes
--token=ghp_abcbecomes--token=****. Ecosystem aggregation (top_commands,categorize_command,top_passthrough) only looks at the firstwhitespace-delimited token, so headline
rtk gainoutput isunchanged.
--by-projectfilters by hash now. Same semantics (one row perproject), shorter DB row.
tracking.enabled = falseis now honoured. No-op INSERT; readsare still allowed so
rtk gainkeeps showing past stats.RTK_TRACK=0one-shot env opt-out.RTK_CONFIG_PATHexplicit config override.No DB schema change, no public Rust API change, no CLI flag removal.
Test plan
cargo fmt --all— cleancargo clippy --all-targets -- -D warnings— cleancargo test --bin rtk -- --test-threads=8— 1920 passed, 0 failed, 6 ignoredsrc/core/redact.rs: 6 (URL userinfo, Bearer, flag-value, inline env,credential heuristic, idempotent).
src/core/tracking.rs: 8 Finding 2 tests + 5 Finding 3 tests, allserialised via a per-module
TRACKING_ENV_LOCKmutex.PRAGMA user_version = 0, runs the migration, verifies token /user / password gone and second-run is a no-op.
target/release/rtk --versionruns in<10ms on warm cache (rtk itself),
rtk gh --version~50ms (dominatedby
ghstartup, not rtk overhead).Refs
docs/superpowers/specs/2026-05-20-rtk-security-privacy-design.md(local only — not pushed)src/core/redact.rsfor tee-file content scrubbing.