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..."