diff --git a/lib/puppet/face/epp.rb b/lib/puppet/face/epp.rb index 662c02039b2..a3d519cf612 100644 --- a/lib/puppet/face/epp.rb +++ b/lib/puppet/face/epp.rb @@ -440,7 +440,12 @@ def get_values(compiler, options) def render_inline(epp_source, compiler, options) template_args = get_values(compiler, options) - Puppet::Pops::Evaluator::EppEvaluator.inline_epp(compiler.topscope, epp_source, template_args) + result = Puppet::Pops::Evaluator::EppEvaluator.inline_epp(compiler.topscope, epp_source, template_args) + if result.instance_of?(Puppet::Pops::Types::PSensitiveType::Sensitive) + result.unwrap + else + result + end end 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) if template_file.nil? && Puppet::FileSystem.exist?(epp_template_name) epp_template_name = File.expand_path(epp_template_name) end - output << Puppet::Pops::Evaluator::EppEvaluator.epp(compiler.topscope, epp_template_name, compiler.environment, template_args) + result = Puppet::Pops::Evaluator::EppEvaluator.epp(compiler.topscope, epp_template_name, compiler.environment, template_args) + if result.instance_of?(Puppet::Pops::Types::PSensitiveType::Sensitive) + output << result.unwrap + else + output << result + end rescue Puppet::ParseError => detail Puppet.err("--- #{epp_template_name}") if show_filename raise detail diff --git a/lib/puppet/functions/epp.rb b/lib/puppet/functions/epp.rb index f0d8399d2d7..cd563a6aa3c 100644 --- a/lib/puppet/functions/epp.rb +++ b/lib/puppet/functions/epp.rb @@ -40,6 +40,7 @@ scope_param param 'String', :path optional_param 'Hash[Pattern[/^\w+$/], Any]', :parameters + return_type 'Variant[String, Sensitive[String]]' end def epp(scope, path, parameters = nil) diff --git a/lib/puppet/functions/inline_epp.rb b/lib/puppet/functions/inline_epp.rb index affc3544134..7b191de6d34 100644 --- a/lib/puppet/functions/inline_epp.rb +++ b/lib/puppet/functions/inline_epp.rb @@ -51,6 +51,7 @@ scope_param() param 'String', :template optional_param 'Hash[Pattern[/^\w+$/], Any]', :parameters + return_type 'Variant[String, Sensitive[String]]' end def inline_epp(scope, template, parameters = nil) diff --git a/lib/puppet/pops/evaluator/evaluator_impl.rb b/lib/puppet/pops/evaluator/evaluator_impl.rb index 446fc68247e..8bf13d22e86 100644 --- a/lib/puppet/pops/evaluator/evaluator_impl.rb +++ b/lib/puppet/pops/evaluator/evaluator_impl.rb @@ -462,10 +462,24 @@ def calculate(left, right, bin_expr, scope) end def eval_EppExpression(o, scope) + contains_sensitive = false + scope["@epp"] = [] evaluate(o.body, scope) - result = scope["@epp"].join - result + result = scope["@epp"].map do |r| + if r.instance_of?(Puppet::Pops::Types::PSensitiveType::Sensitive) + contains_sensitive = true + string(r.unwrap, scope) + else + r + end + end.join + + if contains_sensitive + Puppet::Pops::Types::PSensitiveType::Sensitive.new(result) + else + result + end end def eval_RenderStringExpression(o, scope) @@ -474,7 +488,12 @@ def eval_RenderStringExpression(o, scope) end def eval_RenderExpression(o, scope) - scope["@epp"] << string(evaluate(o.expr, scope), scope) + result = evaluate(o.expr, scope) + if result.instance_of?(Puppet::Pops::Types::PSensitiveType::Sensitive) + scope["@epp"] << result + else + scope["@epp"] << string(result, scope) + end nil end diff --git a/spec/unit/functions/inline_epp_spec.rb b/spec/unit/functions/inline_epp_spec.rb index f50ae6e0d37..8b39eb5bc4f 100644 --- a/spec/unit/functions/inline_epp_spec.rb +++ b/spec/unit/functions/inline_epp_spec.rb @@ -1,8 +1,10 @@ - require 'spec_helper' +require 'puppet_spec/compiler' + describe "the inline_epp function" do include PuppetSpec::Files + include PuppetSpec::Compiler let :node do Puppet::Node.new('localhost') end let :compiler do Puppet::Parser::Compiler.new(node) end @@ -73,6 +75,29 @@ expect(eval_template("string was: <%= $string %>")).to eq("string was: the string value") end + context "when using Sensitive" do + it "returns an unwrapped sensitive value as a String" do + expect(eval_and_collect_notices(<<~END)).to eq(["opensesame"]) + notice(inline_epp("<%= Sensitive('opensesame').unwrap %>")) + END + end + + it "rewraps a sensitive value" do + # note entire result is redacted, not just sensitive part + expect(eval_and_collect_notices(<<~END)).to eq(["Sensitive [value redacted]"]) + notice(inline_epp("This is sensitive <%= Sensitive('opensesame') %>")) + END + end + + it "can be double wrapped" do + catalog = compile_to_catalog(<<~END) + notify { 'title': + message => Sensitive(inline_epp("<%= Sensitive('opensesame') %>")) + } + END + expect(catalog.resource(:notify, 'title')['message']).to eq('opensesame') + end + end def eval_template_with_args(content, args_hash) epp_function.call(scope, content, args_hash)