Skip to content

Commit 74dc5b6

Browse files
knqyf263masahiro331tomoyamachilizriceJohannestegner
authored
chore(deps): merge go-dep-parser into Trivy (aquasecurity#6094)
Signed-off-by: Arunprasad Rajkumar <[email protected]> Signed-off-by: guoguangwu <[email protected]> Signed-off-by: dependabot[bot] <[email protected]> Signed-off-by: knqyf263 <[email protected]> Co-authored-by: Masahiro <[email protected]> Co-authored-by: Tomoya Amachi <[email protected]> Co-authored-by: Masahiro <[email protected]> Co-authored-by: Liz Rice <[email protected]> Co-authored-by: Johannes <[email protected]> Co-authored-by: aprp <[email protected]> Co-authored-by: rahul2393 <[email protected]> Co-authored-by: Arunprasad Rajkumar <[email protected]> Co-authored-by: Emrecan BATI <[email protected]> Co-authored-by: sherif84 <[email protected]> Co-authored-by: Sherif Fathalla <[email protected]> Co-authored-by: sherif <[email protected]> Co-authored-by: Sam Lane <[email protected]> Co-authored-by: Ankush K <[email protected]> Co-authored-by: Ankush K <[email protected]> Co-authored-by: Tauseef <[email protected]> Co-authored-by: Daniel <[email protected]> Co-authored-by: Matthieu MOREL <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: afdesk <[email protected]> Co-authored-by: AndreyLevchenko <[email protected]> Co-authored-by: Kobus van Schoor <[email protected]> Co-authored-by: Jan-Otto Kröpke <[email protected]> Co-authored-by: jerbob92 <[email protected]> Co-authored-by: DmitriyLewen <[email protected]> Co-authored-by: Shira Cohen <[email protected]> Co-authored-by: astevenson-microsoft <[email protected]> Co-authored-by: Kyriakos Georgiou <[email protected]> Co-authored-by: mycodeself <[email protected]> Co-authored-by: DavidSalame <[email protected]> Co-authored-by: Tom Fay <[email protected]> Co-authored-by: Tom Fay <[email protected]> Co-authored-by: François Poirotte <[email protected]> Co-authored-by: Guy Ben-Aharon <[email protected]> Co-authored-by: Catminusminus <[email protected]> Co-authored-by: Lior Vaisman Argon <[email protected]> Co-authored-by: Matthieu Maitre <[email protected]> Co-authored-by: Andrea Scarpino <[email protected]> Co-authored-by: MorAlon1 <[email protected]> Co-authored-by: liorj-orca <[email protected]> Co-authored-by: Nikita Pivkin <[email protected]> Co-authored-by: guangwu <[email protected]> Co-authored-by: Nikita Pivkin <[email protected]> Co-authored-by: DmitriyLewen <[email protected]> Co-authored-by: yuriShafet <[email protected]> Co-authored-by: Octogonapus <[email protected]>
1 parent 32a02a9 commit 74dc5b6

File tree

384 files changed

+63319
-79
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

384 files changed

+63319
-79
lines changed

.golangci.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ linters-settings:
1919
locale: US
2020
ignore-words:
2121
- licence
22+
- optimise
2223
gosec:
2324
excludes:
2425
- G101

go.mod

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ require (
1313
github.com/NYTimes/gziphandler v1.1.1
1414
github.com/alicebob/miniredis/v2 v2.31.1
1515
github.com/aquasecurity/bolt-fixtures v0.0.0-20200903104109-d34e7f983986
16-
github.com/aquasecurity/go-dep-parser v0.0.0-20240208080026-8cc7d408bce4
1716
github.com/aquasecurity/go-gem-version v0.0.0-20201115065557-8eed6fe000ce
1817
github.com/aquasecurity/go-npm-version v0.0.0-20201110091526-0b796d180798
1918
github.com/aquasecurity/go-pep440-version v0.0.0-20210121094942-22b2f8951d46
@@ -35,6 +34,7 @@ require (
3534
github.com/aws/aws-sdk-go-v2/service/ecr v1.24.6
3635
github.com/aws/aws-sdk-go-v2/service/s3 v1.48.1
3736
github.com/aws/aws-sdk-go-v2/service/sts v1.26.7
37+
github.com/bitnami/go-version v0.0.0-20231130084017-bb00604d650c
3838
github.com/bmatcuk/doublestar/v4 v4.6.1
3939
github.com/cenkalti/backoff v2.2.1+incompatible
4040
github.com/cheggaaa/pb/v3 v3.1.4
@@ -55,6 +55,7 @@ require (
5555
github.com/google/wire v0.5.0
5656
github.com/hashicorp/go-getter v1.7.3
5757
github.com/hashicorp/go-multierror v1.1.1
58+
github.com/hashicorp/go-retryablehttp v0.7.5
5859
github.com/hashicorp/golang-lru/v2 v2.0.6
5960
github.com/in-toto/in-toto-golang v0.9.0
6061
github.com/knqyf263/go-apk-version v0.0.0-20200609155635-041fdbb8563f
@@ -63,6 +64,7 @@ require (
6364
github.com/knqyf263/go-rpmdb v0.0.0-20231008124120-ac49267ab4e1
6465
github.com/knqyf263/nested v0.0.1
6566
github.com/kylelemons/godebug v1.1.0
67+
github.com/liamg/jfather v0.0.7
6668
github.com/magefile/mage v1.15.0
6769
github.com/mailru/easyjson v0.7.7
6870
github.com/masahiro331/go-disk v0.0.0-20220919035250-c8da316f91ac
@@ -72,6 +74,7 @@ require (
7274
github.com/masahiro331/go-vmdk-parser v0.0.0-20221225061455-612096e4bbbd
7375
github.com/masahiro331/go-xfs-filesystem v0.0.0-20230608043311-a335f4599b70
7476
github.com/mattn/go-shellwords v1.0.12
77+
github.com/microsoft/go-rustaudit v0.0.0-20220808201409-204dfee52032
7578
github.com/mitchellh/hashstructure/v2 v2.0.2
7679
github.com/mitchellh/mapstructure v1.5.0
7780
github.com/moby/buildkit v0.12.5
@@ -104,6 +107,7 @@ require (
104107
go.uber.org/zap v1.26.0
105108
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa
106109
golang.org/x/mod v0.14.0
110+
golang.org/x/net v0.20.0
107111
golang.org/x/sync v0.6.0
108112
golang.org/x/term v0.16.0
109113
golang.org/x/text v0.14.0
@@ -120,19 +124,16 @@ require (
120124
github.com/antchfx/htmlquery v1.3.0
121125
github.com/apparentlymart/go-cidr v1.1.0
122126
github.com/aws/smithy-go v1.19.0
123-
github.com/bitnami/go-version v0.0.0-20231130084017-bb00604d650c
124-
github.com/hashicorp/go-uuid v1.0.3
127+
github.com/hashicorp/go-uuid v1.0.1
125128
github.com/hashicorp/hcl/v2 v2.19.1
126129
github.com/liamg/iamgo v0.0.9
127-
github.com/liamg/jfather v0.0.7
128130
github.com/liamg/memoryfs v1.6.0
129131
github.com/mitchellh/go-homedir v1.1.0
130132
github.com/olekukonko/tablewriter v0.0.5
131133
github.com/owenrumney/squealer v1.2.1
132134
github.com/zclconf/go-cty v1.13.0
133135
github.com/zclconf/go-cty-yaml v1.0.3
134136
golang.org/x/crypto v0.18.0
135-
golang.org/x/net v0.20.0
136137
helm.sh/helm/v3 v3.14.1
137138
)
138139

@@ -318,7 +319,6 @@ require (
318319
github.com/mattn/go-isatty v0.0.19 // indirect
319320
github.com/mattn/go-runewidth v0.0.14 // indirect
320321
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect
321-
github.com/microsoft/go-rustaudit v0.0.0-20220808201409-204dfee52032 // indirect
322322
github.com/miekg/dns v1.1.53 // indirect
323323
github.com/mitchellh/copystructure v1.2.0 // indirect
324324
github.com/mitchellh/go-testing-interface v1.14.1 // indirect

go.sum

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -325,8 +325,6 @@ github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew
325325
github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4=
326326
github.com/aquasecurity/bolt-fixtures v0.0.0-20200903104109-d34e7f983986 h1:2a30xLN2sUZcMXl50hg+PJCIDdJgIvIbVcKqLJ/ZrtM=
327327
github.com/aquasecurity/bolt-fixtures v0.0.0-20200903104109-d34e7f983986/go.mod h1:NT+jyeCzXk6vXR5MTkdn4z64TgGfE5HMLC8qfj5unl8=
328-
github.com/aquasecurity/go-dep-parser v0.0.0-20240208080026-8cc7d408bce4 h1:6qs80w4qPbPnF6GhbIifSANqfCrq90CKtSUBaw6p0z0=
329-
github.com/aquasecurity/go-dep-parser v0.0.0-20240208080026-8cc7d408bce4/go.mod h1:P0PmelcN1ABKJrDzRbPnn6hK7RvgI+xmjiV/9uPaNnY=
330328
github.com/aquasecurity/go-gem-version v0.0.0-20201115065557-8eed6fe000ce h1:QgBRgJvtEOBtUXilDb1MLi1p1MWoyFDXAu5DEUl5nwM=
331329
github.com/aquasecurity/go-gem-version v0.0.0-20201115065557-8eed6fe000ce/go.mod h1:HXgVzOPvXhVGLJs4ZKO817idqr/xhwsTcj17CLYY74s=
332330
github.com/aquasecurity/go-mock-aws v0.0.0-20240109054747-49e4b5da33cb h1:dNxUB2bSbiLGNYcXkbBKrrfuY96+dXhA9FahEFZ4THQ=
@@ -1084,6 +1082,9 @@ github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9n
10841082
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
10851083
github.com/hashicorp/go-getter v1.7.3 h1:bN2+Fw9XPFvOCjB0UOevFIMICZ7G2XSQHzfvLUyOM5E=
10861084
github.com/hashicorp/go-getter v1.7.3/go.mod h1:W7TalhMmbPmsSMdNjD0ZskARur/9GJ17cfHTRtXV744=
1085+
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
1086+
github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c=
1087+
github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
10871088
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
10881089
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
10891090
github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I=
@@ -1098,9 +1099,8 @@ github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoD
10981099
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
10991100
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
11001101
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
1102+
github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE=
11011103
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
1102-
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
1103-
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
11041104
github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek=
11051105
github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
11061106
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
package conan
2+
3+
import (
4+
"fmt"
5+
"io"
6+
"strings"
7+
8+
"github.com/liamg/jfather"
9+
"golang.org/x/exp/slices"
10+
"golang.org/x/xerrors"
11+
12+
dio "github.com/aquasecurity/trivy/pkg/dependency/parser/io"
13+
"github.com/aquasecurity/trivy/pkg/dependency/parser/log"
14+
"github.com/aquasecurity/trivy/pkg/dependency/parser/types"
15+
)
16+
17+
type LockFile struct {
18+
GraphLock GraphLock `json:"graph_lock"`
19+
}
20+
21+
type GraphLock struct {
22+
Nodes map[string]Node `json:"nodes"`
23+
}
24+
25+
type Node struct {
26+
Ref string `json:"ref"`
27+
Requires []string `json:"requires"`
28+
StartLine int
29+
EndLine int
30+
}
31+
32+
type Parser struct{}
33+
34+
func NewParser() types.Parser {
35+
return &Parser{}
36+
}
37+
38+
func (p *Parser) Parse(r dio.ReadSeekerAt) ([]types.Library, []types.Dependency, error) {
39+
var lock LockFile
40+
input, err := io.ReadAll(r)
41+
if err != nil {
42+
return nil, nil, xerrors.Errorf("failed to read canon lock file: %w", err)
43+
}
44+
if err := jfather.Unmarshal(input, &lock); err != nil {
45+
return nil, nil, xerrors.Errorf("failed to decode canon lock file: %w", err)
46+
}
47+
48+
// Get a list of direct dependencies
49+
var directDeps []string
50+
if root, ok := lock.GraphLock.Nodes["0"]; ok {
51+
directDeps = root.Requires
52+
}
53+
54+
// Parse packages
55+
parsed := make(map[string]types.Library)
56+
for i, node := range lock.GraphLock.Nodes {
57+
if node.Ref == "" {
58+
continue
59+
}
60+
lib, err := parseRef(node)
61+
if err != nil {
62+
log.Logger.Debug(err)
63+
continue
64+
}
65+
66+
// Determine if the package is a direct dependency or not
67+
direct := slices.Contains(directDeps, i)
68+
lib.Indirect = !direct
69+
70+
parsed[i] = lib
71+
}
72+
73+
// Parse dependency graph
74+
var libs []types.Library
75+
var deps []types.Dependency
76+
for i, node := range lock.GraphLock.Nodes {
77+
lib, ok := parsed[i]
78+
if !ok {
79+
continue
80+
}
81+
82+
var childDeps []string
83+
for _, req := range node.Requires {
84+
if child, ok := parsed[req]; ok {
85+
childDeps = append(childDeps, child.ID)
86+
}
87+
}
88+
if len(childDeps) != 0 {
89+
deps = append(deps, types.Dependency{
90+
ID: lib.ID,
91+
DependsOn: childDeps,
92+
})
93+
}
94+
95+
libs = append(libs, lib)
96+
}
97+
return libs, deps, nil
98+
}
99+
100+
func parseRef(node Node) (types.Library, error) {
101+
// full ref format: package/version@user/channel#rrev:package_id#prev
102+
// various examples:
103+
// 'pkga/0.1@user/testing'
104+
// 'pkgb/0.1.0'
105+
// 'pkgc/system'
106+
// 'pkgd/0.1.0#7dcb50c43a5a50d984c2e8fa5898bf18'
107+
ss := strings.Split(strings.Split(strings.Split(node.Ref, "@")[0], "#")[0], "/")
108+
if len(ss) != 2 {
109+
return types.Library{}, xerrors.Errorf("Unable to determine conan dependency: %q", node.Ref)
110+
}
111+
return types.Library{
112+
ID: fmt.Sprintf("%s/%s", ss[0], ss[1]),
113+
Name: ss[0],
114+
Version: ss[1],
115+
Locations: []types.Location{
116+
{
117+
StartLine: node.StartLine,
118+
EndLine: node.EndLine,
119+
},
120+
},
121+
}, nil
122+
}
123+
124+
// UnmarshalJSONWithMetadata needed to detect start and end lines of deps
125+
func (n *Node) UnmarshalJSONWithMetadata(node jfather.Node) error {
126+
if err := node.Decode(&n); err != nil {
127+
return err
128+
}
129+
// Decode func will overwrite line numbers if we save them first
130+
n.StartLine = node.Range().Start.Line
131+
n.EndLine = node.Range().End.Line
132+
return nil
133+
}
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
package conan_test
2+
3+
import (
4+
"os"
5+
"sort"
6+
"strings"
7+
"testing"
8+
9+
"github.com/stretchr/testify/assert"
10+
"github.com/stretchr/testify/require"
11+
12+
"github.com/aquasecurity/trivy/pkg/dependency/parser/c/conan"
13+
"github.com/aquasecurity/trivy/pkg/dependency/parser/types"
14+
)
15+
16+
func TestParse(t *testing.T) {
17+
tests := []struct {
18+
name string
19+
inputFile string // Test input file
20+
wantLibs []types.Library
21+
wantDeps []types.Dependency
22+
}{
23+
{
24+
name: "happy path",
25+
inputFile: "testdata/happy.lock",
26+
wantLibs: []types.Library{
27+
{
28+
ID: "pkga/0.0.1",
29+
Name: "pkga",
30+
Version: "0.0.1",
31+
Locations: []types.Location{
32+
{
33+
StartLine: 13,
34+
EndLine: 22,
35+
},
36+
},
37+
},
38+
{
39+
ID: "pkgb/system",
40+
Name: "pkgb",
41+
Version: "system",
42+
Indirect: true,
43+
Locations: []types.Location{
44+
{
45+
StartLine: 23,
46+
EndLine: 29,
47+
},
48+
},
49+
},
50+
{
51+
ID: "pkgc/0.1.1",
52+
Name: "pkgc",
53+
Version: "0.1.1",
54+
Locations: []types.Location{
55+
{
56+
StartLine: 30,
57+
EndLine: 35,
58+
},
59+
},
60+
},
61+
},
62+
wantDeps: []types.Dependency{
63+
{
64+
ID: "pkga/0.0.1",
65+
DependsOn: []string{
66+
"pkgb/system",
67+
},
68+
},
69+
},
70+
},
71+
{
72+
name: "happy path. lock file with revisions support",
73+
inputFile: "testdata/happy2.lock",
74+
wantLibs: []types.Library{
75+
{
76+
ID: "openssl/3.0.3",
77+
Name: "openssl",
78+
Version: "3.0.3",
79+
Locations: []types.Location{
80+
{
81+
StartLine: 12,
82+
EndLine: 22,
83+
},
84+
},
85+
},
86+
{
87+
ID: "zlib/1.2.12",
88+
Name: "zlib",
89+
Version: "1.2.12",
90+
Indirect: true,
91+
Locations: []types.Location{
92+
{
93+
StartLine: 23,
94+
EndLine: 30,
95+
},
96+
},
97+
},
98+
},
99+
wantDeps: []types.Dependency{
100+
{
101+
ID: "openssl/3.0.3",
102+
DependsOn: []string{
103+
"zlib/1.2.12",
104+
},
105+
},
106+
},
107+
},
108+
{
109+
name: "happy path. lock file without dependencies",
110+
inputFile: "testdata/empty.lock",
111+
},
112+
{
113+
name: "sad path. wrong ref format",
114+
inputFile: "testdata/sad.lock",
115+
},
116+
}
117+
118+
for _, tt := range tests {
119+
t.Run(tt.name, func(t *testing.T) {
120+
f, err := os.Open(tt.inputFile)
121+
require.NoError(t, err)
122+
defer f.Close()
123+
124+
gotLibs, gotDeps, err := conan.NewParser().Parse(f)
125+
require.NoError(t, err)
126+
127+
sort.Slice(gotLibs, func(i, j int) bool {
128+
ret := strings.Compare(gotLibs[i].Name, gotLibs[j].Name)
129+
if ret != 0 {
130+
return ret < 0
131+
}
132+
return gotLibs[i].Version < gotLibs[j].Version
133+
})
134+
135+
assert.Equal(t, tt.wantLibs, gotLibs)
136+
assert.Equal(t, tt.wantDeps, gotDeps)
137+
})
138+
}
139+
}

0 commit comments

Comments
 (0)