* Hide all Kernel methods within the TemplateWrapper class.
* Update TemplateWrapper to qualify calls to Kernel#raise.
* Create a local alias for the Kernel#binding method, which does not work as
advertised if called through a qualified name.
* Implement a test to ensure that a range of dangerous Kernel methods can be
evaluated correctly within the template.
Signed-off-by: Daniel Pittman <[EMAIL PROTECTED]>
---
lib/puppet/parser/templatewrapper.rb | 43 ++++++++++++++++++++++++++++++----
test/language/functions.rb | 39 ++++++++++++++++++++++++++++++
2 files changed, 77 insertions(+), 5 deletions(-)
diff --git a/lib/puppet/parser/templatewrapper.rb
b/lib/puppet/parser/templatewrapper.rb
index 4790cea..201bc7c 100644
--- a/lib/puppet/parser/templatewrapper.rb
+++ b/lib/puppet/parser/templatewrapper.rb
@@ -1,17 +1,50 @@
# A simple wrapper for templates, so they don't have full access to
# the scope objects.
+#
+# WARNING: This code does not have all the regular Kernel methods available
+# unqualified. This is important for template variable processing, but *BAD*
+# if you (say) thought raise was syntax rather than a method.
class Puppet::Parser::TemplateWrapper
attr_accessor :scope, :file
include Puppet::Util
Puppet::Util.logmethods(self)
+ # Address Redmine #1427: the Kernel module exports a bunch of methods that
+ # are called if used as unqualified terms within any object. This,
+ # unfortunately, means that a Kernel method will shadow a puppet variable.
+ #
+ # We can work around that, though, by hiding those methods inside this
+ # object and ensuring that they act as if undefined -- which causes the
+ # evaluation inside ERB to work as expected by calling our method_missing.
+ #
+ # Since Ruby doesn't provide an 'instance_variable_missing' method we
+ # can't use that to capture these lookups. A pity that isn't there eh?
+
+ # Unfortunately, binding does not work as advertised if you qualify the
+ # name in any fashion, so we are forced to retain a local alias that is
+ # less likely to conflict with a valid puppet variable.
+ alias_method(:__binding__, :binding)
+
+ # Shadow all the Kernel methods we have so they act as if undefined.
+ # Only apply this to direct methods of kernel, not inherited methods.
+ Kernel.methods(false).each do |name|
+ begin
+ undef_method(name)
+ rescue
+ # Ignore the error and hope that nothing too disasterous happens.
+ # Module#method_added triggers an "undefined method" exception
+ # within Puppet, presumably because it is visible in Kernel but
+ # not to us.
+ end
+ end
+
def initialize(scope, file)
@scope = scope
@file = Puppet::Module::find_template(file,
@scope.compiler.environment)
unless FileTest.exists?(@file)
- raise Puppet::ParseError,
- "Could not find template %s" % file
+ Kernel.raise(Puppet::ParseError,
+ "Could not find template %s" % file)
end
# We'll only ever not have a parser in testing, but, eh.
@@ -40,8 +73,8 @@ class Puppet::Parser::TemplateWrapper
else
# Just throw an error immediately, instead of searching for
# other missingmethod things or whatever.
- raise Puppet::ParseError,
- "Could not find value for '%s'" % name
+ Kernel.raise(Puppet::ParseError,
+ "Could not find value for '%s'" % name)
end
end
@@ -49,7 +82,7 @@ class Puppet::Parser::TemplateWrapper
result = nil
benchmark(:debug, "Interpolated template [EMAIL PROTECTED]") do
template = ERB.new(File.read(@file), 0, "-")
- result = template.result(binding)
+ result = template.result(__binding__)
end
result
diff --git a/test/language/functions.rb b/test/language/functions.rb
index a5d52d7..f231207 100755
--- a/test/language/functions.rb
+++ b/test/language/functions.rb
@@ -279,6 +279,45 @@ class TestLangFunctions < Test::Unit::TestCase
end
end
+ # Make sure that we can use variable names that are identical to Kernel
+ # exported methods, such as 'fork', 'puts', 'format' or 'raise'
+ def test_singletemplates
+ template = tempfile()
+
+ # Test a variety of Kernel methods
+ %w(raise fork puts format binding chop eval exec).each do |word|
+ File.open(template, "w") do |f|
+ f.puts "template <%= #{word} %>"
+ end
+
+ func = nil
+ assert_nothing_raised do
+ func = Puppet::Parser::AST::Function.new(
+ :name => "template",
+ :ftype => :rvalue,
+ :arguments => AST::ASTArray.new(
+ :children => [stringobj(template)]
+ )
+ )
+ end
+ ast = varobj("output", func)
+
+ scope = mkscope
+ assert_raise(Puppet::ParseError) do
+ ast.evaluate(scope)
+ end
+
+ scope.setvar(word, "passes the test")
+
+ assert_nothing_raised do
+ ast.evaluate(scope)
+ end
+
+ assert_equal("template passes the test\n",
scope.lookupvar("output"),
+ "Shadowed Kernel methods were not handled correctly")
+ end
+ end
+
def test_autoloading_functions
assert_equal(false, Puppet::Parser::Functions.function(:autofunc),
"Got told autofunc already exists")
--
1.5.4.3
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"Puppet Developers" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at
http://groups.google.com/group/puppet-dev?hl=en
-~----------~----~----~----~------~----~------~--~---