From 2df6def7f9dbcd55c49a57dbea5e7826b121cec0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Soko=C5=82owski?= Date: Wed, 4 Aug 2021 17:41:31 +0200 Subject: [PATCH] ci: add scripts/sign-linux-tarball.sh for GPG signing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds `scripts/sign-linux-file.sh` which expectes the following variables set: * `LINUX_GPG_PRIVATE_KEY_FILE` - Path to the GPG export of private key. * `LINUX_GPG_PRIVATE_KEY_PASS` - Password necessary to use the private key. Given a file it creates a file with a `.asc` suffix containing the signature: ``` > wget -q https://status-im-prs.ams3.digitaloceanspaces.com/StatusIm-210809-104514-156806-pr.tar.gz > tar xvf StatusIm-210809-104514-156806-pr.tar.gz StatusIm-210809-104514-156806-pr.AppImage StatusIm-210809-104514-156806-pr.AppImage.asc > gpg --verify StatusIm-210809-104514-156806-pr.AppImage.asc gpg: assuming signed data in 'StatusIm-210809-104514-156806-pr.AppImage' gpg: Signature made Mon 09 Aug 2021 12:54:49 PM CEST using RSA key ID E20B4DFD gpg: Good signature from "Status.im Devel Signing (GPG key for signing Status.im development builds.) " [ultimate] Primary key fingerprint: BBF0 5F92 536B ED19 30A9 FD44 009F B3BF E20B 4DFD ``` Issue: https://github.com/status-im/infra-ci/issues/25 Requires: https://github.com/status-im/status-jenkins-lib/pull/32 Signed-off-by: Jakub SokoĊ‚owski --- Makefile | 16 ++++++--- ci/Dockerfile | 9 +++-- ci/Jenkinsfile.combined | 2 +- ci/Jenkinsfile.linux | 17 ++++----- ci/Jenkinsfile.macos | 2 +- ci/Jenkinsfile.windows | 2 +- scripts/sign-linux-file.sh | 72 ++++++++++++++++++++++++++++++++++++++ scripts/sign-macos-pkg.sh | 4 ++- 8 files changed, 103 insertions(+), 21 deletions(-) create mode 100755 scripts/sign-linux-file.sh diff --git a/Makefile b/Makefile index 07b754e8f..fbf461e12 100644 --- a/Makefile +++ b/Makefile @@ -248,12 +248,13 @@ $(APPIMAGE_TOOL): echo -e "\e[92mFetching:\e[39m appimagetool" rm -rf tmp/linux mkdir -p tmp/linux/tools - wget https://github.com/AppImage/AppImageKit/releases/download/continuous/$(_APPIMAGE_TOOL) + wget -nv https://github.com/AppImage/AppImageKit/releases/download/continuous/$(_APPIMAGE_TOOL) mv $(_APPIMAGE_TOOL) tmp/linux/tools/ chmod +x $(APPIMAGE_TOOL) STATUS_CLIENT_APPIMAGE ?= pkg/Status.AppImage STATUS_CLIENT_TARBALL ?= pkg/Status.tar.gz +STATUS_CLIENT_TARBALL_FULL ?= $(shell realpath $(STATUS_CLIENT_TARBALL)) $(STATUS_CLIENT_APPIMAGE): override RESOURCES_LAYOUT := -d:production $(STATUS_CLIENT_APPIMAGE): nim_status_client $(APPIMAGE_TOOL) nim-status.desktop @@ -288,11 +289,18 @@ $(STATUS_CLIENT_APPIMAGE): nim_status_client $(APPIMAGE_TOOL) nim-status.desktop mkdir -p pkg $(APPIMAGE_TOOL) tmp/linux/dist $(STATUS_CLIENT_APPIMAGE) +# if LINUX_GPG_PRIVATE_KEY_FILE is not set then we don't generate a signature +ifdef LINUX_GPG_PRIVATE_KEY_FILE + scripts/sign-linux-file.sh $(STATUS_CLIENT_APPIMAGE) +endif $(STATUS_CLIENT_TARBALL): $(STATUS_CLIENT_APPIMAGE) - tar czvf $(STATUS_CLIENT_TARBALL) \ - -C $(shell dirname $(STATUS_CLIENT_APPIMAGE)) \ - $(shell basename $(STATUS_CLIENT_APPIMAGE)) + cd $(shell dirname $(STATUS_CLIENT_APPIMAGE)) && \ + tar czvf $(STATUS_CLIENT_TARBALL_FULL) --ignore-failed-read \ + $(shell basename $(STATUS_CLIENT_APPIMAGE)){,.asc} +ifdef LINUX_GPG_PRIVATE_KEY_FILE + scripts/sign-linux-file.sh $(STATUS_CLIENT_TARBALL) +endif DMG_TOOL := node_modules/.bin/create-dmg diff --git a/ci/Dockerfile b/ci/Dockerfile index 22b80bd68..39e2b90e8 100644 --- a/ci/Dockerfile +++ b/ci/Dockerfile @@ -14,8 +14,13 @@ RUN export DEBIAN_FRONTEND=noninteractive \ && sudo apt install -yq software-properties-common \ && sudo add-apt-repository -y ppa:git-core/ppa \ && sudo apt update -yq \ + && sudo apt purge -yq gnupg \ && sudo apt install -yq --fix-missing \ - build-essential cmake git s3cmd libpcre3-dev libnss3 libxcomposite1 libxtst6 jq gstreamer1.0-plugins-good gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly gstreamer1.0-libav gstreamer1.0-tools gstreamer1.0-alsa gstreamer1.0-pulseaudio + build-essential cmake jq git s3cmd gnupg2 \ + libpcre3-dev libnss3 libxcomposite1 libxtst6 \ + gstreamer1.0-plugins-good gstreamer1.0-plugins-bad \ + gstreamer1.0-plugins-ugly gstreamer1.0-libav \ + gstreamer1.0-tools gstreamer1.0-alsa gstreamer1.0-pulseaudio # Installing Golang RUN GOLANG_SHA256="aed845e4185a0b2a3c3d5e1d0a35491702c55889192bb9c30e67a3de6849c067" \ @@ -40,5 +45,5 @@ USER jenkins ENV HOME="/home/jenkins" LABEL maintainer="jakub@status.im" -LABEL source="https://github.com/status-im/nim-status-client" +LABEL source="https://github.com/status-im/status-desktop" LABEL description="Build image for the Status Desktop client written in Nim." diff --git a/ci/Jenkinsfile.combined b/ci/Jenkinsfile.combined index 13382798c..36856b3ec 100644 --- a/ci/Jenkinsfile.combined +++ b/ci/Jenkinsfile.combined @@ -1,4 +1,4 @@ -library 'status-jenkins-lib@v1.2.20' +library 'status-jenkins-lib@ci-linux-signing' pipeline { agent { label 'linux' } diff --git a/ci/Jenkinsfile.linux b/ci/Jenkinsfile.linux index 4cd12bde1..2225981f6 100644 --- a/ci/Jenkinsfile.linux +++ b/ci/Jenkinsfile.linux @@ -1,10 +1,10 @@ -library 'status-jenkins-lib@v1.2.20' +library 'status-jenkins-lib@ci-linux-signing' pipeline { agent { docker { label 'linux' - image 'statusteam/nim-status-client-build:1.0.2' + image 'statusteam/nim-status-client-build:1.0.3' /* allows jenkins use cat and mounts '/dev/fuse' for linuxdeployqt */ args '--entrypoint="" --cap-add SYS_ADMIN --security-opt apparmor:unconfined --device /dev/fuse' } @@ -64,14 +64,9 @@ pipeline { } stage('Package') { - steps { - withCredentials([string( - credentialsId: utils.getInfuraTokenCred(), - variable: 'INFURA_TOKEN' - )]) { - sh 'make tgz-linux' - } - } + steps { script { + linux.bundle('tgz-linux') + } } } stage('Parallel Upload') { @@ -84,7 +79,7 @@ pipeline { } stage('Archive') { steps { script { - archiveArtifacts(env.STATUS_CLIENT_TARBALL) + archiveArtifacts("${env.STATUS_CLIENT_TARBALL}*") } } } } diff --git a/ci/Jenkinsfile.macos b/ci/Jenkinsfile.macos index 1c5244429..6332548b9 100644 --- a/ci/Jenkinsfile.macos +++ b/ci/Jenkinsfile.macos @@ -1,4 +1,4 @@ -library 'status-jenkins-lib@v1.2.20' +library 'status-jenkins-lib@ci-linux-signing' pipeline { agent { diff --git a/ci/Jenkinsfile.windows b/ci/Jenkinsfile.windows index a700905a7..9cd7026ad 100644 --- a/ci/Jenkinsfile.windows +++ b/ci/Jenkinsfile.windows @@ -1,4 +1,4 @@ -library 'status-jenkins-lib@v1.2.20' +library 'status-jenkins-lib@ci-linux-signing' pipeline { agent { label 'windows' } diff --git a/scripts/sign-linux-file.sh b/scripts/sign-linux-file.sh new file mode 100755 index 000000000..6d4741204 --- /dev/null +++ b/scripts/sign-linux-file.sh @@ -0,0 +1,72 @@ +#!/usr/bin/env bash +set -eof pipefail + +# Checks ----------------------------------------------------------------------- + +if [[ $(uname) != 'Linux' ]]; then + echo 'This only works on Linux.' >&2 + exit 1 +fi +if [[ $# -lt 1 ]]; then + echo 'sign-linux-tarball.sh ' >&2 + exit 1 +fi +if [[ -z "${LINUX_GPG_PRIVATE_KEY_FILE}" ]]; then + echo "Unable to import GPG key file if LINUX_GPG_PRIVATE_KEY_FILE is not set!" >&2 + exit 1 +fi +if [[ -z "${LINUX_GPG_PRIVATE_KEY_PASS}" ]]; then + echo "Unable to import GPG key file if LINUX_GPG_PRIVATE_KEY_PASS is not set!" >&2 + exit 1 +fi +if [[ ! -f "${LINUX_GPG_PRIVATE_KEY_FILE}" ]]; then + echo "No such file exists: ${LINUX_GPG_PRIVATE_KEY_FILE}" >&2 + exit 1 +fi + +# Signing ---------------------------------------------------------------------- + +function clean_up { + STATUS=$? + if [[ "${STATUS}" -ne 0 ]]; then + echo -e "\n###### ERROR: See above for details." + fi + set +e + + echo -e "\n### Removing Temporary Keyring..." + rm -frv "${GNUPGHOME}" + exit $STATUS +} + +# First and only argument is the file to create signature for +TARGET="${1}" + +# Use a temporary GPG home and for the keyring. +export GNUPGHOME=$(mktemp -d $HOME/.gnupg.tmp.XXXXXX) +# Remove the GPG home along with the keyring regardless of how script exits. +trap clean_up EXIT + +# Fix for 'gpg: signing failed: Inappropriate ioctl for device' in Docker +echo 'allow-loopback-pinentry' > "${GNUPGHOME}/gpg-agent.conf" +echo 'pinentry-mode loopback' > "${GNUPGHOME}/gpg.conf" + +# Import the GPG key file into the temporary keyring. +echo -e "\n### Importing GPG private key..." +gpg2 --batch --yes --passphrase-fd 0 \ + --import "${LINUX_GPG_PRIVATE_KEY_FILE}" \ + <<< "${LINUX_GPG_PRIVATE_KEY_PASS}" + +# Trust all immported keys ultimately. +gpg2 --list-secret-keys --with-colons \ + | awk -F: '/fpr/{printf "%s:6:\n", $10}' \ + | gpg2 --import-ownertrust --batch + +echo -e "\n### Signing target..." +gpg2 --batch --yes --passphrase-fd 0 --verbose \ + --armor --detach-sign "${TARGET}" \ + <<< "${LINUX_GPG_PRIVATE_KEY_PASS}" + +echo -e "\n### Verifying signature..." +gpg2 --batch --verify "${TARGET}.asc" "${TARGET}" + +echo -e "\n### DONE" diff --git a/scripts/sign-macos-pkg.sh b/scripts/sign-macos-pkg.sh index 0d765593d..bb590d1aa 100755 --- a/scripts/sign-macos-pkg.sh +++ b/scripts/sign-macos-pkg.sh @@ -17,7 +17,9 @@ CODESIGN_OPTS_EXTRA=("${@}") function clean_up { STATUS=$? - [[ $? -eq 0 ]] || echo -e "\n###### ERROR: See above for details." + if [[ "${STATUS}" -eq 0 ]]; then + echo -e "\n###### ERROR: See above for details." + fi set +e echo -e "\n###### Cleaning up..."