Skip to content

Commit d1da4da

Browse files
fix(bun): error on mismatched checksums
1 parent 4946338 commit d1da4da

File tree

2 files changed

+61
-9
lines changed

2 files changed

+61
-9
lines changed

crates/turborepo-lockfiles/src/bun/de.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,17 @@ impl<'de> Deserialize<'de> for PackageEntry {
5050
.pop_front()
5151
.and_then(val_to_info)
5252
.or_else(|| vals.pop_front().and_then(val_to_info));
53+
let checksum = vals.pop_front().and_then(|val| match val {
54+
Vals::Str(sha) => Some(sha),
55+
Vals::Info(_) => None,
56+
});
5357
Ok(Self {
5458
ident: key,
5559
info,
5660
// The rest are only necessary for serializing a lockfile and aren't needed until adding
5761
// `prune` support
5862
registry: None,
59-
checksum: None,
63+
checksum,
6064
root: None,
6165
})
6266
}
@@ -117,7 +121,7 @@ mod test {
117121
.collect(),
118122
..Default::default()
119123
}),
120-
checksum: None,
124+
checksum: Some("sha".into()),
121125
root: None,
122126
}
123127
);

crates/turborepo-lockfiles/src/bun/mod.rs

+55-7
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use crate::Lockfile;
1313
mod de;
1414
mod id;
1515

16-
type Map<K, V> = std::collections::HashMap<K, V>;
16+
type Map<K, V> = std::collections::BTreeMap<K, V>;
1717

1818
#[derive(Debug, thiserror::Error)]
1919
pub enum Error {
@@ -25,12 +25,18 @@ pub enum Error {
2525
Print(#[from] biome_formatter::PrintError),
2626
#[error("Turborepo cannot serialize Bun lockfiles.")]
2727
NotImplemented,
28+
#[error("{ident} had two entries with differing checksums: {sha1}, {sha2}")]
29+
MismatchedShas {
30+
ident: String,
31+
sha1: String,
32+
sha2: String,
33+
},
2834
}
2935

3036
#[derive(Debug)]
3137
pub struct BunLockfile {
3238
data: BunLockfileData,
33-
key_to_entry: Map<String, String>,
39+
key_to_entry: HashMap<String, String>,
3440
}
3541

3642
#[derive(Debug, Deserialize)]
@@ -230,9 +236,22 @@ impl FromStr for BunLockfile {
230236
.map_err(Error::from)?;
231237
let strict_json = format.print().map_err(Error::from)?;
232238
let data: BunLockfileData = serde_json::from_str(strict_json.as_code())?;
233-
let mut key_to_entry = Map::new();
239+
let mut key_to_entry = HashMap::with_capacity(data.packages.len());
234240
for (path, info) in data.packages.iter() {
235-
key_to_entry.insert(info.ident.clone(), path.clone());
241+
if let Some(prev_path) = key_to_entry.insert(info.ident.clone(), path.clone()) {
242+
let prev_info = data
243+
.packages
244+
.get(&prev_path)
245+
.expect("we just got this path from the packages list");
246+
if prev_info.checksum != info.checksum {
247+
return Err(Error::MismatchedShas {
248+
ident: info.ident.clone(),
249+
sha1: prev_info.checksum.clone().unwrap_or_default(),
250+
sha2: info.checksum.clone().unwrap_or_default(),
251+
}
252+
.into());
253+
}
254+
}
236255
}
237256
Ok(Self { data, key_to_entry })
238257
}
@@ -264,6 +283,7 @@ impl PackageInfo {
264283
#[cfg(test)]
265284
mod test {
266285
use pretty_assertions::assert_eq;
286+
use serde_json::json;
267287
use test_case::test_case;
268288

269289
use super::*;
@@ -298,10 +318,13 @@ mod test {
298318
"validate-npm-package-name",
299319
]
300320
.as_slice();
321+
// Both @turbo/gen and log-symbols depend on the same version of chalk
322+
// log-symbols version wins out, but this is okay since they are the same exact
323+
// version of chalk.
301324
const TURBO_GEN_CHALK_DEPS: &[&str] = [
302-
"@turbo/gen/chalk/ansi-styles",
303-
"@turbo/gen/chalk/escape-string-regexp",
304-
"@turbo/gen/chalk/supports-color",
325+
"log-symbols/chalk/ansi-styles",
326+
"log-symbols/chalk/escape-string-regexp",
327+
"log-symbols/chalk/supports-color",
305328
]
306329
.as_slice();
307330
const CHALK_DEPS: &[&str] = ["ansi-styles", "supports-color"].as_slice();
@@ -336,4 +359,29 @@ mod test {
336359
crate::Package::new("[email protected]", "3.0.0+patches/[email protected]")
337360
);
338361
}
362+
363+
#[test]
364+
fn test_failure_if_mismatched_keys() {
365+
let contents = serde_json::to_string(&json!({
366+
"lockfileVersion": 0,
367+
"workspaces": {
368+
"": {
369+
"name": "test",
370+
"dependencies": {
371+
"foo": "^1.0.0",
372+
"bar": "^1.0.0",
373+
}
374+
}
375+
},
376+
"packages": {
377+
"bar": ["[email protected]", { "dependencies": { "shared": "^1.0.0" } }, "sha512-goodbye"],
378+
"bar/shared": ["[email protected]", {}, "sha512-bar"],
379+
"foo": ["[email protected]", { "dependencies": { "shared": "^1.0.0" } }, "sha512-hello"],
380+
"foo/shared": ["[email protected]", { }, "sha512-foo"],
381+
}
382+
}))
383+
.unwrap();
384+
let lockfile = BunLockfile::from_str(&contents);
385+
assert!(lockfile.is_err(), "matching packages have differing shas");
386+
}
339387
}

0 commit comments

Comments
 (0)