Review Linear Issues and Security Fixes · Entire
Verdict
1. Are they duplicates? — Yes.
ENCLI-270 and ENCLI-271 are the same report:
| ENCLI-270 | ENCLI-271 | |
|---|---|---|
| GitHub source | issue #1757 | issue #1759 |
| Created | 2026-07-15 05:52 | 2026-07-15 05:57 |
| Status | Canceled (05:57:54) | Triage (label: Bug) |
| Title/body | Identical (270 has slightly richer markdown formatting) | Same content, plain-text |
Same reporter, same repro, same root-cause analysis, filed 5 minutes apart. ENCLI-270 was cancelled essentially at the moment 271 was created — the team already de-duped by keeping 271 (the cleaner one, with the Bug label). No further action needed on the duplicate question; 271 is the live copy.
2. Is the underlying bug real? — Yes, confirmed in code.
The reporter's root-cause analysis is accurate. There are three code paths that decide what's excluded:
state.go:shouldIgnoreSessionTrackingPath(session tracking) — consultsIsInfrastructurePath+agent.AllProtectedFiles()+agent.AllProtectedDirs()✓strategy/common.go:isProtectedPath(rewind/filtering) — consultsagent.AllProtectedDirs()✓checkpoint/ephemeral.go:collectChangedFiles(first-checkpoint path, ~line 1252/1268) — onlypaths.IsInfrastructurePath(filename), which is solely a.entire/subpath check ✗
So on the first checkpoint of a session, protected-dir content (e.g. .claude/, a plugin's .terminalhire/) is captured into the shadow tree, exactly as reported. The documented contract ("excluded from checkpoints and diffs") is violated.
3. Is it a security concern? — Low. Local-only; not a data-exfiltration bug. The reporter's own triage was correct.
I traced where the captured content can go:
- Shadow branch (
entire/<sha7>-<hash6>) holds the raw file content.PrePushpushes onlyrefs.Push/ theentire/checkpoints/v1branch — never shadow branches, which are cleaned up locally (cleanupPushedShadowBranches). So the content is never pushed. entire/checkpoints/v1(the pushable branch) stores redacted transcripts + metadata (FilesTouchedis a list of path names, not content). It does not carry the shadow tree's file blobs. AndFilesTouchedis derived from the session-tracking path, which does honor protected dirs — so protected paths shouldn't even appear there..git/entire-sessions/<id>.jsonholds the content locally too — also never pushed.
Net: the leak is confined to local git objects. An attacker would already need filesystem access to .git/, at which point they could read the working tree directly. It does not cross the trust boundary the SECURITY.md rubric cares about (remote actor / auto-push exfiltration).
That said, it's not zero-risk and shouldn't be dismissed as cosmetic:
- Protected dirs like
.claude/routinely containsettings.local.jsonwith API keys / MCP tokens. Writing them into extra local git objects broadens their footprint (backups,git fsck/reflog recovery, disk forensics, accidentalgit pushof a shadow ref). - It's a broken security contract, agent-agnostic, and fires 100% of the time on session start — so it silently affects every user, and any future change that does push shadow content would turn this into a real leak.
Recommendation: treat 271 as a valid bug (privacy/hygiene), not a security-embargo issue — keep it on the public tracker rather than routing to security@. The fix is exactly what the reporter proposed: have collectChangedFiles also consult agent.AllProtectedDirs()/AllProtectedFiles(), mirroring shouldIgnoreSessionTrackingPath, plus a regression test in ephemeral_test.go. Worth noting the current branch is protected-dirs — this looks like the fix is already in progress.
Summary
Fix (cmd/entire/cli/checkpoint/ephemeral.go): added isProtectedCheckpointPath, which checks .entire/ plus agent.AllProtectedDirs() and agent.AllProtectedFiles(), and wired it into the three filter sites in collectChangedFiles. This makes the first-checkpoint path apply the same protected-dir exclusions the session-tracking (state.go) and rewind (common.go) paths already use.
Regression test (cmd/entire/cli/checkpoint/checkpoint_test.go): TestCollectChangedFiles_ExcludesProtectedDirs now covers both leak vectors the report described:
- Built-in
.claude/(real claude-code agent, via blank import). - External-plugin-style
.terminalhire/dir and.terminalhirercfile, via a minimalfakePluginAgentregistered into the registry — exercising theAllProtectedDirs/AllProtectedFilesunion explicitly. - Asserts
.entire/is still excluded and an ordinary untracked file (src/keep.txt) is still captured. - Disables
core.excludesFileso the machine's global gitignore can't mask the leak (the exact machine-dependence the report flagged).
Verification: passes with the fix; without it, the failure output shows all three protected paths captured — confirming the leak is agent-agnostic and fires on first checkpoint, exactly as ENCLI-271 reported. gofmt clean, golangci-lint 0 issues.
Not yet run: full mise run check (integration + e2e canary). No commit made — say the word and I'll run the full check and prepare a commit on protected-dirs.