fix(kiro-cli): derive the POSIX search dirs from the home that was asked for - #7172
Conversation
|
Full CI triage on this head — two failures, neither attributable to the diff. This PR touches only
No SHA churn to reroll. |
|
🤖 Kiro Crew [operator: NicholasRBowers#a942f9ca]: This PR has been inactive for 7+ days with failing CI. I've assessed the blockers and they appear resolvable — I'll push fixes directly to this branch as a co-author. Assessment: All 3 failing tests ( If you'd prefer I don't touch this PR, add the |
a14af88 to
b9bf504
Compare
|
🤖 Kiro Crew [operator: NicholasRBowers#a942f9ca] Drive-to-green update — rebase-only push, no code changes.
The new head re-fires CI; on green the fork review lanes (GPT/Opus/Design/First Principles/UX) will dispatch. Monitoring at 5-minute intervals. |
GPT 5.6 Review (fork) — ✅ no blocking findingsReviewed Review detailsNo findings. |
Opus 4.8 Review (fork) — ✅ no blocking findingsReviewed Review detailsThe change is a straightforward correctness fix: the POSIX branch now forwards No findings. [OPUS-REVIEWED] 7b919c2 |
First Principles Review (Fable 5, fork) — ✅ PASSPremise-level review of All verification is done. Every load-bearing claim in the PR holds in the trusted base: the POSIX branch omits First-Principles-Verdict: PASS A one-argument fix at cause level: the purity contract two callers already rely on becomes true instead of only asserted. What this change shipsIntent: make the POSIX CLI search derive every home-relative directory from the home the caller asked for — a FIX.
The contract has 2 real consumers (kiro_prerequisite.py:1829–1842 pins Subtractions
[FIRST-PRINCIPLES-REVIEWED] 7b919c2 |
Design Review (Fable 5, fork) — ✅ PASSDesign-level review of The fix checks out end-to-end: the base code at Design-Verdict: PASS A one-argument fix at the true root cause, using an existing documented seam, mirroring the branch that was already correct, with property-pinning tests. Suggestions
[DESIGN-REVIEWED] 7b919c2 |
…ked for
`known_kiro_cli_dirs` builds `~/.local/bin` and `~/.cargo/bin` from its
`home` argument, then appends `augmented_path(...)` for the inherited
PATH. On POSIX it omitted `home=`, and `augmented_path` falls back to a
LIVE `os.path.expanduser("~")` — so one call returned a directory list
mixing two accounts: the caller's home for the first entries, and
whichever account owns the process for the `{home}`-templated extras
(`.toolbox/bin`, `.npm-packages/bin`, `.volta/bin`, the mise shims) and
the Node bin dirs. The win32 branch already forwards `home=`.
That breaks the property the ACP spawn resolver relies on. It pins one
`(platform, home, environ)` reading and passes it to both the resolve and
the "kiro-cli not found (searched ...)" diagnostic precisely so the
directories named are the directories walked; a live re-read in the
middle lets the two disagree. It is the split-read class kirodotdev#5048 and kirodotdev#6986
fixed at the call sites, surviving one level down — and kirodotdev#6986's own
review named it.
Forward `home=` on the POSIX branch, mirroring win32, and state the
purity contract in the docstring instead of leaving it implied.
Original fix authored by Leon (leonlaiyc). Rebased onto current main to
clear base-drift CI failures; no code changes in the rebase.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Kiro Crew <noreply@kirodotdev.github.io>
b9bf504 to
7b919c2
Compare
|
🤖 Kiro Crew [operator: NicholasRBowers#a942f9ca] self-added: no
|
|
🤖 Kiro Crew [operator: NicholasRBowers#a942f9ca] Drive-to-green update — round 2, head Changes in this push:
Local gates on |
|
🤖 Kiro Crew [operator: NicholasRBowers#a942f9ca] ✅ Review-ready at head
Ready for maintainer review and merge. Auto-merge is not armed. |
iamwhatever
left a comment
There was a problem hiding this comment.
Tier 1 auto-approve: fix (2 files). Criteria: no conflict, no requested changes, security path denylist clean, design-doc gate clean, SAST annotations clean, security checklist all-NO, AI reviewers green. Category: fix -- the POSIX branch of known_kiro_cli_dirs omitted the home= forward to augmented_path, so a single call mixed .local/bin/.cargo/bin from the caller's home with the {home}-templated and Node/mise entries from the process's account, breaking the ACP resolver's "the directories named in a not-found message are the directories that were searched" contract; one missing keyword plus a regression test, no behaviour change elsewhere. CodeQL is not applicable on this fork PR (default-setup emits no check-run); SAST coverage is Semgrep only, latest run success with 0 annotations.
Problem / Motivation
known_kiro_cli_dirs(platform_name, home, environ)returns the directories where Kiro CLI may be installed. It builds the first entries from itshomeargument, then appends the augmented inherited PATH:augmented_pathresolves its own home when the keyword is omitted —resolved_home = home or os.path.expanduser("~")(env.py:661) — and uses it to format_EXTRA_PATH_DIRS({home}/.toolbox/bin,{home}/.npm-packages/bin,{home}/.volta/bin,{mise_data}/shims) plus the Node bin dirs. So one call returns a list mixing two accounts. The win32 branch three lines above already forwards it:augmented_path("", home=str(home)).Measured on current
main(5fe1d64e4), asking for/home/alicewhile the process home is elsewhere:Why it matters
This breaks the exact property the ACP spawn resolver was just built to rely on.
acp/client.py's_resolve_kiro_cli_for_spawnsays so in its own docstring:On POSIX it is not a pure function of those arguments. A live
expanduser("~")sits in the middle, so the resolve and the diagnostic are two readings again — which is precisely the split-read defect #5048 and #6986 fixed at the call sites, surviving one level down. #6986's First Principles review named it:It is not only the message.
find_kiro_cli_candidateswalks this same list, so the directories actually searched for the binary are half-derived from the wrong account whenever the caller'shomediffers from the process's live~. Both production callers pin ahomeup front for exactly this reason —PrerequisiteMonitorcapturesself._homeat construction and probes later on a worker thread (kiro_prerequisite.py:1879,:2533), and_resolve_kiro_cli_for_spawnsnapshots per attempt — so the gap between capture and use is real by design, not hypothetical.Being scoped to POSIX, this is invisible on the Windows branch that was already correct.
What changed (motivation → approach → change)
Symptom → the search-dir list mixes two accounts, so a reported search path can disagree with the search that ran. Root cause → the POSIX branch drops the
home=keyword that the win32 branch passes, andaugmented_paththen falls back to a liveexpanduser("~"). Change → forward it, mirroring the branch that was already right.src/kiro_crew/kiro_cli.py, one argument:augmented_path'shomekeyword already exists and is already documented for this case ("pins user-relative candidates for callers already resolving a specific account instead of whichever account owns the current process"). Nothing is added; an existing seam is used on the branch that was missing it.The function's docstring now states the purity contract rather than leaving it implied in a caller's docstring, so the next reader of
known_kiro_cli_dirssees the property that the ACP diagnostic depends on. The new code comment says why the keyword is there, naming the caller contract it serves.Scope. One production line plus its comment and docstring. No behaviour change for win32 (already forwarding), and none for any caller whose
homematches the process home — which is why this is a latent-correctness fix rather than a visible-symptom one, and the PR says so rather than claiming a user report.Tests
New in
test/test_env.py, classTestKnownKiroCliDirsIsPureInItsHome— sited next to the existingaugmented_path/known_kiro_cli_dirsboundary tests:test_posix_dirs_never_mention_the_process_home— patchesexpanduserto a distinct process home, asks for another, and asserts no returned entry is derived from the process home. Carries its own control (the asked-for home IS represented) so it cannot pass by the function returning nothing home-relative.test_the_templated_extras_follow_the_asked_home— names.toolbox,.npm-packages,.voltaindividually and requires each entry to start with the asked-for home..local/binalone would not discriminate: the POSIX branch always built that one correctly, so a partial fix would pass a looser assertion.test_win32_branch_still_pins_its_home— the control on the branch that was already correct, showing the fix mirrors an existing convention rather than inventing one.test_two_calls_with_the_same_arguments_agree_across_a_home_change— the property the ACP diagnostic needs, stated directly: same arguments, process home moved in between, same result.Red-before, production change reverted with the tests in place: 3 failed, 1 passed (the win32 control passes on both sides, as it must).
Green after,
test_env.py+test_acp_client.py+test_kiro_prerequisite.py(Python 3.10.6, Windows):origin/main, twiceExactly the four new tests, no flips in either direction. The 18 are a stable Windows-only local baseline reproduced on pristine main —
TestResolveKrb5Ccname(POSIXos.getuid) and two path-separator assertions inTestAugmentedPath/TestExtraMcpPathDirs.test_acp_client.py+test_kiro_prerequisite.pyalone are 677 passed, 50 skipped, 0 failed on this branch.Gates green: flake8, isort,
scripts/check_black_formatting.py,mypyon the changed module (no issues in it).Manual verification
N/A — unit coverage sufficient: the defect is which account a returned directory string is derived from, which the tests observe directly by pinning two different homes. Reproducing it by hand needs a gateway whose process home differs from the account being resolved, on POSIX.
Related Issues
Residual named by the First Principles review on #6986 (merged). Same split-read class as #5048 (merged).
no linked issue: both prior issues in this defect class are already closed; this PR fixes the residual their reviews named, which was never filed as its own issue.
Pattern harvest
Rule candidate: review-prompt — when a function takes an
environ/homeargument, flag any code path inside it (including helpers it calls, likeaugmented_pathwithouthome=) that falls back to liveos.environ/os.path.expanduser("~")reads. This is the third instance of the split-read class (#5048, #6986, here), each one level deeper in the call chain.Checklist
feat|fix|docs|refactor|perf|test|chore|ci|build|revert: ...)