Skip to content

Robustness: home-prefix path collapse over-matches sibling directories — make redactHomePath boundary-safe across all seven sites #844

Description

@qwen-code-dev-bot

sourceType

source:self-discovery — undirected maintainer review pass over the repository itself (no diff trigger).

sourceLinkOrEvidence

Concrete evidence in the current tree (main @ 587fb20):

The home-directory collapse used across every redacted display surface tests p.startsWith(home) with no path-boundary check, so a sibling directory whose name merely begins with the home string is misread as being under the home directory:

  • src/permission-impact.ts:248-253 — the shared redactHomePath:
    export function redactHomePath(p: string): string {
      const home = process.env.HOME ?? process.env.USERPROFILE;
      if (home && p.startsWith(home)) {
        return "~" + p.slice(home.length);
      }
      return p;
    }
  • Six local copies repeat the identical boundary-less pattern:
    • src/session-summary.ts:482 (redactPath, then redactSecrets)
    • src/session-search.ts:218 (redactWorkspacePath, then redactSecrets)
    • src/sandbox-diag.ts:75 (redactPath)
    • src/health-inventory.ts:424 (redactPath)
    • src/doctor.ts:266 (redactPath)
    • src/readline-store-warnings.ts:15 (redactStorePath, injectable home)

Minimal reproduction: with HOME=/home/alice, the path /home/alice2/proj satisfies "/home/alice2/proj".startsWith("/home/alice"), so it renders as ~2/proj — i.e. the listing claims the session lives under the user's home when it actually lives in a sibling directory. HOME=/root + /rootfs/x~fs/x is the same defect.

redactHomePath is imported by 35+ modules (attention-summary, sessions-overview, evidence-archive, provider-invocation, session-inspect, session-picker, tui-shell, …), so every surface that prints a workspace/config path inherits the over-match.

problemStatement

The ~ collapse is meant to hide the current user's home prefix. Because the match is a bare startsWith(home) with no separator/end boundary, a path that is a sibling of the home directory (shares the home string as a strict prefix but is not inside it) is also collapsed, producing a misleading ~… path that misrepresents where the session/workspace/config actually lives. This affects the session list, attention summary, doctor, health inventory, session search, sandbox diagnostics, and readline store warnings — every redacted path display.

userValue

--list-sessions, --attention, --doctor, --health-inventory, --search-sessions, and the store/sandbox diagnostics show a truthful location: paths under the home collapse to ~, sibling directories are shown as the (secret-redacted) paths they really are, so a user can correctly tell which repository/workspace a session belongs to.

scope

  • Make redactHomePath (src/permission-impact.ts) boundary-safe: collapse only when p === home or p starts with home followed by a path separator (use the platform separator, e.g. node:path sep).
  • Make the six local copies boundary-safe as well (session-summary.ts, session-search.ts, sandbox-diag.ts, health-inventory.ts, doctor.ts, readline-store-warnings.ts). Prefer routing them through the shared redactHomePath where the surrounding redactSecrets wrap allows; otherwise apply the same boundary check in place.
  • Add regression tests for the boundary behavior (see testPlan).

nonGoals

acceptanceCriteria

  1. A sibling path (strict-prefix match without a following separator) is not collapsed: redactHomePath("/home/alice2/proj") with HOME=/home/alice returns /home/alice2/proj (and sites that wrap redactSecrets still secret-redact it).
  2. A path under the home is collapsed: redactHomePath("/home/alice/proj")~/proj; redactHomePath("/home/alice")~.
  3. All seven sites (shared helper + six local copies) are boundary-safe; no sibling over-match remains.
  4. Inputs unaffected by the boundary (under-home, outside-home non-sibling) behave as before.
  5. Focused regression tests cover sibling / under-home / home-alone; all existing tests pass.

testPlan

  • Unit tests against the exported redactHomePath in tests/unit/permission-impact.test.ts (currently zero tests reference it): sibling not collapsed, under-home collapsed, home-alone → ~, and a HOME with a trailing separator if the implementation normalizes one.
  • Cover at least one local copy through its exported surface (e.g. readline-store-warnings.ts's redactStorePath, which already accepts an injectable home) to prove the boundary holds there too.
  • Gate: npm run typecheck, npm run build, npm test.

dogfoodPlan

Post-merge, run the permission-impact unit suite plus npm run smoke, and run --list-sessions / --attention against a real store to confirm under-home workspace paths still render with ~ and no surface regresses.

riskAndSecurityNotes

  • Display-only; the collapse becomes strictly more conservative. A sibling path that was wrongly collapsed to a misleading ~… now renders its secret-redacted real path — this is more correct and does not leak the current user's home (the sibling is, by definition, outside it).
  • redactSecrets still runs wherever a site wraps it, so no secret surface is widened.
  • Behavior for paths genuinely under the home is unchanged (~ collapse preserved), so the privacy intent of the helper is intact.
  • Low risk: pure string-boundary change in display helpers; no I/O, trust, or mutation path touched.

duplicateSearchEvidence

Searched open + closed Issues and PRs for home-path / redactHomePath / tilde / sibling / boundary:

parentChildRelationship

Standalone leaf Issue. Independent of any parent; not part of the surrogate/truncation series or the secret-redaction line (#805).

dependencyOrder

No blocking dependencies; executable immediately (redactHomePath already exists and is exported). Single vertical slice: one boundary fix applied across the shared helper and six copies, plus focused regression tests.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    agent-readyTrusted issue ready for autonomous implementationenhancementNew feature or requestpriority:p3Low priority: address when capacity allowssource:self-discoveryNormalized execution work from reproducible product dogfood

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions