GeezerVisonThe World Wide Web, restored to 800 pixels of glory. | |||||||||
| Home|About|Gaming cabinet|Archives|How it works|Starter sites | |||||||||
GeezerVison is showing github.com — fix(cli)!: require consent before patching user-patched packages by mikolalysenko · Pull Request #1646 · SocketDev/socket-patch Conversation
|
|
Burn-down agent: CI on 98d2edd had two separate failures. Fixed (29dd054): Needs a decision (coverage job): 5 tests in
Question: when the protection comes only from an inspection failure (unparseable lockfile, workspace glob outside the root) and not from real patch evidence, should Generated by Claude Code |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
- apply: release apply.lock before reporting a user_patch_conflict, like the manifest-load failures above it, so telemetry can't block siblings. - core: match Cargo [patch]/[replace] names ignoring case and -/_, since crates.io treats those as the same crate. - core: follow go.work `use` members so a member go.mod replace protects its module from the workspace root too. - scan: hide user_patch_conflict/override warnings under --silent, matching user_patches::check; the JSON envelope still carries them. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
The #480 [patch] override shapes are now caught first by the user-patch gate (user_patch_conflict), so they no longer reach redirect_cargo_dep_overridden. Scan with --allow-user-patches so the shapes keep exercising the redirect guards, and ignore the resulting user_patch_override notice; tests/user_patches.rs covers the gate. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
From /code-review high on #1646: - A `cd` after patch-package (`patch-package && cd ios && pod install`) no longer marks the patch directory unresolvable and blocks all npm. - Yarn alias locators (`alias@npm:[email protected]`) protect `real`, the name the crawler reports, instead of a name that never matches. - Cargo [patch] paths use vendor's path_is_socket_owned, so a user path like `.socket/vendor/../../forks/x` is no longer treated as Socket's. - yarn.lock is scanned line by line for patch resolutions instead of parsed (every Berry lock has compat patches); pnpm locks parse with a budget large enough for big monorepos; package-lock/bun.lock are only parsed when they mention `patched`, so a stub or broken lock with no patch evidence no longer protects every npm package. - Workspace globs walk directories only, take only dirs with a package.json as members, flag a symlink only when it would be a member, and resolve `..` lexically (re-rooting `../shared/*`). - Approved user_patch_override warnings print once: check() no longer prints, callers do, and a nested apply leaves them to its caller. - The hosted re-check refuses through the hosted module's refuse(), so the scan envelope is kept and telemetry precedes the JSON error. - A scan whose every package is protected says so instead of "No packages found. Run your package manager's install first." - Go hosted/build tests for replace guards now pass --allow-user-patches so they keep testing the guards behind the consent gate. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Two review findings on #1646, resolved as decided with the maintainer: - apply no longer refuses a whole run over one protected manifest entry (a postinstall apply would fail every install). Protected records sit the run out with a user_patch_conflict warning, everything else applies, and skips alone exit 0. The manifest on disk is unchanged, and skipped Go entries are kept out of the stale-redirect reconcile. `apply --check` stays read-only and verifies every entry. Explicit `get` and `vendor` still refuse; vendor now reverts dropped entries before its check so a protected record can't block that cleanup. - The default mismatch policy is the new MismatchPolicy::SocketContent: Strict, except a file whose hash names a stored .socket/blobs blob (another Socket patch's output, as after an update to a newer patch for the same release) is overwritten with the usual content_mismatch_overwritten warning. --strict stays fully strict. Contract and usage docs updated to match. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
- A nested apply under `get` now reports the older manifest entries it skips for project patches (stderr and the JSON envelope via the run report); `get` checks only its own selection. `scan` already reports every protected installed package, so its nested apply stays quiet. - vendor: a conflict found after reconcile_dropped already wrote is recorded as per-package `failed` events instead of a top-level error, which the contract reserves for runs where nothing happened. - patch-package `cd` detection matches `cd` as a command, not the tail of a word such as `abcd`. - The ancestor workspace walk never reaches the home directory or above, so a checkout without `.git` doesn't read `~/.cargo/config.toml` or a stray `~/patches/` as project evidence. - Discovery is skipped when no in-scope purl is in an ecosystem the detector reads (an empty or pypi-only manifest on postinstall). - npm/Bun locks are read once instead of twice. - The scan message for protected packages no longer claims they were the only reason the scan came up empty. - Contract: a pruned or unshared blob means earlier Socket output reads as drift; `apply --force` is the explicit way through. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
|
bugbot run Generated by Claude Code |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Stale Bugbot comment from a previous run.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
|
Burn-down agent: CI is green on Question for a human: should this PR fix that race now, by mapping purls that apply skipped as user-patched to Generated by Claude Code |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
Clarify that the flag accepts conflicts with existing project patches or local modifications. Rename the parser field and nested forwarding, diagnostics, contract, usage examples and existing tests consistently.
Preserve reason-bearing skip events across standalone and nested apply. Recheck conflicts under the apply lock and report late project patches in human and JSON output; count only actual applications, including mixed failures and multiple installed copies. Document the event contract and cover conflicts introduced during API fetches with deterministic regression tests.
|
bugbot run Generated by Claude Code |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Stale Bugbot comment from a previous run.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
Resolve conflicts with main's manifest/ledger gitignore checks (#1638) and the gem variant test split (#1642): - vendor eject runs main's ledger gitignore refusal first, then the user-patch consent check, so both guards stay in place. - CLI_CONTRACT keeps the PR's skipped-apply event wording and main's manifest_gitignored warning paragraph. - get_failure_paths keeps both sides' new tests. - The gem singleton mismatch tests (now split across cli_gem_variant_mismatch_policy.rs and apply_render.rs on main) pass --allow-patch-conflicts, since this PR gates the mismatch overwrite behind explicit consent. Co-Authored-By: Claude <[email protected]>
The nested apply in get / agent scan covers the whole manifest, so record_apply_outcome was copying every leftover skip (already_patched, vendored, package_not_installed) for packages the run never selected into the envelope, inflating summary.skipped. Keep only the user_patch_conflict skips for unselected packages, which are the conflicts found after selection that the caller needs to see (Bugbot finding on #1646). Co-Authored-By: Claude <[email protected]>
|
bugbot run Generated by Claude Code |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Cursor Bugbot has reviewed your changes using high effort and found 2 potential issues.
Bugbot Autofix prepared a fix for the issue found in the latest run.
Or push these changes by commenting:
@cursor push e957d768d4
diff --git a/crates/socket-patch-cli/src/commands/apply.rs b/crates/socket-patch-cli/src/commands/apply.rs --- a/crates/socket-patch-cli/src/commands/apply.rs +++ b/crates/socket-patch-cli/src/commands/apply.rs @@ -405,6 +405,9 @@ let mut tree = manifest.clone(); tree.patches .retain(|purl, _| owned_by_apply(purl) && !is_local_go(purl, &args.common)); + // Packages the project patched itself sit this run out, so `--check` + // skips them too (it verifies only the patches `apply` would process). + super::user_patches::skip_protected(&args.common, &mut tree.patches).await; // The same PnP gate `apply` runs: a PnP tree hides every npm copy, so // without it each npm patch would read as not installed and pass calm. if matches!( @@ -1206,7 +1209,7 @@ }; // Packages the project patched itself sit this run out (warned); every - // other record still applies. The read-only `--check` verifies them all. + // other record still applies. let mut manifest = manifest; let (user_patch_warnings, user_patch_skips) = if args.check { Default::default() diff --git a/crates/socket-patch-cli/tests/user_patches.rs b/crates/socket-patch-cli/tests/user_patches.rs --- a/crates/socket-patch-cli/tests/user_patches.rs +++ b/crates/socket-patch-cli/tests/user_patches.rs @@ -214,11 +214,15 @@ BEFORE, "the environment grants no consent" ); - let (_, stdout, _) = run_with_env( + let (code, stdout, _) = run_with_env( tmp.path(), &["apply", "--json", "--offline", "--check"], &[], ); + assert_eq!( + code, 0, + "--check exits 0 when protected records are skipped: {stdout}" + ); assert!(!stdout.contains("user_patch_conflict"), "{stdout}"); }
You can send follow-ups to the cloud agent here.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
`apply --check` verifies every manifest entry, including packages the project patched itself, but a plain `apply` skips those packages. A drift on one of them pointed at a remedy that could never clear it. The drift detail now names the project patch evidence, and the remedy line says such a package applies only with --allow-patch-conflicts after review, or by merging the fixes manually. Check still verifies every entry, as decided for #1646. Co-Authored-By: Claude <[email protected]>
|
bugbot run Generated by Claude Code |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Stale Bugbot comment from a previous run.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
The previous remedy still quoted a bare `socket-patch apply`, which skips every project-patched package, and offered a manual merge that cannot make installed bytes match afterHash. When a drifting package has a project patch, the quoted command now carries --allow-patch-conflicts (after a review prompt), so running it verbatim clears the drift. The integration test runs that remedy and re-checks. Co-Authored-By: Claude <[email protected]>
|
bugbot run Generated by Claude Code |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 85be54d. Configure here.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Burn-down agent: labeled Ready for review at
Generated by Claude Code |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Final reviewer: sent to the merge queue at Generated by Claude Code |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
Resolve the vendor_eject.rs conflict with #1646 by keeping both new tests: this PR's manifest-plus-hosted-pins eject test and main's user-patch consent test for the eject path. Co-Authored-By: Claude <[email protected]>
A package the project patches itself is applied by the package manager on top of whatever tarball the lock names, so a Socket pin of it either fails the install or installs the user's diff stacked on the Socket patch. The CLI's consent gate (patch::user_patches::UserPatchIndex, #1646) already kept `scan` / `get` / `vendor` / `apply` from wiring such pnpm, yarn berry and patch-package packages unless --allow-patch-conflicts, but two consumers did not read that evidence: - vex discovery attested a pnpm, yarn, vlt (or npm / Bun) pin of such a package: a pin written before the patch was declared, or one an --allow-patch-conflicts run wrote. - the in-memory hosted engine (Node addon, hosted-bundle) has no gate in front of it and rewired them. One detector, three consumers. UserPatchIndex's pnpm / yarn / patch-package parse rules are factored into pure helpers (pnpm_yaml, yarn_manifest, yarn_lock, patch_package_dirs, patch_file), which the consent gate keeps using, plus UserPatchIndex::npm_family_in, which reads the same declarations through a ProjectView (disk, snapshot or memory): package.json's pnpm.patchedDependencies, yarn patch: descriptors and patch-package dirs, pnpm-workspace.yaml's patchedDependencies, the patches of the given pnpm locks (top-level map, patch_hash suffixes) and yarn.lock's user patch: locators. It leaves out npm's and Bun's own top-level patchedDependencies, which no other package manager reads and which #711 / #367 / #2010 already judge per resolution. - Discovery: a new vex::discover::user_patched pass marks every npm ref the index protects UnattestedKind::UserPatchedDependency (the ref stays, so rollback / remove / list still find it). The bytes the install runs are Socket's patch alone only when no user patch is declared, so a declared one always withholds the statement, with or without consent. - Hosted: engine::withhold_user_patched drops such candidates from every rewriter and records them skipped `user_patch_conflict` (the consent gate's code), plus a warning in memory. The in-memory engine always applies it; the CLI disk flow applies it unless --allow-patch-conflicts (it adds the Rush lock the consent gate does not read). - Vendored: unchanged. Every vendored entry point already runs the consent gate, which refuses (`vendor`, vendored writers) or skips (`scan`, `apply`) these packages. Override: the existing --allow-patch-conflicts, invocation-only. It already covered pnpm / yarn / patch-package at the consent gate and now also lifts the engine gate; vex never attests while the patch is declared. npm / Bun native patches stay refused even with consent, as before. vlt has no patch mechanism ([email protected] has no patchedDependencies, patch_hash or `patch` command; vlt.json modifiers rewrite specs), and neither has yarn classic, so patch-package is what is read for both. Co-Authored-By: Claude Opus 5.5 <[email protected]>
A package the project patches itself is applied by the package manager on top of whatever tarball the lock names, so a Socket pin of it either fails the install or installs the user's diff stacked on the Socket patch. The CLI's consent gate (patch::user_patches::UserPatchIndex, #1646) already kept `scan` / `get` / `vendor` / `apply` from wiring such pnpm, yarn berry and patch-package packages unless --allow-patch-conflicts, but two consumers did not read that evidence: - vex discovery attested a pnpm, yarn, vlt (or npm / Bun) pin of such a package: a pin written before the patch was declared, or one an --allow-patch-conflicts run wrote. - the in-memory hosted engine (Node addon, hosted-bundle) has no gate in front of it and rewired them. One detector, three consumers. UserPatchIndex's pnpm / yarn / patch-package parse rules are factored into pure helpers (pnpm_yaml, yarn_manifest, yarn_lock, patch_package_dirs, patch_file), which the consent gate keeps using, plus UserPatchIndex::npm_family_in, which reads the same declarations through a ProjectView (disk, snapshot or memory): package.json's pnpm.patchedDependencies, yarn patch: descriptors and patch-package dirs, pnpm-workspace.yaml's patchedDependencies, the patches of the given pnpm locks (top-level map, patch_hash suffixes) and yarn.lock's user patch: locators. It leaves out npm's and Bun's own top-level patchedDependencies, which no other package manager reads and which #711 / #367 / #2010 already judge per resolution. - Discovery: a new vex::discover::user_patched pass marks every npm ref the index protects UnattestedKind::UserPatchedDependency (the ref stays, so rollback / remove / list still find it). The bytes the install runs are Socket's patch alone only when no user patch is declared, so a declared one always withholds the statement, with or without consent. - Hosted: engine::withhold_user_patched drops such candidates from every rewriter and records them skipped `user_patch_conflict` (the consent gate's code), plus a warning in memory. The in-memory engine always applies it; the CLI disk flow applies it unless --allow-patch-conflicts (it adds the Rush lock the consent gate does not read). - Vendored: unchanged. Every vendored entry point already runs the consent gate, which refuses (`vendor`, vendored writers) or skips (`scan`, `apply`) these packages. Override: the existing --allow-patch-conflicts, invocation-only. It already covered pnpm / yarn / patch-package at the consent gate and now also lifts the engine gate; vex never attests while the patch is declared. npm / Bun native patches stay refused even with consent, as before. vlt has no patch mechanism ([email protected] has no patchedDependencies, patch_hash or `patch` command; vlt.json modifiers rewrite specs), and neither has yarn classic, so patch-package is what is read for both. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Owner clarification: the repository-root bound is for workspaces; a
global run should be able to read anywhere on the system. The shared
user-patch walk now takes a ReadScope { Workspace, Global }, chosen once
from the CLI mode (GlobalArgs::read_scope, from --global / -g /
--global-prefix), and only a Workspace walk bounds its reads: a
workspace member or --patch-dir beyond the git repository root protects
every npm package instead of being read. A Global walk reads both
wherever they are and protects exactly what they patch. The ancestor
walk itself (stop at .git, never reach the home directory) is the same
in both scopes.
UserPatchIndex::discover stays the workspace walk;
UserPatchIndex::discover_scoped takes the scope, which the CLI's
inspect() now threads through. A global run still inspects no project
(a local checkout does not govern the global tree, #1646), so the
Global arm is reached through the core API today. vex discovery and the
in-memory hosted engine only run on workspaces and keep the bound.
ReadScope has the shape of #2025's utils::repo_root::ReadScope (same
variants and of_global), so it is swapped for that type when the two
branches meet.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
There was an error while loading. Please reload this page.
Successfully merging this pull request may close these issues.
There was an error while loading. Please reload this page.