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
- Read the subprocess output embedded in the message — it carries the actual sigstore-cli error (auth, network, or version problem).
- In GitHub Actions, grant OIDC: add `permissions: { id-token: write, contents: read }` to the job or workflow.
- Ensure sigstore-cli is usable in the pushing environment: `gem install sigstore-cli`, then verify with `gem exec --conservative sigstore-cli --version`.
- Allow egress to fulcio.sigstore.dev / rekor.sigstore.dev (and the runner's OIDC provider) through proxies and firewalls.
- 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
- Grant `permissions: id-token: write` to GitHub Actions jobs that run gem push.
- Keep sigstore-cli installed in any environment that pushes gems.
- Whitelist egress to fulcio.sigstore.dev and rekor.sigstore.dev on firewalled runners.
- Dry-run a dummy gem push in CI before release day to verify the signing path.
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
- The gem #{installer.gem} can't be installed because the secu
- missing codepage argument
- unexpected debug option: %.*s\n
- too long: %s (max:%d)\n
- setup_debug_log failed (can't allocate memory)\n
AI-assisted analysis of ruby/ruby@0e5b888e1c (2026-08-21).
Data as JSON: /api/errors/d69941d976fefad8.
Report an issue: GitHub.