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.
134 lines
3.5 KiB
134 lines
3.5 KiB
#!/usr/bin/ruby |
|
|
|
require 'optparse' |
|
require 'yaml' |
|
require 'fileutils' |
|
require 'pathname' |
|
|
|
@options = {} |
|
|
|
def system!(cmd) |
|
system(cmd) or raise "failed to run #{cmd}" |
|
end |
|
|
|
def sanitize(str, where) |
|
raise "unsanitary string in #{where}" if (str =~ /[^\w.-]/) |
|
str |
|
end |
|
|
|
def sanitize_path(str, where) |
|
raise "unsanitary string in #{where}" if (str =~ /[^@\w\/.:+-]/) |
|
str |
|
end |
|
|
|
def info(str) |
|
puts str if @options[:verbose] |
|
end |
|
|
|
################################ |
|
|
|
OptionParser.new do |opts| |
|
opts.banner = "Usage: build [options] <build-description>.yml" |
|
|
|
opts.on("-v", "--verbose", "be more verbose") do |v| |
|
@options[:verbose] = v |
|
end |
|
opts.on("-r REL", "--release REL", "release name") do |v| |
|
@options[:release] = v |
|
end |
|
|
|
opts.on("-d DEST", "--destination DEST", "directory to place signature in") do |v| |
|
@options[:destination] = v |
|
end |
|
end.parse! |
|
|
|
base_dir = Pathname.new(__FILE__).expand_path.dirname.parent |
|
|
|
build_desc_file = ARGV.shift or raise "must supply YAML build description file" |
|
|
|
build_desc = YAML.load_file(build_desc_file) |
|
|
|
in_sums = [] |
|
|
|
result_dir = 'result' |
|
|
|
package_name = build_desc["name"] or raise "must supply name" |
|
package_name = sanitize(package_name, "package name") |
|
|
|
destination = @options[:destination] || File.join(base_dir, "sigs", package_name) |
|
release = @options[:release] || "current" |
|
release = sanitize(release, "release") |
|
|
|
release_path = File.join(destination, release) |
|
|
|
File.exists?(release_path) or raise "#{release_path} does not exist" |
|
|
|
result_file = "#{package_name}-build.assert" |
|
sig_file = "#{result_file}.sig" |
|
|
|
current_manifest = nil |
|
|
|
did_fail = false |
|
|
|
Dir.foreach(release_path) do |signer_dir| |
|
next if signer_dir == "." or signer_dir == ".." |
|
signer_path = sanitize_path(File.join(release_path, signer_dir), "signer path") |
|
next if !File.directory?(signer_path) |
|
result_path = sanitize_path(File.join(signer_path, result_file), "result path") |
|
sig_path = sanitize_path(File.join(signer_path, sig_file), "result path") |
|
|
|
if !File.exist?(result_path) |
|
puts "missing result at #{result_path}" |
|
next |
|
end |
|
|
|
if !File.exist?(sig_path) |
|
puts "missing signature at #{sig_path}" |
|
next |
|
end |
|
|
|
result = YAML.load_file(result_path) |
|
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") |
|
out = `gpg --quiet --batch --verify \"#{sig_path}\" \"#{result_path}\" 2>&1` |
|
if $? != 0 |
|
out.each_line do |line| |
|
if line =~ /^gpg: Signature made/ |
|
info(line) |
|
else |
|
puts line |
|
end |
|
end |
|
puts "#{signer_dir}: BAD SIGNATURE" |
|
did_fail = true |
|
elsif current_manifest and (result['out_manifest'] != current_manifest or result['release'] != release or result['name'] != package_name) |
|
out.each_line do |line| |
|
if line =~ /^gpg: Signature made/ |
|
info(line) |
|
elsif line =~ /^gpg: Good signature/ |
|
info(line) |
|
elsif line =~ /^gpg: aka/ |
|
info(line) |
|
else |
|
puts line |
|
end |
|
end |
|
puts "#{signer_dir}: MISMATCH" |
|
did_fail = true |
|
else |
|
out.each_line do |line| |
|
if line =~ /^gpg: Signature made/ |
|
info(line) |
|
elsif line =~ /^gpg: Good signature/ |
|
info(line) |
|
elsif line =~ /^gpg: aka/ |
|
info(line) |
|
else |
|
puts line |
|
end |
|
end |
|
puts "#{signer_dir}: OK" |
|
end |
|
current_manifest = result['out_manifest'] |
|
end |
|
|
|
exit 1 if did_fail
|
|
|