aptible-auth 1.3.0 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fa366e77caf944b6664bf9028ed18951244aa306db65267f4f7cd6abc5b186b6
4
- data.tar.gz: f8142c1e9887387bf58187937b5f182396b83ff9f68f834811065b5606e33de0
3
+ metadata.gz: 7fa3270646948b32ac4d6f467b2441757c28af525f0c2c1bf465c0a7ceda6cf4
4
+ data.tar.gz: d4869199daef0e8763be2bda7c4dd60bc59a35bb90664cade8ec81141df8551c
5
5
  SHA512:
6
- metadata.gz: b8e25debb3cca514e6b6fd343d57f1010ca657e34640e7a5a188d45ff98d48a2c1946ff56ff9019d015c22d6f9d5b4b47ec6d927a4dd96f26727f020c778ef2a
7
- data.tar.gz: 6e4947efb5abd53ea279f90be54d237c289d14d4f968ea5b49e2b7ba570828d6f51708a744ac8c6d7c7cdbadd47a071d0d4b55cc4a1c88d4c0ef27cc8e34678c
6
+ metadata.gz: 53f90bf3f134007f0003edadb8a1bc254811c6e3ca76d473dde1a0447b03dc4e75176e6550c455d7bce55567a0bfc81789a2f22237faf3a6d85b931bba879370
7
+ data.tar.gz: 7b673c460863f56d6b9319314ccc291fade0fd3d678bb64f2de5716de86e6585541988f2078616774e661c8435d096df689d90e85aa8370ef214e3df34d61767
@@ -15,22 +15,15 @@ jobs:
15
15
  strategy:
16
16
  fail-fast: false
17
17
  matrix:
18
- RUBY_VERSION: [2.6, 2.7, 3.3, 3.4]
18
+ RUBY_VERSION: [2.3, 2.4, 2.5, 2.6, 2.7, 3.1, 3.2, 3.3, 3.4]
19
+ env:
20
+ RUBY_VERSION: ${{ matrix.RUBY_VERSION }}
19
21
  steps:
20
22
  - name: Check out code
21
23
  uses: actions/checkout@v4
22
24
 
23
- - name: Install Ruby
24
- uses: ruby/setup-ruby@v1
25
- with:
26
- ruby-version: ${{ matrix.RUBY_VERSION }}
27
- bundler: 1.17.3
28
-
29
- - name: Bundle install
30
- run: bundle install
31
-
32
25
  - name: Rubocop
33
- run: bundle exec rake rubocop
26
+ run: make lint
34
27
 
35
28
  - name: Rspec
36
- run: bundle exec rspec
29
+ run: make test
@@ -0,0 +1,26 @@
1
+ on:
2
+ release:
3
+ types: [published]
4
+
5
+ jobs:
6
+ push:
7
+ name: Push gem to RubyGems.org
8
+ runs-on: ubuntu-latest
9
+
10
+ permissions:
11
+ id-token: write
12
+ contents: write
13
+
14
+ steps:
15
+ - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8
16
+ with:
17
+ persist-credentials: false
18
+ - name: Set up Ruby
19
+ uses: ruby/setup-ruby@211ffaaa5f8dda97e9e8bca4e70d0fbaf2f8c41c
20
+ with:
21
+ bundler-cache: false
22
+ ruby-version: "3.3"
23
+
24
+ - run: bundle install
25
+
26
+ - uses: rubygems/release-gem@1c162a739e8b4cb21a676e97b087e8268d8fc40b
data/.gitignore CHANGED
@@ -16,3 +16,4 @@ test/tmp
16
16
  test/version_tmp
17
17
  tmp
18
18
  .idea
19
+ /docker/ruby-*/
data/Dockerfile ADDED
@@ -0,0 +1,20 @@
1
+ ARG RUBY_VERSION=2.3.1
2
+ FROM ruby:${RUBY_VERSION}
3
+
4
+ ARG BUNDLER_VERSION=1.17.3
5
+ ENV BUNDLER_VERSION=${BUNDLER_VERSION}
6
+ RUN if [ "${BUNDLER_VERSION}" != "" ] ; then \
7
+ gem install bundler -v "${BUNDLER_VERSION}" ; \
8
+ fi
9
+
10
+ WORKDIR /app
11
+ COPY Gemfile /app/
12
+ COPY aptible-auth.gemspec /app/
13
+ RUN mkdir -p /app/lib/aptible/auth/
14
+ COPY lib/aptible/auth/version.rb /app/lib/aptible/auth/
15
+
16
+ RUN bundle install
17
+
18
+ COPY . /app
19
+
20
+ CMD ["bash"]
data/Makefile ADDED
@@ -0,0 +1,74 @@
1
+
2
+ export COMPOSE_IGNORE_ORPHANS ?= true
3
+ export RUBY_VERSION ?= 2.3.1
4
+ RUBY_VERSION_MAJOR = $(word 1,$(subst ., ,$(RUBY_VERSION)))
5
+ RUBY_VERSION_MINOR = $(word 2,$(subst ., ,$(RUBY_VERSION)))
6
+ export BUNDLER_VERSION ?=
7
+ ifeq ($(BUNDLER_VERSION),)
8
+ ifeq ($(RUBY_VERSION_MAJOR),2)
9
+ # Use old bundler for Ruby 2.3-2.6; Ruby 2.7 needs bundler 2.x to avoid resolver bugs
10
+ ifeq ($(RUBY_VERSION_MINOR),7)
11
+ export BUNDLER_VERSION = 2.4.22
12
+ else
13
+ export BUNDLER_VERSION = 1.17.3
14
+ endif
15
+ endif
16
+ endif
17
+ PROJECT_NAME = $(shell ls *.gemspec | sed 's/\.gemspec//')
18
+ export COMPOSE_PROJECT_NAME ?= $(PROJECT_NAME)-$(subst .,_,$(RUBY_VERSION))
19
+
20
+ default: help
21
+
22
+ ## Show this help message
23
+ help:
24
+ @echo "\n\033[1;34mAvailable targets:\033[0m\n"
25
+ @awk 'BEGIN {FS = ":"; prev = ""} \
26
+ /^## / {prev = substr($$0, 4); next} \
27
+ /^[a-zA-Z_-]+:/ {if (prev != "") printf " \033[1;36m%-20s\033[0m %s\n", $$1, prev; prev = ""} \
28
+ {prev = ""}' $(MAKEFILE_LIST) | sort
29
+ @echo
30
+
31
+ BUILD_ARGS ?=
32
+ ## Build and pull docker compose images
33
+ build: gemfile-lock
34
+ docker compose build --pull $(BUILD_ARGS)
35
+
36
+ ## Create a Gemfile.lock specific to the container (i.e., for the ruby version)
37
+ gemfile-lock:
38
+ mkdir -pv ./docker/ruby-$(RUBY_VERSION)/ && \
39
+ echo '' > ./docker/ruby-$(RUBY_VERSION)/Gemfile.lock
40
+
41
+ ## Open shell in a docker container, supports CMD=
42
+ bash: build
43
+ $(MAKE) run CMD=bash
44
+
45
+ CMD ?= bash
46
+ ## Run command in a docker container, supports CMD=
47
+ run:
48
+ docker compose run --rm runner $(CMD)
49
+
50
+ ## Run tests in a docker container, supports ARGS=
51
+ test: build
52
+ $(MAKE) test-direct ARGS="$(ARGS)"
53
+
54
+ ## Run tests in a docker container without building, supports ARGS=
55
+ test-direct:
56
+ $(MAKE) run CMD="bundle exec rspec $(ARGS)"
57
+
58
+ ## Run rubocop in a docker container, supports ARGS=
59
+ lint: build
60
+ $(MAKE) lint-direct ARGS="$(ARGS)"
61
+
62
+ ## Run rubocop in a docker container without building, supports ARGS=
63
+ lint-direct:
64
+ $(MAKE) run CMD="bundle exec rake rubocop $(ARGS)"
65
+
66
+ ## Clean up docker compose resources
67
+ clean: clean-gemfile-lock
68
+ docker compose down --remove-orphans --volumes
69
+
70
+ ## Clean up the container specific Gemfile.lock
71
+ clean-gemfile-lock:
72
+ rm -v ./docker/ruby-$(RUBY_VERSION)/Gemfile.lock ||:
73
+
74
+ .PHONY: build bash test
data/aptible-auth.gemspec CHANGED
@@ -21,15 +21,15 @@ Gem::Specification.new do |spec|
21
21
  spec.require_paths = ['lib']
22
22
 
23
23
  spec.add_dependency 'aptible-resource', '~> 1.0'
24
- spec.add_dependency 'concurrent-ruby', '1.3.4'
25
24
  spec.add_dependency 'gem_config'
26
25
  spec.add_dependency 'multipart-post', '2.1.1'
27
26
  spec.add_dependency 'oauth2', '2.0.9'
28
27
 
29
28
  spec.add_development_dependency 'aptible-tasks', '>= 0.6.0'
29
+ spec.add_development_dependency 'httplog'
30
30
  spec.add_development_dependency 'pry'
31
31
  spec.add_development_dependency 'rake'
32
32
  spec.add_development_dependency 'rspec', '~> 3.0'
33
33
  spec.add_development_dependency 'rspec-its'
34
- spec.add_development_dependency 'timecop', '~> 0.8.1'
34
+ spec.add_development_dependency 'timecop', '~> 0.9.10'
35
35
  end
@@ -0,0 +1,12 @@
1
+ services:
2
+ runner:
3
+ build:
4
+ context: .
5
+ args:
6
+ RUBY_VERSION: ${RUBY_VERSION:-2.3.1}
7
+ BUNDLER_VERSION: ${BUNDLER_VERSION:-}
8
+ volumes:
9
+ - type: bind
10
+ source: .
11
+ target: /app
12
+ - ./docker/ruby-${RUBY_VERSION}/Gemfile.lock:/app/Gemfile.lock
@@ -40,6 +40,11 @@ module Aptible
40
40
  cause: e)
41
41
  end
42
42
 
43
+ def self.current_token(token:)
44
+ url = "#{Aptible::Auth.configuration.root_url}/current_token"
45
+ find_by_url(url, token: token)
46
+ end
47
+
43
48
  def authenticate_user(email, password, options = {})
44
49
  options[:scope] ||= 'manage'
45
50
  oauth_token = oauth.password.get_token(email, password, options)
@@ -24,6 +24,21 @@ module Aptible
24
24
  # TODO: Implement query params for /operations
25
25
  []
26
26
  end
27
+
28
+ # Returns roles with their organizations pre-loaded to avoid N+1 API calls
29
+ # when iterating through roles and accessing role.organization.
30
+ # Makes 2 backend requests: one for orgs, one for roles.
31
+ def roles_with_organizations
32
+ orgs_by_href = Organization.all(token: token, headers: headers)
33
+ .index_by(&:href)
34
+
35
+ roles.tap do |all_roles|
36
+ all_roles.each do |role|
37
+ org = orgs_by_href[role.links[:organization].href]
38
+ role.instance_variable_set(:@organization, org)
39
+ end
40
+ end
41
+ end
27
42
  end
28
43
  end
29
44
  end
@@ -1,5 +1,5 @@
1
1
  module Aptible
2
2
  module Auth
3
- VERSION = '1.3.0'.freeze
3
+ VERSION = '1.5.0'.freeze
4
4
  end
5
5
  end
@@ -229,4 +229,33 @@ describe Aptible::Auth::Token do
229
229
  expect(subject.send(:oauth)).to be(c)
230
230
  end
231
231
  end
232
+
233
+ describe '.current_token' do
234
+ let(:token_response) { double 'token_response' }
235
+ let(:access_token) { 'my_access_token' }
236
+ let(:root_url) { 'https://auth.example.com' }
237
+
238
+ before do
239
+ Aptible::Auth.configuration.root_url = root_url
240
+ end
241
+
242
+ it 'should fetch from /current_token endpoint with the provided token' do
243
+ expect(described_class).to receive(:find_by_url)
244
+ .with("#{root_url}/current_token", token: access_token)
245
+ .and_return(token_response)
246
+
247
+ expect(described_class.current_token(token: access_token)).to eq(token_response)
248
+ end
249
+
250
+ it 'should use configured root_url' do
251
+ custom_url = 'https://custom-auth.aptible.com'
252
+ Aptible::Auth.configuration.root_url = custom_url
253
+
254
+ expect(described_class).to receive(:find_by_url)
255
+ .with("#{custom_url}/current_token", token: access_token)
256
+ .and_return(token_response)
257
+
258
+ described_class.current_token(token: access_token)
259
+ end
260
+ end
232
261
  end
@@ -30,4 +30,95 @@ describe Aptible::Auth::User do
30
30
  expect(subject.organizations.count).to eq 1
31
31
  end
32
32
  end
33
+
34
+ describe '#roles_with_organizations' do
35
+ let(:token) { 'some-token' }
36
+ let(:headers) { { 'Authorization' => 'Bearer some-token' } }
37
+
38
+ let(:org1) do
39
+ double('Aptible::Auth::Organization', href: '/organizations/1', id: 1)
40
+ end
41
+ let(:org2) do
42
+ double('Aptible::Auth::Organization', href: '/organizations/2', id: 2)
43
+ end
44
+
45
+ let(:org1_link) do
46
+ double('Aptible::Auth::Organization::Link', href: '/organizations/1')
47
+ end
48
+ let(:org2_link) do
49
+ double('Aptible::Auth::Organization::Link', href: '/organizations/2')
50
+ end
51
+
52
+ let(:role1_links) { double('Role1::Links') }
53
+ let(:role2_links) { double('Role2::Links') }
54
+ let(:role3_links) { double('Role3::Links') }
55
+
56
+ let(:role1) { Aptible::Auth::Role.new }
57
+ let(:role2) { Aptible::Auth::Role.new }
58
+ let(:role3) { Aptible::Auth::Role.new }
59
+
60
+ before do
61
+ subject.stub(:token) { token }
62
+ subject.stub(:headers) { headers }
63
+
64
+ role1_links.stub(:[]).with(:organization) { org1_link }
65
+ role2_links.stub(:[]).with(:organization) { org2_link }
66
+ role3_links.stub(:[]).with(:organization) { org1_link }
67
+
68
+ role1.stub(:links) { role1_links }
69
+ role2.stub(:links) { role2_links }
70
+ role3.stub(:links) { role3_links }
71
+ end
72
+
73
+ it 'returns the roles' do
74
+ allow(Aptible::Auth::Organization).to receive(:all).and_return([org1])
75
+ subject.stub(:roles) { [role1] }
76
+
77
+ expect(subject.roles_with_organizations).to eq [role1]
78
+ end
79
+
80
+ it 'pre-populates @organization on each role' do
81
+ allow(Aptible::Auth::Organization).to receive(:all)
82
+ .with(token: token, headers: headers)
83
+ .and_return([org1, org2])
84
+ subject.stub(:roles) { [role1, role2] }
85
+
86
+ subject.roles_with_organizations
87
+
88
+ expect(role1.instance_variable_get(:@organization)).to eq org1
89
+ expect(role2.instance_variable_get(:@organization)).to eq org2
90
+ end
91
+
92
+ it 'maps multiple roles to the same organization' do
93
+ allow(Aptible::Auth::Organization).to receive(:all)
94
+ .with(token: token, headers: headers)
95
+ .and_return([org1, org2])
96
+ subject.stub(:roles) { [role1, role2, role3] }
97
+
98
+ subject.roles_with_organizations
99
+
100
+ expect(role1.instance_variable_get(:@organization)).to eq org1
101
+ expect(role2.instance_variable_get(:@organization)).to eq org2
102
+ expect(role3.instance_variable_get(:@organization)).to eq org1
103
+ end
104
+
105
+ it 'returns empty array when user has no roles' do
106
+ allow(Aptible::Auth::Organization).to receive(:all)
107
+ .with(token: token, headers: headers)
108
+ .and_return([])
109
+ subject.stub(:roles) { [] }
110
+
111
+ expect(subject.roles_with_organizations).to eq []
112
+ end
113
+
114
+ it 'makes exactly one call to Organization.all' do
115
+ expect(Aptible::Auth::Organization).to receive(:all)
116
+ .with(token: token, headers: headers)
117
+ .once
118
+ .and_return([org1])
119
+ subject.stub(:roles) { [role1] }
120
+
121
+ subject.roles_with_organizations
122
+ end
123
+ end
33
124
  end
metadata CHANGED
@@ -1,13 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aptible-auth
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.0
4
+ version: 1.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Frank Macreery
8
+ autorequire:
8
9
  bindir: bin
9
10
  cert_chain: []
10
- date: 1980-01-02 00:00:00.000000000 Z
11
+ date: 2025-12-29 00:00:00.000000000 Z
11
12
  dependencies:
12
13
  - !ruby/object:Gem::Dependency
13
14
  name: aptible-resource
@@ -23,20 +24,6 @@ dependencies:
23
24
  - - "~>"
24
25
  - !ruby/object:Gem::Version
25
26
  version: '1.0'
26
- - !ruby/object:Gem::Dependency
27
- name: concurrent-ruby
28
- requirement: !ruby/object:Gem::Requirement
29
- requirements:
30
- - - '='
31
- - !ruby/object:Gem::Version
32
- version: 1.3.4
33
- type: :runtime
34
- prerelease: false
35
- version_requirements: !ruby/object:Gem::Requirement
36
- requirements:
37
- - - '='
38
- - !ruby/object:Gem::Version
39
- version: 1.3.4
40
27
  - !ruby/object:Gem::Dependency
41
28
  name: gem_config
42
29
  requirement: !ruby/object:Gem::Requirement
@@ -93,6 +80,20 @@ dependencies:
93
80
  - - ">="
94
81
  - !ruby/object:Gem::Version
95
82
  version: 0.6.0
83
+ - !ruby/object:Gem::Dependency
84
+ name: httplog
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
96
97
  - !ruby/object:Gem::Dependency
97
98
  name: pry
98
99
  requirement: !ruby/object:Gem::Requirement
@@ -155,14 +156,14 @@ dependencies:
155
156
  requirements:
156
157
  - - "~>"
157
158
  - !ruby/object:Gem::Version
158
- version: 0.8.1
159
+ version: 0.9.10
159
160
  type: :development
160
161
  prerelease: false
161
162
  version_requirements: !ruby/object:Gem::Requirement
162
163
  requirements:
163
164
  - - "~>"
164
165
  - !ruby/object:Gem::Version
165
- version: 0.8.1
166
+ version: 0.9.10
166
167
  description: Ruby client for auth.aptible.com
167
168
  email:
168
169
  - frank@macreery.com
@@ -172,16 +173,19 @@ extra_rdoc_files: []
172
173
  files:
173
174
  - ".github/CODEOWNERS"
174
175
  - ".github/workflows/ci.yml"
176
+ - ".github/workflows/release.yml"
175
177
  - ".gitignore"
176
178
  - ".rspec"
177
- - ".ruby-version"
179
+ - Dockerfile
178
180
  - Gemfile
179
181
  - LICENSE.md
182
+ - Makefile
180
183
  - Procfile
181
184
  - README.md
182
185
  - Rakefile
183
186
  - SECURITY.md
184
187
  - aptible-auth.gemspec
188
+ - docker-compose.yml
185
189
  - lib/aptible/auth.rb
186
190
  - lib/aptible/auth/agent.rb
187
191
  - lib/aptible/auth/client.rb
@@ -217,6 +221,7 @@ homepage: https://github.com/aptible/aptible-auth-ruby
217
221
  licenses:
218
222
  - MIT
219
223
  metadata: {}
224
+ post_install_message:
220
225
  rdoc_options: []
221
226
  require_paths:
222
227
  - lib
@@ -231,7 +236,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
231
236
  - !ruby/object:Gem::Version
232
237
  version: '0'
233
238
  requirements: []
234
- rubygems_version: 3.6.9
239
+ rubygems_version: 3.5.22
240
+ signing_key:
235
241
  specification_version: 4
236
242
  summary: Ruby client for auth.aptible.com
237
243
  test_files:
data/.ruby-version DELETED
@@ -1 +0,0 @@
1
- 3.4