test(migrate): cover execute()/verify() flow with isolated fake engines - #23
Merged
Merged
Conversation
plan() refuses dest==src, but execute() re-reads the plan JSON from disk, so a hand-edited plan file can still pair a directory with itself: an empty source dir slips past the non-empty-destination check, the copy trivially verifies (0==0), and rmtree then deletes it as its own destination. The guard compares resolve_path()+normcase() on both sides, so trailing separators and Windows case variants are covered too. Surfaced by a Socket supply-chain audit anomaly (LOW) on core/migrate.py.
…POSIX CI caught the guard's blind spot: os.path.normcase lowercases on Windows but returns POSIX paths unchanged, while macOS's default APFS volumes are case-insensitive. A tampered plan pairing '/Users/me/models' with an upper-cased spelling slipped past the guard on macOS and ran the self- migration flow. Compare resolved paths, fold case additionally on darwin; on Linux the comparison stays exact (case-sensitive filesystems keep distinct Foo/foo as distinct directories).
execute() was only covered by the dest==source guard tests; its whole status matrix ran untested. Drive it through the real rules engine (a custom rules dir marks the source as migratable FakeApp data) against fake copy/link engines and get_work_dir pointed at tmp_path: - succeeded via link method and via manual method (hint recorded, no link created) - verification-failed leaves the original untouched - copy-ok-source-not-removed when rmtree raises OSError - dry-run copies nothing and writes no result file - RequiresAppClosed blocks until --app-closed is attested - stale-plan gates: vanished source, non-empty destination verify() had no coverage at all: passing report writes LastVerification back into the result file, missing destination / drifted file counts / broken link each fail their own check, and a missing result file raises FileNotFoundError. Full suite: 156 passed, 39 skipped -- skip count matches the known Windows baseline (39). Stacked on #22.
tzzs
force-pushed
the
test/migrate-flow-coverage
branch
from
September 13, 2026 18:51
7e22477 to
565d8b5
Compare
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.
Closes the remaining coverage gap flagged in the Socket-audit triage (#22):
migrate.execute()had only the dest==source guard tests, andmigrate.verify()had none at all (tests/integration/test_cli_smoke.py explicitly deferred migrate e2e coverage).Stacked on #22 — the first commit is the guard fix; this PR's own change is the second commit only.
What's covered
execute()— driven through the real rules engine (custom rules dir marks the source as migratable FakeApp data, soidentify_path+assert_not_critical+ themigratablere-validation all run for real) against fake copy/link engines (platform_pkg.get_copy_engine/get_link_engine/get_work_dirmonkeypatched, per the platform Protocols):Method(hint recorded, no link)verification-failed(copy engine silently drops a file) leaves the original untouchedcopy-ok-source-not-removedwhenshutil.rmtreeraises OSErrorconfirm=False) copies nothing and writes no result fileRequiresAppClosedblocks until--app-closedis attestedverify()— hand-crafted result files: passing report appendsLastVerificationback into the result JSON; missing destination / drifted file count / broken link each fail their own check; missing result file raisesFileNotFoundError.Verification
156 passed, 39 skipped— skip count matches the known Windows baseline (39).