You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

gverify 4.3KB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. #!/usr/bin/ruby
  2. require 'optparse'
  3. require 'yaml'
  4. require 'fileutils'
  5. require 'pathname'
  6. @options = {}
  7. def system!(cmd)
  8. system(cmd) or raise "failed to run #{cmd}"
  9. end
  10. def sanitize(str, where)
  11. raise "unsanitary string in #{where}" if (str =~ /[^\w.-]/)
  12. str
  13. end
  14. def sanitize_path(str, where)
  15. raise "unsanitary string in #{where}" if (str =~ /[^@\w\/.:+-]/)
  16. str
  17. end
  18. def info(str)
  19. puts str if @options[:verbose]
  20. end
  21. ################################
  22. OptionParser.new do |opts|
  23. opts.banner = "Usage: build [options] <build-description>.yml"
  24. opts.on("-v", "--verbose", "be more verbose") do |v|
  25. @options[:verbose] = v
  26. end
  27. opts.on("-r REL", "--release REL", "release name") do |v|
  28. @options[:release] = v
  29. end
  30. opts.on("-d DEST", "--destination DEST", "directory to place signature in") do |v|
  31. @options[:destination] = v
  32. end
  33. opts.on("-c SIGNER", "--compare-to SIGNER", "compare other manifests to SIGNER's, if not given pick first") do |v|
  34. @options[:compareto] = v
  35. end
  36. end.parse!
  37. base_dir = Pathname.new(__FILE__).expand_path.dirname.parent
  38. build_desc_file = ARGV.shift or raise "must supply YAML build description file"
  39. build_desc = YAML.load_file(build_desc_file)
  40. in_sums = []
  41. result_dir = 'result'
  42. package_name = build_desc["name"] or raise "must supply name"
  43. package_name = sanitize(package_name, "package name")
  44. destination = @options[:destination] || File.join(base_dir, "sigs", package_name)
  45. release = @options[:release] || "current"
  46. release = sanitize(release, "release")
  47. verbose = @options[:verbose]
  48. release_path = File.join(destination, release)
  49. File.exists?(release_path) or raise "#{release_path} does not exist"
  50. result_file = "#{package_name}-build.assert"
  51. sig_file = "#{result_file}.sig"
  52. current_manifest = nil
  53. if @options[:compareto]
  54. # Load a specific 'golden' manifest to compare to
  55. compareto = @options[:compareto]
  56. result_path = sanitize_path(File.join(release_path, compareto, result_file), "result path")
  57. result = YAML.load_file(result_path)
  58. current_manifest = result['out_manifest']
  59. end
  60. did_fail = false
  61. Dir.foreach(release_path) do |signer_dir|
  62. next if signer_dir == "." or signer_dir == ".."
  63. signer_path = sanitize_path(File.join(release_path, signer_dir), "signer path")
  64. next if !File.directory?(signer_path)
  65. result_path = sanitize_path(File.join(signer_path, result_file), "result path")
  66. sig_path = sanitize_path(File.join(signer_path, sig_file), "result path")
  67. if !File.exist?(result_path)
  68. puts "missing result at #{result_path}"
  69. next
  70. end
  71. if !File.exist?(sig_path)
  72. puts "missing signature at #{sig_path}"
  73. next
  74. end
  75. result = YAML.load_file(result_path)
  76. system("gpg --keyserver pgp.mit.edu --recv-keys `gpg --quiet --batch --verify \"#{File.join(signer_path, 'signature.pgp')}\" \"#{result_path}\" 2>&1 | head -n1 | grep \"key ID\" | awk '{ print $15 }'` > /dev/null 2>&1")
  77. out = `gpg --quiet --batch --verify \"#{sig_path}\" \"#{result_path}\" 2>&1`
  78. if $? != 0
  79. out.each_line do |line|
  80. if line =~ /^gpg: Signature made/
  81. info(line)
  82. else
  83. puts line
  84. end
  85. end
  86. puts "#{signer_dir}: BAD SIGNATURE"
  87. did_fail = true
  88. elsif current_manifest and (result['out_manifest'] != current_manifest or result['release'] != release or result['name'] != package_name)
  89. out.each_line do |line|
  90. if line =~ /^gpg: Signature made/
  91. info(line)
  92. elsif line =~ /^gpg: Good signature/
  93. info(line)
  94. elsif line =~ /^gpg: aka/
  95. info(line)
  96. else
  97. puts line
  98. end
  99. end
  100. puts "#{signer_dir}: MISMATCH"
  101. if verbose
  102. lines1 = current_manifest.each_line
  103. lines2 = result['out_manifest'].each_line
  104. lines1.zip(lines2) do |line|
  105. if line[0] != line[1]
  106. puts "- "+line[0]
  107. puts "+ "+line[1]
  108. end
  109. end
  110. end
  111. did_fail = true
  112. else
  113. out.each_line do |line|
  114. if line =~ /^gpg: Signature made/
  115. info(line)
  116. elsif line =~ /^gpg: Good signature/
  117. info(line)
  118. elsif line =~ /^gpg: aka/
  119. info(line)
  120. else
  121. puts line
  122. end
  123. end
  124. puts "#{signer_dir}: OK"
  125. end
  126. if !current_manifest
  127. # take first manifest as 'current' to compare against
  128. current_manifest = result['out_manifest']
  129. end
  130. end
  131. exit 1 if did_fail