From 1ce57a25ecc1fc2af8824238c24503e6a937da59 Mon Sep 17 00:00:00 2001 From: 2GT-Rich <107219997+2GT-Rich@users.noreply.github.com> Date: Thu, 3 Sep 2026 10:24:59 -0700 Subject: [PATCH] ci: stop interpolating commit text into a shell command MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The release notes were passed through a step output and interpolated straight into the gh command. Commit messages here routinely contain backticks, so the shell evaluated them as command substitution — which failed the first release outright, and would let a commit message run arbitrary code in CI. Notes are written to a file and passed with --notes-file; nothing from the commit reaches a shell as code. Co-Authored-By: Claude Opus 5 --- .github/workflows/release.yml | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5d9312e..d0a822b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -36,29 +36,32 @@ jobs: - name: Compose notes from the commit that shipped it if: steps.v.outputs.unchanged != 'true' - id: notes + env: + VERSION: ${{ steps.v.outputs.version }} run: | + # Written to a file rather than passed through a step output. Commit + # messages here routinely contain backticks, and interpolating one into + # a shell command lets the shell evaluate it — which is both why the + # first attempt failed and a way to run arbitrary code in CI from a + # commit message. { - echo 'body<> "$GITHUB_OUTPUT" + printf '\n---\n' + printf 'Container image: `ghcr.io/2gt-media-group-llc/mikrotik-manager:%s`\n\n' "$VERSION" + printf 'Documentation: https://2gt-media-group-llc.github.io/mikrotik-manager/\n' + } > /tmp/release-notes.md - name: Publish if: steps.v.outputs.unchanged != 'true' env: GH_TOKEN: ${{ github.token }} + VERSION: ${{ steps.v.outputs.version }} run: | - TAG="v${{ steps.v.outputs.version }}" + TAG="v$VERSION" # Betas are marked pre-release so nobody is pointed at one by accident. PRERELEASE="" case "$TAG" in *beta*|*alpha*|*rc*) PRERELEASE="--prerelease" ;; esac gh release create "$TAG" \ --title "$TAG" \ - --notes "${{ steps.notes.outputs.body }}" \ + --notes-file /tmp/release-notes.md \ $PRERELEASE