Skip to content

Commit

Permalink
chore: refactor and apply review fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
dus7eh committed Apr 3, 2024
1 parent 5cb6032 commit 650bf9c
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 38 deletions.
10 changes: 6 additions & 4 deletions docs/docs/coverage/language/c.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# C/C++

Trivy supports [Conan][conan] C/C++ Package Manager.
Trivy supports Conan C/C++ Package Manager ([v1][conanV1] and [v2][conanV2] with limitations).

The following scanners are supported.

Expand All @@ -12,12 +12,14 @@ The following table provides an outline of the features Trivy offers.

| Package manager | File | Transitive dependencies | Dev dependencies | [Dependency graph][dependency-graph] | Position |
| --------------- | -------------- | :---------------------: | :--------------: | :----------------------------------: | :------: |
| Conan | conan.lock[^1] | | Excluded |||
| Conan | conan.lock[^1] |[^2] | Excluded |||

## Conan
In order to detect dependencies, Trivy searches for `conan.lock`[^1].

[conan]: https://docs.conan.io/1/index.html
[conanV1]: https://docs.conan.io/1/index.html
[conanV2]: https://docs.conan.io/2/
[dependency-graph]: ../../configuration/reporting.md#show-origins-of-vulnerable-dependencies

[^1]: `conan.lock` is default name. To scan a custom filename use [file-patterns](../../configuration/skipping.md#file-patterns)
[^1]: `conan.lock` is default name. To scan a custom filename use [file-patterns](../../configuration/skipping.md#file-patterns)
[^2]: For `conan.lock` in version 2, indirect dependencies are included in analysis but not flagged explicitly in dependency tree
74 changes: 40 additions & 34 deletions pkg/dependency/parser/c/conan/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@ import (
xio "github.com/aquasecurity/trivy/pkg/x/io"
)

type LockFileV1 struct {
type LockFile struct {
GraphLock GraphLock `json:"graph_lock"`
Requires Requires `json:"requires"`
}

type GraphLock struct {
Expand All @@ -30,17 +31,21 @@ type Node struct {
EndLine int
}

type LockFileV2 struct {
Requires []string `json:"requires"`
type Require struct {
Dependency string
StartLine int
EndLine int
}

type Requires []Require

type Parser struct{}

func NewParser() types.Parser {
return &Parser{}
}

func (p *Parser) parseRequirementsV1(lock LockFileV1) ([]types.Library, []types.Dependency, error) {
func (p *Parser) parseV1(lock LockFile) ([]types.Library, []types.Dependency, error) {
var libs []types.Library
var deps []types.Dependency
var directDeps []string
Expand All @@ -54,7 +59,7 @@ func (p *Parser) parseRequirementsV1(lock LockFileV1) ([]types.Library, []types.
if node.Ref == "" {
continue
}
lib, err := parseRefV1(node)
lib, err := toLibrary(node.Ref, node.StartLine, node.EndLine)
if err != nil {
log.Logger.Debug(err)
continue
Expand Down Expand Up @@ -92,38 +97,40 @@ func (p *Parser) parseRequirementsV1(lock LockFileV1) ([]types.Library, []types.
return libs, deps, nil
}

func (p *Parser) parseRequirementsV2(lock LockFileV2) ([]types.Library, []types.Dependency, error) {
func (p *Parser) parseV2(lock LockFile) ([]types.Library, []types.Dependency, error) {
var libs []types.Library

for _, req := range lock.Requires {
lib, _ := parseRefV2(req)
lib, err := toLibrary(req.Dependency, req.StartLine, req.EndLine)
if err != nil {
log.Logger.Debug(err)
continue
}

libs = append(libs, lib)
}
return libs, []types.Dependency{}, nil
}

func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, error) {
var lockV1 LockFileV1
var lockV2 LockFileV2
var lock LockFile

input, err := io.ReadAll(r)
if err != nil {
return nil, nil, xerrors.Errorf("failed to read conan lock file: %w", err)
}

// try to parse requirements as conan v1.x
if err := jfather.Unmarshal(input, &lockV1); err != nil {
if err := jfather.Unmarshal(input, &lock); err != nil {
return nil, nil, xerrors.Errorf("failed to decode conan lock file: %w", err)
}
if lockV1.GraphLock.Nodes != nil {

// try to parse requirements as conan v1.x
if lock.GraphLock.Nodes != nil {
log.Logger.Debug("Handling conan lockfile as v1.x")
return p.parseRequirementsV1(lockV1)
return p.parseV1(lock)
} else {
// try to parse requirements as conan v2.x
log.Logger.Debug("Handling conan lockfile as v2.x")
if err := jfather.Unmarshal(input, &lockV2); err != nil {
return nil, nil, xerrors.Errorf("failed to decode conan lock file: %w", err)
}
return p.parseRequirementsV2(lockV2)
return p.parseV2(lock)
}
}

Expand All @@ -141,8 +148,8 @@ func parsePackage(text string) (string, string, error) {
return ss[0], ss[1], nil
}

func parseRefV1(node Node) (types.Library, error) {
name, version, err := parsePackage(node.Ref)
func toLibrary(pkg string, startLine int, endLine int) (types.Library, error) {

Check failure on line 151 in pkg/dependency/parser/c/conan/parse.go

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest)

paramTypeCombine: func(pkg string, startLine int, endLine int) (types.Library, error) could be replaced with func(pkg string, startLine, endLine int) (types.Library, error) (gocritic)

Check failure on line 151 in pkg/dependency/parser/c/conan/parse.go

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest)

paramTypeCombine: func(pkg string, startLine int, endLine int) (types.Library, error) could be replaced with func(pkg string, startLine, endLine int) (types.Library, error) (gocritic)
name, version, err := parsePackage(pkg)
if err != nil {
return types.Library{}, err
}
Expand All @@ -152,25 +159,13 @@ func parseRefV1(node Node) (types.Library, error) {
Version: version,
Locations: []types.Location{
{
StartLine: node.StartLine,
EndLine: node.EndLine,
StartLine: startLine,
EndLine: endLine,
},
},
}, nil
}

func parseRefV2(req string) (types.Library, error) {
name, version, err := parsePackage(req)
if err != nil {
return types.Library{}, err
}
return types.Library{
ID: dependency.ID(ftypes.Conan, name, version),
Name: name,
Version: version,
}, nil
}

// UnmarshalJSONWithMetadata needed to detect start and end lines of deps
func (n *Node) UnmarshalJSONWithMetadata(node jfather.Node) error {
if err := node.Decode(&n); err != nil {
Expand All @@ -181,3 +176,14 @@ func (n *Node) UnmarshalJSONWithMetadata(node jfather.Node) error {
n.EndLine = node.Range().End.Line
return nil
}

func (r *Require) UnmarshalJSONWithMetadata(node jfather.Node) error {
var dep string
if err := node.Decode(&dep); err != nil {
return err
}
r.Dependency = dep
r.StartLine = node.Range().Start.Line
r.EndLine = node.Range().End.Line
return nil
}
12 changes: 12 additions & 0 deletions pkg/dependency/parser/c/conan/parse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,11 +113,23 @@ func TestParse(t *testing.T) {
ID: "matrix/1.3",
Name: "matrix",
Version: "1.3",
Locations: []types.Location{
{
StartLine: 5,
EndLine: 5,
},
},
},
{
ID: "sound32/1.0",
Name: "sound32",
Version: "1.0",
Locations: []types.Location{
{
StartLine: 4,
EndLine: 4,
},
},
},
},
wantDeps: []types.Dependency{},
Expand Down

0 comments on commit 650bf9c

Please sign in to comment.