Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package build for openSUSE:Factory checked 
in at 2023-02-10 14:34:02
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/build (Old)
 and      /work/SRC/openSUSE:Factory/.build.new.1848 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "build"

Fri Feb 10 14:34:02 2023 rev:148 rq:1063831 version:20230208

Changes:
--------
--- /work/SRC/openSUSE:Factory/build/build.changes      2023-01-08 
21:25:19.511170708 +0100
+++ /work/SRC/openSUSE:Factory/.build.new.1848/build.changes    2023-02-10 
14:34:04.253472567 +0100
@@ -1,0 +2,8 @@
+Wed Feb  8 11:54:16 UTC 2023 - Adrian Schröter <adr...@suse.de>
+
+- SPDX SBOM generation for container and product builds
+- Revert & Redo "Better filetype detection for temp changes files"
+- Fix typo in glibc hwcaps supplements
+- Implement lua string macros
+
+-------------------------------------------------------------------

Old:
----
  obs-build-20230105.tar.gz

New:
----
  obs-build-20230208.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ build.spec ++++++
--- /var/tmp/diff_new_pack.i1AoN4/_old  2023-02-10 14:34:04.793475794 +0100
+++ /var/tmp/diff_new_pack.i1AoN4/_new  2023-02-10 14:34:04.801475842 +0100
@@ -28,7 +28,7 @@
 Summary:        A Script to Build SUSE Linux RPMs
 License:        GPL-2.0-only OR GPL-3.0-only
 Group:          Development/Tools/Building
-Version:        20230105
+Version:        20230208
 Release:        0
 Source:         obs-build-%{version}.tar.gz
 BuildRoot:      %{_tmppath}/%{name}-%{version}-build

++++++ PKGBUILD ++++++
--- /var/tmp/diff_new_pack.i1AoN4/_old  2023-02-10 14:34:04.849476129 +0100
+++ /var/tmp/diff_new_pack.i1AoN4/_new  2023-02-10 14:34:04.853476153 +0100
@@ -1,5 +1,5 @@
 pkgname=build
-pkgver=20230105
+pkgver=20230208
 pkgrel=0
 pkgdesc="Build packages in sandbox"
 arch=('i686' 'x86_64')

++++++ _service ++++++
--- /var/tmp/diff_new_pack.i1AoN4/_old  2023-02-10 14:34:04.877476296 +0100
+++ /var/tmp/diff_new_pack.i1AoN4/_new  2023-02-10 14:34:04.881476320 +0100
@@ -1,7 +1,7 @@
 <services>
   <service name="tar_scm" mode="manual">
-    <param name="revision">20230105</param>
-    <param name="version">20230105</param>
+    <param name="revision">20230208</param>
+    <param name="version">20230208</param>
     <param name="url">https://github.com/openSUSE/obs-build.git</param>
     <param name="scm">git</param>
     <param name="extract">dist/build.changes</param>

++++++ build.dsc ++++++
--- /var/tmp/diff_new_pack.i1AoN4/_old  2023-02-10 14:34:04.897476415 +0100
+++ /var/tmp/diff_new_pack.i1AoN4/_new  2023-02-10 14:34:04.901476439 +0100
@@ -1,6 +1,6 @@
 Format: 1.0
 Source: build
-Version: 20230105
+Version: 20230208
 Binary: build
 Maintainer: Adrian Schroeter <adr...@suse.de>
 Architecture: all

++++++ debian.changelog ++++++
--- /var/tmp/diff_new_pack.i1AoN4/_old  2023-02-10 14:34:04.929476607 +0100
+++ /var/tmp/diff_new_pack.i1AoN4/_new  2023-02-10 14:34:04.933476631 +0100
@@ -1,4 +1,4 @@
-build (20230105) unstable; urgency=low
+build (20230208) unstable; urgency=low
 
   * Update to current git trunk
     - add sles11sp2 build config and adapt autodetection

++++++ obs-build-20230105.tar.gz -> obs-build-20230208.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/obs-build-20230105/Build/Rpm.pm 
new/obs-build-20230208/Build/Rpm.pm
--- old/obs-build-20230105/Build/Rpm.pm 2023-01-05 13:17:01.000000000 +0100
+++ new/obs-build-20230208/Build/Rpm.pm 2023-02-08 14:13:47.000000000 +0100
@@ -227,6 +227,55 @@
   return \%m;
 }
 
+# no support for most special chars yet
+sub luapattern {
+  my ($pat) = @_;
+  $pat = "\Q$pat\E";
+  $pat =~ s/^\\\^/\^/;
+  $pat =~ s/\\\$/\$/;
+  $pat =~ s/\\\./\./;
+  $pat =~ s/\\\*/\*/;
+  $pat =~ s/\\\-/\*\?/;
+  $pat =~ s/\\\?/\?/;
+  $pat =~ s/\\\+/\+/;
+  $pat =~ s/\\%([%ds])/\\$1/g;
+  return $pat;
+}
+
+sub luamacro {
+  my ($macname, @args) = @_;
+  push @args, '' unless @args;
+  return lc($args[0]) if $macname eq 'lower';
+  return uc($args[0]) if $macname eq 'upper';
+  return length($args[0]) if $macname eq 'len';
+  return reverse($args[0]) if $macname eq 'reverse';
+  return $args[0] x $args[1] if $macname eq 'rep';
+  if ($macname eq 'sub') {
+    push @args, 1 if @args < 2;
+    push @args, -1 if @args < 3;
+    $args[1] -= 1 if $args[1] > 0;
+    $args[1] = length($args[0]) + $args[1] if $args[1] < 0;
+    $args[1] = 0 if $args[1] < 0;
+    $args[2] -= 1 if $args[2] > 0;
+    $args[2] = length($args[0]) + $args[2] if $args[2] < 0;
+    return $args[1] <= $args[2] ? substr($args[0], $args[1], $args[2] - 
$args[1] + 1) : '';
+  }
+  if ($macname eq 'gsub') {
+    return unless @args >= 3;
+    my $pat = luapattern($args[1]);
+    my $rep = $args[3];
+    eval {
+      if (!defined($rep)) {
+        $args[0] =~ s/$pat/$args[2]/g;
+      } else {
+        $args[0] =~ s/$pat(?(?{$rep--<=0})(*F))/$args[2]/g;
+      }
+    };
+    return $@ ? '' : $args[0];
+  }
+  return '';
+}
+
 sub initmacros {
   my ($config, $macros, $macros_args) = @_;
   for my $line (@{$config->{'macros'} || []}) {
@@ -383,6 +432,19 @@
       $macalt = (expr($macalt))[0];
       $macalt =~ s/^[v\"]//;   # stringify
       $expandedline .= $macalt;
+    } elsif ($macname eq 'gsub' || $macname eq 'len' || $macname eq 'lower' || 
$macname eq 'upper' || $macname eq 'rep' || $macname eq 'reverse' || $macname 
eq 'sub') {
+      my @args;
+      if (defined $macalt) {
+       push @args, $macalt;
+      } elsif (defined $macdata)  {
+       push @args, split(' ', $macdata);
+      } else {
+       $line =~ /^\s*([^\n]*).*$/;
+       push @args, split(' ', $1);
+       $line = '';
+      }
+      $_ = expandmacros($config, $_, $lineno, $macros, $macros_args, $tries) 
for @args;
+      $expandedline .= luamacro($macname, @args);
     } elsif (exists($macros->{$macname})) {
       if (!defined($macros->{$macname})) {
        print STDERR "Warning: spec file parser",($lineno?" line 
$lineno":''),": can't expand '$macname'\n" if $config->{'warnings'};
@@ -900,6 +962,7 @@
 ###########################################################################
 
 my %rpmstag = (
+  "SIGMD5"         => 261,
   "SIGTAG_SIZE"    => 1000,     # Header+Payload size in bytes. */
   "SIGTAG_PGP"     => 1002,     # RSA signature over Header+Payload
   "SIGTAG_MD5"     => 1004,     # MD5 hash over Header+Payload
@@ -911,9 +974,12 @@
   "SUMMARY"        => 1004,
   "DESCRIPTION"    => 1005,
   "BUILDTIME"      => 1006,
+  "VENDOR"         => 1011,
   "LICENSE"        => 1014,
   "ARCH"           => 1022,
   "OLDFILENAMES"   => 1027,
+  "FILEMODES"      => 1030,
+  "FILEDIGESTS"    => 1035,
   "SOURCERPM"      => 1044,
   "PROVIDENAME"    => 1047,
   "REQUIREFLAGS"   => 1048,
@@ -944,7 +1010,8 @@
   "OLDENHANCESNAME" => 1159,
   "OLDENHANCESVERSION" => 1160,
   "OLDENHANCESFLAGS" => 1161,
-  "RECOMMENDNAME" => 5046,
+  "FILEDIGESTALGO" => 5011,
+  "RECOMMENDNAME"  => 5046,
   "RECOMMENDVERSION" => 5047,
   "RECOMMENDFLAGS" => 5048,
   "SUGGESTNAME"    => 5049,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/obs-build-20230105/Build/Rpmmd.pm 
new/obs-build-20230208/Build/Rpmmd.pm
--- old/obs-build-20230105/Build/Rpmmd.pm       2023-01-05 13:17:01.000000000 
+0100
+++ new/obs-build-20230208/Build/Rpmmd.pm       2023-02-08 14:13:47.000000000 
+0100
@@ -129,6 +129,7 @@
         'rpm:enhances' =>    { 'rpm:entry' => { _start => \&primary_handle_dep 
, _tag => 'enhances' }, },
         'rpm:obsoletes' =>   { 'rpm:entry' => { _start => \&primary_handle_dep 
, _tag => 'obsoletes' }, },
         'rpm:buildhost' => { _text => 1, _end => \&generic_store_text, _tag => 
'buildhost' },
+        'rpm:vendor' => { _text => 1, _end => \&generic_store_text, _tag => 
'vendor' },
         'rpm:license' => { _text => 1, _end => \&generic_store_text, _tag => 
'license' },
         'rpm:sourcerpm' => { _text => 1, _end => \&primary_handle_sourcerpm , 
_tag => 'source' },
 ### currently commented out, as we ignore file provides in expanddeps
@@ -210,6 +211,7 @@
   }
   delete $data->{'checksum'} unless $options->{'withchecksum'};
   delete $data->{'license'} unless $options->{'withlicense'};
+  delete $data->{'vendor'} unless $options->{'withvendor'};
   return generic_add_result(@_);
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/obs-build-20230105/Makefile 
new/obs-build-20230208/Makefile
--- old/obs-build-20230105/Makefile     2023-01-05 13:17:01.000000000 +0100
+++ new/obs-build-20230208/Makefile     2023-02-08 14:13:47.000000000 +0100
@@ -91,6 +91,7 @@
            download_assets \
            export_debian_orig_from_git \
            unpack_slsa_provenance \
+           generate_sbom \
            $(DESTDIR)$(pkglibdir)
        install -m644 \
            qemu-reg \
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/obs-build-20230105/baselibs_configs/baselibs_global.conf 
new/obs-build-20230208/baselibs_configs/baselibs_global.conf
--- old/obs-build-20230105/baselibs_configs/baselibs_global.conf        
2023-01-05 13:17:01.000000000 +0100
+++ new/obs-build-20230208/baselibs_configs/baselibs_global.conf        
2023-02-08 14:13:47.000000000 +0100
@@ -48,13 +48,13 @@
 targettype x86-64-v4 baselib +^/usr/lib64/(.*\.so.*)$ -> 
/usr/lib64/glibc-hwcaps/x86-64-v4/$1
 targettype x86-64-v2 requires "<match1> = <version>-<release>"
 targettype x86-64-v2 autoreqprov off
-targettype x86-64-v2 supplements "(<match1> = <version> and 
patterns-glibc-hwcaps-x86_64-v2)"
+targettype x86-64-v2 supplements "(<match1> = <version> and 
patterns-glibc-hwcaps-x86-64-v2)"
 targettype x86-64-v3 requires "<match1> = <version>-<release>"
 targettype x86-64-v3 autoreqprov off
-targettype x86-64-v3 supplements "(<match1> = <version> and 
patterns-glibc-hwcaps-x86_64-v3)"
+targettype x86-64-v3 supplements "(<match1> = <version> and 
patterns-glibc-hwcaps-x86-64-v3)"
 targettype x86-64-v4 requires "<match1> = <version>-<release>"
 targettype x86-64-v4 autoreqprov off
-targettype x86-64-v4 supplements "(<match1> = <version> and 
patterns-glibc-hwcaps-x86_64-v4)"
+targettype x86-64-v4 supplements "(<match1> = <version> and 
patterns-glibc-hwcaps-x86-64-v4)"
 post "/sbin/ldconfig"
 
 package /(.*)-debuginfo$/
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/obs-build-20230105/build-recipe-docker 
new/obs-build-20230208/build-recipe-docker
--- old/obs-build-20230105/build-recipe-docker  2023-01-05 13:17:01.000000000 
+0100
+++ new/obs-build-20230208/build-recipe-docker  2023-02-08 14:13:47.000000000 
+0100
@@ -287,6 +287,13 @@
     fi
     rm -rf "$BUILD_ROOT/$TOPDIR/SOURCES/repos/UPLOAD"
 
+    # create sbom if requested
+    if test -n "$(queryconfig --dist "$BUILD_DIST" --configdir "$CONFIG_DIR" 
--archpath "$BUILD_ARCH" buildflags spdx)" ; then
+       echo "Generating sbom file"
+       generate_sbom "$BUILD_ROOT$TOPDIR/DOCKER/$FILENAME.tar" > 
"$BUILD_ROOT$TOPDIR/DOCKER/$FILENAME.sbom.json"
+       test -s "$BUILD_ROOT$TOPDIR/DOCKER/$FILENAME.sbom.json" || rm -f 
"$BUILD_ROOT$TOPDIR/DOCKER/$FILENAME.sbom.json"
+    fi
+ 
     # We're done. Clean up.
     recipe_cleanup_docker
     BUILD_SUCCEEDED=true
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/obs-build-20230105/build-recipe-kiwi 
new/obs-build-20230208/build-recipe-kiwi
--- old/obs-build-20230105/build-recipe-kiwi    2023-01-05 13:17:01.000000000 
+0100
+++ new/obs-build-20230208/build-recipe-kiwi    2023-02-08 14:13:47.000000000 
+0100
@@ -357,6 +357,7 @@
                    mv "$i" $BUILD_ROOT/$TOPDIR/KIWI/.
                    test -n "$milestone" && echo "$milestone" > 
$BUILD_ROOT/$TOPDIR/OTHER/${i%.iso}.milestone ;;
            *.packages) mv $i $BUILD_ROOT/$TOPDIR/OTHER/. ;;
+           *.sbom.json) mv $i $BUILD_ROOT/$TOPDIR/OTHER/. ;;
            *.report)
                mv $i $BUILD_ROOT/$TOPDIR/OTHER/.
                test -n "$milestone" && echo "$milestone" > 
$BUILD_ROOT/$TOPDIR/OTHER/${i%.report}.milestone
@@ -693,7 +694,16 @@
     test -n "$RELEASE" && args=("${args[@]}" --release "$RELEASE")
     for r in $BUILD_ROOT/$TOPDIR/KIWI/*.tar ; do
        test -e "$r" && perl -I$BUILD_DIR -MBuild::Kiwi -e 
Build::Kiwi::showcontainerinfo -- "${args[@]}" 
$BUILD_ROOT/$TOPDIR/SOURCES/$RECIPEFILE "$r" > "${r%.tar}.containerinfo"
-       test -s "${r%.tar}.containerinfo" || rm -f "${r%.tar}.containerinfo"
+       if test -s "${r%.tar}.containerinfo" ; then
+           # create sbom if requested
+           if test -n "$(queryconfig --dist "$BUILD_DIST" --configdir 
"$CONFIG_DIR" --archpath "$BUILD_ARCH" buildflags spdx)" ; then
+               echo "Generating sbom file for ${r##*/}"
+               generate_sbom "$r" > "${r%.tar}.sbom.json"
+               test -s "${r%.tar}.sbom.json" || rm -f "${r%.tar}.sbom.json"
+           fi
+       else
+           rm -f "${r%.tar}.containerinfo"
+       fi
     done
     if test -n "$KIWI_DERIVED_CONTAINER" ; then
        for r in $BUILD_ROOT/$TOPDIR/KIWI/*.packages ; do
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/obs-build-20230105/dist/build.changes 
new/obs-build-20230208/dist/build.changes
--- old/obs-build-20230105/dist/build.changes   2023-01-05 13:17:01.000000000 
+0100
+++ new/obs-build-20230208/dist/build.changes   2023-02-08 14:13:47.000000000 
+0100
@@ -1,4 +1,12 @@
 -------------------------------------------------------------------
+Wed Feb  8 11:54:16 UTC 2023 - Adrian Schröter <adr...@suse.de>
+
+- SPDX SBOM generation for container and product builds
+- Revert & Redo "Better filetype detection for temp changes files"
+- Fix typo in glibc hwcaps supplements
+- Implement lua string macros
+
+-------------------------------------------------------------------
 Mon Jan  2 08:09:43 UTC 2023 - Adrian Schröter <adr...@suse.de>
 
 - configure mkbaselibs to create glibc-hwcaps baselibs as well
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/obs-build-20230105/generate_sbom 
new/obs-build-20230208/generate_sbom
--- old/obs-build-20230105/generate_sbom        1970-01-01 01:00:00.000000000 
+0100
+++ new/obs-build-20230208/generate_sbom        2023-02-08 14:13:47.000000000 
+0100
@@ -0,0 +1,561 @@
+#!/usr/bin/perl
+
+################################################################
+#
+# Copyright (c) 2023 SUSE Linux LLC
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 or 3 as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program (see the file COPYING); if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+#
+################################################################
+
+BEGIN {
+  unshift @INC, ($::ENV{'BUILD_DIR'} || '/usr/lib/build');
+}
+
+use strict;
+
+use File::Find;
+use File::Temp;
+
+use Digest::SHA;
+use Digest::MD5;
+
+use Build::Rpm;
+use Build::SimpleJSON;
+
+my $spdx_json_template = {
+  '_order' => [ qw{spdxVersion dataLicense SPDXID name documentNamespace 
creationInfo packages files relationships} ],
+  'creationInfo' => {
+    '_order' => [ qw{created creators licenseListVersion} ],
+  },
+  'packages' => {
+    '_order' => [ qw{name SPDXID versionInfo originator downloadLocation 
sourceInfo licenseConcluded licenseDeclared copyrightText externalRefs} ],
+    'externalRefs' => {
+      '_order' => [ qw{referenceCategory referenceType referenceLocator} ],
+    },
+  },
+  'files' => {
+    '_order' => [ qw{fileName SPDXID checksums licenseConcluded copyrightText 
comment} ],
+  },
+  'relationships' => {
+    '_order' => [ qw{spdxElementId relatedSpdxElement relationshipType} ],
+  },
+};
+
+my $intoto_json_template = {
+  '_order' => [ qw{_type predicateType subject predicate} ],
+  'subject' => {
+    '_order' => [ qw{name digest} ],
+  },
+  'predicate' => $spdx_json_template,
+};
+
+
+sub urlencode {
+  my ($str, $iscgi) = @_;
+  if ($iscgi) {
+    $str =~ 
s/([\000-\037<>;\"#\?&\+=%[\177-\377])/sprintf("%%%02X",ord($1))/sge;
+    $str =~ tr/ /+/;
+  } else {
+    $str =~ 
s/([\000-\040<>;\"#\?&\+=%[\177-\377])/sprintf("%%%02X",ord($1))/sge;
+  }
+  return $str;
+}
+
+sub rfc3339time {
+  my ($t) = @_;
+  my @gt = gmtime($t || time());
+  return sprintf "%04d-%02d-%02dT%02d:%02d:%02dZ", $gt[5] + 1900, $gt[4] + 1, 
@gt[3,2,1,0];
+}
+
+sub sha256file {
+  my ($fn) = @_;
+  my $ctx = Digest::SHA->new(256);
+  eval { $ctx->addfile($fn) };
+  die("$fn: $@\n") if $@;
+  return $ctx->hexdigest();
+}
+
+sub system_chroot {
+  my ($root, @args) = @_;
+  my $pid = 0;
+  if ($args[0] eq 'exec') {
+    shift @args;
+  } else {
+    $pid = fork();
+    die("fork: $!\n") unless defined $pid;
+  }
+  if (!$pid) {
+    if ($args[0] eq 'quiet') {
+      shift @args;
+      open(STDOUT, '>>', '/dev/null');
+      open(STDERR, '>>', '/dev/null');
+    }
+    if ($args[0] eq 'stdout') {
+      open(STDOUT, '>', $args[1]) || die("$args[1]: $!\n");
+      splice(@args, 0, 2);
+    }
+    !$root || chroot($root) || die("chroot $root: $!\n");
+    exec(@args);
+    die("exec $args[0]: $!\n");
+  }
+  die unless waitpid($pid, 0) == $pid;
+  return $?;
+}
+
+sub popen_chroot {
+  my ($root, @args) = @_;
+
+  my $fd;
+  if (!$root) {
+    open($fd, '-|', @args) || die("open: $!\n");
+    return $fd;
+  }
+  my $pid = open($fd, '-|');
+  die("open: $!\n") unless defined $pid;
+  if ($pid == 0) {
+    !$root || chroot($root) || die("chroot $root: $!\n");
+    exec(@args);
+    die("exec $args[0]: $!\n");
+  }
+  return $fd;
+}
+
+sub can_run {
+  my ($root, $fname) = @_;
+  return 0 if $root && $>;
+  return -x "$root$fname";
+}
+
+sub systemq {
+  my $pid = fork();
+  die("fork: $!\n") unless defined $pid;
+  if (!$pid) {
+    open(STDOUT, '>', '/dev/null') || die("/dev/null: $!\n");
+    exec @_;
+    die("$_[0]: $!\n");
+  }
+  waitpid($pid, 0) == $pid || die("waitpid: $!\n");
+  exit($?) if $?;
+}
+
+sub uncompress_container {
+  my ($container, $outfile) = @_;
+  my @decompressor;
+  if ($container =~ /\.tar$/) {
+    push @decompressor, 'cat';
+  } elsif ($container =~ /\.tar\.gz$/) {
+    push @decompressor, 'gunzip';
+  } elsif ($container =~ /\.tar\.xz$/) {
+    push @decompressor, 'xzdec';
+  } else {
+    die("$container: unknown format\n");
+  }
+  my $pid = fork();
+  die("fork: $!\n") unless defined $pid;
+  if (!$pid) {
+    open(STDIN, '<', $container) || die("$container: $!\n");
+    open(STDOUT, '>', $outfile) || die("$outfile: $!\n");
+    exec @decompressor;
+    die("$decompressor[0]: $!\n");
+  }
+  waitpid($pid, 0) == $pid || die("waitpid: $!\n");
+  exit($?) if $?;
+}
+
+sub unpack_container {
+  my ($dir, $container) = @_;
+  uncompress_container($container, "$dir/cont");
+  systemq('skopeo', 'copy', "docker-archive:$dir/cont", 
"oci:$dir/image:latest");
+  unlink("$dir/cont");
+  systemq('umoci', 'unpack', '--image', "$dir/image:latest", "$dir/unpack");
+  return "$dir/unpack/rootfs";
+}
+
+sub dump_rpmdb {
+  my ($root, $outfile) = @_;
+  my $dbpath;
+  for my $phase (0, 1) {
+    if (can_run($root, '/usr/bin/rpmdb')) {
+      # check if we have the exportdb option
+      if (system_chroot($root, 'quiet', '/usr/bin/rpmdb', '--exportdb', 
'--version') == 0) {
+        if ($dbpath) {
+          system_chroot($root, 'stdout', $outfile, '/usr/bin/rpmdb', 
'--dbpath', $dbpath, '--exportdb');
+        } else {
+          system_chroot($root, 'stdout', $outfile, '/usr/bin/rpmdb', 
'--exportdb');
+        }
+      }
+      exit($?) if $?;
+      return;
+    }
+    # try to get the dbpath from the root if we can
+    if (!$dbpath && can_run($root, '/usr/bin/rpm')) {
+      my $fd = popen_chroot($root, '/usr/bin/rpm', '--eval', '%_dbpath');
+      my $path = <$fd>;
+      close($fd);
+      chomp $path;
+      $dbpath = $path if $path && $path =~ /^\//;
+    }
+    $dbpath ||= '/var/lib/rpm';           # guess
+    # try to dump with rpmdb_dump
+    if (-s "$root$dbpath/Packages" && can_run($root, 
'/usr/lib/rpm/rpmdb_dump')) {
+      my $outfh;
+      open($outfh, '>', $outfile) || die("$outfile: $!\n");
+      my $fd = popen_chroot($root, '/usr/lib/rpm/rpmdb_dump', 
"$dbpath/Packages");
+      while (<$fd>) {
+       next unless /^\s*[0-9a-fA-F]{8}/;
+       chomp;
+       my $v = <$fd>;
+       die("unexpected EOF\n") unless $v;
+       chomp $v;
+       substr($v, 0, 1, '') while substr($v, 0, 1) eq ' ';
+       $v = pack('H*', $v);
+       next if length($v) < 16;
+       my ($il, $dl) = unpack('NN', $v);
+       die("bad header length\n") unless length($v) == 8 + $il * 16 + $dl;
+       die("print: $!\n") unless print $outfh pack('H*', '8eade80100000000');
+       die("print: $!\n") unless print $outfh $v;
+      }
+      close($fd) || die("rpmdb_dump: $!\n");
+      close($outfh) || die("close: $!\n");
+      return;
+    }
+
+    last unless $root;
+    # try with the system rpm and a dbpath
+    $dbpath = "$root$dbpath";
+    $root = '';
+  }
+  die("could not dump rpm database\n");
+}
+
+sub gen_filelist {
+  my ($dir) = @_;
+  my $fd;
+  my $pid = open($fd, '-|');
+  die("fork: $!\n") unless defined $pid;
+  if (!$pid) {
+    chdir($dir) || die("chdir $!\n");
+    exec('find', '-print0');
+    die("find: $!\n");
+  }
+  local $/ = "\0";
+  my @files = <$fd>;
+  chomp @files;
+  close($fd) || die("find: $?\n");
+  $_ =~ s/^\.\//\// for @files;
+  $_ = {'name' => $_} for @files;
+  for my $f (@files) {
+    if (-l "$dir$f->{'name'}" || ! -f _) {
+      $f->{'SKIP'} = 1;
+      next;
+    }
+    $f->{'sha256sum'} = sha256file("$dir/$f->{'name'}");
+  }
+  return \@files;
+}
+
+sub read_rpm {
+  my ($rpm) = @_;
+  my %r = Build::Rpm::rpmq($rpm, qw{NAME VERSION RELEASE EPOCH ARCH LICENSE 
SOURCERPM DISTURL FILENAMES VENDOR FILEMODES FILEDIGESTS FILEDIGESTALGO 
SIGMD5});
+  delete $r{$_} for qw{BASENAMES DIRNAMES DIRINDEXES}; # save mem
+  for (qw{NAME VERSION RELEASE EPOCH ARCH LICENSE SOURCERPM DISTURL VENDOR 
FILEDIGESTALGO SIGMD5}) {
+    next unless $r{$_};
+    die("bad rpm entry for $_\n") unless ref($r{$_}) eq 'ARRAY' && @{$r{$_}} 
== 1;
+    $r{$_} = $r{$_}->[0];
+  }
+  return \%r;
+}
+
+sub read_pkgs_rpmdb {
+  my ($rpmhdrs) = @_;
+  my $fd;
+  open($fd, '<', $rpmhdrs) || die("$rpmhdrs: $!\n");
+  my @rpms;
+  while (1) {
+    my $hdr = '';
+    last unless read($fd, $hdr, 16) == 16;
+    my ($il, $dl) = unpack('@8NN', $hdr);
+    die("bad rpm header\n") unless $il && $dl;
+    die("bad rpm header\n") unless read($fd, $hdr, $il * 16 + $dl, 16) == $il 
* 16 + $dl;
+    push @rpms, read_rpm([ $hdr ]);
+  }
+  close($fd);
+  @rpms = sort {$a->{'NAME'} cmp $b->{'NAME'} || $a->{'VERSION'} cmp 
$b->{'VERSION'} || $a->{'RELEASE'} cmp $b->{'RELEASE'}} @rpms;
+  return \@rpms;
+}
+
+sub read_pkgs_from_product_directory {
+  my ($dir) = @_;
+  my @rpms;
+  my $addrpmfile = sub {
+    my $fn = $File::Find::name;
+    push @rpms, read_rpm($fn) if $fn =~ /\.rpm$/;
+  };
+  find($addrpmfile, $dir);
+  return \@rpms;
+}
+
+sub read_pkgs_from_rpmmd {
+  my ($primaryfile) = @_;
+
+  require Build::Rpmmd;
+  my $fh;
+  if ($primaryfile =~ /\.gz$/) {
+    open($fh, '-|', 'gunzip', '-dc', $primaryfile) || die("$primaryfile: 
$!\n");
+  } else {
+    open($fh, '<', $primaryfile) || die("$primaryfile: $!\n");
+  }
+  my @rpms;
+  for my $pkg (@{Build::Rpmmd::parse($fh, undef, 'withlicense' => 1, 
'withchecksum' => 1, 'withvendor' => 1)}) {
+    my $r = {};
+    for (qw{name epoch version release arch vendor sourcerpm license 
checksum}) {
+      $r->{uc($_)} = $pkg->{$_} if defined $pkg->{$_};
+    }
+    push @rpms, $r;
+  }
+  close($fh);
+  return \@rpms;
+}
+
+sub read_dist {
+  my ($dir) = @_;
+  my %dist;
+  my $fd;
+  if (open($fd, '<', "$dir/etc/os-release") || open($fd, '<', 
"$dir/usr/lib/os-release")) {
+    while(<$fd>) {
+      chomp;
+      next unless /\s*(\S+)=(.*)/;
+      my $k = lc($1);
+      my $v = $2;
+      $v =~ s/\s+$//;
+      $v =~ s/^\"(.*)\"$/$1/;
+      if ($k eq 'id_like') {
+        push @{$dist{$k}}, $v;
+      } else {
+        $dist{$k} = $v;
+      }
+    }
+    close($fd);
+  }
+  return %dist ? \%dist : undef;
+}
+
+sub gen_purl_rpm {
+  my ($p, $distro) = @_;
+
+  my $vr = $p->{'VERSION'};
+  $vr = "$vr-$p->{'RELEASE'}" if defined $p->{'RELEASE'};
+  my $vendor = lc($p->{'VENDOR'});
+  $vendor =~ s/obs:\/\///; # third party OBS builds
+  $vendor =~ s/\ .*//;     # eg. SUSE LLC...
+  $vendor =~ s/\/?$/\//;
+  my $purlurl = "pkg:".urlencode("rpm/$vendor$p->{'NAME'}\@$vr").'?';
+  $purlurl .= '&epoch='.urlencode($p->{'EPOCH'}) if $p->{'EPOCH'};
+  $purlurl .= '&arch='.urlencode($p->{'ARCH'}) if $p->{'ARCH'};
+  $purlurl .= '&upstream='.urlencode($p->{'SOURCERPM'}) if $p->{'SOURCERPM'};
+  $purlurl .= '&distro='.urlencode($distro) if $distro;
+  $purlurl =~ s/\?\&/\?/;
+  $purlurl =~ s/\?$//;
+  return $purlurl;
+}
+
+my $wrap_intoto;
+my $isproduct;
+my $distro;
+my $rpmmd;
+
+while (@ARGV && $ARGV[0] =~ /^-/) {
+  my $opt = shift @ARGV;
+  if ($opt eq '--distro') {
+    $distro = shift @ARGV;
+  } elsif ($opt eq '--intoto') {
+    $wrap_intoto = 1;
+  } elsif ($opt eq '--product') {
+    $isproduct = 1;
+  } elsif ($opt eq '--rpmmd') {
+    $rpmmd = 1;
+  } else {
+    last if $opt eq '--';
+    die("unknown option: $opt\n");
+  }
+}
+
+die("usage: generate_spdx_sbom [--disto NAME] [--intoto] [--product] 
PRODUCT_DIRECTORY|CONTAINER_TAR\n") unless @ARGV == 1;
+my $toprocess = $ARGV[0];
+
+my $tmpdir = File::Temp::tempdir( CLEANUP => 1 );
+
+my $files;
+my $pkgs;
+my $dist;
+if ($isproduct) {
+  # product case
+  #$files = gen_filelist($toprocess);
+  $pkgs = read_pkgs_from_product_directory($toprocess);
+} elsif ($rpmmd) {
+  require Build::Rpmmd;
+  my $primary;
+  if (-d $toprocess) {
+    my %d = map {$_->{'type'} => $_} 
@{Build::Rpmmd::parse_repomd("$toprocess/repomd.xml")};
+    my $primary = $d{'primary'};
+    die("no primary type in repomd.xml\n") unless $primary;
+    my $loc = $primary->{'location'};
+    $loc =~ s/.*\///;
+    $toprocess .= "/$loc";
+  }
+  die("$toprocess: $!\n") unless -e $toprocess;
+  $pkgs = read_pkgs_from_rpmmd($toprocess);
+} else {
+  # container tar case
+  my $unpackdir = unpack_container($tmpdir, $toprocess);
+  dump_rpmdb($unpackdir, "$tmpdir/rpmdb");
+
+  $files = gen_filelist($unpackdir);
+  $pkgs = read_pkgs_rpmdb("$tmpdir/rpmdb");
+  $dist = read_dist($unpackdir);
+}
+
+my $subjectname = $toprocess;
+$subjectname =~ s/.*\///;
+
+if (!$distro && $dist) {
+  $distro = $dist->{'id'};
+  $distro .= "-$dist->{'version_id'}" if defined($dist->{'version_id'}) && 
$dist->{'version_id'} ne '';
+  $distro .= "-$dist->{'build_id'}" if defined($dist->{'build_id'}) && 
$dist->{'build_id'} ne '';
+}
+
+my $spdx = {
+  'spdxVersion' => 'SPDX-2.3',
+  'dataLicense' => 'CC0-1.0',
+  'SPDXID' => 'SPDXRef-DOCUMENT',
+  'name' => $subjectname,
+};
+
+my $creationinfo = {
+  'created' => rfc3339time(time()),
+  'creators' => [ 'Tool: obs_build_generate_spdx_sbom-1.0' ],
+  'licenseListVersion' => '3.19',
+};
+$spdx->{'creationInfo'} = $creationinfo;
+
+for my $p (@$pkgs) {
+  my $vr = $p->{'VERSION'};
+  $vr = "$vr-$p->{'RELEASE'}" if defined $p->{'RELEASE'};
+  my $evr = $vr;
+  $evr = "$p->{'EPOCH'}:$evr" if $p->{'EPOCH'};
+  my $spdxpkg = {
+    'name' => $p->{'NAME'},
+    'versionInfo' => $evr,
+  };
+  $spdxpkg->{'originator'} = "Organization: $p->{'VENDOR'}" if $p->{'VENDOR'};
+  $spdxpkg->{'downloadLocation'} = 'NOASSERTION';
+  $spdxpkg->{'sourceInfo'} = 'acquired package info from RPM DB';
+  $spdxpkg->{'licenseConcluded'} = 'NOASSERTION';
+  $spdxpkg->{'licenseDeclared'} = 'NOASSERTION';
+  my $license = $p->{'LICENSE'};
+  if ($license) {
+    $license =~ s/ and / AND /g;
+    $spdxpkg->{'licenseConcluded'} = $license;
+    $spdxpkg->{'licenseDeclared'} = $license;
+  }
+  $spdxpkg->{'copyrightText'} = 'NOASSERTION';
+  my $purlurl = gen_purl_rpm($p, $distro);
+  my @xref;
+  push @xref, { 'referenceCategory' => 'PACKAGE-MANAGER', 'referenceType' => 
'purl', 'referenceLocator', $purlurl } if $purlurl;
+  $spdxpkg->{'externalRefs'} = \@xref if @xref;
+  if (!$p->{'spdx_id'}) {
+    if ($p->{'SIGMD5'}) {
+      $p->{'spdx_id'} = "SPDXRef-Package-$p->{'NAME'}-".unpack('H*', 
$p->{'SIGMD5'});
+    } elsif ($p->{'CHECKSUM'}) {
+      my $id = $p->{'CHECKSUM'};
+      $id =~ s/.*://;
+      $id = substr($id, 0, 32);
+      $p->{'spdx_id'} = "SPDXRef-Package-$p->{'NAME'}-$id";
+    } else {
+      my $id = Digest::MD5::md5_hex(Build::SimpleJSON::unparse($p));
+      $p->{'spdx_id'} = "SPDXRef-Package-$p->{'NAME'}-$id";
+    }
+    $p->{'spdx_id'} =~ s/[^a-zA-Z0-9\.\-]/-/g;
+  }
+  $spdxpkg->{'SPDXID'} = $p->{'spdx_id'};
+  push @{$spdx->{'packages'}}, $spdxpkg;
+}
+
+for my $f (@$files) {
+  next if $f->{'SKIP'};
+  my $spdxfile = {
+    'fileName' => $f->{'name'},
+    'licenseConcluded' => 'NOASSERTION',
+    'copyrightText' => '',
+  };
+  my @chks;
+  push @chks, { 'algorithm' => 'SHA256', 'checksumValue' => $f->{'sha256sum'} 
} if $f->{'sha256sum'};
+  $spdxfile->{'checksums'} = \@chks if @chks;
+  $f->{'spdx_id'} = 
"SPDXRef-".Digest::MD5::md5_hex($f->{'name'}.($f->{'sha256sum'} || ''));
+  $spdxfile->{'SPDXID'} = $f->{'spdx_id'};
+  push @{$spdx->{'files'}}, $spdxfile;
+}
+
+if (@$files) {
+  my %f2p;
+  for my $p (@$pkgs) {
+    push @{$f2p{$_}}, $p for @{$p->{'FILENAMES'} || []};
+  }
+  for my $f (@$files) {
+    next if $f->{'SKIP'};
+    #warn("unpackaged file: $f->{'name'}\n") unless @{$f2p{$f->{'name'}} || 
[]};
+    for my $p (@{$f2p{$f->{'name'}} || []}) {
+      next unless $f->{'spdx_id'} && $p->{'spdx_id'};
+      my $rel = {
+        'spdxElementId' => $p->{'spdx_id'},
+        'relatedSpdxElement' => $f->{'spdx_id'},
+       'relationshipType', 'CONTAINS',
+      };
+      push @{$spdx->{'relationships'}}, $rel;
+    }
+  }
+}
+
+push @{$spdx->{'relationships'}}, {
+  'spdxElementId' => 'SPDXRef-DOCUMENT',
+  'relatedSpdxElement' => 'SPDXRef-DOCUMENT',
+  'relationshipType', 'DESCRIBES',
+};
+
+my $uuid = pack('H*', '1e9d579964de4594a4e835719a1c259f');     # uuid ns
+$uuid = substr(Digest::SHA::sha1($uuid . Build::SimpleJSON::unparse($spdx, 
'template' => $spdx_json_template, 'keepspecial' => 1)), 0, 16);
+substr($uuid, 6, 1, pack('C', unpack('@6C', $uuid) & 0x0f | 0x50));
+substr($uuid, 8, 1, pack('C', unpack('@8C', $uuid) & 0x3f | 0x80));
+$uuid = join('-', unpack("H8H4H4H4H12", $uuid));
+
+$spdx->{'documentNamespace'} = 
'http://open-build-service.org/spdx/'.urlencode($subjectname).'-'.$uuid;
+
+if ($wrap_intoto) {
+  my $subject = { 'name' => $subjectname };
+  # no digest for products as it might be a directory. And an iso file would 
change the checksum later while signing.
+  $subject->{'digest'} = { 'sha256' => sha256file($toprocess) } unless 
$isproduct;
+  my $intoto = {
+    '_type' => 'https://in-toto.io/Statement/v0.1',
+    'subject' => [ $subject ],
+    'predicateType' => 'https://spdx.dev/Document',
+    'predicate' => $spdx,
+  };
+  print Build::SimpleJSON::unparse($intoto, 'template' => 
$intoto_json_template, 'keepspecial' => 1)."\n";
+} else {
+  print Build::SimpleJSON::unparse($spdx, 'template' => $spdx_json_template, 
'keepspecial' => 1)."\n";
+}
+
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/obs-build-20230105/mkbaselibs 
new/obs-build-20230208/mkbaselibs
--- old/obs-build-20230105/mkbaselibs   2023-01-05 13:17:01.000000000 +0100
+++ new/obs-build-20230208/mkbaselibs   2023-02-08 14:13:47.000000000 +0100
@@ -591,13 +591,18 @@
        if ($rr =~ /^(.*?)\s*->\s*(.*?)$/) {
          $rr = $1;
          my $mrr = $2;
-         for my $f (grep {/$rr/} @rpmfiles) {
-           $files{$f} = 1;
-           $moves{$f} = $mrr;
-           if ($mrr =~ /\$[1-9]/) {
+         if ($mrr =~ /\$[1-9]/) {
+           for my $f (grep {/$rr/} @rpmfiles) {
+             $files{$f} = 1;
+             $moves{$f} = $mrr;
              my @s = $f =~ /$rr/;
              $moves{$f} =~ s/\$([1-9])/$s[$1 - 1]/g;
            }
+         } else {
+           if (grep {$_ eq $rr} @rpmfiles) {
+             $files{$rr} = 1;
+             $moves{$rr} = $mrr;
+           }
          }
        } else {
          for (grep {/$rr/} @rpmfiles) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/obs-build-20230105/obs-docker-support 
new/obs-build-20230208/obs-docker-support
--- old/obs-build-20230105/obs-docker-support   2023-01-05 13:17:01.000000000 
+0100
+++ new/obs-build-20230208/obs-docker-support   2023-02-08 14:13:47.000000000 
+0100
@@ -314,7 +314,11 @@
 }
 
 if test `id -u` != "0"; then
-    echo "obs-docker-support: not executed as root user!"
+    echo <<EOF
+obs-docker-support: not executed as root user!
+
+This can happen if your base container (see FROM line) is setting USER 
already, then builds in dependent container run as that user/group.
+EOF
     exit 1
 fi
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/obs-build-20230105/vc new/obs-build-20230208/vc
--- old/obs-build-20230105/vc   2023-01-05 13:17:01.000000000 +0100
+++ new/obs-build-20230208/vc   2023-02-08 14:13:47.000000000 +0100
@@ -118,7 +118,7 @@
        touch $changelog
 fi
 
-tmpfile=`mktemp -q vctmp.XXXXXX.$changelog`
+tmpfile=`mktemp -q $changelog.vctmp.XXXXXX.changes`
 if [ $? -ne 0 ]; then
        echo "$0: Can't create temp file, exiting..."
        exit 1

Reply via email to