From 8d548cbb58492a929a5c520b03ae1eefce204dbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Wed, 22 Oct 2025 09:45:29 +0200 Subject: [PATCH 1/7] Revise release directory naming Include the Git tag in the name of the release directory rather than just the version number. Revise the script for the "release" job accordingly. This enables using the $CI_COMMIT_TAG variable in job scripts without the need to resort to string manipulation to strip the leading "v", improving readability. The only place where string manipulation is applied to the Git tag is now the "release" job itself, to verify that the Git tag matches the version number embedded in the source tarball name. --- .gitlab-ci.yml | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index c153c63ae3..8ee438ad33 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1615,18 +1615,17 @@ release: <<: *base_image stage: release script: - - export BIND_DIRECTORY="$(basename build/meson-dist/bind-*.tar.xz ".tar.xz")" + - export RELEASE_DIRECTORY="bind-${CI_COMMIT_TAG}-release" + - export BIND_VERSION="bind-${CI_COMMIT_TAG#v}" # Prepare release tarball contents (tarballs + documentation) - - mkdir -p "${BIND_DIRECTORY}-release/doc/arm" - - pushd "${BIND_DIRECTORY}-release" - - mv "../build/meson-dist/${BIND_DIRECTORY}.tar.xz" . - - tar --extract --file="${BIND_DIRECTORY}.tar.xz" - - mv "${BIND_DIRECTORY}"/{COPYRIGHT,LICENSE,README.md,srcid} . - - rm -rf "${BIND_DIRECTORY}" + - mkdir -p "${RELEASE_DIRECTORY}/doc/arm" + - pushd "${RELEASE_DIRECTORY}" + - mv "../build/meson-dist/${BIND_VERSION}.tar.xz" . + - tar --extract --file="${BIND_VERSION}.tar.xz" --strip-components=1 "${BIND_VERSION}"/{COPYRIGHT,LICENSE,README.md,srcid} - mv ../build/arm/ doc/arm/html/ - mv ../build/arm-epub/Bv9ARM.epub doc/arm/ - - echo 'Redirect' > "RELEASE-NOTES-${BIND_DIRECTORY}.html" - - echo 'Redirect' > "CHANGELOG-${BIND_DIRECTORY}.html" + - echo 'Redirect' > "RELEASE-NOTES-${BIND_VERSION}.html" + - echo 'Redirect' > "CHANGELOG-${BIND_VERSION}.html" - popd needs: - job: tarball-create @@ -1637,7 +1636,7 @@ release: - *rule_tag artifacts: paths: - - "*-release" + - bind-${CI_COMMIT_TAG}-release expire_in: "1 month" # Job signing the source tarballs in the release directory @@ -1647,7 +1646,7 @@ sign: tags: - signer script: - - export RELEASE_DIRECTORY="$(echo *-release)" + - export RELEASE_DIRECTORY="bind-${CI_COMMIT_TAG}-release" - pushd "${RELEASE_DIRECTORY}" - | echo From c61767453de055673538da826f8fab8537c8ed7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Wed, 22 Oct 2025 09:45:29 +0200 Subject: [PATCH 2/7] Add a template for SSH-confirmed jobs Add a YAML template for jobs that require an SSH connection to a dedicated, locked-down runner for signing off on sensitive operations (e.g. signing, publishing). These jobs all follow a similar scheme: 1. Runner prepares the necessary files in a well-known location (/tmp). 2. Runner generates a shell script to be run by an authorized user. 3. Runner sleeps while waiting for a signal that the script was run. 4. Authorized user logs in to the runner over SSH and runs the script. 5. Runner collects the relevant files and logs as job artifacts. One additional complication is that each of the above steps needs to be carried out under the assumption that GitLab Runner is running under a different user account than the one used for logging in over SSH, necessitating careful file permission handling. Having a YAML template for jobs that need to follow the above scheme significantly improves readability and reuse as each job only needs to define (via the "variables" YAML key): - SSH_SCRIPT_RUNNER_PRE: the code the runner should execute before an authorized user logs in over SSH (typically: setting up files in a well-known location), - SSH_SCRIPT_CLIENT: contents of the shell script to be run by an authorized user, - SSH_SCRIPT_RUNNER_POST: the code the runner should execute after an authorized user runs the script over SSH (typically: artifact collection and cleanup). --- .gitlab-ci.yml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 8ee438ad33..710b86cac5 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1639,6 +1639,31 @@ release: - bind-${CI_COMMIT_TAG}-release expire_in: "1 month" +.signer-ssh-job: &signer_ssh_job + stage: release + when: manual + allow_failure: false + tags: + - signer + script: + - ( rm -f "/tmp/${CI_JOB_NAME}.log" "/tmp/${CI_JOB_NAME}-done" && umask 111 && touch "/tmp/${CI_JOB_NAME}.log" "/tmp/${CI_JOB_NAME}-done" ) + - | + cat > "/tmp/${CI_JOB_NAME}.sh" < "/tmp/${CI_JOB_NAME}-done" + } 2>&1 | tee "/tmp/${CI_JOB_NAME}.log" + EOF + - chmod +x "/tmp/${CI_JOB_NAME}.sh" + - /bin/sh -c "set -e -x; ${SSH_SCRIPT_RUNNER_PRE}" + - echo -e "\e[31m*** Sleeping until /tmp/${CI_JOB_NAME}.sh is executed over SSH... ⌛\e[0m" + - while [ "$(cat "/tmp/${CI_JOB_NAME}-done")" != "${CI_COMMIT_TAG}" ]; do sleep 10; done + - /bin/sh -c "set -e -x; ${SSH_SCRIPT_RUNNER_POST}" + - cp "/tmp/${CI_JOB_NAME}.log" "${CI_PROJECT_DIR}/${CI_JOB_NAME}-${CI_COMMIT_TAG}.log" + - rm -f "/tmp/${CI_JOB_NAME}.log" "/tmp/${CI_JOB_NAME}-done" "/tmp/${CI_JOB_NAME}.sh" + # Job signing the source tarballs in the release directory sign: From 868887ac65657307644e19427a04f6f3560df9ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Wed, 22 Oct 2025 09:45:29 +0200 Subject: [PATCH 3/7] Rework the "sign" job Adapt the "sign" job to use the YAML template for SSH-confirmed jobs. Make the signing process user-agnostic. --- .gitlab-ci.yml | 45 +++++++++++++++------------------------------ 1 file changed, 15 insertions(+), 30 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 710b86cac5..123b4d1f0b 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1667,44 +1667,29 @@ release: # Job signing the source tarballs in the release directory sign: - stage: release - tags: - - signer - script: - - export RELEASE_DIRECTORY="bind-${CI_COMMIT_TAG}-release" - - pushd "${RELEASE_DIRECTORY}" - - | - echo - cat > /tmp/sign-bind9.sh <>> Signing \${FILE}..." - gpg2 --local-user "\${SIGNING_KEY_FINGERPRINT}" --armor --digest-algo SHA512 --detach-sign --output "\${FILE}.asc" "\${FILE}" - done - } 2>&1 | tee "${CI_PROJECT_DIR}/signing.log" - EOF - chmod +x /tmp/sign-bind9.sh - echo -e "\e[31m*** Please sign the releases by following the instructions at:\e[0m" - echo -e "\e[31m*** \e[0m" - echo -e "\e[31m*** ${SIGNING_HELP_URL}\e[0m" - echo -e "\e[31m*** \e[0m" - echo -e "\e[31m*** Sleeping until files in ${PWD} are signed... ⌛\e[0m" - while [ "$(find . -name "*.asc" -size +0 | sed "s|\.asc$||" | sort)" != "$(find . -name "*.tar.xz" | sort)" ]; do sleep 10; done - - popd - - tar --create --file="${RELEASE_DIRECTORY}.tar.gz" --gzip "${RELEASE_DIRECTORY}" + <<: *signer_ssh_job + before_script: + - export SOURCE_TARBALL="bind-${CI_COMMIT_TAG#v}.tar.xz" + variables: + RELEASE_DIRECTORY: bind-${CI_COMMIT_TAG}-release + SSH_SCRIPT_RUNNER_PRE: |- + ( umask 111 && cat "${RELEASE_DIRECTORY}/$${SOURCE_TARBALL}" > "/tmp/${CI_COMMIT_TAG}.bin" ) + SSH_SCRIPT_CLIENT: |- + gpg2 --local-user "$${SIGNING_KEY_FINGERPRINT}" --armor --digest-algo SHA512 --detach-sign --output "/tmp/${CI_COMMIT_TAG}.asc" "/tmp/${CI_COMMIT_TAG}.bin" + SSH_SCRIPT_RUNNER_POST: |- + cat "/tmp/${CI_COMMIT_TAG}.asc" > "${RELEASE_DIRECTORY}/$${SOURCE_TARBALL}.asc" + tar --create --file="${RELEASE_DIRECTORY}".tar.gz --gzip "${RELEASE_DIRECTORY}" + rm -f "/tmp/${CI_COMMIT_TAG}.bin" "/tmp/${CI_COMMIT_TAG}.asc" artifacts: paths: - - "*.tar.gz" - - signing.log + - bind-${CI_COMMIT_TAG}-release.tar.gz + - sign-${CI_COMMIT_TAG}.log expire_in: never needs: - job: release artifacts: true rules: - *rule_tag - when: manual - allow_failure: false # Job creating the release announcement MR in Printing Press From a7fd3ebd0b1ddbef1d3aff8f8fac1f43ae05e804 Mon Sep 17 00:00:00 2001 From: Andoni Duarte Pintado Date: Tue, 16 Sep 2025 17:10:44 +0200 Subject: [PATCH 4/7] Add the "staging" job Add a new SSH-confirmed GitLab CI job that uploads a release tarball prepared by the "sign" job to a staging environment specified using CI variables. --- .gitlab-ci.yml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 123b4d1f0b..d67e8da3c7 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1691,6 +1691,29 @@ sign: rules: - *rule_tag +# Job staging the signed tarballs + +staging: + <<: *signer_ssh_job + variables: + RELEASE_TARBALL: bind-${CI_COMMIT_TAG}-release.tar.gz + SSH_SCRIPT_RUNNER_PRE: |- + mv "${RELEASE_TARBALL}" "/tmp/${RELEASE_TARBALL}" + SSH_SCRIPT_CLIENT: |- + scp "/tmp/${RELEASE_TARBALL}" "${STAGING_USER_UPLOAD}@${STAGING_HOST}:${STAGING_DIR}" + ssh "${STAGING_USER_ACTIONS}@${STAGING_HOST}" "unpack ${CI_COMMIT_TAG}" + SSH_SCRIPT_RUNNER_POST: |- + rm -f "/tmp/${RELEASE_TARBALL}" + artifacts: + paths: + - staging-${CI_COMMIT_TAG}.log + expire_in: "1 month" + needs: + - job: sign + artifacts: true + rules: + - if: '$CI_COMMIT_TAG != null' + # Job creating the release announcement MR in Printing Press prepare-release-announcement: From 1d88db4d631b12f33b2062490bca90f93626d6fa Mon Sep 17 00:00:00 2001 From: Andoni Duarte Pintado Date: Fri, 17 Oct 2025 09:52:45 +0200 Subject: [PATCH 5/7] Add the "publish-private" job Add a new SSH-confirmed GitLab CI job that publishes a previously staged release to a destination that is not a well-known URL. The details of what specifically this entails are controlled by the staging environment. --- .gitlab-ci.yml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index d67e8da3c7..2db0c47ab0 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1714,6 +1714,26 @@ staging: rules: - if: '$CI_COMMIT_TAG != null' +# Job copying a staged release to a secret location + +publish-private: + <<: *signer_ssh_job + variables: + SSH_SCRIPT_CLIENT: |- + ssh "${STAGING_USER_ACTIONS}@${STAGING_HOST}" "publish-private ${CI_COMMIT_TAG}" + SSH_SCRIPT_RUNNER_POST: |- + awk '/^Public Use URL:/ {print $$NF}' "/tmp/${CI_JOB_NAME}.log" > "url-${CI_COMMIT_TAG}.txt" + artifacts: + paths: + - publish-private-${CI_COMMIT_TAG}.log + - url-${CI_COMMIT_TAG}.txt + expire_in: "1 month" + needs: + - job: staging + artifacts: false + rules: + - if: '$CI_COMMIT_TAG != null && ($CI_COMMIT_TAG =~ /-S/ || $RELEASE_TYPE == "security")' + # Job creating the release announcement MR in Printing Press prepare-release-announcement: From a27b1954f21bb04d397ccda63cffd1a0843ef80d Mon Sep 17 00:00:00 2001 From: Andoni Duarte Pintado Date: Thu, 23 Oct 2025 15:13:00 +0200 Subject: [PATCH 6/7] Add the "publish" job Add a new SSH-confirmed GitLab CI job that publishes a previously staged release to a well-known URL. The details of what specifically this entails are controlled by the staging environment. --- .gitlab-ci.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 2db0c47ab0..fa94f93b3d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1734,6 +1734,23 @@ publish-private: rules: - if: '$CI_COMMIT_TAG != null && ($CI_COMMIT_TAG =~ /-S/ || $RELEASE_TYPE == "security")' +# Job copying a staged release to a well-known location + +publish: + <<: *signer_ssh_job + variables: + SSH_SCRIPT_CLIENT: |- + ssh "${STAGING_USER_ACTIONS}@${STAGING_HOST}" "publish ${CI_COMMIT_TAG}" + artifacts: + paths: + - publish-${CI_COMMIT_TAG}.log + expire_in: "1 month" + needs: + - job: staging + artifacts: false + rules: + - if: '$CI_COMMIT_TAG != null && $CI_COMMIT_TAG !~ /-S/' + # Job creating the release announcement MR in Printing Press prepare-release-announcement: From 0734ec2a68b4a97f9e080096dfd679d5584a265d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Mon, 27 Oct 2025 05:15:09 +0100 Subject: [PATCH 7/7] Deduplicate triggering rules for tag pipeline jobs Define and use more YAML anchors for triggering rules commonly used by tag pipeline jobs. This builds on top of the work done in commit 675d9c74251fee8ec034e87bdd43e7da97119a5d, improving readability and reuse. --- .gitlab-ci.yml | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index fa94f93b3d..68702ce65c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -306,6 +306,12 @@ stages: .rule_tag: &rule_tag - if: '$CI_PROJECT_NAMESPACE == "isc-private" && $CI_COMMIT_TAG != null' +.rule_tag_open_source: &rule_tag_open_source + - if: '$CI_PROJECT_NAMESPACE == "isc-private" && $CI_COMMIT_TAG != null && $CI_COMMIT_TAG !~ /-S/' + +.rule_tag_security_or_subscription: &rule_tag_security_or_subscription + - if: '$CI_PROJECT_NAMESPACE == "isc-private" && $CI_COMMIT_TAG != null && ($RELEASE_TYPE == "security" || $CI_COMMIT_TAG =~ /-S/)' + .rule_source_other_than_mr: &rule_source_other_than_mr - if: '$CI_PIPELINE_SOURCE =~ /^(api|pipeline|schedule|trigger|web)$/ && $REBASE_ONLY != "1"' @@ -1712,7 +1718,7 @@ staging: - job: sign artifacts: true rules: - - if: '$CI_COMMIT_TAG != null' + - *rule_tag # Job copying a staged release to a secret location @@ -1732,7 +1738,7 @@ publish-private: - job: staging artifacts: false rules: - - if: '$CI_COMMIT_TAG != null && ($CI_COMMIT_TAG =~ /-S/ || $RELEASE_TYPE == "security")' + - *rule_tag_security_or_subscription # Job copying a staged release to a well-known location @@ -1749,7 +1755,7 @@ publish: - job: staging artifacts: false rules: - - if: '$CI_COMMIT_TAG != null && $CI_COMMIT_TAG !~ /-S/' + - *rule_tag_open_source # Job creating the release announcement MR in Printing Press @@ -1765,7 +1771,7 @@ prepare-release-announcement: - bind9-qa/releng/prepare_release_announcement.py --metadata bind9-qa/releng/metadata.json needs: [] rules: - - if: '$CI_COMMIT_TAG != null && $CI_COMMIT_TAG !~ /-S/' + - *rule_tag_open_source artifacts: paths: - printing-press/ @@ -1785,7 +1791,7 @@ merge-tag: - bind9-qa/releng/merge_tag.py --tag "$CI_COMMIT_TAG" needs: [] rules: - - if: '$CI_COMMIT_TAG != null && $CI_COMMIT_TAG !~ /-S/' + - *rule_tag_open_source artifacts: paths: - bind9/