From c76fc42d03e1f290de723bb9022e7ad4cc8eef5f Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Wed, 3 Jun 2015 16:23:36 +0200 Subject: [PATCH] Script for signing existing .narinfo files in a binary cache --- sign-binary-cache.pl | 101 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100755 sign-binary-cache.pl diff --git a/sign-binary-cache.pl b/sign-binary-cache.pl new file mode 100755 index 0000000..0818042 --- /dev/null +++ b/sign-binary-cache.pl @@ -0,0 +1,101 @@ +#! /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";