Skip to content

Commit

Permalink
[backend] multiple slsa provenance tweaks
Browse files Browse the repository at this point in the history
- rename _slsa_provenance_stmt.json to _slsa_provenance.json
- map urls to api/publish server if configured
- also add the build config to the materials list
- also pin the build config
  • Loading branch information
mlschroe committed Apr 28, 2022
1 parent b4c2e8b commit 19dda9d
Show file tree
Hide file tree
Showing 8 changed files with 102 additions and 28 deletions.
18 changes: 13 additions & 5 deletions src/backend/BSRepServer/SLSA.pm
Original file line number Diff line number Diff line change
Expand Up @@ -103,15 +103,23 @@ sub link_binary {
}

sub link_binaries {
my ($prpa, $digests) = @_;
my ($prpa, $digests, $configs) = @_;

my $gbininfo;
for my $digest (sort keys %$digests) {
next if -e "$slsadir/$prpa/$digest";
mkdir_p("$slsadir/$prpa");
$gbininfo ||= read_gbininfo($prpa);
my $tmp = "$slsadir/$prpa/.incoming$$";
die("404 binary $digests->{$digest} digest $digest does not exist in $prpa\n") unless link_binary($prpa, $gbininfo, $digests->{$digest}, $digest, $tmp);
my $filename = $digests->{$digest};
if ($filename eq '_config') {
if ($configs && $configs->{$digest} && Digest::SHA::sha256_hex($configs->{$digest}) eq $digest) {
writestr($tmp, "$slsadir/$prpa/$digest", $configs->{$digest});
next;
}
die("404 a config with digest $digest does not exist in $prpa\n");
}
$gbininfo ||= read_gbininfo($prpa);
die("404 binary $digests->{$digest} digest $digest does not exist in $prpa\n") unless link_binary($prpa, $gbininfo, $filename, $digest, $tmp);
if (!link($tmp, "$slsadir/$prpa/$digest")) {
my $err = "link $slsadir/$prpa/.incoming$$ $slsadir/$prpa/$digest: $!";
unlink($tmp);
Expand All @@ -126,9 +134,9 @@ sub link_binaries {
}

sub add_references {
my ($prpa, $refprpa, $digests) = @_;
my ($prpa, $refprpa, $digests, $configs) = @_;

link_binaries($prpa, $digests);
link_binaries($prpa, $digests, $configs);
my $h = connectdb($prpa);
BSSQLite::begin_work($h);
my $got = $h->selectcol_arrayref("SELECT digest FROM refs WHERE prpa = ?", undef, $refprpa) || die($h->errstr);
Expand Down
7 changes: 7 additions & 0 deletions src/backend/BSSched/BuildJob.pm
Original file line number Diff line number Diff line change
Expand Up @@ -1221,6 +1221,13 @@ sub create {

}
$binfo->{'slsaprovenance'} = $bconf->{'buildflags:slsaprovenance'} if $bconf->{'buildflags:slsaprovenance'};
if ($binfo->{'slsaprovenance'}) {
if ($BSConfig::sourcepublish_downloadurl) {
$binfo->{'slsadownloadurl'} = "$BSConfig::sourcepublish_downloadurl/_slsa";
} elsif ($BSConfig::api_url) {
$binfo->{'slsadownloadurl'} = $BSConfig::api_url;
}
}
}
$ctx->writejob($job, $binfo, $reason);

Expand Down
1 change: 1 addition & 0 deletions src/backend/BSXML.pm
Original file line number Diff line number Diff line change
Expand Up @@ -644,6 +644,7 @@ our $buildinfo = [
'modularity_yaml', # external

'slsaprovenance', # internal
'slsadownloadurl', # internal

[ 'preinstallimage' =>
'project',
Expand Down
3 changes: 2 additions & 1 deletion src/backend/bs_repserver
Original file line number Diff line number Diff line change
Expand Up @@ -4272,8 +4272,9 @@ sub registry_version {
sub slsa_addrefs {
my ($cgi, $refprpa) = @_;
my $refs = BSUtil::fromstorable(BSServer::read_data(1000000000));
my $configs = delete $refs->{'_config'};
for my $prpa (sort keys %$refs) {
BSRepServer::SLSA::add_references($prpa, $refprpa, $refs->{$prpa});
BSRepServer::SLSA::add_references($prpa, $refprpa, $refs->{$prpa}, $configs);
}
return $BSStdServer::return_ok;
}
Expand Down
20 changes: 14 additions & 6 deletions src/backend/bs_signer
Original file line number Diff line number Diff line change
Expand Up @@ -494,13 +494,21 @@ sub signslaprovenance {
for my $material (@$materials) {
die("bad material in provenance file?\n") unless ref($material) eq 'HASH';
die("bad material uri in provenance file?\n") unless $material->{'uri'};
next unless $material->{'uri'} =~ /^(https?:.*)\/build\/([^\/]+)\/([^\/]+)\/([^\/]+)\/(?:[^\/]+)\/([^\/]+)$/s;
my $server = $1;
my $prpa = "$2/$3/$4";
my $bin = $5;
next unless $material->{'uri'} =~ /\/_?slsa\/([^\/]+)\/([^\/]+)\/([^\/]+)\/(?:[^\/]+)\/([^\/]+)\/([^\/]+)$/s;
my $prpa = "$1/$2/$3";
my $bin = $4;
die("material with bad digest\n") unless ref($material->{'digest'}) eq 'HASH' && $material->{'digest'}->{'sha256'};
$todo{$prpa}->{$material->{'digest'}->{'sha256'}} = $bin;
}
if ($signfile eq '_slsa_provenance.json') {
# also send the config if we have one
my $buildinfo = readxml("$jobdir/_buildenv", 1) || {};
if ($buildinfo->{'config'}) {
my $digest = Digest::SHA::sha256_hex($buildinfo->{'config'});
$todo{'_config'}->{$digest} = $buildinfo->{'config'};
}
}

my $param = {
'uri' => "$BSConfig::srcserver/slsa",
'request' => 'POST',
Expand Down Expand Up @@ -675,7 +683,7 @@ sub signjob {
my $projid = $info->{'project'};
$prpa_stats = "$projid/$info->{'repository'}/$arch";
my @files = sort(ls($jobdir));
my @signfiles = grep {$_ eq '_slsa_provenance_stmt.json' || /\.(?:d?rpm|sha256|iso|pkg\.tar\.gz|pkg\.tar\.xz|pkg\.tar\.zst|rsasign|AppImage|appx|helminfo)$/} @files;
my @signfiles = grep {$_ eq '_slsa_provenance.json' || /\.(?:d?rpm|sha256|iso|pkg\.tar\.gz|pkg\.tar\.xz|pkg\.tar\.zst|rsasign|AppImage|appx|helminfo)$/} @files;
my $needpubkey;
if (grep {$_ eq '.kiwitree_tosign'} @files) {
for my $f (split("\n", readstr("$jobdir/.kiwitree_tosign"))) {
Expand Down Expand Up @@ -723,7 +731,7 @@ sub signjob {

eval {
for my $signfile (@signfiles) {
if ($signfile eq '_slsa_provenance_stmt.json') {
if ($signfile eq '_slsa_provenance.json') {
signslaprovenance($jobstatus, "$jobdir/$signfile", $jobdir, "$projid/$info->{'repository'}/$info->{'arch'}", @signargs);
next;
}
Expand Down
1 change: 1 addition & 0 deletions src/backend/bs_srcserver
Original file line number Diff line number Diff line change
Expand Up @@ -7311,6 +7311,7 @@ sub slsa_addrefs {
my %servers;
for my $prpa (sort keys %$refs) {
my ($projid) = split('/', $prpa);
$projid = (split('/', $refprpa))[0] if $prpa eq '_config'; # keep extra config data
my $proj = BSRevision::readproj_local($projid, 1);
$proj = BSSrcServer::Remote::remoteprojid($projid) if !$proj || $proj->{'remoteurl'};
if ($proj->{'remoteurl'}) {
Expand Down
73 changes: 60 additions & 13 deletions src/backend/bs_worker
Original file line number Diff line number Diff line change
Expand Up @@ -1067,25 +1067,27 @@ sub getsources {
die("getsources: $errors");
}
# verify sources
my @materials;
my %res = map {$_->{'name'} => $_} @$res;
my $md5 = '';
my @f = ls($dir);
for my $f (sort @f) {
die("unexpected file: $f") unless $res{$f};
$md5 .= "$res{$f}->{'md5'} $f\n";
my $sha256sum = sha256file("$dir/$f");
my $uri = BSHTTP::urlencode("$server/source/$buildinfo->{'project'}/$buildinfo->{'package'}/$f")."?rev=$buildinfo->{'srcmd5'}";
push @{$buildinfo->{'materials'}}, { 'uri' => $uri, 'digest' => { 'sha256' => $sha256sum } };
}
$md5 = Digest::MD5::md5_hex($md5);
die("source verification fails: $md5 != $buildinfo->{'verifymd5'}\n") if $md5 ne $buildinfo->{'verifymd5'};

# add to slsa materials list
if ($buildinfo->{'slsaprovenance'}) {
add_slsa_materials_sourcefile($buildinfo, $_, "$dir/$_") for @f;
}

return @meta unless $buildinfo->{'file'} =~ /\.kiwi$/;

# get additional kiwi sources
my @sdep = grep {($_->{'repoarch'} || '') eq 'src'} @{$buildinfo->{'bdep'} || []};
for my $src (@sdep) {
die("additional kiwi sources not implemented for slsa provenance\n") if $buildinfo->{'slsaprovenance'};
print "$src->{'name'}, ";
my $idir = "$src->{'project'}/$src->{'package'}";
$idir = "$dir/images/$idir";
Expand Down Expand Up @@ -2660,9 +2662,7 @@ sub getbinaries {
# sigh, no package information available yet...
$origins->{$_} = "$repoprp/$arch";
}
my $sha256sum = sha256file("$dir/$gotpkg->{'name'}");
my $uri = BSHTTP::urlencode("$server/build/$repo->{'project'}/$repo->{'repository'}/$arch/_repository/$gotpkg->{'name'}");
push @{$buildinfo->{'materials'}}, { 'uri' => $uri, 'digest' => { 'sha256' => $sha256sum } };
add_slsa_materials_binary($buildinfo, "$repo->{'project'}/$repo->{'repository'}/$arch", $gotpkg->{'name'}, "$dir/$gotpkg->{'name'}") if $buildinfo->{'slsaprovenance'};
}
@todo = grep {!$done{"$binaryprefix$_"}} @todo;
}
Expand Down Expand Up @@ -2690,9 +2690,7 @@ sub getbinaries {
# sigh, no package information available yet...
$origins->{$_} = "$repoprp/$arch";
}
my $sha256sum = sha256file("$dir/$gotpkg->{'name'}");
my $uri = BSHTTP::urlencode("$server/build/$repo->{'project'}/$repo->{'repository'}/$arch/_repository/$gotpkg->{'name'}");
push @{$buildinfo->{'materials'}}, { 'uri' => $uri, 'digest' => { 'sha256' => $sha256sum } };
add_slsa_materials_binary($buildinfo, "$repo->{'project'}/$repo->{'repository'}/$arch", $gotpkg->{'name'}, "$dir/$gotpkg->{'name'}") if $buildinfo->{'slsaprovenance'};
}
@todo = grep {!$done{$_}} @todo;
}
Expand Down Expand Up @@ -3261,6 +3259,55 @@ sub generate_slsa_provenance_statement {
return Build::SimpleJSON::unparse($stmt, 'template' => $slsa_json_template, 'keepspecial' => 1);
}

sub add_slsa_materials_sourcefile {
my ($buildinfo, $filename, $localfile) = @_;
my $sha256sum = sha256file($localfile);
my $uri;
if ($buildinfo->{'slsadownloadurl'} && $buildinfo->{'slsadownloadurl'} =~ /(.*)\/_slsa$/) {
# using the source publishing server
my $server = $1;
$uri = BSHTTP::urlencode("$server/$buildinfo->{'project'}/$buildinfo->{'package'}/$buildinfo->{'srcmd5'}/$filename");
} else {
# using the api server
my $server = $buildinfo->{'slsadownloadurl'} || $buildinfo->{'srcserver'} || $srcserver;
$uri = BSHTTP::urlencode("$server/source/$buildinfo->{'project'}/$buildinfo->{'package'}/$filename")."?rev=$buildinfo->{'srcmd5'}";
}
push @{$buildinfo->{'materials'}}, { 'uri' => $uri, 'digest' => { 'sha256' => $sha256sum } };
}

sub add_slsa_materials_binary {
my ($buildinfo, $prpa, $filename, $localfile) = @_;
my $sha256sum = sha256file($localfile);
my $uri;
if ($buildinfo->{'slsadownloadurl'} && $buildinfo->{'slsadownloadurl'} =~ /\/_slsa$/) {
# using the source publishing server
my $server = $buildinfo->{'slsadownloadurl'};
$uri = BSHTTP::urlencode("$server/$prpa/$filename/$sha256sum");
} else {
# using the api server
my $server = $buildinfo->{'slsadownloadurl'} || $buildinfo->{'srcserver'} || $srcserver;
$uri = BSHTTP::urlencode("$server/slsa/$prpa/$filename/$sha256sum");
}
push @{$buildinfo->{'materials'}}, { 'uri' => $uri, 'digest' => { 'sha256' => $sha256sum } };
}

sub add_slsa_materials_config {
my ($buildinfo, $prp, $config) = @_;
my $sha256sum = Digest::SHA::sha256_hex($config);
my ($prpa, $filename) = ("$prp/noarch", '_config');
my $uri;
if ($buildinfo->{'slsadownloadurl'} && $buildinfo->{'slsadownloadurl'} =~ /\/_slsa$/) {
# using the source publishing server
my $server = $buildinfo->{'slsadownloadurl'};
$uri = BSHTTP::urlencode("$server/$prpa/$filename/$sha256sum");
} else {
# using the api server
my $server = $buildinfo->{'slsadownloadurl'} || $buildinfo->{'srcserver'} || $srcserver;
$uri = BSHTTP::urlencode("$server/slsa/$prpa/$filename/$sha256sum");
}
push @{$buildinfo->{'materials'}}, { 'uri' => $uri, 'digest' => { 'sha256' => $sha256sum } };
}

$Build::Kiwi::urlmapper = sub {return '_obsrepositories'} unless $Build::Kiwi::urlmapper;

sub dobuild {
Expand Down Expand Up @@ -3428,7 +3475,7 @@ sub dobuild {
}
$buildinfo->{'outbuildinfo'}->{'config'} = $config;
writestr("$buildroot/.build.config", undef, $config);

add_slsa_materials_config($buildinfo, "$projid/$repoid", $config);

my $bconf = Build::read_config($buildinfo->{'arch'}, "$buildroot/.build.config");
my $useccache = $buildinfo->{'ccache'} ? 1 : 0;
Expand Down Expand Up @@ -4398,10 +4445,10 @@ if ($ex == 0) {
@send = map {{name => (split('/', $_))[-1], filename => $_}} @send;
@send = grep {$_->{'name'} ne '_generated_buildreqs'} @send;

@send = grep {$_->{'name'} !~ /slsa_provenance.json$/} @send;
if ($buildinfo->{'slsaprovenance'}) {
@send = grep {$_->{'name'} ne '_slsa_provenance_stmt.json'} @send;
my $slsa_provenance = generate_slsa_provenance_statement($buildinfo, \@send);
push @send, { 'name' => '_slsa_provenance_stmt.json', 'data' => $slsa_provenance };
push @send, { 'name' => '_slsa_provenance.json', 'data' => $slsa_provenance };
}

if ($kiwitree) {
Expand Down
7 changes: 4 additions & 3 deletions src/backend/t/1000-bs_worker.t
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ my $buildinfo = {
}
],
arch => 'x86_64',
slsaprovenance => 1,
};

$Test::Mock::BSRPC::fixtures_map = {
Expand Down Expand Up @@ -131,19 +132,19 @@ $expected_materials = [
'digest' => {
'sha256' => 'acf63da2befc85cee24689330ddf62629681e59b5007fa3ffca09ff789f7cb28'
},
'uri' => 'http://srcserver/build/openSUSE.org:openSUSE:Tumbleweed/dod/x86_64/_repository/aaa_base.rpm'
'uri' => 'srcserver/slsa/openSUSE.org:openSUSE:Tumbleweed/dod/x86_64/aaa_base.rpm/acf63da2befc85cee24689330ddf62629681e59b5007fa3ffca09ff789f7cb28'
},
{
'digest' => {
'sha256' => 'be546d31264bf3ea084cd6c0bb659872eef0388583983379a72edfb26f021680'
},
'uri' => 'http://srcserver/build/openSUSE.org:openSUSE:Tumbleweed/dod/x86_64/_repository/filesystem.rpm'
'uri' => 'srcserver/slsa/openSUSE.org:openSUSE:Tumbleweed/dod/x86_64/filesystem.rpm/be546d31264bf3ea084cd6c0bb659872eef0388583983379a72edfb26f021680'
},
{
'digest' => {
'sha256' => '80c185cd2f7d2cc9960308a9ce07d97b20c098d7a71008ba7d74dfd1031cfe26'
},
'uri' => 'http://srcserver/build/openSUSE.org:openSUSE:Tumbleweed/dod/x86_64/_repository/liblua5_4-5.rpm'
'uri' => 'srcserver/slsa/openSUSE.org:openSUSE:Tumbleweed/dod/x86_64/liblua5_4-5.rpm/80c185cd2f7d2cc9960308a9ce07d97b20c098d7a71008ba7d74dfd1031cfe26'
}
];
is_deeply($buildinfo->{'materials'}, $expected_materials, "getbinaries- Add 'materials' of binaries to \$buildinfo");
Expand Down

0 comments on commit 19dda9d

Please sign in to comment.