Skip to content

fix(storage): reject non-directory paths in project add - #5223

Merged
me2seeks merged 1 commit into
apache:mainfrom
riba2534:fix/project-add-reject-file
Sep 12, 2026
Merged

me2seeks merged 1 commit into
apache:mainfrom
riba2534:fix/project-add-reject-file

Conversation

@riba2534

Copy link
Copy Markdown
Contributor

Summary

runtime-host project add did not validate that the supplied path is a directory. A regular file inside a Git repository returned Project catalog mutation outcome is unknown and drained the Host; outside Git the same file was accepted as an unavailable folder project.

resolveProjectLocation already realpath'd the input but never checked stat().isDirectory() before repository discovery. Inside a Git worktree that reached git -C <file> rev-parse ..., whose numeric failure is not an invalid-path errno, so the coordinator called requestDrain(). Reject non-directories with TypeError so register/add treat them as invalid input and the Host stays up.

Fixes #5220

Verification

export PATH="/home/box/.local/node-v22.19.0/bin:$PATH"
npm ci --ignore-scripts
node scripts/apply-dependency-patches.mjs
npm --workspace @maka/core run build
npm --workspace @maka/storage run build
cd packages/storage && node --test dist/__tests__/project-catalog.test.js

Result: 23/23 pass, including new test a regular file is rejected as a project location (file outside Git, file inside a Git repo, and catalog.register of that file).

Did not run full workspace npm test or the CLI Host reproduction from the issue (build surface limited to @maka/core + @maka/storage).

AI use

Select exactly one:

  • No generative tool made a substantive contribution
  • Generative tooling made a substantive contribution

Tool(s) and scope: Cursor / Grok assisted the surgical resolveProjectLocation check and the unit test; commit author/committer is riba2534 only.

Checklist

  • Tests cover the change and fail without it
  • Lint, format, typecheck and the affected suites pass locally

Does this PR entail a change in behavior?

  • Yes — described under Summary above
  • No

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.
@github-actions github-actions Bot added the effort/S Under 100 readable lines label Sep 12, 2026

@me2seeks me2seeks left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 进程仍然存活。

@me2seeks
me2seeks merged commit aa3f8e5 into apache:main Sep 12, 2026
2 checks passed
likun666661 added a commit that referenced this pull request Sep 28, 2026
* 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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

effort/S Under 100 readable lines

Projects

None yet

Development

Successfully merging this pull request may close these issues.

runtime-host project add with a regular file inside a Git repository shuts down the Host

2 participants