Repository navigation
Harden the installer engine against untrusted packs + lifecycle data loss - #53
Closed
tmcfarlane wants to merge 1 commit into
Closed
tmcfarlane wants to merge 1 commit into
tmcfarlane wants to merge 1 commit into
Conversation
…le data loss The engine installs pack.json content with zero validation and will soon take third-party packs. Six verified fixes, each with an adversarial regression test (engine test coverage goes 4 -> 11): - Path traversal (critical): validate pack id + skill names against the slug pattern at load time (blocks '../..' payloads for the CLI and bridge), plus a containment guard that refuses any destination resolving outside the tool dir. Was: skills[].name joined straight into the write path -> arbitrary file write / RCE. - Git-hook trust bypass: gate the project-scope pre-commit hook on the DECLARED permissions.gitHooks (the field the CLI/GUI render), not a substring in uninstall.extraPaths. A pack showing gitHooks:false can no longer install a hook that runs its shell on every commit. - Silent data loss on first install: a pre-existing untracked user file that collides with a pack path is now classified userModified and backed up to *.omc-bak instead of being clobbered. - Upgrade orphans: files the previous version shipped but the new one drops are now removed (only the ones we still own) and cleared from the lock, restoring the 'leave no trace' guarantee. - Uninstall data loss: skip deleting a file whose content no longer matches what we recorded (user edited it); report it as keptModified. - Lockfile integrity: write via temp-file + atomic rename so a crash / concurrent writer can't leave a truncated lock.json (which readLock treats as empty, orphaning every prior install). Existing parity/backup/uninstall/git-hook tests still pass; team-avatar (gitHooks:true) is unaffected. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Hardens the installer engine (
packages/core) before it starts accepting third-party packs. Todaypack.jsoncontent is installed with zero validation, and several lifecycle paths silently lose user data. Six verified fixes, each with an adversarial regression test — engine coverage goes 4 → 11 tests.Stacked on #52 (base
feat/tauri-desktop).Fixes
skills[].namewas joined straight into the write path, soname: "../../.."escaped~/.cursor(e.g. into~/.ssh/authorized_keys). Now: slug-validatepack.id+ skill names at load time (covers the CLI and the bridge), plus a containment guard (assertWithin) that refuses any destination resolving outside the tool dir.uninstall.extraPaths, ignoringpermissions.gitHooks— the field the CLI/GUI show users. Now gated on the declared permission; a pack showinggitHooks:falsecan't install one.userModifiedand backed up to*.omc-bak.rm'd every recorded file unconditionally, including ones the user edited. Now skips files whose content no longer matches what we recorded and reports them askeptModified.writeLocknow writes to a temp file + atomicrename, so a crash / concurrent writer can't leave a truncatedlock.json(whichreadLocktreats as empty, orphaning every prior install).Tests (
packages/core/test/hardening.test.mjs)assertWithinunit • skill-name traversal rejected at load • bad pack id rejected • first-install collision backs up the user file • upgrade removes + de-lists the orphan • uninstall preserves a user-edited file • git hook honorspermissions.gitHooks.Verification
node --test packages/core/test/*.test.mjs).scripts/validate-packs.mjsgreen; the shippedteam-avatarpack (gitHooks:true, valid slugs) is unaffected.Not in scope (follow-ups)
sourceRootcan still point outside the pack dir (the flagship relies on"../.."); the containment guard keeps writes inside the tool dir regardless, but the real fix is making packs self-contained.🤖 Generated with Claude Code