Repository navigation
fix(storage): reject non-directory paths in project add - #5223
Conversation
resolveProjectLocation realpath'd the input but never checked stat().isDirectory() before Git discovery. A regular file inside a repository reached `git -C <file> rev-parse`, whose numeric failure is not an invalid-path errno, so the Host coordinator drained with commit_outcome_unknown. Outside Git the same file was registered as an unavailable folder project. Reject non-directories with TypeError so register/add treat them as invalid input and the Host stays up.
me2seeks
left a comment
There was a problem hiding this comment.
I found no blocking correctness issue at f708b6e46b46d401c36423e85e02277f7c749d49.
The new check is placed at the right authority boundary: after realpath establishes the canonical target and before Git discovery can run with a non-directory -C path. Directory targets and symlinks resolving to directories keep their existing behavior, while regular files and other non-directory filesystem nodes become typed invalid input. The Host coordinator already maps that TypeError to invalid_request, so the mutation does not enter the uncertain-commit drain path.
Validation on the exact head: clean install and test build; 23/23 project-catalog tests; Biome and whitespace checks; and an isolated real Runtime Host CLI reproduction. Both a file inside a valid Git repository and a file outside Git were rejected with Project catalog input is invalid; project list succeeded after each rejection and the same Host process remained alive.
中文说明
我在精确提交 f708b6e46b46d401c36423e85e02277f7c749d49 上没有发现阻塞问题。
检查位置合理:先用 realpath 得到真实目标,再在 Git 探测前确认它确实是目录。因此真实目录及指向目录的符号链接不受影响,普通文件和其他非目录节点会作为无效输入返回,也不会再进入“提交结果未知”并关闭 Host 的路径。
本地干净构建和 project-catalog 测试 23/23 通过。我还启动了隔离的真实 Runtime Host:Git 仓库内文件和仓库外文件均被拒绝;每次拒绝后 project list 都成功,同一个 Host 进程仍然存活。
* docs: inventory Grok-assisted merged contributions Record the post-2026-08-14 mainline PR set and review boundaries before evaluating replacement changes. Generated-by: OpenAI Codex * docs: triage Grok-assisted PR surfaces against current tree Record present-path counts and review targets without asserting line-level survival or legal disposition. Generated-by: OpenAI Codex * docs: distinguish squash dates from original Grok use evidence Flag mixed-date #2967 and the #3123 provenance discrepancy for review. Generated-by: OpenAI Codex * docs: record current-main revert feasibility for queue PR The disposable #3544 reverse patch produced 31 conflicts and was aborted without product changes. Generated-by: OpenAI Codex * revert(runtime): remove Grok-authored PTY exit reconciliation from #3082 * revert(storage): remove Grok-assisted directory check from #5223 * fix: independently restore PTY exit and project path safeguards * test(runtime): independently assert queued PTY exit settlement * docs: record surviving Eval and navigation contribution boundaries * revert(storage): remove #3070 explicit nested project selection * fix(storage): distinguish selected folders from historical Git paths * revert(desktop): disconnect #3099 rail grouping persistence * fix(desktop): own rail grouping persistence in layout store * docs: record local replacements and no-code dispositions * docs: distinguish mixed attribution and removed prompt-rail test * fix(eval): isolate framework selection per trial context * test(ci): independently verify Astryx inventory drift gate * fix(eval): classify CONNECT by tunnel destination * fix(desktop): fence live content readiness by observation generation * docs: record Grok contribution audit progress and onboarding contract * fix(eval): mark audit truncation before an oversized append * fix(runtime): honor retry delays in standard Headers * fix(runtime-host): reject stale queue reorder revisions * fix(runtime-host): bound retry wait after clock rollback * docs: reconcile remaining Grok audit dispositions after upstream merge * test(desktop): verify Daily Review fixture releases root after failure * docs: update Desktop build verification after upstream merge * test(desktop): verify terminal query parser routing * fix(eval): scope trial framework selection to execution * fix(eval): reject malformed UTF-8 in egress audit records * fix(eval): validate CONNECT authority before egress classification * fix(runtime): fall back to valid retry-after header * fix(ui): require queue revision before dragging entries * fix(ui): discard reorder drag after queue revision advances * docs: record queue reorder Electron regression * refactor(desktop): reduce live seed to one readiness state * refactor(eval): scope framework selection to runner lifetime * refactor(eval): isolate egress normalization and audit decoding * refactor(runtime): isolate provider retry policy * refactor(queue): share exact reorder policy across host and UI * refactor(queue): reject empty reorder operations * fix(protocol): advance epoch for reorder validation * docs(audit): refresh verification status * refactor(desktop): pass captured queue and seed authorities * docs(audit): record live egress verification * fix(protocol): advance epoch for reorder revision fencing * docs(audit): close technical dispositions and legal handoff * docs(audit): refresh final upstream verification * docs(audit): advance final main baseline * docs(audit): record latest main verification * docs(audit): align with latest UI baseline * docs(audit): refresh current inventory size * docs(audit): verify latest retry upstream * docs(audit): reopen incomplete Grok rewrites * refactor(ci): replace Astryx inventory gate core * refactor(storage): replace nested project selection flow * test(desktop): replace rail layout persistence coverage * refactor(eval): replace framework selection authority * refactor(eval): replace egress audit and tunnel policy * refactor(desktop): replace live observation visibility gate * refactor(runtime-host): replace provider retry projection * refactor(message-queue): replace per-entry mutation flow * fix(review): simplify rewritten contribution boundaries * docs(audit): refresh replacement survival evidence * refactor(eval): isolate egress audit evidence * refactor(desktop): rebuild connection fixture seeding * refactor(desktop): rebuild observation recovery flow * refactor(desktop): finish observation visibility rewrite * test(desktop): remove legacy observation scaffolding * test(desktop): complete observation rewrite attribution * refactor(desktop): retire moved observation remnants * refactor(desktop): finalize observation callback rewrite * refactor(desktop): name observation event consumer * refactor(desktop): complete observation event migration * refactor(ui): separate queued message view * refactor(runtime-host): unify queued mutation admission * refactor(desktop): isolate message queue actions * test(desktop): rebuild message queue story * refactor(queue): centralize mutation test and composer contracts * refactor(desktop): isolate message queue chrome styles * test(desktop): rebuild terminal query policy coverage * refactor(runtime): isolate provider retry classification * refactor(runtime-host): isolate desktop e2e backend fixture * refactor(core): separate relative time policy from formatting * refactor(eval): make raw transport rejection explicit * refactor(eval): model framework selection as an immutable spec * refactor(ci): isolate Astryx inventory contract * refactor(desktop): isolate painted-frame streaming observer * refactor(runtime): centralize PTY control finalization * refactor(runtime-host): type queue mutation handlers centrally * refactor(desktop): register queue mutations from one table * refactor(eval): centralize relay framework imports * refactor(runtime-host): isolate desktop e2e checkpoint policy * refactor(ui): centralize composer send policy * test(runtime-host): share queue mutation fixture dispatch * refactor(desktop): isolate Agent Graph panel model and backend port * refactor: isolate queue retry and connect policy boundaries * chore(ci): refresh Astryx surface inventory after rebase * fix(ci): align queue and shell contracts * fix(protocol): advance runtime host epoch * fix(ci): normalize runtime host test license header * style: format files for CI * fix(desktop): satisfy renderer architecture ratchet * fix(desktop): remove unused graph panel exports * fix(queue): restore host mutation compatibility * fix(ci): restore desktop deadline and queue seeds * fix(ci): correct streaming observer and queue id guards * test(ui): assert queue recovery action label * fix(ui): restore side chat queue controls * test(storybook): scope queue action assertion --------- Co-authored-by: likun <kunli@alva.xyz>
Summary
runtime-host project adddid not validate that the supplied path is a directory. A regular file inside a Git repository returnedProject catalog mutation outcome is unknownand drained the Host; outside Git the same file was accepted as an unavailable folder project.resolveProjectLocationalready realpath'd the input but never checkedstat().isDirectory()before repository discovery. Inside a Git worktree that reachedgit -C <file> rev-parse ..., whose numeric failure is not an invalid-path errno, so the coordinator calledrequestDrain(). Reject non-directories withTypeErrorso register/add treat them as invalid input and the Host stays up.Fixes #5220
Verification
Result: 23/23 pass, including new test
a regular file is rejected as a project location(file outside Git, file inside a Git repo, andcatalog.registerof that file).Did not run full workspace
npm testor the CLI Host reproduction from the issue (build surface limited to@maka/core+@maka/storage).AI use
Select exactly one:
Tool(s) and scope: Cursor / Grok assisted the surgical
resolveProjectLocationcheck and the unit test; commit author/committer is riba2534 only.Checklist
Does this PR entail a change in behavior?