Skip to content

Commit

Permalink
feat: check if the same version installed
Browse files Browse the repository at this point in the history
Signed-off-by: knqyf263 <[email protected]>
  • Loading branch information
knqyf263 committed May 16, 2024
1 parent 7862d49 commit 06d085a
Show file tree
Hide file tree
Showing 21 changed files with 130 additions and 59 deletions.
1 change: 1 addition & 0 deletions pkg/plugin/index.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ type Index struct {
Version int `yaml:"version"`
Plugins []struct {
Name string `yaml:"name"`
Version string `yaml:"version"`
Maintainer string `yaml:"maintainer"`
Summary string `yaml:"summary"`
Repository string `yaml:"repository"`
Expand Down
26 changes: 16 additions & 10 deletions pkg/plugin/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,20 @@ var (
type ManagerOption func(indexer *Manager)

func WithWriter(w io.Writer) ManagerOption {
return func(indexer *Manager) {
indexer.w = w
return func(manager *Manager) {
manager.w = w
}
}

func WithLogger(logger *log.Logger) ManagerOption {
return func(manager *Manager) {
manager.logger = logger
}
}

func WithIndexURL(indexURL string) ManagerOption {
return func(indexer *Manager) {
indexer.indexURL = indexURL
return func(manager *Manager) {
manager.indexURL = indexURL
}
}

Expand Down Expand Up @@ -90,11 +96,11 @@ func Search(ctx context.Context, keyword string) error { return defaultManager(

// Install installs a plugin
func (m *Manager) Install(ctx context.Context, arg string, opts Options) (Plugin, error) {
input := m.parseArg(arg)
input := m.parseArg(ctx, arg)
input.name = m.tryIndex(ctx, input.name)

// If the plugin is already installed, it skips installing the plugin.
if p, installed := m.isInstalled(ctx, input.name); installed {
if p, installed := m.isInstalled(ctx, input.name, input.version); installed {
m.logger.InfoContext(ctx, "The plugin is already installed", log.String("name", p.Name))
return p, nil
}
Expand Down Expand Up @@ -343,14 +349,14 @@ func (m *Manager) loadMetadata(dir string) (Plugin, error) {
return plugin, nil
}

func (m *Manager) isInstalled(ctx context.Context, url string) (Plugin, bool) {
func (m *Manager) isInstalled(ctx context.Context, url, version string) (Plugin, bool) {
installedPlugins, err := m.LoadAll(ctx)
if err != nil {
return Plugin{}, false
}

for _, plugin := range installedPlugins {
if plugin.Repository == url {
if plugin.Repository == url && (version == "" || plugin.Version == version) {
return plugin, true
}
}
Expand All @@ -371,12 +377,12 @@ func (i *Input) String() string {
return i.name
}

func (m *Manager) parseArg(arg string) Input {
func (m *Manager) parseArg(ctx context.Context, arg string) Input {
before, after, found := strings.Cut(arg, "@v")
if !found {
return Input{name: arg}
} else if _, err := semver.Parse(after); err != nil {
m.logger.Debug("Unable to identify the plugin version", log.String("name", arg), log.Err(err))
m.logger.DebugContext(ctx, "Unable to identify the plugin version", log.String("name", arg), log.Err(err))
return Input{name: arg}
}
// cf. https://github.com/hashicorp/go-getter/blob/268c11cae8cf0d9374783e06572679796abe9ce9/README.md#git-git
Expand Down
59 changes: 37 additions & 22 deletions pkg/plugin/manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package plugin_test
import (
"bytes"
"context"
"fmt"
"github.com/aquasecurity/trivy/pkg/clock"
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
v1 "github.com/google/go-containerregistry/pkg/v1"
Expand All @@ -22,6 +23,34 @@ import (
"github.com/aquasecurity/trivy/pkg/plugin"
)

func setupInstalledPlugin(t *testing.T, homeDir string, p plugin.Plugin) {
pluginDir := filepath.Join(homeDir, ".trivy", "plugins", p.Name)

// Create the test plugin directory
err := os.MkdirAll(pluginDir, os.ModePerm)
require.NoError(t, err)

// write the plugin name
pluginMetadata := fmt.Sprintf(`name: "%s"
repository: "%s"
version: "%s"
usage: test
description: test
platforms:
- selector:
os: linux
arch: amd64
uri: ./test.sh
bin: ./test.sh
installed:
platform:
os: linux
arch: amd64`, p.Name, p.Repository, p.Version)

err = os.WriteFile(filepath.Join(pluginDir, "plugin.yaml"), []byte(pluginMetadata), os.ModePerm)
require.NoError(t, err)
}

func TestManager_Run(t *testing.T) {
if runtime.GOOS == "windows" {
// the test.sh script can't be run on windows so skipping
Expand Down Expand Up @@ -318,38 +347,24 @@ func TestManager_Upgrade(t *testing.T) {
t.Skip("Test satisfied adequately by Linux tests")
}
pluginName := "test_plugin"
pluginVersion := "0.0.5"

tempDir := t.TempDir()
pluginDir := filepath.Join(tempDir, ".trivy", "plugins", pluginName)

t.Setenv("XDG_DATA_HOME", tempDir)

// Create the test plugin directory
err := os.MkdirAll(pluginDir, os.ModePerm)
require.NoError(t, err)

// write the plugin name
pluginMetadata := `name: "test_plugin"
repository: testdata/test_plugin
version: "0.0.5"
usage: test
description: A simple test plugin
installed:
platform:
os: linux
arch: amd64`

err = os.WriteFile(filepath.Join(pluginDir, "plugin.yaml"), []byte(pluginMetadata), os.ModePerm)
require.NoError(t, err)
setupInstalledPlugin(t, tempDir, plugin.Plugin{
Name: pluginName,
Version: pluginVersion,
Repository: "testdata/test_plugin",
})

ctx := context.Background()
m := plugin.NewManager()

// verify initial version
verifyVersion(t, ctx, m, pluginName, "0.0.5")
verifyVersion(t, ctx, m, pluginName, pluginVersion)

// Upgrade the existing plugin
err = m.Upgrade(ctx, nil)
err := m.Upgrade(ctx, nil)
require.NoError(t, err)

// verify plugin updated
Expand Down
88 changes: 68 additions & 20 deletions pkg/plugin/manager_unix_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,24 @@ package plugin_test

import (
"archive/zip"
"bytes"
"context"
"fmt"
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"testing"
"time"

v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1"
"github.com/sosedoff/gitkit" // Not work on Windows
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/aquasecurity/trivy/pkg/clock"
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/log"
"github.com/aquasecurity/trivy/pkg/plugin"
"github.com/aquasecurity/trivy/pkg/utils/fsutils"
)
Expand All @@ -37,13 +42,20 @@ func setupGitServer() (*httptest.Server, error) {
}

func TestManager_Install(t *testing.T) {
ts, err := setupGitServer()
gs, err := setupGitServer()
require.NoError(t, err)
defer ts.Close()
t.Cleanup(gs.Close)

ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
zr := zip.NewWriter(w)
require.NoError(t, zr.AddFS(os.DirFS("testdata/test_plugin")))
require.NoError(t, zr.Close())
}))
t.Cleanup(ts.Close)

wantPlugin := plugin.Plugin{
Name: "test_plugin",
Repository: "github.com/aquasecurity/trivy-plugin-test",
Repository: "testdata/test_plugin",
Version: "0.2.0",
Summary: "test",
Description: "test",
Expand All @@ -67,41 +79,75 @@ func TestManager_Install(t *testing.T) {
wantPluginWithVersion := wantPlugin
wantPluginWithVersion.Version = "0.1.0"

wantLogs := `2021-08-25T12:20:30Z INFO Installing the plugin... src="%s"
2021-08-25T12:20:30Z INFO Plugin successfully installed name="test_plugin" version="%s"
`

tests := []struct {
name string
pluginName string
installed *plugin.Plugin
want plugin.Plugin
wantFile string
wantLogs string
wantErr string
}{
{
name: "http",
want: wantPlugin,
wantFile: ".trivy/plugins/test_plugin/test.sh",
name: "http",
pluginName: ts.URL + "/test_plugin.zip",
want: wantPlugin,
wantFile: ".trivy/plugins/test_plugin/test.sh",
wantLogs: fmt.Sprintf(wantLogs, ts.URL+"/test_plugin.zip", "0.2.0"),
},
{
name: "local path",
pluginName: "testdata/test_plugin",
want: wantPlugin,
wantFile: ".trivy/plugins/test_plugin/test.sh",
wantLogs: fmt.Sprintf(wantLogs, "testdata/test_plugin", "0.2.0"),
},
{
name: "git",
pluginName: "git::" + ts.URL + "/test_plugin.git",
pluginName: "git::" + gs.URL + "/test_plugin.git",
want: wantPlugin,
wantFile: ".trivy/plugins/test_plugin/test.sh",
wantLogs: fmt.Sprintf(wantLogs, "git::"+gs.URL+"/test_plugin.git", "0.2.0"),
},
{
name: "with version",
pluginName: "git::" + ts.URL + "/[email protected]",
pluginName: "git::" + gs.URL + "/[email protected]",
want: wantPluginWithVersion,
wantFile: ".trivy/plugins/test_plugin/test.sh",
wantLogs: fmt.Sprintf(wantLogs, "git::"+gs.URL+"/test_plugin.git", "0.1.0"),
},
{
name: "via index",
pluginName: "test",
pluginName: "test_plugin",
want: wantPlugin,
wantFile: ".trivy/plugins/test_plugin/test.sh",
wantLogs: fmt.Sprintf(wantLogs, "testdata/test_plugin", "0.2.0"),
},
{
name: "installed",
pluginName: "test_plugin",
installed: &plugin.Plugin{
Name: "test_plugin",
Repository: "testdata/test_plugin",
Version: "0.2.0",
},
want: wantPlugin,
wantLogs: "2021-08-25T12:20:30Z INFO The plugin is already installed name=\"test_plugin\"\n",
},
{
name: "different version installed",
pluginName: "[email protected]",
installed: &plugin.Plugin{
Name: "test_plugin",
Repository: "testdata/test_plugin",
Version: "0.1.0",
},
want: wantPlugin,
wantLogs: fmt.Sprintf(wantLogs, "testdata/test_plugin", "0.2.0"),
},
{
name: "plugin not found",
Expand All @@ -124,17 +170,16 @@ func TestManager_Install(t *testing.T) {
// For plugin index
fsutils.SetCacheDir("testdata")

if tt.pluginName == "" {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
zr := zip.NewWriter(w)
require.NoError(t, zr.AddFS(os.DirFS("testdata/test_plugin")))
require.NoError(t, zr.Close())
}))
t.Cleanup(ts.Close)
tt.pluginName = ts.URL + "/test_plugin.zip"
if tt.installed != nil {
setupInstalledPlugin(t, dst, *tt.installed)
}

got, err := plugin.NewManager().Install(context.Background(), tt.pluginName, plugin.Options{
var gotLogs bytes.Buffer
logger := log.New(log.NewHandler(&gotLogs, nil))

ctx := clock.With(context.Background(), time.Date(2021, 8, 25, 12, 20, 30, 5, time.UTC))

got, err := plugin.NewManager(plugin.WithLogger(logger)).Install(ctx, tt.pluginName, plugin.Options{
Platform: ftypes.Platform{
Platform: &v1.Platform{
Architecture: "amd64",
Expand All @@ -149,7 +194,10 @@ func TestManager_Install(t *testing.T) {
assert.NoError(t, err)

assert.EqualExportedValues(t, tt.want, got)
assert.FileExists(t, filepath.Join(dst, tt.wantFile))
if tt.wantFile != "" {
assert.FileExists(t, filepath.Join(dst, tt.wantFile))
}
assert.Equal(t, tt.wantLogs, gotLogs.String())
})
}
}
2 changes: 1 addition & 1 deletion pkg/plugin/testdata/plugin/index.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ plugins:
maintainer: aquasecurity
summary: A bar plugin
repository: github.com/aquasecurity/trivy-plugin-bar
- name: test
- name: test_plugin
maintainer: aquasecurity
summary: A test plugin
repository: testdata/test_plugin
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
xM��
�0 ���S��[7a}ɺ�
�#iE�޵(��s�,>-0��!b C!)�����A1�$�$~h� ��� �����AI��ZI,�\:�r*{,��A�8��'��o�M����hd���^�ݩ� �����[������Bi
Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.

This file was deleted.

Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
6 changes: 3 additions & 3 deletions pkg/plugin/testdata/test_plugin.git/packed-refs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# pack-refs with: peeled fully-peeled sorted
96e190ae5bcaa3900e568608faf00f16c3ff2714 refs/heads/main
3b147ae5ffafba7c1d833b4f4bc8ac6a22a8c9bf refs/tags/v0.1.0
96e190ae5bcaa3900e568608faf00f16c3ff2714 refs/tags/v0.2.0
d78abde66b1d35bdac65402f0e2cddf3a96cd377 refs/heads/main
929b4718db99b64a38b4e8c3ec8e673976821c08 refs/tags/v0.1.0
d78abde66b1d35bdac65402f0e2cddf3a96cd377 refs/tags/v0.2.0
Empty file.
Empty file.
2 changes: 1 addition & 1 deletion pkg/plugin/testdata/test_plugin/plugin.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: "test_plugin"
repository: github.com/aquasecurity/trivy-plugin-test
repository: testdata/test_plugin
version: "0.2.0"
summary: test
description: test
Expand Down

0 comments on commit 06d085a

Please sign in to comment.