feat(setup): add --check and --remove flags with dry-run + edit previews#99
Merged
Merged
Conversation
`setup` previously only added its install hook. This adds two inverse modes,
both honoring the existing --dry-run / --yes / --json flags and printing the
exact set of proposed edits before touching disk:
- `setup --check`: read-only verification. Exits 0 only when every package.json
is configured for socket-patch and none failed to parse; otherwise exit 1.
- `setup --remove`: reverts the lifecycle scripts setup added. Full revert —
emptied postinstall/dependencies keys are deleted, an emptied `scripts`
object is dropped, sibling scripts and key order are preserved.
Scope is npm-family only, matching the surface `setup` already configures;
check/remove operate purely on package.json.
Core: `remove_socket_patch_from_script` + `remove_package_json{_object,_content}`
in detect.rs (exact inverse of generate_updated_script, reusing the same
non-object guards) and `remove_package_json` in update.rs.
Tests: core unit tests; setup_invariants check/remove flows; cli_parse_setup
flag + conflict coverage; and the setup-matrix driver now does a non-destructive
check->remove->check round-trip after install/verify, asserted for npm-family
cases (untagged elsewhere, consistent with the non-blocking BASELINE GAP
convention).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ences The previous round-trip inspected package.json (grepped for socket-patch) and flag state. Replace it with a behavioral verification driven by real (setup)·(package-manager install) cycles, for npm-family cases that run setup: install -> patch NOT applied (no hook yet) setup --check -> fails (not configured) setup --yes; setup --check -> passes (configured) reinstall -> patch applied (hook fires; the main actual_applied) setup --remove --yes; setup --check -> fails (reverted) reinstall -> patch NOT applied (hook gone) A clean `rm -rf node_modules` precedes each observation so the lifecycle hook acts on a pristine package. run-case.sh factors out do_install/verify_applied/ reset_modules; emit_result drops `remove_clean` and adds applied_before_setup, applied_after_remove, and check_before_setup_exit. The harness round_trip_failure asserts the patch bookends are not-applied and check goes false->true->false. Non-npm / no-setup cases keep the simple single-install flow unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…the file
The matrix decided "applied" by scanning the patched file for the marker
string. Now it actually EXECUTES the patched module with the ecosystem's
standard runner and checks for the marker in the runtime output:
npm/yarn/pnpm -> node <file> bun -> bun <file> deno -> deno run
pip -> ./venv/bin/python <file> uv -> uv run python poetry/pdm/hatch -> *run python
To make the patched code observable at runtime, the committed blob is now
runnable: `console.log("MARKER")` for JS, `print("MARKER")` for Python.
Compiled/loaded ecosystems we can't execute (cargo/go/maven/nuget/gem/
composer) keep an inert comment and fall back to reading the file (`cat`),
preserving today's behavior for those gaps.
verify_applied() runs every resolved copy of the file (covers hoisting, the
pnpm store, and workspace/monorepo member dirs) and ORs the results.
Also fixes a parallel-test race: the blob was written to a fixed /tmp/sm_blob,
so concurrent package-manager test fns clobbered each other's fixture
(afterHash mismatch -> apply no-op). Each case now uses its own mktemp file.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Wenxin Jiang (Wenxin-Jiang)
approved these changes
Jun 2, 2026
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.
Summary
socket-patch setuppreviously only added its install hook (thepostinstall/dependencieslifecycle scripts inpackage.json). This PR adds two inverse modes, both honoring the existing--dry-run,--yes, and--jsonflags and printing the exact set of proposed edits before touching disk:setup --check— read-only verification. Exits0only when every discoveredpackage.jsonis configured for socket-patch and none failed to parse; otherwise exits1. JSON statuses:configured/needs_configuration/error/no_files.setup --remove— reverts the hookssetupadded. Full revert: an emptiedpostinstall/dependencieskey is deleted, an emptiedscriptsobject is dropped, and sibling scripts + key order are preserved. JSON statuses:success/partial_failure/not_configured/dry_run/no_files.The two flags are mutually exclusive (
conflicts_with). Scope is npm-family only, matching the surfacesetupalready configures — check/remove operate purely onpackage.json.Changes
Core (
crates/socket-patch-core/src/package_json/)detect.rs:remove_socket_patch_from_script(splits on&&, drops socket-patch segments — the exact inverse ofgenerate_updated_script) +remove_package_json_object/remove_package_json_content, reusing the same non-object-root / non-object-scriptsguards as the update path.update.rs:remove_package_json(path, dry_run) -> RemoveResultwithRemoveStatus { Removed, NotConfigured, Error }, mirroringupdate_package_json.CLI (
crates/socket-patch-cli/src/commands/setup.rs)SetupArgsgains--check/--remove;run()dispatches torun_check/run_remove/run_setup. Existing setup flow is unchanged (refactored to share adiscoverhelper that keeps the pnpm root-only filtering).Tests
setup_invariants.rs: check on configured/unconfigured/no-files/read-only; remove round-trip preserving sibling scripts; remove dry-run; nothing-to-remove; check+remove conflict.cli_parse_setup.rs: flag parsing, conflict, defaults.run-case.shrecordssetup --checkafter configure, and after install/verify runs a non-destructive--remove→--check→ grep round-trip, emitting four new JSON fields.setup_matrix_common/mod.rsasserts check=0 / remove=0 / check-after-remove≠0 / clean for npm-family cases; untagged elsewhere, consistent with the existing non-blocking BASELINE GAP convention.Verification
cargo test(core + cli) green. (The lonecargo_fetch_scan_sync_patches_real_filefailure is a pre-existing network-gated cargo-registry e2e test, untouched by this PR.)SOCKET_PATCH_TEST_HOST=1) passes including the new round-trip assertions.🤖 Generated with Claude Code