Skip to content

Commit 3d02a31

Browse files
authored
fix(plugin): respect --insecure (#7022)
Signed-off-by: knqyf263 <[email protected]>
1 parent 8d618e4 commit 3d02a31

File tree

8 files changed

+108
-19
lines changed

8 files changed

+108
-19
lines changed

pkg/commands/app.go

+20-5
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ Use "{{.CommandPath}} [command] --help" for more information about a command.{{e
6262

6363
// NewApp is the factory method to return Trivy CLI
6464
func NewApp() *cobra.Command {
65+
cobra.EnableTraverseRunHooks = true // To execute persistent pre-run hooks from all parents.
6566
globalFlags := flag.NewGlobalFlagGroup()
6667
rootCmd := NewRootCommand(globalFlags)
6768
rootCmd.AddGroup(
@@ -89,7 +90,7 @@ func NewApp() *cobra.Command {
8990
NewServerCommand(globalFlags),
9091
NewConfigCommand(globalFlags),
9192
NewConvertCommand(globalFlags),
92-
NewPluginCommand(),
93+
NewPluginCommand(globalFlags),
9394
NewModuleCommand(globalFlags),
9495
NewKubernetesCommand(globalFlags),
9596
NewSBOMCommand(globalFlags),
@@ -719,14 +720,25 @@ func NewConfigCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command {
719720
return cmd
720721
}
721722

722-
func NewPluginCommand() *cobra.Command {
723+
func NewPluginCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command {
724+
var pluginOptions flag.Options
725+
pluginFlags := &flag.Flags{
726+
GlobalFlagGroup: globalFlags,
727+
}
723728
cmd := &cobra.Command{
724729
Use: "plugin subcommand",
725730
Aliases: []string{"p"},
726731
GroupID: groupManagement,
727732
Short: "Manage plugins",
728733
SilenceErrors: true,
729734
SilenceUsage: true,
735+
PersistentPreRunE: func(cmd *cobra.Command, args []string) (err error) {
736+
pluginOptions, err = pluginFlags.ToOptions(args)
737+
if err != nil {
738+
return err
739+
}
740+
return nil
741+
},
730742
}
731743
cmd.AddCommand(
732744
&cobra.Command{
@@ -746,7 +758,7 @@ func NewPluginCommand() *cobra.Command {
746758
DisableFlagsInUseLine: true,
747759
Args: cobra.ExactArgs(1),
748760
RunE: func(cmd *cobra.Command, args []string) error {
749-
if _, err := plugin.Install(cmd.Context(), args[0], plugin.Options{}); err != nil {
761+
if _, err := plugin.Install(cmd.Context(), args[0], plugin.Options{Insecure: pluginOptions.Insecure}); err != nil {
750762
return xerrors.Errorf("plugin install error: %w", err)
751763
}
752764
return nil
@@ -805,7 +817,10 @@ func NewPluginCommand() *cobra.Command {
805817
Short: "Run a plugin on the fly",
806818
Args: cobra.MinimumNArgs(1),
807819
RunE: func(cmd *cobra.Command, args []string) error {
808-
return plugin.Run(cmd.Context(), args[0], plugin.Options{Args: args[1:]})
820+
return plugin.Run(cmd.Context(), args[0], plugin.Options{
821+
Args: args[1:],
822+
Insecure: pluginOptions.Insecure,
823+
})
809824
},
810825
},
811826
&cobra.Command{
@@ -816,7 +831,7 @@ func NewPluginCommand() *cobra.Command {
816831
SilenceUsage: true,
817832
Args: cobra.NoArgs,
818833
RunE: func(cmd *cobra.Command, _ []string) error {
819-
if err := plugin.Update(cmd.Context()); err != nil {
834+
if err := plugin.Update(cmd.Context(), plugin.Options{Insecure: pluginOptions.Insecure}); err != nil {
820835
return xerrors.Errorf("plugin update error: %w", err)
821836
}
822837
return nil

pkg/downloader/download.go

+15-4
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ import (
1010
)
1111

1212
// DownloadToTempDir downloads the configured source to a temp dir.
13-
func DownloadToTempDir(ctx context.Context, url string) (string, error) {
14-
tempDir, err := os.MkdirTemp("", "trivy-plugin")
13+
func DownloadToTempDir(ctx context.Context, url string, insecure bool) (string, error) {
14+
tempDir, err := os.MkdirTemp("", "trivy-download")
1515
if err != nil {
1616
return "", xerrors.Errorf("failed to create a temp dir: %w", err)
1717
}
@@ -21,26 +21,37 @@ func DownloadToTempDir(ctx context.Context, url string) (string, error) {
2121
return "", xerrors.Errorf("unable to get the current dir: %w", err)
2222
}
2323

24-
if err = Download(ctx, url, tempDir, pwd); err != nil {
24+
if err = Download(ctx, url, tempDir, pwd, insecure); err != nil {
2525
return "", xerrors.Errorf("download error: %w", err)
2626
}
2727

2828
return tempDir, nil
2929
}
3030

3131
// Download downloads the configured source to the destination.
32-
func Download(ctx context.Context, src, dst, pwd string) error {
32+
func Download(ctx context.Context, src, dst, pwd string, insecure bool) error {
3333
// go-getter doesn't allow the dst directory already exists if the src is directory.
3434
_ = os.RemoveAll(dst)
3535

3636
var opts []getter.ClientOption
37+
if insecure {
38+
opts = append(opts, getter.WithInsecure())
39+
}
3740

3841
// Clone the global map so that it will not be accessed concurrently.
3942
getters := maps.Clone(getter.Getters)
4043

4144
// Overwrite the file getter so that a file will be copied
4245
getters["file"] = &getter.FileGetter{Copy: true}
4346

47+
// Since "httpGetter" is a global pointer and the state is shared,
48+
// once it is executed without "WithInsecure()",
49+
// it cannot enable WithInsecure() afterwards because its state is preserved.
50+
// cf. https://github.com/hashicorp/go-getter/blob/5a63fd9c0d5b8da8a6805e8c283f46f0dacb30b3/get.go#L63-L65
51+
httpGetter := &getter.HttpGetter{Netrc: true}
52+
getters["http"] = httpGetter
53+
getters["https"] = httpGetter
54+
4455
// Build the client
4556
client := &getter.Client{
4657
Ctx: ctx,

pkg/downloader/downloader_test.go

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package downloader_test
2+
3+
import (
4+
"context"
5+
"net/http"
6+
"net/http/httptest"
7+
"os"
8+
"testing"
9+
10+
"github.com/stretchr/testify/assert"
11+
"github.com/stretchr/testify/require"
12+
13+
"github.com/aquasecurity/trivy/pkg/downloader"
14+
)
15+
16+
func TestDownload(t *testing.T) {
17+
// Set up a test server with a self-signed certificate
18+
server := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
19+
_, err := w.Write([]byte("test content"))
20+
require.NoError(t, err)
21+
}))
22+
defer server.Close()
23+
24+
tests := []struct {
25+
name string
26+
insecure bool
27+
wantErr bool
28+
}{
29+
{
30+
"Secure (should fail)",
31+
false,
32+
true,
33+
},
34+
{
35+
"Insecure (should succeed)",
36+
true,
37+
false,
38+
},
39+
}
40+
41+
for _, tt := range tests {
42+
t.Run(tt.name, func(t *testing.T) {
43+
// Set up the destination path
44+
dst := t.TempDir()
45+
46+
// Execute the download
47+
err := downloader.Download(context.Background(), server.URL, dst, "", tt.insecure)
48+
49+
if tt.wantErr {
50+
assert.Error(t, err)
51+
return
52+
}
53+
require.NoError(t, err)
54+
55+
// Check the content of the downloaded file
56+
content, err := os.ReadFile(dst)
57+
require.NoError(t, err)
58+
assert.Equal(t, "test content", string(content))
59+
})
60+
}
61+
}

pkg/oci/artifact.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,8 @@ func (a *Artifact) download(ctx context.Context, layer v1.Layer, fileName, dir s
188188
}
189189

190190
// Decompress the downloaded file if it is compressed and copy it into the dst
191-
if err = downloader.Download(ctx, f.Name(), dir, dir); err != nil {
191+
// NOTE: it's local copying, the insecure option doesn't matter.
192+
if err = downloader.Download(ctx, f.Name(), dir, dir, false); err != nil {
192193
return xerrors.Errorf("download error: %w", err)
193194
}
194195

pkg/plugin/index.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,9 @@ type Index struct {
3232
} `yaml:"plugins"`
3333
}
3434

35-
func (m *Manager) Update(ctx context.Context) error {
35+
func (m *Manager) Update(ctx context.Context, opts Options) error {
3636
m.logger.InfoContext(ctx, "Updating the plugin index...", log.String("url", m.indexURL))
37-
if err := downloader.Download(ctx, m.indexURL, filepath.Dir(m.indexPath), ""); err != nil {
37+
if err := downloader.Download(ctx, m.indexURL, filepath.Dir(m.indexPath), "", opts.Insecure); err != nil {
3838
return xerrors.Errorf("unable to download the plugin index: %w", err)
3939
}
4040
return nil
@@ -69,10 +69,10 @@ func (m *Manager) Search(ctx context.Context, keyword string) error {
6969

7070
// tryIndex returns the repository URL if the plugin name is found in the index.
7171
// Otherwise, it returns the input name.
72-
func (m *Manager) tryIndex(ctx context.Context, name string) string {
72+
func (m *Manager) tryIndex(ctx context.Context, name string, opts Options) string {
7373
// If the index file does not exist, download it first.
7474
if !fsutils.FileExists(m.indexPath) {
75-
if err := m.Update(ctx); err != nil {
75+
if err := m.Update(ctx, opts); err != nil {
7676
m.logger.ErrorContext(ctx, "Failed to update the plugin index", log.Err(err))
7777
return name
7878
}

pkg/plugin/index_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ func TestManager_Update(t *testing.T) {
2626
t.Cleanup(ts.Close)
2727

2828
manager := plugin.NewManager(plugin.WithIndexURL(ts.URL + "/index.yaml"))
29-
err := manager.Update(context.Background())
29+
err := manager.Update(context.Background(), plugin.Options{})
3030
require.NoError(t, err)
3131

3232
indexPath := filepath.Join(tempDir, ".trivy", "plugins", "index.yaml")

pkg/plugin/manager.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -92,13 +92,13 @@ func Upgrade(ctx context.Context, names []string) error { return defaultManager(
9292
func Uninstall(ctx context.Context, name string) error { return defaultManager().Uninstall(ctx, name) }
9393
func Information(name string) error { return defaultManager().Information(name) }
9494
func List(ctx context.Context) error { return defaultManager().List(ctx) }
95-
func Update(ctx context.Context) error { return defaultManager().Update(ctx) }
95+
func Update(ctx context.Context, opts Options) error { return defaultManager().Update(ctx, opts) }
9696
func Search(ctx context.Context, keyword string) error { return defaultManager().Search(ctx, keyword) }
9797

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

103103
// If the plugin is already installed, it skips installing the plugin.
104104
if p, installed := m.isInstalled(ctx, input.name, input.version); installed {
@@ -111,7 +111,7 @@ func (m *Manager) Install(ctx context.Context, arg string, opts Options) (Plugin
111111
}
112112

113113
func (m *Manager) install(ctx context.Context, src string, opts Options) (Plugin, error) {
114-
tempDir, err := downloader.DownloadToTempDir(ctx, src)
114+
tempDir, err := downloader.DownloadToTempDir(ctx, src, opts.Insecure)
115115
if err != nil {
116116
return Plugin{}, xerrors.Errorf("download failed: %w", err)
117117
}

pkg/plugin/plugin.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ type Options struct {
5757
Args []string
5858
Stdin io.Reader // For output plugin
5959
Platform ftypes.Platform
60+
Insecure bool
6061
}
6162

6263
func (p *Plugin) Cmd(ctx context.Context, opts Options) (*exec.Cmd, error) {
@@ -154,7 +155,7 @@ func (p *Plugin) install(ctx context.Context, dst, pwd string, opts Options) err
154155
p.Installed.Platform = lo.FromPtr(platform.Selector)
155156

156157
log.DebugContext(ctx, "Downloading the execution file...", log.String("uri", platform.URI))
157-
if err = downloader.Download(ctx, platform.URI, dst, pwd); err != nil {
158+
if err = downloader.Download(ctx, platform.URI, dst, pwd, opts.Insecure); err != nil {
158159
return xerrors.Errorf("unable to download the execution file (%s): %w", platform.URI, err)
159160
}
160161
return nil

0 commit comments

Comments
 (0)