Skip to content

Commit cd6d2b0

Browse files
authored
Merge pull request #21 from puppetlabs/CONT-234_fix_bug_in_get-title-tokens_function
(CONT-234) Fix bug in get-title-tokens function
2 parents 3e263e0 + 7352928 commit cd6d2b0

File tree

2 files changed

+97
-46
lines changed

2 files changed

+97
-46
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,22 @@
11
PuppetLint.new_check(:check_unsafe_interpolations) do
22
COMMANDS = Array['command', 'onlyif', 'unless']
3+
INTERPOLATED_STRINGS = Array[:DQPRE, :DQMID]
34
def check
45
# Gather any exec commands' resources into an array
56
exec_resources = resource_indexes.map { |resource|
67
resource_parameters = resource[:param_tokens].map(&:value)
78
resource if resource[:type].value == 'exec' && !(COMMANDS & resource_parameters).empty?
89
}.compact
910

10-
# Get title tokens with modified puppet lint function
11-
title_tokens_list = get_title_tokens
11+
# Filter the list of titles returned by get_title_tokens for those contained in an exec
12+
exec_title_tokens = get_title_tokens.select { |title|
13+
title if title[:resource_type].value == 'exec'
14+
}.compact
1215

1316
# Iterate over title tokens and raise a warning if any are variables
14-
title_tokens_list[:tokens].each do |token|
15-
if token.type == :VARIABLE
16-
notify_warning(token)
17+
unless exec_title_tokens.empty?
18+
exec_title_tokens.each do |title|
19+
check_unsafe_title(title)
1720
end
1821
end
1922

@@ -23,11 +26,18 @@ def check
2326
end
2427
end
2528

26-
# Iterates over tokens in a command and raises a warning if an interpolated variable is found
29+
# Iterate over the tokens in a title and raise a warning if an interpolated variable is found
30+
def check_unsafe_title(title)
31+
title[:tokens].each do |token|
32+
notify_warning(token.next_code_token) if interpolated?(token)
33+
end
34+
end
35+
36+
# Iterates over an exec resource and if a command, onlyif or unless paramter is found, it is checked for unsafe interpolations
2737
def check_unsafe_interpolations(command_resources)
2838
command_resources[:tokens].each do |token|
29-
# We are only interested in tokens from command onwards
30-
next unless token.type == :NAME
39+
# Skip iteration if token isn't a command of type :NAME
40+
next unless COMMANDS.include?(token.value) && token.type == :NAME
3141
# Don't check the command if it is parameterised
3242
next if parameterised?(token)
3343

@@ -54,9 +64,7 @@ def check_command(token)
5464
# Iterate through tokens in command
5565
while current_token.type != :NEWLINE
5666
# Check if token is a varibale and if it is parameterised
57-
if current_token.type == :VARIABLE
58-
rule_violations.append(current_token)
59-
end
67+
rule_violations.append(current_token.next_code_token) if interpolated?(current_token)
6068
current_token = current_token.next_token
6169
end
6270

@@ -76,45 +84,48 @@ def parameterised?(token)
7684
# This function is a replacement for puppet_lint's title_tokens function which assumes titles have single quotes
7785
# This function adds a check for titles in double quotes where there could be interpolated variables
7886
def get_title_tokens
79-
tokens_array = []
80-
result = {}
87+
result = []
8188
tokens.each_index do |token_idx|
82-
if tokens[token_idx].type == :COLON
83-
# Check if title is an array
84-
if tokens[token_idx - 1].type == :RBRACK
85-
array_start_idx = tokens.rindex do |r|
86-
r.type == :LBRACK
87-
end
88-
title_array_tokens = tokens[(array_start_idx + 1)..(token_idx - 2)]
89-
tokens_array.concat(title_array_tokens.select do |token|
90-
{ STRING: true, NAME: true }.include?(token.type)
91-
end)
92-
result = {
93-
tokens: tokens_array,
94-
resource_type: tokens[array_start_idx].prev_code_token.prev_code_token
95-
}
96-
# Check if title is double quotes string
97-
elsif tokens[token_idx - 1].type == :DQPOST
98-
# Find index of the start of the title
99-
title_start_idx = tokens.rindex do |r|
100-
r.type == :DQPRE
101-
end
102-
result = {
103-
# Title is tokens from :DQPRE to the index before :COLON
104-
tokens: tokens[title_start_idx..(token_idx - 1)],
105-
resource_type: tokens[title_start_idx].prev_code_token.prev_code_token
106-
}
107-
# Title is in single quotes
108-
else
109-
next_token = tokens[token_idx].next_code_token
110-
tokens_array.concat(tokens[..token_idx - 1]) unless next_token.type == :LBRACE
111-
result = {
112-
tokens: tokens_array,
113-
resource_type: tokens[token_idx - 1].prev_code_token.prev_code_token
114-
}
89+
next unless tokens[token_idx].type == :COLON
90+
tokens_array = []
91+
# Check if title is an array
92+
if tokens[token_idx - 1].type == :RBRACK
93+
array_start_idx = tokens.rindex do |r|
94+
r.type == :LBRACK
95+
end
96+
title_array_tokens = tokens[(array_start_idx + 1)..(token_idx - 2)]
97+
tokens_array.concat(title_array_tokens.select do |token|
98+
{ STRING: true, NAME: true }.include?(token.type)
99+
end)
100+
result << {
101+
tokens: tokens_array,
102+
resource_type: tokens[array_start_idx].prev_code_token.prev_code_token
103+
}
104+
# Check if title is double quotes string
105+
elsif tokens[token_idx - 1].type == :DQPOST
106+
# Find index of the start of the title
107+
title_start_idx = tokens.rindex do |r|
108+
r.type == :DQPRE
115109
end
110+
result << {
111+
# Title is tokens from :DQPRE to the index before :COLON
112+
tokens: tokens[title_start_idx..(token_idx - 1)],
113+
resource_type: tokens[title_start_idx].prev_code_token.prev_code_token
114+
}
115+
# Title is in single quotes
116+
else
117+
next_token = tokens[token_idx].next_code_token
118+
tokens_array.concat([tokens[token_idx - 1]]) unless next_token.type == :LBRACE
119+
result << {
120+
tokens: tokens_array,
121+
resource_type: tokens[token_idx - 1].prev_code_token.prev_code_token
122+
}
116123
end
117124
end
118125
result
119126
end
127+
128+
def interpolated?(token)
129+
INTERPOLATED_STRINGS.include?(token.type)
130+
end
120131
end

spec/puppet-lint/plugins/check_unsafe_interpolations_spec.rb

+40
Original file line numberDiff line numberDiff line change
@@ -120,5 +120,45 @@ class foo {
120120
expect(problems).to have(0).problems
121121
end
122122
end
123+
124+
context 'file resource' do
125+
let(:code) do
126+
<<-PUPPET
127+
class foo {
128+
file { '/etc/bar':
129+
ensure => file,
130+
backup => false,
131+
content => $baz,
132+
}
133+
}
134+
PUPPET
135+
end
136+
137+
it 'detects zero problems' do
138+
expect(problems).to have(0).problems
139+
end
140+
end
141+
142+
context 'file resource and an exec with unsafe interpolation in command' do
143+
let(:code) do
144+
<<-PUPPET
145+
class foo {
146+
file { '/etc/bar':
147+
ensure => file,
148+
backup => false,
149+
content => $baz,
150+
}
151+
152+
exec { 'qux':
153+
command => "echo ${foo}",
154+
}
155+
}
156+
PUPPET
157+
end
158+
159+
it 'detects one problem' do
160+
expect(problems).to have(1).problems
161+
end
162+
end
123163
end
124164
end

0 commit comments

Comments
 (0)