Skip to content

Commit bd43992

Browse files
committed
(PUP-8969) Preserve sensitiveness of epp templates
If an EPP template contains a Sensitive data type, then join the unwrapped value, but wrap the entire result as Sensitive. This way the underlying sensitive value is preserved, and the caller can access it by unwrapping the entire result. Previously, the result was always a string and contained the generic 'Sensitive [redacted]' message, so the underlying sensitive value was lost. Update the `epp` and `inline_epp` function signatures, since they can both return either String or Sensitive[String]. Update the `epp` application to unwrap sensitive values produced by the above functions.
1 parent 1f07dc4 commit bd43992

File tree

5 files changed

+61
-6
lines changed

5 files changed

+61
-6
lines changed

lib/puppet/face/epp.rb

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -440,7 +440,12 @@ def get_values(compiler, options)
440440

441441
def render_inline(epp_source, compiler, options)
442442
template_args = get_values(compiler, options)
443-
Puppet::Pops::Evaluator::EppEvaluator.inline_epp(compiler.topscope, epp_source, template_args)
443+
result = Puppet::Pops::Evaluator::EppEvaluator.inline_epp(compiler.topscope, epp_source, template_args)
444+
if result.instance_of?(Puppet::Pops::Types::PSensitiveType::Sensitive)
445+
result.unwrap
446+
else
447+
result
448+
end
444449
end
445450

446451
def render_file(epp_template_name, compiler, options, show_filename, file_nbr)
@@ -457,7 +462,12 @@ def render_file(epp_template_name, compiler, options, show_filename, file_nbr)
457462
if template_file.nil? && Puppet::FileSystem.exist?(epp_template_name)
458463
epp_template_name = File.expand_path(epp_template_name)
459464
end
460-
output << Puppet::Pops::Evaluator::EppEvaluator.epp(compiler.topscope, epp_template_name, compiler.environment, template_args)
465+
result = Puppet::Pops::Evaluator::EppEvaluator.epp(compiler.topscope, epp_template_name, compiler.environment, template_args)
466+
if result.instance_of?(Puppet::Pops::Types::PSensitiveType::Sensitive)
467+
output << result.unwrap
468+
else
469+
output << result
470+
end
461471
rescue Puppet::ParseError => detail
462472
Puppet.err("--- #{epp_template_name}") if show_filename
463473
raise detail

lib/puppet/functions/epp.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
scope_param
4141
param 'String', :path
4242
optional_param 'Hash[Pattern[/^\w+$/], Any]', :parameters
43+
return_type 'Variant[String, Sensitive[String]]'
4344
end
4445

4546
def epp(scope, path, parameters = nil)

lib/puppet/functions/inline_epp.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
scope_param()
5252
param 'String', :template
5353
optional_param 'Hash[Pattern[/^\w+$/], Any]', :parameters
54+
return_type 'Variant[String, Sensitive[String]]'
5455
end
5556

5657
def inline_epp(scope, template, parameters = nil)

lib/puppet/pops/evaluator/evaluator_impl.rb

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -462,10 +462,24 @@ def calculate(left, right, bin_expr, scope)
462462
end
463463

464464
def eval_EppExpression(o, scope)
465+
contains_sensitive = false
466+
465467
scope["@epp"] = []
466468
evaluate(o.body, scope)
467-
result = scope["@epp"].join
468-
result
469+
result = scope["@epp"].map do |r|
470+
if r.instance_of?(Puppet::Pops::Types::PSensitiveType::Sensitive)
471+
contains_sensitive = true
472+
string(r.unwrap, scope)
473+
else
474+
r
475+
end
476+
end.join
477+
478+
if contains_sensitive
479+
Puppet::Pops::Types::PSensitiveType::Sensitive.new(result)
480+
else
481+
result
482+
end
469483
end
470484

471485
def eval_RenderStringExpression(o, scope)
@@ -474,7 +488,12 @@ def eval_RenderStringExpression(o, scope)
474488
end
475489

476490
def eval_RenderExpression(o, scope)
477-
scope["@epp"] << string(evaluate(o.expr, scope), scope)
491+
result = evaluate(o.expr, scope)
492+
if result.instance_of?(Puppet::Pops::Types::PSensitiveType::Sensitive)
493+
scope["@epp"] << result
494+
else
495+
scope["@epp"] << string(result, scope)
496+
end
478497
nil
479498
end
480499

spec/unit/functions/inline_epp_spec.rb

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
21
require 'spec_helper'
32

3+
require 'puppet_spec/compiler'
4+
45
describe "the inline_epp function" do
56
include PuppetSpec::Files
7+
include PuppetSpec::Compiler
68

79
let :node do Puppet::Node.new('localhost') end
810
let :compiler do Puppet::Parser::Compiler.new(node) end
@@ -73,6 +75,28 @@
7375
expect(eval_template("string was: <%= $string %>")).to eq("string was: the string value")
7476
end
7577

78+
context "when using Sensitive" do
79+
it "returns an unwrapped sensitive value as a String" do
80+
expect(eval_and_collect_notices(<<~END)).to eq(["opensesame"])
81+
notice(inline_epp("<%= Sensitive('opensesame').unwrap %>"))
82+
END
83+
end
84+
85+
it "rewraps a sensitive value" do
86+
expect(eval_and_collect_notices(<<~END)).to eq(["Sensitive [value redacted]"])
87+
notice(inline_epp("<%= Sensitive('opensesame') %>"))
88+
END
89+
end
90+
91+
it "can be double wrapped" do
92+
catalog = compile_to_catalog(<<~END)
93+
notify { 'title':
94+
message => Sensitive(inline_epp("<%= Sensitive('opensesame') %>"))
95+
}
96+
END
97+
expect(catalog.resource(:notify, 'title')['message']).to eq('opensesame')
98+
end
99+
end
76100

77101
def eval_template_with_args(content, args_hash)
78102
epp_function.call(scope, content, args_hash)

0 commit comments

Comments
 (0)