Skip to content

Commit 661c117

Browse files
committed
Stop uv projects scanning the system Python
A fresh uv checkout (uv.lock with no .venv synced yet, or a UV_PROJECT_ENVIRONMENT that doesn't exist yet) and a directory holding only PEP 723 script locks fell back to the global site-packages. Every OS-Python package then joined the candidate set, so a vendored scan tried to vendor packages the project never depends on and exited 1 with pypi_uv_lock_package_missing. uv only ever installs such a project into its own env, and the lock already supplies the lock-only packages, so the crawl now returns no env for it. A uv.lock shared with Poetry, PDM or Pipenv files keeps the old fallback. Fixes #964 Assisted-by: Claude Code:claude-opus-5-5
1 parent b6d0416 commit 661c117

121 files changed

Lines changed: 2400 additions & 842 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/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/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());
@@ -1045,7 +1048,9 @@ mod tests {
10451048
..GlobalArgs::default()
10461049
};
10471050
let state = socket_patch_core::vendor::load_state(root).await;
1048-
vendored_ledger_supplement(&args, crawled, &state).await.packages
1051+
vendored_ledger_supplement(&args, crawled, &state)
1052+
.await
1053+
.packages
10491054
}
10501055

10511056
/// A ledger entry vendored as `@3.0.2.0` is the crawled composer
@@ -1080,7 +1085,9 @@ mod tests {
10801085
out.iter().map(|p| &p.purl).collect::<Vec<_>>()
10811086
);
10821087

1083-
let out = vendored_ledger_supplement(&args, &[], &Ok(state)).await.packages;
1088+
let out = vendored_ledger_supplement(&args, &[], &Ok(state))
1089+
.await
1090+
.packages;
10841091
assert_eq!(
10851092
out.iter().map(|p| p.purl.as_str()).collect::<Vec<_>>(),
10861093
vec!["pkg:composer/psr/log@3.0.2.0"]
@@ -1183,7 +1190,10 @@ mod tests {
11831190
let state = npm_ledger_with_lock(tmp.path(), lock.as_deref()).await;
11841191
let out = vendored_ledger_supplement(&args, &[], &state).await;
11851192
assert_eq!(
1186-
out.packages.iter().map(|p| p.purl.as_str()).collect::<Vec<_>>(),
1193+
out.packages
1194+
.iter()
1195+
.map(|p| p.purl.as_str())
1196+
.collect::<Vec<_>>(),
11871197
vec!["pkg:npm/left-pad@1.3.0"],
11881198
"lock={lock:?}"
11891199
);

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

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -982,7 +982,8 @@ pub(crate) async fn run_redirect_selected(
982982
socket_patch_core::utils::fs::read_regular_to_string_sync(path).ok()
983983
})
984984
};
985-
let rewrite_options = || RewriteOptions {
985+
let rewrite_options = || {
986+
RewriteOptions {
986987
dry_run: common.dry_run,
987988
targets_pipenv_lock,
988989
pipenv_major,
@@ -994,6 +995,7 @@ pub(crate) async fn run_redirect_selected(
994995
npm_allow_remote_config: !common.no_npm_allow_remote_config,
995996
npm_outer: &npm_outer,
996997
blocking: true,
998+
}
997999
};
9981000
// The rollout gate plans again without its deferred rows: keep what
9991001
// the second pass needs.
@@ -2431,13 +2433,19 @@ fn join_names(names: &[String], max: usize) -> String {
24312433
/// artifacts, then verify with `vex`. After a vendored→hosted takeover
24322434
/// (`vendored_removed`) the commit also has to carry the deleted vendored
24332435
/// ledger entries and artifacts.
2434-
fn format_next_steps(files: &[String], edits: &[socket_patch_core::patch::redirect::FileEdit], vendored_removed: bool) -> Vec<String> {
2436+
fn format_next_steps(
2437+
files: &[String],
2438+
edits: &[socket_patch_core::patch::redirect::FileEdit],
2439+
vendored_removed: bool,
2440+
) -> Vec<String> {
24352441
if files.is_empty() && !vendored_removed {
24362442
return Vec::new();
24372443
}
24382444
let mut commit: Vec<String> = Vec::new();
24392445
if vendored_removed {
2440-
commit.push(".socket/vendor/ (the removed vendored ledger entries and artifacts)".to_string());
2446+
commit.push(
2447+
".socket/vendor/ (the removed vendored ledger entries and artifacts)".to_string(),
2448+
);
24412449
}
24422450
commit.extend(files.iter().cloned());
24432451
let npm = files
@@ -4624,19 +4632,43 @@ mod tests {
46244632
use super::npm_allow_remote_one_line;
46254633
let hosts = ["patch.socket.dev"];
46264634
let cases = [
4627-
(npm_allow_remote_configured_detail(&hosts, true, false), "Note: set"),
4628-
(npm_allow_remote_configured_detail(&hosts, false, false), "Note: set"),
4629-
(npm_allow_remote_configured_detail(&hosts, true, true), "Note: would set"),
4630-
(npm_allow_remote_already_detail(&hosts), "Note: .npmrc already"),
4631-
(npm_allow_remote_user_set_detail(&hosts, "none"), "Warning: npm >=12"),
4632-
(npm_allow_remote_env_set_detail(&hosts, "npm_config_allow_remote", "none"), "Warning: npm >=12"),
4635+
(
4636+
npm_allow_remote_configured_detail(&hosts, true, false),
4637+
"Note: set",
4638+
),
4639+
(
4640+
npm_allow_remote_configured_detail(&hosts, false, false),
4641+
"Note: set",
4642+
),
4643+
(
4644+
npm_allow_remote_configured_detail(&hosts, true, true),
4645+
"Note: would set",
4646+
),
4647+
(
4648+
npm_allow_remote_already_detail(&hosts),
4649+
"Note: .npmrc already",
4650+
),
4651+
(
4652+
npm_allow_remote_user_set_detail(&hosts, "none"),
4653+
"Warning: npm >=12",
4654+
),
4655+
(
4656+
npm_allow_remote_env_set_detail(&hosts, "npm_config_allow_remote", "none"),
4657+
"Warning: npm >=12",
4658+
),
46334659
(npm_allow_remote_manual_detail(&hosts), "Warning: npm >=12"),
4634-
(npm_allow_remote_unreadable_detail(&hosts, "is a symlink"), "Warning: npm >=12"),
4660+
(
4661+
npm_allow_remote_unreadable_detail(&hosts, "is a symlink"),
4662+
"Warning: npm >=12",
4663+
),
46354664
];
46364665
for (detail, start) in cases {
46374666
let line = npm_allow_remote_one_line(&detail);
46384667
assert!(line.starts_with(start), "{line}");
4639-
assert!(!line.contains('\n') && line.ends_with("(details: --verbose)."), "{line}");
4668+
assert!(
4669+
!line.contains('\n') && line.ends_with("(details: --verbose)."),
4670+
"{line}"
4671+
);
46404672
}
46414673
}
46424674
}

0 commit comments

Comments
 (0)