Skip to content

Commit 088cb33

Browse files
authored
Merge pull request #869 from puppetlabs/GH-811-reimplement_reverted_PR
docker_run_flags: Shellescape any provided values
2 parents ba2c378 + 3f09d92 commit 088cb33

File tree

4 files changed

+59
-16
lines changed

4 files changed

+59
-16
lines changed

lib/puppet/parser/functions/docker_run_flags.rb

+19-8
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,32 @@
11
# frozen_string_literal: true
22

3-
require 'shellwords'
43
#
54
# docker_run_flags.rb
65
#
76
module Puppet::Parser::Functions
7+
newfunction(:'docker::escape', type: :rvalue) do |args|
8+
subject = args[0]
9+
10+
escape_function = if self['facts'] && self['facts']['os']['family'] == 'windows'
11+
'powershell_escape'
12+
else
13+
'shell_escape'
14+
end
15+
16+
call_function(escape_function, subject)
17+
end
18+
819
# Transforms a hash into a string of docker flags
920
newfunction(:docker_run_flags, type: :rvalue) do |args|
1021
opts = args[0] || {}
1122
flags = []
1223

1324
if opts['username']
14-
flags << "-u '#{opts['username'].shellescape}'"
25+
flags << "-u #{call_function('docker::escape', [opts['username']])}"
1526
end
1627

1728
if opts['hostname']
18-
flags << "-h '#{opts['hostname'].shellescape}'"
29+
flags << "-h #{call_function('docker::escape', [opts['hostname']])}"
1930
end
2031

2132
if opts['restart']
@@ -24,9 +35,9 @@ module Puppet::Parser::Functions
2435

2536
if opts['net']
2637
if opts['net'].is_a? String
27-
flags << "--net #{opts['net'].shellescape}"
38+
flags << "--net #{call_function('docker::escape', [opts['net']])}"
2839
elsif opts['net'].is_a? Array
29-
flags << "--net #{opts['net'].join(' --net ').shellescape}"
40+
flags += opts['net'].map { |item| ["--net #{call_function('docker::escape', [item])}"] }
3041
end
3142
end
3243

@@ -72,17 +83,17 @@ module Puppet::Parser::Functions
7283

7384
multi_flags = ->(values, fmt) {
7485
filtered = [values].flatten.compact
75-
filtered.map { |val| (fmt + params_join_char) % val }
86+
filtered.map { |val| (fmt + params_join_char) % call_function('docker::escape', [val]) }
7687
}
7788

7889
[
7990
['--dns %s', 'dns'],
8091
['--dns-search %s', 'dns_search'],
8192
['--expose=%s', 'expose'],
8293
['--link %s', 'links'],
83-
['--lxc-conf="%s"', 'lxc_conf'],
94+
['--lxc-conf=%s', 'lxc_conf'],
8495
['--volumes-from %s', 'volumes_from'],
85-
['-e "%s"', 'env'],
96+
['-e %s', 'env'],
8697
['--env-file %s', 'env_file'],
8798
['-p %s', 'ports'],
8899
['-l %s', 'labels'],

metadata.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
"dependencies": [
1111
{
1212
"name": "puppetlabs/stdlib",
13-
"version_requirement": ">= 4.24.0 < 9.0.0"
13+
"version_requirement": ">= 8.2.0 < 9.0.0"
1414
},
1515
{
1616
"name": "puppetlabs/apt",

spec/acceptance/docker_params_changed_spec.rb

+7-7
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
else
2424
docker_args = ''
2525
docker_network = 'bridge'
26-
volume_location = '/opt'
26+
volume_location = '/opt/'
2727
docker_image = 'hello-world:linux'
2828
end
2929

@@ -33,8 +33,8 @@
3333
install_pp = "class { 'docker': #{docker_args}}"
3434
apply_manifest(install_pp)
3535
end
36-
run_shell("mkdir #{volume_location}/volume_1")
37-
run_shell("mkdir #{volume_location}/volume_2")
36+
run_shell("mkdir #{volume_location}volume_1")
37+
run_shell("mkdir #{volume_location}volume_2")
3838
end
3939

4040
context 'when image is changed' do
@@ -78,8 +78,8 @@ class {'docker': #{docker_args}}
7878
volumes1 = "volumes => ['volume-1:C:\\volume_1']"
7979
volumes2 = "volumes => ['volume-1:C:\\volume_1', 'volume-2:C:\\volume_2']"
8080
else
81-
volumes1 = "volumes => ['volume-1:#{volume_location}/volume_1']"
82-
volumes2 = "volumes => ['volume-1:#{volume_location}/volume_1', 'volume-2:#{volume_location}/volume_2']"
81+
volumes1 = "volumes => ['volume-1:#{volume_location}volume_1']"
82+
volumes2 = "volumes => ['volume-1:#{volume_location}volume_1', 'volume-2:#{volume_location}volume_2']"
8383
end
8484

8585
let(:pp1) do
@@ -143,7 +143,7 @@ class {'docker': #{docker_args}}
143143
end
144144

145145
after(:all) do
146-
run_shell("rm -r #{volume_location}/volume_1")
147-
run_shell("rm -r #{volume_location}/volume_2")
146+
run_shell("rm -r #{volume_location}volume_1")
147+
run_shell("rm -r #{volume_location}volume_2")
148148
end
149149
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
require 'spec_helper'
2+
3+
describe 'the "docker_run_flags" parser function' do
4+
before :each do
5+
Puppet[:modulepath] = 'spec/fixtures/modules'
6+
end
7+
8+
let :scope do
9+
node = Puppet::Node.new('localhost')
10+
compiler = Puppet::Parser::Compiler.new(node)
11+
scope = Puppet::Parser::Scope.new(compiler)
12+
allow(scope).to receive(:environment).and_return(nil)
13+
allow(scope).to receive(:[]).with('facts').and_return({ 'os' => { 'family' => os_family } })
14+
scope
15+
end
16+
17+
context 'on POSIX system' do
18+
let(:os_family) { 'Linux' }
19+
20+
it 'escapes special chars' do
21+
expect(scope.function_docker_run_flags([{ 'env' => [%.MYSQL_PASSWORD='"$()[]{}<>.], 'extra_params' => [] }])).to eq(%(-e MYSQL_PASSWORD\\=\\'\\"\\$\\(\\)\\[\\]\\{\\}\\<\\> \\\n))
22+
end
23+
end
24+
25+
context 'on windows' do
26+
let(:os_family) { 'windows' }
27+
28+
it 'escapes special chars' do
29+
expect(scope.function_docker_run_flags([{ 'env' => [%.MYSQL_PASSWORD='"$()[]{}<>.], 'extra_params' => [] }])).to eq(%^-e MYSQL_PASSWORD=`'\\`"`$()[]{}<> \\\n^)
30+
end
31+
end
32+
end

0 commit comments

Comments
 (0)