3scale_toolbox 0.14.0 → 0.15.0

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