class PuppetValidator

Public Class Methods

new(app=nil) click to toggle source
Calls superclass method
# File lib/puppet-validator.rb, line 34
def initialize(app=nil)
  super(app)

  # make sure that all the settings we expect are defined.
  [:disabled_lint_checks, :puppet_versions, :csrf].each do |name|
    next if settings.respond_to? name

    settings.define_singleton_method(name) { Array.new }

    settings.define_singleton_method("#{name}=") do |arg|
      settings.define_singleton_method(name) { arg }
    end
  end

  # can pass in an array, a filename, or a list of checks
  if settings.disabled_lint_checks.class == String
    path = File.expand_path(settings.disabled_lint_checks)
    if File.file? path
      data = File.readlines(path).map {|line| line.chomp }
      data.reject! {|line| line.empty? or line.start_with? '#' }

      settings.disabled_lint_checks = data
    else
      settings.disabled_lint_checks = settings.disabled_lint_checks.split(',')
    end
  end

  # put all installed Puppet versions in reverse semver order
  #settings.puppet_versions = settings.puppet_versions.sort_by { |v| Gem::Version.new(v) }.reverse
  settings.puppet_versions = Gem::Specification.all.select {|g| g.name == 'puppet' }.collect {|g| g.version.to_s }

  settings.logger.error "Please gem install one or more Puppet versions." if settings.puppet_versions.empty?

end
run_in_process() { || ... } click to toggle source

rspec defines a crapton of global information and doesn't clean up well between runs. This means that there are global objects that leak and chew up memory. To counter that, we fork a process to run the spec test.

This also allows us to load different versions of Puppet so users can select the version they want to validate against.

# File lib/puppet-validator/helpers.rb, line 8
def self.run_in_process
  raise "Please define a block to run in a new process." unless block_given?

  reader, writer = IO.pipe
  output = nil

  if fork
    writer.close
    output = reader.read
    reader.close
    Process.wait
  else
    # Attempt to drop privileges for safety.
    Process.euid = Etc.getpwnam('nobody').uid if Process.uid == 0
    
    begin
      reader.close
      writer.write(yield)
      writer.close
    rescue StandardError, LoadError => e
      settings.logger.error e.message
      settings.logger.debug e.backtrace.join "\n"
      writer.write e.message
    end

    # if we fire any at_exit hooks, Sinatra has a kitten
    exit!
  end

  output
end

Public Instance Methods

check_size_limit!() click to toggle source
# File lib/puppet-validator.rb, line 219
def check_size_limit!
  content = request.body.read
  request.body.rewind

  if content.size > MAXSIZE
    halt 403, "Submitted code size is #{content.size}, which is larger than the maximum size of #{MAXSIZE}."
  end
end
csrf_safe!() click to toggle source
# File lib/puppet-validator.rb, line 205
def csrf_safe!
  return true unless settings.csrf
  if session[:csrf] == params['_csrf'] && session[:csrf] == request.cookies['authenticity_token']
    true
  else
    logger.warn 'CSRF attempt detected. Ensure that server time is correct.'
    logger.debug "session: #{session[:csrf]}"
    logger.debug "  param: #{params['_csrf']}"
    logger.debug " cookie: #{request.cookies['authenticity_token']}"

    halt 403, 'Request validation failed.'
  end
end
sanitize_code(code) click to toggle source
# File lib/puppet-validator.rb, line 232
def sanitize_code(code)
  frag = Nokogiri::HTML.fragment(code)
  unless frag.elements.empty?
    logger.warn 'HTML code found in validation string'
    frag.elements.each { |elem| logger.debug "HTML: #{elem.to_s}" }
    code = CGI.escapeHTML(code)
  end
  code
end
sanitize_code!() click to toggle source
# File lib/puppet-validator.rb, line 228
def sanitize_code!
  params['code'] = sanitize_code(params['code'])
end
validate_all() click to toggle source
# File lib/puppet-validator.rb, line 242
def validate_all
  syntax = PuppetValidator::Validators::Syntax.new(settings, params['version'])
  result = syntax.validate(params['code'])

  # munge the data slightly to make it more consumable
  result[:version]  = params['version']
  result[:success]  = result[:status]
  result[:status]   = result[:status] ? :success : :fail
  result[:column]   = result[:pos]
  result[:messages] = []

  # initial highlighting for the potential syntax error
  if result[:line]
    line       = result[:line]
    start      = [line - CONTEXT, 0].max

    result[:messages] << {
        :from   => [start, 0],
          :to   => [line - 1, result[:column]],
      :message  => result[:message],
      :severity => 'error',
    }
  end

  # then add all the lint warnings and tooltip
  if params['lint']
    linter = PuppetValidator::Validators::Lint.new(settings)
    lint   = linter.validate(params['code'], params['checks'])

    result[:lint_warnings] = ! lint.empty?

    lint.each do |item|
      line = item[:line]-1;
      result[:messages] << {
            :from => [line, 0],
              :to => [line, 1000],
         :message => "#{item[:kind].upcase}: #{item[:message]}",
        :severity => 'warning'
      }
    end
  end

  result
end
validate_request!() click to toggle source
# File lib/puppet-validator.rb, line 200
def validate_request!
  csrf_safe!
  check_size_limit!
end