Skip to content

Commit

Permalink
Attest by default when using trusted publishing
Browse files Browse the repository at this point in the history
Fallback to pushing without attestations on any failure

Signed-off-by: Samuel Giddins <segiddins@segiddins.me>
  • Loading branch information
segiddins committed Nov 20, 2024
1 parent 612653d commit c81905f
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 1 deletion.
11 changes: 10 additions & 1 deletion action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@ inputs:
description: "Whether to setup the trusted publisher for the gem"
required: false
default: "true"
attestations:
description: >-
[EXPERIMENTAL]
Enable experimental support for sigstore attestations.
Only works with RubyGems.org via Trusted Publishing.
required: false
default: "true"
outputs: {}
branding:
color: "red"
Expand All @@ -25,10 +32,12 @@ runs:
shell: bash
- name: Configure trusted publishing credentials
if: ${{ inputs.setup-trusted-publisher == 'true' }}
uses: rubygems/configure-rubygems-credentials@v1.0.0
uses: rubygems/configure-rubygems-credentials@a2b9242bc411d79356771fc9b9ddebcc3cd1b5dd
- name: Run release rake task
run: bundle exec rake release
shell: bash
env:
RUBYOPT: "${{ inputs.attestations == 'true' && format('-r{0}/rubygems-attestation-patch.rb {1}', github.action_path, env.RUBYOPT) || env.RUBYOPT }}"
- name: Wait for release to propagate
if: ${{ inputs.await-release == 'true' }}
run: gem exec rubygems-await pkg/*.gem
Expand Down
49 changes: 49 additions & 0 deletions rubygems-attestation-patch.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# frozen_string_literal: true

return unless defined?(Gem)

require "rubygems/commands/push_command"

Gem::Commands::PushCommand.prepend(Module.new do
def send_push_request(name, args)
return super if options[:attestations]&.any? || @host != "https://rubygems.org"

begin
send_push_request_with_attestation(name, args)
rescue StandardError => e
alert_warning "Failed to push with attestation, retrying without attestation.\n#{e.full_message}"
super
end
end

def send_push_request_with_attestation(name, args)
attestation = attest!(name)
if options[:attestations]
options[:attestations] << attestation
send_push_request(name, args)
else
rubygems_api_request(*args, scope: get_push_scope) do |request|
request.set_form([
["gem", Gem.read_binary(name), { filename: name, content_type: "application/octet-stream" }],
["attestations", "[#{Gem.read_binary(attestation)}]", { content_type: "application/json" }]
], "multipart/form-data")
request.add_field "Authorization", api_key
end
end
end

def attest!(name)
require "open3"
bundle = "#{name}.sigstore.json"
env = defined?(Bundler.unbundled_env) ? Bundler.unbundled_env : ENV.to_h
out, st = Open3.capture2e(
env,
Gem.ruby, "-S", "gem", "exec",
"sigstore-cli:0.2.1", "sign", name, "--bundle", bundle,
unsetenv_others: true
)
raise Gem::Exception, "Failed to sign gem:\n\n#{out}" unless st.success?

bundle
end
end)

0 comments on commit c81905f

Please sign in to comment.