Skip to content

Commit 3448241

Browse files
kinda works
1 parent 365e53d commit 3448241

File tree

2 files changed

+181
-46
lines changed

2 files changed

+181
-46
lines changed

config/trivy-utils.go

Lines changed: 169 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,42 @@ import (
88
"os/exec"
99
"path/filepath"
1010
"runtime"
11+
"strings"
12+
13+
"gopkg.in/yaml.v3"
1114
)
1215

16+
// TrivyPluginConfig represents the structure of the trivy plugin.yaml file
17+
type TrivyPluginConfig struct {
18+
Name string `yaml:"name"`
19+
Description string `yaml:"description"`
20+
Downloads []TrivyDownloadConfig `yaml:"downloads"`
21+
ArchMapping map[string]string `yaml:"arch_mapping"`
22+
Binaries []TrivyBinaryConfig `yaml:"binaries"`
23+
}
24+
25+
// TrivyDownloadConfig represents the download configuration in plugin.yaml
26+
type TrivyDownloadConfig struct {
27+
OS []string `yaml:"os"`
28+
URLTemplate string `yaml:"url_template"`
29+
FileNameTemplate string `yaml:"file_name_template"`
30+
Extension TrivyExtensionConfig `yaml:"extension"`
31+
}
32+
33+
// TrivyExtensionConfig defines the file extension based on OS
34+
type TrivyExtensionConfig struct {
35+
Windows string `yaml:"windows"`
36+
Default string `yaml:"default"`
37+
}
38+
39+
// TrivyBinaryConfig represents a binary executable
40+
type TrivyBinaryConfig struct {
41+
Name string `yaml:"name"`
42+
Path string `yaml:"path"`
43+
}
44+
1345
/*
14-
* This installs Trivy using the official install script
46+
* This installs Trivy based on the plugin.yaml configuration
1547
*/
1648
func InstallTrivy(trivyConfig *Runtime, registry string) error {
1749
log.Println("Installing Trivy")
@@ -20,66 +52,156 @@ func InstallTrivy(trivyConfig *Runtime, registry string) error {
2052
trivyFolder := fmt.Sprintf("%s@%s", trivyConfig.Name(), trivyConfig.Version())
2153
installDir := filepath.Join(Config.ToolsDirectory(), trivyFolder)
2254

23-
// Check if already installed
24-
if isTrivyInstalled(trivyConfig) {
25-
fmt.Printf("Trivy %s is already installed\n", trivyConfig.Version())
26-
return nil
27-
}
28-
2955
// Create installation directory
3056
err := os.MkdirAll(installDir, 0755)
3157
if err != nil {
3258
return fmt.Errorf("failed to create installation directory: %w", err)
3359
}
3460

35-
// Use the official install script to download and install Trivy
36-
version := fmt.Sprintf("v%s", trivyConfig.Version())
37-
installScriptURL := "https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh"
61+
// Load the plugin configuration
62+
pluginPath := filepath.Join("plugins", "tools", "trivy", "plugin.yaml")
63+
pluginConfig, err := loadTrivyPluginConfig(pluginPath)
64+
if err != nil {
65+
return fmt.Errorf("failed to load Trivy plugin configuration: %w", err)
66+
}
3867

39-
log.Printf("Installing Trivy %s using the official install script\n", version)
68+
// Find the download configuration for the current OS
69+
var downloadConfig *TrivyDownloadConfig
70+
currentOS := runtime.GOOS
71+
if currentOS == "darwin" {
72+
currentOS = "macos"
73+
}
74+
75+
for i := range pluginConfig.Downloads {
76+
for _, os := range pluginConfig.Downloads[i].OS {
77+
if os == currentOS {
78+
downloadConfig = &pluginConfig.Downloads[i]
79+
break
80+
}
81+
}
82+
if downloadConfig != nil {
83+
break
84+
}
85+
}
86+
87+
if downloadConfig == nil {
88+
return fmt.Errorf("no download configuration found for OS %s", runtime.GOOS)
89+
}
90+
91+
// Get the mapped architecture
92+
arch := runtime.GOARCH
93+
if mappedArch, ok := pluginConfig.ArchMapping[arch]; ok {
94+
arch = mappedArch
95+
}
96+
97+
// Get the appropriate extension
98+
extension := downloadConfig.Extension.Default
99+
if runtime.GOOS == "windows" && downloadConfig.Extension.Windows != "" {
100+
extension = downloadConfig.Extension.Windows
101+
}
102+
103+
// Template substitution for URL
104+
version := trivyConfig.Version()
105+
versionWithPrefix := fmt.Sprintf("v%s", version)
106+
107+
// Handle template substitution properly
108+
fileName := strings.ReplaceAll(downloadConfig.FileNameTemplate, "{{.Version}}", version)
109+
fileName = strings.ReplaceAll(fileName, "{{.OS}}", currentOS)
110+
fileName = strings.ReplaceAll(fileName, "{{.Arch}}", arch)
111+
112+
// Generate URL, making sure to handle the version format
113+
url := strings.ReplaceAll(downloadConfig.URLTemplate, "{{.Version}}", versionWithPrefix)
114+
// If URL template already has v prefix, we need to use version without prefix
115+
if strings.Contains(downloadConfig.URLTemplate, "/v{{.Version}}/") {
116+
url = strings.ReplaceAll(downloadConfig.URLTemplate, "{{.Version}}", version)
117+
}
40118

41-
// Create a temporary directory for the installation
119+
url = strings.ReplaceAll(url, "{{.FileName}}", fileName)
120+
url = strings.ReplaceAll(url, "{{.Extension}}", extension)
121+
url = strings.ReplaceAll(url, "{{.OS}}", currentOS)
122+
url = strings.ReplaceAll(url, "{{.Arch}}", arch)
123+
124+
log.Printf("Using download URL from plugin configuration: %s\n", url)
125+
log.Printf("Using filename: %s.%s\n", fileName, extension)
126+
127+
// Create a temporary directory for the download
42128
tempDir := filepath.Join(installDir, "temp")
43129
err = os.MkdirAll(tempDir, 0755)
44130
if err != nil {
45131
return fmt.Errorf("failed to create temporary directory: %w", err)
46132
}
133+
defer os.RemoveAll(tempDir)
47134

48-
// Download and run the install script
49-
cmd := exec.Command("sh", "-c", fmt.Sprintf("curl -sfL %s | sh -s -- -b %s %s",
50-
installScriptURL, tempDir, version))
51-
135+
// Download and extract
136+
downloadPath := filepath.Join(tempDir, fmt.Sprintf("%s.%s", fileName, extension))
137+
cmd := exec.Command("curl", "-L", "-o", downloadPath, url)
52138
output, err := cmd.CombinedOutput()
53139
if err != nil {
54-
return fmt.Errorf("failed to run Trivy install script: %w\nOutput: %s", err, string(output))
140+
return fmt.Errorf("failed to download Trivy: %w\nOutput: %s", err, string(output))
55141
}
56142

57-
log.Printf("Install script output: %s\n", string(output))
143+
log.Printf("Downloaded Trivy to: %s\n", downloadPath)
58144

59-
// Copy the Trivy binary to the final location
60-
sourcePath := filepath.Join(tempDir, "trivy")
61-
if runtime.GOOS == "windows" {
62-
sourcePath += ".exe"
145+
// Extract the archive
146+
extractDir := filepath.Join(tempDir, "extracted")
147+
err = os.MkdirAll(extractDir, 0755)
148+
if err != nil {
149+
return fmt.Errorf("failed to create extraction directory: %w", err)
63150
}
64151

65-
binaryPath := filepath.Join(installDir, "trivy")
152+
if extension == "zip" {
153+
cmd = exec.Command("unzip", "-q", downloadPath, "-d", extractDir)
154+
} else {
155+
cmd = exec.Command("tar", "-xzf", downloadPath, "-C", extractDir)
156+
}
157+
output, err = cmd.CombinedOutput()
158+
if err != nil {
159+
return fmt.Errorf("failed to extract Trivy: %w\nOutput: %s", err, string(output))
160+
}
161+
162+
log.Printf("Extracted Trivy to: %s\n", extractDir)
163+
164+
// Find the binary from the plugin configuration
165+
var binaryConfig *TrivyBinaryConfig
166+
if len(pluginConfig.Binaries) > 0 {
167+
binaryConfig = &pluginConfig.Binaries[0]
168+
} else {
169+
return fmt.Errorf("no binary configuration found in the plugin")
170+
}
171+
172+
// Find the binary in the extracted directory
173+
var binaryPath string
174+
binaryName := binaryConfig.Name
66175
if runtime.GOOS == "windows" {
67-
binaryPath += ".exe"
176+
binaryName += ".exe"
68177
}
69178

70-
// Check if the source binary exists
71-
if _, err := os.Stat(sourcePath); os.IsNotExist(err) {
72-
return fmt.Errorf("trivy binary not found at %s after installation", sourcePath)
179+
err = filepath.Walk(extractDir, func(path string, info os.FileInfo, err error) error {
180+
if err != nil {
181+
return err
182+
}
183+
if !info.IsDir() && filepath.Base(path) == binaryName {
184+
binaryPath = path
185+
return filepath.SkipDir
186+
}
187+
return nil
188+
})
189+
190+
if binaryPath == "" {
191+
return fmt.Errorf("could not find %s binary in extracted files", binaryName)
73192
}
74193

194+
log.Printf("Found Trivy binary at: %s\n", binaryPath)
195+
75196
// Copy the binary to the final location
76-
source, err := os.Open(sourcePath)
197+
destPath := filepath.Join(installDir, binaryName)
198+
source, err := os.Open(binaryPath)
77199
if err != nil {
78200
return fmt.Errorf("failed to open source binary: %w", err)
79201
}
80202
defer source.Close()
81203

82-
destination, err := os.Create(binaryPath)
204+
destination, err := os.Create(destPath)
83205
if err != nil {
84206
return fmt.Errorf("failed to create destination binary: %w", err)
85207
}
@@ -90,19 +212,32 @@ func InstallTrivy(trivyConfig *Runtime, registry string) error {
90212
return fmt.Errorf("failed to copy binary: %w", err)
91213
}
92214

93-
// Make the copied binary executable
94-
err = os.Chmod(binaryPath, 0755)
215+
// Make the binary executable
216+
err = os.Chmod(destPath, 0755)
95217
if err != nil {
96218
return fmt.Errorf("failed to make binary executable: %w", err)
97219
}
98220

99-
// Clean up the temporary directory
100-
os.RemoveAll(tempDir)
101-
102221
log.Printf("Successfully installed Trivy %s\n", trivyConfig.Version())
103222
return nil
104223
}
105224

225+
// loadTrivyPluginConfig loads the Trivy plugin configuration from the plugin.yaml file
226+
func loadTrivyPluginConfig(path string) (*TrivyPluginConfig, error) {
227+
data, err := os.ReadFile(path)
228+
if err != nil {
229+
return nil, fmt.Errorf("error reading plugin config file: %w", err)
230+
}
231+
232+
var config TrivyPluginConfig
233+
err = yaml.Unmarshal(data, &config)
234+
if err != nil {
235+
return nil, fmt.Errorf("error parsing plugin config file: %w", err)
236+
}
237+
238+
return &config, nil
239+
}
240+
106241
// isTrivyInstalled checks if Trivy is already installed
107242
func isTrivyInstalled(trivyConfig *Runtime) bool {
108243
trivyFolder := fmt.Sprintf("%s@%s", trivyConfig.Name(), trivyConfig.Version())

plugins/tools/trivy/plugin.yaml

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,28 @@
11
name: trivy
2-
description: Container and Filesystem Vulnerability Scanner
2+
description: Trivy vulnerability scanner
33
downloads:
44
- os: [linux]
5-
url_template: "https://github.com/aquasecurity/trivy/releases/download/{{.Version}}/trivy_{{.Version}}_Linux-{{.Arch}}.{{.Extension}}"
6-
file_name_template: "trivy_{{.Version}}_{{.OS}}_{{.Arch}}"
5+
url_template: "https://github.com/aquasecurity/trivy/releases/download/v{{.Version}}/trivy_{{.Version}}_Linux-{{.Arch}}.{{.Extension}}"
6+
file_name_template: "trivy_{{.Version}}_Linux-{{.Arch}}"
77
extension:
88
windows: "zip"
99
default: "tar.gz"
10-
- os: [macos]
11-
url_template: "https://github.com/aquasecurity/trivy/releases/download/{{.Version}}/trivy_{{.Version}}_macOS-{{.Arch}}.{{.Extension}}"
12-
file_name_template: "trivy_{{.Version}}_{{.OS}}_{{.Arch}}"
10+
- os: [macos, darwin]
11+
url_template: "https://github.com/aquasecurity/trivy/releases/download/v{{.Version}}/trivy_{{.Version}}_macOS-{{.Arch}}.{{.Extension}}"
12+
file_name_template: "trivy_{{.Version}}_macOS-{{.Arch}}"
1313
extension:
1414
windows: "zip"
1515
default: "tar.gz"
1616
- os: [windows]
17-
url_template: "https://github.com/aquasecurity/trivy/releases/download/{{.Version}}/trivy_{{.Version}}_windows-{{.Arch}}.{{.Extension}}"
18-
file_name_template: "trivy_{{.Version}}_{{.OS}}_{{.Arch}}"
17+
url_template: "https://github.com/aquasecurity/trivy/releases/download/v{{.Version}}/trivy_{{.Version}}_windows-{{.Arch}}.{{.Extension}}"
18+
file_name_template: "trivy_{{.Version}}_windows-{{.Arch}}"
1919
extension:
2020
default: "zip"
2121
arch_mapping:
22-
"386": "x86"
23-
"amd64": "x64"
24-
"arm": "armv7l"
25-
"arm64": "arm64"
22+
"386": "32bit"
23+
"amd64": "64bit"
24+
"arm": "ARM"
25+
"arm64": "ARM64"
2626
binaries:
2727
- name: trivy
2828
path: "trivy"

0 commit comments

Comments
 (0)