Skip to content

Commit

Permalink
Fix downloads for @yarnpkg/cli-dist (#647)
Browse files Browse the repository at this point in the history
* Fix downloads for @yarnpkg/cli-dist

The changes to make this download script work for both `npm` and `yarn` distributions [#612](#612) has a bug where the requested distribution (`yarn`) differs from its package name if the version is `>=2` (`@yarnpkg/cli-dist`) and that wasn't accounted for in the name of the download file.

The `curl` command that downloads the tarball should have been saving to `yarn-v{x.y.z}.tar.gz` but was instead saving to `@yarnpkg/cli-dist-v{x.y.z}.tar.gz`. This is causing automation failures (e.g.; https://github.com/heroku/buildpacks-nodejs/actions/runs/6179740345/job/16775160336)

This PR keeps the `distribution_name` and `package_name` separate so this mismatch will no longer happen.

It also:
- adds some extra logging which would have made the error more obvious
- DRYS up the `npm_url`, ``tarball_url`, and `downloaded_tarball` which previously were being inlined into commands
- adds retries and timeouts to `curl`
  • Loading branch information
colincasey authored Sep 18, 2023
1 parent 9dd679d commit 6cbd518
Showing 1 changed file with 14 additions and 10 deletions.
24 changes: 14 additions & 10 deletions common/bin/download-verify-npm-package
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
set -o pipefail
set -e

package_name=$1
if [ "npm" != "${package_name}" ] && [ "yarn" != "${package_name}" ]; then
echo "Unrecognized distribution - ${package_name}"
distribution_name=$1
if [ "npm" != "${distribution_name}" ] && [ "yarn" != "${distribution_name}" ]; then
echo "Unrecognized distribution - ${distribution_name}"
exit 1
fi

Expand All @@ -19,28 +19,32 @@ if [ -z "$package_version" ]; then
exit 1
fi

package_name="${distribution_name}"
if [ "yarn" = "${package_name}" ]; then
# Yarn 2+ (aka: "berry") is hosted under a different npm package.
major_version=$(echo "$package_version" | cut -d "." -f 1)
package_name=$([ "$major_version" -ge 2 ] && echo "@yarnpkg/cli-dist" || echo "yarn")
fi

npm_url="https://registry.npmjs.com/${package_name}/${package_version}"

echo "Determining dist url from ${npm_url}" >&2
url=$(curl -sSf "${npm_url}" | jq -r '.dist.tarball')

echo "Downloading ${package_name} tarball from ${url} ..." >&2
curl -sSf -o "./${package_name}-v${package_version}.tar.gz" "${url}"
tarball_url=$(curl --silent --show-error --fail --retry 5 --retry-all-errors --connect-timeout 10 --max-time 60 "${npm_url}" | jq -r '.dist.tarball')
echo "Downloading ${package_name} tarball from ${tarball_url} ..." >&2

downloaded_tarball="./${distribution_name}-v${package_version}.tar.gz"
echo "Saving as ${downloaded_tarball}" >&2

curl --silent --show-error --fail --retry 5 --retry-all-errors --connect-timeout 10 --max-time 60 --output "${downloaded_tarball}" "${tarball_url}"

# Check the file's sha against npm's published sha. This section assumes all
# packages are published with sha512. That was true at the time of writing,
# but if npmjs.org starts using additional checksum algorithms, this section
# will need to be changed.
echo "Checking ${package_name} tarball integrity..." >&2
shasum=$(shasum -b -a 512 "${package_name}"-v"${package_version}".tar.gz | awk '{ print $1 }' | xxd -r -p | base64 | tr -d "\n")
shasum=$(shasum -b -a 512 "${downloaded_tarball}" | awk '{ print $1 }' | xxd -r -p | base64 | tr -d "\n")
actual_integrity="sha512-${shasum}"
published_integrity=$(curl -sSf "https://registry.npmjs.com/${package_name}/${package_version}" | jq -r '.dist.integrity')
published_integrity=$(curl --silent --show-error --fail --retry 5 --retry-all-errors --connect-timeout 10 --max-time 60 "${npm_url}" | jq -r '.dist.integrity')
if [ "$actual_integrity" != "$published_integrity" ]; then
echo "Couldn't verify package integrity. Expected '$published_integrity', got '$actual_integrity'." >&2
exit 1
Expand All @@ -56,7 +60,7 @@ npm_pubkey="MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE1Olb3zMAFFxXKHiIkQO5cJ3Yhl5i6UPp
printf -- '-----BEGIN PUBLIC KEY-----\n%s\n-----END PUBLIC KEY-----\n' "$npm_pubkey" >npm-pubkey.pem

# Fetch the signature from the published package data
curl -sSf "https://registry.npmjs.com/${package_name}/${package_version}" | jq -r '.dist.signatures[0].sig' | base64 -d >npm-signature.bin
curl --silent --show-error --fail --retry 5 --retry-all-errors --connect-timeout 10 --max-time 60 "${npm_url}" | jq -r '.dist.signatures[0].sig' | base64 -d >npm-signature.bin

# Build the signing message
echo -n "${package_name}@${package_version}:${published_integrity}" >message.txt
Expand Down

0 comments on commit 6cbd518

Please sign in to comment.