Skip to content

Commit d5f09ab

Browse files
committed
Fix Hatch env discovery when VIRTUAL_ENV is set
When VIRTUAL_ENV is set, the code was returning early before reaching Hatch environment discovery, causing Hatch envs to be missed. This meant stale install warnings wouldn't be generated for Hatch projects. The fix adds detection for Hatch projects (via hatch.toml or [tool.hatch] in pyproject.toml) and ignores VIRTUAL_ENV for them, similar to how Poetry and PDM are handled. Hatch never uses VIRTUAL_ENV since 'hatch run' always installs into its own out-of-tree environments.
1 parent f8905e1 commit d5f09ab

130 files changed

Lines changed: 2247 additions & 845 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

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

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,7 @@ use clap::Args;
22
use socket_patch_core::api::blob_fetcher::get_missing_blobs;
33
use socket_patch_core::api::client::{get_api_client_with_overrides, ApiClient};
44
use socket_patch_core::crawlers::ruby_crawler::config_path_ignored_warning;
5-
use socket_patch_core::crawlers::{
6-
detect_npm_pkg_manager, Ecosystem, NpmPkgManager, RubyCrawler,
7-
};
5+
use socket_patch_core::crawlers::{detect_npm_pkg_manager, Ecosystem, NpmPkgManager, RubyCrawler};
86
use socket_patch_core::manifest::operations::read_manifest;
97
use socket_patch_core::manifest::schema::{PatchFileInfo, PatchManifest, PatchRecord};
108
use socket_patch_core::patch::apply::{

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

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -431,7 +431,10 @@ pub async fn run(args: ListArgs) -> i32 {
431431
detail: detail.clone(),
432432
});
433433
} else if !args.common.silent {
434-
eprintln!("Warning: {}", crate::commands::rollback::capitalize_first(detail));
434+
eprintln!(
435+
"Warning: {}",
436+
crate::commands::rollback::capitalize_first(detail)
437+
);
435438
}
436439
}
437440
let vendor_state = crate::commands::vendor_state_lenient(&loaded.vendor, args.common.silent);
@@ -773,12 +776,18 @@ mod tests {
773776
let listings = HostedListing::from_pins(
774777
&[
775778
pin("pkg:npm/minimist@1.2.2", &record.uuid),
776-
pin("pkg:npm/other@1.0.0", "33333333-3333-4333-8333-333333333333"),
779+
pin(
780+
"pkg:npm/other@1.0.0",
781+
"33333333-3333-4333-8333-333333333333",
782+
),
777783
],
778784
Some(&legacy),
779785
);
780786
assert_eq!(listings[0].record, record);
781-
assert_eq!(listings[1].record.uuid, "33333333-3333-4333-8333-333333333333");
787+
assert_eq!(
788+
listings[1].record.uuid,
789+
"33333333-3333-4333-8333-333333333333"
790+
);
782791
assert!(listings[1].record.vulnerabilities.is_empty());
783792
assert_eq!(listings[1].lockfiles, vec!["yarn.lock".to_string()]);
784793
}

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

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
pub mod apply;
22
pub(crate) mod bun_preflight;
3-
pub(crate) mod context;
43
pub(crate) mod composer_hints;
4+
pub(crate) mod context;
55
pub(crate) mod fetch_stage;
66
pub mod get;
77
pub mod hosted_bundle;
88
pub mod list;
99
pub(crate) mod lock_cli;
1010
pub mod remove;
1111
pub mod repair;
12-
pub(crate) mod vendored_backend;
1312
pub mod rollback;
1413
pub mod scan;
1514
pub mod update;
1615
pub mod vendor;
16+
pub(crate) mod vendored_backend;
1717
pub mod vex;
1818
pub(crate) mod vex_consumed;
1919
pub(crate) mod vex_sources;
@@ -141,9 +141,11 @@ pub(crate) async fn hosted_state_from_lockfiles(
141141
common: &crate::args::GlobalArgs,
142142
root: &Path,
143143
) -> socket_patch_core::patch::redirect::RedirectState {
144-
hosted_state_from_pins(&socket_patch_core::patch::redirect::upstream::HostedPin::all(
145-
&discover_wiring(common, root).await,
146-
))
144+
hosted_state_from_pins(
145+
&socket_patch_core::patch::redirect::upstream::HostedPin::all(
146+
&discover_wiring(common, root).await,
147+
),
148+
)
147149
}
148150

149151
/// [`hosted_state_from_lockfiles`] over already-discovered pins. A purl
@@ -153,18 +155,17 @@ pub(crate) fn hosted_state_from_pins(
153155
) -> socket_patch_core::patch::redirect::RedirectState {
154156
let mut state = socket_patch_core::patch::redirect::RedirectState::new();
155157
for pin in pins {
156-
state
157-
.records
158-
.entry(pin.purl.clone())
159-
.or_insert_with(|| socket_patch_core::manifest::schema::PatchRecord {
158+
state.records.entry(pin.purl.clone()).or_insert_with(|| {
159+
socket_patch_core::manifest::schema::PatchRecord {
160160
uuid: pin.uuid.clone(),
161161
exported_at: String::new(),
162162
files: Default::default(),
163163
vulnerabilities: Default::default(),
164164
description: String::new(),
165165
license: String::new(),
166166
tier: String::new(),
167-
});
167+
}
168+
});
168169
}
169170
state
170171
}
@@ -191,4 +192,3 @@ pub(crate) fn vendor_state_lenient(
191192
}
192193
}
193194
}
194-

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ use super::rollback::{
1717
pin_before_hash_blobs, rollback_patches_inner, run_hosted_leg, sweep_failure,
1818
sweep_unused_artifacts, HostedLegOutcome, InnerSelection,
1919
};
20-
use crate::commands::vendored_backend::{RevertedEntry, VendorRevertStep, VendoredBackend};
2120
use crate::args::{apply_env_toggles, GlobalArgs};
2221
use crate::commands::lock_cli::acquire_or_emit;
22+
use crate::commands::vendored_backend::{RevertedEntry, VendorRevertStep, VendoredBackend};
2323
use crate::json_envelope::{Command, Envelope, EnvelopeError, PatchAction, PatchEvent, Status};
2424
use crate::ui::plural;
2525

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

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@ use socket_patch_core::manifest::operations::{
1010
};
1111
use socket_patch_core::manifest::schema::{PatchFileInfo, PatchManifest, PatchRecord};
1212
use socket_patch_core::patch::apply::select_installed_variants;
13+
use socket_patch_core::patch::redirect::upstream::HostedPin;
1314
use socket_patch_core::patch::rollback::{
1415
cannot_rollback_error, rollback_package_patch, verify_file_rollback, RollbackResult,
1516
VerifyRollbackResult, VerifyRollbackStatus,
1617
};
1718
use socket_patch_core::telemetry::{track_patch_rollback_failed, track_patch_rolled_back};
1819
use socket_patch_core::utils::purl::{patch_matches, strip_purl_qualifiers};
19-
use socket_patch_core::patch::redirect::upstream::HostedPin;
2020
use socket_patch_core::vendor::{purl_keys_cover, RevertOpts, VendorState};
2121
use std::collections::{HashMap, HashSet};
2222
use std::path::{Path, PathBuf};
@@ -1026,7 +1026,8 @@ pub(crate) async fn run_hosted_leg(common: &GlobalArgs, pins: &[HostedPin]) -> H
10261026
.iter()
10271027
.map(|(code, detail)| (code.to_string(), detail.clone())),
10281028
);
1029-
out.edited_files.extend(outcome.reverted_files.iter().cloned());
1029+
out.edited_files
1030+
.extend(outcome.reverted_files.iter().cloned());
10301031
let unwound: Vec<_> = vlt_targets
10311032
.into_iter()
10321033
.filter(|t| out.reverted.iter().any(|p| p == &t.purl))
@@ -1170,7 +1171,11 @@ pub async fn run(args: RollbackArgs) -> i32 {
11701171
} else if !args.common.silent {
11711172
println!(
11721173
"{} the pre-v5 hosted ledger {}: no lockfile pins a hosted patch.",
1173-
if args.common.dry_run { "Would remove" } else { "Removed" },
1174+
if args.common.dry_run {
1175+
"Would remove"
1176+
} else {
1177+
"Removed"
1178+
},
11741179
socket_patch_core::patch::redirect::REDIRECT_STATE_REL
11751180
);
11761181
}

‎crates/socket-patch-cli/src/commands/scan/discovery.rs‎

Lines changed: 36 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -168,29 +168,32 @@ pub(crate) async fn vendored_ledger_supplement(
168168
}
169169
// `(ledger key, base purl, entry)`; the artifact fallback has no
170170
// entries to probe, so it never reports unwired keys.
171-
let candidates: Vec<(String, String, Option<&socket_patch_core::vendor::VendorEntry>)> =
172-
match state {
173-
Ok(state) => state
174-
.entries
175-
.iter()
176-
.map(|(key, entry)| {
177-
(
178-
key.clone(),
179-
strip_purl_qualifiers(&entry.base_purl).to_string(),
180-
Some(entry),
181-
)
182-
})
183-
.collect(),
184-
// Corrupt/unreadable ledger (a MISSING file is Ok(empty) above):
185-
// recover the vendored set from the committed artifacts, or
186-
// `scan --prune` (whose ledger exemption also degrades to empty)
187-
// would delete still-vendored packages' manifest entries and blobs.
188-
Err(_) => vendored_purls_from_artifacts(common)
189-
.await
190-
.into_iter()
191-
.map(|base| (base.clone(), base, None))
192-
.collect(),
193-
};
171+
let candidates: Vec<(
172+
String,
173+
String,
174+
Option<&socket_patch_core::vendor::VendorEntry>,
175+
)> = match state {
176+
Ok(state) => state
177+
.entries
178+
.iter()
179+
.map(|(key, entry)| {
180+
(
181+
key.clone(),
182+
strip_purl_qualifiers(&entry.base_purl).to_string(),
183+
Some(entry),
184+
)
185+
})
186+
.collect(),
187+
// Corrupt/unreadable ledger (a MISSING file is Ok(empty) above):
188+
// recover the vendored set from the committed artifacts, or
189+
// `scan --prune` (whose ledger exemption also degrades to empty)
190+
// would delete still-vendored packages' manifest entries and blobs.
191+
Err(_) => vendored_purls_from_artifacts(common)
192+
.await
193+
.into_iter()
194+
.map(|base| (base.clone(), base, None))
195+
.collect(),
196+
};
194197
// Composer by release identity: a ledger `@3.0.2.0` is the crawled
195198
// `@3.0.2`, not a second package to supplement.
196199
let key = |p: &str| composer_purl_identity(p).unwrap_or_else(|| normalize_purl(p).into_owned());
@@ -1038,7 +1041,9 @@ mod tests {
10381041
..GlobalArgs::default()
10391042
};
10401043
let state = socket_patch_core::vendor::load_state(root).await;
1041-
vendored_ledger_supplement(&args, crawled, &state).await.packages
1044+
vendored_ledger_supplement(&args, crawled, &state)
1045+
.await
1046+
.packages
10421047
}
10431048

10441049
/// A ledger entry vendored as `@3.0.2.0` is the crawled composer
@@ -1073,7 +1078,9 @@ mod tests {
10731078
out.iter().map(|p| &p.purl).collect::<Vec<_>>()
10741079
);
10751080

1076-
let out = vendored_ledger_supplement(&args, &[], &Ok(state)).await.packages;
1081+
let out = vendored_ledger_supplement(&args, &[], &Ok(state))
1082+
.await
1083+
.packages;
10771084
assert_eq!(
10781085
out.iter().map(|p| p.purl.as_str()).collect::<Vec<_>>(),
10791086
vec!["pkg:composer/psr/log@3.0.2.0"]
@@ -1176,7 +1183,10 @@ mod tests {
11761183
let state = npm_ledger_with_lock(tmp.path(), lock.as_deref()).await;
11771184
let out = vendored_ledger_supplement(&args, &[], &state).await;
11781185
assert_eq!(
1179-
out.packages.iter().map(|p| p.purl.as_str()).collect::<Vec<_>>(),
1186+
out.packages
1187+
.iter()
1188+
.map(|p| p.purl.as_str())
1189+
.collect::<Vec<_>>(),
11801190
vec!["pkg:npm/left-pad@1.3.0"],
11811191
"lock={lock:?}"
11821192
);

‎crates/socket-patch-cli/src/commands/scan/hosted.rs‎

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -932,7 +932,8 @@ pub(crate) async fn run_redirect_selected(
932932
socket_patch_core::utils::fs::read_regular_to_string_sync(path).ok()
933933
})
934934
};
935-
let rewrite_options = || RewriteOptions {
935+
let rewrite_options = || {
936+
RewriteOptions {
936937
dry_run: common.dry_run,
937938
targets_pipenv_lock,
938939
pipenv_major,
@@ -944,6 +945,7 @@ pub(crate) async fn run_redirect_selected(
944945
npm_allow_remote_config: !common.no_npm_allow_remote_config,
945946
npm_outer: &npm_outer,
946947
blocking: true,
948+
}
947949
};
948950
// The rollout gate plans again without its deferred rows: keep what
949951
// the second pass needs.
@@ -2304,13 +2306,19 @@ fn join_names(names: &[String], max: usize) -> String {
23042306
/// artifacts, then verify with `vex`. After a vendored→hosted takeover
23052307
/// (`vendored_removed`) the commit also has to carry the deleted vendored
23062308
/// ledger entries and artifacts.
2307-
fn format_next_steps(files: &[String], edits: &[socket_patch_core::patch::redirect::FileEdit], vendored_removed: bool) -> Vec<String> {
2309+
fn format_next_steps(
2310+
files: &[String],
2311+
edits: &[socket_patch_core::patch::redirect::FileEdit],
2312+
vendored_removed: bool,
2313+
) -> Vec<String> {
23082314
if files.is_empty() && !vendored_removed {
23092315
return Vec::new();
23102316
}
23112317
let mut commit: Vec<String> = Vec::new();
23122318
if vendored_removed {
2313-
commit.push(".socket/vendor/ (the removed vendored ledger entries and artifacts)".to_string());
2319+
commit.push(
2320+
".socket/vendor/ (the removed vendored ledger entries and artifacts)".to_string(),
2321+
);
23142322
}
23152323
commit.extend(files.iter().cloned());
23162324
let npm = files
@@ -4391,19 +4399,43 @@ mod tests {
43914399
use super::npm_allow_remote_one_line;
43924400
let hosts = ["patch.socket.dev"];
43934401
let cases = [
4394-
(npm_allow_remote_configured_detail(&hosts, true, false), "Note: set"),
4395-
(npm_allow_remote_configured_detail(&hosts, false, false), "Note: set"),
4396-
(npm_allow_remote_configured_detail(&hosts, true, true), "Note: would set"),
4397-
(npm_allow_remote_already_detail(&hosts), "Note: .npmrc already"),
4398-
(npm_allow_remote_user_set_detail(&hosts, "none"), "Warning: npm >=12"),
4399-
(npm_allow_remote_env_set_detail(&hosts, "npm_config_allow_remote", "none"), "Warning: npm >=12"),
4402+
(
4403+
npm_allow_remote_configured_detail(&hosts, true, false),
4404+
"Note: set",
4405+
),
4406+
(
4407+
npm_allow_remote_configured_detail(&hosts, false, false),
4408+
"Note: set",
4409+
),
4410+
(
4411+
npm_allow_remote_configured_detail(&hosts, true, true),
4412+
"Note: would set",
4413+
),
4414+
(
4415+
npm_allow_remote_already_detail(&hosts),
4416+
"Note: .npmrc already",
4417+
),
4418+
(
4419+
npm_allow_remote_user_set_detail(&hosts, "none"),
4420+
"Warning: npm >=12",
4421+
),
4422+
(
4423+
npm_allow_remote_env_set_detail(&hosts, "npm_config_allow_remote", "none"),
4424+
"Warning: npm >=12",
4425+
),
44004426
(npm_allow_remote_manual_detail(&hosts), "Warning: npm >=12"),
4401-
(npm_allow_remote_unreadable_detail(&hosts, "is a symlink"), "Warning: npm >=12"),
4427+
(
4428+
npm_allow_remote_unreadable_detail(&hosts, "is a symlink"),
4429+
"Warning: npm >=12",
4430+
),
44024431
];
44034432
for (detail, start) in cases {
44044433
let line = npm_allow_remote_one_line(&detail);
44054434
assert!(line.starts_with(start), "{line}");
4406-
assert!(!line.contains('\n') && line.ends_with("(details: --verbose)."), "{line}");
4435+
assert!(
4436+
!line.contains('\n') && line.ends_with("(details: --verbose)."),
4437+
"{line}"
4438+
);
44074439
}
44084440
}
44094441
}

0 commit comments

Comments
 (0)