Hi Tomasz,

> A quick glimpse tells me that it should be ok. Would you mind adding a
> test to cover this functionality?

No problem — updated patch attached:

  commit d71b37d49e57dd6e31b4d6db5752dcdc607a2dd1
  Author: Chris Lamb <la...@debian.org>
  Date:   Sun Aug 20 16:25:45 2017 -0700
  
      Support storing and retrieval of upstream signatures. (Closes: #871809)
      
      This commit adds support for optionally storing and regenerating an
      upstream signature with the tarball so that it can be verified by,
      for example, dpkg-source(1).
      
      Regardless of the original signature filename provided, it is always
      stored alongside the .delta and .id files as .sig for deterministic
      retrieval.
      
      The existing behaviour of pristine-tar is unchanged unless you specify
      the `-s` option; in particular, extraction of signatures is not performed
      by default - one must specify the filename. This is to prevent breaking
      existing behaviour.
  
   README                                     |  3 ++
   debian/control                             |  3 ++
   pristine-tar                               | 62 
++++++++++++++++++++++++------
   test/samples/signatures/foo-1.0.tar.gz.asc | 16 ++++++++
   test/test_checkout.sh                      | 14 +++++++
   5 files changed, 87 insertions(+), 11 deletions(-)

> Thanks, the amount of love pristine-tar is getting these days must
> make it blush.

:) :)


Best wishes,

-- 
      ,''`.
     : :'  :     Chris Lamb
     `. `'`      la...@debian.org / chris-lamb.co.uk
       `-
>From d71b37d49e57dd6e31b4d6db5752dcdc607a2dd1 Mon Sep 17 00:00:00 2001
From: Chris Lamb <la...@debian.org>
Date: Sun, 20 Aug 2017 16:25:45 -0700
Subject: [PATCH] Support storing and retrieval of upstream signatures.
 (Closes: #871809)

This commit adds support for optionally storing and regenerating an
upstream signature with the tarball so that it can be verified by,
for example, dpkg-source(1).

Regardless of the original signature filename provided, it is always
stored alongside the .delta and .id files as .sig for deterministic
retrieval.

The existing behaviour of pristine-tar is unchanged unless you specify
the `-s` option; in particular, extraction of signatures is not performed
by default - one must specify the filename. This is to prevent breaking
existing behaviour.
---
 README                                     |  3 ++
 debian/control                             |  3 ++
 pristine-tar                               | 62 ++++++++++++++++++++++++------
 test/samples/signatures/foo-1.0.tar.gz.asc | 16 ++++++++
 test/test_checkout.sh                      | 14 +++++++
 5 files changed, 87 insertions(+), 11 deletions(-)
 create mode 100644 test/samples/signatures/foo-1.0.tar.gz.asc

diff --git a/README b/README
index c792882..710c2ff 100644
--- a/README
+++ b/README
@@ -9,3 +9,6 @@ The delta file is designed to be checked into revision control along-side the
 upstream branch, thus allowing Debian packages to be built entirely using
 sources in revision control, without the need to keep copies of upstream
 tarballs. See `delta-format.txt` for details on the format of the delta file.
+
+An optional upstream signature may be attached to tarballs for verification
+by, for example, dpkg-source(1).
diff --git a/debian/control b/debian/control
index 35e3a4a..dab3b3f 100644
--- a/debian/control
+++ b/debian/control
@@ -37,3 +37,6 @@ Description: regenerate pristine tarballs
  the upstream branch, thus allowing Debian packages to be built entirely
  using sources in revision control, without the need to keep copies of
  upstream tarballs.
+ .
+ An optional upstream signature may be attached to tarballs for verification
+ by, for example, dpkg-source(1).
diff --git a/pristine-tar b/pristine-tar
index d4f4b0e..1c4eaf0 100755
--- a/pristine-tar
+++ b/pristine-tar
@@ -10,7 +10,7 @@ B<pristine-tar> [-vdk] gendelta I<tarball> I<delta>
 
 B<pristine-tar> [-vdk] gentar I<delta> I<tarball>
 
-B<pristine-tar> [-vdk] [-m message] commit I<tarball> [I<upstream>]
+B<pristine-tar> [-vdk] [-m message] [-s signaturefile] commit I<tarball> [I<upstream>]
 
 B<pristine-tar> [-vdk] checkout I<tarball>
 
@@ -120,6 +120,14 @@ Don't clean up the temporary directory on exit.
 
 Use this option to specify a custom commit message to pristine-tar commit.
 
+=item -s signaturefile
+
+=item --signature-file=signaturefile
+
+Use this option to optionally commit or checkout an upstream signature
+file for the tarball. Note that extraction of signatures is not
+performed by default.
+
 =back
 
 =head1 EXAMPLES
@@ -198,6 +206,7 @@ use Pristine::Tar;
 use Pristine::Tar::Delta;
 use Pristine::Tar::Formats;
 use Pristine::Tar::DeltaTools;
+use File::Copy;
 use File::Path;
 use File::Basename;
 use Cwd qw{getcwd abs_path};
@@ -226,7 +235,7 @@ use constant {
   XDELTA_LONG => "2.0"
 };
 
-my $message;
+my ($message, $signature_file);
 my $genversion =
   version_from_env(XDELTA3, "xdelta" => XDELTA, "xdelta3" => XDELTA3);
 
@@ -243,7 +252,8 @@ dispatch(
     verify   => [ \&verify, 1 ],
   },
   options => {
-    "m|message=s" => \$message,
+    "m|message=s"        => \$message,
+    "s|signature-file=s" => \$signature_file,
   },
 );
 
@@ -251,8 +261,9 @@ sub usage {
   print STDERR "Usage: pristine-tar [-vdk] gendelta tarball delta\n";
   print STDERR "       pristine-tar [-vdk] gentar delta tarball\n";
   print STDERR
-    "       pristine-tar [-vdk] [-m message] commit tarball [upstream]\n";
-  print STDERR "       pristine-tar [-vdk] checkout tarball\n";
+"       pristine-tar [-vdk] [-m message] [-s signaturefile] commit tarball [upstream]\n";
+  print STDERR
+    "       pristine-tar [-vdk] [-s signaturefile] checkout tarball\n";
   print STDERR "       pristine-tar [-vdk] verify tarball\n";
   print STDERR "       pristine-tar        list\n";
   exit 1;
@@ -780,8 +791,9 @@ sub checkoutdelta {
   my $branch    = "pristine-tar";
   my $deltafile = basename($tarball) . ".delta";
   my $idfile    = basename($tarball) . ".id";
+  my $sigfile   = basename($tarball) . ".asc";
 
-  my ($delta, $id);
+  my ($delta, $id, $signature);
 
   my $vcs = vcstype();
   if ($vcs eq "git") {
@@ -810,11 +822,19 @@ sub checkoutdelta {
     if (!length $id) {
       error "git show $branch:$idfile returned no id";
     }
+    if (defined $signature_file) {
+      # We only extract the signature if the user specifically requested
+      # it and we assume the data will fit comfortably into memory.
+      $signature = `git show $branch:\Q$sigfile\E`;
+      if ($?) {
+        error "git show $branch:$sigfile failed";
+      }
+    }
   } else {
     die "unsupported vcs $vcs";
   }
 
-  return ($delta, $id);
+  return ($delta, $id, $signature);
 }
 
 sub commitdelta {
@@ -825,6 +845,7 @@ sub commitdelta {
   my $branch    = "pristine-tar";
   my $deltafile = basename($tarball) . ".delta";
   my $idfile    = basename($tarball) . ".id";
+  my $sigfile   = basename($tarball) . ".asc";
   my $commit_message =
     defined $message
     ? $message
@@ -839,6 +860,9 @@ sub commitdelta {
     open(OUT, ">$tempdir/$idfile") || die "$tempdir/$idfile: $!";
     print OUT "$id\n";
     close OUT;
+    if (defined $signature_file) {
+      copy($signature_file, "$tempdir/$sigfile") || die "$tempdir/$sigfile: $!";
+    }
 
     # Commit the delta to a branch in git without affecting the
     # index, and without touching the working tree. Aka deep
@@ -867,6 +891,9 @@ sub commitdelta {
         "git ls-tree -r --full-name $branch | git update-index --index-info");
     }
     doit("git", "update-index", "--add", $deltafile, $idfile);
+    if (defined $signature_file) {
+      doit("git", "update-index", "--add", $sigfile);
+    }
     my $sha = `git write-tree`;
     if ($?) {
       error("git write-tree failed");
@@ -896,6 +923,9 @@ sub commitdelta {
     }
 
     message("committed $deltafile to branch $branch");
+    if (defined $signature_file) {
+      message("committed $sigfile to branch $branch");
+    }
   } else {
     die "unsupported vcs $vcs";
   }
@@ -910,6 +940,9 @@ sub commit {
   }
 
   check_file_exists($tarball);
+  if (defined $signature_file) {
+    check_file_exists($signature_file);
+  }
 
   my $tempdir = tempdir();
   my ($sourcedir, $id) = export($upstream);
@@ -937,7 +970,7 @@ sub checkout {
 
   check_directory_exists(dirname($tarball));
 
-  my ($delta, $id) = checkoutdelta($tarball);
+  my ($delta, $id, $signature) = checkoutdelta($tarball);
   my ($sourcedir, undef) = export($id);
   my $pid = open(GENTAR, "|-");
   if (!$pid) {
@@ -950,6 +983,13 @@ sub checkout {
   print GENTAR $delta;
   close GENTAR || error "failed to generate tarball";
   message("successfully generated $tarball") unless $opts{quiet};
+
+  if (defined $signature_file) {
+    open(OUT, ">$signature_file") || die "$signature_file: $!";
+    print OUT $signature;
+    close OUT;
+    message("successfully generated $signature_file") unless $opts{quiet};
+  }
 }
 
 sub list {
@@ -975,7 +1015,7 @@ sub verify {
 
   check_file_exists($tarball);
 
-  my ($deltadata, $id) = checkoutdelta($tarball);
+  my ($deltadata, $id, undef) = checkoutdelta($tarball);
 
   my $deltafile = File::Temp->new();
   print $deltafile $deltadata;
@@ -988,14 +1028,14 @@ sub verify {
 sub check_directory_exists {
   my $dirname = shift;
   if (!-d $dirname) {
-     error "The directory $dirname does not exist.";
+    error "The directory $dirname does not exist.";
   }
 }
 
 sub check_file_exists {
   my $filename = shift;
   if (!$filename eq "-" and !-f $filename) {
-     error "The file $filename does not exist.";
+    error "The file $filename does not exist.";
   }
 }
 
diff --git a/test/samples/signatures/foo-1.0.tar.gz.asc b/test/samples/signatures/foo-1.0.tar.gz.asc
new file mode 100644
index 0000000..4007584
--- /dev/null
+++ b/test/samples/signatures/foo-1.0.tar.gz.asc
@@ -0,0 +1,16 @@
+-----BEGIN PGP SIGNATURE-----
+
+iQIzBAABCAAdFiEEwv5L0nHBObhsUz5GHpU+J9QxHlgFAlmaJtQACgkQHpU+J9Qx
+Hlhp4w/+Mar21XUcP2rsNXSUl/+bwW87tNGuGSCQscclPuJHz754mQJwFQvVqLT3
+72xL4xwv60+CTOLvH9iFvGGt8oFKBpPOOducPXm/l3J/IkY4B7wuYY6J8ZbFE6ue
+jpC8VFj/JX2jAWrqiF0eC95MIyOtvFO52cr76/7vdmnrUpnY1Bv6dKGb2UQenYjO
+F17Y85ZKugYnuvHy+4dbi4mhTuNUE6tEKwK/kiY3tc5e64b3KkqOvRMjxiW+I7oR
+Be8b2CIKoBbfGOYb5qfE2Fmvd7XqdC/rqoYf/hMm8I4wzJ1IQa1kAnkvtqh0nbbP
+NET1XE8YF80SDfmsslBsbAhH2s+dnJq1kMtyC+0RZN4y/qdcmuXnl2VGtyXFxWgS
+QdoXGFcxmbQOeaPsAFcFAnalyG5sjQT+FfzXeBa2iSamvFz4o/8EyHEvUrXrAieM
+YLFPwd5pvThV4/rB3cHG3Kyw6gxhM5tMAG9a8yHRaGq0r9q7QZJIC2dRMBCuSyTc
+s9zeUgmEVwtpAYLb5ESgmFRU0xiVh3smyks36SuoaiZjknJwkC0LIG/Ptc5c7ZL3
+Bn5uAV8W0f3JeEQJZD7aFlKqOyiaGLfuOmsh1LUSpJov+voRBGxrJK6+Yl60ZQtb
+g9oqBXp6AmGnFwOCImwXD17qQct3qXRn0vmwIki3bxcEY+c8Yvg=
+=ZDm8
+-----END PGP SIGNATURE-----
diff --git a/test/test_checkout.sh b/test/test_checkout.sh
index b661ba9..ad13b75 100644
--- a/test/test_checkout.sh
+++ b/test/test_checkout.sh
@@ -16,4 +16,18 @@ test_checkout_noop() {
   assertTrue "$tarball should not be overwritten" "test '$tarball' -ot NOW"
 }
 
+test_checkout_signature() {
+  local orig_tarball=$SAMPLES/tarballs/foo-1.0.tar.gz
+  local upstream_signature=$SAMPLES/signatures/foo-1.0.tar.gz.asc
+  local tarball=$(basename "$orig_tarball")
+  local signature=$(basename "$upstream_signature")
+
+  git_init pkg
+  import_tarball "$orig_tarball"
+  pristine-tar commit -s "${upstream_signature}" "$orig_tarball"
+  false
+  assertSuccess pristine-tar checkout -s "$signature" "$tarball"
+  assertTrue "$signature generated successfully" "cmp '$upstream_signature' '$signature'"
+}
+
 . shunit2
-- 
2.14.1

Reply via email to