Skip to content

fix: strip developer-identity paths from the cli.Run error envelope (iss-76) - #50

Merged
REPPL merged 2 commits into
mainfrom
fix/iss-76-json-error-abspath-leak
Jul 13, 2026
Merged

fix: strip developer-identity paths from the cli.Run error envelope (iss-76)#50
REPPL merged 2 commits into
mainfrom
fix/iss-76-json-error-abspath-leak

Conversation

@REPPL

@REPPL REPPL commented Jul 12, 2026

Copy link
Copy Markdown
Owner

What

cli.Run renders every command error into the --json envelope and the stderr
line. Identity-bearing local paths reached that surface three ways — an
os.PathError/os.LinkError, a path fmt-formatted into a core error, and a
custom error type — so a verb error could print the developer's home or repo
path. iss-29 fixed one branch (docs-lint config load); this generalises it.

How

New scrubPaths at the Run() boundary:

  • redacts the working-directory (→ .) and home (→ ~) roots wherever they
    appear — catches fmt-formatted and custom-error-type paths a typed walk
    cannot see;
  • reduces any remaining os.PathError/os.LinkError path (e.g. a path argument
    outside both roots) to its base name.

A regex scrub was deliberately avoided: this error surface also carries URLs
(fetch failures) that an absolute-path regex would mangle.

Detectors (watched fail → pass)

  • TestJSONErrorEnvelopeNoAbsolutePathLeakmemory ask --page-json on a
    missing absolute path (PathError).
  • TestCaptureSymlinkErrorNoPathLeak — real capture --json against a symlinked
    issues/open (the fmt-embedded ledger-path guard).
  • TestScrubPaths — unit table: PathError / LinkError / wrapped / joined /
    relative / non-path, plus the capture (cwd) and history (home) classes.

Review

Correctness review: PROMOTE. Security review: initial HOLD reproduced two live
leaks (capture symlink, history store path) — both now closed and re-verified.
The re-review confirmed the identity invariant holds and raised a narrower,
non-identity residual (a verb echoing a user-supplied absolute path outside
cwd/home; and the capture success-envelope path field). Resolved via the
review's option 2 — scope the claim honestly — and filed the residual as
iss-81 rather than widening this change (which would have overlapped iss-79).

Scope

internal/surface/cli/cli.go + one test file + CHANGELOG + ledger (resolves
iss-76, files iss-81). Full make preflight green (build, vet, gofmt, tests,
-race).

Part of drain #2. Chain: branched from main; independent of iss-79/iss-73.

Assisted-by: Claude:claude-opus-4-8

REPPL added 2 commits July 12, 2026 22:42
cli.Run routes every command error through the --json envelope (and the
stderr text line), so absolute local paths reached machine output three ways:
an *os.PathError/*os.LinkError embeds one in Error(); core fmt-formats one via
%s (e.g. capture's ledger-path guards); a custom error type renders one (e.g.
history's home-rooted StorePathError). A typed walk over the two os error
types -- the first cut -- missed the latter two, which a security review
reproduced as live leaks on the same surface.

scrubPaths now redacts the two identity-bearing roots (working directory ->
'.', home -> '~') wherever they appear, then reduces any remaining absolute
PathError/LinkError path to its base name (covering a path argument outside
both roots). Generalises the per-branch fix iss-29 made for docs-lint config.

Detectors watched fail then pass: per-verb --json envelope tables for
'memory ask --page-json' (PathError) and 'capture' on a symlinked issues/open
(fmt-embedded), plus a scrubPaths unit table covering PathError/LinkError/
wrapped/joined/relative/non-path and the capture (cwd) and history (home)
classes.

Scope is the developer-identity portion (cwd/home + PathError/LinkError), not
a universal absolute-path scrub -- a verb echoing a user-supplied absolute
path outside both roots (e.g. 'memory ingest /tmp/x') carries no identity and
is tracked in iss-81, along with the capture success-envelope 'path' field.
A regex scrub is deliberately avoided: this surface also carries URLs a path
regex would mangle. Security review (HOLD -> resolved via its option 2).

Assisted-by: Claude:claude-opus-4-8
iss-76's cli.Run boundary fix lands in this branch. The security re-review
surfaced a narrower, non-identity residual (verb-level echo of a user-supplied
absolute path outside cwd/home; plus the capture success-envelope path field)
-- captured as iss-81 rather than widening iss-76.

Assisted-by: Claude:claude-opus-4-8
@REPPL
REPPL merged commit b604c62 into main Jul 13, 2026
12 checks passed
@REPPL
REPPL deleted the fix/iss-76-json-error-abspath-leak branch July 13, 2026 06:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant