Skip to content

Commit 666bc89

Browse files
feat(trivy): add new trivy feature that also installs plugins
1 parent 6f39a29 commit 666bc89

12 files changed

Lines changed: 386 additions & 0 deletions

.github/workflows/test.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ jobs:
1414
matrix:
1515
features:
1616
- sbom
17+
- trivy
1718
baseImage:
1819
- debian:latest
1920
- ubuntu:latest

src/trivy/README.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
2+
# Trivy (trivy)
3+
4+
A feature to install Trivy to scan for vulnerabilities in container images, file systems, and Git repositories.
5+
6+
## Example Usage
7+
8+
```json
9+
"features": {
10+
"ghcr.io/JasonTheDeveloper/features/trivy:1": {}
11+
}
12+
```
13+
14+
## Options
15+
16+
| Options Id | Description | Type | Default Value |
17+
|-----|-----|-----|-----|
18+
| version | Select or enter Trivy version | string | latest |
19+
| plugins | Select or enter additional plugins to install with Trivy (e.g., mcp for Model Context Protocol plugin) | string | - |
20+
21+
### version
22+
23+
The version of Trivy to install. Set to `"latest"` (default) to automatically fetch the most recent release, or specify an exact version such as `"0.69.1"`. The installer will validate that the requested version exists before proceeding.
24+
25+
### plugins
26+
27+
A comma or space separated list of Trivy plugins to install after Trivy itself is set up. For example:
28+
29+
```json
30+
"features": {
31+
"ghcr.io/JasonTheDeveloper/features/trivy:1": {
32+
"version": "latest",
33+
"plugins": "mcp"
34+
}
35+
}
36+
```
37+
38+
Multiple plugins can be specified:
39+
40+
```json
41+
"plugins": "plugin1, plugin2"
42+
```
43+
44+
---
45+
46+
_Note: This file was auto-generated from the [devcontainer-feature.json](https://github.com/JasonTheDeveloper/features/blob/main/src/trivy/devcontainer-feature.json). Add additional notes to a `NOTES.md`._
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"name": "Trivy",
3+
"id": "trivy",
4+
"version": "1.0.0",
5+
"description": "A feature to install Trivy to scan for vulnerabilities in container images, file systems, and Git repositories",
6+
"options": {
7+
"version": {
8+
"type": "string",
9+
"proposals": [
10+
"latest",
11+
"0.69.1"
12+
],
13+
"default": "latest",
14+
"description": "Select or enter Trivy version"
15+
},
16+
"plugins": {
17+
"type": "string",
18+
"proposals": [
19+
"mcp"
20+
],
21+
"default": "",
22+
"description": "Select or enter additional plugins to install with Trivy (e.g., mcp for Model Context Protocol plugin)"
23+
}
24+
}
25+
}

src/trivy/install.sh

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
#!/bin/bash
2+
3+
TRIVY_VERSION="${VERSION:-"latest"}"
4+
TRIVY_PLUGINS="${PLUGINS:-""}"
5+
6+
set -e
7+
8+
# Clean up
9+
rm -rf /var/lib/apt/lists/*
10+
11+
if [ "$(id -u)" -ne 0 ]; then
12+
echo -e 'Script must be run as root. Use sudo, su, or add "USER root" to your Dockerfile before running this script.'
13+
exit 1
14+
fi
15+
16+
# Checks if packages are installed and installs them if not
17+
check_packages() {
18+
if ! dpkg -s "$@" >/dev/null 2>&1; then
19+
if [ "$(find /var/lib/apt/lists/* | wc -l)" = "0" ]; then
20+
echo "Running apt-get update..."
21+
apt-get update -y
22+
fi
23+
apt-get -y install --no-install-recommends "$@"
24+
fi
25+
}
26+
27+
# Resolve "latest" to the actual latest version tag, and validate that the
28+
# requested version exists in the GitHub releases.
29+
resolve_and_validate_version() {
30+
local requested_version=$1
31+
32+
if [ "${requested_version}" = "latest" ]; then
33+
requested_version=$(curl -sL https://api.github.com/repos/aquasecurity/trivy/releases/latest | jq -r ".tag_name")
34+
if [ -z "${requested_version}" ] || [ "${requested_version}" = "null" ]; then
35+
echo "Failed to fetch the latest Trivy version." >&2
36+
exit 1
37+
fi
38+
fi
39+
40+
# Ensure the version starts with "v"
41+
if [[ "${requested_version}" != v* ]]; then
42+
requested_version="v${requested_version}"
43+
fi
44+
45+
# Validate the version exists
46+
local version_list
47+
version_list=$(curl -sL https://api.github.com/repos/aquasecurity/trivy/releases | jq -r ".[].tag_name")
48+
if ! echo "${version_list}" | grep -qx "${requested_version}"; then
49+
echo -e "Invalid Trivy version: ${requested_version}\nValid recent versions:\n${version_list}" >&2
50+
exit 1
51+
fi
52+
53+
echo "${requested_version}"
54+
}
55+
56+
# Install Trivy plugins. Accepts a comma or space separated list of plugin names.
57+
install_plugins() {
58+
local plugins_input=$1
59+
60+
# Replace commas with spaces to normalize the separator
61+
local plugins
62+
plugins=$(echo "${plugins_input}" | tr ',' ' ')
63+
64+
for plugin in ${plugins}; do
65+
# Trim whitespace
66+
plugin=$(echo "${plugin}" | xargs)
67+
if [ -n "${plugin}" ]; then
68+
echo "Installing Trivy plugin: ${plugin}..."
69+
trivy plugin install "${plugin}"
70+
fi
71+
done
72+
}
73+
74+
# Make sure we have required dependencies
75+
check_packages curl jq ca-certificates
76+
77+
# Resolve and validate the version
78+
echo "Resolving Trivy version '${TRIVY_VERSION}'..."
79+
TRIVY_VERSION=$(resolve_and_validate_version "${TRIVY_VERSION}")
80+
echo "Installing Trivy ${TRIVY_VERSION}..."
81+
82+
# Install Trivy using the official convenience script
83+
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin "${TRIVY_VERSION}"
84+
85+
# Verify installation
86+
trivy --version
87+
88+
# Install plugins if specified
89+
if [ -n "${TRIVY_PLUGINS}" ]; then
90+
echo "Installing Trivy plugins..."
91+
install_plugins "${TRIVY_PLUGINS}"
92+
fi
93+
94+
# Clean up
95+
rm -rf /var/lib/apt/lists/*
96+
97+
echo "Done!"

test/trivy/install_trivy_latest.sh

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#!/usr/bin/env bash
2+
3+
# Scenario: install_trivy_latest
4+
# Verifies that trivy installs successfully when version is set to "latest"
5+
6+
set -e
7+
8+
source dev-container-features-test-lib
9+
10+
# Verify trivy is installed
11+
check "trivy is installed" bash -c "which trivy"
12+
13+
# Verify trivy version output is not empty
14+
check "trivy version reports output" bash -c "trivy --version | grep -i 'version'"
15+
16+
# Verify trivy binary is in the expected location
17+
check "trivy in /usr/local/bin" bash -c "ls /usr/local/bin/trivy"
18+
19+
reportResults
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#!/usr/bin/env bash
2+
3+
# Scenario: install_trivy_specific_version
4+
# Verifies that a specific version of trivy (without "v" prefix) installs correctly
5+
6+
set -e
7+
8+
source dev-container-features-test-lib
9+
10+
# Verify trivy is installed
11+
check "trivy is installed" bash -c "which trivy"
12+
13+
# Verify the exact version is installed (0.69.1)
14+
check "trivy version is 0.69.1" bash -c "trivy --version | grep '0.69.1'"
15+
16+
reportResults
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#!/usr/bin/env bash
2+
3+
# Scenario: install_trivy_with_plugin
4+
# Verifies that trivy installs with the mcp plugin
5+
6+
set -e
7+
8+
source dev-container-features-test-lib
9+
10+
# Verify trivy is installed
11+
check "trivy is installed" bash -c "which trivy"
12+
13+
# Verify trivy version runs
14+
check "trivy version runs" bash -c "trivy --version"
15+
16+
# Verify the mcp plugin is installed
17+
check "mcp plugin is installed" bash -c "trivy plugin list | grep -i 'mcp'"
18+
19+
reportResults
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#!/usr/bin/env bash
2+
3+
# Scenario: install_trivy_with_v_prefix
4+
# Verifies that specifying a version with the "v" prefix works correctly
5+
6+
set -e
7+
8+
source dev-container-features-test-lib
9+
10+
# Verify trivy is installed
11+
check "trivy is installed" bash -c "which trivy"
12+
13+
# Verify the exact version is installed (0.69.1)
14+
check "trivy version is 0.69.1" bash -c "trivy --version | grep '0.69.1'"
15+
16+
reportResults

test/trivy/invalid_plugin.sh

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#!/usr/bin/env bash
2+
3+
# Scenario: invalid_plugin
4+
# Verifies that trivy plugin install fails gracefully when given a
5+
# non-existent plugin name. Trivy is installed with defaults so the
6+
# container builds successfully, and we then test the error path.
7+
8+
set -e
9+
10+
source dev-container-features-test-lib
11+
12+
# Trivy should be installed (the scenario uses "latest")
13+
check "trivy is installed" bash -c "which trivy"
14+
15+
# Attempting to install a non-existent plugin should fail (non-zero exit)
16+
check "install of non-existent plugin fails" bash -c '
17+
if trivy plugin install this-plugin-does-not-exist-xyz 2>&1; then
18+
echo "ERROR: expected plugin install to fail but it succeeded"
19+
exit 1
20+
fi
21+
echo "Correctly failed to install non-existent plugin"
22+
'
23+
24+
# Verify the fake plugin does NOT appear in the plugin list
25+
check "non-existent plugin is not listed" bash -c \
26+
"! trivy plugin list 2>&1 | grep -qi 'this-plugin-does-not-exist-xyz'"
27+
28+
reportResults

test/trivy/invalid_version.sh

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#!/usr/bin/env bash
2+
3+
# Scenario: invalid_version
4+
# Verifies that the install script's version validation correctly rejects
5+
# a non-existent version. Since the container must build successfully to
6+
# run tests, trivy is installed with "latest" and we then exercise the
7+
# validation logic manually.
8+
9+
set -e
10+
11+
source dev-container-features-test-lib
12+
13+
# Trivy should be installed (the scenario uses "latest")
14+
check "trivy is installed" bash -c "which trivy"
15+
16+
# Verify that a completely fake version does NOT appear in the releases list
17+
check "fake version not in releases" bash -c \
18+
"! curl -sL https://api.github.com/repos/aquasecurity/trivy/releases | jq -r '.[].tag_name' | grep -qx 'v99.99.99'"
19+
20+
# Simulate the install script's validation: attempt to match a non-existent
21+
# version against the release list and confirm it fails
22+
check "validation rejects non-existent version" bash -c '
23+
version_list=$(curl -sL https://api.github.com/repos/aquasecurity/trivy/releases | jq -r ".[].tag_name")
24+
if echo "${version_list}" | grep -qx "v99.99.99"; then
25+
echo "ERROR: fake version was found in release list"
26+
exit 1
27+
fi
28+
echo "Correctly rejected non-existent version v99.99.99"
29+
'
30+
31+
# Also verify that a valid version IS accepted by the same logic
32+
check "validation accepts a real version" bash -c '
33+
version_list=$(curl -sL https://api.github.com/repos/aquasecurity/trivy/releases | jq -r ".[].tag_name")
34+
if ! echo "${version_list}" | grep -qx "v0.69.1"; then
35+
echo "ERROR: valid version v0.69.1 was not found in release list"
36+
exit 1
37+
fi
38+
echo "Correctly accepted valid version v0.69.1"
39+
'
40+
41+
reportResults

0 commit comments

Comments
 (0)