Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions crates/socket-patch-cli/CLI_CONTRACT.md

Large diffs are not rendered by default.

58 changes: 58 additions & 0 deletions crates/socket-patch-cli/src/commands/vex_sources.rs
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,10 @@ const NOTE_MAVEN_CLASSIFIER_UNPATCHED: &str = "vex_maven_classifier_unpatched";
/// the crate that names no Socket registry, which cargo resolves as a
/// separate, unpatched package (`vex::Unattested`).
const NOTE_CARGO_UNPINNED_DECLARATION: &str = "vex_cargo_unpinned_declaration";
/// Omission tag and note: a vendored Cargo copy beside a copy of the crate
/// from a source its `[patch]` entry does not redirect (another registry,
/// git), which cargo builds unpatched (`vex::Unattested`).
const NOTE_CARGO_PATCH_BYPASSED: &str = "vex_cargo_patch_bypassed";
/// Omission tag and note: a pnpm lock pins the patch, but a
/// `pnpm-lock.<branch>.yaml` exists, which pnpm installs from instead when
/// `gitBranchLockfile` is on; its presence withholds (`vex::Unattested`).
Expand Down Expand Up @@ -310,6 +314,11 @@ fn unattested_note(kind: UnattestedKind) -> (&'static str, &'static str) {
NOTE_CARGO_UNPINNED_DECLARATION,
"not attested while that declaration stands",
),
UnattestedKind::CargoPatchBypassed => (
NOTE_CARGO_PATCH_BYPASSED,
"not attested while that copy can build beside the vendored one; the vendored \
wiring itself is intact (the warning above says how to clear it)",
),
UnattestedKind::PnpmGitBranchLock => (
NOTE_PNPM_GIT_BRANCH_LOCKFILE,
"not attested while any branch lock exists (or the members that could hold one \
Expand Down Expand Up @@ -2171,6 +2180,55 @@ mod tests {
);
}

/// A vendored Cargo copy beside a copy of the crate its `[patch]`
/// entry does not redirect is omitted as `vex_cargo_patch_bypassed`,
/// the note naming that copy and the remedy.
#[tokio::test]
async fn a_vendored_cargo_copy_beside_a_bypassing_source_is_gated() {
const PURL: &str = "pkg:cargo/serde@1.0.1";
let tmp = tempfile::tempdir().unwrap();
let mut manifest = PatchManifest::new();
manifest.patches.insert(PURL.into(), record(U1));
let vref = vendor_ref(&format!(".socket/vendor/cargo/{U1}/serde-1.0.1")).unwrap();
let mut found = discovery(vec![PatchedRef::vendored(
PURL.into(),
&vref,
"Cargo.toml",
None,
)]);
found.unattested.push(socket_patch_core::vex::Unattested {
purl: PURL.into(),
uuid: U1.into(),
file: "crates/a/Cargo.toml".into(),
detail: "crates/a/Cargo.toml declares serde \"1\" from registry `my-corp`".into(),
kind: UnattestedKind::CargoPatchBypassed,
});
let gated = plan(
&common(tmp.path()),
Sources {
manifest,
vendor: VendorState::new(),
redirect: None,
discovery: found,
},
&[],
&RunApiClient::new(),
)
.await;
assert!(gated.view.patches.is_empty() && gated.hosted.is_empty());
assert_eq!(gated.gated, vec![failed(PURL, NOTE_CARGO_PATCH_BYPASSED)]);
assert!(
gated
.notes
.iter()
.any(|n| n.code == NOTE_CARGO_PATCH_BYPASSED
&& n.detail.contains("from registry `my-corp`")
&& n.detail.contains("says how to clear it")),
"{:?}",
gated.notes
);
}

/// Ledger-only records with no wiring anywhere are gated, except the
/// manifest-owned one, which falls back to agent-mode verification; an
/// in-run confirmed purl is live by construction.
Expand Down
2 changes: 1 addition & 1 deletion crates/socket-patch-core/src/patch/redirect/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2538,7 +2538,7 @@ fn cargo_manifest_package_id(
/// in either the git-index or the sparse spelling. Compared the way cargo's
/// `CanonicalUrl` does: host casing, a trailing `/` and a `.git` suffix do
/// not make a different source (and github paths are case-insensitive).
fn is_crates_io_source(source: &str) -> bool {
pub(crate) fn is_crates_io_source(source: &str) -> bool {
let url = source.trim();
let url = url
.strip_prefix("registry+")
Expand Down
Loading
Loading