@@ -22,10 +22,10 @@ def check
2222 end
2323 end
2424
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
2626 def check_unsafe_title ( title )
2727 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 )
2929 end
3030 end
3131
@@ -60,7 +60,7 @@ def check_command(token)
6060 # Iterate through tokens in command
6161 while current_token . type != :NEWLINE
6262 # 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 )
6464 current_token = current_token . next_token
6565 end
6666
@@ -78,7 +78,7 @@ def parameterised?(token)
7878 end
7979
8080 # 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
8282 def get_exec_titles
8383 result = [ ]
8484 tokens . each_index do |token_idx |
@@ -114,8 +114,52 @@ def get_exec_titles
114114 result
115115 end
116116
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
119163 end
120164
121165 # Finds the index offset of the next instance of `value` in `tokens_slice` from the original index
0 commit comments