-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Push with auto-attestation #9325
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
9ee556d
e658556
3a9f4bf
0fd9443
0460b2a
365ccdc
9cd860f
fcd4d81
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -92,21 +92,70 @@ def send_gem(name) | |
| private | ||
|
|
||
| def send_push_request(name, args) | ||
| # Attestation is only supported on rubygems.org with GitHub Actions (not JRuby) | ||
| if RUBY_ENGINE != "jruby" && attestation_supported_host? && ENV["GITHUB_ACTIONS"] | ||
| send_push_request_with_attestation(name, args) | ||
| else | ||
| send_push_request_without_attestation(name, args) | ||
| end | ||
| end | ||
|
|
||
| def send_push_request_without_attestation(name, args) | ||
| scope = get_push_scope | ||
| rubygems_api_request(*args, scope: scope) do |request| | ||
| body = Gem.read_binary name | ||
| if options[:attestations].any? | ||
| request.set_form([ | ||
| ["gem", body, { filename: name, content_type: "application/octet-stream" }], | ||
| get_attestations_part, | ||
| ], "multipart/form-data") | ||
| else | ||
| request.body = body | ||
| request.add_field "Content-Type", "application/octet-stream" | ||
| request.add_field "Content-Length", request.body.size | ||
| request.body = body | ||
| request.add_field "Content-Type", "application/octet-stream" | ||
| request.add_field "Content-Length", request.body.size | ||
| request.add_field "Authorization", api_key | ||
| end | ||
| end | ||
|
|
||
| def send_push_request_with_attestation(name, args) | ||
| attestations = if options[:attestations].any? | ||
| options[:attestations].map do |attestation| | ||
| Gem.read_binary(attestation) | ||
| end | ||
| else | ||
| bundle_path = attest!(name) | ||
| begin | ||
| [Gem.read_binary(bundle_path)] | ||
| ensure | ||
| File.unlink(bundle_path) if bundle_path && File.exist?(bundle_path) | ||
| end | ||
| end | ||
| bundles = "[" + attestations.join(",") + "]" | ||
|
|
||
| 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", bundles, { content_type: "application/json" }], | ||
| ], "multipart/form-data") | ||
| request.add_field "Authorization", api_key | ||
| end | ||
| rescue StandardError => e | ||
| alert_warning "Failed to push with attestation, retrying without attestation.\n#{e.full_message}" | ||
| send_push_request_without_attestation(name, args) | ||
| end | ||
|
|
||
| def attest!(name) | ||
| require "open3" | ||
| require "tempfile" | ||
|
|
||
| tempfile = Tempfile.new([File.basename(name, ".*"), ".sigstore.json"]) | ||
| bundle = tempfile.path | ||
| tempfile.close(false) | ||
|
|
||
| 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.2", "sign", name, "--bundle", bundle, | ||
| unsetenv_others: true | ||
| ) | ||
| raise Gem::Exception, "Failed to sign gem:\n\n#{out}" unless st.success? | ||
|
|
||
| bundle | ||
| end | ||
|
|
||
| def get_hosts_for(name) | ||
|
|
@@ -122,14 +171,7 @@ def get_push_scope | |
| :push_rubygem | ||
| end | ||
|
|
||
| def get_attestations_part | ||
| bundles = "[" + options[:attestations].map do |attestation| | ||
| Gem.read_binary(attestation) | ||
| end.join(",") + "]" | ||
| [ | ||
| "attestations", | ||
| bundles, | ||
| { content_type: "application/json" }, | ||
| ] | ||
| def attestation_supported_host? | ||
| (@host || Gem.host) == "https://rubygems.org" | ||
| end | ||
|
Comment on lines
+174
to
176
|
||
| end | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The early return for
RUBY_ENGINE == "jruby" || !attestation_supported_host?skips all attestation, including when the user explicitly passes--attestation. That changes existing behavior and also contradicts the PR description (“When--attestationoption provided,gem pushonly uses that.”). Consider only disabling auto attestation here (i.e., still callsend_push_request_with_attestationwhenoptions[:attestations].any?), and gate theattest!path separately for JRuby/unsupported hosts.