├── CODEOWNERS ├── bin └── install_node ├── cache ├── v0 │ └── node-versions ├── v1 │ └── node-versions ├── v2 │ └── node-versions └── v3 │ └── node-versions ├── cloudformation └── install-node-build-user.template ├── package.json ├── readme.md └── util ├── recache └── test /CODEOWNERS: -------------------------------------------------------------------------------- 1 | # global owners 2 | * @mapbox/data-platform 3 | -------------------------------------------------------------------------------- /bin/install_node: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -eu 3 | 4 | bin_only="false" 5 | 6 | if [ -n "${INSTALL_NODE_URL+1}" ]; then 7 | INSTALL_NODE_URL=$INSTALL_NODE_URL 8 | else 9 | INSTALL_NODE_URL="https://s3.amazonaws.com/mapbox/vendor/nodejs" 10 | fi 11 | 12 | if [ -z "${NV+1}" -o -z "${NP+1}" -o -z "${OD+1}" ]; then 13 | node_version=$1 14 | platformarch=$2 15 | output_dir=$3 16 | if [ -n "${4+1}" ]; then 17 | bin_only=$4 18 | fi 19 | else 20 | node_version=$NV 21 | platformarch=$NP 22 | output_dir=$OD 23 | if [ -n "${BO+1}" ]; then 24 | bin_only=$BO 25 | fi 26 | fi 27 | 28 | # Enforce default arch for legacy arch-free args. 29 | case $platformarch in 30 | "linux") 31 | platformarch="linux-x64" 32 | ;; 33 | "darwin") 34 | platformarch="darwin-x64" 35 | ;; 36 | esac 37 | 38 | # Output info about requested range and resolved node version 39 | echo "Requested node version: $node_version" 40 | echo "Requested node platform+arch: $platformarch" 41 | 42 | if [ "$bin_only" = "true" ]; then 43 | echo "Requested bin only: $bin_only" 44 | fi 45 | 46 | case $platformarch in 47 | "linux-x64") 48 | url="$INSTALL_NODE_URL/v$node_version/node-v$node_version-linux-x64.tar.gz" 49 | ;; 50 | "darwin-x64") 51 | url="$INSTALL_NODE_URL/v$node_version/node-v$node_version-darwin-x64.tar.gz" 52 | ;; 53 | *) 54 | echo "Not a valid platform+arch. Specify one of linux-x64|darwin-x64" 55 | exit 1 56 | ;; 57 | esac 58 | 59 | tmp="$(mktemp -d -t install-node.XXXXXX)" 60 | trap "rm -rf $tmp" EXIT 61 | 62 | cd "$tmp" 63 | 64 | # Download node 65 | if type curl > /dev/null; then 66 | curl -Lsfo $(basename $url) "$url" 67 | elif type wget > /dev/null; then 68 | wget -qO $(basename $url) "$url" 69 | else 70 | echo "Either curl or wget required for install-node" 71 | exit 1 72 | fi 73 | 74 | # Install node 75 | if [ "$bin_only" = "true" ]; then 76 | tar --strip 2 -xzf "node-v$node_version-$platformarch.tar.gz" --directory "$output_dir" "node-v$node_version-$platformarch/bin/node" 77 | else 78 | tar --strip-components 1 -xzf "node-v$node_version-$platformarch.tar.gz" --no-same-owner --directory "$output_dir" 79 | # Change the location of the npm cache so different versions of node don't interfere with each other 80 | mkdir -p "$output_dir/.npm" 81 | echo "cache=$output_dir/.npm" >> "$output_dir/lib/node_modules/npm/npmrc" 82 | fi 83 | -------------------------------------------------------------------------------- /cache/v0/node-versions: -------------------------------------------------------------------------------- 1 | 0.10.20 2 | 0.10.21 3 | 0.10.22 4 | 0.10.23 5 | 0.10.24 6 | 0.10.25 7 | 0.10.26 8 | 0.10.27 9 | 0.10.28 10 | 0.10.30 11 | 0.10.31 12 | 0.10.32 13 | 0.10.33 14 | 0.8.21 15 | 0.8.22 16 | 0.8.23 17 | 0.8.24 18 | 0.8.25 19 | 0.8.26 20 | -------------------------------------------------------------------------------- /cache/v1/node-versions: -------------------------------------------------------------------------------- 1 | 0.12.7 2 | 0.12.2 3 | 0.12.0 4 | 0.10.40 5 | 0.10.39 6 | 0.10.38 7 | 0.10.20 8 | 0.10.21 9 | 0.10.22 10 | 0.10.23 11 | 0.10.24 12 | 0.10.25 13 | 0.10.26 14 | 0.10.27 15 | 0.10.28 16 | 0.10.30 17 | 0.10.31 18 | 0.10.32 19 | 0.10.33 20 | 0.8.26 21 | 0.8.25 22 | 0.8.24 23 | 0.8.23 24 | 0.8.22 25 | 0.8.21 26 | -------------------------------------------------------------------------------- /cache/v2/node-versions: -------------------------------------------------------------------------------- 1 | 8.14.0 2 | 8.11.2 3 | 6.15.0 4 | 6.11.1 5 | 6.10.3 6 | 6.10.2 7 | 6.10.0 8 | 6.0.0 9 | 5.10.0 10 | 5.2.0 11 | 5.1.1 12 | 5.1.0 13 | 5.0.0 14 | 4.8.7 15 | 4.8.4 16 | 4.8.2 17 | 4.4.3 18 | 4.4.2 19 | 4.4.0 20 | 4.3.2 21 | 4.3.1 22 | 4.3.0 23 | 4.2.6 24 | 4.2.5 25 | 4.2.4 26 | 4.2.3 27 | 4.2.2 28 | 4.2.1 29 | 4.2.0 30 | 4.1.2 31 | 4.1.1 32 | 4.1.0 33 | 4.0.0 34 | 0.12.13 35 | 0.12.9 36 | 0.12.8 37 | 0.12.7 38 | 0.12.2 39 | 0.12.0 40 | 0.10.44 41 | 0.10.42 42 | 0.10.41 43 | 0.10.40 44 | 0.10.39 45 | 0.10.38 46 | 0.10.20 47 | 0.10.21 48 | 0.10.22 49 | 0.10.23 50 | 0.10.24 51 | 0.10.25 52 | 0.10.26 53 | 0.10.27 54 | 0.10.28 55 | 0.10.30 56 | 0.10.31 57 | 0.10.32 58 | 0.10.33 59 | 0.8.26 60 | 0.8.25 61 | 0.8.24 62 | 0.8.23 63 | 0.8.22 64 | 0.8.21 65 | -------------------------------------------------------------------------------- /cache/v3/node-versions: -------------------------------------------------------------------------------- 1 | 20.7.0 2 | 20.2.0 3 | 18.18.0 4 | 18.16.0 5 | 18.9.0 6 | 16.20.2 7 | 16.20.0 8 | 16.17.0 9 | 14.16.0 10 | 14.15.4 11 | 14.15.1 12 | 12.0.0 13 | 12.1.0 14 | 12.2.0 15 | 12.15.0 16 | 12.18.4 17 | 12.20.0 18 | 10.13.0 19 | 10.14.0 20 | 10.14.1 21 | 10.14.2 22 | 10.15.0 23 | 10.15.1 24 | 10.15.2 25 | 10.15.3 26 | 10.19.0 27 | 8.9.0 28 | 8.9.1 29 | 8.9.2 30 | 8.9.3 31 | 8.9.4 32 | 8.10.0 33 | 8.11.0 34 | 8.11.1 35 | 8.11.2 36 | 8.11.3 37 | 8.11.4 38 | 8.12.0 39 | 8.13.0 40 | 8.14.0 41 | 8.14.1 42 | 8.15.0 43 | 8.15.1 44 | 8.16.0 45 | -------------------------------------------------------------------------------- /cloudformation/install-node-build-user.template: -------------------------------------------------------------------------------- 1 | { 2 | "AWSTemplateFormatVersion": "2010-09-09", 3 | "Description": "Travis user for building install-node", 4 | "Resources": { 5 | "InstallNodeCacheUser": { 6 | "Type": "AWS::IAM::User", 7 | "Properties": { 8 | "Path": "/service/", 9 | "Policies": [ 10 | { 11 | "PolicyName": "install-node-cache", 12 | "PolicyDocument": { 13 | "Statement": [ 14 | { 15 | "Action": [ 16 | "s3:PutObject", 17 | "s3:PutObjectAcl" 18 | ], 19 | "Effect": "Allow", 20 | "Resource": [ 21 | "arn:aws:s3:::mapbox/vendor/nodejs/*", 22 | "arn:aws:s3:::mapbox/apps/install-node/*" 23 | ] 24 | } 25 | ] 26 | } 27 | } 28 | ] 29 | } 30 | }, 31 | "InstallNodeCacheKey": { 32 | "Type": "AWS::IAM::AccessKey", 33 | "Properties": { 34 | "UserName": { 35 | "Ref": "InstallNodeCacheUser" 36 | } 37 | } 38 | } 39 | }, 40 | "Outputs": { 41 | "BuildAccessKeyId": { 42 | "Value": { 43 | "Ref": "InstallNodeCacheKey" 44 | } 45 | }, 46 | "BuildSecretAccessKey": { 47 | "Value": { 48 | "Fn::GetAtt": [ 49 | "InstallNodeCacheKey", 50 | "SecretAccessKey" 51 | ] 52 | } 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "install-node", 3 | "version": "3.0.1", 4 | "description": "Install node.js", 5 | "author": "Mapbox", 6 | "license": "ISC", 7 | "private": true, 8 | "bin": { 9 | "install_node": "./bin/install_node" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # install_node 2 | 3 | [![Build Status](https://travis-ci.com/mapbox/install-node.svg?branch=master)](https://travis-ci.com/mapbox/install-node) 4 | 5 | A bash script to install a version of node.js for a platform of your choosing, without depending on nodejs.org being available. 6 | 7 | In addition, nodejs binaries cached by Mapbox have had their signatures and shasums verified before being cached. 8 | 9 | ## Install and run from S3 10 | 11 | The latest version of the `install-node` script is always available at `https://mapbox.s3.amazonaws.com/apps/install-node/latest/run`. Versioned `install-node` scripts are still available at `https://mapbox.s3.amazonaws.com/apps/install-node/v{VERSION}/run`, but the latest version is recommended. 12 | 13 | You should install the script from S3 with `curl` or `wget` and run it, specifying parameters as environment variables: 14 | 15 | ``` 16 | $ curl https://mapbox.s3.amazonaws.com/apps/install-node/latest/run | NV=16.17.0 NP=linux-x64 OD=/usr/local sh 17 | ``` 18 | 19 | ## Usage 20 | 21 | ``` 22 | $ install_node [bin_only=true|false] 23 | ``` 24 | 25 | Please note this script uses nodejs compiled binaries, so will not work on Linux distributions using alternative `libc` implementations such as Alpine Linux. nodejs should be compiled from source on those systems. 26 | 27 | This will find the corresponding node.js version for the requested `platform+arch` (one of `linux-x64` or `darwin-x64` and drop it into the specified `dir`. 28 | 29 | If the optional fourth `bin_only` arg is set to `true` then only the node binary will be installed instead of npm and related resources (headers, man pages, etc.) 30 | 31 | *Note: the legacy platform (without arch) arguments `linux`, `darwin` are mapped to the following for backwards compatibility.* 32 | 33 | legacy platform arg | platform+arch 34 | --- | --- 35 | linux | linux-x64 36 | darwin | darwin-x64 37 | 38 | **Mirror URL** 39 | 40 | By default `install_node` will download node from a Mapbox S3 mirror of x64 versions of node. 41 | 42 | You can point `install_node` add the official node dist endpoint or your own mirror by using the `INSTALL_NODE_URL` env var. 43 | 44 | When using a custom nodejs mirror url, please note that the `install_node` script itself does not perform any validation or verification of the download. 45 | 46 | ``` 47 | $ INSTALL_NODE_URL=http://nodejs.org/dist install_node v14.16.0 linux-x64 /usr/local 48 | ``` 49 | 50 | ## Allowed Versions 51 | 52 | All versions of nodejs cached by Mapbox are available using any version of the `install-node` script. The most current list of LTS and current nodejs releases cached is available at https://github.com/mapbox/install-node/blob/master/cache/v3/node-versions 53 | 54 | ## Adding new versions 55 | 56 | Update the v3 cache file, and on commit, new versions added will be cached by the Travis CI job. 57 | 58 | ## v3 Changes 59 | 60 | - Deprecated Windows support 61 | - Carbon LTS (v8) and later only 62 | - Updated nodejs team package signatures 63 | 64 | ## CI Builds 65 | - We have disabled Travis CI integration and are no longer running builds 66 | - Node versions that were already stashed on s3 will remain 67 | -------------------------------------------------------------------------------- /util/recache: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | # check version of install-node 5 | install_v=$(node -e "console.log(($(cat $(dirname $0)/../package.json)).version.split('.')[0])") 6 | 7 | main_file="$(dirname $0)/../bin/install_node" 8 | version_file="$(dirname $0)/../cache/v${install_v}/node-versions" 9 | versions=( $(cat "$version_file") ) 10 | dest="s3://mapbox/vendor/nodejs" 11 | apps_dest="s3://mapbox/apps/install-node" 12 | tmp=$(mktemp -d -t install-node.XXXXXX) 13 | gitsha=$(cd $(dirname $0) && git rev-parse HEAD) 14 | 15 | function cachefile() { 16 | local filename=$1 17 | local localname=$(echo $1 | tr '/' '-') 18 | local nv=$2 19 | 20 | if wget -q -O $localname "https://nodejs.org/dist/v$nv/$filename"; then 21 | md5sum "$localname" > "$localname.md5" 22 | else 23 | echo "$filename not found at https://nodejs.org/dist/v$nv/$filename" && return 0 24 | fi 25 | 26 | # RHEL/centos7 does not ship with a parent shasum function. 27 | # Fallback to sha1sum if not found. 28 | shasum="" 29 | if which shasum > /dev/null; then 30 | shasum=$(which shasum) 31 | elif which sha1sum > /dev/null; then 32 | shasum=$(which sha1sum) 33 | fi 34 | 35 | # Check that shasum of tarball is present 36 | echo "Verifying nodejs shasum" 37 | if [ ! -z $(echo "$SHASUMFILE" | grep 256) ]; then 38 | node_shasum="$($shasum -a 256 $localname | grep -oE '^[0-9a-f]+')" 39 | else 40 | node_shasum="$($shasum $localname | grep -oE '^[0-9a-f]+')" 41 | fi 42 | grep "$node_shasum" "$SHASUMFILE" 43 | 44 | # Check if file already exists on s3 45 | if aws s3 cp "$dest/v$nv/$filename.md5" "./$localname-online.md5" > /dev/null 2>&1; then 46 | if md5sum -c $localname-online.md5; then 47 | echo "$filename unchanged" 48 | return 0 49 | fi 50 | fi 51 | 52 | aws s3 cp --acl public-read "$localname" "$dest/v$nv/$filename" 53 | aws s3 cp --acl public-read "$localname.md5" "$dest/v$nv/$filename.md5" 54 | } 55 | 56 | # Add trusted gpg keys for verifying nodejs downloads 57 | if which gpg > /dev/null; then 58 | # from https://github.com/nodejs/node#verifying-binaries, 59 | # keyserver list taken from the nodejs v10.x Dockerfile 60 | for key in \ 61 | 94AE36675C464D64BAFA68DD7434390BDBE9B9C5 \ 62 | FD3A5288F042B6850C66B31F09FE44734EB7990E \ 63 | 71DCFD284A79C3B38668286BC97EC7A07EDE3FC1 \ 64 | DD8F2338BAE7501E3DD5AC78C273792F7D83545D \ 65 | C4F0DFFF4E8C1A8236409D08E73BC641CC11F4C8 \ 66 | B9AE9905FFD7803F25714661B63B535A4C206CA9 \ 67 | 77984A986EBC2AA786BC0F66B01FBB92821C587A \ 68 | 8FCCA13FEF1D0C2E91008E09770F7A9A5AE15600 \ 69 | 4ED778F539E3634C779C87C6D7062848A1AB005C \ 70 | A48C2BEE680E841632CD4E44F07496B3EB3C1762 \ 71 | B9E2F5981AA6E0CD28160D9FF13993A75599653C \ 72 | 141F07595B7B3FFE74309A937405533BE57C7D57 \ 73 | 74F12602B6F1C4E913FAA37AD3A89613643B6201 \ 74 | 61FC681DFB92A079F1685E77973F295594EC4689 \ 75 | 890C08DB8579162FEE0DF9DB8BEAB4DFCF555EF4 \ 76 | C82FA3AE1CBEDC6BE46B9360C43CEC45C17AB93C \ 77 | 108F52B48DB57BB0CC439B2997B01419BD92F80A \ 78 | ; do 79 | gpg --batch --keyserver hkps://keyserver.ubuntu.com --recv-keys "$key" || 80 | gpg --batch --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys "$key" || 81 | gpg --batch --keyserver hkp://ipv4.pool.sks-keyservers.net --recv-keys "$key" || 82 | gpg --batch --keyserver hkp://pgp.mit.edu:80 --recv-keys "$key" ; 83 | done 84 | else 85 | echo "!WARN! gpg not found. Please install and try again" && exit 1 86 | fi 87 | 88 | aws s3 cp --acl public-read "$main_file" $apps_dest/$gitsha/run 89 | aws s3 cp --acl public-read "$version_file" $apps_dest/cache/v${install_v}/ 90 | 91 | if git describe --tags --exact-match 2> /dev/null; then 92 | tag=$(git describe --tags --exact-match) 93 | aws s3 cp --acl public-read "$main_file" $apps_dest/$tag/run 94 | # latest major versions tagged always available at /latest/run 95 | aws s3 cp --acl public-read "$main_file" $apps_dest/latest/run 96 | fi 97 | 98 | cd "$tmp" 99 | 100 | # Cache node.js packages to S3 101 | for nv in "${versions[@]}"; do 102 | echo "Caching Node.js v$nv to S3" 103 | 104 | # Verify signed SHASUMS file to ensure it can be trusted 105 | # Versions after 4.0.0 use shasum's 256 algorithm, check for both 106 | SHASUMFILE="SHASUMS.txt.asc" 107 | if ! wget -q -O $SHASUMFILE "https://nodejs.org/dist/v$nv/$SHASUMFILE"; then 108 | echo "$SHASUMFILE not found" && rm $SHASUMFILE 109 | SHASUMFILE="SHASUMS256.txt.asc" 110 | if ! wget -q -O $SHASUMFILE "https://nodejs.org/dist/v$nv/$SHASUMFILE"; then 111 | echo "$SHASUMFILE not found. No SHASUM file found for v$nv, exiting." && exit 1 112 | fi 113 | fi 114 | 115 | echo "Verifying signature of nodejs $SHASUMFILE" 116 | gpg --verify < $SHASUMFILE 117 | 118 | cachefile node-v$nv-linux-x64.tar.gz $nv 119 | cachefile node-v$nv-darwin-x64.tar.gz $nv 120 | rm ./* 121 | done 122 | -------------------------------------------------------------------------------- /util/test: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | install_node=$(dirname $0)/../bin/install_node 4 | failed="0" 5 | 6 | function assertNo() { 7 | if [ -e $1 ]; then 8 | echo "not ok - notfound $1"; 9 | failed="1" 10 | else 11 | echo "ok - notfound $1" 12 | fi 13 | } 14 | 15 | function assertOk() { 16 | if [ -e $1 ]; then 17 | echo "ok - found $1" 18 | else 19 | echo "not ok - found $1"; 20 | failed="1" 21 | fi 22 | } 23 | 24 | function assertMD5() { 25 | if [ -e $1 ]; then 26 | echo "ok - found $1 $(md5sum $1 | grep -oE '[0-f]{32}')" 27 | else 28 | echo "not ok - found $1"; 29 | failed="1" 30 | fi 31 | } 32 | 33 | function assertExit0() { 34 | if $1 &> /dev/null; then 35 | echo "ok - exit 0 $1"; 36 | else 37 | echo "not ok - exit 0 $1"; 38 | failed="1" 39 | fi 40 | } 41 | 42 | function assertExit1() { 43 | if $1 &> /dev/null; then 44 | echo "not ok - exit 1+ $1"; 45 | failed="1" 46 | else 47 | echo "ok - exit 1+ $1"; 48 | fi 49 | } 50 | 51 | function failure() { 52 | local testdir=$(mktemp -d -t test-install-node.XXXXXX) 53 | echo "# install_node $1 $2 $testdir" 54 | assertExit1 "$install_node $1 $2 $testdir" 55 | assertNo $testdir/bin/node 56 | assertNo $testdir/bin/npm 57 | assertNo $testdir/include/node 58 | assertNo $testdir/lib/node_modules/npm 59 | assertNo $testdir/share/man 60 | assertNo $testdir/.npm 61 | rm -rf $testdir 62 | 63 | local testdir=$(mktemp -d -t test-install-node.XXXXXX) 64 | echo "# NV=$1 NP=$2 OD=$testdir install_node" 65 | NV=$1 NP=$2 OD=$testdir assertExit1 "$install_node" 66 | assertNo $testdir/bin/node 67 | assertNo $testdir/bin/npm 68 | assertNo $testdir/include/node 69 | assertNo $testdir/lib/node_modules/npm 70 | assertNo $testdir/share/man 71 | assertNo $testdir/.npm 72 | rm -rf $testdir 73 | } 74 | 75 | function successUnix() { 76 | local testdir=$(mktemp -d -t test-install-node.XXXXXX) 77 | echo "# install_node $1 $2 $testdir" 78 | assertExit0 "$install_node $1 $2 $testdir" 79 | assertMD5 $testdir/bin/node 80 | assertOk $testdir/bin/npm 81 | assertOk $testdir/include/node 82 | assertOk $testdir/lib/node_modules/npm 83 | assertOk $testdir/share/man 84 | assertOk $testdir/.npm 85 | rm -rf $testdir 86 | 87 | local testdir=$(mktemp -d -t test-install-node.XXXXXX) 88 | echo "# NV=$1 NP=$2 OD=$testdir install_node" 89 | NV=$1 NP=$2 OD=$testdir assertExit0 "$install_node" 90 | assertMD5 $testdir/bin/node 91 | assertOk $testdir/bin/npm 92 | assertOk $testdir/include/node 93 | assertOk $testdir/lib/node_modules/npm 94 | assertOk $testdir/share/man 95 | assertOk $testdir/.npm 96 | rm -rf $testdir 97 | } 98 | 99 | function successUnixBin() { 100 | local testdir=$(mktemp -d -t test-install-node.XXXXXX) 101 | echo "# install_node $1 $2 $testdir true" 102 | assertExit0 "$install_node $1 $2 $testdir true" 103 | assertMD5 $testdir/node 104 | assertNo $testdir/bin 105 | assertNo $testdir/include 106 | assertNo $testdir/lib 107 | assertNo $testdir/share 108 | assertNo $testdir/.npm 109 | rm -rf $testdir 110 | 111 | local testdir=$(mktemp -d -t test-install-node.XXXXXX) 112 | echo "# NV=$1 NP=$2 OD=$testdir BO=true install_node" 113 | NV=$1 NP=$2 OD=$testdir BO=true assertExit0 "$install_node" 114 | assertMD5 $testdir/node 115 | assertNo $testdir/bin 116 | assertNo $testdir/include 117 | assertNo $testdir/lib 118 | assertNo $testdir/share 119 | assertNo $testdir/.npm 120 | rm -rf $testdir 121 | } 122 | 123 | # official dist 124 | INSTALL_NODE_URL=http://nodejs.org/dist successUnix 10.15.3 linux 125 | # normal s3 mirror 126 | successUnix 10.15.3 linux 127 | successUnix 10.15.3 linux-x64 128 | successUnix 10.15.3 darwin 129 | successUnix 10.15.3 darwin-x64 130 | # invalid version 131 | failure foo.bar linux 132 | # invalid platform 133 | failure 0.10.30 freebsd 134 | 135 | if [ "$failed" == "1" ]; then 136 | exit 1 137 | else 138 | exit 0 139 | fi 140 | --------------------------------------------------------------------------------