aikido-ruby-client 0.0.1 → 0.0.3

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: e1aff36ac4f8ac9f17a073b5acfead422df83829a80e7f6f7ec3a8d68426214d
4
- data.tar.gz: 7a84efa160d1e3701ab301d04a71eb967f24e7cda172c9b34f60c34bd277e467
3
+ metadata.gz: 6692ba6b0f697d0f69b840a95e96cbbca656863ed9c71af7c48fc2634678a659
4
+ data.tar.gz: 9997f0daca4a3e133a3d5e3c041f8ddf66bd6af56521d18d6c8bfbffbc323b40
5
5
  SHA512:
6
- metadata.gz: 5250c5726c5920423b88b31c982a792251fca565fca0996bee526a1e222e6dc38c27074482e93fa8752ef7a09ca89588e00f996bb4f85f3baf8369d884fc98bf
7
- data.tar.gz: f74ecf9b1df49a4e84608ed68900ded1dfa8b672e8a00cbdd5d762214bf670be3ba6117d60a21dc44a8bc5792d42498d4a574c19a4e2d18ce715a72c296e50b9
6
+ metadata.gz: 5597d2ddd0e6a518a078e6fa6d2b55e3c01a022ffadbb018fe76423f761f9c4381a4dc06bc647866b8bea5ea21cdb8230811c0e71cc60f9ef46e78ed2d4057c3
7
+ data.tar.gz: d1659f8a75fe77dbd4e60f8b74884b3354458c520482531b49d7b10e014ca1ccbbc8958743686814a5bc075ecbf03b176bb321055df6bc12145651e6aa5dae40
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --require spec_helper
data/.rubocop.yml CHANGED
@@ -1,7 +1,12 @@
1
1
  AllCops:
2
2
  TargetRubyVersion: 2.7
3
3
  NewCops: enable
4
+ SuggestExtensions: false
4
5
 
5
6
  Naming/FileName:
6
7
  Exclude:
7
8
  - 'lib/aikido-ruby-client.rb'
9
+
10
+ Metrics/BlockLength:
11
+ Exclude:
12
+ - 'spec/**/*.rb'
data/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## [v0.0.3](https://github.com/anakinj/aikido-ruby-client/tree/v0.0.3) (2024-03-10)
4
+
5
+ **Features:**
6
+
7
+ - Support for even more endpoints
8
+
9
+ ## [v0.0.2](https://github.com/anakinj/aikido-ruby-client/tree/v0.0.2) (2024-03-10)
10
+
11
+ **Features:**
12
+
13
+ - More api methods
14
+ - Pagination support
15
+ - Specs backed by VCR recordings
16
+
3
17
  ## [v0.0.1](https://github.com/anakinj/aikido-ruby-client/tree/v0.0.1) (2024-03-10)
4
18
 
5
19
  **Features:**
data/exe/aikido CHANGED
@@ -5,4 +5,10 @@ require 'aikido-ruby-client'
5
5
 
6
6
  client = Aikido::Client.new
7
7
 
8
- puts client.issues
8
+ result = client.public_send(ARGV[0], *ARGV[1..-1])
9
+
10
+ if result.is_a?(Aikido::PaginatedResponse)
11
+ puts result.to_a
12
+ else
13
+ puts result
14
+ end
data/lib/aikido/client.rb CHANGED
@@ -2,35 +2,93 @@
2
2
 
3
3
  require 'httpx'
4
4
 
5
+ require_relative 'errors'
6
+ require_relative 'paginated_response'
7
+
5
8
  module Aikido
6
9
  # HTTP Client to interact with the Aikido API
7
10
  # Official documentation: https://apidocs.aikido.dev/
8
11
  class Client
9
12
  def initialize(client_id: nil, client_secret: nil)
10
- @client_id = client_id || ENV.fetch('AIKIDO_CLIENT_ID', nil)
13
+ @client_id = client_id || ENV.fetch('AIKIDO_CLIENT_ID', nil)
11
14
  @client_secret = client_secret || ENV.fetch('AIKIDO_CLIENT_SECRET', nil)
12
15
  end
13
16
 
14
17
  def authorize
15
- http.plugin(:basic_auth).basic_auth(@client_id, @client_secret).post('/oauth/token',
16
- json: { grant_type: 'client_credentials' })
18
+ handle_response!(http.plugin(:basic_auth)
19
+ .basic_auth(@client_id, @client_secret)
20
+ .post('/oauth/token', json: { grant_type: 'client_credentials' }))
21
+ end
22
+
23
+ def workspace
24
+ get('/public/v1/workspace').json
25
+ end
26
+
27
+ def clouds
28
+ PaginatedResponse.new do |page|
29
+ get('/public/v1/clouds', params: { page: page }).json
30
+ end
31
+ end
32
+
33
+ def connect_aws_cloud(role_arn:, name:, environment:)
34
+ handle_response!(authed_http.post('/public/v1/clouds/aws',
35
+ json: { role_arn: role_arn,
36
+ name: name,
37
+ environment: environment })).json
17
38
  end
18
39
 
19
- def issues(params: {})
20
- authed_http.get('/public/v1/issues/export', params: params).json
40
+ def issues(options = {})
41
+ get('/public/v1/issues/export', params: options).json
21
42
  end
22
43
 
23
44
  def issue(id)
24
- authed_http.get("/public/v1/issues/#{id.to_i}").json
45
+ get("/public/v1/issues/#{id.to_i}").json
25
46
  end
26
47
 
27
- def repositories
28
- # TODO: Paginated response
29
- authed_http.get('/public/v1/repositories/code', params: params).json
48
+ def issue_groups
49
+ PaginatedResponse.new do |page|
50
+ get('/public/v1/open-issue-groups', params: { page: page }).json
51
+ end
52
+ end
53
+
54
+ def issue_group(id)
55
+ get("/public/v1/issues/groups/#{id.to_i}").json
56
+ end
57
+
58
+ def code_repositories
59
+ PaginatedResponse.new do |page|
60
+ get('/public/v1/repositories/code', params: { page: page }).json
61
+ end
62
+ end
63
+
64
+ def code_repository_sbom(id, format: 'csv')
65
+ get("/public/v1/repositories/code/#{id.to_i}/licenses/export", params: { format: format }).read
66
+ end
67
+
68
+ def teams
69
+ PaginatedResponse.new do |page|
70
+ get('/public/v1/teams', params: { page: page }).json
71
+ end
72
+ end
73
+
74
+ def create_team(name:)
75
+ handle_response!(authed_http.post('/public/v1/teams', json: { name: name })).json
76
+ end
77
+
78
+ def update_team(id)
79
+ raise NotImplementedError
80
+ end
81
+
82
+ def containers
83
+ get('/public/v1/containers').json
30
84
  end
31
85
 
32
86
  private
33
87
 
88
+ def get(path, params: {})
89
+ handle_response!(authed_http.get(path, params: params))
90
+ end
91
+
34
92
  def authed_http
35
93
  http.plugin(:auth).bearer_auth(auth_token)
36
94
  end
@@ -47,5 +105,25 @@ module Aikido
47
105
  # TODO: Handle token expiration
48
106
  @auth_token ||= authorize.json['access_token']
49
107
  end
108
+
109
+ def handle_response!(response)
110
+ case response.status
111
+ when 200..299
112
+ response
113
+ else
114
+ raise_response_error!(response)
115
+ end
116
+ end
117
+
118
+ def raise_response_error!(response)
119
+ case response.status
120
+ when 400
121
+ raise Errors::BadRequestError, response
122
+ when 401
123
+ raise Errors::UnauthorizedError, response
124
+ else
125
+ raise Errors::ApiError, response
126
+ end
127
+ end
50
128
  end
51
129
  end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aikido
4
+ # Represents a context for interacting with the Aikido API
5
+ # Context will store data in memory for further processing
6
+ class Context
7
+ def initialize(client: nil)
8
+ @client = client || Aikido::Client.new
9
+ end
10
+
11
+ def issues_for_code_repository(external_repo_id:)
12
+ repo = code_repositories.find { |r| r['external_repo_id'] == external_repo_id }
13
+ return [] unless repo
14
+
15
+ issues.select do |issue|
16
+ issue['code_repo_id'] == repo['id']
17
+ end
18
+ end
19
+
20
+ def code_repositories
21
+ @code_repositories ||= @client.code_repositories
22
+ end
23
+
24
+ def issues
25
+ @issues ||= @client.issues
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aikido
4
+ module Errors
5
+ AikidoError = Class.new(StandardError)
6
+
7
+ # Represents an error that occurred while making an API request.
8
+ class ApiError < AikidoError
9
+ def initialize(response)
10
+ @response = response
11
+ super("API Error: #{response.status}")
12
+ end
13
+
14
+ def message
15
+ json = @response.json
16
+ if json.key?('error_description')
17
+ "#{super} - #{json['error_description']}"
18
+ elsif json.key?('reason_phrase')
19
+ "#{super} - #{json['reason_phrase']}"
20
+ else
21
+ super
22
+ end
23
+ end
24
+ end
25
+
26
+ BadRequestError = Class.new(ApiError)
27
+ UnauthorizedError = Class.new(ApiError)
28
+ NotFoundError = Class.new(ApiError)
29
+ end
30
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aikido
4
+ # Represents a reponse that is paginated
5
+ class PaginatedResponse
6
+ include Enumerable
7
+
8
+ def initialize(&block)
9
+ @page_loader = block
10
+ @pages = []
11
+ load_page(0)
12
+ end
13
+
14
+ def each(&block)
15
+ return enum_for(:each) unless block_given?
16
+
17
+ loop.with_index do |_, index|
18
+ page = load_page(index)
19
+ break if page.empty?
20
+
21
+ page.each(&block)
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ def load_page(page)
28
+ @pages[page] ||= @page_loader.call(page)
29
+ end
30
+ end
31
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Aikido
4
- VERSION = '0.0.1'
4
+ VERSION = '0.0.3'
5
5
  end
@@ -1,3 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'aikido/client'
4
+ require 'aikido/context'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aikido-ruby-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joakim Antman
@@ -32,6 +32,7 @@ executables:
32
32
  extensions: []
33
33
  extra_rdoc_files: []
34
34
  files:
35
+ - ".rspec"
35
36
  - ".rubocop.yml"
36
37
  - CHANGELOG.md
37
38
  - LICENSE.txt
@@ -40,6 +41,9 @@ files:
40
41
  - exe/aikido
41
42
  - lib/aikido-ruby-client.rb
42
43
  - lib/aikido/client.rb
44
+ - lib/aikido/context.rb
45
+ - lib/aikido/errors.rb
46
+ - lib/aikido/paginated_response.rb
43
47
  - lib/aikido/version.rb
44
48
  homepage: https://github.com/anakinj/aikido-ruby-client
45
49
  licenses:
@@ -47,7 +51,7 @@ licenses:
47
51
  metadata:
48
52
  homepage_uri: https://github.com/anakinj/aikido-ruby-client
49
53
  source_code_uri: https://github.com/anakinj
50
- changelog_uri: https://github.com/anakinj/jwk-loader/blob/0.0.1/CHANGELOG.md
54
+ changelog_uri: https://github.com/anakinj/jwk-loader/blob/0.0.3/CHANGELOG.md
51
55
  rubygems_mfa_required: 'true'
52
56
  post_install_message:
53
57
  rdoc_options: []