diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8954e51..f0768c5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -122,8 +122,9 @@ jobs: echo "Tag $TAG already exists" >&2 exit 1 fi - git tag "$TAG" "$GITHUB_SHA" - git push origin "refs/tags/$TAG" + gh api --method POST "repos/$GITHUB_REPOSITORY/git/refs" \ + -f ref="refs/tags/$TAG" \ + -f sha="$GITHUB_SHA" gh release create "$TAG" \ --repo "$GITHUB_REPOSITORY" \ --title "$TAG" \ diff --git a/scripts/check-release-control.mjs b/scripts/check-release-control.mjs index cd5b407..3a23b8a 100644 --- a/scripts/check-release-control.mjs +++ b/scripts/check-release-control.mjs @@ -49,6 +49,8 @@ export async function checkReleaseControl(root = resolve(import.meta.dirname, ". expect(release.permissions?.contents === "read", "release planning must be read-only"); expect(release.jobs?.release?.permissions?.contents === "write", "tag creation alone needs contents:write"); expect(release.jobs?.release?.environment === "release-control", "release authorization must use the protected release-control environment"); + expect(raw["release.yml"].includes('repos/$GITHUB_REPOSITORY/git/refs'), "release controller must create tags with its scoped GitHub token"); + expect(!raw["release.yml"].includes('git push origin "refs/tags/$TAG"'), "release controller must not push tags without explicit authentication"); expect(raw["release.yml"].includes("--draft"), "release controller must create a draft release"); expect(!raw["release.yml"].includes("--draft=false"), "release controller must not finalize its own release");