feat(go): license support (#3683)

This commit is contained in:
Teppei Fukuda
2023-02-24 17:52:35 +02:00
committed by GitHub
parent 6a3294e476
commit 793cc43d4c
18 changed files with 294 additions and 83 deletions

View File

@@ -4,10 +4,10 @@
Trivy supports two types of Go scanning, Go Modules and binaries built by Go.
The following table provides an outline of the features Trivy offers.
| Artifact | Offline[^1] | Dev dependencies |
|----------|:-----------:|:-----------------|
| Modules | ✓ | Include |
| Binaries | ✓ | Exclude |
| Artifact | Offline[^1] | Dev dependencies | License |
|----------|:-----------:|:-----------------|:-------:|
| Modules | ✓ | Include | ✓[^2] |
| Binaries | ✓ | Exclude | - |
!!! note
Trivy scans only dependencies of the Go project.
@@ -17,10 +17,10 @@ The following table provides an outline of the features Trivy offers.
### Go Modules
Depending on Go versions, the required files are different.
| Version | Required files | Offline | License |
|---------|:--------------:|:-------:|:-------:|
| \>=1.17 | go.mod | ✓ | - |
| <1.17 | go.mod, go.sum | ✓ | - |
| Version | Required files | Offline |
|---------|:--------------:|:-------:|
| \>=1.17 | go.mod | ✓ |
| <1.17 | go.mod, go.sum | ✓ |
In Go 1.17+ projects, Trivy uses `go.mod` for direct/indirect dependencies.
On the other hand, it uses `go.mod` for direct dependencies and `go.sum` for indirect dependencies in Go 1.16 or less.
@@ -59,4 +59,5 @@ Also, you can scan your local binaries.
$ trivy fs ./your_binary
```
[^1]: It doesn't require the Internet access.
[^1]: It doesn't require the Internet access.
[^2]: Need to download modules to local cache beforehand, like `go mod download`

View File

@@ -3,7 +3,6 @@
package integration
import (
"github.com/aquasecurity/trivy/pkg/fanal/analyzer"
"os"
"path/filepath"
"testing"
@@ -11,8 +10,9 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/aquasecurity/trivy/pkg/fanal/analyzer"
"github.com/aquasecurity/trivy/pkg/module"
"github.com/aquasecurity/trivy/pkg/utils"
"github.com/aquasecurity/trivy/pkg/utils/fsutils"
)
func TestModule(t *testing.T) {
@@ -43,14 +43,24 @@ func TestModule(t *testing.T) {
// Set up Spring4Shell module
t.Setenv("XDG_DATA_HOME", cacheDir)
_, err = utils.CopyFile(filepath.Join("../", "examples", "module", "spring4shell", "spring4shell.wasm"),
_, err = fsutils.CopyFile(filepath.Join("../", "examples", "module", "spring4shell", "spring4shell.wasm"),
filepath.Join(moduleDir, "spring4shell.wasm"))
require.NoError(t, err)
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
osArgs := []string{"--cache-dir", cacheDir, "image", "--ignore-unfixed", "--format", "json",
"--skip-update", "--offline-scan", "--input", tt.input}
osArgs := []string{
"--cache-dir",
cacheDir,
"image",
"--ignore-unfixed",
"--format",
"json",
"--skip-update",
"--offline-scan",
"--input",
tt.input,
}
// Set up the output file
outputFile := filepath.Join(t.TempDir(), "output.json")
@@ -58,7 +68,10 @@ func TestModule(t *testing.T) {
outputFile = tt.golden
}
osArgs = append(osArgs, []string{"--output", outputFile}...)
osArgs = append(osArgs, []string{
"--output",
outputFile,
}...)
// Run Trivy
err = execute(osArgs)

View File

@@ -29,7 +29,7 @@ import (
"github.com/aquasecurity/trivy/pkg/rpc/client"
"github.com/aquasecurity/trivy/pkg/scanner"
"github.com/aquasecurity/trivy/pkg/types"
"github.com/aquasecurity/trivy/pkg/utils"
"github.com/aquasecurity/trivy/pkg/utils/fsutils"
)
// TargetKind represents what kind of artifact Trivy scans
@@ -366,12 +366,12 @@ func (r *runner) initCache(opts flag.Options) error {
}
// standalone mode
utils.SetCacheDir(opts.CacheDir)
fsutils.SetCacheDir(opts.CacheDir)
cacheClient, err := operation.NewCache(opts.CacheOptions)
if err != nil {
return xerrors.Errorf("unable to initialize the cache: %w", err)
}
log.Logger.Debugf("cache dir: %s", utils.CacheDir())
log.Logger.Debugf("cache dir: %s", fsutils.CacheDir())
if opts.Reset {
defer cacheClient.Close()

View File

@@ -3,24 +3,22 @@ package operation
import (
"context"
"crypto/tls"
"crypto/x509"
"os"
"strings"
"github.com/aquasecurity/trivy/pkg/policy"
"github.com/samber/lo"
"github.com/aquasecurity/trivy/pkg/flag"
"github.com/go-redis/redis/v8"
"github.com/google/wire"
"github.com/samber/lo"
"golang.org/x/xerrors"
"github.com/aquasecurity/trivy-db/pkg/metadata"
"github.com/aquasecurity/trivy/pkg/db"
"github.com/aquasecurity/trivy/pkg/fanal/cache"
"github.com/aquasecurity/trivy/pkg/flag"
"github.com/aquasecurity/trivy/pkg/log"
"github.com/aquasecurity/trivy/pkg/utils"
"github.com/aquasecurity/trivy/pkg/policy"
"github.com/aquasecurity/trivy/pkg/utils/fsutils"
)
// SuperSet binds cache dependencies
@@ -45,7 +43,7 @@ func NewCache(c flag.CacheOptions) (Cache, error) {
}
if !lo.IsEmpty(c.RedisOptions) {
caCert, cert, err := utils.GetTLSConfig(c.RedisCACert, c.RedisCert, c.RedisKey)
caCert, cert, err := GetTLSConfig(c.RedisCACert, c.RedisCert, c.RedisKey)
if err != nil {
return Cache{}, err
}
@@ -66,7 +64,7 @@ func NewCache(c flag.CacheOptions) (Cache, error) {
}
// standalone mode
fsCache, err := cache.NewFSCache(utils.CacheDir())
fsCache, err := cache.NewFSCache(fsutils.CacheDir())
if err != nil {
return Cache{}, xerrors.Errorf("unable to initialize fs cache: %w", err)
}
@@ -87,8 +85,8 @@ func (c Cache) Reset() (err error) {
// ClearDB clears the DB cache
func (c Cache) ClearDB() (err error) {
log.Logger.Info("Removing DB file...")
if err = os.RemoveAll(utils.CacheDir()); err != nil {
return xerrors.Errorf("failed to remove the directory (%s) : %w", utils.CacheDir(), err)
if err = os.RemoveAll(fsutils.CacheDir()); err != nil {
return xerrors.Errorf("failed to remove the directory (%s) : %w", fsutils.CacheDir(), err)
}
return nil
}
@@ -172,3 +170,21 @@ func InitBuiltinPolicies(ctx context.Context, cacheDir string, quiet, skipUpdate
}
return policyPaths, nil
}
// GetTLSConfig gets tls config from CA, Cert and Key file
func GetTLSConfig(caCertPath, certPath, keyPath string) (*x509.CertPool, tls.Certificate, error) {
cert, err := tls.LoadX509KeyPair(certPath, keyPath)
if err != nil {
return nil, tls.Certificate{}, err
}
caCert, err := os.ReadFile(caCertPath)
if err != nil {
return nil, tls.Certificate{}, err
}
caCertPool := x509.NewCertPool()
caCertPool.AppendCertsFromPEM(caCert)
return caCertPool, cert, nil
}

View File

@@ -11,7 +11,7 @@ import (
"github.com/aquasecurity/trivy/pkg/log"
"github.com/aquasecurity/trivy/pkg/module"
rpcServer "github.com/aquasecurity/trivy/pkg/rpc/server"
"github.com/aquasecurity/trivy/pkg/utils"
"github.com/aquasecurity/trivy/pkg/utils/fsutils"
)
// Run runs the scan
@@ -21,13 +21,13 @@ func Run(ctx context.Context, opts flag.Options) (err error) {
}
// configure cache dir
utils.SetCacheDir(opts.CacheDir)
fsutils.SetCacheDir(opts.CacheDir)
cache, err := operation.NewCache(opts.CacheOptions)
if err != nil {
return xerrors.Errorf("server cache error: %w", err)
}
defer cache.Close()
log.Logger.Debugf("cache dir: %s", utils.CacheDir())
log.Logger.Debugf("cache dir: %s", fsutils.CacheDir())
if opts.Reset {
return cache.ClearDB()

View File

@@ -3,10 +3,16 @@ package mod
import (
"context"
"errors"
"fmt"
"go/build"
"io"
"io/fs"
"os"
"path/filepath"
"regexp"
"unicode"
"github.com/samber/lo"
"golang.org/x/exp/maps"
"golang.org/x/exp/slices"
"golang.org/x/xerrors"
@@ -18,6 +24,9 @@ import (
"github.com/aquasecurity/trivy/pkg/fanal/analyzer"
"github.com/aquasecurity/trivy/pkg/fanal/analyzer/language"
"github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/licensing"
"github.com/aquasecurity/trivy/pkg/log"
"github.com/aquasecurity/trivy/pkg/utils/fsutils"
)
func init() {
@@ -26,10 +35,13 @@ func init() {
const version = 2
var requiredFiles = []string{
types.GoMod,
types.GoSum,
}
var (
requiredFiles = []string{
types.GoMod,
types.GoSum,
}
licenseRegexp = regexp.MustCompile(`^(?i)((UN)?LICEN(S|C)E|COPYING|README|NOTICE).*$`)
)
type gomodAnalyzer struct {
modParser godeptypes.Parser
@@ -82,6 +94,10 @@ func (a *gomodAnalyzer) PostAnalyze(_ context.Context, input analyzer.PostAnalys
return nil, xerrors.Errorf("walk error: %w", err)
}
if err = fillLicenses(apps); err != nil {
return nil, xerrors.Errorf("unable to identify licenses: %w", err)
}
return &analyzer.AnalysisResult{
Applications: apps,
}, nil
@@ -154,3 +170,100 @@ func mergeGoSum(gomod, gosum *types.Application) {
gomod.Libraries = maps.Values(uniq)
}
func fillLicenses(apps []types.Application) error {
gopath := os.Getenv("GOPATH")
if gopath == "" {
gopath = build.Default.GOPATH
}
// $GOPATH/pkg/mod
modPath := filepath.Join(gopath, "pkg", "mod")
if !fsutils.DirExists(modPath) {
log.Logger.Debugf("GOPATH (%s) not found. Need 'go mod download' to fill license information", modPath)
return nil
}
licenses := map[string][]string{}
for i, app := range apps {
for j, lib := range app.Libraries {
libID := lib.Name + "@v" + lib.Version
if l, ok := licenses[libID]; ok {
// Fill licenses
apps[i].Libraries[j].Licenses = l
continue
}
// e.g. $GOPATH/pkg/mod/github.com/aquasecurity/go-dep-parser@v1.0.0
modDir := filepath.Join(modPath, fmt.Sprintf("%s@v%s", normalizeModName(lib.Name), lib.Version))
l, err := findLicense(modDir)
if err != nil {
return xerrors.Errorf("golang license error: %w", err)
} else if l == nil || len(l.Findings) == 0 {
continue
}
licenseNames := lo.Map(l.Findings, func(finding types.LicenseFinding, _ int) string {
return finding.Name
})
// Cache the detected licenses
licenses[libID] = licenseNames
// Fill licenses
apps[i].Libraries[j].Licenses = licenseNames
}
}
return nil
}
func findLicense(dir string) (*types.LicenseFile, error) {
var license *types.LicenseFile
err := filepath.WalkDir(dir, func(path string, d fs.DirEntry, err error) error {
if err != nil {
return err
} else if !d.Type().IsRegular() {
return nil
}
if !licenseRegexp.MatchString(filepath.Base(path)) {
return nil
}
// e.g. $GOPATH/pkg/mod/github.com/aquasecurity/go-dep-parser@v0.0.0-20220406074731-71021a481237/LICENSE
f, err := os.Open(path)
if err != nil {
return xerrors.Errorf("file (%s) open error: %w", path, err)
}
defer f.Close()
l, err := licensing.Classify(path, f)
if err != nil {
return xerrors.Errorf("license classify error: %w", err)
}
// License found
if l != nil && len(l.Findings) > 0 {
license = l
return io.EOF
}
return nil
})
// The module path may not exist
if errors.Is(err, os.ErrNotExist) {
return nil, nil
} else if err != nil && !errors.Is(err, io.EOF) {
return nil, fmt.Errorf("finding a known open source license: %w", err)
}
return license, nil
}
// normalizeModName escapes upper characters
// e.g. 'github.com/BurntSushi/toml' => 'github.com/!burnt!sushi'
func normalizeModName(name string) string {
var newName []rune
for _, c := range name {
if unicode.IsUpper(c) {
// 'A' => '!a'
newName = append(newName, '!', unicode.ToLower(c))
} else {
newName = append(newName, c)
}
}
return string(newName)
}

View File

@@ -32,6 +32,9 @@ func Test_gomodAnalyzer_Analyze(t *testing.T) {
{
Name: "github.com/aquasecurity/go-dep-parser",
Version: "0.0.0-20220406074731-71021a481237",
Licenses: []string{
"MIT",
},
},
{
Name: "golang.org/x/xerrors",
@@ -60,6 +63,9 @@ func Test_gomodAnalyzer_Analyze(t *testing.T) {
Name: "github.com/BurntSushi/toml",
Version: "0.3.1",
Indirect: true,
Licenses: []string{
"MIT",
},
},
},
},
@@ -91,6 +97,7 @@ func Test_gomodAnalyzer_Analyze(t *testing.T) {
},
}
for _, tt := range tests {
t.Setenv("GOPATH", "testdata")
t.Run(tt.name, func(t *testing.T) {
a, err := newGoModAnalyzer(analyzer.AnalyzerOptions{})
require.NoError(t, err)

View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2013 TOML authors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019 Teppei Fukuda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -5,7 +5,7 @@ import (
"github.com/spf13/cobra"
"github.com/aquasecurity/trivy/pkg/utils"
"github.com/aquasecurity/trivy/pkg/utils/fsutils"
)
var (
@@ -58,7 +58,7 @@ var (
CacheDirFlag = Flag{
Name: "cache-dir",
ConfigName: "cache.dir",
Value: utils.DefaultCacheDir(),
Value: fsutils.DefaultCacheDir(),
Usage: "cache directory",
Persistent: true,
}
@@ -109,7 +109,16 @@ func NewGlobalFlagGroup() *GlobalFlagGroup {
}
func (f *GlobalFlagGroup) flags() []*Flag {
return []*Flag{f.ConfigFile, f.ShowVersion, f.Quiet, f.Debug, f.Insecure, f.Timeout, f.CacheDir, f.GenerateDefaultConfig}
return []*Flag{
f.ConfigFile,
f.ShowVersion,
f.Quiet,
f.Debug,
f.Insecure,
f.Timeout,
f.CacheDir,
f.GenerateDefaultConfig,
}
}
func (f *GlobalFlagGroup) AddFlags(cmd *cobra.Command) {

View File

@@ -23,7 +23,7 @@ import (
"github.com/aquasecurity/trivy/pkg/module/serialize"
"github.com/aquasecurity/trivy/pkg/scanner/post"
"github.com/aquasecurity/trivy/pkg/types"
"github.com/aquasecurity/trivy/pkg/utils"
"github.com/aquasecurity/trivy/pkg/utils/fsutils"
)
var (
@@ -266,7 +266,10 @@ func newWASMPlugin(ctx context.Context, ccache wazero.CompilationCache, code []b
// Avoid reflection for logging as it implies an overhead of >1us per call.
for n, f := range logFunctions {
envBuilder.NewFunctionBuilder().
WithGoModuleFunction(f, []api.ValueType{api.ValueTypeI32, api.ValueTypeI32}, []api.ValueType{}).
WithGoModuleFunction(f, []api.ValueType{
api.ValueTypeI32,
api.ValueTypeI32,
}, []api.ValueType{}).
WithParameterNames("offset", "size").
Export(n)
}
@@ -698,7 +701,7 @@ func isType(ctx context.Context, mod api.Module, name string) (bool, error) {
}
func dir() string {
return filepath.Join(utils.HomeDir(), RelativeDir)
return filepath.Join(fsutils.HomeDir(), RelativeDir)
}
func modulePostScanSpec(ctx context.Context, mod api.Module) (serialize.PostScanSpec, error) {

View File

@@ -13,7 +13,7 @@ import (
"github.com/aquasecurity/trivy/pkg/fanal/analyzer"
"github.com/aquasecurity/trivy/pkg/module"
"github.com/aquasecurity/trivy/pkg/scanner/post"
"github.com/aquasecurity/trivy/pkg/utils"
"github.com/aquasecurity/trivy/pkg/utils/fsutils"
)
func TestManager_Register(t *testing.T) {
@@ -94,7 +94,7 @@ func TestManager_Register(t *testing.T) {
require.NoError(t, err)
// Copy the wasm module for testing
_, err = utils.CopyFile(modulePath, filepath.Join(moduleDir, filepath.Base(modulePath)))
_, err = fsutils.CopyFile(modulePath, filepath.Join(moduleDir, filepath.Base(modulePath)))
require.NoError(t, err)
}

View File

@@ -15,7 +15,7 @@ import (
"github.com/stretchr/testify/require"
"github.com/aquasecurity/trivy/pkg/oci"
"github.com/aquasecurity/trivy/pkg/utils"
"github.com/aquasecurity/trivy/pkg/utils/fsutils"
)
type fakeLayer struct {
@@ -53,7 +53,10 @@ func TestNewArtifact(t *testing.T) {
name: "sad: two layers",
mediaType: "application/vnd.cncf.openpolicyagent.layer.v1.tar+gzip",
layersReturns: layersReturns{
layers: []v1.Layer{layer, layer},
layers: []v1.Layer{
layer,
layer,
},
},
wantErr: "OCI artifact must be a single layer",
},
@@ -78,7 +81,7 @@ func TestNewArtifact(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tempDir := t.TempDir()
utils.SetCacheDir(tempDir)
fsutils.SetCacheDir(tempDir)
// Mock image
img := new(fakei.FakeImage)
@@ -90,7 +93,8 @@ func TestNewArtifact(t *testing.T) {
Size: 100,
Digest: v1.Hash{
Algorithm: "sha256",
Hex: "cba33656188782852f58993f45b68bfb8577f64cdcf02a604e3fc2afbeb5f2d8"},
Hex: "cba33656188782852f58993f45b68bfb8577f64cdcf02a604e3fc2afbeb5f2d8",
},
Annotations: map[string]string{
"org.opencontainers.image.title": "bundle.tar.gz",
},
@@ -131,7 +135,7 @@ func TestArtifact_Download(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tempDir := t.TempDir()
utils.SetCacheDir(tempDir)
fsutils.SetCacheDir(tempDir)
// Mock layer
layer, err := tarball.LayerFromFile(tt.input)
@@ -148,7 +152,8 @@ func TestArtifact_Download(t *testing.T) {
Size: 100,
Digest: v1.Hash{
Algorithm: "sha256",
Hex: "cba33656188782852f58993f45b68bfb8577f64cdcf02a604e3fc2afbeb5f2d8"},
Hex: "cba33656188782852f58993f45b68bfb8577f64cdcf02a604e3fc2afbeb5f2d8",
},
Annotations: map[string]string{
"org.opencontainers.image.title": "bundle.tar.gz",
},

View File

@@ -14,7 +14,7 @@ import (
"github.com/aquasecurity/trivy/pkg/downloader"
"github.com/aquasecurity/trivy/pkg/log"
"github.com/aquasecurity/trivy/pkg/utils"
"github.com/aquasecurity/trivy/pkg/utils/fsutils"
)
const (
@@ -171,7 +171,7 @@ func Install(ctx context.Context, url string, force bool) (Plugin, error) {
}
// Copy plugin.yaml into the plugin dir
if _, err = utils.CopyFile(filepath.Join(tempDir, configFile), filepath.Join(pluginDir, configFile)); err != nil {
if _, err = fsutils.CopyFile(filepath.Join(tempDir, configFile), filepath.Join(pluginDir, configFile)); err != nil {
return Plugin{}, xerrors.Errorf("failed to copy plugin.yaml: %w", err)
}
@@ -314,7 +314,7 @@ func loadMetadata(dir string) (Plugin, error) {
}
func dir() string {
return filepath.Join(utils.HomeDir(), pluginsRelativeDir)
return filepath.Join(fsutils.HomeDir(), pluginsRelativeDir)
}
func isInstalled(url string) (Plugin, bool) {

View File

@@ -17,7 +17,7 @@ import (
dbc "github.com/aquasecurity/trivy/pkg/db"
"github.com/aquasecurity/trivy/pkg/fanal/cache"
"github.com/aquasecurity/trivy/pkg/log"
"github.com/aquasecurity/trivy/pkg/utils"
"github.com/aquasecurity/trivy/pkg/utils/fsutils"
rpcCache "github.com/aquasecurity/trivy/rpc/cache"
rpcScanner "github.com/aquasecurity/trivy/rpc/scanner"
)
@@ -160,12 +160,12 @@ func (w dbWorker) hotUpdate(ctx context.Context, cacheDir string, dbUpdateWg, re
}
// Copy trivy.db
if _, err = utils.CopyFile(db.Path(tmpDir), db.Path(cacheDir)); err != nil {
if _, err = fsutils.CopyFile(db.Path(tmpDir), db.Path(cacheDir)); err != nil {
return xerrors.Errorf("failed to copy the database file: %w", err)
}
// Copy metadata.json
if _, err = utils.CopyFile(metadata.Path(tmpDir), metadata.Path(cacheDir)); err != nil {
if _, err = fsutils.CopyFile(metadata.Path(tmpDir), metadata.Path(cacheDir)); err != nil {
return xerrors.Errorf("failed to copy the metadata file: %w", err)
}

View File

@@ -19,7 +19,7 @@ import (
"github.com/aquasecurity/trivy-db/pkg/metadata"
dbFile "github.com/aquasecurity/trivy/pkg/db"
"github.com/aquasecurity/trivy/pkg/fanal/cache"
"github.com/aquasecurity/trivy/pkg/utils"
"github.com/aquasecurity/trivy/pkg/utils/fsutils"
rpcCache "github.com/aquasecurity/trivy/rpc/cache"
)
@@ -59,7 +59,10 @@ func Test_dbWorker_update(t *testing.T) {
{
name: "happy path",
needsUpdate: needsUpdate{
input: needsUpdateInput{appVersion: "1", skip: false},
input: needsUpdateInput{
appVersion: "1",
skip: false,
},
output: needsUpdateOutput{needsUpdate: true},
},
download: download{
@@ -75,7 +78,10 @@ func Test_dbWorker_update(t *testing.T) {
{
name: "not update",
needsUpdate: needsUpdate{
input: needsUpdateInput{appVersion: "1", skip: false},
input: needsUpdateInput{
appVersion: "1",
skip: false,
},
output: needsUpdateOutput{needsUpdate: false},
},
args: args{appVersion: "1"},
@@ -83,7 +89,10 @@ func Test_dbWorker_update(t *testing.T) {
{
name: "skip update",
needsUpdate: needsUpdate{
input: needsUpdateInput{appVersion: "1", skip: true},
input: needsUpdateInput{
appVersion: "1",
skip: true,
},
output: needsUpdateOutput{needsUpdate: false},
},
args: args{appVersion: "1"},
@@ -91,7 +100,10 @@ func Test_dbWorker_update(t *testing.T) {
{
name: "NeedsUpdate returns an error",
needsUpdate: needsUpdate{
input: needsUpdateInput{appVersion: "1", skip: false},
input: needsUpdateInput{
appVersion: "1",
skip: false,
},
output: needsUpdateOutput{err: xerrors.New("fail")},
},
args: args{appVersion: "1"},
@@ -100,7 +112,10 @@ func Test_dbWorker_update(t *testing.T) {
{
name: "Download returns an error",
needsUpdate: needsUpdate{
input: needsUpdateInput{appVersion: "1", skip: false},
input: needsUpdateInput{
appVersion: "1",
skip: false,
},
output: needsUpdateOutput{needsUpdate: true},
},
download: download{
@@ -132,11 +147,11 @@ func Test_dbWorker_update(t *testing.T) {
err := os.MkdirAll(db.Dir(tmpDir), 0744)
require.NoError(t, err)
_, err = utils.CopyFile("testdata/new.db", db.Path(tmpDir))
_, err = fsutils.CopyFile("testdata/new.db", db.Path(tmpDir))
require.NoError(t, err)
// fake download: copy testdata/metadata.json to tmpDir/db/metadata.json
_, err = utils.CopyFile("testdata/metadata.json", metadata.Path(tmpDir))
_, err = fsutils.CopyFile("testdata/metadata.json", metadata.Path(tmpDir))
require.NoError(t, err)
}).Return(tt.download.err)
}

View File

@@ -1,8 +1,6 @@
package utils
package fsutils
import (
"crypto/tls"
"crypto/x509"
"fmt"
"io"
"os"
@@ -72,20 +70,9 @@ func CopyFile(src, dst string) (int64, error) {
return n, err
}
// GetTLSConfig get tls config from CA, Cert and Key file
func GetTLSConfig(caCertPath, certPath, keyPath string) (*x509.CertPool, tls.Certificate, error) {
cert, err := tls.LoadX509KeyPair(certPath, keyPath)
if err != nil {
return nil, tls.Certificate{}, err
func DirExists(path string) bool {
if f, err := os.Stat(path); os.IsNotExist(err) || !f.IsDir() {
return false
}
caCert, err := os.ReadFile(caCertPath)
if err != nil {
return nil, tls.Certificate{}, err
}
caCertPool := x509.NewCertPool()
caCertPool.AppendCertsFromPEM(caCert)
return caCertPool, cert, nil
return true
}

View File

@@ -1,4 +1,4 @@
package utils
package fsutils
import (
"os"