mirror of
https://github.com/aquasecurity/trivy.git
synced 2025-12-12 15:50:15 -08:00
feat(go): license support (#3683)
This commit is contained in:
@@ -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`
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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",
|
||||
},
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package utils
|
||||
package fsutils
|
||||
|
||||
import (
|
||||
"os"
|
||||
Reference in New Issue
Block a user