puppet-lint-check_unsafe_interpolations 0.0.4 → 0.0.5

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: 7030c967d7f3f39c1829abe1d620bd93c22e556e0ff9238e2197ef65c3faba27
4
- data.tar.gz: 6b7397d25a2e92fee44bae25c3b3386b66468d7adf7c6c51f1a3044ae8db00ea
3
+ metadata.gz: 06bfbbbb77295091db599b90f1f6052b98b96e5b3d0d5ab3dc77526527739d56
4
+ data.tar.gz: e5861ad1c3ce71eef31c619fe6ec00f4edbd58df53741ec9c6e302516276d1bc
5
5
  SHA512:
6
- metadata.gz: c91e94e645dae141e93b74324f16c88a4ede801d56e1f501e994500d99ebc4ae418f9c25107c081d513ca23db3040455de97915f7c753bb00ae1481419fd6493
7
- data.tar.gz: 93f689e32e264b4aa107a9986d1f17692bd55ec34863263f73cdc642b02d6eff894cedd10bbf8dbf554ca66b1b2e0a636ae1bbb047bbb22dc56ffa799f5bf7f7
6
+ metadata.gz: 3fff01f49a697082783b3ea9b6eab8fe92c26e10ddbe8c981eaac0dce1d733166903201f8f7ee438401453fd0096e2c571d5dabd9a5da12163d6a08cec5c306c
7
+ data.tar.gz: 0fe2a37dda1149d9396371c0eff81048845253cbb94b7badfd91c25c0496b5e10a3240a653b5fe494cba74a16002569b7df6292f936b7f34c8b1bebb240d0ecc
@@ -22,10 +22,10 @@ PuppetLint.new_check(:check_unsafe_interpolations) do
22
22
  end
23
23
  end
24
24
 
25
- # Iterate over the tokens in a title and raise a warning if an interpolated variable is found
25
+ # Iterate over the tokens in a title and raise a warning if an unsafe interpolated variable is found
26
26
  def check_unsafe_title(title)
27
27
  title.each do |token|
28
- notify_warning(token.next_code_token) if interpolated?(token)
28
+ notify_warning(token.next_code_token) if unsafe_interpolated?(token)
29
29
  end
30
30
  end
31
31
 
@@ -33,7 +33,7 @@ PuppetLint.new_check(:check_unsafe_interpolations) do
33
33
  def check_unsafe_interpolations(command_resources)
34
34
  command_resources[:tokens].each do |token|
35
35
  # Skip iteration if token isn't a command of type :NAME
36
- next unless COMMANDS.include?(token.value) && token.type == :NAME
36
+ next unless COMMANDS.include?(token.value) && (token.type == :NAME || token.type == :UNLESS)
37
37
  # Don't check the command if it is parameterised
38
38
  next if parameterised?(token)
39
39
 
@@ -60,7 +60,7 @@ PuppetLint.new_check(:check_unsafe_interpolations) do
60
60
  # Iterate through tokens in command
61
61
  while current_token.type != :NEWLINE
62
62
  # Check if token is a varibale and if it is parameterised
63
- rule_violations.append(current_token.next_code_token) if interpolated?(current_token)
63
+ rule_violations.append(current_token.next_code_token) if unsafe_interpolated?(current_token)
64
64
  current_token = current_token.next_token
65
65
  end
66
66
 
@@ -78,7 +78,7 @@ PuppetLint.new_check(:check_unsafe_interpolations) do
78
78
  end
79
79
 
80
80
  # This function is a replacement for puppet_lint's title_tokens function which assumes titles have single quotes
81
- # This function adds a check for titles in double quotes where there could be interpolated variables
81
+ # This function adds a check for titles in double quotes where there could be unsafe interpolated variables
82
82
  def get_exec_titles
83
83
  result = []
84
84
  tokens.each_index do |token_idx|
@@ -100,8 +100,8 @@ PuppetLint.new_check(:check_unsafe_interpolations) do
100
100
  # Check if title is double quotes string
101
101
  elsif tokens[token_idx].next_code_token.next_code_token.type == :DQPRE
102
102
  # Find the start and end of the title
103
- title_start_idx = tokens.rindex { |r| r.type == :DQPRE }
104
- title_end_idx = tokens.rindex { |r| r.type == :DQPOST }
103
+ title_start_idx = tokens.find_index(tokens[token_idx].next_code_token.next_code_token)
104
+ title_end_idx = title_start_idx + index_offset_for(':', tokens[title_start_idx..tokens.length])
105
105
 
106
106
  result << tokens[title_start_idx..title_end_idx]
107
107
  # Title is in single quotes
@@ -114,7 +114,60 @@ PuppetLint.new_check(:check_unsafe_interpolations) do
114
114
  result
115
115
  end
116
116
 
117
- def interpolated?(token)
118
- INTERPOLATED_STRINGS.include?(token.type)
117
+ def find_closing_brack(token)
118
+ while (token = token.next_code_token)
119
+ case token.type
120
+ when :RBRACK
121
+ return token
122
+ when :LBRACK
123
+ token = find_closing_brack(token)
124
+ end
125
+ end
126
+ raise 'not reached'
127
+ end
128
+
129
+ def find_closing_paren(token)
130
+ while (token = token.next_code_token)
131
+ case token.type
132
+ when :RPAREN
133
+ return token
134
+ when :LPAREN
135
+ token = find_closing_paren(token)
136
+ end
137
+ end
138
+ raise 'not reached'
139
+ end
140
+
141
+ def unsafe_interpolated?(token)
142
+ # XXX: Since stdlib 9.0.0 'shell_escape' is deprecated in favor or 'stdlib::shell_escape'
143
+ # When the shell_escape function is removed from stdlib, we want to remove it bellow.
144
+ return false unless INTERPOLATED_STRINGS.include?(token.type)
145
+
146
+ token = token.next_code_token
147
+
148
+ if token.type == :FUNCTION_NAME && ['shell_escape', 'stdlib::shell_escape'].include?(token.value)
149
+ token = token.next_code_token
150
+ token = find_closing_paren(token).next_code_token if token.type == :LPAREN
151
+ return ![:DQPOST, :DQMID].include?(token.type)
152
+ elsif token.type == :VARIABLE
153
+ token = token.next_code_token
154
+ token = find_closing_brack(token).next_code_token if token.type == :LBRACK
155
+ if token.type == :DOT && [:NAME, :FUNCTION_NAME].include?(token.next_code_token.type) && ['shell_escape', 'stdlib::shell_escape'].include?(token.next_code_token.value)
156
+ token = token.next_code_token.next_code_token
157
+ token = find_closing_paren(token).next_code_token if token.type == :LPAREN
158
+ return ![:DQPOST, :DQMID].include?(token.type)
159
+ end
160
+ end
161
+
162
+ true
163
+ end
164
+
165
+ # Finds the index offset of the next instance of `value` in `tokens_slice` from the original index
166
+ def index_offset_for(value, tokens_slice)
167
+ i = 0
168
+ while i < tokens_slice.length
169
+ return i if value.include?(tokens_slice[i].value)
170
+ i += 1
171
+ end
119
172
  end
120
173
  end
@@ -1,4 +1,4 @@
1
1
  # version of this gem
2
2
  class CheckUnsafeInterpolations
3
- VERSION ||= '0.0.4'.freeze
3
+ VERSION ||= '0.0.5'.freeze
4
4
  end
@@ -33,6 +33,8 @@ describe 'check_unsafe_interpolations' do
33
33
 
34
34
  exec { 'bar':
35
35
  command => "echo ${foo} ${bar}",
36
+ onlyif => "${baz}",
37
+ unless => "${bazz}",
36
38
  }
37
39
 
38
40
  }
@@ -40,12 +42,14 @@ describe 'check_unsafe_interpolations' do
40
42
  end
41
43
 
42
44
  it 'detects multiple unsafe exec command arguments' do
43
- expect(problems).to have(2).problems
45
+ expect(problems).to have(4).problems
44
46
  end
45
47
 
46
48
  it 'creates two warnings' do
47
49
  expect(problems).to contain_warning(msg)
48
- expect(problems).to contain_warning(msg)
50
+ expect(problems).to contain_warning("unsafe interpolation of variable 'bar' in exec command")
51
+ expect(problems).to contain_warning("unsafe interpolation of variable 'baz' in exec command")
52
+ expect(problems).to contain_warning("unsafe interpolation of variable 'bazz' in exec command")
49
53
  end
50
54
  end
51
55
 
@@ -87,6 +91,44 @@ describe 'check_unsafe_interpolations' do
87
91
  end
88
92
  end
89
93
 
94
+ context 'exec with shell escaped string in command' do
95
+ let(:code) do
96
+ <<-PUPPET
97
+ class foo {
98
+
99
+ exec { 'bar':
100
+ command => "echo ${foo.stdlib::shell_escape} ${bar.stdlib::shell_escape()}",
101
+ onlyif => "${bar[1].stdlib::shell_escape}",
102
+ unless => "[ -x ${stdlib::shell_escape(reticulate($baz))} ]",
103
+ }
104
+ }
105
+ PUPPET
106
+ end
107
+
108
+ it 'detects zero problems' do
109
+ expect(problems).to have(0).problems
110
+ end
111
+ end
112
+
113
+ context 'exec with post-processed shell escaped string in command' do
114
+ let(:code) do
115
+ <<-PUPPET
116
+ class foo {
117
+
118
+ exec { 'bar':
119
+ command => "echo ${reticulate(foo.stdlib::shell_escape)} ${bar.stdlib::shell_escape().reticulate}",
120
+ onlyif => "${bar[1].stdlib::shell_escape.reticulate()}",
121
+ unless => "[ -x ${reticulate(stdlib::shell_escape($baz))} ]",
122
+ }
123
+ }
124
+ PUPPET
125
+ end
126
+
127
+ it 'detects zero problems' do
128
+ expect(problems).to have(4).problems
129
+ end
130
+ end
131
+
90
132
  context 'exec that has an array of args in command' do
91
133
  let(:code) do
92
134
  <<-PUPPET
data/spec/spec_helper.rb CHANGED
@@ -1,3 +1,4 @@
1
1
  require 'puppet-lint'
2
+ require 'rspec/collection_matchers'
2
3
 
3
4
  PuppetLint::Plugins.load_spec_helper
metadata CHANGED
@@ -1,35 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: puppet-lint-check_unsafe_interpolations
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Puppet, Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-12-12 00:00:00.000000000 Z
11
+ date: 2024-05-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: puppet-lint
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">="
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.0'
20
- - - "<"
21
- - !ruby/object:Gem::Version
22
- version: '4'
19
+ version: '4.0'
23
20
  type: :runtime
24
21
  prerelease: false
25
22
  version_requirements: !ruby/object:Gem::Requirement
26
23
  requirements:
27
- - - ">="
28
- - !ruby/object:Gem::Version
29
- version: '1.0'
30
- - - "<"
24
+ - - "~>"
31
25
  - !ruby/object:Gem::Version
32
- version: '4'
26
+ version: '4.0'
33
27
  description: " A puppet-lint plugin to check for unsafe interpolations.\n"
34
28
  email:
35
29
  executables: []