From 56f6d1c217915fa2d18030b4534f31f4fc5157e2 Mon Sep 17 00:00:00 2001 From: Wibias <37517432+Wibias@users.noreply.github.com> Date: Thu, 13 Aug 2026 00:00:00 +0200 Subject: [PATCH 1/3] Set persist-credentials to false in release workflow --- .github/workflows/release.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ca8ff7a10f..293f4ad5b2 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -48,6 +48,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 with: fetch-depth: 0 + persist-credentials: false - name: Verify dispatched SHA env: From 060b4e593a78d0d1ea845bd5553bf88bcaa42044 Mon Sep 17 00:00:00 2001 From: Wibias <37517432+Wibias@users.noreply.github.com> Date: Thu, 13 Aug 2026 01:03:04 +0200 Subject: [PATCH 2/3] fix(release): authenticate tag creation explicitly Replaced git tag and push commands with GitHub CLI API call to create a tag. --- .github/workflows/release.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 293f4ad5b2..99e3888d4f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -454,8 +454,10 @@ jobs: "${render_args[@]}" if [ -z "$existing_tag_sha" ]; then - git tag "$release_tag" "$GITHUB_SHA" - git push origin "refs/tags/${release_tag}" + gh api --method POST \ + "repos/${GITHUB_REPOSITORY}/git/refs" \ + -f ref="refs/tags/${release_tag}" \ + -f sha="$GITHUB_SHA" >/dev/null fi gh release create "$release_tag" --target "$GITHUB_SHA" --title "$release_tag" \ From 1965dddf76c2f6ca50f46fe8c9101922ec17a721 Mon Sep 17 00:00:00 2001 From: Wibias <37517432+Wibias@users.noreply.github.com> Date: Thu, 13 Aug 2026 02:13:31 +0200 Subject: [PATCH 3/3] test(release): pin authenticated tag creation --- tests/ci-workflows.test.ts | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/tests/ci-workflows.test.ts b/tests/ci-workflows.test.ts index f8d67f42b3..3eaba81ede 100644 --- a/tests/ci-workflows.test.ts +++ b/tests/ci-workflows.test.ts @@ -737,8 +737,17 @@ describe("GitHub Actions hardening", () => { } expect(createStep).not.toContain("set +e\n pr_notes"); expect(createStep.indexOf("gh api")).toBeGreaterThan(-1); - expect(createStep.indexOf('git tag "$release_tag"')).toBeGreaterThan(-1); - expect(createStep.indexOf("gh api")).toBeLessThan(createStep.indexOf('git tag "$release_tag"')); + const tagRefApi = '"repos/${GITHUB_REPOSITORY}/git/refs"'; + expect(createStep).toContain("gh api --method POST"); + expect(createStep).toContain(tagRefApi); + expect(createStep).toContain('-f ref="refs/tags/${release_tag}"'); + expect(createStep).toContain('-f sha="$GITHUB_SHA" >/dev/null'); + expect(createStep).not.toContain('git tag "$release_tag"'); + expect(createStep).not.toContain('git push origin "refs/tags/${release_tag}"'); + + // Release notes must be fully rendered before the remote tag is created. + expect(createStep.indexOf('"${render_args[@]}"')) + .toBeLessThan(createStep.indexOf(tagRefApi)); // The notes baseline must read the FULL tag set, not `--merged HEAD`: stable // tags live on main's lineage, which the preview branch does not carry, and a // trailing same-core preview must not hide the stable from the range