ree_lib 1.3.13 → 1.3.14

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: 5a4843ec9ab12ce886333af41c258c9994ced5666fc6720a443fd42e7b8e1300
4
- data.tar.gz: de155878c3031c3bcbfc24a3ca1b2fb1cf6822420cbd3959f3221da9172f1769
3
+ metadata.gz: 2ebed252b6557db13e60268884fd6b1a0f405f256d28aaf18953764886ab6cb0
4
+ data.tar.gz: e6328fda6013213c588f834b5a0782c271c76686b8303a0f458cfac5e926c80d
5
5
  SHA512:
6
- metadata.gz: 399d35c7b455d605572dcf8c5ebd426de556401e9eb6fd75b0c47745abf691dc8956f743e94e3ab8674c991d6bea040d55901e0b9443d7ec55a7c7bbc609f65a
7
- data.tar.gz: ecad1589e6231b1fee0baa64d7bfcc5fea36dcb23deb5b02b6bbe9f0bcc307934f50ec086b7ec795c55a8a22c899516c8680b1bb0943c50136dcb9020963914d
6
+ metadata.gz: 06ad16d1ca9361397b0e324d8ab0d9a3a064337831384f45616dd500efb88367c84be252537d203e07ec08cb109e8f976980ff39ac2de315f96938a21edc697e
7
+ data.tar.gz: fa3b6b910f9855585af6f0e985720db3773d7483779f65d3907badc16711e5bfdd159abcfcd8135466a5a2c57a75645da44c79ba532e0bcd9bf777d50aa7bdd5
data/Gemfile.lock CHANGED
@@ -9,7 +9,7 @@ PATH
9
9
  PATH
10
10
  remote: .
11
11
  specs:
12
- ree_lib (1.3.13)
12
+ ree_lib (1.3.14)
13
13
  bigdecimal
14
14
  binding_of_caller
15
15
  i18n
@@ -54,11 +54,12 @@ through `ree_logger`.
54
54
 
55
55
  ## What gets audited
56
56
 
57
- `Route#audited?` returns `internal?` unless the route says otherwise:
57
+ Nothing is audited until the route says so:
58
58
 
59
59
  ```ruby
60
60
  get "api/v1/admin/users" do
61
- visibility :internal # audited by default
61
+ visibility :internal
62
+ audit true # recorded
62
63
  end
63
64
 
64
65
  get "api/v1/admin/health" do
@@ -66,19 +67,20 @@ get "api/v1/admin/health" do
66
67
  audit false # deliberately silent
67
68
  end
68
69
 
69
- get "api/v1/exports" do
70
- audit true # public route reaching into someone else's data
71
- end
72
-
73
70
  get "api/v1/organizations/:id/balance" do
74
71
  audit :on_annotation # the owner calls it too — see below
75
72
  end
76
73
  ```
77
74
 
78
- Tying the default to `visibility` rather than to a hand-kept list is deliberate:
79
- `visibility` is mandatory on admin paths (the routes DSL fails at boot without
80
- it), so the audited set cannot drift away from the set of routes that actually
81
- touch client data.
75
+ The flag is declared at the route and nowhere else. Deriving it from
76
+ `visibility` would work just as well and read far worse: whether a call lands in
77
+ the access trail is exactly the kind of fact a reader must see where the route
78
+ is written, not infer from a flag that means something else.
79
+
80
+ Forgetting it is not possible where it matters: like `visibility`, `audit` is
81
+ mandatory on admin paths — a route whose path carries an `admin` segment fails
82
+ at boot until it declares one. So the audited set cannot drift away from the set
83
+ of routes that reach client data.
82
84
 
83
85
  ### `audit :on_annotation`
84
86
 
@@ -99,6 +99,14 @@ RSpec.describe "ree_routes audit" do
99
99
  summary "Internal route"
100
100
  sections "Admin"
101
101
  visibility :internal
102
+ audit true
103
+ action :ok_cmd, **opts
104
+ end
105
+
106
+ get "api/internal_undeclared" do
107
+ summary "Internal route that never mentions audit"
108
+ sections "Admin"
109
+ visibility :internal
102
110
  action :ok_cmd, **opts
103
111
  end
104
112
 
@@ -148,6 +156,7 @@ RSpec.describe "ree_routes audit" do
148
156
  summary "Internal route refusing access"
149
157
  sections "Admin"
150
158
  visibility :internal
159
+ audit true
151
160
  action :denied_cmd, **opts
152
161
  end
153
162
 
@@ -155,6 +164,7 @@ RSpec.describe "ree_routes audit" do
155
164
  summary "Internal route blowing up"
156
165
  sections "Admin"
157
166
  visibility :internal
167
+ audit true
158
168
  action :boom_cmd, **opts
159
169
  end
160
170
  end
@@ -274,6 +284,13 @@ RSpec.describe "ree_routes audit" do
274
284
  expect(event.accessor).to eq({user: "visitor"})
275
285
  end
276
286
 
287
+ it "leaves an internal route that never declared audit out of the trail" do
288
+ get "api/internal_undeclared"
289
+
290
+ expect(last_response.status).to eq(200)
291
+ expect(test_sink.events).to be_empty
292
+ end
293
+
277
294
  it "leaves a silenced internal route out of the trail" do
278
295
  get "api/internal_silenced"
279
296
 
@@ -97,6 +97,14 @@ module ReeRoutes
97
97
  )
98
98
  end
99
99
 
100
+ if !builder.get_route.audit_declared? && admin_path?(path)
101
+ raise ArgumentError.new(
102
+ "admin route #{path} must declare audit explicitly: " \
103
+ "`audit true` to record the call in the access trail, " \
104
+ "or `audit false` if the route touches nothing worth recording"
105
+ )
106
+ end
107
+
100
108
  route = builder.get_route
101
109
 
102
110
  @dsl.link(route.action.name, from: route.action.package_name)
@@ -16,12 +16,18 @@ class ReeRoutes::Route
16
16
  !public?
17
17
  end
18
18
 
19
- # Internal routes are audited unless told otherwise. `visibility` is
20
- # mandatory for admin paths (see DSL#define_route), so this list can never
21
- # drift away from the set of routes that actually touch client data which a
22
- # hand-maintained list of audited routes inevitably would.
19
+ # Auditing is declared at the route and nowhere else. Deriving it from
20
+ # `visibility` would work just as well and read far worse: whether a call
21
+ # lands in the access trail is exactly the kind of fact that must be visible
22
+ # where the route is written, not inferred from a flag that means something
23
+ # else. `audit` is mandatory on admin paths (see DSL#define_route), so the
24
+ # audited set still cannot drift away from the routes that touch client data.
23
25
  def audited?
24
- @audit.nil? ? internal? : @audit != false
26
+ @audit == true || @audit == :on_annotation
27
+ end
28
+
29
+ def audit_declared?
30
+ !@audit.nil?
25
31
  end
26
32
 
27
33
  # `audit :on_annotation` — a public route that the client calls for its own
@@ -76,7 +76,14 @@ RSpec.describe ReeRoutes::DSL, type: [:autoclean] do
76
76
  default_warden_scope :user
77
77
 
78
78
  get "internal_default" do
79
- summary "Internal route, audited by default"
79
+ summary "Internal route that says it is audited"
80
+ action :cmd, from: :ree_routes_test
81
+ visibility :internal
82
+ audit true
83
+ end
84
+
85
+ get "internal_undeclared" do
86
+ summary "Internal route that never mentions audit"
80
87
  action :cmd, from: :ree_routes_test
81
88
  visibility :internal
82
89
  end
@@ -137,7 +144,10 @@ RSpec.describe ReeRoutes::DSL, type: [:autoclean] do
137
144
  }
138
145
 
139
146
  expect(routes["internal_default"].audited?).to eq(true)
147
+ expect(routes["internal_undeclared"].audited?).to eq(false)
148
+ expect(routes["internal_undeclared"].audit_declared?).to eq(false)
140
149
  expect(routes["internal_silenced"].audited?).to eq(false)
150
+ expect(routes["internal_silenced"].audit_declared?).to eq(true)
141
151
  expect(routes["public_default"].audited?).to eq(false)
142
152
  expect(routes["public_audited"].audited?).to eq(true)
143
153
  expect(routes["public_on_annotation"].audited?).to eq(true)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ReeLib
4
- VERSION = "1.3.13"
4
+ VERSION = "1.3.14"
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.13
4
+ version: 1.3.14
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ruslan Gatiyatov