Files
gentoo/dev-util/kup/files/kup-server-putraw.patch
Sam James 710c24ff43 dev-util/kup: add putraw command
This is from robbat2 for infra use, as we don't want the recompression
behaviour. From https://wiki.gentoo.org/wiki/Project:Infrastructure/Project_Distfiles#Outstanding_Issues_before_Launch
> Implement putraw command that does NOT decompress tar files to sign the underlying .tar;
> this is needed for uploading external files where the original checksum is important to Gentoo,
> and re-compression would alter that.

Add this in the ebuild for more testing.

Signed-off-by: Sam James <sam@gentoo.org>
2026-03-31 20:34:59 +01:00

303 lines
9.2 KiB
Diff

https://github.com/robbat2/kup/pull/1
From ee7223a8eea366ae8c39450f25272f3006732abb Mon Sep 17 00:00:00 2001
From: "Robin H. Johnson" <rjohnson@coreweave.com>
Date: Wed, 11 Mar 2026 21:39:06 -0700
Subject: [PATCH] feat: putraw command
Signed-off-by: Robin H. Johnson <rjohnson@coreweave.com>
---
kup | 46 ++++++++++++++++++++++++++++++++++++
kup-server | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++
kup-server.1 | 9 ++++++-
kup.1 | 46 +++++++++++++++++++++++++++++-------
4 files changed, 158 insertions(+), 10 deletions(-)
diff --git a/kup b/kup
index f3a5d0f..bdb37c5 100755
--- a/kup
+++ b/kup
@@ -93,6 +93,7 @@ sub usage($) {
print STDERR " put local_file signature remote_path\n";
print STDERR " put --tar [--prefix=] remote_tree ref signature remote_path\n";
print STDERR " put --diff remote_tree ref1 ref2 signature remote_path\n";
+ print STDERR " putraw local_file signature remote_path\n";
print STDERR " mkdir remote_path\n";
print STDERR " mv|move old_path new_path\n";
print STDERR " ln|link old_path new_path\n";
@@ -474,6 +475,49 @@ sub cmd_put()
command('PUT', url_encode($remote));
}
+# PUTRAW command - upload a file exactly as-is without recompression
+sub cmd_putraw()
+{
+ my $file = shift @args;
+
+ if ($file =~ /^-/) {
+ die "$0: unknown option to putraw command: $file\n";
+ }
+
+ # Upload the file as-is; force plain ('%') format so the server stores
+ # exactly the bytes we have locally without decompressing.
+ cat_file('DATA', $file, '%');
+
+ # Get the local filename without directory
+ my($vol, $dir, $file_tail);
+ ($vol, $dir, $file_tail) = File::Spec->splitpath($file);
+
+ my $sign = shift @args;
+ my $remote = shift @args;
+
+ if (!defined($remote)) {
+ usage(1);
+ }
+
+ # Allow trailing slash to use local filename
+ if ($remote =~ m:/$: && defined($file_tail)) {
+ $remote .= $file_tail;
+ }
+
+ my $xrt = $remote;
+ $remote = canonicalize_path($remote);
+ if (!is_valid_filename($remote)) {
+ die "$0: invalid pathname: $xrt\n";
+ }
+
+ if ($remote =~ /\.sign$/) {
+ die "$0: target filename cannot end in .sign\n";
+ }
+
+ cat_file('SIGN', $sign, undef);
+ command('PUTRAW', url_encode($remote));
+}
+
# MKDIR command
sub cmd_mkdir()
{
@@ -601,6 +645,8 @@ sub process_commands()
if ($cmd eq 'put') {
cmd_put();
+ } elsif ($cmd eq 'putraw') {
+ cmd_putraw();
} elsif ($cmd eq 'mkdir') {
cmd_mkdir();
} elsif ($cmd eq 'move' || $cmd eq 'mv') {
diff --git a/kup-server b/kup-server
index 8bdab50..ba326fa 100755
--- a/kup-server
+++ b/kup-server
@@ -30,6 +30,8 @@
# - updates the current signature blob (follows immediately)
# PUT pathname
# - installs the current data blob as <pathname>
+# PUTRAW pathname
+# - installs the current data blob as <pathname> without recompression
# MKDIR pathname
# - creates a new directory
# MOVE old-path new-path
@@ -903,6 +905,69 @@ sub put_file(@)
cleanup();
}
+sub putraw_file(@)
+{
+ my @args = @_;
+
+ if (scalar(@args) != 1) {
+ fatal("Bad PUTRAW command");
+ }
+
+ my($file) = @args;
+
+ if (!$have_data) {
+ fatal("PUTRAW without DATA");
+ }
+ if (!$have_sign) {
+ fatal("PUTRAW without SIGN");
+ }
+
+ if (!signature_valid()) {
+ fatal("Signature invalid");
+ }
+
+ if (!is_valid_filename($file)) {
+ fatal("Invalid filename in PUTRAW command");
+ }
+
+ if ($file =~ /\.sign$/) {
+ fatal("$file: Target filename cannot end in .sign");
+ }
+
+ make_timestamps_match();
+
+ # Log SHA256 of the raw (as-uploaded) file
+ my $sha = Digest::SHA->new('sha256');
+ print STDERR "\rCalculating sha256 for ".$file." ";
+ $sha->addfile($tmpdir.'/data');
+ syslog(LOG_NOTICE, "sha256: %s: %s", $file, $sha->hexdigest);
+ print STDERR "... logged.\n";
+
+ lock_tree();
+
+ foreach my $e ('', '.sign') {
+ if (-e $data_path.$file.$e && ! -f _) {
+ fatal("$file: Trying to overwrite a non-file");
+ }
+ }
+
+ my @install_ext = ('.sign', '');
+ my @undoes = ();
+ foreach my $e (@install_ext) {
+ my $target = $data_path.$file.$e;
+ if (!rename($tmpdir.'/data'.$e, $target)) {
+ my $err = $!;
+ unlink(@undoes);
+ $! = $err;
+ fatal("$file: Failed to install files: $!");
+ }
+ push(@undoes, $target);
+ }
+
+ unlock_tree();
+ cleanup();
+}
+
sub do_mkdir(@)
{
my @args = @_;
@@ -1305,6 +1370,8 @@ while (defined($line = get_command())) {
get_sign_data(@args);
} elsif ($cmd eq 'PUT') {
put_file(@args);
+ } elsif ($cmd eq 'PUTRAW') {
+ putraw_file(@args);
} elsif ($cmd eq 'MKDIR') {
do_mkdir(@args);
} elsif ($cmd eq 'MOVE' || $cmd eq 'LINK') {
diff --git a/kup-server.1 b/kup-server.1
index 2143090..6dd8ec7 100644
--- a/kup-server.1
+++ b/kup-server.1
@@ -28,6 +28,12 @@ for specific tree access control. On the client side, a corresponding
client-side utility
.BR kup
is used to initiate the connection and perform the uploads.
+.PP
+Uploaded files must be accompanied by a PGP detached signature. For
+the \fBPUT\fP command the signature covers the uncompressed content and
+the server generates all configured compression formats. For the
+\fBPUTRAW\fP command the signature covers the file exactly as uploaded,
+and the server stores it verbatim without recompression.
.SH GLOBAL CONFIG
.PP
The configuration file for
@@ -127,4 +133,5 @@ or (at your option) any later version; incorporated herein by
reference. There is NO warranty; not even for MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
.SH "SEE ALSO"
-.BR kup (1)
+.BR kup (1),
+.BR kup-proto (5)
diff --git a/kup.1 b/kup.1
index 811afb3..6ad8210 100644
--- a/kup.1
+++ b/kup.1
@@ -18,9 +18,13 @@ kup \- kernel.org upload utility
.PP
This utility is used to upload files to \fIkernel.org\fP and other
systems using the same upload system (\fBkup-server\fP). Each upload
-is required to have a PGP signature, and the server will generate
-multiple compressed formats if the content uploaded is intended to be
-compressed.
+is required to have a PGP signature. For the
+.B put
+command, the server will generate multiple compressed formats if the
+content uploaded is intended to be compressed. For the
+.B putraw
+command, the file is stored exactly as uploaded without any
+recompression.
.PP
Additionally, if the user has content from a
.BR git (1)
@@ -68,15 +72,19 @@ or if not set, no subcommand will be used (default kup-server behavior).
A series of commands can be specified on a single command line,
separated by a double dash argument (\fB\-\-\fP).
.PP
-In all cases, PGP signatures are detached signature files
+For the \fBput\fP command, PGP signatures are detached signature files
corresponding to the \fIuncompressed\fP content. If a
-\fIremote_path\fP ends in \fP\.gz\fP then
+\fIremote_path\fP ends in \fB\.gz\fP then
.BR gzip ,
.B bzip2
and
.B xz
compressed files are generated on the server; otherwise the content is
stored uncompressed.
+.PP
+For the \fBputraw\fP command, the PGP signature must correspond to the
+exact bytes of \fIlocal_file\fP as uploaded. The file is stored
+verbatim at \fIremote_path\fP with no recompression.
.TP
\fBput\fP \fIlocal_file\fP \fPsignature_file\fP \fIremote_path\fP
Upload the file \fIlocal_file\fP signed with
@@ -111,6 +119,14 @@ version of
.B git
locally as on the server in order to produce a valid signature.
.TP
+\fBputraw\fP \fIlocal_file\fP \fIsignature_file\fP \fIremote_path\fP
+Upload the file \fIlocal_file\fP signed with \fIsignature_file\fP and
+store it at \fIremote_path\fP exactly as-is, without any
+decompression or recompression. The signature must cover the exact
+bytes of \fIlocal_file\fP. Unlike \fBput\fP, the remote filename
+extension is not remapped and no additional compression formats are
+generated.
+.TP
\fBmkdir\fP \fIremote_path\fP
Create a new directory on the server.
.TP
@@ -139,10 +155,10 @@ relative to the \fIold_path\fP minus the final component. Similarly,
if \fInew_path\fP ends in a slash then the final component of
\fIold_path\fP will be appended.
.PP
-For the \fPput\fP command, except when \fB\-\-tar\fP or \fB\-\-diff\fP
-is specified, if the \fIremote_path\fP ends in a slash then the
-final (filename) component of \fIlocal_file\fP will be appended to the
-final pathname.
+For the \fBput\fP command, except when \fB\-\-tar\fP or \fB\-\-diff\fP
+is specified, and for the \fBputraw\fP command, if the \fIremote_path\fP
+ends in a slash then the final (filename) component of \fIlocal_file\fP
+will be appended to the final pathname.
.SH CONFIG FILE
Kup checks the presence of $HOME/.kuprc and can load the
.B host
@@ -174,6 +190,16 @@ kup put foolib-1.0.tar.bz2 foolib-1.0.tar.asc /pub/foolib/foolib-1.0.tar.bz2
.fi
.RE
.PP
+Upload a pre-built tarball exactly as-is (e.g. a release artifact that
+must not be altered), signing the compressed file directly:
+.PP
+.RS
+.nf
+gpg --detach-sign --armor foolib-1.0.tar.gz
+kup putraw foolib-1.0.tar.gz foolib-1.0.tar.gz.asc /pub/foolib/foolib-1.0.tar.gz
+.fi
+.RE
+.PP
Generate a tarball locally, sign it, then tell kup-server to generate an
identical tarball on the server, verify the signature, and put the compressed
results in /pub/foolib:
@@ -197,6 +223,8 @@ or (at your option) any later version; incorporated herein by
reference. There is NO warranty; not even for MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
.SH "SEE ALSO"
+.BR kup-proto (5),
+.BR kup-server (1),
.BR git (1),
.BR ssh (1),
.BR gzip (1),