Skip to content

Commit 40b729a

Browse files
Use symbolic action references in release workflows
1 parent 52a98e1 commit 40b729a

9 files changed

Lines changed: 53 additions & 24 deletions

File tree

‎.github/workflows/release-prepare.yaml‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,12 @@ jobs:
2525
if: github.ref == 'refs/heads/main'
2626
runs-on: ubuntu-latest
2727
steps:
28-
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
28+
- uses: actions/checkout@v7
2929
with:
3030
ref: main
3131
fetch-depth: 0
3232
persist-credentials: false
33-
- uses: ruby/setup-ruby@a0102e0972be65f351c307e2d64b9314a57c8073 # v1
33+
- uses: ruby/setup-ruby@v1
3434
with:
3535
ruby-version: "3.4"
3636
bundler-cache: true

‎.github/workflows/release-publish.yaml‎

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,11 @@ jobs:
2727
release: ${{ steps.inspect.outputs.release }}
2828
commit: ${{ steps.inspect.outputs.commit }}
2929
steps:
30-
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
30+
- uses: actions/checkout@v7
3131
with:
3232
fetch-depth: 0
3333
persist-credentials: false
34-
- uses: ruby/setup-ruby@a0102e0972be65f351c307e2d64b9314a57c8073 # v1
34+
- uses: ruby/setup-ruby@v1
3535
with:
3636
ruby-version: "3.4"
3737
bundler-cache: true
@@ -52,12 +52,15 @@ jobs:
5252
id-token: write
5353
attestations: write
5454
steps:
55-
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
55+
- uses: actions/checkout@v7
5656
with:
57+
# Inspection verified this merged commit belongs to the default branch.
58+
# Checkout v7 also blocks merged fork PRs without this explicit opt-in.
59+
allow-unsafe-pr-checkout: true
5760
ref: ${{ needs.inspect.outputs.commit }}
5861
fetch-depth: 0
5962
persist-credentials: false
60-
- uses: ruby/setup-ruby@a0102e0972be65f351c307e2d64b9314a57c8073 # v1
63+
- uses: ruby/setup-ruby@v1
6164
with:
6265
ruby-version: "3.4"
6366
rubygems: '4.0.21'
@@ -76,7 +79,7 @@ jobs:
7679
- name: Attest gem and release receipt
7780
if: steps.build.outputs.restored != 'true'
7881
id: attest
79-
uses: actions/attest@1e69f48acb82d1966a394da916b4c1698aa569d6 # v4
82+
uses: actions/attest@v4
8083
with:
8184
subject-path: |
8285
${{ steps.build.outputs.package }}
@@ -88,13 +91,13 @@ jobs:
8891
run: cp "$ATTESTATION_BUNDLE" pkg/provenance.sigstore.json
8992
- name: Preserve release before upload
9093
if: steps.build.outputs.restored != 'true'
91-
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
94+
uses: actions/upload-artifact@v7
9295
with:
9396
name: ${{ steps.build.outputs.artifact }}
9497
path: pkg/
9598
if-no-files-found: error
9699
retention-days: 90
97-
- uses: rubygems/configure-rubygems-credentials@2a7221c7c44c30ebc68eda38fa25c60b918245c7
100+
- uses: rubygems/configure-rubygems-credentials@main
98101
- name: Verify, publish, and finalize
99102
env:
100103
GH_TOKEN: ${{ github.token }}

‎.github/workflows/release-validate.yaml‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@ jobs:
1515
name: Release validation
1616
runs-on: ubuntu-latest
1717
steps:
18-
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
18+
- uses: actions/checkout@v7
1919
with:
2020
ref: ${{ github.event.pull_request.head.sha }}
2121
fetch-depth: 0
2222
persist-credentials: false
23-
- uses: ruby/setup-ruby@a0102e0972be65f351c307e2d64b9314a57c8073 # v1
23+
- uses: ruby/setup-ruby@v1
2424
with:
2525
ruby-version: "3.4"
2626
bundler-cache: true

‎context/getting-started.md‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ bundle exec bake agent:context:install
1818
bundle exec bake gem:github:setup:plan
1919
```
2020

21-
Setup adds three pinned workflows, `config/release.yaml`, native ruleset payloads, and `.github/releasing.md`. Identical reruns do nothing; conflicting existing files stop before any file is written. Setup does not replace other publishers: remove conflicting release workflows during migration.
21+
Setup adds three release workflows, `config/release.yaml`, native ruleset payloads, and `.github/releasing.md`. Identical reruns do nothing; conflicting existing files stop before any file is written. Setup does not replace other publishers: remove conflicting release workflows during migration.
2222

2323
To adopt template fixes after upgrading the gem, start from a clean working tree, edit `config/release.yaml` as needed, and regenerate:
2424

@@ -29,6 +29,8 @@ git diff
2929

3030
The task updates the managed workflows, policy payloads, configuration formatting, and maintainer instructions directly in the working tree and returns the changed paths. It does not stage, commit, or change remote settings. An agent or maintainer can review the diff and selectively keep changes, restoring repository-specific customizations from Git where needed. Commit or stash existing edits first: generated files are replaced by the current templates. Repeating an update produces no further changes; intentionally retained customizations will appear in later update diffs. Apply remote rulesets after the corresponding workflows are running.
3131

32+
Release workflows follow `bake modernize` action versions and use moving major tags where upstream provides them. These tags receive upstream updates automatically; full commit hashes select fixed revisions. The RubyGems credentials action uses its [documented `@main` reference](https://github.com/rubygems/configure-rubygems-credentials#trusted-publisher-recommended), since upstream does not provide a moving major tag. Repositories that require fixed revisions can customize these references.
33+
3234
The default is two approvals with explicit administrator bypass, dismissed stale reviews, approval of the last push, strict up-to-date CI, and immutable default-branch history/release tags. These branch rules affect **all PRs** into the default branch. Ordinary administrator reviews count as one review. A human who dispatches a bot-authored PR is not its author under GitHub's native rules.
3335

3436
Review `gem:github:setup:plan`, merge the setup PR, and confirm that **Release validation** and every selected check run. Then apply the four managed rulesets using an administrator's `gh` login:

‎guides/getting-started/readme.md‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ bundle exec bake agent:context:install
1818
bundle exec bake gem:github:setup:plan
1919
```
2020

21-
Setup adds three pinned workflows, `config/release.yaml`, native ruleset payloads, and `.github/releasing.md`. Identical reruns do nothing; conflicting existing files stop before any file is written. Setup does not replace other publishers: remove conflicting release workflows during migration.
21+
Setup adds three release workflows, `config/release.yaml`, native ruleset payloads, and `.github/releasing.md`. Identical reruns do nothing; conflicting existing files stop before any file is written. Setup does not replace other publishers: remove conflicting release workflows during migration.
2222

2323
To adopt template fixes after upgrading the gem, start from a clean working tree, edit `config/release.yaml` as needed, and regenerate:
2424

@@ -29,6 +29,8 @@ git diff
2929

3030
The task updates the managed workflows, policy payloads, configuration formatting, and maintainer instructions directly in the working tree and returns the changed paths. It does not stage, commit, or change remote settings. An agent or maintainer can review the diff and selectively keep changes, restoring repository-specific customizations from Git where needed. Commit or stash existing edits first: generated files are replaced by the current templates. Repeating an update produces no further changes; intentionally retained customizations will appear in later update diffs. Apply remote rulesets after the corresponding workflows are running.
3131

32+
Release workflows follow `bake modernize` action versions and use moving major tags where upstream provides them. These tags receive upstream updates automatically; full commit hashes select fixed revisions. The RubyGems credentials action uses its [documented `@main` reference](https://github.com/rubygems/configure-rubygems-credentials#trusted-publisher-recommended), since upstream does not provide a moving major tag. Repositories that require fixed revisions can customize these references.
33+
3234
The default is two approvals with explicit administrator bypass, dismissed stale reviews, approval of the last push, strict up-to-date CI, and immutable default-branch history/release tags. These branch rules affect **all PRs** into the default branch. Ordinary administrator reviews count as one review. A human who dispatches a bot-authored PR is not its author under GitHub's native rules.
3335

3436
Review `gem:github:setup:plan`, merge the setup PR, and confirm that **Release validation** and every selected check run. Then apply the four managed rulesets using an administrator's `gh` login:

‎templates/release-prepare.yaml.erb‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,12 @@ jobs:
2525
if: github.ref == 'refs/heads/<%= branch %>'
2626
runs-on: ubuntu-latest
2727
steps:
28-
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
28+
- uses: actions/checkout@v7
2929
with:
3030
ref: <%= branch %>
3131
fetch-depth: 0
3232
persist-credentials: false
33-
- uses: ruby/setup-ruby@a0102e0972be65f351c307e2d64b9314a57c8073 # v1
33+
- uses: ruby/setup-ruby@v1
3434
with:
3535
ruby-version: <%= ruby.to_json %>
3636
bundler-cache: true

‎templates/release-publish.yaml.erb‎

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,11 @@ jobs:
2727
release: ${{ steps.inspect.outputs.release }}
2828
commit: ${{ steps.inspect.outputs.commit }}
2929
steps:
30-
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
30+
- uses: actions/checkout@v7
3131
with:
3232
fetch-depth: 0
3333
persist-credentials: false
34-
- uses: ruby/setup-ruby@a0102e0972be65f351c307e2d64b9314a57c8073 # v1
34+
- uses: ruby/setup-ruby@v1
3535
with:
3636
ruby-version: <%= ruby.to_json %>
3737
bundler-cache: true
@@ -52,12 +52,15 @@ jobs:
5252
id-token: write
5353
attestations: write
5454
steps:
55-
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
55+
- uses: actions/checkout@v7
5656
with:
57+
# Inspection verified this merged commit belongs to the default branch.
58+
# Checkout v7 also blocks merged fork PRs without this explicit opt-in.
59+
allow-unsafe-pr-checkout: true
5760
ref: ${{ needs.inspect.outputs.commit }}
5861
fetch-depth: 0
5962
persist-credentials: false
60-
- uses: ruby/setup-ruby@a0102e0972be65f351c307e2d64b9314a57c8073 # v1
63+
- uses: ruby/setup-ruby@v1
6164
with:
6265
ruby-version: <%= ruby.to_json %>
6366
rubygems: '4.0.21'
@@ -78,7 +81,7 @@ jobs:
7881
- name: Attest gem and release receipt
7982
if: steps.build.outputs.restored != 'true'
8083
id: attest
81-
uses: actions/attest@1e69f48acb82d1966a394da916b4c1698aa569d6 # v4
84+
uses: actions/attest@v4
8285
with:
8386
subject-path: |
8487
${{ steps.build.outputs.package }}
@@ -90,13 +93,13 @@ jobs:
9093
run: cp "$ATTESTATION_BUNDLE" pkg/provenance.sigstore.json
9194
- name: Preserve release before upload
9295
if: steps.build.outputs.restored != 'true'
93-
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
96+
uses: actions/upload-artifact@v7
9497
with:
9598
name: ${{ steps.build.outputs.artifact }}
9699
path: pkg/
97100
if-no-files-found: error
98101
retention-days: 90
99-
- uses: rubygems/configure-rubygems-credentials@2a7221c7c44c30ebc68eda38fa25c60b918245c7
102+
- uses: rubygems/configure-rubygems-credentials@main
100103
- name: Verify, publish, and finalize
101104
env:
102105
GH_TOKEN: ${{ github.token }}

‎templates/release-validate.yaml.erb‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@ jobs:
1515
name: Release validation
1616
runs-on: ubuntu-latest
1717
steps:
18-
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
18+
- uses: actions/checkout@v7
1919
with:
2020
ref: ${{ github.event.pull_request.head.sha }}
2121
fetch-depth: 0
2222
persist-credentials: false
23-
- uses: ruby/setup-ruby@a0102e0972be65f351c307e2d64b9314a57c8073 # v1
23+
- uses: ruby/setup-ruby@v1
2424
with:
2525
ruby-version: <%= ruby.to_json %>
2626
bundler-cache: true

‎test/bake/gem/github/setup.rb‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,25 @@ def generate
6262
expect(File.read(path)).to be == "Custom workflow\n"
6363
end
6464

65+
it "permits a fork checkout only after merged release inspection" do
66+
generate
67+
workflow = YAML.safe_load_file(File.join(root, ".github/workflows/release-publish.yaml"))
68+
inspect = workflow.fetch("jobs").fetch("inspect")
69+
expect(inspect.fetch("if")).to be == "github.event.pull_request.merged == true"
70+
expect(inspect.fetch("steps").first.fetch("with")).not.to have_keys("allow-unsafe-pr-checkout", "ref")
71+
expect(inspect.fetch("steps").last.fetch("run")).to be == "bundle exec bake gem:github:release:resolve"
72+
publish = workflow.fetch("jobs").fetch("publish")
73+
expect(publish.fetch("needs")).to be == "inspect"
74+
expect(publish.fetch("if")).to be == "needs.inspect.outputs.release == 'true'"
75+
checkout = publish.fetch("steps").first.fetch("with")
76+
expect(checkout.fetch("ref")).to be == "${{ needs.inspect.outputs.commit }}"
77+
expect(checkout.fetch("allow-unsafe-pr-checkout")).to be == true
78+
%w[prepare validate].each do |name|
79+
workflow = File.read(File.join(root, ".github/workflows/release-#{name}.yaml"))
80+
expect(workflow).not.to be(:include?, "allow-unsafe-pr-checkout")
81+
end
82+
end
83+
6584
it "attests both the gem and its source receipt with native provenance" do
6685
generate
6786
workflow = YAML.safe_load_file(File.join(root, ".github/workflows/release-publish.yaml"))

0 commit comments

Comments
 (0)