Skip to content

Commit

Permalink
feat(alpine): add digests for apk packages (#4168)
Browse files Browse the repository at this point in the history
  • Loading branch information
DmitriyLewen committed May 10, 2023
1 parent 86f0016 commit b003f58
Show file tree
Hide file tree
Showing 10 changed files with 187 additions and 6 deletions.
6 changes: 6 additions & 0 deletions pkg/digest/digest.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ func (a Algorithm) String() string {
const (
SHA1 Algorithm = "sha1" // sha1 with hex encoding (lower case only)
SHA256 Algorithm = "sha256" // sha256 with hex encoding (lower case only)
MD5 Algorithm = "md5" // md5 with hex encoding (lower case only)
)

// Digest allows simple protection of hex formatted digest strings, prefixed by their algorithm.
Expand All @@ -35,6 +36,11 @@ func NewDigest(alg Algorithm, h hash.Hash) Digest {
return Digest(fmt.Sprintf("%s:%x", alg, h.Sum(nil)))
}

// NewDigestFromString returns a Digest from alg and a string.
func NewDigestFromString(alg Algorithm, h string) Digest {
return Digest(fmt.Sprintf("%s:%s", alg, h))
}

func (d Digest) Algorithm() Algorithm {
return Algorithm(d[:d.sepIndex()])
}
Expand Down
1 change: 1 addition & 0 deletions pkg/fanal/analyzer/analyzer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,7 @@ func TestAnalyzerGroup_AnalyzeFile(t *testing.T) {
SrcName: "musl",
SrcVersion: "1.1.24-r2",
Licenses: []string{"MIT"},
Digest: "sha1:cb2316a189ebee5282c4a9bd98794cc2477a74c6",
},
},
},
Expand Down
32 changes: 32 additions & 0 deletions pkg/fanal/analyzer/pkg/apk/apk.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package apk
import (
"bufio"
"context"
"encoding/base64"
"encoding/hex"
"fmt"
"os"
"path"
Expand All @@ -13,6 +15,7 @@ import (
"github.com/samber/lo"
"golang.org/x/exp/slices"

"github.com/aquasecurity/trivy/pkg/digest"
"github.com/aquasecurity/trivy/pkg/fanal/analyzer"
"github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/licensing"
Expand Down Expand Up @@ -91,6 +94,11 @@ func (a alpinePkgAnalyzer) parseApkInfo(scanner *bufio.Scanner) ([]types.Package
a.parseProvides(line, pkg.ID, provides)
case "D:": // dependencies (corresponds to depend in PKGINFO, concatenated by spaces into a single line)
pkg.DependsOn = a.parseDependencies(line)
case "C:":
d := decodeChecksumLine(line)
if d != "" {
pkg.Digest = d
}
}

if pkg.Name != "" && pkg.Version != "" {
Expand Down Expand Up @@ -206,3 +214,27 @@ func (a alpinePkgAnalyzer) Type() analyzer.Type {
func (a alpinePkgAnalyzer) Version() int {
return analyzerVersion
}

// decodeChecksumLine decodes checksum line
func decodeChecksumLine(line string) digest.Digest {
if len(line) < 2 {
log.Logger.Debugf("Unable to decode checksum line of apk package: %s", line)
return ""
}
// https://wiki.alpinelinux.org/wiki/Apk_spec#Package_Checksum_Field
// https://stackoverflow.com/a/71712569
alg := digest.MD5
d := line[2:]
if strings.HasPrefix(d, "Q1") {
alg = digest.SHA1
d = d[2:] // remove `Q1` prefix
}

decodedDigestString, err := base64.StdEncoding.DecodeString(d)
if err != nil {
log.Logger.Debugf("unable to decode digest: %s", err)
return ""
}
h := hex.EncodeToString(decodedDigestString)
return digest.NewDigestFromString(alg, h)
}
14 changes: 14 additions & 0 deletions pkg/fanal/analyzer/pkg/apk/apk_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ func TestParseApkInfo(t *testing.T) {
SrcName: "musl",
SrcVersion: "1.1.14-r10",
Licenses: []string{"MIT"},
Digest: "sha1:d68b402f35f57750f49156b0cb4e886a2ad35d2d",
},
{
ID: "busybox@1.24.2-r9",
Expand All @@ -35,6 +36,7 @@ func TestParseApkInfo(t *testing.T) {
SrcVersion: "1.24.2-r9",
Licenses: []string{"GPL-2.0"},
DependsOn: []string{"musl@1.1.14-r10"},
Digest: "sha1:ca124719267cd0bedc2f4cb850a286ac13f0ad44",
},
{
ID: "alpine-baselayout@3.0.3-r0",
Expand All @@ -44,6 +46,7 @@ func TestParseApkInfo(t *testing.T) {
SrcVersion: "3.0.3-r0",
Licenses: []string{"GPL-2.0"},
DependsOn: []string{"busybox@1.24.2-r9", "musl@1.1.14-r10"},
Digest: "sha1:a214896150411d72dd1fafdb32d1c6c4855cccfa",
},
{
ID: "alpine-keys@1.1-r0",
Expand All @@ -52,6 +55,7 @@ func TestParseApkInfo(t *testing.T) {
SrcName: "alpine-keys",
SrcVersion: "1.1-r0",
Licenses: []string{"GPL-3.0"},
Digest: "sha1:4def7ffaee6aeba700c1d62570326f75cbb8fa25",
},
{
ID: "zlib@1.2.8-r2",
Expand All @@ -61,6 +65,7 @@ func TestParseApkInfo(t *testing.T) {
SrcVersion: "1.2.8-r2",
Licenses: []string{"Zlib"},
DependsOn: []string{"musl@1.1.14-r10"},
Digest: "sha1:efd04d34d40aa8eb331480127364c27a8ba760ef",
},
{
ID: "libcrypto1.0@1.0.2h-r1",
Expand All @@ -70,6 +75,7 @@ func TestParseApkInfo(t *testing.T) {
SrcVersion: "1.0.2h-r1",
Licenses: []string{"openssl"},
DependsOn: []string{"musl@1.1.14-r10", "zlib@1.2.8-r2"},
Digest: "sha1:65c860ff8f103b664f40ba849a3f5a51c69c8beb",
},
{
ID: "libssl1.0@1.0.2h-r1",
Expand All @@ -78,6 +84,7 @@ func TestParseApkInfo(t *testing.T) {
SrcName: "openssl",
SrcVersion: "1.0.2h-r1",
Licenses: []string{"openssl"},
Digest: "sha1:7120f337e93b2b4c44e0f5f31a15b60dc678ca14",
DependsOn: []string{
"libcrypto1.0@1.0.2h-r1",
"musl@1.1.14-r10",
Expand All @@ -90,6 +97,7 @@ func TestParseApkInfo(t *testing.T) {
SrcName: "apk-tools",
SrcVersion: "2.6.7-r0",
Licenses: []string{"GPL-2.0"},
Digest: "sha1:0990c0acd62b4175818c3a4cc60ed11f14e23bd8",
DependsOn: []string{
"libcrypto1.0@1.0.2h-r1",
"libssl1.0@1.0.2h-r1",
Expand All @@ -104,6 +112,7 @@ func TestParseApkInfo(t *testing.T) {
SrcName: "pax-utils",
SrcVersion: "1.1.6-r0",
Licenses: []string{"GPL-2.0"},
Digest: "sha1:f9bab817c5ad93e92a6218bc0f7596b657c02d90",
DependsOn: []string{"musl@1.1.14-r10"},
},
{
Expand All @@ -113,6 +122,7 @@ func TestParseApkInfo(t *testing.T) {
SrcName: "musl",
SrcVersion: "1.1.14-r10",
Licenses: []string{"MIT", "BSD-3-Clause", "GPL-2.0"},
Digest: "sha1:608aa1dd39eff7bc6615d3e5e33383750f8f5ecc",
DependsOn: []string{
"musl@1.1.14-r10",
"scanelf@1.1.6-r0",
Expand All @@ -125,6 +135,7 @@ func TestParseApkInfo(t *testing.T) {
SrcName: "libc-dev",
SrcVersion: "0.7-r0",
Licenses: []string{"GPL-3.0"},
Digest: "sha1:9055bc7afd76cf2672198042f72fc4a5ed4fa961",
DependsOn: []string{"musl-utils@1.1.14-r10"},
},
{
Expand All @@ -134,6 +145,7 @@ func TestParseApkInfo(t *testing.T) {
SrcName: "pkgconf",
SrcVersion: "1.6.0-r0",
Licenses: []string{"ISC"},
Digest: "sha1:e6242ac29589c8a84a4b179b491ea7c29fce66a9",
DependsOn: []string{"musl@1.1.14-r10"},
},

Expand All @@ -144,6 +156,7 @@ func TestParseApkInfo(t *testing.T) {
SrcName: "sqlite",
SrcVersion: "3.26.0-r3",
Licenses: []string{"Public-Domain"},
Digest: "sha1:1464946c3a5f0dd5a67ca1af930fc17af7a74474",
DependsOn: []string{"musl@1.1.14-r10"},
},

Expand All @@ -154,6 +167,7 @@ func TestParseApkInfo(t *testing.T) {
SrcName: "test-parent",
SrcVersion: "2.9.11_pre20061021-r2",
Licenses: []string{"Public-Domain"},
Digest: "sha1:f0bf315ec54828188910e4a665c00bc48bdbdd7d",
DependsOn: []string{
"pkgconf@1.6.0-r0",
"sqlite-libs@3.26.0-r3",
Expand Down
14 changes: 14 additions & 0 deletions pkg/fanal/artifact/image/image_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ func TestArtifact_Inspect(t *testing.T) {
SrcName: "alpine-baselayout",
SrcVersion: "3.2.0-r3",
Licenses: []string{"GPL-2.0"},
Digest: "sha1:8f373f5b329c3aaf136eb30c63a387661ee0f3d0",
DependsOn: []string{
"busybox@1.31.1-r9",
"musl@1.1.24-r2",
Expand All @@ -53,6 +54,7 @@ func TestArtifact_Inspect(t *testing.T) {
SrcName: "alpine-keys",
SrcVersion: "2.1-r2",
Licenses: []string{"MIT"},
Digest: "sha1:64929f85b7f8b4adbb664d905410312936b79d9b",
},
{
ID: "apk-tools@2.10.4-r3",
Expand All @@ -61,6 +63,7 @@ func TestArtifact_Inspect(t *testing.T) {
SrcName: "apk-tools",
SrcVersion: "2.10.4-r3",
Licenses: []string{"GPL-2.0"},
Digest: "sha1:b15ad0c90e4493dfdc948d6b90a8e020da8936ef",
DependsOn: []string{
"libcrypto1.1@1.1.1d-r3",
"libssl1.1@1.1.1d-r3",
Expand All @@ -75,6 +78,7 @@ func TestArtifact_Inspect(t *testing.T) {
SrcName: "busybox",
SrcVersion: "1.31.1-r9",
Licenses: []string{"GPL-2.0"},
Digest: "sha1:a457703d71654811ea28d8d27a5cfc49ece27b34",
DependsOn: []string{
"musl@1.1.24-r2",
},
Expand All @@ -89,6 +93,7 @@ func TestArtifact_Inspect(t *testing.T) {
"MPL-2.0",
"GPL-2.0",
},
Digest: "sha1:3aeb8a90d7179d2a187782e980a964494e08c5fb",
},
{
ID: "libc-utils@0.7.2-r0",
Expand All @@ -97,6 +102,7 @@ func TestArtifact_Inspect(t *testing.T) {
SrcName: "libc-dev",
SrcVersion: "0.7.2-r0",
Licenses: []string{"BSD-3-Clause"},
Digest: "sha1:a7bf32bd32c6d3de2d1c4d7e753a0919b998cd01",
DependsOn: []string{
"musl-utils@1.1.24-r2",
},
Expand All @@ -108,6 +114,7 @@ func TestArtifact_Inspect(t *testing.T) {
SrcName: "openssl",
SrcVersion: "1.1.1d-r3",
Licenses: []string{"OpenSSL"},
Digest: "sha1:dd8fb9a3cce7b2bcf954271da62fb85dac2b106a",
DependsOn: []string{
"musl@1.1.24-r2",
},
Expand All @@ -119,6 +126,7 @@ func TestArtifact_Inspect(t *testing.T) {
SrcName: "openssl",
SrcVersion: "1.1.1d-r3",
Licenses: []string{"OpenSSL"},
Digest: "sha1:938d46e41b3e56b339a3aeb2d02fad3d75728f35",
DependsOn: []string{
"libcrypto1.1@1.1.1d-r3",
"musl@1.1.24-r2",
Expand All @@ -131,6 +139,7 @@ func TestArtifact_Inspect(t *testing.T) {
SrcName: "libtls-standalone",
SrcVersion: "2.9.1-r0",
Licenses: []string{"ISC"},
Digest: "sha1:b2e5627a56378ea6eeb962a8f33722df9393c1c5",
DependsOn: []string{
"ca-certificates-cacert@20191127-r1",
"libcrypto1.1@1.1.1d-r3",
Expand All @@ -145,6 +154,7 @@ func TestArtifact_Inspect(t *testing.T) {
SrcName: "musl",
SrcVersion: "1.1.24-r2",
Licenses: []string{"MIT"},
Digest: "sha1:cb2316a189ebee5282c4a9bd98794cc2477a74c6",
},
{
ID: "musl-utils@1.1.24-r2",
Expand All @@ -157,6 +167,7 @@ func TestArtifact_Inspect(t *testing.T) {
"BSD-3-Clause",
"GPL-2.0",
},
Digest: "sha1:6d3b45e79dbab444ca7cbfa59e2833203be6fb6a",
DependsOn: []string{
"musl@1.1.24-r2",
"scanelf@1.2.4-r0",
Expand All @@ -169,6 +180,7 @@ func TestArtifact_Inspect(t *testing.T) {
SrcName: "pax-utils",
SrcVersion: "1.2.4-r0",
Licenses: []string{"GPL-2.0"},
Digest: "sha1:d6147beb32bff803b5d9f83a3bec7ab319087185",
DependsOn: []string{
"musl@1.1.24-r2",
},
Expand All @@ -180,6 +192,7 @@ func TestArtifact_Inspect(t *testing.T) {
SrcName: "busybox",
SrcVersion: "1.31.1-r9",
Licenses: []string{"GPL-2.0"},
Digest: "sha1:3b685152af320120ae8941c740d3376b54e43c10",
DependsOn: []string{
"libtls-standalone@2.9.1-r0",
"musl@1.1.24-r2",
Expand All @@ -192,6 +205,7 @@ func TestArtifact_Inspect(t *testing.T) {
SrcName: "zlib",
SrcVersion: "1.2.11-r3",
Licenses: []string{"Zlib"},
Digest: "sha1:acca078ee8baa93e005f57b2fae359c1efd443cd",
DependsOn: []string{
"musl@1.1.24-r2",
},
Expand Down
10 changes: 6 additions & 4 deletions pkg/fanal/artifact/local/fs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func TestArtifact_Inspect(t *testing.T) {
},
putBlobExpectation: cache.ArtifactCachePutBlobExpectation{
Args: cache.ArtifactCachePutBlobArgs{
BlobID: "sha256:fc0c7d225197e1c103784139def1e34b642e8183cf54519cac79dd0cfdd19aba",
BlobID: "sha256:2846219523ad45fe4a17495304ed0a36163f1bd66e7fb0b4c19c5d1d4a966c82",
BlobInfo: types.BlobInfo{
SchemaVersion: types.BlobJSONSchemaVersion,
OS: types.OS{
Expand All @@ -65,6 +65,7 @@ func TestArtifact_Inspect(t *testing.T) {
SrcName: "musl",
SrcVersion: "1.1.24-r2",
Licenses: []string{"MIT"},
Digest: "sha1:cb2316a189ebee5282c4a9bd98794cc2477a74c6",
},
},
},
Expand All @@ -76,9 +77,9 @@ func TestArtifact_Inspect(t *testing.T) {
want: types.ArtifactReference{
Name: "host",
Type: types.ArtifactFilesystem,
ID: "sha256:fc0c7d225197e1c103784139def1e34b642e8183cf54519cac79dd0cfdd19aba",
ID: "sha256:2846219523ad45fe4a17495304ed0a36163f1bd66e7fb0b4c19c5d1d4a966c82",
BlobIDs: []string{
"sha256:fc0c7d225197e1c103784139def1e34b642e8183cf54519cac79dd0cfdd19aba",
"sha256:2846219523ad45fe4a17495304ed0a36163f1bd66e7fb0b4c19c5d1d4a966c82",
},
},
},
Expand Down Expand Up @@ -119,7 +120,7 @@ func TestArtifact_Inspect(t *testing.T) {
},
putBlobExpectation: cache.ArtifactCachePutBlobExpectation{
Args: cache.ArtifactCachePutBlobArgs{
BlobID: "sha256:fc0c7d225197e1c103784139def1e34b642e8183cf54519cac79dd0cfdd19aba",
BlobID: "sha256:2846219523ad45fe4a17495304ed0a36163f1bd66e7fb0b4c19c5d1d4a966c82",
BlobInfo: types.BlobInfo{
SchemaVersion: types.BlobJSONSchemaVersion,
OS: types.OS{
Expand All @@ -137,6 +138,7 @@ func TestArtifact_Inspect(t *testing.T) {
SrcName: "musl",
SrcVersion: "1.1.24-r2",
Licenses: []string{"MIT"},
Digest: "sha1:cb2316a189ebee5282c4a9bd98794cc2477a74c6",
},
},
},
Expand Down
Loading

0 comments on commit b003f58

Please sign in to comment.