From 831ca50dd63b2c632f18a6b42fa6dde17d5c6ec2 Mon Sep 17 00:00:00 2001 From: Leorize Date: Tue, 7 Dec 2021 16:17:26 -0600 Subject: [PATCH] containers: switch to official node binaries NodeSource, while handy, does not support version pinning. As such it would be impossible for us to ensure that the image can be reproduced. See https://github.com/nodesource/distributions/issues/33. Included is also a script to update the containers version of NodeJS automatically, pending integration with CI. --- containers/Containerfile | 94 +++++++++++++++++++++++++++----- containers/check-node-updates.sh | 37 +++++++++++++ 2 files changed, 116 insertions(+), 15 deletions(-) create mode 100755 containers/check-node-updates.sh diff --git a/containers/Containerfile b/containers/Containerfile index 6310386..19fb772 100644 --- a/containers/Containerfile +++ b/containers/Containerfile @@ -3,30 +3,86 @@ # This file is licensed under the terms of the MIT license. See "license.txt" # included in this distribution for more information. -# --- Image used for building the compiler - # The name of the Debian release being used. # -# This image tracks LTS releases. +# These images tracks LTS releases. ARG debian_release=buster -FROM docker.io/debian:$debian_release-slim as builder +# Update this monthly +# +# If you alter this line formatting or move it away from the top, update +# check-node-updates.sh to do update checking/fixing properly. +ARG node_version=16.13.1 + +# --- Builder image to download NodeJS for other images -# Respecified here so that the variable can be used by this image -ARG debian_release +# This image tracks testing since it works better for ARMv7 +FROM docker.io/debian:testing-slim as node-downloader -# Add the NodeSource keyring to APT -ADD --chmod=644 https://deb.nodesource.com/gpgkey/nodesource.gpg.key /etc/apt/trusted.gpg.d/nodesource.asc +# Inherit this from global environment +ARG node_version -# Install ca-certificates in order to download from NodeSource. +# Update APT and install tools to download nodejs RUN apt-get update \ && DEBIAN_FRONTEND=noninteractive apt-get install -y \ --no-install-recommends \ + curl \ ca-certificates \ - # Add the NodeSource sources to APT - && echo "deb [signed-by=/etc/apt/trusted.gpg.d/nodesource.asc] https://deb.nodesource.com/node_16.x $debian_release main" > /etc/apt/sources.list.d/nodesource.list \ - # Update APT then install compiler build dependencies - && apt-get update \ + gnupg \ + xz-utils \ + && rm -rf /var/lib/apt/lists/* + +# Download and extract nodejs +RUN set -eux \ + && dpkg_arch=$(dpkg --print-architecture) \ + && node_arch= \ + && case "$dpkg_arch" in \ + amd64) node_arch="x64";; \ + arm64) node_arch="arm64";; \ + armhf) node_arch="armv7l";; \ + *) echo "Error: unsupported nodejs architecture"; exit 1;; \ + esac \ + # Import trusted release keys + # https://github.com/nodejs/node#release-keys + && gpg --keyserver keyserver.ubuntu.com \ + --keyserver keys.openpgp.org \ + --recv-keys \ + 4ED778F539E3634C779C87C6D7062848A1AB005C \ + 94AE36675C464D64BAFA68DD7434390BDBE9B9C5 \ + 74F12602B6F1C4E913FAA37AD3A89613643B6201 \ + 71DCFD284A79C3B38668286BC97EC7A07EDE3FC1 \ + 8FCCA13FEF1D0C2E91008E09770F7A9A5AE15600 \ + C4F0DFFF4E8C1A8236409D08E73BC641CC11F4C8 \ + C82FA3AE1CBEDC6BE46B9360C43CEC45C17AB93C \ + DD8F2338BAE7501E3DD5AC78C273792F7D83545D \ + A48C2BEE680E841632CD4E44F07496B3EB3C1762 \ + 108F52B48DB57BB0CC439B2997B01419BD92F80A \ + B9E2F5981AA6E0CD28160D9FF13993A75599653C \ + # Download the tarball + && release_name=node-v${node_version}-linux-${node_arch} \ + && tarball_name=${release_name}.tar.xz \ + && curl -LO "https://nodejs.org/dist/v${node_version}/${tarball_name}" \ + # Download the checksums + && curl -LO "https://nodejs.org/dist/v${node_version}/SHASUMS256.txt.asc" \ + # Verify the signatures + && gpg -o SHASUMS256.txt --decrypt SHASUMS256.txt.asc \ + # Verify the checksums + # + # It would be better if we have pipefail here, but sha256sum knows to bail + # when there is an empty input, so all is well. + && grep -F "${tarball_name}" SHASUMS256.txt | sha256sum -c - \ + # Extract the tarball + && mkdir -p "/node-${node_version}" \ + && tar -C "/node-${node_version}" --strip-components=1 -xf "${tarball_name}" \ + # Remove artifacts to save space (even though this is just a builder image) + && rm SHASUMS256.txt* "$tarball_name" + +# --- Image used for building the compiler + +FROM docker.io/debian:${debian_release}-slim as builder + +# Update APT then install compiler build dependencies +RUN apt-get update \ && DEBIAN_FRONTEND=noninteractive apt-get install -y \ --no-install-recommends \ # Required for building the compiler @@ -40,14 +96,22 @@ RUN apt-get update \ git \ # Required for running build script python3 \ - # Required for building docs - nodejs \ # Required for sharing artifacts in CI + ca-certificates \ curl \ # Required to build archives zstd \ && rm -rf /var/lib/apt/lists/* +# Inherit the variable to this image +ARG node_version + +# Install NodeJS +COPY --from=node-downloader /node-${node_version} /opt/node-${node_version} + +# Add Node to PATH +ENV PATH="/opt/node-${node_version}/bin:${PATH}" + # --- Image used for testing the compiler FROM builder as tester diff --git a/containers/check-node-updates.sh b/containers/check-node-updates.sh new file mode 100755 index 0000000..55a33cf --- /dev/null +++ b/containers/check-node-updates.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash + +# Set safety bash features +set -eu -o pipefail + +scriptDir=$(dirname "$(realpath "${BASH_SOURCE[0]}")") + +# Grab the containers NodeJS version +containerVer=$(grep -m 1 -F "node_version=" "$scriptDir/Containerfile" | cut -d'=' -f 2) + +echo "Containers version: $containerVer" + +# Look for the latest LTS in NodeJS index +latestLts=$(curl -sL https://nodejs.org/dist/index.json | jq -r 'first(.[] | select(.lts != false) | .version | ltrimstr("v"))') + +echo "Latest LTS version: $latestLts" + +if [[ $latestLts == "$containerVer" ]]; then + echo "Containers' NodeJS is up-to-date" +else + echo "Containers' NodeJS is outdated, performing update" + temporary=$(mktemp "$scriptDir/Containerfile.tmp.XXXXXXXXXX") + # Write the update to a temporary + # + # This sed script captures everything up to `node_version=`, then change the + # portion after the `=` to the latest version + sed 's/\(.*node_version=\).*/\1'"$latestLts"'/' "$scriptDir/Containerfile" > "$temporary" + # Show the diff + diff -u "$scriptDir/Containerfile" "$temporary" || { + # Diff returns either 1 or 0 on success, so exit failure otherwise + if [[ $? -ne 1 && $? -ne 0 ]]; then + exit "$?" + fi + } + # Then replace the original file + mv -v "$temporary" "$scriptDir/Containerfile" +fi