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 +4 -4
- data/Gemfile.lock +2 -2
- data/lib/ree_lib/packages/ree_roda/package/ree_roda/plugins/ree_logger.rb +20 -3
- data/lib/ree_lib/packages/ree_roda/package/ree_roda/plugins/ree_routes.rb +8 -2
- data/lib/ree_lib/packages/ree_roda/package/ree_roda/services/build_swagger_from_routes.rb +13 -2
- data/lib/ree_lib/packages/ree_roda/spec/ree_roda/plugins/ree_logger_spec.rb +36 -0
- data/lib/ree_lib/packages/ree_routes/package/ree_routes/dsl.rb +17 -0
- data/lib/ree_lib/packages/ree_routes/package/ree_routes/route.rb +11 -1
- data/lib/ree_lib/packages/ree_routes/package/ree_routes/route_builder.rb +13 -0
- data/lib/ree_lib/version.rb +1 -1
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 237cf0a00005f59af6c0741f79302159d84433b60b63e401baa4ae95ab0dd2ae
|
|
4
|
+
data.tar.gz: f9c00515a41e9d78fc2c3ac1785d5a8a21d1f4142461537299e4c1678d4a6b61
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c712530b729aa1e48d53de393ee737b7605c233108940e78f09f4561c36b69c413136880f8b72f73f694d4a6ac5ee7e4010d2d46ff2dcdb30450ad1fd2bb9a56
|
|
7
|
+
data.tar.gz: e148d3f589e0c2863a9b1958d903458407c1646f0fca6ca79c5fb0839893c0bc00059b4a80a9c0b45cf6710e4e9b6802f6a94ee9b8958fa485701164cd99a240
|
data/Gemfile.lock
CHANGED
|
@@ -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: " +
|
|
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(
|
|
11
|
-
|
|
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)
|
data/lib/ree_lib/version.rb
CHANGED
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.
|
|
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
|