3scale_toolbox 0.14.0 → 0.15.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.
Files changed (28) hide show
  1. checksums.yaml +4 -4
  2. data/3scale_toolbox.gemspec +2 -1
  3. data/README.md +21 -3
  4. data/lib/3scale_toolbox.rb +5 -1
  5. data/lib/3scale_toolbox/attribute_filters.rb +2 -0
  6. data/lib/3scale_toolbox/attribute_filters/attribute_filter.rb +9 -0
  7. data/lib/3scale_toolbox/attribute_filters/service_id_from_ref_filter.rb +30 -0
  8. data/lib/3scale_toolbox/commands/activedocs_command/apply_command.rb +1 -1
  9. data/lib/3scale_toolbox/commands/activedocs_command/list_command.rb +18 -1
  10. data/lib/3scale_toolbox/commands/import_command/openapi.rb +26 -5
  11. data/lib/3scale_toolbox/commands/import_command/openapi/create_activedocs_step.rb +4 -17
  12. data/lib/3scale_toolbox/commands/import_command/openapi/create_service_step.rb +1 -5
  13. data/lib/3scale_toolbox/commands/import_command/openapi/mapping_rule.rb +3 -2
  14. data/lib/3scale_toolbox/commands/import_command/openapi/step.rb +43 -5
  15. data/lib/3scale_toolbox/commands/import_command/openapi/update_policies_step.rb +7 -11
  16. data/lib/3scale_toolbox/commands/import_command/openapi/update_service_oidc_conf_step.rb +2 -17
  17. data/lib/3scale_toolbox/commands/import_command/openapi/update_service_proxy_step.rb +10 -10
  18. data/lib/3scale_toolbox/openapi.rb +2 -0
  19. data/lib/3scale_toolbox/openapi/oas3.rb +232 -0
  20. data/lib/3scale_toolbox/openapi/swagger.rb +192 -0
  21. data/lib/3scale_toolbox/tasks/copy_service_proxy_task.rb +1 -0
  22. data/lib/3scale_toolbox/version.rb +1 -1
  23. data/licenses.xml +161 -1
  24. data/resources/oas3_meta_schema.json +1654 -0
  25. metadata +24 -6
  26. data/lib/3scale_toolbox/commands/import_command/openapi/threescale_api_spec.rb +0 -80
  27. data/lib/3scale_toolbox/swagger.rb +0 -1
  28. data/lib/3scale_toolbox/swagger/swagger.rb +0 -123
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3f7c696659a170ef2b061871c02cae7bf03fee297f0a9820e9ad8edd13d273e6
4
- data.tar.gz: 8452cce3946098d1732184b7e371c1bf80cfc16071608eba39250ac318f40b0d
3
+ metadata.gz: bf0d2a187e793d654f6e6cef6990cfabaada5072f3a72b9820b1fed1ac13ddfb
4
+ data.tar.gz: c1b56e8e76059e0143444ff9ef12da633b97ef74b0fccb6875480be8b22cf9e6
5
5
  SHA512:
6
- metadata.gz: 76a2ed5ef4e2e987a8db94d586fffe2d75e6c84408894a74d75a0d7050739ca70339f4203b2cd883f5670bfda87d4bfd7a8bfa5a7bbbc6eb024de565be5a3333
7
- data.tar.gz: 38fba12044b61af86f71765c4e7f58ae1c0a65c73aaa491fe7c696f6ca0d58b84cb14a5651345d8cf9e7978cb7ae2e5443e21404bb04539fa93b315daea4a363
6
+ metadata.gz: f2bf8c3a1f5860a3c6d24fa5fbc976b9b3361ea8ef6a57bbc0707d5f3900a31d8022e9596080bf8129d47116d13d3ab4d2ae7bfc41e246d179adf0f757c7c598
7
+ data.tar.gz: 3a206838d82a662f56276e7d98291cf74f5bc69eb9f39de239bb3d15f457e62b81e336ee1d0438a508fdecc46f692b49610627ef6413d05788b4c9f1a8c3f2e5
@@ -34,9 +34,10 @@ Gem::Specification.new do |spec|
34
34
  spec.add_development_dependency 'rake', '~> 10.0'
35
35
  spec.add_development_dependency 'rspec', '~> 3.8'
36
36
  spec.add_development_dependency 'webmock', '~> 3.4'
37
- spec.required_ruby_version = '>= 2.4'
37
+ spec.required_ruby_version = '>= 2.5'
38
38
 
39
39
  spec.add_dependency '3scale-api', '~> 0.6.0'
40
40
  spec.add_dependency 'cri', '~> 2.15'
41
41
  spec.add_dependency 'json-schema', '~> 2.8'
42
+ spec.add_dependency 'oas_parser', '~> 0.20'
42
43
  end
data/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  # 3scale toolbox
2
- [![Build Status](https://travis-ci.org/3scale/3scale_toolbox.svg?branch=master)](https://travis-ci.org/3scale/3scale_toolbox)
2
+ [![CircleCI](https://circleci.com/gh/3scale/3scale_toolbox.svg?style=svg)](https://circleci.com/gh/3scale/3scale_toolbox)
3
3
 
4
4
  This software is licensed under the [Apache 2.0 license](https://www.apache.org/licenses/LICENSE-2.0).
5
5
 
@@ -9,6 +9,7 @@ See the LICENSE and NOTICE files that should have been provided along with this
9
9
  3scale toolbox is a set of tools to help you manage your 3scale product. Using the [3scale API Ruby Client](https://github.com/3scale/3scale-api-ruby).
10
10
 
11
11
  ## Table of contents
12
+ * [Requirements](#requirements)
12
13
  * [Installation](#installation)
13
14
  * [Usage](#usage)
14
15
  * [Copy a service](docs/copy-service.md)
@@ -32,10 +33,27 @@ See the LICENSE and NOTICE files that should have been provided along with this
32
33
  * [Troubleshooting](#troubleshooting)
33
34
  * [Contributing](#contributing)
34
35
 
36
+ ## Requirements
37
+ Supported Ruby interpreters
38
+
39
+ * MRI 2.5
40
+ * MRI 2.6
41
+
35
42
  ## Installation
36
43
  Install the toolbox:
37
44
 
38
- $ gem install 3scale_toolbox
45
+ ```
46
+ $ gem install 3scale_toolbox
47
+ ```
48
+
49
+ The [3scale toolbox packaging repo](https://github.com/3scale/3scale_toolbox_packaging)
50
+ provides packages and installation/deployment steps for the following platforms:
51
+ * CentOS/Fedora
52
+ * Ubuntu/Debian
53
+ * Mac OS X
54
+ * Windows
55
+ * Docker
56
+ * Kubernetes / Openshift
39
57
 
40
58
  ## Usage
41
59
 
@@ -178,7 +196,7 @@ $ 3scale service_list my-3scale-instance
178
196
 
179
197
  It is a requirement that we include a file describing all the licenses used in the product, so that users can examine it.
180
198
 
181
- Run `rake license_finder:check` to check licenses when dependencies change.
199
+ Run `rake license_finder:check` to check licenses when dependencies change.
182
200
 
183
201
  Run `rake license_finder:report > licenses.xml` to update licenses file.
184
202
 
@@ -6,20 +6,24 @@ require 'time'
6
6
  require 'csv'
7
7
  require 'net/http'
8
8
  require 'pathname'
9
+ require 'oas_parser'
9
10
  require '3scale/api'
11
+ require 'json-schema'
12
+ require 'erb'
10
13
 
11
14
  require '3scale_toolbox/version'
12
15
  require '3scale_toolbox/helper'
13
16
  require '3scale_toolbox/error'
14
17
  require '3scale_toolbox/proxy_logger'
15
18
  require '3scale_toolbox/resource_reader'
16
- require '3scale_toolbox/swagger'
17
19
  require '3scale_toolbox/configuration'
18
20
  require '3scale_toolbox/remotes'
19
21
  require '3scale_toolbox/3scale_client_factory'
20
22
  require '3scale_toolbox/entities'
21
23
  require '3scale_toolbox/tasks'
24
+ require '3scale_toolbox/attribute_filters'
22
25
  require '3scale_toolbox/base_command'
26
+ require '3scale_toolbox/openapi'
23
27
  require '3scale_toolbox/commands'
24
28
  require '3scale_toolbox/cli'
25
29
 
@@ -0,0 +1,2 @@
1
+ require '3scale_toolbox/attribute_filters/attribute_filter'
2
+ require '3scale_toolbox/attribute_filters/service_id_from_ref_filter'
@@ -0,0 +1,9 @@
1
+ module ThreeScaleToolbox
2
+ module AttributeFilters
3
+ module AttributeFilter
4
+ def filter(enumerable)
5
+ raise "Not implemented"
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,30 @@
1
+ module ThreeScaleToolbox
2
+ module AttributeFilters
3
+ class ServiceIDFilterFromServiceRef
4
+ include AttributeFilter
5
+
6
+ attr_reader :remote, :service_ref, :service_id_key
7
+
8
+ def initialize(remote, service_ref, service_id_key)
9
+ @remote = remote
10
+ @service_ref = service_ref
11
+ @service_id_key = service_id_key
12
+ end
13
+
14
+ def filter(enumerable)
15
+ svc_id = find_service
16
+ enumerable.select { |e| e.key?(service_id_key) && e[service_id_key].to_s == svc_id.to_s }
17
+ end
18
+
19
+ private
20
+
21
+ def find_service
22
+ svc_id = -1
23
+ Entities::Service.find(remote: remote, ref: service_ref).tap do |svc|
24
+ svc_id = svc.id if !svc.nil?
25
+ end
26
+ svc_id
27
+ end
28
+ end
29
+ end
30
+ end
@@ -20,7 +20,7 @@ module ThreeScaleToolbox
20
20
  option :i, :'service-id', "Specify the Service ID associated to the ActiveDocs", argument: :required
21
21
  option :p, :'publish', "Specify it to publish the ActiveDocs on the Developer Portal. Otherwise it will be hidden", argument: :forbidden
22
22
  option nil, :'hide', "Specify it to hide the ActiveDocs on the Developer Portal", argument: :forbidden
23
- option nil, :'skip-swagger-validations', "Specify it to skip validation of the Swagger specification", argument: :forbidden
23
+ option nil, :'skip-swagger-validations', "Skip validation of the Swagger specification. true or false", argument: :required, transform: ThreeScaleToolbox::Helper::BooleanTransformer.new
24
24
  option :d, :'description', "Specify the description of the ActiveDocs", argument: :required
25
25
  option :s, :'name', "Specify the name of the ActiveDocs", argument: :required
26
26
  option nil, :'openapi-spec', "Specify the swagger spec. Can be a file, an URL or '-' to read from stdin. This option is mandatory when applying the ActiveDoc for the first time", argument: :required
@@ -14,6 +14,7 @@ module ThreeScaleToolbox
14
14
  runner ListSubcommand
15
15
 
16
16
  param :remote
17
+ option :s, :'service-ref', "Filter the ActiveDocs by Service reference", argument: :required
17
18
  end
18
19
  end
19
20
 
@@ -42,8 +43,24 @@ module ThreeScaleToolbox
42
43
  puts fields_to_show.map { |e| e.upcase }.join("\t")
43
44
  end
44
45
 
46
+ def service_ref_filter
47
+ options[:'service-ref']
48
+ end
49
+
50
+ def filters
51
+ res = []
52
+ if !service_ref_filter.nil?
53
+ res << AttributeFilters::ServiceIDFilterFromServiceRef.new(remote, service_ref_filter, "service_id")
54
+ end
55
+ res
56
+ end
57
+
58
+ def filtered_activedocs(activedocs)
59
+ filters.reduce(activedocs) { |current_list, filter| filter.filter(current_list) }
60
+ end
61
+
45
62
  def print_results(activedocs, fields_to_show)
46
- activedocs.each do |activedoc|
63
+ filtered_activedocs(activedocs).each do |activedoc|
47
64
  puts fields_to_show.map { |field| activedoc.fetch(field, '(empty)') }.join("\t")
48
65
  end
49
66
  end
@@ -2,7 +2,6 @@ require '3scale_toolbox/commands/import_command/openapi/method'
2
2
  require '3scale_toolbox/commands/import_command/openapi/mapping_rule'
3
3
  require '3scale_toolbox/commands/import_command/openapi/operation'
4
4
  require '3scale_toolbox/commands/import_command/openapi/step'
5
- require '3scale_toolbox/commands/import_command/openapi/threescale_api_spec'
6
5
  require '3scale_toolbox/commands/import_command/openapi/create_method_step'
7
6
  require '3scale_toolbox/commands/import_command/openapi/create_mapping_rule_step'
8
7
  require '3scale_toolbox/commands/import_command/openapi/create_service_step'
@@ -30,6 +29,7 @@ module ThreeScaleToolbox
30
29
  option :t, 'target_system_name', 'Target system name', argument: :required
31
30
  flag nil, 'activedocs-hidden', 'Create ActiveDocs in hidden state'
32
31
  flag nil, 'skip-openapi-validation', 'Skip OpenAPI schema validation'
32
+ flag nil, 'prefix-matching', 'Use prefix matching instead of strict matching on mapping rules derived from openapi operations'
33
33
  option nil, 'oidc-issuer-endpoint', 'OIDC Issuer Endpoint', argument: :required
34
34
  option nil, 'default-credentials-userkey', 'Default credentials policy userkey', argument: :required
35
35
  option nil, 'override-private-basepath', 'Override the basepath for the private URLs', argument: :required
@@ -37,6 +37,8 @@ module ThreeScaleToolbox
37
37
  option nil, 'staging-public-base-url', 'Custom public staging URL', argument: :required
38
38
  option nil, 'production-public-base-url', 'Custom public production URL', argument: :required
39
39
  option nil, 'override-private-base-url', 'Custom private base URL', argument: :required
40
+ option nil, 'backend-api-secret-token', 'Custom secret token sent by the API gateway to the backend API',argument: :required
41
+ option nil, 'backend-api-host-header', 'Custom host header sent by the API gateway to the backend API', argument: :required
40
42
  param :openapi_resource
41
43
 
42
44
  runner OpenAPISubcommand
@@ -69,10 +71,9 @@ module ThreeScaleToolbox
69
71
  end
70
72
 
71
73
  def create_context
72
- openapi_resource = load_resource(arguments[:openapi_resource])
73
74
  {
74
75
  api_spec_resource: openapi_resource,
75
- api_spec: ThreeScaleApiSpec.new(load_openapi(openapi_resource), options[:'override-public-basepath']),
76
+ api_spec: openapi_parser,
76
77
  threescale_client: threescale_client(fetch_required_option(:destination)),
77
78
  target_system_name: options[:target_system_name],
78
79
  activedocs_published: !options[:'activedocs-hidden'],
@@ -80,14 +81,34 @@ module ThreeScaleToolbox
80
81
  default_credentials_userkey: options[:'default-credentials-userkey'],
81
82
  skip_openapi_validation: options[:'skip-openapi-validation'],
82
83
  override_private_basepath: options[:'override-private-basepath'],
84
+ override_public_basepath: options[:'override-public-basepath'],
83
85
  production_public_base_url: options[:'production-public-base-url'],
84
86
  staging_public_base_url: options[:'staging-public-base-url'],
85
87
  override_private_base_url: options[:'override-private-base-url'],
88
+ backend_api_secret_token: options[:'backend-api-secret-token'],
89
+ backend_api_host_header: options[:'backend-api-host-header'],
90
+ prefix_matching: options[:'prefix-matching'],
86
91
  }
87
92
  end
88
93
 
89
- def load_openapi(openapi_resource)
90
- Swagger.build(openapi_resource, validate: !options[:'skip-openapi-validation'])
94
+ def openapi_resource
95
+ @openapi_resource ||= load_resource(openapi_path)
96
+ end
97
+
98
+ def openapi_path
99
+ arguments[:openapi_resource]
100
+ end
101
+
102
+ def validate
103
+ !options[:'skip-openapi-validation']
104
+ end
105
+
106
+ def openapi_parser
107
+ if openapi_resource.key?('openapi')
108
+ ThreeScaleToolbox::OpenAPI::OAS3.build(openapi_path, openapi_resource, validate: validate)
109
+ else
110
+ ThreeScaleToolbox::OpenAPI::Swagger.build(openapi_resource, validate: validate)
111
+ end
91
112
  rescue JSON::Schema::ValidationError => e
92
113
  raise ThreeScaleToolbox::Error, "OpenAPI schema validation failed: #{e.message}"
93
114
  end
@@ -53,26 +53,13 @@ module ThreeScaleToolbox
53
53
  # Other processing steps can work with original openapi spec
54
54
  Helper.hash_deep_dup(resource).tap do |activedocs|
55
55
  # public production base URL
56
- URI(service.proxy.fetch('endpoint')).tap do |uri|
57
- activedocs['host'] = "#{uri.host}:#{uri.port}"
58
- activedocs['schemes'] = [uri.scheme]
59
- end
60
-
61
56
  # the basePath field is updated to a new value only when overriden by optional param
62
- activedocs['basePath'] = api_spec.public_base_path
63
-
57
+ api_spec.set_server_url(activedocs,
58
+ URI.join(service.proxy.fetch('endpoint'), public_base_path))
64
59
  # security definitions
65
60
  # just valid for oauth2 when oidc_issuer_endpoint is supplied
66
- if !security.nil? && security.type == 'oauth2' && !oidc_issuer_endpoint.nil?
67
- # authorizationURL
68
- if %w[implicit accessCode].include?(security.flow)
69
- activedocs['securityDefinitions'][security.id]['authorizationUrl'] = authorization_url
70
- end
71
-
72
- # tokenUrl
73
- if %w[password application accessCode].include?(security.flow)
74
- activedocs['securityDefinitions'][security.id]['tokenUrl'] = token_url
75
- end
61
+ if !api_spec.security.nil? && api_spec.security[:type] == 'oauth2' && !oidc_issuer_endpoint.nil?
62
+ api_spec.set_oauth2_urls(activedocs, api_spec.security[:id], authorization_url, token_url)
76
63
  end
77
64
  end
78
65
  end
@@ -33,7 +33,7 @@ module ThreeScaleToolbox
33
33
  default_service_settings.tap do |svc|
34
34
  svc['name'] = service_name
35
35
  svc['description'] = service_description
36
- svc['backend_version'] = backend_version
36
+ svc['backend_version'] = api_spec.service_backend_version
37
37
  svc['system_name'] = service_system_name
38
38
  svc['deployment_option'] = 'self_managed' if !production_public_base_url.nil? || !staging_public_base_url.nil?
39
39
  end
@@ -50,10 +50,6 @@ module ThreeScaleToolbox
50
50
  def service_description
51
51
  api_spec.description
52
52
  end
53
-
54
- def backend_version
55
- api_spec.backend_version
56
- end
57
53
  end
58
54
  end
59
55
  end
@@ -17,8 +17,9 @@ module ThreeScaleToolbox
17
17
  end
18
18
 
19
19
  def pattern
20
- # apply strict matching
21
- "#{raw_pattern}$"
20
+ res = "#{raw_pattern}"
21
+ res = "#{res}$" if !operation[:prefix_matching] # apply strict matching
22
+ res
22
23
  end
23
24
 
24
25
  def raw_pattern
@@ -31,7 +31,21 @@ module ThreeScaleToolbox
31
31
  # api_spec.operations are readonly
32
32
  # store operations in context
33
33
  # each operation can be extended with extra information to be used later
34
- context[:operations] ||= api_spec.operations
34
+ context[:operations] ||= build_3scale_operations
35
+ end
36
+
37
+ def build_3scale_operations
38
+ api_spec.operations.map do |op|
39
+ Operation.new(
40
+ base_path: base_path,
41
+ public_base_path: public_base_path,
42
+ path: op[:path],
43
+ verb: op[:verb],
44
+ operationId: op[:operation_id],
45
+ description: op[:description],
46
+ prefix_matching: prefix_matching,
47
+ )
48
+ end
35
49
  end
36
50
 
37
51
  def target_system_name
@@ -43,10 +57,6 @@ module ThreeScaleToolbox
43
57
  context[:api_spec_resource]
44
58
  end
45
59
 
46
- def security
47
- api_spec.security
48
- end
49
-
50
60
  def oidc_issuer_endpoint
51
61
  context[:oidc_issuer_endpoint]
52
62
  end
@@ -59,6 +69,10 @@ module ThreeScaleToolbox
59
69
  context[:override_private_basepath]
60
70
  end
61
71
 
72
+ def override_public_basepath
73
+ context[:override_public_basepath]
74
+ end
75
+
62
76
  def production_public_base_url
63
77
  context[:production_public_base_url]
64
78
  end
@@ -70,6 +84,30 @@ module ThreeScaleToolbox
70
84
  def override_private_base_url
71
85
  context[:override_private_base_url]
72
86
  end
87
+
88
+ def backend_api_secret_token
89
+ context[:backend_api_secret_token]
90
+ end
91
+
92
+ def backend_api_host_header
93
+ context[:backend_api_host_header]
94
+ end
95
+
96
+ def prefix_matching
97
+ context[:prefix_matching]
98
+ end
99
+
100
+ def base_path
101
+ api_spec.base_path || '/'
102
+ end
103
+
104
+ def public_base_path
105
+ override_public_basepath || base_path
106
+ end
107
+
108
+ def private_base_path
109
+ override_private_basepath || base_path
110
+ end
73
111
  end
74
112
  end
75
113
  end
@@ -33,7 +33,7 @@ module ThreeScaleToolbox
33
33
 
34
34
  def add_anonymous_access_policy(policies)
35
35
  # only on 'open api' security req
36
- return unless security.nil?
36
+ return unless api_spec.security.nil?
37
37
 
38
38
  return if policies.any? { |policy| policy['name'] == 'default_credentials' }
39
39
 
@@ -60,12 +60,12 @@ module ThreeScaleToolbox
60
60
 
61
61
  def add_rh_sso_keycloak_role_check_policy(policies)
62
62
  # only applies to oauth2 sec type
63
- return if security.nil? || security.type != 'oauth2'
63
+ return if api_spec.security.nil? || api_spec.security[:type] != 'oauth2'
64
64
 
65
65
  return if policies.any? { |policy| policy['name'] == 'keycloak_role_check' }
66
66
 
67
67
  # only when there are scopes defined
68
- return if security.scopes.empty?
68
+ return if api_spec.security[:scopes].empty?
69
69
 
70
70
  policies << keycloak_policy
71
71
  end
@@ -79,7 +79,7 @@ module ThreeScaleToolbox
79
79
  scopes: [
80
80
  {
81
81
  realm_roles: [],
82
- client_roles: security.scopes.map { |scope| { 'name': scope } }
82
+ client_roles: api_spec.security[:scopes].map { |scope| { 'name': scope } }
83
83
  }
84
84
  ]
85
85
  },
@@ -88,7 +88,7 @@ module ThreeScaleToolbox
88
88
  end
89
89
 
90
90
  def add_url_rewritting_policy(policies)
91
- return if private_base_path == api_spec.public_base_path
91
+ return if private_base_path == public_base_path
92
92
 
93
93
  url_rewritting_policy_idx = policies.find_index do |policy|
94
94
  policy['name'] == 'url_rewriting'
@@ -101,10 +101,6 @@ module ThreeScaleToolbox
101
101
  end
102
102
  end
103
103
 
104
- def private_base_path
105
- override_private_basepath || api_spec.base_path
106
- end
107
-
108
104
  def url_rewritting_policy
109
105
  regex = url_rewritting_policy_regex
110
106
  replace = url_rewritting_policy_replace
@@ -128,11 +124,11 @@ module ThreeScaleToolbox
128
124
  end
129
125
 
130
126
  def url_rewritting_policy_regex
131
- "^#{api_spec.public_base_path}"
127
+ "^#{public_base_path}"
132
128
  end
133
129
 
134
130
  def url_rewritting_policy_replace
135
- "#{private_base_path}"
131
+ private_base_path
136
132
  end
137
133
  end
138
134
  end