Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix yarn lockfile with unknown resolvers #345

Merged
merged 4 commits into from
May 5, 2022
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
87 changes: 67 additions & 20 deletions cli/src/lockfiles/javascript.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,32 +100,65 @@ impl Parseable for YarnLock {
.get(&"resolution".into())
.and_then(YamlValue::as_str)
.filter(|s| !s.is_empty())
.ok_or_else(|| anyhow!("Failed to parse resolution field in yarn lock file"))?;
.ok_or_else(|| anyhow!("Failed to parse yarn resolution field"))?;

let (name, mut resolver) = match resolution[1..].split_once('@') {
Some((name, resolver)) => (&resolution[..name.len() + 1], resolver.to_owned()),
None => {
return Err(anyhow!(
"Failed to parse yarn resolution field for '{}'",
resolution
))
}
};

// Ignore workspace-local dependencies like project itself ("project@workspace:.").
if resolution[1..].contains("@workspace:") {
continue;
// Extract original resolver from patch.
if let Some((_, patch)) = resolver.split_once("patch:") {
// Exctract resolver from `@scope/package@RESOLVER#patch`.
let patch = patch[1..].split_once('@');
let subresolver = patch.and_then(|(_, resolver)| resolver.split_once('#'));
resolver = match subresolver {
Some((resolver, _)) => resolver.to_owned(),
None => {
return Err(anyhow!(
"Failed to parse yarn patch dependency for '{}'",
resolution
))
}
};

// Revert character replacements.
resolver = resolver.replace("%3A", ":");
resolver = resolver.replace("%23", "#");
resolver = resolver.replace("%25", "%");
}

let (name, _version) = match resolution[1..].split_once("@patch:") {
// Extract npm version from patched dependencies.
Some((_, patch)) => patch
.rsplit_once("@npm")
.ok_or_else(|| anyhow!("Failed to parse patch in yarn lock file"))?,
None => resolution
.rsplit_once("@npm")
.ok_or_else(|| anyhow!("Failed to parse name in yarn lock file"))?,
let (name, version) = if resolver.starts_with("workspace:") {
// Ignore filesystem dependencies like the project ("project@workspace:.").
continue;
} else if resolver.starts_with("npm:") {
let version = package
.get(&"version".into())
.and_then(YamlValue::as_str)
.ok_or_else(|| anyhow!("Failed to parse yarn version for '{}'", resolution))?;

(name, version.to_owned())
} else if resolver.starts_with("http:")
|| resolver.starts_with("https:")
|| resolver.starts_with("ssh:")
{
(name, resolver)
} else {
return Err(anyhow!(
"Failed to parse yarn dependency resolver for '{}'",
resolution
));
};

let version = package
.get(&"version".into())
.and_then(YamlValue::as_str)
.ok_or_else(|| anyhow!("Failed to parse version in yarn lock file"))?;

packages.push(PackageDescriptor {
name: name.to_owned(),
version: version.to_owned(),
package_type: PackageType::Npm,
name: name.to_owned(),
version,
});
}

Expand Down Expand Up @@ -213,7 +246,7 @@ mod tests {

let pkgs = parser.parse().unwrap();

assert_eq!(pkgs.len(), 51);
assert_eq!(pkgs.len(), 53);

let expected_pkgs = [
PackageDescriptor {
Expand All @@ -236,6 +269,20 @@ mod tests {
version: "1.2.3".into(),
package_type: PackageType::Npm,
},
PackageDescriptor {
name: "ethereumjs-abi".into(),
version: "https://github.com/ethereumjs/ethereumjs-abi.git\
#commit=ee3994657fa7a427238e6ba92a84d0b529bbcde0"
.into(),
package_type: PackageType::Npm,
},
PackageDescriptor {
name: "@me/remote-patch".into(),
version: "ssh://git@github.com:phylum/remote-patch\
#commit=d854c43ea177d1faeea56189249fff8c24a764bd"
.into(),
package_type: PackageType::Npm,
},
];

for expected_pkg in expected_pkgs {
Expand Down
14 changes: 14 additions & 0 deletions cli/tests/fixtures/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -470,3 +470,17 @@ __metadata:
checksum: ae0123222c6df65b437669d63dfa8c36cee20a504101b2fcd97b8bf76f91259c17f9f2b4d70a1e3c6bbcee7f51b28392833adb6b2770b23b01abec84e369660b
languageName: node
linkType: hard

"ethereumjs-abi@git+https://github.com/ethereumjs/ethereumjs-abi.git":
version: 0.6.8
resolution: "ethereumjs-abi@https://github.com/ethereumjs/ethereumjs-abi.git#commit=ee3994657fa7a427238e6ba92a84d0b529bbcde0"
checksum: ae074be0bb012857ab5d3ae644d1163b908a48dd724b7d2567cfde309dc72222d460438f2411936a70dc949dc604ce1ef7118f7273bd525815579143c907e336
languageName: node
linkType: hard

"@me/remote-patch@patch:@me/remote-patch@ssh://git@github.com:phylum/remote-patch#commit=d854c43ea177d1faeea56189249fff8c24a764bd#.yarn/patches/@me-remote-patch-0deadbeef0::locator=root%40workspace%3A.":
version: 1.2.3
resolution: "@me/remote-patch@patch:@me/remote-patch@ssh%3A//git@github.com%3Aphylum/remote-patch%23commit=d854c43ea177d1faeea56189249fff8c24a764bd#.yarn/patches/@me-remote-patch-0deadbeef0::version=1.2.3&hash=ff00ff&locator=root%40workspace%3A."
checksum: ae0123222c6df65b437669d63dfa8c36cee20a504101b2fcd97b8bf76f91259c17f9f2b4d70a1e3c6bbcee7f51b28392833adb6b2770b23b01abec84e369660b
languageName: node
linkType: hard