Skip to content

Commit 71bfc08

Browse files
committed
[scripts] Introduce trivy-scan-images.sh
Tool: gitpod/catfood.gitpod.cloud
1 parent 91ad3e7 commit 71bfc08

File tree

3 files changed

+222
-0
lines changed

3 files changed

+222
-0
lines changed
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
apiVersion: v1
2+
domain: example.com
3+
authProviders: []
4+
blockNewUsers:
5+
enabled: false
6+
passlist: []
7+
certificate:
8+
kind: secret
9+
name: https-certificates
10+
containerRegistry:
11+
enableAdditionalECRAuth: false
12+
inCluster: false
13+
privateBaseImageAllowList: []
14+
subassemblyBucket: ""
15+
external:
16+
url: "registry.example.com"
17+
certificate:
18+
kind: secret
19+
name: registry-certificate
20+
database:
21+
inCluster: false
22+
external:
23+
certificate:
24+
kind: secret
25+
name: database-certificate
26+
disableDefinitelyGp: true
27+
kind: Full
28+
metadata:
29+
region: local
30+
shortname: default
31+
objectStorage:
32+
inCluster: false
33+
resources:
34+
requests:
35+
memory: 2Gi
36+
s3:
37+
endpoint: "s3.example.com"
38+
bucket: "gitpod-storage"
39+
credentials:
40+
kind: secret
41+
name: object-storage-credentials
42+
observability:
43+
logLevel: info
44+
openVSX:
45+
url: https://open-vsx.org
46+
repository: eu.gcr.io/gitpod-dev-artifact/build
47+
workspace:
48+
maxLifetime: 36h0m0s
49+
resources:
50+
requests:
51+
cpu: "1"
52+
memory: 2Gi
53+
runtime:
54+
containerdRuntimeDir: /var/lib/containerd/io.containerd.runtime.v2.task/k8s.io
55+
containerdSocketDir: /run/containerd
56+
fsShiftMethod: shiftfs

scripts/trivy/trivy-scan-images.sh

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
#!/bin/bash
2+
# Copyright (c) 2025 Gitpod GmbH. All rights reserved.
3+
# Licensed under the GNU Affero General Public License (AGPL).
4+
# See License.AGPL.txt in the project root for license information.
5+
6+
set -uo pipefail
7+
8+
# Check if VERSION and FAIL_ON are provided
9+
if [[ $# -lt 2 ]]; then
10+
echo "Usage: $0 VERSION FAIL_ON [TRIVY_ARGS...]"
11+
echo " VERSION: The version to scan (e.g., main-gha.32006)"
12+
echo " FAIL_ON: Severity threshold to fail on (empty, HIGH, or CRITICAL)"
13+
echo " TRIVY_ARGS: Additional arguments to pass to Trivy"
14+
echo "Example: $0 main-gha.32006 HIGH"
15+
exit 1
16+
fi
17+
18+
# Extract VERSION and FAIL_ON from arguments and remove them from args list
19+
VERSION="$1"
20+
FAIL_ON="$2"
21+
shift 2
22+
23+
# Validate FAIL_ON value
24+
if [[ -n "$FAIL_ON" ]] && [[ "$FAIL_ON" != "HIGH" ]] && [[ "$FAIL_ON" != "CRITICAL" ]]; then
25+
echo "Error: FAIL_ON must be either empty, 'HIGH', or 'CRITICAL'"
26+
exit 1
27+
fi
28+
29+
30+
if ! command -v jq &> /dev/null; then
31+
echo "jq not found. Please install jq to continue."
32+
exit 1
33+
fi
34+
35+
# Set up working directory
36+
SCAN_DIR=$(mktemp -d -t trivy-scan-XXXXXX)
37+
echo "Working directory: $SCAN_DIR"
38+
39+
# Directory where this script is located
40+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
41+
CONFIG_DIR="$SCRIPT_DIR"
42+
INSTALLER_CONFIG_FILE="scan-installer-config.yaml"
43+
TRIVYIGNORE_PATH="$SCRIPT_DIR/trivyignore.yaml"
44+
45+
# Ensure Trivy is installed
46+
TRIVY_CMD="trivy"
47+
if ! command -v "$TRIVY_CMD" &> /dev/null; then
48+
echo "Trivy not found. Installing..."
49+
mkdir -p "$SCAN_DIR/bin"
50+
TRIVY_CMD="$SCAN_DIR/bin/trivy"
51+
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b "$SCAN_DIR/bin"
52+
fi
53+
54+
echo "=== Gathering list of all images for $VERSION"
55+
# Run the installer docker image to get the list of images
56+
docker run --rm -v "$CONFIG_DIR:/config" eu.gcr.io/gitpod-core-dev/build/installer:"${VERSION}" mirror list \
57+
-c "/config/$INSTALLER_CONFIG_FILE" > "$SCAN_DIR/mirror.json"
58+
59+
# Extract original image references
60+
jq -r '.[].original' "$SCAN_DIR/mirror.json" > "$SCAN_DIR/images.txt"
61+
62+
# Remove empty lines
63+
sed -i '/^\s*$/d' "$SCAN_DIR/images.txt"
64+
65+
# Filter out specific image patterns
66+
echo "=== Filtered out images:"
67+
TOTAL_BEFORE=$(wc -l < "$SCAN_DIR/images.txt")
68+
69+
# Apply all filters at once using extended regex
70+
grep -v -E "/build/ide/|/gitpod/workspace-|/library/mysql|/library/redis|/cloudsql-docker/gce-proxy" "$SCAN_DIR/images.txt" > "$SCAN_DIR/filtered_images.txt"
71+
72+
TOTAL_AFTER=$(wc -l < "$SCAN_DIR/filtered_images.txt")
73+
FILTERED=$((TOTAL_BEFORE - TOTAL_AFTER))
74+
75+
echo " Total filtered: $FILTERED"
76+
77+
# Use filtered list for scanning
78+
mv "$SCAN_DIR/filtered_images.txt" "$SCAN_DIR/images.txt"
79+
80+
# Count total images
81+
TOTAL_IMAGES=$(wc -l < "$SCAN_DIR/images.txt")
82+
echo "=== Found $TOTAL_IMAGES images to scan"
83+
84+
# Create results directory
85+
RESULT_FILE="$SCAN_DIR/result.jsonl"
86+
87+
# Scan all images with Trivy
88+
COUNTER=0
89+
FAILED=0
90+
while IFS= read -r IMAGE_REF; do
91+
((COUNTER=COUNTER+1))
92+
93+
echo "= Scanning $IMAGE_REF [$COUNTER / $TOTAL_IMAGES]"
94+
95+
# Run Trivy on the image
96+
scan_time=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
97+
trivy_output=$("$TRIVY_CMD" image "$IMAGE_REF" --ignorefile "$TRIVYIGNORE_PATH" --scanners vuln --format json "$@" | jq -c)
98+
scan_status=$?
99+
100+
# Create a JSON object for the current scan
101+
if [ $scan_status -eq 0 ]; then
102+
# Check if trivy_output is valid JSON
103+
if echo "$trivy_output" | jq empty > /dev/null 2>&1; then
104+
# Direct approach - create the combined JSON object using jq directly
105+
jq -c --arg image "$IMAGE_REF" --arg scan_time "$scan_time" \
106+
'. + {image: $image, scan_time: $scan_time}' <<< "$trivy_output" | jq >> "$RESULT_FILE"
107+
else
108+
# If trivy output is not valid JSON, treat as error
109+
echo "Warning: Trivy returned invalid JSON for $IMAGE_REF"
110+
jq -n --arg image "$IMAGE_REF" \
111+
--arg scan_time "$scan_time" \
112+
--arg error "Invalid JSON output from Trivy" \
113+
--arg details "$trivy_output" \
114+
'{image: $image, scan_time: $scan_time, error: $error, error_details: $details}' | jq >> "$RESULT_FILE"
115+
((FAILED=FAILED+1))
116+
fi
117+
118+
else
119+
# For error cases, create a simple JSON object
120+
jq -n --arg image "$IMAGE_REF" \
121+
--arg scan_time "$scan_time" \
122+
--arg error "Trivy scan failed" \
123+
--arg details "$trivy_output" \
124+
'{image: $image, scan_time: $scan_time, error: $error, error_details: $details}' >> "$RESULT_FILE"
125+
((FAILED=FAILED+1))
126+
fi
127+
128+
echo ""
129+
done < "$SCAN_DIR/images.txt"
130+
131+
# Generate summary report
132+
echo "=== Scan Summary ==="
133+
echo "Scan directory: $SCAN_DIR"
134+
echo "Results file: $RESULT_FILE"
135+
echo "Total ignored images: $FILTERED"
136+
echo "Total scanned images: $TOTAL_IMAGES"
137+
echo "Failed scans: $FAILED"
138+
echo "Triviy binary: $TRIVY_CMD"
139+
echo "Triviy version: $($TRIVY_CMD version)"
140+
echo ""
141+
142+
# Count vulnerabilities by severity
143+
echo "=== Vulnerability Summary ==="
144+
CRITICAL="$(jq -r 'if .Results != null then [.Results[].Vulnerabilities // [] | .[] | select(.Severity == "CRITICAL")] | length else 0 end' "$RESULT_FILE" 2>/dev/null | awk '{sum+=$1} END {print sum}')"
145+
HIGH="$(jq -r 'if .Results != null then [.Results[].Vulnerabilities // [] | .[] | select(.Severity == "HIGH")] | length else 0 end' "$RESULT_FILE" 2>/dev/null | awk '{sum+=$1} END {print sum}')"
146+
echo "CRITICAL: $CRITICAL"
147+
echo "HIGH: $HIGH"
148+
echo ""
149+
150+
echo "=== Scan completed ==="
151+
if [[ $FAILED -gt 0 ]]; then
152+
echo "ERROR: $FAILED scans failed"
153+
exit 1
154+
fi
155+
156+
# Check if we should fail based on vulnerability counts
157+
if [[ "$FAIL_ON" == "CRITICAL" ]] && [[ $CRITICAL -gt 0 ]]; then
158+
echo "FAIL: Found $CRITICAL CRITICAL vulnerabilities, and FAIL_ON=CRITICAL was specified"
159+
exit 1
160+
elif [[ "$FAIL_ON" == "HIGH" ]] && [[ $((CRITICAL + HIGH)) -gt 0 ]]; then
161+
echo "FAIL: Found $CRITICAL CRITICAL and $HIGH HIGH vulnerabilities, and FAIL_ON=HIGH was specified"
162+
exit 1
163+
fi
164+
165+
echo "0 $FAIL_ON or higher vulnerabilities found."
166+
exit 0

scripts/trivy/trivyignore.yaml

Whitespace-only changes.

0 commit comments

Comments
 (0)