55require 'fileutils'
66require 'open3'
77require 'shellwords'
8+ require 'tempfile'
89
910module OctocatalogDiff
1011 module Util
@@ -13,7 +14,7 @@ class ScriptRunner
1314 # For an exception running the script
1415 class ScriptException < RuntimeError ; end
1516
16- attr_reader :script , :logger , :stdout , :stderr , :exitcode
17+ attr_reader :script , :script_src , : logger, :stdout , :stderr , :exitcode
1718
1819 # Create the object - the object is a configured script, which can be executed multiple
1920 # times with different environment varibles.
@@ -24,7 +25,8 @@ class ScriptException < RuntimeError; end
2425 # opts[:override_script_path] (Optional) Directory where a similarly-named script MAY exist
2526 def initialize ( opts = { } )
2627 @logger = opts . fetch ( :logger )
27- @script = find_script ( opts . fetch ( :default_script ) , opts [ :override_script_path ] )
28+ @script_src = find_script ( opts . fetch ( :default_script ) , opts [ :override_script_path ] )
29+ @script = temp_script ( @script_src )
2830 @stdout = nil
2931 @stderr = nil
3032 @exitcode = nil
@@ -48,7 +50,7 @@ def run(opts = {})
4850 env [ 'PWD' ] = working_dir
4951 env [ 'PATH' ] ||= ENV [ 'PATH' ]
5052
51- cmdline = [ @ script, argv ] . flatten . compact . map { |x | Shellwords . escape ( x ) } . join ( ' ' )
53+ cmdline = [ script , argv ] . flatten . compact . map { |x | Shellwords . escape ( x ) } . join ( ' ' )
5254 @logger . debug "Execute: #{ cmdline } "
5355
5456 @stdout , @stderr , status = Open3 . capture3 ( env , cmdline , unsetenv_others : true , chdir : working_dir )
@@ -62,6 +64,24 @@ def run(opts = {})
6264
6365 private
6466
67+ # PRIVATE: Create a temporary file with the contents of the script and mark the script executable.
68+ # This is to avoid changing ownership or permissions on any user-supplied file.
69+ #
70+ # @param script [String] Path to script
71+ # @return [String] Path to tempfile containing script
72+ def temp_script ( script )
73+ unless File . file? ( script )
74+ raise Errno ::ENOENT , "Script '#{ script } ' not found"
75+ end
76+ script_name , extension = script . split ( '.' , 2 )
77+ tempfile = ::Tempfile . new ( [ File . basename ( script_name ) , ".#{ extension } " ] )
78+ tempfile . write ( File . read ( script ) )
79+ tempfile . close
80+ FileUtils . chmod 0o755 , tempfile . path
81+ at_exit { FileUtils . rm_f tempfile . path }
82+ tempfile . path
83+ end
84+
6585 # PRIVATE: Determine the path to the script to execute, taking into account the default script
6686 # location and the optional override script path.
6787 #
0 commit comments