Skip to content

Commit

Permalink
Merge pull request #342 from micahhausler/rpm-scanner
Browse files Browse the repository at this point in the history
Add RPM image scanner
  • Loading branch information
k8s-ci-robot authored Sep 14, 2023
2 parents 1e7573a + d4fae86 commit 69afd10
Show file tree
Hide file tree
Showing 12 changed files with 506 additions and 139 deletions.
2 changes: 1 addition & 1 deletion cmd/bom/cmd/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ completed by a later stage in your CI/CD pipeline. See the
&genOpts.scanImages,
"scan-images",
true,
"scan container images to look for OS information (currently debian only)",
"scan container images to look for OS information (currently debian, alpine, and rpm only)",
)

generateCmd.PersistentFlags().StringVar(
Expand Down
10 changes: 10 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ module sigs.k8s.io/bom
go 1.20

require (
github.com/glebarez/go-sqlite v1.20.3
github.com/go-git/go-git/v5 v5.9.0
github.com/google/go-containerregistry v0.16.1
github.com/google/licenseclassifier/v2 v2.0.0
github.com/google/uuid v1.3.1
github.com/in-toto/in-toto-golang v0.9.0
github.com/knqyf263/go-rpmdb v0.0.0-20230723082926-067d98befa60
github.com/nozzle/throttler v0.0.0-20180817012639-2ea982251481
github.com/sirupsen/logrus v1.9.3
github.com/spf13/cobra v1.7.0
Expand All @@ -28,18 +30,26 @@ require (
github.com/blang/semver/v4 v4.0.0 // indirect
github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be // indirect
github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/golang/snappy v0.0.3 // indirect
github.com/klauspost/pgzip v1.2.5 // indirect
github.com/mattn/go-isatty v0.0.17 // indirect
github.com/mattn/go-runewidth v0.0.9 // indirect
github.com/mholt/archiver/v3 v3.5.1 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/nwaples/rardecode v1.1.0 // indirect
github.com/pierrec/lz4/v4 v4.1.2 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230126093431-47fa9a501578 // indirect
github.com/ulikunitz/xz v0.5.9 // indirect
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
golang.org/x/tools v0.13.0 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
modernc.org/libc v1.22.2 // indirect
modernc.org/mathutil v1.5.0 // indirect
modernc.org/memory v1.5.0 // indirect
modernc.org/sqlite v1.20.3 // indirect
)

require (
Expand Down
23 changes: 23 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ github.com/docker/docker-credential-helpers v0.7.0/go.mod h1:rETQfLdHNT3foU5kuNk
github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 h1:iFaUwBSo5Svw6L7HYpRu/0lE3e0BaElwnNO1qkNQxBY=
github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5/go.mod h1:qssHWj60/X5sZFNxpG4HBPDHVqxNm4DfnCKgrbZOT+s=
github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/glebarez/go-sqlite v1.20.3 h1:89BkqGOXR9oRmG58ZrzgoY/Fhy5x0M+/WV48U5zVrZ4=
github.com/glebarez/go-sqlite v1.20.3/go.mod h1:u3N6D/wftiAzIOJtZl6BmedqxmmkDfH3q+ihjqxC9u0=
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU=
Expand All @@ -47,6 +51,7 @@ github.com/google/go-containerregistry v0.16.1 h1:rUEt426sR6nyrL3gt+18ibRcvYpKYd
github.com/google/go-containerregistry v0.16.1/go.mod h1:u0qB2l7mvtWVR5kNcbFIhFY1hLbf8eeGapA+vbFDCtQ=
github.com/google/licenseclassifier/v2 v2.0.0 h1:1Y57HHILNf4m0ABuMVb6xk4vAJYEUO0gDxNpog0pyeA=
github.com/google/licenseclassifier/v2 v2.0.0/go.mod h1:cOjbdH0kyC9R22sdQbYsFkto4NGCAc+ZSwbeThazEtM=
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ=
github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/in-toto/in-toto-golang v0.9.0 h1:tHny7ac4KgtsfrG6ybU8gVOZux2H8jN05AXJ9EBM1XU=
Expand All @@ -62,6 +67,8 @@ github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQs
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE=
github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
github.com/knqyf263/go-rpmdb v0.0.0-20230723082926-067d98befa60 h1:kTBDRI2BJvNYFjMcOH5zskWS5QYDqUDE0owFpb38Vng=
github.com/knqyf263/go-rpmdb v0.0.0-20230723082926-067d98befa60/go.mod h1:9LQcoMCMQ9vrF7HcDtXfvqGO4+ddxFQ8+YF/0CVGDww=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
Expand All @@ -71,6 +78,8 @@ github.com/magefile/mage v1.15.0 h1:BvGheCMAsG3bWUDbZ8AyXXpCNwU9u5CB6sM+HNb9HYg=
github.com/magefile/mage v1.15.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A=
github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA=
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/maxbrunsfeld/counterfeiter/v6 v6.7.0 h1:z0CfPybq3CxaJvrrpf7Gme1psZTqHhJxf83q6apkSpI=
Expand Down Expand Up @@ -98,6 +107,9 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/remyoudompheng/bigfft v0.0.0-20230126093431-47fa9a501578 h1:VstopitMQi3hZP0fzvnsLmzXZdQGc4bEcgu24cp+d4M=
github.com/remyoudompheng/bigfft v0.0.0-20230126093431-47fa9a501578/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sclevine/spec v1.4.0 h1:z/Q9idDcay5m5irkZ28M7PtQM4aOISzOpj4bUPkDee8=
Expand Down Expand Up @@ -149,6 +161,7 @@ golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220906165534-d0df966e6959/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
Expand All @@ -161,6 +174,8 @@ golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58
golang.org/x/tools/go/vcs v0.1.0-deprecated h1:cOIJqWBl99H1dH5LWizPa+0ImeeJq3t3cJjaeOWUAL4=
golang.org/x/tools/go/vcs v0.1.0-deprecated/go.mod h1:zUrvATBAvEI9535oC0yWYsLsHIV4Z7g63sNPVMtuBy8=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
Expand All @@ -179,5 +194,13 @@ gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0=
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 h1:HNSDgDCrr/6Ly3WEGKZftiE7IY19Vz2GdbOCyI4qqhc=
k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
modernc.org/libc v1.22.2 h1:4U7v51GyhlWqQmwCHj28Rdq2Yzwk55ovjFrdPjs8Hb0=
modernc.org/libc v1.22.2/go.mod h1:uvQavJ1pZ0hIoC/jfqNoMLURIMhKzINIWypNM17puug=
modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ=
modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/memory v1.5.0 h1:N+/8c5rE6EqugZwHii4IFsaJ7MUhoWX07J5tC/iI5Ds=
modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
modernc.org/sqlite v1.20.3 h1:SqGJMMxjj1PHusLxdYxeQSodg7Jxn9WWkaAQjKrntZs=
modernc.org/sqlite v1.20.3/go.mod h1:zKcGyrICaxNTMEHSr1HQ2GUraP0j+845GYw37+EyT6A=
sigs.k8s.io/release-utils v0.7.5-0.20230707140704-1bf6b4c5d954 h1:6UHf2P+yurMG0iMLk1XA7pFHI+7Fg02UxMGs8VmUKuM=
sigs.k8s.io/release-utils v0.7.5-0.20230707140704-1bf6b4c5d954/go.mod h1:T5b2rUC28a7miTkatQ3jogupUQqb+CGn1HBfoW83p40=
2 changes: 2 additions & 0 deletions pkg/osinfo/container_scanner.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ func ReadOSPackages(layers []string) (
cs = newDebianScanner()
case OSAlpine, OSWolfi:
cs = newAlpineScanner()
case OSAmazonLinux, OSFedora, OSRHEL:
cs = newRPMScanner()
default:
return 0, nil, nil
}
Expand Down
136 changes: 0 additions & 136 deletions pkg/osinfo/container_scanner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,69 +17,11 @@ limitations under the License.
package osinfo

import (
"fmt"
"net/url"
"strings"
"testing"

purl "github.com/package-url/packageurl-go"
"github.com/stretchr/testify/require"
)

func TestReadDebianPackages(t *testing.T) {
ct := newDebianScanner()
for _, tc := range []struct {
layers []string
targetLayer int
numPackages int
shouldErr bool
nilPackages bool // Packages are nil when a layer has an unexptected OS
}{
// Two versions of DB in each layer
{[]string{"testdata/dpkg-layer1.tar.gz", "testdata/dpkg-layer2.tar.gz"}, 1, 87, false, false},
// Only one layer, one DB with 83 packages
{[]string{"testdata/dpkg-layer1.tar.gz"}, 0, 83, false, false},
// First layer no data, second with 87 packages
{[]string{"testdata/link-with-no-dots.tar.gz", "testdata/dpkg-layer2.tar.gz"}, 1, 87, false, false},
// The inverse
{[]string{"testdata/dpkg-layer2.tar.gz", "testdata/link-with-no-dots.tar.gz"}, 0, 87, false, false},
// One layer, no packages, unsupported OS
{[]string{"testdata/link-with-no-dots.tar.gz"}, 0, 0, false, true},
} {
layerNum, packages, err := ct.ReadOSPackages(tc.layers)
require.Equal(t, tc.targetLayer, layerNum)
if !tc.shouldErr {
require.NoError(t, err)
} else {
require.Error(t, err)
}

// Check if packages should be nil:
if tc.nilPackages {
require.Nil(t, packages)
} else {
require.NotNil(t, packages)
require.Len(t, *packages, tc.numPackages)
}
}
}

func TestParseDpkDb(t *testing.T) {
_, packages, err := ReadOSPackages([]string{
"testdata/link-with-no-dots.tar.gz", // The first layer contains the OS Info
"testdata/dpkg-layer1.tar.gz", // The second layer contains the dpkg database
})

require.NoError(t, err)

require.Equal(t, "bash", (*packages)[4].Package)
require.Equal(t, "amd64", (*packages)[4].Architecture)
require.Equal(t, "5.0-4", (*packages)[4].Version)
require.Equal(t, "http://tiswww.case.edu/php/chet/bash/bashtop.html", (*packages)[4].HomePage)
require.Equal(t, "Matthias Klose", (*packages)[4].MaintainerName)
require.Equal(t, "doko@debian.org", (*packages)[4].MaintainerEmail)
}

func TestReadOSPackages(t *testing.T) {
layer, packages, err := ReadOSPackages([]string{
"testdata/link-with-no-dots.tar.gz", // The first layer contains the OS Info
Expand All @@ -97,81 +39,3 @@ func TestReadOSPackages(t *testing.T) {
_, _, err = ReadOSPackages([]string{"testdata/nonexistent"})
require.Error(t, err)
}

func TestPackageURL(t *testing.T) {
for _, tc := range []struct {
dbe PackageDBEntry
expected string
}{
{
// Emtpty db entry
dbe: PackageDBEntry{},
expected: "",
},
{
// Only package
dbe: PackageDBEntry{Package: "test"},
expected: "",
},
{
// Emtpty db entry
dbe: PackageDBEntry{
Package: "test", Namespace: "osname",
},
expected: "",
},
{
// Tyoe missing
dbe: PackageDBEntry{
Package: "test", Version: "v1.0.0", Namespace: "osname",
},
expected: "",
},
{
// Minimum elements
dbe: PackageDBEntry{
Package: "test", Version: "v1.0.0", Type: purl.TypeDebian, Namespace: "osname",
},
expected: "pkg:deb/osname/test@v1.0.0",
},
{
// All but type
dbe: PackageDBEntry{
Package: "test", Version: "v1.0.0", Architecture: "amd64",
Type: purl.TypeDebian, Namespace: "osname",
},
expected: "pkg:deb/osname/test@v1.0.0?arch=amd64",
},
} {
p := tc.dbe.PackageURL()
require.Equal(t, tc.expected, p)
if p == "" {
continue
}
parsed, err := url.Parse(p)
require.NoError(t, err)
require.Equal(t, "pkg", parsed.Scheme)
require.True(t, strings.HasPrefix(p, fmt.Sprintf(
"pkg:%s/%s/%s@%s", tc.dbe.Type, tc.dbe.Namespace,
tc.dbe.Package, tc.dbe.Version,
)))
require.Equal(t, tc.dbe.Architecture, parsed.Query().Get("arch"))
}
}

func TestParseApkDB(t *testing.T) {
ct := newAlpineScanner()

// Test we have the expected packages
pk, err := ct.ParseDB("testdata/apkdb")
require.NoError(t, err)
require.NotNil(t, pk)
require.Len(t, *pk, 39)

// Test package data
require.Equal(t, "ca-certificates-bundle", (*pk)[0].Package)
require.Equal(t, "20220614-r2", (*pk)[0].Version)
require.Equal(t, "x86_64", (*pk)[0].Architecture)
require.Equal(t, "MPL-2.0 AND MIT", (*pk)[0].License)
require.Equal(t, "e07d34854d632d6491a45dd854cdabd177e990cc", (*pk)[0].Checksums["SHA1"])
}
74 changes: 74 additions & 0 deletions pkg/osinfo/layer_scanner.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ type layerScanner interface {
OSType(layerPath string) (ostype OSType, err error)
OSReleaseData(layerPath string) (osrelease string, err error)
ExtractFileFromTar(tarPath, filePath, destPath string) error
FileExistsInTar(tarPath, filePath string) (bool, error)
}

// newLayerScanner returns a LayerScanner.
Expand Down Expand Up @@ -142,6 +143,79 @@ func (e ErrFileNotFoundInTar) Error() string {
return "file not found in tarball"
}

// FileExistsInTar finds a file in a tarball.
func (loss *layerOSScanner) FileExistsInTar(tarPath, filePath string) (bool, error) {
// Open the tar file
f, err := os.Open(tarPath)
if err != nil {
return false, fmt.Errorf("opening tarball: %w", err)
}
defer f.Close()

// Read the first bytes to determine if the file is compressed
var sample [3]byte
var gzipped bool
if _, err := io.ReadFull(f, sample[:]); err != nil {
return false, fmt.Errorf("sampling bytes from file header: %w", err)
}
if _, err := f.Seek(0, 0); err != nil {
return false, fmt.Errorf("rewinding read pointer: %w", err)
}

// From: https://github.com/golang/go/blob/1fadc392ccaefd76ef7be5b685fb3889dbee27c6/src/compress/gzip/gunzip.go#L185
if sample[0] == 0x1f && sample[1] == 0x8b && sample[2] == 0x08 {
gzipped = true
}

const dotSl = "./"
filePath = strings.TrimPrefix(filePath, dotSl)

var tr *tar.Reader
tr = tar.NewReader(f)
if gzipped {
gzf, err := gzip.NewReader(f)
if err != nil {
return false, fmt.Errorf("creating gzip reader: %w", err)
}
tr = tar.NewReader(gzf)
}

// Search for the os-file in the tar contents
for {
hdr, err := tr.Next()
if err == io.EOF {
return false, ErrFileNotFoundInTar{}
}
if err != nil {
return false, fmt.Errorf("reading tarfile: %w", err)
}

if hdr.FileInfo().IsDir() {
continue
}

// Scan for the os-release file in the tarball
if strings.TrimPrefix(hdr.Name, dotSl) == filePath {
// If this is a symlink, follow:
if hdr.FileInfo().Mode()&os.ModeSymlink == os.ModeSymlink {
target := hdr.Linkname
// Check if its relative:
if !strings.HasPrefix(target, string(filepath.Separator)) {
newTarget := filepath.Dir(filePath)

//nolint:gosec // This is not zipslip, path it not used for writing just
// to search a file in the tarfile, the extract path is fexed.
newTarget = filepath.Join(newTarget, hdr.Linkname)
target = filepath.Clean(newTarget)
}
logrus.Infof("%s is a symlink, following to %s", filePath, target)
return loss.FileExistsInTar(tarPath, target)
}
return true, nil
}
}
}

// extractFileFromTar extracts filePath from tarPath and stores it in destPath
func (loss *layerOSScanner) ExtractFileFromTar(tarPath, filePath, destPath string) error {
// Open the tar file
Expand Down
4 changes: 2 additions & 2 deletions pkg/osinfo/layer_scanner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import (
)

func TestExtractFileFromTar(t *testing.T) {
loss := &layerOSScanner{}
loss := newLayerScanner()

file, err := os.CreateTemp("", "extract-")
require.NoError(t, err)
Expand Down Expand Up @@ -57,7 +57,7 @@ func TestExtractFileFromTar(t *testing.T) {
}

func TestOSReleaseData(t *testing.T) {
loss := &layerOSScanner{}
loss := newLayerScanner()
data, err := loss.OSReleaseData("testdata/link-with-dots.tar.gz")
require.NoError(t, err)
require.NotEmpty(t, data)
Expand Down
Loading

0 comments on commit 69afd10

Please sign in to comment.