Skip to content

Commit 6f25969

Browse files
committed
(MODULES-4976) Add windows escaping functions
The shell_escape function is not usable on windows where batch files and powershell scripts use different escape rules. Add two functions to escape strings on windots for batch (batch_escape) and powershell (powershell_escape).
1 parent 934328e commit 6f25969

File tree

4 files changed

+124
-0
lines changed

4 files changed

+124
-0
lines changed
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# frozen_string_literal: true
2+
3+
#
4+
# batch_escape.rb
5+
#
6+
module Puppet::Parser::Functions
7+
newfunction(:batch_escape, type: :rvalue, doc: <<-DOC
8+
@summary
9+
Escapes a string so that it can be safely used in a batch shell command line.
10+
11+
@return
12+
A string of characters with special characters converted to their escaped form.
13+
14+
>* Note:* that the resulting string should be used unquoted and is not intended for use in double quotes nor in single
15+
quotes.
16+
DOC
17+
) do |arguments|
18+
raise(Puppet::ParseError, "batch_escape(): Wrong number of arguments given (#{arguments.size} for 1)") if arguments.size != 1
19+
20+
string = arguments[0].to_s
21+
22+
result = ''
23+
24+
string.chars.each do |char|
25+
result += case char
26+
when '"' then '""'
27+
when '$', '\\' then "\\#{char}"
28+
else char
29+
end
30+
end
31+
32+
return %("#{result}")
33+
end
34+
end
35+
36+
# vim: set ts=2 sw=2 et :
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# frozen_string_literal: true
2+
3+
#
4+
# powershell_escape.rb
5+
#
6+
module Puppet::Parser::Functions
7+
newfunction(:powershell_escape, type: :rvalue, doc: <<-DOC
8+
@summary
9+
Escapes a string so that it can be safely used in a PowerShell command line.
10+
11+
@return
12+
A string of characters with special characters converted to their escaped form.
13+
14+
>* Note:* that the resulting string should be used unquoted and is not intended for use in double quotes nor in single
15+
quotes.
16+
DOC
17+
) do |arguments|
18+
raise(Puppet::ParseError, "shell_escape(): Wrong number of arguments given (#{arguments.size} for 1)") if arguments.size != 1
19+
20+
string = arguments[0].to_s
21+
22+
result = ''
23+
24+
string.chars.each do |char|
25+
result += case char
26+
when ' ', "'", '`', '|', "\n", '$' then "`#{char}"
27+
when '"' then '\`"'
28+
else char
29+
end
30+
end
31+
32+
return result
33+
end
34+
end
35+
36+
# vim: set ts=2 sw=2 et :

spec/functions/batch_escape_spec.rb

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# frozen_string_literal: true
2+
3+
require 'spec_helper'
4+
5+
describe 'batch_escape' do
6+
it { is_expected.not_to eq(nil) }
7+
8+
describe 'signature validation' do
9+
it { is_expected.to run.with_params.and_raise_error(Puppet::ParseError, %r{wrong number of arguments}i) }
10+
it { is_expected.to run.with_params('foo', 'bar').and_raise_error(Puppet::ParseError, %r{wrong number of arguments}i) }
11+
end
12+
13+
describe 'stringification' do
14+
it { is_expected.to run.with_params(10).and_return('"10"') }
15+
it { is_expected.to run.with_params(false).and_return('"false"') }
16+
end
17+
18+
describe 'escaping' do
19+
it { is_expected.to run.with_params('foo').and_return('"foo"') }
20+
it { is_expected.to run.with_params('foo bar').and_return('"foo bar"') }
21+
it {
22+
is_expected.to run.with_params('~`!@#$%^&*()_-=[]\{}|;\':",./<>?')
23+
.and_return('"~`!@#\\$%^&*()_-=[]\\\{}|;\':"",./<>?"')
24+
}
25+
end
26+
end
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# frozen_string_literal: true
2+
3+
require 'spec_helper'
4+
5+
describe 'powershell_escape' do
6+
it { is_expected.not_to eq(nil) }
7+
8+
describe 'signature validation' do
9+
it { is_expected.to run.with_params.and_raise_error(Puppet::ParseError, %r{wrong number of arguments}i) }
10+
it { is_expected.to run.with_params('foo', 'bar').and_raise_error(Puppet::ParseError, %r{wrong number of arguments}i) }
11+
end
12+
13+
describe 'stringification' do
14+
it { is_expected.to run.with_params(10).and_return('10') }
15+
it { is_expected.to run.with_params(false).and_return('false') }
16+
end
17+
18+
describe 'escaping' do
19+
it { is_expected.to run.with_params('foo').and_return('foo') }
20+
it { is_expected.to run.with_params('foo bar').and_return('foo` bar') }
21+
it {
22+
is_expected.to run.with_params('~`!@#$%^&*()_-=[]\{}|;\':",./<>?')
23+
.and_return('~``!@#`$%^&*()_-=[]\{}`|;`\':\\`",./<>?')
24+
}
25+
end
26+
end

0 commit comments

Comments
 (0)