Skip to content

fix(cli): preserve malformed configuration before setup mutations - #401

Open
DivyamTalwar wants to merge 5 commits into
activeloopai:mainfrom
DivyamTalwar:fix/cli-preserve-malformed-config
Open

DivyamTalwar wants to merge 5 commits into
activeloopai:mainfrom
DivyamTalwar:fix/cli-preserve-malformed-config

Conversation

@DivyamTalwar

@DivyamTalwar DivyamTalwar commented Sep 22, 2026 •

Copy link
Copy Markdown

Summary

Fixes #400.

Installers and first-run migration must not treat malformed or unreadable existing configuration as empty. Validate Hermes YAML and Codex/Cursor hook JSON before payload mutation; only ENOENT means missing. Passive configuration reads remain non-throwing, while migration and explicit writes refuse invalid or unreadable state.

The final review follow-up performs the same read-only preflight at the entry to heavy embeddings install and uninstall, before dependencies, shared payloads, links or daemon operations are changed. Hermes uses parser root metadata to accept genuinely empty YAML documents, including explicit document markers, while rejecting scalar, sequence, tagged-null and anchored-null roots.

Version Bump

No release requested. Package versions, dependencies, lockfiles and release workflows are unchanged.

Test plan

  • Original-source negative controls reproduce destructive handling of malformed configuration. The earlier corrected branch passed 80 focused and 216 adjacent tests.
  • New follow-up tests on the previous d72535a2 PR head: 11 failed and 24 controls passed, reproducing heavy-operation ordering and explicit-empty-YAML rejection.
  • Final focused configuration, Hermes and heavy-embeddings suites: 55 passed, zero failed. These use actual temporary configuration/payload/link files, with subprocess, dependency installation and process-signaling boundaries mocked.
  • Exact final commit a061e94c8f22989955e6f736145b77f6f98de502: independent Node 22/Linux full suite with coverage, 5,880 passed, zero failed, zero skipped. Typecheck, build, duplication guard, critical-only OpenClaw bundle audit and diff checks pass in the same gate.

Final exact-commit commands and validation logs, job config-validation-followup. This supersedes the previous-head validation for the follow-up changes.

Limits

This is validation before mutation, not a transactional installer or an atomic check-and-use guarantee. Existing in-process configuration caching and concurrent external edits retain their prior limitations. Valid YAML writes retain the existing serializer behavior. Nonzero dispatcher status is independently fixed by #377 and is not duplicated here. Native Windows and real permission-denied mounts were not exercised.

The unchanged full macOS baseline has known failures and skips; a clean full macOS suite is not claimed. No real credentials, customer transcripts, live model/API calls, real package installation or real user configuration were used by regression tests.

DivyamTalwar and others added 2 commits September 22, 2026 04:27
CLI installers and preference migration currently interpret malformed JSON or YAML as empty configuration, then overwrite or delete the user's file. Validate before payload mutations and refuse writes when parsing fails so recovery remains user-controlled.\n\nConstraint: Existing installs must preserve unrelated settings and malformed files must never be repaired by silent replacement\nRejected: Treat malformed config as empty and continue | destroys user data and hides the recovery action\nConfidence: high\nScope-risk: moderate\nReversibility: clean\nDirective: Keep malformed-config paths fail-safe; do not broaden parsers to auto-repair unknown user files\nTested: Focused Vitest installer and user-config suites; TypeScript noEmit\nNot-tested: Native Windows filesystem behavior
Malformed and unreadable user configuration must remain authoritative until the user repairs it. Validate installer configuration before payload mutations, preserve passive hook fallbacks, and surface explicit uninstall failures without rewriting user bytes.

Constraint: Capture and startup readers must remain non-throwing even when the shared user config is malformed or unreadable
Rejected: Preflight with existsSync | lookup errors can be misclassified as missing and trigger destructive migration
Confidence: high
Scope-risk: moderate
Directive: Keep config validation ahead of every installer payload mutation and treat only ENOENT as missing
Tested: 80 focused tests, 216 adjacent tests, TypeScript typecheck, build, jscpd
Not-tested: Full repository test suite, real EACCES mount behavior, live user installations
@coderabbitai

coderabbitai Bot commented Sep 22, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

Next included review available in 1 minute.

Check out review usage here.

View limit details

Limit details: You’ve used all 4 included reviews currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Repository: activeloopai/hivemind/.coderabbit.yaml

Review profile: CHILL

Plan: Advanced

Run ID: 05ccc202-ad02-4d4c-aa0f-8681225dedf5

📥 Commits

Reviewing files that changed from the base of the PR and between ce30de7 and a061e94.

📒 Files selected for processing (11)
  • src/cli/embeddings.ts
  • src/cli/install-codex.ts
  • src/cli/install-cursor.ts
  • src/cli/install-hermes.ts
  • src/user-config.ts
  • tests/claude-code/user-config-io-failure.test.ts
  • tests/claude-code/user-config.test.ts
  • tests/cli/cli-embeddings-config-preflight.test.ts
  • tests/cli/cli-install-codex-fs.test.ts
  • tests/cli/cli-install-cursor-fs.test.ts
  • tests/cli/cli-install-hermes.test.ts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Heavy embeddings install and uninstall now perform a read-only user-config preflight before dependency, link, prune, or daemon work. Hermes also recognizes parser-confirmed empty YAML documents only for explicit markers and supported directives, while retaining scalar, collection, and explicit-null rejection. Focused hermetic tests cover malformed and injected-read failures plus exact YAML regressions.

Constraint: Preserve passive user-config getter behavior, missing-file semantics, setter contracts, and the existing cache limitation\nRejected: Make writeUserConfig transactional across provisioning | broader scope than the review correction\nConfidence: high\nScope-risk: narrow\nReversibility: clean\nDirective: Do not infer broad TOCTOU guarantees from the read-only preflight\nTested: Node 22 focused/adjacent Vitest 156 tests; OpenClaw bundle wiring 5 tests; typecheck; build; duplication scan; critical-only bundle audit\nNot-tested: Full suite and coordinator-owned Linux gate
@DivyamTalwar

Copy link
Copy Markdown
Author

Final review found two additional edge cases: heavy embeddings cleanup can mutate payloads before strict config validation, and an explicit empty YAML document (---) is rejected. A follow-up is being tested within this PR; please hold merge until the updated commit and validation are linked. The previous exact-commit results remain valid for their stated coverage, but did not exercise these paths.

The empty-document regression needs to accept legal start/end marker pairs and supported directives while rejecting parser-null forms such as !!null and anchored nulls. Keep the parser success check, then use a narrow lexical structure check for the empty-document branch and preserve the valid-config preflight paths in the hermetic embeddings tests.

Constraint: Preserve js-yaml parser authority, exact malformed-config bytes, existing config cache/setter contracts, and missing-file behavior
Rejected: Accept every parsed null or rely only on parser root kind | tagged and anchored nulls also report null-like roots
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep lexical acceptance limited to legal empty markers/directives and ordered marker pairs
Tested: Node 22 Hermes 27 tests; embeddings preflight 6 tests; combined focused/adjacent 160 tests; typecheck
Not-tested: Final build/audit rerun after this follow-up and full Linux suite
Related: 3725c43
The parser reports empty documents and explicit null-like roots through the same null value, but close-event metadata distinguishes an empty node from a tag or anchor. Keep the empty-document acceptance parser-driven and reject those explicit null forms without broadening the accepted syntax.

Constraint: Preserve legal YAML markers/directives, BOM/comments, parser success semantics, and payload-preserving rejection
Rejected: Treat every null-like parser result as an empty config | tagged and anchored null roots must remain rejected
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Retain the parser metadata guard whenever adding null-root compatibility cases
Tested: Node 22 Hermes 29 tests; final focused matrix rerun pending
Not-tested: Final build/audit rerun after this commit and full Linux suite
Related: d2b7913
@DivyamTalwar

Copy link
Copy Markdown
Author

Both final-review findings are corrected in a061e94: heavy embeddings operations validate configuration before mutation, and Hermes accepts genuinely empty YAML documents without accepting tagged/anchored null roots. The previous head fails 11 new cases; the corrected head passes all 55 focused tests and the full Node 22/Linux gate: 5,880 passed, zero failed or skipped, with coverage/build/typecheck/duplication/bundle checks. Final validation: https://github.com/DivyamTalwar/hivemind/actions/runs/35674754671 . The PR body now reflects this exact head, and the temporary hold for these two findings is resolved.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

cli: malformed or unreadable configuration can be overwritten during setup

1 participant