#!/usr/bin/env ruby

require 'shellwords'
require 'logger'
require 'optparse'
require 'tempfile'

class RepoSignatureChecker
  def initialize
    @repo_dir = '/srv/www/htdocs/repo'
    @keyring = Tempfile.new('repo-check-keyring')
    @keyring.close

    parse_options
    @logger = Logger.new(@opt_nagios ? IO::NULL : STDOUT)
  end

  def parse_options
    OptionParser.new do |opts|
      opts.banner = "Verifies repository metadata GPG signatures.\nUsage: #{File.basename($0)} [options]"

      opts.on("-n", "--nagios", "Terse output for Nagios") { @opt_nagios = true }
      opts.on("-d", "--dir [REPO_DIR]", "Path to repo directory") { |param| @repo_dir = param }
    end.parse!
  end

  def check_repo(dir)
    cmd = "gpg --no-default-keyring --keyring #{@keyring.path} --import #{dir}/repomd.xml.key 2>&1"
    out = `#{cmd}`

    if $?.exitstatus != 0
      @logger.warn cmd
      @logger.warn out
      return false
    end

    cmd = "gpg --no-default-keyring --keyring #{@keyring.path} --verify #{dir}/repomd.xml.asc #{dir}/repomd.xml 2>&1"
    out = `#{cmd}`

    if $?.exitstatus != 0
      @logger.warn cmd
      @logger.warn out
      return false
    end

    true
  end

  def run
    repodata_dirs = `find #{@repo_dir} -type d -name repodata`
    if repodata_dirs.empty?
      puts "No repositories found in #{@repo_dir}"
      exit 2
    end

    valid_repos = 0
    invalid_repos = 0

    repodata_dirs.each_line do |line|
      dir = Shellwords.escape(line.strip)
      result = check_repo(dir)
      result ? valid_repos += 1 : invalid_repos += 1
    end

    puts "Valid repos=#{valid_repos}, invalid repos=#{invalid_repos}"
    if invalid_repos > 0
      exit 2
    else
      exit 0
    end
  ensure
    gpg_backup_file = @keyring.path + "~"
    File.unlink(gpg_backup_file) if File.exist?(gpg_backup_file)
    @keyring.unlink
  end
end

RepoSignatureChecker.new.run
