Skip to content

Commit b8b7752

Browse files
mikolalysenkoclaude
andcommitted
Merge origin/main into agent/fix-gem-takeover-declaration-preflight
Brings in the vex_consumed alias test fix (#849) that main's red test/test-release/coverage jobs were waiting on. Co-Authored-By: Claude <noreply@anthropic.com>
2 parents 5b14678 + 99f61d2 commit b8b7752

31 files changed

Lines changed: 2025 additions & 340 deletions

‎AGENTS.md‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Agent instructions
2+
3+
## CHANGELOG.md is written only at release time
4+
5+
Don't add, edit or delete entries in `CHANGELOG.md` in a feature, fix,
6+
refactor, CI or docs PR, even if a doc, template or reviewer asks for one.
7+
The `[Unreleased]` section is written when a release is cut, by the release
8+
agent, from the PRs merged since the last tag and the code itself. Put the
9+
details of a change in its commit messages and PR description instead.
10+
11+
If a PR you work on already changes `CHANGELOG.md`, restore that file to its
12+
merge-base version. The only exceptions are release PRs: a `release/v*`
13+
branch, or the release train's `release-sync` PR.

‎CHANGELOG.md‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,11 @@ Pre-v3.0 entries are concise summaries derived from each tag's commit
99
history. For full per-release detail, see the
1010
[GitHub releases page](https://github.com/SocketDev/socket-patch/releases).
1111

12-
Add entries under `[Unreleased]`; its `###` headings set the next version's
13-
bump (Breaking/Removed → major, Added/Changed/Deprecated → minor, anything
14-
else → patch). Releases are cut by the release train
12+
PRs never edit this file. Only the release agent writes `[Unreleased]`, at
13+
release time, from the PRs merged since the last tag and the code they
14+
changed. Its `###` headings set the next version's bump (Breaking/Removed →
15+
major, Added/Changed/Deprecated → minor, anything else → patch). Releases
16+
are cut by the release train
1517
([docs/release-train/DESIGN.md](docs/release-train/DESIGN.md)) with
1618
`scripts/release.py`: a release candidate's `[Unreleased]` entries become a
1719
`## [X.Y.Z-rc.N]` section, the rolling `release-sync` PR brings each cut

‎CLAUDE.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
@AGENTS.md

‎crates/socket-patch-cli/src/commands/vex_consumed.rs‎

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -715,8 +715,11 @@ mod tests {
715715
None,
716716
)
717717
.await;
718-
assert_eq!(installed_again, installed);
719-
let (paths, calls) = tracked_npm_hosted(&common, &installed_again).await;
718+
// Since #605 the name-keyed resolver probes bundled trees itself, so
719+
// it already returns the aliases and the nested store's peers. Feed
720+
// the earlier, alias-free set to keep exercising alias expansion;
721+
// the resolver's own set is checked against the same result below.
722+
let (paths, calls) = tracked_npm_hosted(&common, &installed).await;
720723
assert_eq!(calls.len(), 1);
721724
let mut inputs = calls[0].clone();
722725
inputs.sort();
@@ -738,6 +741,9 @@ mod tests {
738741
.len(),
739742
paths.len()
740743
);
744+
let (mut resolved, _) = tracked_npm_hosted(&common, &installed_again).await;
745+
resolved.sort();
746+
assert_eq!(resolved, expected, "the resolver's own copy set");
741747
}
742748

743749
#[cfg(unix)]
@@ -768,14 +774,19 @@ mod tests {
768774
None,
769775
)
770776
.await;
771-
assert!(installed.is_empty(), "{installed:?}");
772-
let (mut paths, calls) = tracked_npm_hosted(&common, &installed).await;
777+
// Since #605 the name-keyed resolver reaches the alias and its
778+
// sibling peers on its own. An alias-only set (what an alias-blind
779+
// resolver returns) must still expand to the same copies.
780+
let (mut paths, calls) = tracked_npm_hosted(&common, &HashMap::new()).await;
773781
assert_eq!(calls, vec![vec![alias.clone()]]);
774782
let mut expected = peers;
775783
expected.push(alias);
776784
paths.sort();
777785
expected.sort();
778786
assert_eq!(paths, expected);
787+
let (mut resolved, _) = tracked_npm_hosted(&common, &installed).await;
788+
resolved.sort();
789+
assert_eq!(resolved, expected, "the resolver's own copy set");
779790
}
780791

781792
#[cfg(unix)]

‎crates/socket-patch-cli/tests/cli/api_client_errors_e2e.rs‎

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
//! failure into a fake success fails loudly.
77
88
use std::path::{Path, PathBuf};
9-
use std::process::Command;
109

1110
use wiremock::matchers::{method, path};
1211
use wiremock::{Mock, MockServer, ResponseTemplate};
@@ -116,7 +115,7 @@ async fn get_uuid_with_401_falls_back_to_proxy() {
116115
.await;
117116

118117
let tmp = tempfile::tempdir().unwrap();
119-
let out = Command::new(binary())
118+
let out = crate::common::hermetic_command(&binary())
120119
.args([
121120
"get",
122121
UUID,
@@ -199,7 +198,7 @@ async fn get_uuid_with_500_reports_error() {
199198
.await;
200199

201200
let tmp = tempfile::tempdir().unwrap();
202-
let out = Command::new(binary())
201+
let out = crate::common::hermetic_command(&binary())
203202
.args([
204203
"get",
205204
UUID,
@@ -239,7 +238,7 @@ async fn get_uuid_with_malformed_json_reports_parse_error() {
239238
.await;
240239

241240
let tmp = tempfile::tempdir().unwrap();
242-
let out = Command::new(binary())
241+
let out = crate::common::hermetic_command(&binary())
243242
.args([
244243
"get",
245244
UUID,
@@ -281,7 +280,7 @@ async fn scan_with_400_bad_request_reports_failure() {
281280
write_root(tmp.path());
282281
write_npm_package(tmp.path(), "foo");
283282

284-
let out = Command::new(binary())
283+
let out = crate::common::hermetic_command(&binary())
285284
.args([
286285
"scan",
287286
"--json",
@@ -323,7 +322,7 @@ async fn scan_with_400_bad_request_reports_failure() {
323322
async fn get_with_unreachable_api_url_reports_error() {
324323
let tmp = tempfile::tempdir().unwrap();
325324
// Port 1 is reserved and reliably refuses connections.
326-
let out = Command::new(binary())
325+
let out = crate::common::hermetic_command(&binary())
327326
.args([
328327
"get",
329328
UUID,
@@ -354,7 +353,7 @@ async fn scan_with_unreachable_api_url_reports_failure() {
354353
write_root(tmp.path());
355354
write_npm_package(tmp.path(), "bar");
356355

357-
let out = Command::new(binary())
356+
let out = crate::common::hermetic_command(&binary())
358357
.args([
359358
"scan",
360359
"--json",
@@ -397,7 +396,7 @@ async fn get_by_cve_with_500_reports_error() {
397396
.await;
398397

399398
let tmp = tempfile::tempdir().unwrap();
400-
let out = Command::new(binary())
399+
let out = crate::common::hermetic_command(&binary())
401400
.args([
402401
"get",
403402
cve,
@@ -434,7 +433,7 @@ async fn get_by_ghsa_with_404_reports_not_found() {
434433
.await;
435434

436435
let tmp = tempfile::tempdir().unwrap();
437-
let out = Command::new(binary())
436+
let out = crate::common::hermetic_command(&binary())
438437
.args([
439438
"get",
440439
ghsa,
@@ -510,7 +509,7 @@ async fn repair_with_blob_404_marks_failure_in_summary() {
510509
)
511510
.unwrap();
512511

513-
let out = Command::new(binary())
512+
let out = crate::common::hermetic_command(&binary())
514513
.args([
515514
"repair",
516515
"--json",

‎crates/socket-patch-cli/tests/cli/cli_dry_run_paths_e2e.rs‎

Lines changed: 10 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
//! dry-run flag-propagation branches each command's `run` has.
55
66
use std::path::{Path, PathBuf};
7-
use std::process::Command;
87

98
use sha2::{Digest, Sha256};
109

@@ -95,11 +94,9 @@ fn make_applicable_npm_patch(root: &Path) {
9594
fn apply_dry_run_empty_manifest_emits_dry_run_envelope() {
9695
let tmp = tempfile::tempdir().expect("tempdir");
9796
make_socket_with_empty_manifest(tmp.path());
98-
let out = Command::new(binary())
97+
let out = crate::common::hermetic_command(&binary())
9998
.args(["apply", "--json", "--dry-run"])
10099
.current_dir(tmp.path())
101-
.env_remove("SOCKET_API_TOKEN")
102-
.env_remove("SOCKET_CLI_API_TOKEN")
103100
.output()
104101
.expect("run apply");
105102
let stdout = String::from_utf8_lossy(&out.stdout);
@@ -165,11 +162,9 @@ fn apply_dry_run_with_real_patch_verifies_without_mutating() {
165162
);
166163

167164
// ---- DRY RUN ----
168-
let out = Command::new(binary())
165+
let out = crate::common::hermetic_command(&binary())
169166
.args(["apply", "--json", "--dry-run", "--offline"])
170167
.current_dir(tmp.path())
171-
.env_remove("SOCKET_API_TOKEN")
172-
.env_remove("SOCKET_CLI_API_TOKEN")
173168
.output()
174169
.expect("run apply --dry-run");
175170
let stdout = String::from_utf8_lossy(&out.stdout);
@@ -249,11 +244,9 @@ fn apply_dry_run_with_real_patch_verifies_without_mutating() {
249244
// This guarantees the dry-run assertions above are non-vacuous: the
250245
// patch really is applicable, so "nothing changed" under --dry-run is a
251246
// meaningful result rather than an artifact of an inapplicable fixture.
252-
let out2 = Command::new(binary())
247+
let out2 = crate::common::hermetic_command(&binary())
253248
.args(["apply", "--json", "--offline"])
254249
.current_dir(tmp.path())
255-
.env_remove("SOCKET_API_TOKEN")
256-
.env_remove("SOCKET_CLI_API_TOKEN")
257250
.output()
258251
.expect("run apply (real)");
259252
let stdout2 = String::from_utf8_lossy(&out2.stdout);
@@ -335,11 +328,9 @@ fn apply_dry_run_human_count_excludes_vendored() {
335328
// Prove the fixture is non-vacuous first: in JSON mode the vendored
336329
// entry must classify as skipped/vendored (if the vendor ledger were
337330
// unreadable it would fail open and this test would assert nothing).
338-
let out = Command::new(binary())
331+
let out = crate::common::hermetic_command(&binary())
339332
.args(["apply", "--json", "--dry-run", "--offline"])
340333
.current_dir(tmp.path())
341-
.env_remove("SOCKET_API_TOKEN")
342-
.env_remove("SOCKET_CLI_API_TOKEN")
343334
.output()
344335
.expect("run apply --json --dry-run");
345336
let stdout = String::from_utf8_lossy(&out.stdout);
@@ -366,11 +357,9 @@ fn apply_dry_run_human_count_excludes_vendored() {
366357

367358
// The human summary must agree with that classification: only the
368359
// genuinely applicable package counts as patchable.
369-
let out = Command::new(binary())
360+
let out = crate::common::hermetic_command(&binary())
370361
.args(["apply", "--dry-run", "--offline"])
371362
.current_dir(tmp.path())
372-
.env_remove("SOCKET_API_TOKEN")
373-
.env_remove("SOCKET_CLI_API_TOKEN")
374363
.output()
375364
.expect("run apply --dry-run");
376365
assert_eq!(out.status.code(), Some(0));
@@ -387,11 +376,9 @@ fn apply_dry_run_human_count_excludes_vendored() {
387376
fn repair_dry_run_offline_emits_dry_run_envelope() {
388377
let tmp = tempfile::tempdir().expect("tempdir");
389378
make_socket_with_empty_manifest(tmp.path());
390-
let out = Command::new(binary())
379+
let out = crate::common::hermetic_command(&binary())
391380
.args(["repair", "--json", "--dry-run", "--offline"])
392381
.current_dir(tmp.path())
393-
.env_remove("SOCKET_API_TOKEN")
394-
.env_remove("SOCKET_CLI_API_TOKEN")
395382
.output()
396383
.expect("run repair");
397384
let stdout = String::from_utf8_lossy(&out.stdout);
@@ -415,11 +402,9 @@ fn repair_dry_run_offline_emits_dry_run_envelope() {
415402
fn rollback_with_empty_manifest_emits_envelope() {
416403
let tmp = tempfile::tempdir().expect("tempdir");
417404
make_socket_with_empty_manifest(tmp.path());
418-
let out = Command::new(binary())
405+
let out = crate::common::hermetic_command(&binary())
419406
.args(["rollback", "--json", "--offline"])
420407
.current_dir(tmp.path())
421-
.env_remove("SOCKET_API_TOKEN")
422-
.env_remove("SOCKET_CLI_API_TOKEN")
423408
.output()
424409
.expect("run rollback");
425410
let stdout = String::from_utf8_lossy(&out.stdout);
@@ -449,7 +434,7 @@ fn rollback_with_empty_manifest_emits_envelope() {
449434
fn remove_with_no_socket_dir_emits_manifest_not_found() {
450435
let tmp = tempfile::tempdir().expect("tempdir");
451436
// NO .socket/ directory at all.
452-
let out = Command::new(binary())
437+
let out = crate::common::hermetic_command(&binary())
453438
.args([
454439
"remove",
455440
"11111111-1111-4111-8111-111111111111",
@@ -458,8 +443,6 @@ fn remove_with_no_socket_dir_emits_manifest_not_found() {
458443
"--skip-rollback",
459444
])
460445
.current_dir(tmp.path())
461-
.env_remove("SOCKET_API_TOKEN")
462-
.env_remove("SOCKET_CLI_API_TOKEN")
463446
.output()
464447
.expect("run remove");
465448
let stdout = String::from_utf8_lossy(&out.stdout);
@@ -483,11 +466,9 @@ fn remove_with_no_socket_dir_emits_manifest_not_found() {
483466
fn list_with_empty_manifest_emits_empty_envelope() {
484467
let tmp = tempfile::tempdir().expect("tempdir");
485468
make_socket_with_empty_manifest(tmp.path());
486-
let out = Command::new(binary())
469+
let out = crate::common::hermetic_command(&binary())
487470
.args(["list", "--json"])
488471
.current_dir(tmp.path())
489-
.env_remove("SOCKET_API_TOKEN")
490-
.env_remove("SOCKET_CLI_API_TOKEN")
491472
.output()
492473
.expect("run list");
493474
let stdout = String::from_utf8_lossy(&out.stdout);
@@ -511,11 +492,9 @@ fn list_with_empty_manifest_emits_empty_envelope() {
511492
#[test]
512493
fn apply_silent_no_manifest_produces_no_output() {
513494
let tmp = tempfile::tempdir().expect("tempdir");
514-
let out = Command::new(binary())
495+
let out = crate::common::hermetic_command(&binary())
515496
.args(["apply", "--silent"])
516497
.current_dir(tmp.path())
517-
.env_remove("SOCKET_API_TOKEN")
518-
.env_remove("SOCKET_CLI_API_TOKEN")
519498
.output()
520499
.expect("run apply");
521500
assert_eq!(out.status.code(), Some(0));

‎crates/socket-patch-cli/tests/cli_parse_remove.rs‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ use socket_patch_cli::commands::remove::{run, RemoveArgs};
1212
use socket_patch_cli::{Cli, Commands};
1313
use std::path::PathBuf;
1414

15+
#[path = "common/hermetic.rs"]
16+
mod hermetic;
17+
1518
fn parse_remove(extra: &[&str]) -> RemoveArgs {
1619
let mut argv = vec!["socket-patch", "remove"];
1720
argv.extend_from_slice(extra);
@@ -335,7 +338,7 @@ fn record_json(uuid: &str) -> String {
335338
/// Run the compiled `socket-patch remove` binary against `cwd`, fully offline
336339
/// and with telemetry disabled so the test never touches the network.
337340
fn run_remove_binary(cwd: &std::path::Path, extra: &[&str]) -> std::process::Output {
338-
std::process::Command::new(env!("CARGO_BIN_EXE_socket-patch"))
341+
hermetic::binary_command()
339342
.arg("remove")
340343
.arg("--cwd")
341344
.arg(cwd)

0 commit comments

Comments
 (0)