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
6 changes: 1 addition & 5 deletions crates/socket-patch-core/src/vendor/lock_inventory/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,7 @@
//! with no installed copy ([`super::registry_fetch`]), verifying the bytes
//! against the integrity the lock records — FAIL-CLOSED: an entry whose
//! lock carries no content verifier is never fetched;
//! * `repair` recovers ledger entries ([`recover_lock_entry`]) and the pin a
//! rewired lock records for a vendored artifact
//! ([`wired_vendor_integrity`]);
//! * `repair` recovers ledger entries ([`recover_lock_entry`]);
//! * ledger liveness (`vex::discover`) reads EVERY lock's instance
//! ([`inventory_project_every_lock`]) as evidence that a package resolves
//! from somewhere other than its patch.
Expand Down Expand Up @@ -66,7 +64,6 @@ pub(crate) mod pypi;
pub(crate) mod recover;
pub mod view;
pub(crate) mod vlt;
pub(crate) mod wired;
pub(crate) mod yarn;

pub use self::bun::{bun_binary_lock_drives, bun_text_lock_drives};
Expand All @@ -79,7 +76,6 @@ pub(crate) use self::npm_family::inventory_npm_lock;
pub(crate) use self::pypi::pipfile_lock_entries;
pub use self::recover::recover_lock_entry;
pub use self::view::{DiskSnapshot, MemoryEntry, MemoryProject, ProjectView, ReadSet};
pub use self::wired::wired_vendor_integrity;

// The per-format views `inventory_project_diagnosed` unions (and the test
// modules reach through `super::*`).
Expand Down
220 changes: 4 additions & 216 deletions crates/socket-patch-core/src/vendor/lock_inventory/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -470,54 +470,6 @@ async fn bun_binary_inventory_works_without_an_install_or_runtime() {
}
}

#[tokio::test]
async fn bun_binary_vendor_integrity_follows_live_package_records() {
let bytes = include_bytes!("../../../tests/fixtures/bun-lockb/1.1.45/bun.lockb");
let mut lock = super::super::bun_lockb::BunLockb::parse(bytes).unwrap();
let package = lock
.packages()
.unwrap()
.into_iter()
.find(|package| package.name == "minimist")
.unwrap();
let tmp = tempfile::tempdir().unwrap();
let rel = ".socket/vendor/npm/11111111-1111-4111-8111-111111111111/minimist-1.2.2.tgz";
let first = format!("sha512-{}", "A".repeat(86) + "==");
lock.set_package(package.id, rel, &first).unwrap();
tokio::fs::write(tmp.path().join("bun.lockb"), lock.bytes())
.await
.unwrap();
assert_eq!(
wired_vendor_integrity(tmp.path(), rel).await,
Some(LockIntegrity::Sri(first))
);
let next = rel.replace(
"11111111-1111-4111-8111-111111111111",
"22222222-2222-4222-8222-222222222222",
);
lock.set_package(
package.id,
&next,
&format!("sha512-{}", "A".repeat(86) + "=="),
)
.unwrap();
tokio::fs::write(tmp.path().join("bun.lockb"), lock.bytes())
.await
.unwrap();
assert_eq!(
wired_vendor_integrity(tmp.path(), rel).await,
None,
"retired strings are not active resolutions"
);
assert!(wired_vendor_integrity(tmp.path(), &next).await.is_some());
write(tmp.path(), "bun.lock", BUN_LOCK).await;
assert_eq!(
wired_vendor_integrity(tmp.path(), &next).await,
None,
"text lock takes precedence"
);
}

/// A pnpm-lock.yaml whose lockfileVersion the probe refuses — pnpm 6
/// wrote 5.3; only 5.4/6.0/9.0 route to a backend. This is the shape
/// that reaches the version-refusal discovery fallback, where a live
Expand Down Expand Up @@ -1792,35 +1744,6 @@ async fn inventories_script_and_pylock_files_without_installed_packages() {
assert!(!entries.iter().any(|entry| entry.name == "local"));
}

#[tokio::test]
async fn pylock_repair_uses_the_exact_artifact_hash_and_refuses_conflicts() {
let tmp = tempfile::tempdir().unwrap();
let path = ".socket/vendor/pypi/uuid/alpha-1-py3-none-any.whl";
let sha = "a".repeat(64);
let pylock = format!("lock-version='1.0'\n[[packages]]\nname='alpha'\nversion='1'\narchive={{path='{path}',hashes={{sha256='{sha}'}}}}\n");
write(tmp.path(), "pylock.toml", &pylock).await;
assert_eq!(
wired_vendor_integrity(tmp.path(), path).await,
Some(LockIntegrity::Sha256Hex(sha.clone()))
);
assert_eq!(
wired_vendor_integrity(tmp.path(), &format!("{path}.other")).await,
None
);
write(tmp.path(), "example.py.lock", &format!("version=1\n[[package]]\nname='alpha'\nversion='1'\nsource={{path='{path}'}}\nwheels=[{{filename='alpha-1-py3-none-any.whl',hash='sha256:{sha}'}}]\n")).await;
assert_eq!(
wired_vendor_integrity(tmp.path(), path).await,
Some(LockIntegrity::Sha256Hex(sha.clone()))
);
write(
tmp.path(),
"pylock.toml",
&pylock.replace(&sha, &"b".repeat(64)),
)
.await;
assert_eq!(wired_vendor_integrity(tmp.path(), path).await, None);
}

#[test]
fn legacy_and_pep751_archive_hashes_stay_with_their_own_wheels() {
let sha = "b".repeat(64);
Expand Down Expand Up @@ -2276,8 +2199,7 @@ async fn fifo_lockfiles_fail_fast_instead_of_wedging() {
let root = tmp.path().to_path_buf();
// Every filename this module opens: the per-ecosystem inventories,
// the npm-family readers (reached without the flavor probe touching
// the same file via the shrinkwrap/sibling/rush fallbacks), and
// wired_vendor_integrity (no probe at all).
// the same file via the shrinkwrap/sibling/rush fallbacks).
let names = [
"Cargo.lock",
"go.sum",
Expand Down Expand Up @@ -2317,7 +2239,6 @@ async fn fifo_lockfiles_fail_fast_instead_of_wedging() {
inventory_vlt(&root).await,
inventory_pnpm_lock_at(&root.join("shrinkwrap.yaml")).await,
gem_remotes(&root).await,
wired_vendor_integrity(&root, ".socket/vendor/npm/x/x.tgz").await,
)
};
let Ok(results) = tokio::time::timeout(deadline, all).await else {
Expand All @@ -2330,22 +2251,8 @@ async fn fifo_lockfiles_fail_fast_instead_of_wedging() {
}
panic!("lockfile inventories must fail fast on FIFO lockfiles");
};
let (
cargo,
go,
composer,
gem,
pypi,
npm,
pnpm,
yarn_c,
yarn_b,
bun,
vlt,
legacy,
remotes,
wired,
) = results;
let (cargo, go, composer, gem, pypi, npm, pnpm, yarn_c, yarn_b, bun, vlt, legacy, remotes) =
results;
for (label, opt) in [
("cargo", cargo),
("go", go),
Expand All @@ -2366,7 +2273,6 @@ async fn fifo_lockfiles_fail_fast_instead_of_wedging() {
);
}
assert!(remotes.is_empty(), "{remotes:?}");
assert!(wired.is_none(), "{wired:?}");
}

#[tokio::test]
Expand Down Expand Up @@ -2972,119 +2878,6 @@ async fn pure_wheel_rejects_short_hash_missing_hash_and_non_http_url() {
assert_eq!(pure_wheel_from_uv_unit(&ftp), None, "non-http url");
}

/// The yarn-classic `integrity <sri>` branch of `wired_vendor_integrity`
/// — the trust anchor for repair's no-ledger reconstruction on
/// yarn-classic projects (rewired classic locks carry exactly this
/// line). Rides along fail-soft: an unparseable JSON lock and a v1 lock
/// without a `packages` map are both skipped, not fatal.
#[tokio::test]
async fn wired_vendor_integrity_reads_rewired_yarn_classic_and_skips_bad_json_locks() {
let tmp = tempfile::tempdir().unwrap();
let rel = ".socket/vendor/npm/9f6b2c4e-1d3a-4f6b-8c2d-7e5a9b1c3d5f/left-pad-1.3.0.tgz";
// Unparseable JSON lock: skipped fail-soft.
write(tmp.path(), "npm-shrinkwrap.json", "not json").await;
// v1 lock without a packages map: skipped fail-soft.
write(
tmp.path(),
"package-lock.json",
r#"{"lockfileVersion":1,"dependencies":{}}"#,
)
.await;
// The rewired classic block, exactly as yarn_classic_lock rewires it.
write(
tmp.path(),
"yarn.lock",
&format!(
"# yarn lockfile v1\n\n\
\"left-pad@file:./{rel}\":\n \
version \"1.3.0\"\n \
resolved \"file:./{rel}#0000000000000000000000000000000000000000\"\n \
integrity sha512-ours==\n"
),
)
.await;

assert_eq!(
wired_vendor_integrity(tmp.path(), rel).await,
Some(LockIntegrity::Sri("sha512-ours==".into())),
"the classic `integrity <sri>` line is the wired trust anchor"
);
}

/// The yarn / bun branches of `wired_vendor_integrity` read the entry
/// models lockfile discovery reads, not a line window: a berry block whose
/// carried sections push `checksum:` far below the reference, yarn 4.0.x's
/// bare-hex checksum, a CRLF classic lock, a shadowed classic block (yarn
/// keeps the last one) and bun's digest-less re-save (which must never
/// borrow the next tuple's sha512).
#[tokio::test]
async fn wired_vendor_integrity_reads_yarn_and_bun_entries_structurally() {
let rel = ".socket/vendor/npm/9f6b2c4e-1d3a-4f6b-8c2d-7e5a9b1c3d5f/left-pad-1.3.0.tgz";
let hex = "ab".repeat(64);
let berry = |checksum: &str| {
format!(
"__metadata:\n version: 8\n cacheKey: 10c0\n\n\
\"left-pad@file:./{rel}::locator=app%40workspace%3A.\":\n \
version: 1.3.0\n \
resolution: \"left-pad@file:./{rel}#./{rel}::hash=abc&locator=app%40workspace%3A.\"\n \
dependencies:\n a: \"npm:1.0.0\"\n b: \"npm:1.0.0\"\n c: \"npm:1.0.0\"\n d: \"npm:1.0.0\"\n e: \"npm:1.0.0\"\n \
checksum: {checksum}\n \
languageName: node\n \
linkType: hard\n"
)
};
for (checksum, want) in [
(format!("10c0/{hex}"), format!("10c0/{hex}")),
(hex.clone(), format!("10c0/{hex}")),
] {
let tmp = tempfile::tempdir().unwrap();
write(tmp.path(), "yarn.lock", &berry(&checksum)).await;
assert_eq!(
wired_vendor_integrity(tmp.path(), rel).await,
Some(LockIntegrity::BerryChecksum(want)),
"{checksum}"
);
}

let classic = |key: &str, sri: &str| {
format!(
"{key}:\n version \"1.3.0\"\n resolved \"file:./{rel}#0000000000000000000000000000000000000000\"\n integrity {sri}\n"
)
};
let tmp = tempfile::tempdir().unwrap();
let lock = format!(
"# yarn lockfile v1\n\n{}\n{}",
classic("left-pad@^1.3.0", "sha512-shadowed=="),
classic("left-pad@^1.3.0", "sha512-live==")
)
.replace('\n', "\r\n");
write(tmp.path(), "yarn.lock", &lock).await;
assert_eq!(
wired_vendor_integrity(tmp.path(), rel).await,
Some(LockIntegrity::Sri("sha512-live==".into())),
"the live (last) block of a CRLF lock"
);

let bun = |ours: &str| {
format!(
"{{\n \"lockfileVersion\": 1,\n \"workspaces\": {{\n \"\": {{\n \"name\": \"app\",\n }},\n }},\n \"packages\": {{\n \"left-pad\": [\"left-pad@./{rel}\", {{}}{ours}],\n\n \"right-pad\": [\"right-pad@1.0.0\", \"\", {{}}, \"sha512-theirs==\"],\n }}\n}}\n"
)
};
let tmp = tempfile::tempdir().unwrap();
write(tmp.path(), "bun.lock", &bun(", \"sha512-ours==\"")).await;
assert_eq!(
wired_vendor_integrity(tmp.path(), rel).await,
Some(LockIntegrity::Sri("sha512-ours==".into()))
);
let tmp = tempfile::tempdir().unwrap();
write(tmp.path(), "bun.lock", &bun("")).await;
assert_eq!(
wired_vendor_integrity(tmp.path(), rel).await,
None,
"a digest-less re-save pins nothing"
);
}

/// `PnpmPackage::resolution_tokens` exposes the raw `resolution:` value the
/// grammar refused (a nested map, a duplicate key, a wrapped flow map), so
/// lockfile discovery can still tell a Socket-shaped entry from anything
Expand Down Expand Up @@ -3768,8 +3561,7 @@ async fn requirements_index_option_in_an_include_spans_the_tree() {
/// dangling `bun.lock` link is absent to it and it installs from the
/// `bun.lockb` beside it (verified with Bun 1.2.23 and 1.3.14:
/// `bun install --frozen-lockfile` installs from the binary lock). The
/// inventory, the wired-integrity probe and vendored routing must all pick
/// `bun.lockb` too, instead of losing every package of the live lock.
/// inventory and vendored routing must both pick `bun.lockb` too, instead of losing every package of the live lock.
#[cfg(unix)]
#[tokio::test]
async fn bun_dangling_text_lock_link_leaves_the_binary_lock_live() {
Expand Down Expand Up @@ -3797,10 +3589,6 @@ async fn bun_dangling_text_lock_link_leaves_the_binary_lock_live() {
vec![("is-number".into(), "7.0.0".into())],
"the binary lock's registry packages (minimist is vendored)"
);
assert_eq!(
wired_vendor_integrity(tmp.path(), rel).await,
Some(LockIntegrity::Sri(sri))
);
assert!(super::super::bun_lock::binary_lock_drives(tmp.path()));
// The hosted engine's view-level answer (disk and snapshot) agrees.
assert!(!bun_text_lock_drives(&ProjectView::Disk(tmp.path())));
Expand Down
Loading
Loading