diff --git a/.github/workflows/stackhpc-container-image-build.yml b/.github/workflows/stackhpc-container-image-build.yml
index 7ad69b8151..f3e9004998 100644
--- a/.github/workflows/stackhpc-container-image-build.yml
+++ b/.github/workflows/stackhpc-container-image-build.yml
@@ -153,9 +153,10 @@ jobs:
run: |
docker ps
- - name: Install Trivy
+ - name: Install Grype and Syft
run: |
- curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sudo sh -s -- -b /usr/local/bin v0.69.2
+ curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sudo sh -s -- -b /usr/local/bin
+ curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sudo sh -s -- -b /usr/local/bin
- name: Install yq
run: |
diff --git a/doc/source/contributor/testing-ci-automation.rst b/doc/source/contributor/testing-ci-automation.rst
index 4601c74dbd..b14af4d65c 100644
--- a/doc/source/contributor/testing-ci-automation.rst
+++ b/doc/source/contributor/testing-ci-automation.rst
@@ -230,8 +230,9 @@ A Pulp authentication proxy container is deployed on the runner that provides
unauthenticated access to the package repositories in Ark. This avoids leaking
Ark credentials into the built container images.
-Once built, images are scanned for vulnerabilities using `Trivy
-`_. Any critical vulnerabilities will break the build,
+Once built, images are scanned for vulnerabilities using `Grype
+`_ and `Syft
+`_. Any critical vulnerabilities will break the build,
unless the ``push-dirty`` input is true.
If the ``push`` input is true, images are pushed to Ark, and a `container sync
diff --git a/etc/kayobe/trivy/allowed-vulnerabilities.yml b/etc/kayobe/grype/allowed-vulnerabilities.yml
similarity index 98%
rename from etc/kayobe/trivy/allowed-vulnerabilities.yml
rename to etc/kayobe/grype/allowed-vulnerabilities.yml
index 1e17880e37..a81980a210 100644
--- a/etc/kayobe/trivy/allowed-vulnerabilities.yml
+++ b/etc/kayobe/grype/allowed-vulnerabilities.yml
@@ -1,6 +1,6 @@
---
###############################################################################
-# Trivy allowed vulnerabilities list
+# Grype allowed vulnerabilities list
# Example allowed vulnerabilities file setup
#
diff --git a/tools/scan-images.sh b/tools/scan-images.sh
index 9736b3bc74..9f4f67a8e0 100755
--- a/tools/scan-images.sh
+++ b/tools/scan-images.sh
@@ -2,21 +2,14 @@
set -eo pipefail
# Disable telemetry and version check:
-# https://github.com/aquasecurity/trivy/discussions/8945
-export TRIVY_DISABLE_TELEMETRY=true
-export TRIVY_SKIP_VERSION_CHECK=true
+export GRYPE_CHECK_FOR_APP_UPDATE=false
+export SYFT_CHECK_FOR_APP_UPDATE=false
# Global variables
scan_common_args=" \
- --exit-code 1 \
- --scanners vuln \
- --format json \
- --severity HIGH,CRITICAL \
- --ignore-unfixed \
- --db-repository ghcr.io/aquasecurity/trivy-db:2 \
- --db-repository public.ecr.aws/aquasecurity/trivy-db \
- --java-db-repository ghcr.io/aquasecurity/trivy-java-db:1 \
- --java-db-repository public.ecr.aws/aquasecurity/trivy-java-db "
+ --fail-on high \
+ --output json \
+ --only-fixed "
# Print usage instructions and error with wrong inputs
usage() {
@@ -26,11 +19,15 @@ usage() {
# Check dependencies are installed, print installation instructions otherwise
check_deps_installed() {
- if ! trivy --version > /dev/null; then
- echo 'Please install trivy: curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sudo sh -s -- -b /usr/local/bin v0.69.2'
+ if ! grype --version > /dev/null 2>&1; then
+ echo 'Please install grype: curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin'
exit 1
fi
- if ! yq --version > /dev/null; then
+ if ! syft --version > /dev/null 2>&1; then
+ echo 'Please install syft: curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin'
+ exit 1
+ fi
+ if ! yq --version > /dev/null 2>&1; then
echo 'Please install yq: sudo dnf/apt install yq'
exit 1
fi
@@ -55,20 +52,20 @@ get_images() {
cat "$output_file"
}
-# Generate ignored vulnerabilities file
-generate_trivy_ignore() {
+# Generate grype configuration file
+generate_grype_config() {
local imagename=$1
local global_vulnerabilities
- global_vulnerabilities=$(yq .global_allowed_vulnerabilities[] src/kayobe-config/etc/kayobe/trivy/allowed-vulnerabilities.yml 2> /dev/null)
+ global_vulnerabilities=$(yq .global_allowed_vulnerabilities[] src/kayobe-config/etc/kayobe/grype/allowed-vulnerabilities.yml 2> /dev/null)
local image_vulnerabilities
- image_vulnerabilities=$(yq ."$imagename"'_allowed_vulnerabilities[]' src/kayobe-config/etc/kayobe/trivy/allowed-vulnerabilities.yml 2> /dev/null)
+ image_vulnerabilities=$(yq ."$imagename"'_allowed_vulnerabilities[]' src/kayobe-config/etc/kayobe/grype/allowed-vulnerabilities.yml 2> /dev/null)
- truncate -s 0 .trivyignore # ensure we start from a clean slate
+ echo "ignore:" > .grype.yaml
for vulnerability in $global_vulnerabilities; do
- echo "$vulnerability" >> .trivyignore
+ echo " - vulnerability: $vulnerability" >> .grype.yaml
done
for vulnerability in $image_vulnerabilities; do
- echo "$vulnerability" >> .trivyignore
+ echo " - vulnerability: $vulnerability" >> .grype.yaml
done
}
@@ -79,20 +76,18 @@ generate_summary_csv() {
echo '"PkgName","PkgPath","PkgID","VulnerabilityID","FixedVersion","PrimaryURL","Severity"' > "$summary"
- jq -r '.Results[]
- | select(.Vulnerabilities)
- | .Vulnerabilities
- | map(select(.PkgName | test("kernel") | not ))
- | group_by(.VulnerabilityID)
+ jq -r '.matches
+ | map(select(.artifact.name | test("kernel") | not ))
+ | group_by(.vulnerability.id)
| map(
[
- (map(.PkgName) | unique | join(";")),
- (map(.PkgPath | select( . != null )) | join(";")),
- .[0].PkgID,
- .[0].VulnerabilityID,
- .[0].FixedVersion,
- .[0].PrimaryURL,
- .[0].Severity
+ (map(.artifact.name) | unique | join(";")),
+ (map(.artifact.locations[]?.path // empty) | unique | join(";")),
+ .[0].artifact.purl,
+ .[0].vulnerability.id,
+ (.[0].vulnerability.fix.versions | join(";")),
+ (.[0].vulnerability.urls | first),
+ (.[0].vulnerability.severity | ascii_upcase)
]
)
| .[]
@@ -111,34 +106,24 @@ categorise_image() {
fi
}
-# Generate SBOM, return correct scan command for SBOM
+# Generate SBOM using syft, return correct scan command for SBOM
generate_sbom() {
local sbom="$1"
local scan="$2"
local image="$3"
- trivy image \
- --debug \
- --format spdx-json \
- --output "$sbom" \
- "$image" &> "$sbom.log"
- if [ ! -e "$sbom" ]; then
- (
- echo "ERROR: trivy image didn't produce the sbom file $sbom for $image" 1>&2
- echo "==== trivy log ===="
- cat "$sbom.log"
- ) 1>&2
- exit 1
- elif grep -q FATAL "$sbom.log"; then
+ syft "$image" \
+ -o spdx-json \
+ > "$sbom" 2> "$sbom.log"
+
+ if [ ! -s "$sbom" ]; then
(
- echo "ERROR: trivy image encountered a fatal error producing $sbom for $image"
- echo "==== trivy log ===="
+ echo "ERROR: syft didn't produce the sbom file $sbom for $image" 1>&2
+ echo "==== syft log ===="
cat "$sbom.log"
- echo "==== sbom.json ===="
- cat "$sbom"
) 1>&2
exit 1
else
- echo "trivy sbom $scan_common_args --output $scan $sbom"
+ echo "grype $sbom $scan_common_args"
fi
}
@@ -154,7 +139,7 @@ scan_image() {
local summary="image-scan-output/${imagename}/${filename}-summary.csv"
mkdir -p "image-scan-output/$imagename"
- generate_trivy_ignore "$imagename"
+ generate_grype_config "$imagename"
# If SBOM is required, generate it first and scan the results, otherwise we
# scan the image directly.
@@ -162,19 +147,21 @@ scan_image() {
echo "Generating SBOM for $imagename"
scan_command="$(generate_sbom "$sbom" "$scan" "$image")"
else
- scan_command="trivy image $scan_common_args --output $scan $image"
+ scan_command="grype $image $scan_common_args"
fi
# Run scan against image or SBOM, format output. If no results, delete files.
echo "Scanning $imagename for vulnerabilities"
- if $scan_command >& "$scan.log"; then
+ if $scan_command > "$scan" 2> "$scan.log"; then
rm -f "$scan"
echo "${image}" >> image-scan-output/clean-images.txt
- elif [ ! -f "$scan" ]; then
+ # return code is 2 if a vulnerability is found with a severity higher than
+ # configured
+ elif [ $? -ne 2 ]; then
(
- echo "ERROR: trivy scan encountered an error producing $scan"
+ echo "ERROR: grype scan encountered an error producing $scan"
echo "Command: $scan_command"
- echo "==== trivy log ===="
+ echo "==== grype log ===="
cat "$scan.log"
if $generate_sbom; then
echo "==== sbom.json ===="
@@ -184,7 +171,11 @@ scan_image() {
exit 1
else
generate_summary_csv "$scan" "$summary"
- categorise_image "$summary" "$image"
+ if [ "$(tail -n +2 "$summary" | wc -l)" -eq 0 ]; then
+ echo "${image}" >> image-scan-output/clean-images.txt
+ else
+ categorise_image "$summary" "$image"
+ fi
fi
}