Using CircleCI to set Rubygems Credentials

rubygems

#1

I have the following error while trying to deploy a gem to rubygems.org via docker

Releasing new Gem
fastlane-plugin-lizard 1.1.0 built to pkg/fastlane-plugin-lizard-1.1.0.gem.
Tagged v1.1.0.
Pushed git commits and tags.
rake aborted!
Your rubygems.org credentials aren't set. Run `gem push` to set them.
/root/repo/Rakefile:20:in `block in <top (required)>'
/usr/local/bundle/gems/rake-12.3.1/exe/rake:27:in `<top (required)>'
Tasks: TOP => release => release:rubygem_push
(See full trace by running task with --trace)
Exited with code 1

I can’t do a gem push and add credentials in without human intervention. Is there other ways to go about doing it?

I am looking at setting a file at ~/.gem/credentials to enable rake release to work. Please help!


#2

Would you clarify why this is so, for readers who aren’t familiar with Ruby but who might be able to help with Linux/CI things generally?


#3

I need a file in ~./gem/credentials that will contain the rubygems api for rake release command to work, but the circleci environment variable options does not allow


#4

Why do you say it does it not allow this? You can copy any file you like to ~./gem/credentials.

Are you wanting to use a credential in an environment variable to write the contents of this file?


#5

The problem is that ~./gem/credentials needs to contain the API key in plain text. We don’t want to publish this plain text, so including it in the repository or config.yml is out of the question.

For reference, note how Travis does it: they have created a mechanism that allows to store sensitive data in an encrypted form to the public configuration file.

Unfortunately, Rubygems does not seem to support authentication based on public keys. :confused:


#6

Easy. Put the API key in your project > Settings (cog icon) > Environment Variables, giving it a suitable name (e.g. GEM_API_KEY).

Then create a credentials file with a placeholder key (e.g. __GEM_API_KEY__) and store that in your repo. When you do your build, write the file into the correct place using sed with the appropriate key replacement, and the post build (if you want to be paranoid), shred the credentials file.


#7

Sounds a little round-about but reasonable, thanks!

Does CircleCI have any means of factoring out things? At this point, it looks like config.yml is going to be about 5 times as long as a .travis.yml that does the same thing, and full of repetition. Some of that is due to little syntactic support for build matrices, and some of it due to there being shortcuts/packages for common tasks in Travis.


#8

Is it? I am trying to work out what would be simpler than running sed on a file. I suppose it could be done in one line with printf and line breaks, but that might get a bit unwieldy.


#9

If guess “round-about” is the wrong word; it’s certainly easy to script.
What feels off is that every gem developer and their mum will write the same thing, over and over again.

Plus, having necessary config outside of the config file can be bothersome. For instance, to mention just one use case, if I fork a repo that uses Circle CI, I won’t be able to just use it myself: I’ll have to go and set some settings in the web UI.
Of course, to be fair, secrets will always need touching. I don’t yet have enough experience with CI/CD to estimate whether this will be an issue with non-secrets.


#10

For the convenience of Googlers, this is what I did.

  1. Create file .circleci/gem_credentials with this content:

    ---
    :rubygems_api_key: __RUBYGEMS_API_KEY__
    
  2. In the Circle CI web frontend, add environment variable RUBYGEMS_API_KEY to the configuration of your repository. Set your (secret) API token as a value.

    Yes, we’ll have to trust Circle CI with it. If we decide we don’t anymore, we can always reset the API key on rubygems.org.

  3. Use the following snippet in your config.yml:

    - run:
          name: Deploy Gem
          command: |
            echo "gem `gem --version`"
            mkdir ~/.gem
            cat .circleci/gem_credentials | sed -e "s/__RUBYGEMS_API_KEY__/${RUBYGEMS_API_KEY}/" > ~/.gem/credentials
            chmod 0600 ~/.gem/credentials
            gem push my_gem-*.gem
            shred -u ~/.gem/credentials
    

    This is assuming that the requisite files have either been checked out or built earlier during the same job, or passed from an earlier job by means of a workspace.

Thanks @halfer for your help!


#11

Good write-up!

Yep, they are designed for this. The env var screen says:

Add environment variables to the build. You can add sensitive data (e.g. API keys) here, rather than placing them in the repository.

Of course, one has to decide whether to trust a CI provider at all :grinning:


#12

thank you! will give this a go!

the reason why I ask this question is because I do not want to save the credentials file into the image which was exposed in dockerhub as a public image


#13

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.