ree_lib 1.3.7 → 1.3.9

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: 22c9b3f24637ea89df5a633bb65b00165bdcf89193dc870cacd6521ead772c5a
4
- data.tar.gz: fa3c84478540381ba0dba7046bf41dc472e3de75fed7bc99b53e78cddc14de4c
3
+ metadata.gz: 237cf0a00005f59af6c0741f79302159d84433b60b63e401baa4ae95ab0dd2ae
4
+ data.tar.gz: f9c00515a41e9d78fc2c3ac1785d5a8a21d1f4142461537299e4c1678d4a6b61
5
5
  SHA512:
6
- metadata.gz: 7f7c74ea3f1d7a72b9c61dc8ddf2291dc4493a863c89cbda641f42ffbb8a505b5fe7537cb2d39bb03c65fc805350a3d5788c68b77e5a86a05dbbc70061f077c3
7
- data.tar.gz: 8ad1a702714b65592c6c37f932d22d86727263240faa64e3b23c48a2b330d7f2cfab37c162bdb8d9ad0edb0b9e004871f0ae266dbfc0d1097f4899239c31a5e7
6
+ metadata.gz: c712530b729aa1e48d53de393ee737b7605c233108940e78f09f4561c36b69c413136880f8b72f73f694d4a6ac5ee7e4010d2d46ff2dcdb30450ad1fd2bb9a56
7
+ data.tar.gz: e148d3f589e0c2863a9b1958d903458407c1646f0fca6ca79c5fb0839893c0bc00059b4a80a9c0b45cf6710e4e9b6802f6a94ee9b8958fa485701164cd99a240
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ../ree
3
3
  specs:
4
- ree (1.3.2)
4
+ ree (1.3.3)
5
5
  base64
6
6
  commander
7
7
  logger
@@ -9,7 +9,7 @@ PATH
9
9
  PATH
10
10
  remote: .
11
11
  specs:
12
- ree_lib (1.3.6)
12
+ ree_lib (1.3.9)
13
13
  bigdecimal
14
14
  binding_of_caller
15
15
  i18n
@@ -11,14 +11,18 @@ class Roda
11
11
  module ReeLogger
12
12
  REE_LOGGER_DEFAULTS = {
13
13
  method: :info,
14
- log_params: true
14
+ log_params: true,
15
+ filter_params: [],
16
+ filter_params_placeholder: '[FILTERED]'
15
17
  }
16
18
 
17
19
  def self.configure(app, **opts)
18
20
  opts = REE_LOGGER_DEFAULTS.merge(opts)
19
- app.opts[:ree_logger] = ::ReeLogger::Logger.new
21
+ app.opts[:ree_logger] = opts[:ree_logger] || ::ReeLogger::Logger.new
20
22
  app.opts[:ree_logger_filter] = opts[:filter] if opts[:filter]
21
23
  app.opts[:ree_logger_log_params] = !!opts[:log_params]
24
+ app.opts[:ree_logger_filter_params] = opts[:filter_params].map(&:to_s)
25
+ app.opts[:ree_logger_filter_params_placeholder] = opts[:filter_params_placeholder]
22
26
  end
23
27
 
24
28
  def self.start_timer
@@ -46,7 +50,7 @@ class Roda
46
50
 
47
51
  message = <<~DOC
48
52
  Request/Response details:
49
- Request: #{env["REQUEST_METHOD"]} #{env["QUERY_STRING"] && !env["QUERY_STRING"].empty? ? env["SCRIPT_NAME"].to_s + env["PATH_INFO"] + "?#{env["QUERY_STRING"]}": env["SCRIPT_NAME"].to_s + env["PATH_INFO"]} #{opts[:ree_logger_log_params] ? "\n Params: " + request.params.inspect : ""}
53
+ Request: #{env["REQUEST_METHOD"]} #{env["QUERY_STRING"] && !env["QUERY_STRING"].empty? ? env["SCRIPT_NAME"].to_s + env["PATH_INFO"] + "?#{env["QUERY_STRING"]}": env["SCRIPT_NAME"].to_s + env["PATH_INFO"]} #{opts[:ree_logger_log_params] ? "\n Params: " + _ree_logger_filtered_params.inspect : ""}
50
54
  Response status: #{response.status || "-"}#{(400..499).include?(response.status) ? "\n Response body: " + response.body[0].to_s : ""}
51
55
  Time Taken: #{elapsed_time}
52
56
  DOC
@@ -54,6 +58,19 @@ class Roda
54
58
  opts[:ree_logger].info(message)
55
59
  end
56
60
 
61
+ def _ree_logger_filtered_params
62
+ params = request.params
63
+ filter_keys = opts[:ree_logger_filter_params]
64
+
65
+ return params if filter_keys.empty?
66
+
67
+ placeholder = opts[:ree_logger_filter_params_placeholder]
68
+
69
+ params.each_with_object({}) do |(k, v), h|
70
+ h[k] = filter_keys.include?(k.to_s) ? placeholder : v
71
+ end
72
+ end
73
+
57
74
  # Create timer instance used for timing
58
75
  def _roda_before_05__ree_logger
59
76
  @_request_timer = ReeLogger.start_timer
@@ -17,7 +17,8 @@ class Roda
17
17
 
18
18
  module ClassMethods
19
19
  def ree_routes(routes, swagger_title: "", swagger_description: "",
20
- swagger_version: "", swagger_url: "", api_url: "")
20
+ swagger_version: "", swagger_url: "", api_url: "",
21
+ swagger_include_internal: nil)
21
22
  @ree_routes ||= []
22
23
  @ree_routes += routes
23
24
 
@@ -27,12 +28,17 @@ class Roda
27
28
  opts[:ree_routes_swagger_url] = swagger_url
28
29
  opts[:ree_routes_api_url] = api_url
29
30
 
31
+ # nil keeps the global default (Ree.hide_internal_swagger_endpoints);
32
+ # pass true/false to force one app to differ from it.
33
+ swagger_opts = swagger_include_internal.nil? ? {} : { include_internal: swagger_include_internal }
34
+
30
35
  opts[:ree_routes_swagger] = ReeRoda::BuildSwaggerFromRoutes.new.call(
31
36
  @ree_routes,
32
37
  opts[:ree_routes_swagger_title],
33
38
  opts[:ree_routes_swagger_description],
34
39
  opts[:ree_routes_swagger_version],
35
- opts[:ree_routes_api_url]
40
+ opts[:ree_routes_api_url],
41
+ **swagger_opts
36
42
  )
37
43
 
38
44
  build_routes_proc
@@ -7,8 +7,19 @@ class ReeRoda::BuildSwaggerFromRoutes
7
7
  link "ree_swagger/dto/endpoint_dto", -> { EndpointDto }
8
8
  end
9
9
 
10
- contract(ArrayOf[ReeRoutes::Route], String, String, String, String => Hash)
11
- def call(routes, title, description, version, api_url)
10
+ contract(
11
+ ArrayOf[ReeRoutes::Route], String, String, String, String,
12
+ Ksplat[include_internal?: Bool] => Hash
13
+ )
14
+ def call(routes, title, description, version, api_url, **opts)
15
+ # Defaults to the global switch (see Ree.hide_internal_swagger_endpoints),
16
+ # so one codebase can serve a public and an internal document.
17
+ include_internal = opts.fetch(:include_internal) {
18
+ !Ree.hide_internal_swagger_endpoints?
19
+ }
20
+
21
+ routes = routes.select(&:public?) if !include_internal
22
+
12
23
  endpoints = routes.map do |route|
13
24
  method_decorator = Ree::Contracts.get_method_decorator(
14
25
  route.action.klass, :call, scope: :instance
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal = true
2
+
3
+ package_require("ree_roda/plugins/ree_logger")
4
+
5
+ RSpec.describe :ree_logger do
6
+ it "filters request params" do
7
+ class TestFilterApp < ReeRoda::App
8
+ route do |r|
9
+ r.get "health" do
10
+ "success"
11
+ end
12
+
13
+ r.ree_routes
14
+ end
15
+ end
16
+
17
+ env = { "REQUEST_METHOD" => "GET", "PATH_INFO" => "/health", "QUERY_STRING" => "email=test@example.com&password=password" }
18
+
19
+ class TestFilterLogger
20
+ def info(msg)
21
+ @logs ||= []
22
+ @logs << msg
23
+ end
24
+
25
+ def logs
26
+ @logs
27
+ end
28
+ end
29
+ logger = TestFilterLogger.new
30
+
31
+ TestFilterApp.plugin(:ree_logger, ree_logger: logger, filter_params: ['password'])
32
+ TestFilterApp.app.call(env)
33
+
34
+ expect(logger.logs.first).to match('"password" => "\[FILTERED\]"')
35
+ end
36
+ end
@@ -24,6 +24,8 @@ module ReeRoutes
24
24
  include Ree::Contracts::Core
25
25
  include Ree::Contracts::ArgContracts
26
26
 
27
+ ADMIN_PATH_SEGMENT = "admin"
28
+
27
29
  def routes(name, &proc)
28
30
  raise ArgumentError.new("block is required") if !block_given?
29
31
 
@@ -87,6 +89,14 @@ module ReeRoutes
87
89
  raise ArgumentError.new("action, summary and auth scope should be provided for #{builder.get_route.inspect}")
88
90
  end
89
91
 
92
+ if builder.get_route.visibility.nil? && admin_path?(path)
93
+ raise ArgumentError.new(
94
+ "admin route #{path} must declare visibility explicitly: " \
95
+ "`visibility :internal` to keep it out of generated swagger, " \
96
+ "or `visibility :public` if it is intentionally documented"
97
+ )
98
+ end
99
+
90
100
  route = builder.get_route
91
101
 
92
102
  @dsl.link(route.action.name, from: route.action.package_name)
@@ -98,6 +108,13 @@ module ReeRoutes
98
108
  @routes << route
99
109
  route
100
110
  end
111
+
112
+ # Forgetting `visibility` on an admin route is invisible in review and
113
+ # silently publishes it, so make it a boot-time failure instead.
114
+ contract String => Bool
115
+ def admin_path?(path)
116
+ path.split("/").include?(ADMIN_PATH_SEGMENT)
117
+ end
101
118
  end
102
119
  end
103
120
  end
@@ -2,7 +2,17 @@
2
2
 
3
3
  class ReeRoutes::Route
4
4
  attr_accessor :summary, :request_method, :serializer, :respond_to,
5
- :sections, :action, :route, :warden_scopes, :path, :override
5
+ :sections, :action, :route, :warden_scopes, :path, :override,
6
+ :visibility
7
+
8
+ # Routing always includes every route; visibility only affects generated docs.
9
+ def public?
10
+ visibility.nil? || visibility == :public
11
+ end
12
+
13
+ def internal?
14
+ !public?
15
+ end
6
16
 
7
17
  def valid?
8
18
  !action.nil? && !summary.nil? && !warden_scopes.nil? && !warden_scopes.empty?
@@ -5,6 +5,8 @@ require_relative "route"
5
5
  class ReeRoutes::RouteBuilder
6
6
  Redirect = Struct.new(:path, :code)
7
7
 
8
+ VISIBILITIES = [:public, :internal].freeze
9
+
8
10
  def initialize
9
11
  @route = ReeRoutes::Route.new
10
12
  @route.respond_to = :json
@@ -42,6 +44,17 @@ class ReeRoutes::RouteBuilder
42
44
  @route.summary = str
43
45
  end
44
46
 
47
+ contract Symbol => Symbol
48
+ def visibility(value)
49
+ if !VISIBILITIES.include?(value)
50
+ raise ArgumentError.new(
51
+ "visibility should be one of #{VISIBILITIES.inspect}, got #{value.inspect}"
52
+ )
53
+ end
54
+
55
+ @route.visibility = value
56
+ end
57
+
45
58
  contract Symbol, Symbol => nil
46
59
  def serializer(name, from:)
47
60
  object = Ree.container.packages_facade.get_object(from, name)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ReeLib
4
- VERSION = "1.3.7"
4
+ VERSION = "1.3.9"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ree_lib
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.7
4
+ version: 1.3.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ruslan Gatiyatov
@@ -891,6 +891,7 @@ files:
891
891
  - lib/ree_lib/packages/ree_roda/package/ree_roda/services/build_swagger_from_routes.rb
892
892
  - lib/ree_lib/packages/ree_roda/package/ree_roda/services/status_from_error.rb
893
893
  - lib/ree_lib/packages/ree_roda/spec/ree_roda/app_spec.rb
894
+ - lib/ree_lib/packages/ree_roda/spec/ree_roda/plugins/ree_logger_spec.rb
894
895
  - lib/ree_lib/packages/ree_roda/spec/ree_roda/services/build_routing_tree_spec.rb
895
896
  - lib/ree_lib/packages/ree_roda/spec/ree_roda/services/build_swagger_from_routes_spec.rb
896
897
  - lib/ree_lib/packages/ree_roda/spec/ree_roda/services/locales/en.yml