Repository navigation
Reject relative existing --target-dir as invalid_target before composition - #369
Conversation
…ore composition (Fixes #367)
Fleet review (qwen38)Lens: evidence. The fix matches issue #367's stated contract: runDirectoryInstall now refuses any target that is not absolute or not clean with error=invalid_target before any stat or composition work, and the new Suggestion (2)
Question (1)
Verdict: ready to merge |
Fleet review (glm)Lens: requirements + adversarial. The change satisfies the explicit acceptance criterion of issue #367: an existing relative path now fails closed with error=invalid_target (exitUsage) before any stat or composition work, and the new Suggestion (1)
Question (1)
Verdict: ready to merge |
Fleet review (glmflash)Lens: adversarial The fix is narrow and consistent with the stated contract: runDirectoryInstall now refuses any target that is not absolute or not clean before the os.Stat gate, which closes the relative-existing hole from #367 (a relative existing directory passed Stat/IsDir and surfaced as install_composition_failed/exit 70 instead of invalid_target). Boundary cases I attacked: empty target (IsAbs("")==false, refused with the same diagnostic as before), absolute-but-unclean paths like /tmp/./x (now correctly refused per the 'not clean' contract, previously they slipped into composition), trailing-slash paths (Clean normalizes them away, refused), and non-existing relative paths (unchanged refusal). No blocking defects found. One test-robustness concern below: the new relative-existing case silently degenerates into the pre-existing 'relative' case if the command under test ever runs with a different working directory, which would make the test pass even without the fix. Suggestion (1)
Verdict: ready to merge |
Fleet review (mimo)Lens: requirements. The diff satisfies issue #367's repro and stated acceptance: runDirectoryInstall now refuses any non-absolute or non-clean target with error=invalid_target before os.Stat and before any composition work (install.go:108), and the new relative-existing case pins the exact repro shape the issue says previously exited 70 with install_composition_failed, asserting both the error string and that nothing was applied. Verified at the reviewed head that runDirectoryInstall is only reachable from the --target-dir branch of runInstallCommand, so the default (no flag) install path is unaffected. Two non-blocking gaps: the issue's Expected behavior names four malformed classes but the 'not clean' class has no test case, and the strict filepath.Clean comparison flips previously-working absolute inputs (trailing slash, /./, //) to invalid_target - that follows the contract as written ('not clean' is listed as malformed), but the intent for the trailing-slash form should be confirmed because the issue's repro and release-notes quote only concern relative paths. Suggestion (1)
Question (1)
Verdict: ready to merge |
Fleet review (deepseek)Lens: evidence + test design. The diff closes the reported repro (issue #367): a relative path that exists on disk now stops at the new absolute+clean guard in runDirectoryInstall with error=invalid_target and exitUsage, before any stat, composition or backup work. The added Suggestion (1)
Question (1)
Verdict: ready to merge |
Post-merge QA (glm)Lens: requirements + adversarial. The change satisfies the explicit acceptance criterion of issue #367: an existing relative path now fails closed with error=invalid_target (exitUsage) before any stat or composition work, and the new Suggestion (1)
Question (1)
Verdict: clean |
Post-merge QA (deepseek)Lens: evidence + test design. The fix targets the right gate: runDirectoryInstall now refuses a non-absolute or unclean target before the os.Stat check, so a relative path that exists on disk reaches the explicit invalid_target diagnostic and exitUsage instead of failing later as install_composition_failed. The new Question (1)
Verdict: clean |
…ll (#388) * fix(cli): refuse relative --target-dir in doctor, update, and uninstall install refused a relative or unclean --target-dir as invalid_target (#369), but doctor accepted it, probed the directory with a temporary file, and exited 0, while update reported invalid_catalog or target_absent. Every command that consumes --target-dir now runs the same validTargetDir check before reading or writing the directory, and refuses with error=invalid_target and exit 64. docs/operating.md used a relative path in its install example; it now uses an absolute one and states the shared rule. Fixes #372 * fix(cli): validate an empty --target-dir instead of falling back doctor and uninstall treated `--target-dir ""` as an absent flag: doctor ran the host runtime report, and uninstall ran the canonical all-roots uninstall, so `cortex uninstall --target-dir "$TARGET"` with an unset TARGET removed every Cortex-owned skill and exited 0. update refused the same input as invalid_command. All three now track whether the flag was given and refuse an empty value with error=invalid_target, exit 64, like install. The refusal test adds the empty value, Windows path shapes (drive-relative, rooted without a drive, mixed separators), install's --target-dir= form, target-before-catalog precedence for update, and an unchanged home. Its uninstall dependencies fail the test if the canonical roots are ever resolved, so it cannot touch a real home. docs/operating.md now states exactly which inputs every command refuses and which answers stay command-specific. Refs #372 * docs(cli): note that usage errors precede the --target-dir check (Refs #372) * test(cli): pin trailing separators, the empty runtime, and a valid target Address the fleet review on #388: - A trailing separator (the form shell completion produces) is refused as invalid_target by every --target-dir command. On main, doctor accepted it and reported presence, update failed with the misleading invalid_catalog (exit 70), and install and uninstall already refused it; the change is pinned and named in docs/operating.md. - update --runtime "" stays a usage error, so the runtime mode never reaches the directory mode through an empty runtime ID. - A valid absolute target is still accepted (doctor control case), and TestValidTargetDir pins the check itself, including over-refusal. Refs #372 * fix(cli): refuse missing or non-directory update targets as invalid_target Refs #390 --------- Co-authored-by: Juan Barbat <[email protected]>
Fixes #367
Problem
A relative path that exists on disk passed to
cortex install --target-dirslipped past the directory-target validation.runDirectoryInstallonly checked the path withos.Stat, so a relative existing directory cleared that gate, reached candidate composition, and failed later with the genericinstall_composition_failed(exit 70) instead of the promisedinvalid_targetdiagnostic. Non-existing relative paths were refused correctly, which is why the existing test case forrelativenever caught this.Change
runDirectoryInstallnow rejects any target that is not absolute or not clean before any stat or composition work, so every malformed target shares the one explicitinvalid_targetdiagnostic before any write, as the directory-target contract states. The refusal happens first, so no composition or backup work runs for a malformed path.Test
Added a
relative-existingcase toTestInstallDirectoryTargetFailClosedOnInvalidPaths: a relative path pointing at a real directory, the exact shape from the issue repro. RED before the fix (exit 70,install_composition_failed), GREEN after (exit code fromexitUsage,error=invalid_target, nothing applied). Full./internal/clisuite andgo vetpass.