action_policy 0.7.4 → 0.7.6
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/CHANGELOG.md +14 -3
- data/lib/.rbnext/3.0/action_policy/behaviours/policy_for.rb +1 -1
- data/lib/.rbnext/3.0/action_policy/policy/cache.rb +1 -1
- data/lib/.rbnext/3.0/action_policy/policy/execution_result.rb +1 -1
- data/lib/.rbnext/3.0/action_policy/policy/pre_check.rb +3 -3
- data/lib/.rbnext/3.0/action_policy/rspec/be_authorized_to.rb +4 -4
- data/lib/.rbnext/3.0/action_policy/rspec/have_authorized_scope.rb +4 -4
- data/lib/.rbnext/3.0/action_policy/utils/pretty_print.rb +2 -2
- data/lib/.rbnext/3.1/action_policy/behaviours/policy_for.rb +1 -1
- data/lib/.rbnext/3.2/action_policy/behaviours/policy_for.rb +1 -1
- data/lib/.rbnext/3.2/action_policy/rspec/be_authorized_to.rb +4 -4
- data/lib/.rbnext/3.2/action_policy/rspec/have_authorized_scope.rb +4 -4
- data/lib/.rbnext/3.4/action_policy/behaviours/policy_for.rb +70 -0
- data/lib/.rbnext/3.4/action_policy/i18n.rb +56 -0
- data/lib/.rbnext/3.4/action_policy/policy/cache.rb +101 -0
- data/lib/.rbnext/3.4/action_policy/policy/pre_check.rb +160 -0
- data/lib/.rbnext/3.4/action_policy/rspec/be_authorized_to.rb +96 -0
- data/lib/.rbnext/3.4/action_policy/rspec/have_authorized_scope.rb +130 -0
- data/lib/.rbnext/3.4/action_policy/utils/pretty_print.rb +155 -0
- data/lib/action_policy/behaviour.rb +1 -1
- data/lib/action_policy/behaviours/policy_for.rb +1 -1
- data/lib/action_policy/i18n.rb +1 -1
- data/lib/action_policy/policy/cache.rb +1 -1
- data/lib/action_policy/policy/execution_result.rb +1 -1
- data/lib/action_policy/policy/pre_check.rb +3 -3
- data/lib/action_policy/rails/controller.rb +45 -4
- data/lib/action_policy/rails/policy/instrumentation.rb +1 -0
- data/lib/action_policy/rspec/be_authorized_to.rb +3 -3
- data/lib/action_policy/rspec/have_authorized_scope.rb +3 -3
- data/lib/action_policy/test_helper.rb +1 -1
- data/lib/action_policy/utils/pretty_print.rb +2 -2
- data/lib/action_policy/version.rb +1 -1
- data/lib/action_policy.rb +1 -1
- data/lib/ruby_lsp/action_policy/addon.rb +170 -0
- metadata +11 -6
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# From https://gist.github.com/skryukov/35539d57b51f38235faaace2c1a2c1a1
|
|
4
|
+
|
|
5
|
+
require "active_support/inflector"
|
|
6
|
+
|
|
7
|
+
module RubyLsp
|
|
8
|
+
module ActionPolicy
|
|
9
|
+
class Addon < ::RubyLsp::Addon
|
|
10
|
+
def name
|
|
11
|
+
"ActionPolicy"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def activate(global_state, outgoing_queue)
|
|
15
|
+
require "action_policy"
|
|
16
|
+
warn "[ActionPolicy] Activating Ruby LSP addon v#{::ActionPolicy::VERSION}"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def deactivate
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def create_definition_listener(response_builder, node_context, uri, dispatcher)
|
|
23
|
+
Definition.new(response_builder, node_context, uri, dispatcher)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
class Definition
|
|
28
|
+
include Requests::Support::Common
|
|
29
|
+
include ActiveSupport::Inflector
|
|
30
|
+
|
|
31
|
+
POLICY_SUPERCLASSES = ["ApplicationPolicy", "ActionPolicy::Base"].freeze
|
|
32
|
+
|
|
33
|
+
def initialize(response_builder, uri, node_context, dispatcher)
|
|
34
|
+
@response_builder = response_builder
|
|
35
|
+
@node_context = node_context
|
|
36
|
+
@uri = uri
|
|
37
|
+
@path = uri.to_standardized_path
|
|
38
|
+
@policy_rules_cache = {}
|
|
39
|
+
|
|
40
|
+
dispatcher.register(self, :on_symbol_node_enter)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def on_symbol_node_enter(node)
|
|
44
|
+
return unless in_authorize_call?
|
|
45
|
+
|
|
46
|
+
target = @node_context.call_node
|
|
47
|
+
# authorization target is the first argument (if explicit)
|
|
48
|
+
policy_class = find_policy_class(target.arguments&.child_node&.first)
|
|
49
|
+
return unless policy_class
|
|
50
|
+
|
|
51
|
+
policy_path = find_policy_file(policy_class)
|
|
52
|
+
return unless policy_path
|
|
53
|
+
|
|
54
|
+
ensure_policy_rules_cached(policy_path)
|
|
55
|
+
add_definition(policy_path, node.value)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
private
|
|
59
|
+
|
|
60
|
+
def in_authorize_call?
|
|
61
|
+
call = @node_context.call_node
|
|
62
|
+
call.is_a?(Prism::CallNode) && call.message == "authorize!"
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def find_policy_class(target)
|
|
66
|
+
content = File.read(@path)
|
|
67
|
+
document = Prism.parse(content)
|
|
68
|
+
class_node = find_containing_class(document.value)
|
|
69
|
+
return derive_policy_from_target(target) unless class_node
|
|
70
|
+
|
|
71
|
+
class_name = class_node.constant_path.slice
|
|
72
|
+
return unless class_name.end_with?("Controller", "Channel")
|
|
73
|
+
|
|
74
|
+
resource_name = class_name
|
|
75
|
+
.delete_suffix("Controller")
|
|
76
|
+
.delete_suffix("Channel")
|
|
77
|
+
.singularize
|
|
78
|
+
"#{resource_name}Policy"
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def find_containing_class(root)
|
|
82
|
+
return unless root.respond_to?(:statements)
|
|
83
|
+
|
|
84
|
+
root.statements.body.find do |node|
|
|
85
|
+
node.is_a?(Prism::ClassNode) &&
|
|
86
|
+
node.constant_path.slice.end_with?("Controller", "Channel")
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def derive_policy_from_target(target)
|
|
91
|
+
target_name = case target
|
|
92
|
+
when Prism::InstanceVariableReadNode
|
|
93
|
+
target.name.to_s[1..].classify
|
|
94
|
+
when Prism::ConstantReadNode
|
|
95
|
+
target.name.to_s
|
|
96
|
+
when NilClass
|
|
97
|
+
return
|
|
98
|
+
else
|
|
99
|
+
target.slice
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
target_name.end_with?("Policy") ? target_name : "#{target_name}Policy"
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def find_policy_file(policy_class)
|
|
106
|
+
file_path = policy_class.gsub(/([a-z])([A-Z])/, "\\1_\\2").downcase
|
|
107
|
+
root_path = Dir.pwd
|
|
108
|
+
|
|
109
|
+
[
|
|
110
|
+
File.join(root_path, "app/policies/#{file_path}.rb"),
|
|
111
|
+
File.join(root_path, "app/policies/#{file_path}_policy.rb"),
|
|
112
|
+
*Dir.glob(File.join(root_path, "app/policies/**/#{file_path}.rb")),
|
|
113
|
+
*Dir.glob(File.join(root_path, "app/policies/**/#{file_path}_policy.rb"))
|
|
114
|
+
].find { |path| File.exist?(path) }
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def ensure_policy_rules_cached(policy_path)
|
|
118
|
+
return if @policy_rules_cache[policy_path]
|
|
119
|
+
|
|
120
|
+
content = File.read(policy_path)
|
|
121
|
+
document = Prism.parse(content)
|
|
122
|
+
|
|
123
|
+
document.value.statements.body.each do |stmt|
|
|
124
|
+
if stmt.is_a?(Prism::ClassNode)
|
|
125
|
+
@policy_rules_cache[policy_path] = extract_rules(stmt)
|
|
126
|
+
break
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def extract_rules(node)
|
|
132
|
+
return {} unless node.body
|
|
133
|
+
|
|
134
|
+
rules = {}
|
|
135
|
+
private_section = false
|
|
136
|
+
|
|
137
|
+
node.body.child_nodes.each do |stmt|
|
|
138
|
+
case stmt
|
|
139
|
+
when Prism::CallNode
|
|
140
|
+
if stmt.message == "private"
|
|
141
|
+
private_section = true
|
|
142
|
+
elsif stmt.message == "alias_rule" && stmt.arguments&.arguments
|
|
143
|
+
stmt.arguments.arguments
|
|
144
|
+
.select { |arg| arg.is_a?(Prism::SymbolNode) }
|
|
145
|
+
.each { |arg| rules[arg.value] ||= stmt.location.start_line }
|
|
146
|
+
end
|
|
147
|
+
when Prism::DefNode
|
|
148
|
+
next if private_section
|
|
149
|
+
rules[stmt.name.to_s] = stmt.location.start_line
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
rules
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def add_definition(policy_path, action)
|
|
156
|
+
rules = @policy_rules_cache[policy_path]
|
|
157
|
+
line_number = rules&.[](action.to_s)
|
|
158
|
+
return unless line_number
|
|
159
|
+
|
|
160
|
+
@response_builder << Interface::Location.new(
|
|
161
|
+
uri: URI::Generic.from_path(path: policy_path).to_s,
|
|
162
|
+
range: Interface::Range.new(
|
|
163
|
+
start: Interface::Position.new(line: line_number - 1, character: 0),
|
|
164
|
+
end: Interface::Position.new(line: line_number - 1, character: 0)
|
|
165
|
+
)
|
|
166
|
+
)
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
end
|
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: action_policy
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.7.
|
|
4
|
+
version: 0.7.6
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Vladimir Dementyev
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: ruby-next-core
|
|
@@ -162,6 +161,13 @@ files:
|
|
|
162
161
|
- lib/.rbnext/3.2/action_policy/rspec/be_authorized_to.rb
|
|
163
162
|
- lib/.rbnext/3.2/action_policy/rspec/have_authorized_scope.rb
|
|
164
163
|
- lib/.rbnext/3.2/action_policy/utils/suggest_message.rb
|
|
164
|
+
- lib/.rbnext/3.4/action_policy/behaviours/policy_for.rb
|
|
165
|
+
- lib/.rbnext/3.4/action_policy/i18n.rb
|
|
166
|
+
- lib/.rbnext/3.4/action_policy/policy/cache.rb
|
|
167
|
+
- lib/.rbnext/3.4/action_policy/policy/pre_check.rb
|
|
168
|
+
- lib/.rbnext/3.4/action_policy/rspec/be_authorized_to.rb
|
|
169
|
+
- lib/.rbnext/3.4/action_policy/rspec/have_authorized_scope.rb
|
|
170
|
+
- lib/.rbnext/3.4/action_policy/utils/pretty_print.rb
|
|
165
171
|
- lib/action_policy.rb
|
|
166
172
|
- lib/action_policy/authorizer.rb
|
|
167
173
|
- lib/action_policy/base.rb
|
|
@@ -218,6 +224,7 @@ files:
|
|
|
218
224
|
- lib/generators/rspec/templates/policy_spec.rb.tt
|
|
219
225
|
- lib/generators/test_unit/policy_generator.rb
|
|
220
226
|
- lib/generators/test_unit/templates/policy_test.rb.tt
|
|
227
|
+
- lib/ruby_lsp/action_policy/addon.rb
|
|
221
228
|
homepage: https://github.com/palkan/action_policy
|
|
222
229
|
licenses:
|
|
223
230
|
- MIT
|
|
@@ -227,7 +234,6 @@ metadata:
|
|
|
227
234
|
documentation_uri: https://actionpolicy.evilmartians.io/
|
|
228
235
|
homepage_uri: https://actionpolicy.evilmartians.io/
|
|
229
236
|
source_code_uri: http://github.com/palkan/action_policy
|
|
230
|
-
post_install_message:
|
|
231
237
|
rdoc_options: []
|
|
232
238
|
require_paths:
|
|
233
239
|
- lib
|
|
@@ -242,8 +248,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
242
248
|
- !ruby/object:Gem::Version
|
|
243
249
|
version: '0'
|
|
244
250
|
requirements: []
|
|
245
|
-
rubygems_version: 3.
|
|
246
|
-
signing_key:
|
|
251
|
+
rubygems_version: 3.6.9
|
|
247
252
|
specification_version: 4
|
|
248
253
|
summary: Authorization framework for Ruby/Rails application
|
|
249
254
|
test_files: []
|