diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b0e830eaa..2bea439c4 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -44,6 +44,12 @@ jobs: run: | VERSION=${GITHUB_REF#refs/tags/} VERSION=${VERSION#v} + # Validate the grammar up front, so a non-semver tag fails here with a clear + # message (the same grammar the Linux, Windows and macOS builders enforce). + if ! echo "$VERSION" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$'; then + echo "derived version '$VERSION' is not X.Y.Z[-suffix]; tag a semver release" >&2 + exit 1 + fi echo "VERSION=$VERSION" >> $GITHUB_OUTPUT - name: Download Artifacts @@ -60,11 +66,17 @@ jobs: done echo "EOF" >> $GITHUB_OUTPUT + # Note: the version and the hashes are passed through environment variables + # instead of direct ${{ }} interpolation into the run block, so that a crafted + # tag/ref/input cannot inject shell into the step. - name: Generate Release Body id: generate_body + env: + VERSION: ${{ steps.get_version.outputs.VERSION }} + HASHES: ${{ steps.generate_hashes.outputs.HASHES }} run: | echo "BODY<> $GITHUB_OUTPUT - echo "Release version ${{ steps.get_version.outputs.VERSION }}" >> $GITHUB_OUTPUT + echo "Release version $VERSION" >> $GITHUB_OUTPUT echo "" >> $GITHUB_OUTPUT echo "Please download the appropriate package for your system." >> $GITHUB_OUTPUT echo "" >> $GITHUB_OUTPUT @@ -74,7 +86,7 @@ jobs: echo "" >> $GITHUB_OUTPUT echo "File Hashes (SHA256):" >> $GITHUB_OUTPUT echo "\`\`\`" >> $GITHUB_OUTPUT - echo "${{ steps.generate_hashes.outputs.HASHES }}" >> $GITHUB_OUTPUT + echo "$HASHES" >> $GITHUB_OUTPUT echo "\`\`\`" >> $GITHUB_OUTPUT echo "EOF" >> $GITHUB_OUTPUT diff --git a/.github/workflows/release_docker.yml b/.github/workflows/release_docker.yml index c52fdd4fa..f7406653a 100644 --- a/.github/workflows/release_docker.yml +++ b/.github/workflows/release_docker.yml @@ -35,15 +35,29 @@ jobs: id: version run: | if [[ $GITHUB_REF == refs/tags/* ]]; then - echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT + VERSION=${GITHUB_REF#refs/tags/} + # Validate the grammar up front (the version flows into docker build/push + # command lines inside build.py), so a non-semver tag fails here with a + # clear message. The leading 'v' is allowed here; build.py strips it. + if ! echo "$VERSION" | grep -Eq '^v?[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$'; then + echo "derived version '$VERSION' is not [v]X.Y.Z[-suffix]; tag a semver release" >&2 + exit 1 + fi + echo "VERSION=$VERSION" >> $GITHUB_OUTPUT else echo "VERSION=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT fi + # Note: the version (and the Docker Hub username) are passed through environment + # variables instead of direct ${{ }} interpolation into the run block, so that a + # crafted tag/ref/input cannot inject shell into the step. - name: Build and Push Docker images + env: + VERSION: ${{ steps.version.outputs.VERSION }} + DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} run: | - python build-tools/docker/build.py --push --docker-hub-user ${{ secrets.DOCKERHUB_USERNAME }} \ - --version ${{ steps.version.outputs.VERSION }} --latest + python build-tools/docker/build.py --push --docker-hub-user "$DOCKERHUB_USERNAME" \ + --version "$VERSION" --latest env: DOCKER_BUILDKIT: 1 diff --git a/.github/workflows/release_macos.yml b/.github/workflows/release_macos.yml index e4adb1aa4..177bfe63a 100644 --- a/.github/workflows/release_macos.yml +++ b/.github/workflows/release_macos.yml @@ -23,6 +23,13 @@ jobs: run: | VERSION=${GITHUB_REF#refs/tags/} VERSION=${VERSION#v} + # Validate the grammar up front, so a non-semver tag fails here with a clear + # message instead of reaching the signing step (the same grammar the Linux and + # Windows builders enforce). + if ! echo "$VERSION" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$'; then + echo "derived version '$VERSION' is not X.Y.Z[-suffix]; tag a semver release" >&2 + exit 1 + fi echo "VERSION=$VERSION" >> $GITHUB_OUTPUT echo "Version extracted: $VERSION" @@ -36,6 +43,9 @@ jobs: run: | cargo build --release --locked --target ${{ matrix.arch }}-apple-darwin --features trezor,ledger + # Note: the version (and the workflow input) are passed through environment + # variables instead of direct ${{ }} interpolation into the run blocks, so + # that a crafted tag/ref/input cannot inject shell into the steps. - name: Sign and Notarize GUI env: MACOS_CERTIFICATE_BASE64: ${{ secrets.MACOS_CERTIFICATE }} @@ -46,16 +56,19 @@ jobs: APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }} VERSION: ${{ steps.get_version.outputs.VERSION }} run: | - ./build-tools/osx/sign_and_notarize.sh ${{ matrix.arch }} ${{ steps.get_version.outputs.VERSION }} + ./build-tools/osx/sign_and_notarize.sh ${{ matrix.arch }} "$VERSION" - name: Package Mintlayer Node (without GUI) + env: + VERSION: ${{ steps.get_version.outputs.VERSION }} + BINARY_LIST: ${{ inputs.binary_list }} run: | - mkdir -p Mintlayer_Node_macos_${{ steps.get_version.outputs.VERSION }}_${{ matrix.arch }} - IFS=',' read -ra BINARIES <<< "${{ inputs.binary_list }}" + mkdir -p "Mintlayer_Node_macos_${VERSION}_${{ matrix.arch }}" + IFS=',' read -ra BINARIES <<< "$BINARY_LIST" for binary in "${BINARIES[@]}"; do - cp target/${{ matrix.arch }}-apple-darwin/release/$binary Mintlayer_Node_macos_${{ steps.get_version.outputs.VERSION }}_${{ matrix.arch }}/ + cp "target/${{ matrix.arch }}-apple-darwin/release/$binary" "Mintlayer_Node_macos_${VERSION}_${{ matrix.arch }}/" done - zip -r Mintlayer_Node_macos_${{ steps.get_version.outputs.VERSION }}_${{ matrix.arch }}.zip Mintlayer_Node_macos_${{ steps.get_version.outputs.VERSION }}_${{ matrix.arch }} + zip -r "Mintlayer_Node_macos_${VERSION}_${{ matrix.arch }}.zip" "Mintlayer_Node_macos_${VERSION}_${{ matrix.arch }}" - name: Upload DMG Artifact (GUI) uses: actions/upload-artifact@v4