aikido-ruby-client 0.0.1 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
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: []