From 8fb4731fadaa6d73a98a9c8b93219840c951bfcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sanja=20Malovi=C4=87?= Date: Wed, 8 Jul 2026 22:48:20 +0200 Subject: [PATCH 1/2] fix(ci): bind release email workflow to production environment Secrets live in the production GitHub Environment; add environment binding and workflow_dispatch for retries without re-tagging. Co-authored-by: Cursor --- .github/workflows/release-email.yml | 38 +++++++++++++++++++++-------- docs/MARKETING-EMAIL.md | 2 ++ 2 files changed, 30 insertions(+), 10 deletions(-) diff --git a/.github/workflows/release-email.yml b/.github/workflows/release-email.yml index f47ad9ac..446b84eb 100644 --- a/.github/workflows/release-email.yml +++ b/.github/workflows/release-email.yml @@ -4,14 +4,23 @@ on: push: tags: - "v[0-9]+.[0-9]+.[0-9]+" + workflow_dispatch: + inputs: + version: + description: "Release version (X.Y.Z) to send" + required: true + previous_version: + description: "Previous tag (X.Y.Z) for bump check; omit for first tag" + required: false concurrency: - group: release-email-${{ github.ref }} + group: release-email-${{ github.event_name == 'workflow_dispatch' && format('manual-{0}', inputs.version) || github.ref }} cancel-in-progress: false jobs: send: runs-on: ubuntu-latest + environment: production steps: - uses: actions/checkout@v4 with: @@ -27,22 +36,31 @@ jobs: - name: Install run: pnpm install --frozen-lockfile - - name: Resolve semver tags + - name: Resolve release version id: tags run: | - CURRENT="${GITHUB_REF_NAME#v}" + if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then + CURRENT="${{ inputs.version }}" + PREVIOUS="${{ inputs.previous_version }}" + else + CURRENT="${GITHUB_REF_NAME#v}" + if ! [[ "$CURRENT" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "Invalid release tag: ${GITHUB_REF_NAME}" >&2 + exit 1 + fi + PREVIOUS=$(git tag -l "v*.*.*" --merged HEAD --sort=-version:refname \ + | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' \ + | grep -v "^${GITHUB_REF_NAME}$" \ + | head -1 \ + | sed 's/^v//') + fi if ! [[ "$CURRENT" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then - echo "Invalid release tag: ${GITHUB_REF_NAME}" >&2 + echo "Invalid release version: ${CURRENT}" >&2 exit 1 fi - PREVIOUS=$(git tag -l "v*.*.*" --merged HEAD --sort=-version:refname \ - | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' \ - | grep -v "^${GITHUB_REF_NAME}$" \ - | head -1 \ - | sed 's/^v//') echo "current=$CURRENT" >> "$GITHUB_OUTPUT" echo "previous=$PREVIOUS" >> "$GITHUB_OUTPUT" - echo "Tag ${GITHUB_REF_NAME} (previous on this line: ${PREVIOUS:-none})" + echo "Release ${CURRENT} (previous: ${PREVIOUS:-none})" - name: Check minor/major bump id: bump diff --git a/docs/MARKETING-EMAIL.md b/docs/MARKETING-EMAIL.md index c37c094b..1343cc22 100644 --- a/docs/MARKETING-EMAIL.md +++ b/docs/MARKETING-EMAIL.md @@ -68,6 +68,8 @@ Required GitHub repository secrets (production): | `TELEMETRY_EMAIL_FROM` | From address | | `TELEMETRY_DASHBOARD_ORIGIN` | Unsubscribe / docs links (e.g. `https://telemetry-tracker.com`) | +Store these in the GitHub **`production`** environment (the workflow job uses `environment: production`). To retry a send without re-tagging, use **Actions → Release product email → Run workflow** with `version` and `previous_version`. + The workflow runs **after** the tag is pushed — finalize `CHANGELOG.md` on `main` **before** tagging so the email body matches the release. ### Manual send (override / backfill) From 96629b263a6e238d690c37ca72c2355120de5c11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sanja=20Malovi=C4=87?= Date: Wed, 8 Jul 2026 22:50:34 +0200 Subject: [PATCH 2/2] fix(ci): pass workflow_dispatch inputs via env to prevent injection Avoid interpolating free-text dispatch fields into shell run blocks; semver validation still runs before outputs are used. Co-authored-by: Cursor --- .github/workflows/release-email.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release-email.yml b/.github/workflows/release-email.yml index 446b84eb..267e2aae 100644 --- a/.github/workflows/release-email.yml +++ b/.github/workflows/release-email.yml @@ -38,10 +38,13 @@ jobs: - name: Resolve release version id: tags + env: + DISPATCH_VERSION: ${{ inputs.version }} + DISPATCH_PREVIOUS_VERSION: ${{ inputs.previous_version }} run: | if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then - CURRENT="${{ inputs.version }}" - PREVIOUS="${{ inputs.previous_version }}" + CURRENT="$DISPATCH_VERSION" + PREVIOUS="$DISPATCH_PREVIOUS_VERSION" else CURRENT="${GITHUB_REF_NAME#v}" if ! [[ "$CURRENT" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then