Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(alpine): add digests for apk packages #4168

Merged
merged 11 commits into from
May 10, 2023
1 change: 1 addition & 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 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
28 changes: 28 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,23 @@ func (a alpinePkgAnalyzer) Type() analyzer.Type {
func (a alpinePkgAnalyzer) Version() int {
return analyzerVersion
}

// decodeChecksumLine decodes checksum line
func decodeChecksumLine(line string) digest.Digest {
// https://wiki.alpinelinux.org/wiki/Apk_spec#Package_Checksum_Field
// https://stackoverflow.com/a/71712569
alg := digest.MD5
d := line[2:]
knqyf263 marked this conversation as resolved.
Show resolved Hide resolved
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.Digest(fmt.Sprintf("%s:%s", alg, h))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if adding digest.NewDigestFromString(alg Algorithm, h string) or something like that?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done - d579f5d

}
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