puppet_auditor 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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