From 9fb0100fd300b414b9820acf7454268c04d11e38 Mon Sep 17 00:00:00 2001 From: Mikola Lysenko Date: Fri, 9 Oct 2026 13:34:53 -0400 Subject: [PATCH] Align ignored npm/vendored e2e tests with v5 Three on-demand live-production tests encoded v4 behavior and failed on main. Each is drift from documented v5 semantics, not a product bug: - test_npm_global_lifecycle: v5 rollback is full-state and drops the manifest records, so the following `apply -g` had nothing to apply. The lifecycle now rolls back with --preserve-state and asserts the record is kept. - test_npm_uuid_shortcut: `socket-patch ` is `get `, which runs hosted mode in a lockfile project. The test now asserts the hosted pin in package-lock.json, and that ` --mode agent` patches in place and records the manifest. - yarn_berry_vendored_install_proof: v5 vendored mode is manifest-free, so the manifest-less VEX leg asserts no manifest instead of deleting one. Co-Authored-By: Claude Opus 5.5 (1M context) --- crates/socket-patch-cli/tests/e2e_npm.rs | 74 +++++++++++++++---- .../tests/e2e_vendored_production.rs | 12 ++- 2 files changed, 69 insertions(+), 17 deletions(-) diff --git a/crates/socket-patch-cli/tests/e2e_npm.rs b/crates/socket-patch-cli/tests/e2e_npm.rs index 63de6c636..a592643e7 100644 --- a/crates/socket-patch-cli/tests/e2e_npm.rs +++ b/crates/socket-patch-cli/tests/e2e_npm.rs @@ -458,16 +458,33 @@ fn test_npm_global_lifecycle() { assert_eq!(patches[0]["purl"].as_str().unwrap(), NPM_PURL); // -- ROLLBACK: restore original file globally ---------------------------- + // v5.0 rollback is full-state: by default it also drops the rolled-back + // manifest records, leaving `apply` nothing to re-apply. This lifecycle + // re-applies next, so it rolls back with `--preserve-state`, which + // restores the file and keeps the record. assert_run_ok( cwd, - &["rollback", "-g", "--global-prefix", nm_str], - "rollback -g", + &[ + "rollback", + "-g", + "--global-prefix", + nm_str, + "--preserve-state", + ], + "rollback -g --preserve-state", ); assert_eq!( git_sha256_file(&index_js), BEFORE_HASH, "index.js should match beforeHash after global rollback" ); + let manifest: serde_json::Value = + serde_json::from_str(&std::fs::read_to_string(&manifest_path).unwrap()).unwrap(); + assert_eq!( + manifest["patches"][NPM_PURL]["uuid"].as_str(), + Some(NPM_UUID), + "rollback --preserve-state keeps the manifest record" + ); // -- APPLY: re-apply from manifest globally ------------------------------ assert_run_ok(cwd, &["apply", "-g", "--global-prefix", nm_str], "apply -g"); @@ -690,7 +707,11 @@ fn test_npm_macos_global_auto_discovery() { ); } -/// UUID shortcut: `socket-patch ` should behave like `socket-patch get `. +/// UUID shortcut: `socket-patch ` behaves like `socket-patch get +/// `. In v5.0 a bare `get` in a lockfile project runs hosted mode: the +/// lockfile is redirected to the Socket-hosted patched tarball and the +/// installed tree is left for the next install; `--mode agent` passes +/// through the shortcut and patches in place, recording the manifest. #[test] #[ignore] fn test_npm_uuid_shortcut() { @@ -708,28 +729,53 @@ fn test_npm_uuid_shortcut() { let index_js = cwd.join("node_modules/minimist/index.js"); assert_eq!(git_sha256_file(&index_js), BEFORE_HASH); - // Run with bare UUID (no "get" subcommand). - assert_run_ok(cwd, &[NPM_UUID], "uuid shortcut"); + // Bare UUID (no "get" subcommand): hosted mode, like a bare `get`. + let (stdout, _) = assert_run_ok(cwd, &[NPM_UUID, "--json"], "uuid shortcut"); + let env: serde_json::Value = serde_json::from_str(&stdout) + .unwrap_or_else(|e| panic!("uuid shortcut --json is not JSON ({e}): {stdout}")); + assert_eq!(env["status"], "success", "{env:#}"); + let lock = std::fs::read_to_string(cwd.join("package-lock.json")).unwrap(); + let lock: serde_json::Value = serde_json::from_str(&lock).unwrap(); + let resolved = lock["packages"]["node_modules/minimist"]["resolved"] + .as_str() + .unwrap_or_default(); + assert!( + resolved.starts_with("https://patch.socket.dev/") && resolved.contains(NPM_UUID), + "the shortcut's hosted get pins minimist to the hosted patch, got {resolved:?}" + ); + assert_eq!( + git_sha256_file(&index_js), + BEFORE_HASH, + "hosted mode rewires the lockfile, not the installed tree" + ); + assert!( + !cwd.join(".socket/manifest.json").exists(), + "hosted mode keeps no manifest" + ); + // `--mode agent` passes through the shortcut: in place, with a manifest. + let agent = tempfile::tempdir().unwrap(); + let cwd = agent.path(); + write_package_json(cwd); + npm_run(cwd, &["install", "minimist@1.2.2"]); + let index_js = cwd.join("node_modules/minimist/index.js"); + assert_run_ok( + cwd, + &[NPM_UUID, "--mode", "agent"], + "uuid shortcut --mode agent", + ); assert_eq!( git_sha256_file(&index_js), AFTER_HASH, - "index.js should match afterHash after UUID shortcut" + "index.js should match afterHash after ` --mode agent`" ); - - // The shortcut must behave like `get`: the manifest must actually record - // our patch, not merely exist as an empty stub. let manifest_path = cwd.join(".socket/manifest.json"); - assert!( - manifest_path.exists(), - "manifest should exist after UUID shortcut" - ); let manifest: serde_json::Value = serde_json::from_str(&std::fs::read_to_string(&manifest_path).unwrap()).unwrap(); let patch = &manifest["patches"][NPM_PURL]; assert!( patch.is_object(), - "manifest should contain {NPM_PURL} after UUID shortcut" + "manifest should contain {NPM_PURL} after the agent-mode shortcut" ); assert_eq!(patch["uuid"].as_str().unwrap(), NPM_UUID); } diff --git a/crates/socket-patch-cli/tests/e2e_vendored_production.rs b/crates/socket-patch-cli/tests/e2e_vendored_production.rs index 51a34a20f..11ab221cb 100644 --- a/crates/socket-patch-cli/tests/e2e_vendored_production.rs +++ b/crates/socket-patch-cli/tests/e2e_vendored_production.rs @@ -1493,8 +1493,9 @@ fn berry_skip_code(env: &serde_json::Value) -> String { /// Manifest-less VEX against PRODUCTION for the berry vendored leg, on the /// fresh checkout the real yarn just installed from the committed artifact: -/// with the manifest deleted (ledger online + `--offline`), with the -/// ledger deleted too (lockfile + artifact, record from the public proxy), +/// with no manifest (v5 vendored mode writes none; ledger online + +/// `--offline`), with the ledger deleted too (lockfile + artifact, record +/// from the public proxy), /// `--offline` with nothing local (`record_unavailable`), and a copy whose /// lock + package.json are reverted to the registry while the ledger and /// artifact stay (`vendor_unwired`, even with `--no-verify`). @@ -1508,7 +1509,12 @@ fn yarn_berry_vendored_manifestless_vex( let manifest = fresh.join(".socket/manifest.json"); let ledger_path = fresh.join(".socket/vendor/state.json"); let ledger = std::fs::read(&ledger_path).expect("vendor ledger"); - std::fs::remove_file(&manifest).expect("scan --mode vendored writes a manifest"); + // v5.0 vendored mode is manifest-free: the ledger embeds each entry's + // record, so the checkout is already manifest-less. + assert!( + !manifest.exists(), + "{LEG}: scan --mode vendored writes no .socket/manifest.json" + ); let (code, env, doc) = yarn_berry_vex(fresh, &[]); assert_berry_vendored_attestation(code, &env, doc, &format!("{LEG}: ledger, online"));