From 19f31a87fbace9bb4b2d7808298b916bcb253b45 Mon Sep 17 00:00:00 2001 From: Ajay Krishnan Date: Sun, 19 Jul 2026 16:23:20 -0700 Subject: [PATCH] Pin CI actions and test Ruby 4 --- .github/workflows/release.yml | 6 +++--- .github/workflows/test.yml | 6 +++--- test/release_workflow_test.rb | 3 ++- test/workflow_contract_test.rb | 39 ++++++++++++++++++++++++++++++++++ 4 files changed, 47 insertions(+), 7 deletions(-) create mode 100644 test/workflow_contract_test.rb diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index cb16d70..4962b14 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -14,11 +14,11 @@ jobs: id-token: write environment: release steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 with: persist-credentials: false - - uses: ruby/setup-ruby@v1 + - uses: ruby/setup-ruby@003a5c4d8d6321bd302e38f6f0ec593f77f06600 # v1.319.0 with: ruby-version: ruby bundler-cache: true - - uses: rubygems/release-gem@v1 + - uses: rubygems/release-gem@052cc82692552de3ef2b81fd670e41d13cba8092 # v1.4.0 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b002486..10dd3eb 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -12,12 +12,12 @@ jobs: strategy: fail-fast: false matrix: - ruby: ["3.2", "3.3", "3.4"] + ruby: ["3.2", "3.3", "3.4", "4.0"] steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - name: Set up Ruby ${{ matrix.ruby }} - uses: ruby/setup-ruby@v1 + uses: ruby/setup-ruby@003a5c4d8d6321bd302e38f6f0ec593f77f06600 # v1.319.0 with: ruby-version: ${{ matrix.ruby }} bundler-cache: true diff --git a/test/release_workflow_test.rb b/test/release_workflow_test.rb index e9afa84..b381b62 100644 --- a/test/release_workflow_test.rb +++ b/test/release_workflow_test.rb @@ -6,6 +6,7 @@ require "yaml" class ReleaseWorkflowTest < Minitest::Test ROOT = File.expand_path("..", __dir__) WORKFLOW_PATH = File.join(ROOT, ".github", "workflows", "release.yml") + RELEASE_GEM_ACTION = "rubygems/release-gem@052cc82692552de3ef2b81fd670e41d13cba8092" def workflow @workflow ||= YAML.safe_load(File.read(WORKFLOW_PATH), aliases: false) @@ -27,7 +28,7 @@ class ReleaseWorkflowTest < Minitest::Test ) steps = push_job.fetch("steps") - assert_equal 1, steps.count { |step| step["uses"] == "rubygems/release-gem@v1" } + assert_equal 1, steps.count { |step| step["uses"] == RELEASE_GEM_ACTION } refute steps.any? { |step| step.fetch("run", "").match?(/\bgem\s+push\b/) } end end diff --git a/test/workflow_contract_test.rb b/test/workflow_contract_test.rb new file mode 100644 index 0000000..c1057c4 --- /dev/null +++ b/test/workflow_contract_test.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +require "minitest/autorun" +require "yaml" + +class WorkflowContractTest < Minitest::Test + ROOT = File.expand_path("..", __dir__) + WORKFLOW_DIRECTORY = File.join(ROOT, ".github", "workflows") + TEST_WORKFLOW_PATH = File.join(WORKFLOW_DIRECTORY, "test.yml") + ACTION_PINS = { + "actions/checkout" => "93cb6efe18208431cddfb8368fd83d5badbf9bfd", + "ruby/setup-ruby" => "003a5c4d8d6321bd302e38f6f0ec593f77f06600", + "rubygems/release-gem" => "052cc82692552de3ef2b81fd670e41d13cba8092" + }.freeze + + def test_matrix_covers_every_supported_ruby + workflow = YAML.safe_load(File.read(TEST_WORKFLOW_PATH), aliases: false) + versions = workflow.dig("jobs", "test", "strategy", "matrix", "ruby") + + assert_equal %w[3.2 3.3 3.4 4.0], versions + end + + def test_every_third_party_action_uses_its_reviewed_commit + action_uses = Dir[File.join(WORKFLOW_DIRECTORY, "*.{yml,yaml}")].sort.flat_map do |path| + File.readlines(path).filter_map do |line| + line[/^\s*-?\s*uses:\s*([^\s#]+)/, 1] + end + end + + assert_equal 5, action_uses.length + action_uses.each do |action_use| + action, separator, revision = action_use.rpartition("@") + + assert_equal "@", separator + assert_equal ACTION_PINS.fetch(action), revision + assert_match(/\A[0-9a-f]{40}\z/, revision) + end + end +end