diff --git a/CHANGELOG.md b/CHANGELOG.md index adb9c0af..0714cf29 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,10 @@ See also the [v0.107.55 GitHub milestone][ms-v0.107.55]. NOTE: Add new changes BELOW THIS COMMENT. --> +### Security + +- The release executables are now signed. + diff --git a/scripts/make/build-docker.sh b/scripts/make/build-docker.sh index ffdfb228..54932995 100644 --- a/scripts/make/build-docker.sh +++ b/scripts/make/build-docker.sh @@ -2,8 +2,7 @@ verbose="${VERBOSE:-0}" -if [ "$verbose" -gt '0' ] -then +if [ "$verbose" -gt '0' ]; then set -x debug_flags='--debug=1' else @@ -20,9 +19,8 @@ commit="${COMMIT:?please set COMMIT}" dist_dir="${DIST_DIR:?please set DIST_DIR}" readonly channel commit dist_dir -if [ "${VERSION:-}" = 'v0.0.0' ] || [ "${VERSION:-}" = '' ] -then - version="$( sh ./scripts/make/version.sh )" +if [ "${VERSION:-}" = 'v0.0.0' ] || [ "${VERSION:-}" = '' ]; then + version="$(sh ./scripts/make/version.sh)" else version="$VERSION" fi @@ -41,7 +39,7 @@ linux/arm64,\ linux/ppc64le" readonly docker_platforms -build_date="$( date -u +'%Y-%m-%dT%H:%M:%SZ' )" +build_date="$(date -u +'%Y-%m-%dT%H:%M:%SZ')" readonly build_date # Set DOCKER_IMAGE_NAME to 'adguard/adguard-home' if you want (and are allowed) @@ -59,27 +57,26 @@ readonly docker_image_name docker_output="${DOCKER_OUTPUT:-type=image,name=${docker_image_name},push=false}" readonly docker_output -case "$channel" -in -('release') +case "$channel" in +'release') docker_version_tag="--tag=${docker_image_name}:${version}" docker_channel_tag="--tag=${docker_image_name}:latest" ;; -('beta') +'beta') docker_version_tag="--tag=${docker_image_name}:${version}" docker_channel_tag="--tag=${docker_image_name}:beta" ;; -('edge') +'edge') # Set the version tag to an empty string when pushing to the edge channel. docker_version_tag='' docker_channel_tag="--tag=${docker_image_name}:edge" ;; -('development') +'development') # Set both tags to an empty string for development builds. docker_version_tag='' docker_channel_tag='' ;; -(*) +*) echo "invalid channel '$channel', supported values are\ 'development', 'edge', 'beta', and 'release'" 1>&2 exit 1 @@ -94,17 +91,17 @@ dist_docker="${dist_dir}/docker" readonly dist_docker mkdir -p "$dist_docker" -cp "${dist_dir}/AdGuardHome_linux_386/AdGuardHome/AdGuardHome"\ +cp "${dist_dir}/AdGuardHome_linux_386/AdGuardHome/AdGuardHome" \ "${dist_docker}/AdGuardHome_linux_386_" -cp "${dist_dir}/AdGuardHome_linux_amd64/AdGuardHome/AdGuardHome"\ +cp "${dist_dir}/AdGuardHome_linux_amd64/AdGuardHome/AdGuardHome" \ "${dist_docker}/AdGuardHome_linux_amd64_" -cp "${dist_dir}/AdGuardHome_linux_arm64/AdGuardHome/AdGuardHome"\ +cp "${dist_dir}/AdGuardHome_linux_arm64/AdGuardHome/AdGuardHome" \ "${dist_docker}/AdGuardHome_linux_arm64_" -cp "${dist_dir}/AdGuardHome_linux_arm_6/AdGuardHome/AdGuardHome"\ +cp "${dist_dir}/AdGuardHome_linux_arm_6/AdGuardHome/AdGuardHome" \ "${dist_docker}/AdGuardHome_linux_arm_v6" -cp "${dist_dir}/AdGuardHome_linux_arm_7/AdGuardHome/AdGuardHome"\ +cp "${dist_dir}/AdGuardHome_linux_arm_7/AdGuardHome/AdGuardHome" \ "${dist_docker}/AdGuardHome_linux_arm_v7" -cp "${dist_dir}/AdGuardHome_linux_ppc64le/AdGuardHome/AdGuardHome"\ +cp "${dist_dir}/AdGuardHome_linux_ppc64le/AdGuardHome/AdGuardHome" \ "${dist_docker}/AdGuardHome_linux_ppc64le_" # Don't use quotes with $docker_version_tag and $docker_channel_tag, because we @@ -112,16 +109,14 @@ cp "${dist_dir}/AdGuardHome_linux_ppc64le/AdGuardHome/AdGuardHome"\ # # TODO(a.garipov): Once flag --tag of docker buildx build supports commas, use # them instead. -$sudo_cmd docker\ - "$debug_flags"\ - buildx build\ - --build-arg BUILD_DATE="$build_date"\ - --build-arg DIST_DIR="$dist_dir"\ - --build-arg VCS_REF="$commit"\ - --build-arg VERSION="$version"\ - --output "$docker_output"\ - --platform "$docker_platforms"\ - $docker_version_tag\ - $docker_channel_tag\ - -f ./docker/Dockerfile\ - . +# +# shellcheck disable=SC2086 +$sudo_cmd docker "$debug_flags" \ + buildx build \ + --build-arg BUILD_DATE="$build_date" \ + --build-arg DIST_DIR="$dist_dir" \ + --build-arg VCS_REF="$commit" \ + --build-arg VERSION="$version" \ + --output "$docker_output" \ + --platform "$docker_platforms" \ + $docker_version_tag $docker_channel_tag -f ./docker/Dockerfile . diff --git a/scripts/make/build-release.sh b/scripts/make/build-release.sh index 581081d5..6eaca776 100644 --- a/scripts/make/build-release.sh +++ b/scripts/make/build-release.sh @@ -15,8 +15,7 @@ verbose="${VERBOSE:-0}" readonly verbose -if [ "$verbose" -gt '1' ] -then +if [ "$verbose" -gt '1' ]; then env set -x fi @@ -32,8 +31,7 @@ set -e -f -u # Function log is an echo wrapper that writes to stderr if the caller requested # verbosity level greater than 0. Otherwise, it does nothing. log() { - if [ "$verbose" -gt '0' ] - then + if [ "$verbose" -gt '0' ]; then # Don't use quotes to get word splitting. echo "$1" 1>&2 fi @@ -49,9 +47,8 @@ readonly channel # Check VERSION against the default value from the Makefile. If it is that, use # the version calculation script. version="${VERSION:-}" -if [ "$version" = 'v0.0.0' ] || [ "$version" = '' ] -then - version="$( sh ./scripts/make/version.sh )" +if [ "$version" = 'v0.0.0' ] || [ "$version" = '' ]; then + version="$(sh ./scripts/make/version.sh)" fi readonly version @@ -60,8 +57,7 @@ log "version '$version'" # Check architecture and OS limiters. Add spaces to the local versions for # better pattern matching. -if [ "${ARCH:-}" != '' ] -then +if [ "${ARCH:-}" != '' ]; then log "arches: '$ARCH'" arches=" $ARCH " else @@ -69,8 +65,7 @@ else fi readonly arches -if [ "${OS:-}" != '' ] -then +if [ "${OS:-}" != '' ]; then log "oses: '$OS'" oses=" $OS " else @@ -79,8 +74,7 @@ fi readonly oses # Require the gpg key and passphrase to be set if the signing is required. -if [ "$sign" -eq '1' ] -then +if [ "$sign" -eq '1' ]; then gpg_key_passphrase="${GPG_KEY_PASSPHRASE:?please set GPG_KEY_PASSPHRASE or unset SIGN}" gpg_key="${GPG_KEY:?please set GPG_KEY or unset SIGN}" signer_api_key="${SIGNER_API_KEY:?please set SIGNER_API_KEY or unset SIGN}" @@ -102,12 +96,9 @@ log "checking tools" # Make sure we fail gracefully if one of the tools we need is missing. Use # alternatives when available. use_shasum='0' -for tool in gpg gzip sed sha256sum tar zip -do - if ! command -v "$tool" > /dev/null - then - if [ "$tool" = 'sha256sum' ] && command -v 'shasum' > /dev/null - then +for tool in gpg gzip sed sha256sum tar zip; do + if ! command -v "$tool" >/dev/null; then + if [ "$tool" = 'sha256sum' ] && command -v 'shasum' >/dev/null; then # macOS doesn't have sha256sum installed by default, but it does # have shasum. log 'replacing sha256sum with shasum -a 256' @@ -157,8 +148,7 @@ readonly platforms # system. sign() { # Only sign if needed. - if [ "$sign" -ne '1' ] - then + if [ "$sign" -ne '1' ]; then return fi @@ -167,34 +157,25 @@ sign() { sign_os="$1" sign_bin_path="$2" - if [ "$sign_os" != 'windows' ] - then - gpg\ - --default-key "$gpg_key"\ - --detach-sig\ - --passphrase "$gpg_key_passphrase"\ - --pinentry-mode loopback\ - -q\ - "$sign_bin_path"\ + if [ "$sign_os" != 'windows' ]; then + gpg \ + --default-key "$gpg_key" \ + --detach-sig \ + --passphrase "$gpg_key_passphrase" \ + --pinentry-mode loopback -q "$sign_bin_path" \ ; return - # TODO(e.burkov): Enable for all releases. - elif [ "$channel" != 'beta' ] - then - return + elif [ "$channel" = 'beta' ] || [ "$channel" = 'release' ]; then + signed_bin_path="${sign_bin_path}.signed" + + env INPUT_FILE="$sign_bin_path" \ + OUTPUT_FILE="$signed_bin_path" \ + SIGNER_API_KEY="$signer_api_key" \ + "$deploy_script_path" sign-executable + + mv "$signed_bin_path" "$sign_bin_path" fi - - signed_bin_path="${sign_bin_path}.signed" - - env\ - INPUT_FILE="$sign_bin_path"\ - OUTPUT_FILE="$signed_bin_path"\ - SIGNER_API_KEY="$signer_api_key"\ - "$deploy_script_path" sign-executable\ - ; - - mv "$signed_bin_path" "$sign_bin_path" } # Function build builds the release for one platform. It builds a binary and an @@ -202,17 +183,16 @@ sign() { build() { # Get the arguments. Here and below, use the "build_" prefix for all # variables local to function build. - build_dir="${dist}/${1}/AdGuardHome"\ - build_ar="$2"\ - build_os="$3"\ - build_arch="$4"\ - build_arm="$5"\ - build_mips="$6"\ + build_dir="${dist}/${1}/AdGuardHome" \ + build_ar="$2" \ + build_os="$3" \ + build_arch="$4" \ + build_arm="$5" \ + build_mips="$6" \ ; # Use the ".exe" filename extension if we build a Windows release. - if [ "$build_os" = 'windows' ] - then + if [ "$build_os" = 'windows' ]; then build_output="./${build_dir}/AdGuardHome.exe" else build_output="./${build_dir}/AdGuardHome" @@ -224,16 +204,14 @@ build() { # # Set GOARM and GOMIPS to an empty string if $build_arm and $build_mips are # the zero value by removing the hyphen as if it's a prefix. - env\ - GOARCH="$build_arch"\ - GOARM="${build_arm#-}"\ - GOMIPS="${build_mips#-}"\ - GOOS="$os"\ - VERBOSE="$(( verbose - 1 ))"\ - VERSION="$version"\ - OUT="$build_output"\ - sh ./scripts/make/go-build.sh\ - ; + env GOARCH="$build_arch" \ + GOARM="${build_arm#-}" \ + GOMIPS="${build_mips#-}" \ + GOOS="$os" \ + VERBOSE="$((verbose - 1))" \ + VERSION="$version" \ + OUT="$build_output" \ + sh ./scripts/make/go-build.sh log "$build_output" @@ -244,17 +222,16 @@ build() { # Make archives. Windows and macOS prefer ZIP archives; the rest, # gzipped tarballs. - case "$build_os" - in - ('darwin'|'windows') + case "$build_os" in + 'darwin' | 'windows') build_archive="./${dist}/${build_ar}.zip" # TODO(a.garipov): Find an option similar to the -C option of tar for # zip. - ( cd "${dist}/${1}" && zip -9 -q -r "../../${build_archive}" "./AdGuardHome" ) + (cd "${dist}/${1}" && zip -9 -q -r "../../${build_archive}" "./AdGuardHome") ;; - (*) + *) build_archive="./${dist}/${build_ar}.tar.gz" - tar -C "./${dist}/${1}" -c -f - "./AdGuardHome" | gzip -9 - > "$build_archive" + tar -C "./${dist}/${1}" -c -f - "./AdGuardHome" | gzip -9 - >"$build_archive" ;; esac @@ -265,8 +242,7 @@ log "starting builds" # Go over all platforms defined in the space-separated table above, tweak the # values where necessary, and feed to build. -echo "$platforms" | while read -r os arch arm mips -do +echo "$platforms" | while read -r os arch arm mips; do # See if the architecture or the OS is in the allowlist. To do so, try # removing everything that matches the pattern (well, a prefix, but that # doesn't matter here) containing the arch or the OS. @@ -277,29 +253,28 @@ do # "* windows *", which doesn't match, so nothing is removed. # # See https://stackoverflow.com/a/43912605/1892060. - if [ "${arches##* $arch *}" != '' ] - then + # + # shellcheck disable=SC2295 + if [ "${arches##* $arch *}" != '' ]; then log "$arch excluded, continuing" continue - elif [ "${oses##* $os *}" != '' ] - then + elif [ "${oses##* $os *}" != '' ]; then log "$os excluded, continuing" continue fi - case "$arch" - in - (arm) + case "$arch" in + arm) dir="AdGuardHome_${os}_${arch}_${arm}" ar="AdGuardHome_${os}_${arch}v${arm}" ;; - (mips*) + mips*) dir="AdGuardHome_${os}_${arch}_${mips}" ar="$dir" ;; - (*) + *) dir="AdGuardHome_${os}_${arch}" ar="$dir" ;; @@ -311,7 +286,7 @@ done log "packing frontend" build_archive="./${dist}/AdGuardHome_frontend.tar.gz" -tar -c -f - ./build | gzip -9 - > "$build_archive" +tar -c -f - ./build | gzip -9 - >"$build_archive" log "$build_archive" log "calculating checksums" @@ -319,8 +294,7 @@ log "calculating checksums" # calculate_checksums uses the previously detected SHA-256 tool to calculate # checksums. Do not use find with -exec, since shasum requires arguments. calculate_checksums() { - if [ "$use_shasum" -eq '0' ] - then + if [ "$use_shasum" -eq '0' ]; then sha256sum "$@" else shasum -a 256 "$@" @@ -337,24 +311,22 @@ calculate_checksums() { cd "./${dist}" - : > ./checksums.txt + : >./checksums.txt - for archive in ./*.zip ./*.tar.gz - do + for archive in ./*.zip ./*.tar.gz; do # Make sure that we don't try to calculate a checksum for a glob pattern # that matched no files. - if [ ! -f "$archive" ] - then + if [ ! -f "$archive" ]; then continue fi - calculate_checksums "$archive" >> ./checksums.txt + calculate_checksums "$archive" >>./checksums.txt done ) log "writing versions" -echo "version=$version" > "./${dist}/version.txt" +echo "version=$version" >"./${dist}/version.txt" # Create the version.json file. @@ -364,8 +336,7 @@ readonly version_download_url version_json # If the channel is edge, point users to the "Platforms" page on the Wiki, # because the direct links to the edge packages are listed there. -if [ "$channel" = 'edge' ] -then +if [ "$channel" = 'edge' ]; then announcement_url='https://github.com/AdguardTeam/AdGuardHome/wiki/Platforms' else announcement_url="https://github.com/AdguardTeam/AdGuardHome/releases/tag/${version}" @@ -379,7 +350,7 @@ echo "{ \"announcement\": \"AdGuard Home ${version} is now available!\", \"announcement_url\": \"${announcement_url}\", \"selfupdate_min_version\": \"0.0\", -" >> "$version_json" +" >>"$version_json" # Add the MIPS* object keys without the "softfloat" part to mitigate the # consequences of #5373. @@ -389,18 +360,17 @@ echo " \"download_linux_mips64\": \"${version_download_url}/AdGuardHome_linux_mips64_softfloat.tar.gz\", \"download_linux_mips64le\": \"${version_download_url}/AdGuardHome_linux_mips64le_softfloat.tar.gz\", \"download_linux_mipsle\": \"${version_download_url}/AdGuardHome_linux_mipsle_softfloat.tar.gz\", -" >> "$version_json" +" >>"$version_json" # Same as with checksums above, don't use ls, because files matching one of the # patterns may be absent. -ar_files="$( find "./${dist}/" ! -name "${dist}" -prune \( -name '*.tar.gz' -o -name '*.zip' \) )" -ar_files_len="$( echo "$ar_files" | wc -l )" +ar_files="$(find "./${dist}" ! -name "${dist}" -prune \( -name '*.tar.gz' -o -name '*.zip' \))" +ar_files_len="$(echo "$ar_files" | wc -l)" readonly ar_files ar_files_len i='1' # Don't use quotes to get word splitting. -for f in $ar_files -do +for f in $ar_files; do platform="$f" # Remove the prefix. @@ -413,16 +383,15 @@ do # Use the filename's base path. filename="${f#"./${dist}/"}" - if [ "$i" -eq "$ar_files_len" ] - then - echo " \"download_${platform}\": \"${version_download_url}/${filename}\"" >> "$version_json" + if [ "$i" -eq "$ar_files_len" ]; then + echo " \"download_${platform}\": \"${version_download_url}/${filename}\"" >>"$version_json" else - echo " \"download_${platform}\": \"${version_download_url}/${filename}\"," >> "$version_json" + echo " \"download_${platform}\": \"${version_download_url}/${filename}\"," >>"$version_json" fi - i="$(( i + 1 ))" + i="$((i + 1))" done -echo '}' >> "$version_json" +echo '}' >>"$version_json" log "finished" diff --git a/scripts/make/sh-lint.sh b/scripts/make/sh-lint.sh index ad0d5d9d..83ed6f1d 100644 --- a/scripts/make/sh-lint.sh +++ b/scripts/make/sh-lint.sh @@ -22,18 +22,5 @@ fi shellcheck -e 'SC2250' -f 'gcc' -o 'all' -x --\ ./scripts/hooks/*\ ./scripts/snap/*\ - ./scripts/make/clean.sh\ - ./scripts/make/go-bench.sh\ - ./scripts/make/go-build.sh\ - ./scripts/make/go-deps.sh\ - ./scripts/make/go-fuzz.sh\ - ./scripts/make/go-lint.sh\ - ./scripts/make/go-test.sh\ - ./scripts/make/go-tools.sh\ - ./scripts/make/go-upd-tools.sh\ - ./scripts/make/helper.sh\ - ./scripts/make/md-lint.sh\ - ./scripts/make/sh-lint.sh\ - ./scripts/make/txt-lint.sh\ - ./scripts/make/version.sh\ + ./scripts/make/*\ ;