diff --git a/.github/workflows/pr-verify.yml b/.github/workflows/pr-verify.yml new file mode 100644 index 0000000..059ef8a --- /dev/null +++ b/.github/workflows/pr-verify.yml @@ -0,0 +1,47 @@ +name: Run Tests + +on: + pull_request: + branches: + - main + +jobs: + # Test on code-dot-org Ruby version + test_3_0_5: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: 3.0.5 + bundler-cache: true + + - name: Install gems + run: bundle install + + - name: Run tests + run: bundle exec rake test + + #Test on latest Ruby + test_3_3: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: 3.3 + bundler-cache: true + + - name: Install gems + run: bundle install + + - name: Run tests + run: bundle exec rake test diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..eca690e --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +3.0.5 diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..f038c68 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,8 @@ +FROM ruby:3.0.5 + +WORKDIR /app + +# Copy bare minimum files to install gems +COPY Gemfile aws-google.gemspec /app/ +COPY lib /app/lib +RUN bundle install diff --git a/README.md b/README.md index 49b54a8..c096056 100644 --- a/README.md +++ b/README.md @@ -24,9 +24,14 @@ Or install it yourself as: Visit the [Google API Console](https://console.developers.google.com/) to create/obtain [OAuth 2.0 Client ID credentials](https://support.google.com/cloud/answer/6158849) (client ID and client secret) for an application in your Google account. ### Create an AWS IAM Role -Create an AWS IAM Role with the desired IAM policies attached, and a ['trust policy'](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_terms-and-concepts.html#term_trust-policy) ([`AssumeRolePolicyDocument`](https://docs.aws.amazon.com/IAM/latest/APIReference/API_CreateRole.html)) allowing the [`sts:AssumeRoleWithWebIdentity`](https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRoleWithWebIdentity.html) action with [Web Identity Federation condition keys](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_iam-condition-keys.html#condition-keys-wif) authorizing +Create an AWS IAM Role with the desired IAM policies attached, and a ['trust policy'][1] ([`AssumeRolePolicyDocument`][2]) allowing the [`sts:AssumeRoleWithWebIdentity`][3] action with [Web Identity Federation condition keys][4] authorizing your Google Client ID (`accounts.google.com:aud`) and a specific set of Google Account IDs (`accounts.google.com:sub`): +[1]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_terms-and-concepts.html#term_trust-policy "IAM Trust Policy" +[2]: https://docs.aws.amazon.com/IAM/latest/APIReference/API_CreateRole.html "Create Role API" +[3]: https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRoleWithWebIdentity.html "Assume Role With Identity API" +[4]: https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_iam-condition-keys.html#condition-keys-wif "IAM Condition Keys" + ```json { "Version": "2012-10-17", @@ -53,6 +58,7 @@ your Google Client ID (`accounts.google.com:aud`) and a specific set of Google A ### Method 1: `Aws::Google` In your Ruby code, construct an `Aws::Google` object by passing the AWS `role_arn`, Google `client_id` and `client_secret`, either as constructor arguments or via the `Aws::Google.config` global defaults: + ```ruby require 'aws/google' @@ -87,9 +93,22 @@ The extra `credential_process` config line tells AWS to [Source Credentials with ## Development -After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment. +Prerequisites: + +* Ruby 3.0.5 + +You can have Ruby installed locally, or use Docker and mount this repository into a Ruby container. By using Docker you can avoid conflicts with differing Ruby versions or other installed gems. To run and 'bash' into a Ruby container, install Docker and run the following. See [docker-compose.yml](docker-compose.yml) for details. + +``` +docker compose build +docker compose run ruby +``` + +With either option, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment. + +To install this gem onto your local machine, run `bundle exec rake install`. -To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org). +To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org). ## Contributing diff --git a/aws-google.gemspec b/aws-google.gemspec index 9cb8004..a80635f 100644 --- a/aws-google.gemspec +++ b/aws-google.gemspec @@ -1,8 +1,9 @@ -lib = File.expand_path('../lib', __FILE__) +lib = File.expand_path('lib', __dir__) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) require 'aws/google/version' Gem::Specification.new do |spec| + spec.required_ruby_version = '>= 3.0.5' spec.name = 'aws-google' spec.version = Aws::Google::VERSION spec.authors = ['Will Jordan'] @@ -21,14 +22,14 @@ Gem::Specification.new do |spec| spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } spec.require_paths = ['lib'] - spec.add_dependency 'aws-sdk-core', '~> 3.130' - spec.add_dependency 'google-apis-core' - spec.add_dependency 'launchy', '~> 2' + spec.add_dependency 'aws-sdk-core', '~> 3.211.0' + spec.add_dependency 'google-apis-core', '~> 0.15.1' + spec.add_dependency 'launchy', '~> 3.0.1' - spec.add_development_dependency 'activesupport', '~> 5' - spec.add_development_dependency 'minitest', '~> 5.14.2' - spec.add_development_dependency 'mocha', '~> 1.5' - spec.add_development_dependency 'rake', '~> 12' - spec.add_development_dependency 'timecop', '~> 0.8' - spec.add_development_dependency 'webmock', '~> 3.3' + spec.add_development_dependency 'activesupport', '~> 6.1.7.8' + spec.add_development_dependency 'minitest', '~> 5.25.1' + spec.add_development_dependency 'mocha', '~> 2.4.5' + spec.add_development_dependency 'rake', '~> 13.2.1' + spec.add_development_dependency 'timecop', '~> 0.9.10' + spec.add_development_dependency 'webmock', '3.24.0' end diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..a39c309 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,7 @@ +services: + ruby: + build: . + volumes: + - .:/app + working_dir: /app + command: bash diff --git a/lib/aws/google/cached_credentials.rb b/lib/aws/google/cached_credentials.rb index 61c93dd..de3b032 100644 --- a/lib/aws/google/cached_credentials.rb +++ b/lib/aws/google/cached_credentials.rb @@ -23,22 +23,31 @@ def initialize(options = {}) end def refresh_if_near_expiration - if near_expiration?(SYNC_EXPIRATION_LENGTH) - @mutex.synchronize do - if near_expiration?(SYNC_EXPIRATION_LENGTH) - refresh - write_credentials - end + return unless near_expiration?(SYNC_EXPIRATION_LENGTH) + + @mutex.synchronize do + if near_expiration?(SYNC_EXPIRATION_LENGTH) + refresh + write_credentials end end end # Write credentials and expiration to AWS credentials file. def write_credentials - # AWS CLI is needed because writing AWS credentials is not supported by the AWS Ruby SDK. + # Ensure the AWS CLI is available before attempting to write credentials. return unless system('which aws >/dev/null 2>&1') - Aws::SharedCredentials::KEY_MAP.transform_values(&@credentials.method(:send)). - merge(expiration: @expiration).each do |key, value| + + # Manually map the credentials to the keys used by AWS CLI + credentials_map = { + 'aws_access_key_id' => @credentials.access_key_id, + 'aws_secret_access_key' => @credentials.secret_access_key, + 'aws_session_token' => @credentials.session_token, + 'expiration' => @expiration + } + + # Use the AWS CLI to set the credentials in the session profile + credentials_map.each do |key, value| system("aws configure set #{key} #{value} --profile #{@session_profile}") end end diff --git a/lib/aws/google/version.rb b/lib/aws/google/version.rb index d3ff4cf..77db7b7 100644 --- a/lib/aws/google/version.rb +++ b/lib/aws/google/version.rb @@ -1,5 +1,5 @@ module Aws class Google - VERSION = '0.2.0'.freeze + VERSION = '0.2.1'.freeze end end diff --git a/test/aws/google_test.rb b/test/aws/google_test.rb index f217585..ba2359e 100644 --- a/test/aws/google_test.rb +++ b/test/aws/google_test.rb @@ -83,9 +83,9 @@ it 'refreshes expired Google auth token credentials' do m = mock m.stubs(:refresh!) - m.stubs(:id_token). - returns(JWT.encode({ email: 'email', exp: Time.now.to_i - 1 }, '')). - then.returns(JWT.encode({ email: 'email' }, '')) + m.stubs(:id_token) + .returns(JWT.encode({ email: 'email', exp: Time.now.to_i - 1 }, '')) + .then.returns(JWT.encode({ email: 'email' }, '')) Google::Auth.stubs(:get_application_default).returns(m) system.times(5) @@ -108,6 +108,7 @@ expiration = provider.expiration _(expiration).must_equal(provider.expiration) Timecop.travel(1.5.hours.from_now) do + provider.refresh! _(expiration).wont_equal(provider.expiration) end end @@ -124,7 +125,7 @@ Aws::Google.any_instance.expects(:refresh).never Aws::Google.new(config).credentials end - + it 'uses config defaults for new AWS clients' do Aws::Google.stubs(:config).returns(config) @oauth_default.once @@ -204,7 +205,7 @@ Aws::Google.new(config).credentials end end - + describe 'no shared config' do before do Aws.shared_config.fresh(