ruby/ruby · warning · Gem::Exception

Failed to sign gem: #{out}

Error message

Failed to sign gem:

#{out}

What it means

Raised by `gem push` while producing a Sigstore attestation: RubyGems shells out to `sigstore-cli sign <gem> --bundle <tmpfile>` (via `gem exec --conservative`) and raises this Gem::Exception, embedding the subprocess's combined stdout/stderr, when the child exits non-zero. In the current flow send_push_request_with_attestation rescues StandardError, prints 'Failed to push with attestation, retrying without attestation' with this message, and pushes the gem unattested — so the push usually completes, minus the attestation.

Source

Thrown at lib/rubygems/commands/push_command.rb:166

  def attest!(name)
    require "open3"
    require "shellwords"
    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
    # Gem.ruby is quoted if it contains whitespace, so split it into argv
    # elements to keep the quotes out of the spawned command.
    out, st = Open3.capture2e(
      env,
      *Shellwords.split(Gem.ruby), "-S", "gem", "exec", "--conservative",
      "sigstore-cli", "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)
    gem_metadata = Gem::Package.new(name).spec.metadata

    [
      gem_metadata["default_gem_server"],
      gem_metadata["allowed_push_host"],
    ]
  end

  def get_push_scope
    :push_rubygem
  end

  def attestation_supported_host?

View on GitHub (pinned to 0e5b888e1c)

Solutions

  1. Read the subprocess output embedded in the message — it carries the actual sigstore-cli error (auth, network, or version problem).
  2. In GitHub Actions, grant OIDC: add `permissions: { id-token: write, contents: read }` to the job or workflow.
  3. Ensure sigstore-cli is usable in the pushing environment: `gem install sigstore-cli`, then verify with `gem exec --conservative sigstore-cli --version`.
  4. Allow egress to fulcio.sigstore.dev / rekor.sigstore.dev (and the runner's OIDC provider) through proxies and firewalls.
  5. If you do not need attestations, treat the warning as informational — the push completes without attestation.
Defensive patterns

Strategy: validation

Validate before calling

require "open3"
require "shellwords"

out, st = Open3.capture2e(*Shellwords.split(Gem.ruby), "-S", "gem", "exec", "--conservative", "sigstore-cli", "--version")
warn "sigstore-cli unusable, attestation will fail:\n#{out}" unless st.success?

Try / catch

begin
  Gem::Commands::PushCommand.new.invoke(*args)
rescue Gem::Exception => e
  raise unless e.message.start_with?("Failed to sign gem")
  warn "pushing without attestation: #{e.message}"
end

Prevention

When it happens

Trigger: Running `gem push` in an environment where auto-attestation triggers (non-JRuby, host is rubygems.org, ENV["GITHUB_ACTIONS"] set) and the sigstore-cli subprocess fails: sigstore-cli not installed, no OIDC/federated credential available, or network failure reaching Fulcio/Rekor.

Common situations: GitHub Actions workflows missing `permissions: id-token: write`; self-hosted or containerized runners without the sigstore-cli gem; firewalled runners blocking sigstore.dev endpoints; a Bundler-sanitized environment confusing the spawned `gem exec` child.

Related errors


AI-assisted analysis of ruby/ruby@0e5b888e1c (2026-08-21). Data as JSON: /api/errors/d69941d976fefad8. Report an issue: GitHub.