mikras_utils 0.3.2 → 0.4.0
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/exe/mkacl +31 -14
- data/exe/rls +30 -0
- data/lib/mikras_utils/mikras.rb +24 -0
- data/lib/mikras_utils/mkacl/analyzer.rb +35 -21
- data/lib/mikras_utils/mkacl/generator.rb +4 -2
- data/lib/mikras_utils/mkacl/generators/acl_functions.rb +26 -9
- data/lib/mikras_utils/mkacl/generators/id_functions.rb +92 -103
- data/lib/mikras_utils/mkacl/generators/role_functions.rb +37 -40
- data/lib/mikras_utils/mkacl/generators/rules.rb +2 -2
- data/lib/mikras_utils/mkacl/generators/seeds.rb +80 -0
- data/lib/mikras_utils/mkacl/parser.rb +39 -15
- data/lib/mikras_utils/mkacl/simple_symtab.rb +58 -0
- data/lib/mikras_utils/mkacl/spec.rb +67 -29
- data/lib/mikras_utils/mkacl.rb +3 -1
- data/lib/mikras_utils/rls/analyzer.rb +108 -0
- data/lib/mikras_utils/rls/parser.rb +70 -0
- data/lib/mikras_utils/rls/spec.rb +86 -0
- data/lib/mikras_utils/version.rb +1 -1
- metadata +10 -2
@@ -0,0 +1,108 @@
|
|
1
|
+
|
2
|
+
class Analyzer
|
3
|
+
attr_reader :spec
|
4
|
+
def vars = spec.variables
|
5
|
+
|
6
|
+
def initialize(spec)
|
7
|
+
@spec = spec
|
8
|
+
end
|
9
|
+
|
10
|
+
def analyze
|
11
|
+
interpolate
|
12
|
+
expand_rules
|
13
|
+
merge_rules
|
14
|
+
spec
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.analyze(spec)
|
18
|
+
self.new(spec).analyze
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
#
|
23
|
+
# Interpolate variables
|
24
|
+
#
|
25
|
+
def interpolate
|
26
|
+
interpolate_variables
|
27
|
+
interpolate_spec
|
28
|
+
end
|
29
|
+
|
30
|
+
def interpolate_variables
|
31
|
+
spec.variables.transform_values! { |a|
|
32
|
+
a.map { |e|
|
33
|
+
if e =~ /^\$[A-Za-z0-9_]+$/
|
34
|
+
spec.variables[e] or ShellOpts::error "Unknown variable #{e}"
|
35
|
+
else
|
36
|
+
e
|
37
|
+
end
|
38
|
+
}.flatten
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
42
|
+
def interpolate_spec
|
43
|
+
spec.rules.each { |r| interpolate_rule(r) }
|
44
|
+
end
|
45
|
+
|
46
|
+
def interpolate_rule(rule)
|
47
|
+
rule.tables = interpolate_array(rule.tables)
|
48
|
+
p rule.opers.map(&:class)
|
49
|
+
|
50
|
+
rule.opers.each { |op| interpolate_oper(op) }
|
51
|
+
end
|
52
|
+
|
53
|
+
def interpolate_oper(oper)
|
54
|
+
oper.accesses.each { |a| interpolate_access(a) }
|
55
|
+
end
|
56
|
+
|
57
|
+
def interpolate_access(access)
|
58
|
+
access.roles = interpolate_array(access.roles)
|
59
|
+
access.tables = interpolate_string(access.tables)
|
60
|
+
access.fields = interpolate_array(access.fields)
|
61
|
+
access.where = interpolate_string(access.where)
|
62
|
+
end
|
63
|
+
|
64
|
+
def interpolate_string(string)
|
65
|
+
return nil if string.nil?
|
66
|
+
for key, value in vars
|
67
|
+
next if !value.is_a?(String)
|
68
|
+
string.gsub!(/#{key}/, value)
|
69
|
+
end
|
70
|
+
string
|
71
|
+
end
|
72
|
+
|
73
|
+
def interpolate_array(array)
|
74
|
+
return nil if array.nil?
|
75
|
+
array.map { |e| vars[e] || e }.flatten
|
76
|
+
end
|
77
|
+
|
78
|
+
#
|
79
|
+
# Expand rules
|
80
|
+
#
|
81
|
+
def expand_rules()
|
82
|
+
rules = []
|
83
|
+
spec.rules.each { |rule|
|
84
|
+
rule.tables.each { |t| r = rule.dup; r.tables = [t]; rules << r }
|
85
|
+
}
|
86
|
+
spec.rules = rules
|
87
|
+
end
|
88
|
+
|
89
|
+
#
|
90
|
+
# Merge rules
|
91
|
+
#
|
92
|
+
def merge_rules()
|
93
|
+
spec.rules = spec.rules.group_by { |rule| rule.tables.first }.map { |table, rules|
|
94
|
+
rule = Rule.new([table])
|
95
|
+
for oper in Spec::OPERS
|
96
|
+
rule[oper] = merge_opers(oper, rules.map { |r| r[oper] }.flatten)
|
97
|
+
end
|
98
|
+
rule
|
99
|
+
}
|
100
|
+
end
|
101
|
+
|
102
|
+
def merge_opers(oper, opers)
|
103
|
+
oper = Oper.new(oper)
|
104
|
+
oper.accesses = opers.map { |op| op.accesses }.flatten
|
105
|
+
oper
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
@@ -0,0 +1,70 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
include ForwardTo
|
6
|
+
|
7
|
+
class Parser
|
8
|
+
def initialize(file)
|
9
|
+
@file = file
|
10
|
+
end
|
11
|
+
|
12
|
+
def parse
|
13
|
+
yaml = YAML.load(IO.read(@file).sub(/^__END__$.*/m, ""), symbolize_names: true)
|
14
|
+
rules = nil
|
15
|
+
variables = {}
|
16
|
+
yaml.each { |key, value|
|
17
|
+
case key
|
18
|
+
when :rules; rules = value.map { |v| parse_rule(v) }
|
19
|
+
when /^\$[A-Z0-9_]+$/; variables[key.to_s] = parse_array(value)
|
20
|
+
else
|
21
|
+
raise "Illegal section: #{key}"
|
22
|
+
end
|
23
|
+
}
|
24
|
+
Spec.new(@file, rules, variables)
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.parse(file) self.new(file).parse end
|
28
|
+
|
29
|
+
private
|
30
|
+
def parse_rule(hash)
|
31
|
+
tables = parse_array(hash[:tables]) or error "Can't find 'table' key"
|
32
|
+
rule = Rule.new(tables)
|
33
|
+
for oper in Spec::OPERS
|
34
|
+
value = hash[oper] or next
|
35
|
+
rule.send(:"#{oper}=", parse_oper(oper, value))
|
36
|
+
end
|
37
|
+
rule
|
38
|
+
end
|
39
|
+
|
40
|
+
def parse_oper(oper, value)
|
41
|
+
case value
|
42
|
+
when String; Oper.new(oper, [Access.new(parse_array(value), nil, nil, nil)])
|
43
|
+
when Hash; Oper.new(oper, [parse_access(value)])
|
44
|
+
when Array; Oper.new(oper, value.map { |hash| parse_access(hash) })
|
45
|
+
else
|
46
|
+
error "Illegal argument: #{value.invaluet}"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def parse_access(hash)
|
51
|
+
illegal_keys = hash.keys - Spec::FIELDS
|
52
|
+
illegal_keys.empty? or error "Illegal keys: #{illegal_keys.join(', ')}"
|
53
|
+
roles = parse_array(hash[:roles])
|
54
|
+
tables = parse_array(hash[:tables])
|
55
|
+
fields = parse_array(hash[:fields])
|
56
|
+
where = hash[:where]
|
57
|
+
Access.new(roles, tables, fields, where)
|
58
|
+
end
|
59
|
+
|
60
|
+
def parse_array(value)
|
61
|
+
case value
|
62
|
+
when String; value.split
|
63
|
+
when Array; value
|
64
|
+
when nil; nil
|
65
|
+
else
|
66
|
+
error "Illegal array value: #{value.inspect}"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
@@ -0,0 +1,86 @@
|
|
1
|
+
|
2
|
+
class Spec
|
3
|
+
OPERS = [:select, :insert, :update, :delete, :attach]
|
4
|
+
FIELDS = [:roles, :tables, :fields, :where]
|
5
|
+
|
6
|
+
attr_reader :file
|
7
|
+
attr_accessor :rules
|
8
|
+
attr_accessor :variables
|
9
|
+
|
10
|
+
forward_to :variables, :[], :[]=
|
11
|
+
|
12
|
+
def initialize(file, rules, variables)
|
13
|
+
@file, @rules, @variables = file, rules, variables
|
14
|
+
end
|
15
|
+
|
16
|
+
def dump
|
17
|
+
puts "File: #{file}"
|
18
|
+
puts "Variables"
|
19
|
+
indent { variables.each { |k,v| puts "#{k} = #{v.inspect}" } }
|
20
|
+
puts "Rules"
|
21
|
+
indent { rules.sort_by { |rule| rule.tables.first }.each(&:dump) }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class Rule
|
26
|
+
attr_accessor :tables
|
27
|
+
attr_accessor *Spec::OPERS
|
28
|
+
|
29
|
+
def initialize(tables)
|
30
|
+
@tables = tables
|
31
|
+
Spec::OPERS.each { |op| self[op] = Oper.new(op) }
|
32
|
+
end
|
33
|
+
|
34
|
+
def opers() = Spec::OPERS.map { |op| self.send(op) }.compact
|
35
|
+
def [](key) = self.send(key)
|
36
|
+
def []=(key, value) self.send(:"#{key}=", value) end
|
37
|
+
|
38
|
+
def to_s() = "Rule, tables: #{tables.join(', ')}"
|
39
|
+
|
40
|
+
def dump
|
41
|
+
puts "Rule"
|
42
|
+
indent {
|
43
|
+
puts "tables: #{tables}"
|
44
|
+
opers.each { |op| op.dump }
|
45
|
+
}
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class Oper
|
50
|
+
attr_reader :name
|
51
|
+
attr_accessor :accesses
|
52
|
+
|
53
|
+
def self.symbol = self.to_s.sub(/Decl/, "").downcase.to_sym
|
54
|
+
|
55
|
+
def initialize(name, accesses = [])
|
56
|
+
@name = name
|
57
|
+
@accesses = accesses
|
58
|
+
end
|
59
|
+
|
60
|
+
def dump
|
61
|
+
puts "#{name}"
|
62
|
+
indent { accesses.each(&:dump) }
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
class Access
|
67
|
+
attr_accessor *Spec::FIELDS
|
68
|
+
|
69
|
+
def initialize(roles, table, fields, where)
|
70
|
+
@roles = roles
|
71
|
+
@table = table
|
72
|
+
@fields = fields
|
73
|
+
@where = where
|
74
|
+
end
|
75
|
+
|
76
|
+
def dump
|
77
|
+
puts "access:"
|
78
|
+
indent {
|
79
|
+
Spec::FIELDS.each { |f|
|
80
|
+
value = self.send(f) or next
|
81
|
+
puts "#{f}: #{value}"
|
82
|
+
}
|
83
|
+
}
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
data/lib/mikras_utils/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mikras_utils
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Claus Rasmussen
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2025-01-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: pg_conn
|
@@ -72,6 +72,7 @@ email:
|
|
72
72
|
executables:
|
73
73
|
- mikras_utils
|
74
74
|
- mkacl
|
75
|
+
- rls
|
75
76
|
extensions: []
|
76
77
|
extra_rdoc_files: []
|
77
78
|
files:
|
@@ -84,7 +85,9 @@ files:
|
|
84
85
|
- build
|
85
86
|
- exe/mikras_utils
|
86
87
|
- exe/mkacl
|
88
|
+
- exe/rls
|
87
89
|
- lib/mikras_utils.rb
|
90
|
+
- lib/mikras_utils/mikras.rb
|
88
91
|
- lib/mikras_utils/mkacl.rb
|
89
92
|
- lib/mikras_utils/mkacl/analyzer.rb
|
90
93
|
- lib/mikras_utils/mkacl/generator.rb
|
@@ -93,8 +96,13 @@ files:
|
|
93
96
|
- lib/mikras_utils/mkacl/generators/insert_triggers.rb
|
94
97
|
- lib/mikras_utils/mkacl/generators/role_functions.rb
|
95
98
|
- lib/mikras_utils/mkacl/generators/rules.rb
|
99
|
+
- lib/mikras_utils/mkacl/generators/seeds.rb
|
96
100
|
- lib/mikras_utils/mkacl/parser.rb
|
101
|
+
- lib/mikras_utils/mkacl/simple_symtab.rb
|
97
102
|
- lib/mikras_utils/mkacl/spec.rb
|
103
|
+
- lib/mikras_utils/rls/analyzer.rb
|
104
|
+
- lib/mikras_utils/rls/parser.rb
|
105
|
+
- lib/mikras_utils/rls/spec.rb
|
98
106
|
- lib/mikras_utils/version.rb
|
99
107
|
- sig/mikras_utils.rbs
|
100
108
|
- tests/acl.fox
|