channel-scripts/sign-binary-cache.pl

102 lines
2.8 KiB
Perl
Raw Normal View History

#! /usr/bin/env nix-shell
#! nix-shell -i perl -p perl perlPackages.NetAmazonS3 perlPackages.ForksSuper perlPackages.DBDSQLite
use strict;
use Forks::Super 'bg_eval';
use List::MoreUtils qw(part);
use MIME::Base64;
use Net::Amazon::S3;
use Nix::Manifest;
use Nix::Store;
use Nix::Utils;
my $bucketName = "nix-cache";
my $nrProcesses = 16;
my $secretKeyFile = "/home/eelco/Misc/Keys/cache.nixos.org-1/secret";
my $s = readFile $secretKeyFile;
chomp $s;
my ($keyName, $secretKey) = split ":", $s;
die "invalid secret key file $secretKeyFile\n" unless defined $keyName && defined $secretKey;
my @files;
while (<>) {
chomp;
push @files, $_;
}
# S3 setup.
my $aws_access_key_id = $ENV{'AWS_ACCESS_KEY_ID'} or die;
my $aws_secret_access_key = $ENV{'AWS_SECRET_ACCESS_KEY'} or die;
my $s3 = Net::Amazon::S3->new(
{ aws_access_key_id => $aws_access_key_id,
aws_secret_access_key => $aws_secret_access_key,
retry => 1,
});
my $bucket = $s3->bucket($bucketName) or die;
# Process .narinfos.
sub signNarInfo {
my ($fn) = @_;
die unless $fn =~ /\.narinfo$/;
my $get = $bucket->get_key($fn, "GET");
die "failed to get $fn\n" unless defined $get;
my $contents = $get->{value};
$contents =~ /^StorePath: (\S+)$/m;
die "corrupt NAR info $fn" unless defined $1;
my $storePath = $1;
if ($contents =~ /^Sig:/m) {
print STDERR "skipping already signed $fn\n";
return;
}
print STDERR "signing $fn...\n";
my $narInfo = parseNARInfo($storePath, $contents);
die "failed to parse NAR info of $fn\n" unless $narInfo;
# Legacy: convert base16 to base32.
my $narHash = $narInfo->{narHash};
if (length $narHash != 59) {
$narHash = `nix-hash --type sha256 --to-base32 ${\(substr($narHash, 7))}`;
chomp $narHash;
$narHash = "sha256:$narHash";
}
#print STDERR "$storePath -> $narInfo->{narHash} $narHash $narInfo->{narSize}\n";
my $refs = [ map { "$Nix::Config::storeDir/$_" } @{$narInfo->{refs}} ];
my $fingerprint = fingerprintPath($storePath, $narHash, $narInfo->{narSize}, $refs);
#print STDERR "FP = $fingerprint\n";
my $sig = encode_base64(signString(decode_base64($secretKey), $fingerprint), "");
$contents .= "Sig: $keyName:$sig\n";
$bucket->add_key($fn, $contents) or die "failed to upload $fn\n";
}
# Fork processes to sign files in parallel.
my $i = 0;
my @filesPerProcess = part { $i++ % $nrProcesses } @files;
my @res;
for (my $n = 0; $n < $nrProcesses; $n++) {
push @res, bg_eval {
foreach my $fn (@{$filesPerProcess[$n]}) {
eval {
signNarInfo($fn);
};
warn "$@" if $@;
}
return 0;
};
}
foreach my $res (@res) { if ($res) { } }
print STDERR "DONE\n";