fix(sleep): confine legacy SKILL.md and CLAUDE.md adoption to staged roots - #289
Open
RohithPariki wants to merge 1 commit into
Open
RohithPariki wants to merge 1 commit into
RohithPariki wants to merge 1 commit into
Conversation
…roots Addresses microsoft#288 by ensuring legacy adopt() verifies that live targets are confined within allowed roots recorded when the night was staged: - In write_staging(): record project_root in manifest and ensure skill_roots is recorded even for pure legacy proposals. - Add staged_project_root() to read and validate the staged project root. - In adopt(): require and validate that live_skill_path is within staged skill_roots and live_memory_path is within staged project_root, failing closed before any files or directory trees are created outside. - Add TestLegacyAdoptionIsConfinedToTheStagedRoots with 8 regression tests.
This branch has not been deployed
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.
Problem
Issue #288 identified an inconsistency between per-skill adoption (
adopt_skills()) and legacy adoption (adopt()):While
adopt_skills()confines live skill targets to the recorded skills roots via_live_target_within_roots()and fails closed if targets escape, legacyadopt()performed no root containment checks on eitherlive_skill_pathorlive_memory_path.Furthermore,
_planned_live_directories()would create any missing parent directory tree and write staged proposals to arbitrary paths outside the project or skills roots (such as~/.bashrcor system files) if a manifest was retargeted or tampered with.In addition,
write_staging()did not recordskill_rootsin the manifest when staging pure legacy proposals, leaving legacy adoptions without a recorded root boundary.Root Cause
write_staging()omittedproject_rootfrommanifest.jsonand only recordedmanifest["skill_roots"]whenskill_rows(per-skill proposals) was non-empty.adopt()validated basename, canonical realpath, and symlink/junction presence, but never validated target containment againstskill_rootsorproject_root.Solution
write_staging(): Always recordmanifest["project_root"] = os.path.abspath(project)and populatemanifest["skill_roots"]even for legacy proposals (deriving the root fromlive_skill_pathandskill_search_roots).run_sleep_cycle(): Passskill_search_roots(cfg)unconditionally towrite_staging().staged_project_root(staging_dir: str) -> strto mirrorstaged_skill_roots(), requiring an absoluteproject_rootinmanifest.jsonand failing closed with an informativeStagingErrorif missing or invalid.adopt():label == "skill": Ensure_live_target_within_roots(live, skill_roots)holds; otherwise raiseStagingError("live target for legacy skill is outside the skills roots recorded when this night was staged: ...").label == "memory": Ensure_live_target_within_roots(live, [project_root])holds; otherwise raiseStagingError("live target for legacy memory is outside the project root: ...").Testing
python -m pytest tests/test_sleep_adopt_skill_subset.py:TestLegacyAdoptionIsConfinedToTheStagedRootswith 8 focused regression tests:test_legacy_skill_retargeted_onto_an_outside_file_is_refused(victim untouched)test_legacy_skill_retargeted_to_create_a_new_outside_file_is_refused(no directories or files created)test_legacy_memory_retargeted_onto_an_outside_file_is_refused(victim untouched)test_legacy_memory_retargeted_to_create_a_new_outside_file_is_refused(no directory or file created)test_legacy_manifest_without_recorded_skill_roots_is_refused(fails closed)test_legacy_manifest_without_recorded_project_root_is_refused(fails closed)test_staged_project_root_reads_and_validatestest_ordinary_legacy_adoption_still_succeedstests/test_sleep_engine.py: all 5 tests passed.Risk
Low. Valid legacy in-root adoption behavior is fully preserved. Staged nights written with unconfined or missing root manifests fail closed with an explicit error to restage.
Issue
Fixes #288