* 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
-~----------~----~----~----~------~----~------~--~---

Reply via email to