puppet_auditor 0.1.0 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9f19c4e65cec6c68311283a645f82a70c5972713a8914998f90980c72ac46d9e
4
- data.tar.gz: 2fcfd26e374196b17aae75102910375efa8f32b25672d2d5de2d4f12effce9e9
3
+ metadata.gz: 84f7e5cffe4df624ca9e10438b1d30199fc56560c954a0eab2bb166b8cc46cf7
4
+ data.tar.gz: be50f8f05976de06718e2285de06ab04d0af18856b6aceb3be42bf7125392aa0
5
5
  SHA512:
6
- metadata.gz: 68f90d008056423702b399e106c75518ffe4e5b44f209a708239f557cc460665a96f7bc4fe4d5efce1b0e7368ef1818a6a4a806d7401e7eb6bf2f4d87bdb74dc
7
- data.tar.gz: '08c51f70e10d0c21edf941cbb9a9414b0c73e7e8367fdf3f35e18897b25b07550e481243a724334b172e91a0cac12e7ccf48fe2f9765bba925ccd63814b7495e'
6
+ metadata.gz: 7f0c3058f2a7765dd714e1ed28a45c77d755eb8494771d55f5d46749a29fd072b891d9a28bc2a5d627a4fec47942bfd8b41282d704e4e67a155f17e02d76188f
7
+ data.tar.gz: 523be5ff715b774b387eb99b786608da7fe952d83a6d9a454db8c8a96057c738c79d5fbd904011ac3328d0c064092ba95c12bf30b446ab00f87b07ccc04c263c
data/Gemfile.lock CHANGED
@@ -1,21 +1,28 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- puppet_auditor (0.1.0)
4
+ puppet_auditor (0.2.0)
5
+ puppet (~> 5.5)
5
6
  puppet-lint (>= 1.1, < 3.0)
6
7
 
7
8
  GEM
8
9
  remote: https://rubygems.org/
9
10
  specs:
10
- coderay (1.1.2)
11
11
  diff-lcs (1.3)
12
12
  docile (1.3.0)
13
+ facter (2.5.1)
14
+ fast_gettext (1.1.2)
15
+ hiera (3.4.4)
13
16
  json (2.1.0)
14
- method_source (0.9.0)
15
- pry (0.11.3)
16
- coderay (~> 1.1.0)
17
- method_source (~> 0.9.0)
18
- puppet-lint (2.3.5)
17
+ locale (2.1.2)
18
+ multi_json (1.13.1)
19
+ puppet (5.5.6)
20
+ facter (> 2.0.1, < 4)
21
+ fast_gettext (~> 1.1.2)
22
+ hiera (>= 3.2.1, < 4)
23
+ locale (~> 2.1)
24
+ multi_json (~> 1.10)
25
+ puppet-lint (2.3.6)
19
26
  rake (10.5.0)
20
27
  rspec (3.7.0)
21
28
  rspec-core (~> 3.7.0)
@@ -46,7 +53,6 @@ PLATFORMS
46
53
 
47
54
  DEPENDENCIES
48
55
  bundler (~> 1.16)
49
- pry
50
56
  puppet_auditor!
51
57
  rake (~> 10.0)
52
58
  rspec (~> 3.0)
data/README.md CHANGED
@@ -1,3 +1,6 @@
1
+ [![Build Status](https://travis-ci.org/instruct-br/puppet_auditor.svg?branch=master)](https://travis-ci.org/instruct-br/puppet_auditor)
2
+ [![Gem Version](https://badge.fury.io/rb/puppet_auditor.svg)](https://badge.fury.io/rb/puppet_auditor)
3
+
1
4
  # PuppetAuditor
2
5
 
3
6
  PuppetAuditor is a tool to test Puppet manifests against a set of defined rules.
@@ -1,7 +1,15 @@
1
1
  module PuppetAuditor
2
2
  class Cli
3
+
4
+ @@path = ''
5
+
6
+ def self.path
7
+ @@path
8
+ end
9
+
3
10
  def initialize(args)
4
11
  @checks = []
12
+
5
13
  OptionParser.new do |opts|
6
14
  opts.banner = "Usage: puppet_auditor [options]"
7
15
 
@@ -30,6 +38,9 @@ module PuppetAuditor
30
38
  load_checks('~/.puppet_auditor.yaml') if user_default && ENV.key?('HOME')
31
39
  load_checks('.puppet_auditor.yaml') if project_default
32
40
  load_checks(specific_yaml_rules) if specific_yaml_rules
41
+
42
+ @@path = File.expand_path('.')
43
+
33
44
  end.parse!
34
45
  end
35
46
 
@@ -1,3 +1,5 @@
1
+ require 'puppet'
2
+
1
3
  module PuppetAuditor
2
4
  class LintPlugin < PuppetLint::CheckPlugin
3
5
 
@@ -14,17 +16,112 @@ module PuppetAuditor
14
16
 
15
17
  def initialize
16
18
  super
17
- @resource = self.class::RESOURCE
18
- @attributes = self.class::ATTRIBUTES
19
- @message = self.class::MESSAGE
19
+ @resource = self.class::RESOURCE
20
+ @attributes = self.class::ATTRIBUTES
21
+ @message = self.class::MESSAGE
22
+ @scoped_variables = { 'global' => {} }
23
+ @scopes = {}
20
24
  end
21
25
 
22
26
  def check
27
+ discover_scopes
28
+ build_scope
29
+ scan_variables
23
30
  resource_indexes.each { |resource| resource_block(resource) if resource[:type].value == @resource }
24
31
  end
25
32
 
26
33
  private
27
34
 
35
+ def build_scope
36
+ Puppet.settings[:hiera_config] = File.join(PuppetAuditor::Cli.path, 'hiera.yaml')
37
+
38
+ env = Puppet::Node::Environment.create(:_p_auditor, [])
39
+ node = Puppet::Node.new('localhost', environment: env)
40
+ Puppet.push_context({environments: Puppet::Environments::Static.new(env)})
41
+ compiler = Puppet::Parser::Compiler.new(node)
42
+ @scope = compiler.topscope
43
+ end
44
+
45
+ def lookup(key)
46
+ Puppet::Pops::Lookup.lookup(key, nil, nil, false, :default, Puppet::Pops::Lookup::Invocation.new(@scope, {}, {}))
47
+ end
48
+
49
+ def class_scopes
50
+ class_indexes.each do |class_hash|
51
+ class_name = class_hash[:tokens].first.next_code_token
52
+ # class name { -> :NAME
53
+ # (...)
54
+ # }
55
+ #
56
+ # class name( -> :FUNCTION_NAME
57
+ # Type $parameter = 'default',
58
+ # ) {
59
+ # (...)
60
+ # }
61
+ if class_name.type == :NAME || class_name.type == :FUNCTION_NAME
62
+ @scopes["class_#{class_name.value}"] = [class_hash[:start], class_hash[:end]]
63
+ @scoped_variables["class_#{class_name.value}"] = {}
64
+ end
65
+ end
66
+ end
67
+
68
+ def defined_type_scopes
69
+ defined_type_indexes.each do |defined_type_hash|
70
+ defined_type_name = defined_type_hash[:tokens].first.next_code_token
71
+ if defined_type_name.type == :NAME
72
+ @scopes["dtype_#{defined_type_name.value}"] = [defined_type_hash[:start], defined_type_hash[:end]]
73
+ @scoped_variables["dtype_#{defined_type_name.value}"] = {}
74
+ end
75
+ end
76
+ end
77
+
78
+ def node_scopes
79
+ node_indexes.each do |node_hash|
80
+ node_name = node_hash[:tokens].first.next_code_token
81
+ if node_name.type == :SSTRING
82
+ @scopes["node_#{node_name.value}"] = [node_hash[:start], node_hash[:end]]
83
+ @scoped_variables["node_#{node_name.value}"] = {}
84
+ end
85
+ end
86
+ end
87
+
88
+ def scope(index)
89
+ @scopes.sort_by { |name, range|
90
+ if name.start_with?('class')
91
+ 0
92
+ elsif name.start_with?('dtype')
93
+ 1
94
+ elsif name.start_with?('node')
95
+ 2
96
+ else
97
+ 3
98
+ end
99
+ }.find(-> { ['global'] }) { |name, range| index.between?(*range) }.first
100
+ end
101
+
102
+ def token_index(unknown)
103
+ tokens.find_index { |indexed| indexed.line == unknown.line && indexed.column == unknown.column }
104
+ end
105
+
106
+ def discover_scopes
107
+ class_scopes
108
+ defined_type_scopes
109
+ node_scopes
110
+ end
111
+
112
+ def scan_variables
113
+ # This method works because:
114
+ # - "variable assignments are evaluation-order dependent"
115
+ # - "Unlike most other languages, Puppet only allows a given variable to be assigned once within a given scope"
116
+ #
117
+ # See: https://puppet.com/docs/puppet/5.5/lang_variables.html
118
+ tokens.each_with_index do |token, index|
119
+ if token.type == :VARIABLE && token.next_code_token.type == :EQUALS
120
+ @scoped_variables[scope(index)][token.value] = cast_token(token.next_code_token.next_code_token)
121
+ end
122
+ end
123
+ end
124
+
28
125
  def resource_block(resource)
29
126
  @attributes.each do |attribute_name, comparison_rules|
30
127
  attribute = resource[:tokens].find { |t| t.type == :NAME && t.value == attribute_name && t.next_code_token.type == :FARROW }
@@ -63,12 +160,27 @@ module PuppetAuditor
63
160
  while next_token.type != :DQPOST
64
161
  next_token = next_token.next_code_token
65
162
  if next_token.type == :VARIABLE
66
- full_str += "${#{next_token.value}}"
163
+ full_str += cast_token(next_token) || "${#{next_token.value}}"
67
164
  else
68
165
  full_str += next_token.value
69
166
  end
70
167
  end
71
168
  full_str
169
+ when :VARIABLE
170
+ @scoped_variables[scope(token_index(token))][token.value]
171
+ when :NAME, :FUNCTION_NAME
172
+ if token.value == 'hiera' || token.value == 'lookup'
173
+ next_token = token
174
+ while next_token.type != :SSTRING && next_token.type != :RPAREN
175
+ next_token = next_token.next_code_token
176
+ if next_token.type == :SSTRING
177
+ return lookup(next_token.value)
178
+ elsif next_token.type == :NAME || next_token.type == :FUNCTION_NAME
179
+ return lookup(cast_token(next_token))
180
+ end
181
+ end
182
+ end
183
+ token.value
72
184
  else
73
185
  token.value
74
186
  end
@@ -1,3 +1,3 @@
1
1
  module PuppetAuditor
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -26,6 +26,7 @@ Gem::Specification.new do |spec|
26
26
  spec.require_paths = ["lib"]
27
27
 
28
28
  spec.add_dependency 'puppet-lint', '>= 1.1', '< 3.0'
29
+ spec.add_dependency 'puppet', '~> 5.5'
29
30
 
30
31
  spec.add_development_dependency "bundler", "~> 1.16"
31
32
  spec.add_development_dependency "rake", "~> 10.0"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: puppet_auditor
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Oscar Esgalha
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-04-26 00:00:00.000000000 Z
11
+ date: 2018-08-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: puppet-lint
@@ -30,6 +30,20 @@ dependencies:
30
30
  - - "<"
31
31
  - !ruby/object:Gem::Version
32
32
  version: '3.0'
33
+ - !ruby/object:Gem::Dependency
34
+ name: puppet
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '5.5'
40
+ type: :runtime
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '5.5'
33
47
  - !ruby/object:Gem::Dependency
34
48
  name: bundler
35
49
  requirement: !ruby/object:Gem::Requirement