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: add support for conan.lock file #2779

Merged
merged 21 commits into from Sep 6, 2022
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/semantic-pr.yaml
Expand Up @@ -64,6 +64,8 @@ jobs:
dotnet
java
go
c
c++

os
lang
Expand Down
33 changes: 17 additions & 16 deletions docs/docs/vulnerability/detection/data-source.md
Expand Up @@ -19,22 +19,23 @@

# Programming Language

| Language | Source | Commercial Use | Delay[^1]|
| ---------------------------- | ----------------------------------------------------|:---------------:|:--------:|
| PHP | [PHP Security Advisories Database][php] | ✅ | - |
| | [GitHub Advisory Database (Composer)][php-ghsa] | ✅ | - |
| Python | [GitHub Advisory Database (pip)][python-ghsa] | ✅ | - |
| | [Open Source Vulnerabilities (PyPI)][python-osv] | ✅ | - |
| Ruby | [Ruby Advisory Database][ruby] | ✅ | - |
| | [GitHub Advisory Database (RubyGems)][ruby-ghsa] | ✅ | - |
| Node.js | [Ecosystem Security Working Group][nodejs] | ✅ | - |
| | [GitHub Advisory Database (npm)][nodejs-ghsa] | ✅ | - |
| Java | [GitLab Advisories Community][gitlab] | ✅ | 1 month |
| | [GitHub Advisory Database (Maven)][java-ghsa] | ✅ | - |
| Go | [GitLab Advisories Community][gitlab] | ✅ | 1 month |
| | [The Go Vulnerability Database][go] | ✅ | - |
| Rust | [Open Source Vulnerabilities (crates.io)][rust-osv] | ✅ | - |
| .NET | [GitHub Advisory Database (NuGet)][dotnet-ghsa] | ✅ | - |
| Language | Source | Commercial Use | Delay[^1]|
|----------|-----------------------------------------------------|:---------------:|:--------:|
| PHP | [PHP Security Advisories Database][php] | ✅ | - |
| | [GitHub Advisory Database (Composer)][php-ghsa] | ✅ | - |
| Python | [GitHub Advisory Database (pip)][python-ghsa] | ✅ | - |
| | [Open Source Vulnerabilities (PyPI)][python-osv] | ✅ | - |
| Ruby | [Ruby Advisory Database][ruby] | ✅ | - |
| | [GitHub Advisory Database (RubyGems)][ruby-ghsa] | ✅ | - |
| Node.js | [Ecosystem Security Working Group][nodejs] | ✅ | - |
| | [GitHub Advisory Database (npm)][nodejs-ghsa] | ✅ | - |
| Java | [GitLab Advisories Community][gitlab] | ✅ | 1 month |
| | [GitHub Advisory Database (Maven)][java-ghsa] | ✅ | - |
| Go | [GitLab Advisories Community][gitlab] | ✅ | 1 month |
| | [The Go Vulnerability Database][go] | ✅ | - |
| Rust | [Open Source Vulnerabilities (crates.io)][rust-osv] | ✅ | - |
| .NET | [GitHub Advisory Database (NuGet)][dotnet-ghsa] | ✅ | - |
| C/C++ | [GitLab Advisories Community][gitlab] | ✅ | 1 month |

[^1]: Intentional delay between vulnerability disclosure and registration in the DB

Expand Down
48 changes: 25 additions & 23 deletions docs/docs/vulnerability/detection/language.md
Expand Up @@ -2,29 +2,30 @@

`Trivy` automatically detects the following files in the container and scans vulnerabilities in the application dependencies.

| Language | File | Image[^8] | Rootfs[^9] | Filesystem[^10] | Repository[^11] | Dev dependencies |
| -------- |-------------------------| :-------: | :--------: | :-------------: | :-------------: | ---------------- |
| Ruby | Gemfile.lock | - | - | ✅ | ✅ | included |
| | gemspec | ✅ | ✅ | - | - | included |
| Python | Pipfile.lock | - | - | ✅ | ✅ | excluded |
| | poetry.lock | - | - | ✅ | ✅ | included |
| | requirements.txt | - | - | ✅ | ✅ | included |
| | egg package[^1] | ✅ | ✅ | - | - | excluded |
| | wheel package[^2] | ✅ | ✅ | - | - | excluded |
| PHP | composer.lock | ✅ | ✅ | ✅ | ✅ | excluded |
| Node.js | package-lock.json | - | - | ✅ | ✅ | excluded |
| | yarn.lock | - | - | ✅ | ✅ | included |
| | pnpm-lock.yaml | - | - | ✅ | ✅ | excluded |
| | package.json | ✅ | ✅ | - | - | excluded |
| .NET | packages.lock.json | ✅ | ✅ | ✅ | ✅ | included |
| | packages.config | ✅ | ✅ | ✅ | ✅ | excluded |
| | .deps.json | ✅ | ✅ | ✅ | ✅ | excluded |
| Java | JAR/WAR/PAR/EAR[^3][^4] | ✅ | ✅ | - | - | included |
| | pom.xml[^5] | - | - | ✅ | ✅ | excluded |
| Go | Binaries built by Go[^6] | ✅ | ✅ | - | - | excluded |
| | go.mod[^7] | - | - | ✅ | ✅ | included |
| Rust | Cargo.lock | ✅ | ✅ | ✅ | ✅ | included |
| | Binaries built with [cargo-auditable](https://github.com/rust-secure-code/cargo-auditable) | ✅ | ✅ | - | - | excluded
| Language | File | Image[^8] | Rootfs[^9] | Filesystem[^10] | Repository[^11] | Dev dependencies |
|----------|--------------------------------------------------------------------------------------------| :-------: | :--------: | :-------------: | :-------------: | ---------------- |
| Ruby | Gemfile.lock | - | - | ✅ | ✅ | included |
| | gemspec | ✅ | ✅ | - | - | included |
| Python | Pipfile.lock | - | - | ✅ | ✅ | excluded |
| | poetry.lock | - | - | ✅ | ✅ | included |
| | requirements.txt | - | - | ✅ | ✅ | included |
| | egg package[^1] | ✅ | ✅ | - | - | excluded |
| | wheel package[^2] | ✅ | ✅ | - | - | excluded |
| PHP | composer.lock | ✅ | ✅ | ✅ | ✅ | excluded |
| Node.js | package-lock.json | - | - | ✅ | ✅ | excluded |
| | yarn.lock | - | - | ✅ | ✅ | included |
| | pnpm-lock.yaml | - | - | ✅ | ✅ | excluded |
| | package.json | ✅ | ✅ | - | - | excluded |
| .NET | packages.lock.json | ✅ | ✅ | ✅ | ✅ | included |
| | packages.config | ✅ | ✅ | ✅ | ✅ | excluded |
| | .deps.json | ✅ | ✅ | ✅ | ✅ | excluded |
| Java | JAR/WAR/PAR/EAR[^3][^4] | ✅ | ✅ | - | - | included |
| | pom.xml[^5] | - | - | ✅ | ✅ | excluded |
| Go | Binaries built by Go[^6] | ✅ | ✅ | - | - | excluded |
| | go.mod[^7] | - | - | ✅ | ✅ | included |
| Rust | Cargo.lock | ✅ | ✅ | ✅ | ✅ | included |
| | Binaries built with [cargo-auditable](https://github.com/rust-secure-code/cargo-auditable) | ✅ | ✅ | - | - | excluded |
| C/C++ | conan.lock[^12] | - | - | ✅ | ✅ | excluded |

The path of these files does not matter.

Expand All @@ -41,3 +42,4 @@ Example: [Dockerfile](https://github.com/aquasecurity/trivy-ci-test/blob/main/Do
[^9]: ✅ means "enabled" and `-` means "disabled" in the rootfs scanning
[^10]: ✅ means "enabled" and `-` means "disabled" in the filesystem scanning
[^11]: ✅ means "enabled" and `-` means "disabled" in the git repository scanning
[^12]: Trivy currently only supports default lock filename(`conan.lock`)
2 changes: 2 additions & 0 deletions go.mod
Expand Up @@ -379,3 +379,5 @@ replace github.com/docker/docker => github.com/docker/docker v20.10.3-0.20220224
// v1.2.0 is taken from github.com/open-policy-agent/opa v0.42.0
// v1.2.0 incompatible with github.com/docker/docker v20.10.3-0.20220224222438-c78f6963a1c0+incompatible
replace oras.land/oras-go => oras.land/oras-go v1.1.1

replace github.com/aquasecurity/go-dep-parser => github.com/aquasecurity/go-dep-parser v0.0.0-20220824112054-4bdc944fa0f9
Copy link
Contributor

Choose a reason for hiding this comment

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

why can we just update go-dep-parser? or it's for testing

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You are right. It is for testing.
So we can see, that Trivy works correctly with these changes.

I will remove replace and update go-dep-parser version after merge #128.
I will also change status to ready for review

4 changes: 2 additions & 2 deletions go.sum
Expand Up @@ -206,8 +206,8 @@ github.com/aquasecurity/bolt-fixtures v0.0.0-20200903104109-d34e7f983986 h1:2a30
github.com/aquasecurity/bolt-fixtures v0.0.0-20200903104109-d34e7f983986/go.mod h1:NT+jyeCzXk6vXR5MTkdn4z64TgGfE5HMLC8qfj5unl8=
github.com/aquasecurity/defsec v0.71.9 h1:eo244v1RQzziClY9xXyVftPibE0fddXbTtkvH52/slU=
github.com/aquasecurity/defsec v0.71.9/go.mod h1:2jYgkIi3UFbkrbtpnr3Cu49JZ3MGuLMJAhyh63jV1I4=
github.com/aquasecurity/go-dep-parser v0.0.0-20220819065825-29e1e04fb7ae h1:1WdRZrDTkXHC5deeJhatiP3IUHHqdIo/dZlagTtlU8g=
github.com/aquasecurity/go-dep-parser v0.0.0-20220819065825-29e1e04fb7ae/go.mod h1:6G1Y5nht5TL9kr1SzmrdE8PrmbNXo9nHx3qFR3qURg0=
github.com/aquasecurity/go-dep-parser v0.0.0-20220824112054-4bdc944fa0f9 h1:8QNyLxg6XHJH1Q3rSOLoyoX7o5tUysL2YgflKk6sdGo=
github.com/aquasecurity/go-dep-parser v0.0.0-20220824112054-4bdc944fa0f9/go.mod h1:6G1Y5nht5TL9kr1SzmrdE8PrmbNXo9nHx3qFR3qURg0=
github.com/aquasecurity/go-gem-version v0.0.0-20201115065557-8eed6fe000ce h1:QgBRgJvtEOBtUXilDb1MLi1p1MWoyFDXAu5DEUl5nwM=
github.com/aquasecurity/go-gem-version v0.0.0-20201115065557-8eed6fe000ce/go.mod h1:HXgVzOPvXhVGLJs4ZKO817idqr/xhwsTcj17CLYY74s=
github.com/aquasecurity/go-mock-aws v0.0.0-20220726154943-99847deb62b0 h1:tihCUjLWkF0b1SAjAKcFltUs3SpsqGrLtI+Frye0D10=
Expand Down
3 changes: 3 additions & 0 deletions pkg/detector/library/driver.go
Expand Up @@ -49,6 +49,9 @@ func NewDriver(libType string) (Driver, error) {
case ftypes.Pipenv, ftypes.Poetry, ftypes.Pip, ftypes.PythonPkg:
ecosystem = vulnerability.Pip
comparer = pep440.Comparer{}
case ftypes.ConanLock:
ecosystem = vulnerability.Conan
comparer = compare.GenericComparer{}
default:
return Driver{}, xerrors.Errorf("unsupported type %s", libType)
}
Expand Down
1 change: 1 addition & 0 deletions pkg/fanal/analyzer/all/import.go
Expand Up @@ -3,6 +3,7 @@ package all
import (
_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/buildinfo"
_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/command/apk"
_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language/c/conan"
_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language/dotnet/deps"
_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language/dotnet/nuget"
_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language/golang/binary"
Expand Down
7 changes: 5 additions & 2 deletions pkg/fanal/analyzer/const.go
Expand Up @@ -70,6 +70,9 @@ const (
TypeGoBinary Type = "gobinary"
TypeGoMod Type = "gomod"

// C/C++
TypeConanLock Type = "conan-lock"

// ============
// Image Config
// ============
Expand Down Expand Up @@ -115,13 +118,13 @@ var (
TypeLanguages = []Type{
TypeBundler, TypeGemSpec, TypeCargo, TypeComposer, TypeJar, TypePom,
TypeNpmPkgLock, TypeNodePkg, TypeYarn, TypePnpm, TypeNuget, TypeDotNetDeps,
TypePythonPkg, TypePip, TypePipenv, TypePoetry, TypeGoBinary, TypeGoMod, TypeRustBinary,
TypePythonPkg, TypePip, TypePipenv, TypePoetry, TypeGoBinary, TypeGoMod, TypeRustBinary, TypeConanLock,
}

// TypeLockfiles has all lock file analyzers
TypeLockfiles = []Type{
TypeBundler, TypeNpmPkgLock, TypeYarn,
TypePnpm, TypePip, TypePipenv, TypePoetry, TypeGoMod, TypePom,
TypePnpm, TypePip, TypePipenv, TypePoetry, TypeGoMod, TypePom, TypeConanLock,
}

// TypeIndividualPkgs has all analyzers for individual packages
Expand Down
48 changes: 48 additions & 0 deletions pkg/fanal/analyzer/language/c/conan/conan.go
@@ -0,0 +1,48 @@
package conan

import (
"context"
"os"

"github.com/aquasecurity/go-dep-parser/pkg/c/conan/lock"
"github.com/aquasecurity/trivy/pkg/fanal/analyzer"
"github.com/aquasecurity/trivy/pkg/fanal/analyzer/language"
"github.com/aquasecurity/trivy/pkg/fanal/types"

"golang.org/x/xerrors"
)

func init() {
analyzer.RegisterAnalyzer(&conanLockAnalyzer{})
}

const (
version = 1
// Lock file name can be anything (https://docs.conan.io/en/latest/versioning/lockfiles/introduction.html#locking-dependencies)
// Now we only check default filename - `conan.lock`
fileName = "conan.lock"
)

// conanLockAnalyzer analyzes conan.lock
type conanLockAnalyzer struct{}

func (a conanLockAnalyzer) Analyze(_ context.Context, input analyzer.AnalysisInput) (*analyzer.AnalysisResult, error) {
p := lock.NewParser()
res, err := language.Analyze(types.ConanLock, input.FilePath, input.Content, p)
if err != nil {
return nil, xerrors.Errorf("%s parse error: %w", input.FilePath, err)
}
return res, nil
}

func (a conanLockAnalyzer) Required(_ string, fileInfo os.FileInfo) bool {
return fileInfo.Name() == fileName
}

func (a conanLockAnalyzer) Type() analyzer.Type {
return analyzer.TypeConanLock
}

func (a conanLockAnalyzer) Version() int {
return version
}
106 changes: 106 additions & 0 deletions pkg/fanal/analyzer/language/c/conan/conan_test.go
@@ -0,0 +1,106 @@
package conan

import (
"os"
"path/filepath"
"testing"

"github.com/aquasecurity/trivy/pkg/fanal/analyzer"
"github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func Test_conanLockAnalyzer_Analyze(t *testing.T) {
tests := []struct {
name string
inputFile string
want *analyzer.AnalysisResult
}{
{
name: "happy path",
inputFile: "testdata/happy.lock",
want: &analyzer.AnalysisResult{
Applications: []types.Application{
{
Type: types.ConanLock,
FilePath: "testdata/happy.lock",
Libraries: []types.Package{
{
Name: "openssl",
Version: "1.1.1k",
},
},
},
},
},
},
{
name: "empty file",
inputFile: "testdata/empty.lock",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
f, err := os.Open(tt.inputFile)
require.NoError(t, err)
defer func() {
err = f.Close()
assert.NoError(t, err)
}()

a := conanLockAnalyzer{}
got, err := a.Analyze(nil, analyzer.AnalysisInput{
FilePath: tt.inputFile,
Content: f,
})

assert.NoError(t, err)
assert.Equal(t, tt.want, got)
})
}
}

func Test_nugetLibraryAnalyzer_Required(t *testing.T) {
tests := []struct {
name string
filePath string
want bool
}{
{
name: "default name",
filePath: "test/conan.lock",
want: true,
},
{
name: "name with prefix",
filePath: "test/pkga_deps.lock",
want: false,
},
{
name: "txt",
filePath: "test/test.txt",
want: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := os.MkdirAll(filepath.Dir(tt.filePath), 0700)
assert.NoError(t, err)
_, err = os.Create(tt.filePath)
assert.NoError(t, err)
defer func() {
err = os.RemoveAll(filepath.Dir(tt.filePath))
assert.NoError(t, err)
}()

fileInfo, err := os.Stat(tt.filePath)
assert.NoError(t, err)

a := conanLockAnalyzer{}
got := a.Required("", fileInfo)
assert.Equal(t, tt.want, got)
})
}
}
14 changes: 14 additions & 0 deletions pkg/fanal/analyzer/language/c/conan/testdata/empty.lock
@@ -0,0 +1,14 @@
{
"graph_lock": {
"nodes": {
"0": {
"options": "o",
"path": "conanfile.txt",
"context": "host"
}
},
"revisions_enabled": false
},
"version": "0.4",
"profile_host": "[settings]\narch=x86_64\narch_build=x86_64\nbuild_type=Release\ncompiler=gcc\ncompiler.libcxx=libstdc++\ncompiler.version=9\nos=Linux\nos_build=Linux\n[options]\n[build_requires]\n[env]\n"
}
24 changes: 24 additions & 0 deletions pkg/fanal/analyzer/language/c/conan/testdata/happy.lock
@@ -0,0 +1,24 @@
{
"graph_lock": {
"nodes": {
"0": {
"options": "o",
"requires": [
"1"
],
"path": "conanfile.txt",
"context": "host"
},
"1": {
"ref": "openssl/1.1.1k",
"options": "",
"package_id": "",
"prev": "0",
"context": "host"
}
},
"revisions_enabled": false
},
"version": "0.4",
"profile_host": "[settings]\narch=x86_64\narch_build=x86_64\nbuild_type=Release\ncompiler=gcc\ncompiler.libcxx=libstdc++\ncompiler.version=9\nos=Linux\nos_build=Linux\n[options]\n[build_requires]\n[env]\n"
}
1 change: 1 addition & 0 deletions pkg/fanal/types/const.go
Expand Up @@ -27,6 +27,7 @@ const (
GoModule = "gomod"
JavaScript = "javascript"
RustBinary = "rustbinary"
ConanLock = "conanlock"

// Config files
YAML = "yaml"
Expand Down