From 1a090f1d26d5c7ed693992735ac29eae7dd3ee8d Mon Sep 17 00:00:00 2001
From: Valery Kharseko <vharseko@3a-systems.ru>
Date: Fri, 07 Aug 2026 14:59:19 +0000
Subject: [PATCH] Add Trivy vulnerability scanning for Docker images (#854)
---
.github/workflows/docker-scan.yml | 59 +++++++++++++++++++++++++++++
.github/workflows/build.yml | 55 +++++++++++++++++++++++++++
2 files changed, 113 insertions(+), 1 deletions(-)
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index a868163..f92f3b7 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -24,7 +24,8 @@
cancel-in-progress: true
# Nothing in this workflow writes back to the repository: the docker jobs push to
-# the local registry service, not to a remote one.
+# the local registry service, not to a remote one. The docker jobs additionally get
+# security-events: write to upload Trivy scan results to code scanning.
permissions:
contents: read
@@ -393,6 +394,9 @@
build-docker:
needs: build-maven
runs-on: 'ubuntu-latest'
+ permissions:
+ contents: read
+ security-events: write
services:
registry:
image: registry:3
@@ -411,6 +415,7 @@
run: |
export git_version_last="$(curl -i -o - --silent https://api.github.com/repos/OpenIdentityPlatform/OpenDJ/releases/latest | grep -m1 "\"name\"" | cut -d\" -f4)" ; echo "last release: $git_version_last"
echo "release_version=$git_version_last" >> $GITHUB_ENV
+ echo "image_repository=${GITHUB_REPOSITORY,,}" >> $GITHUB_ENV
- name: Docker meta
id: meta
uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0
@@ -465,6 +470,28 @@
timeout 3m bash -c 'until docker inspect --format="{{json .State.Health.Status}}" test_custom | grep -q \"healthy\"; do sleep 10; done'
docker exec test_custom 'sh' '-c' '/opt/opendj/bin/ldapsearch --hostname localhost --port 1636 --bindDN "cn=Directory Manager" --bindPassword custom_password --useSsl --trustAll --baseDN "dc=example,dc=com" --searchScope base "(objectClass=*)" 1.1'
docker kill test_custom
+ - name: Scan image for vulnerabilities (Trivy)
+ # trivy resolves the image from the local Docker daemon, so only the runner's
+ # linux/amd64 manifest is scanned; cache: false keeps the ~1GB trivy DBs from
+ # evicting the m2-repository caches out of the repo's 10GB actions-cache quota
+ uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0
+ with:
+ image-ref: localhost:5000/${{ env.image_repository }}:${{ env.release_version }}
+ format: sarif
+ output: trivy-results.sarif
+ severity: CRITICAL,HIGH
+ limit-severities-for-sarif: true
+ ignore-unfixed: true
+ scanners: vuln
+ cache: false
+ - name: Upload Trivy report to GitHub Security
+ uses: github/codeql-action/upload-sarif@v4
+ # upload even if a preceding step failed, but not without a report to upload
+ if: ${{ always() && hashFiles('trivy-results.sarif') != '' }}
+ with:
+ sarif_file: trivy-results.sarif
+ # distinct from the docker-scan.yml categories, which track the published images
+ category: trivy-build-default
- name: Cache JMeter
uses: actions/cache@v5
with:
@@ -512,6 +539,9 @@
build-docker-alpine:
needs: build-maven
runs-on: 'ubuntu-latest'
+ permissions:
+ contents: read
+ security-events: write
services:
registry:
image: registry:3
@@ -530,6 +560,7 @@
run: |
export git_version_last="$(curl -i -o - --silent https://api.github.com/repos/OpenIdentityPlatform/OpenDJ/releases/latest | grep -m1 "\"name\"" | cut -d\" -f4)" ; echo "last release: $git_version_last"
echo "release_version=$git_version_last" >> $GITHUB_ENV
+ echo "image_repository=${GITHUB_REPOSITORY,,}" >> $GITHUB_ENV
- name: Docker meta
id: meta
uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0
@@ -585,6 +616,28 @@
timeout 3m bash -c 'until docker inspect --format="{{json .State.Health.Status}}" test_custom | grep -q \"healthy\"; do sleep 10; done'
docker exec test_custom 'sh' '-c' '/opt/opendj/bin/ldapsearch --hostname localhost --port 1636 --bindDN "cn=Directory Manager" --bindPassword custom_password --useSsl --trustAll --baseDN "dc=example,dc=com" --searchScope base "(objectClass=*)" 1.1'
docker kill test_custom
+ - name: Scan image for vulnerabilities (Trivy)
+ # trivy resolves the image from the local Docker daemon, so only the runner's
+ # linux/amd64 manifest is scanned; cache: false keeps the ~1GB trivy DBs from
+ # evicting the m2-repository caches out of the repo's 10GB actions-cache quota
+ uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0
+ with:
+ image-ref: localhost:5000/${{ env.image_repository }}:${{ env.release_version }}-alpine
+ format: sarif
+ output: trivy-results.sarif
+ severity: CRITICAL,HIGH
+ limit-severities-for-sarif: true
+ ignore-unfixed: true
+ scanners: vuln
+ cache: false
+ - name: Upload Trivy report to GitHub Security
+ uses: github/codeql-action/upload-sarif@v4
+ # upload even if a preceding step failed, but not without a report to upload
+ if: ${{ always() && hashFiles('trivy-results.sarif') != '' }}
+ with:
+ sarif_file: trivy-results.sarif
+ # distinct from the docker-scan.yml categories, which track the published images
+ category: trivy-build-alpine
- name: Cache JMeter
uses: actions/cache@v5
with:
diff --git a/.github/workflows/docker-scan.yml b/.github/workflows/docker-scan.yml
new file mode 100644
index 0000000..3393658
--- /dev/null
+++ b/.github/workflows/docker-scan.yml
@@ -0,0 +1,59 @@
+# The contents of this file are subject to the terms of the Common Development and
+# Distribution License (the License). You may not use this file except in compliance with the
+# License.
+#
+# You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
+# specific language governing permission and limitations under the License.
+#
+# When distributing Covered Software, include this CDDL Header Notice in each file and include
+# the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
+# Header, with the fields enclosed by brackets [] replaced by your own identifying
+# information: "Portions copyright [year] [name of copyright owner]".
+#
+# Copyright 2026 3A Systems, LLC.
+
+# Scans the published Docker images for known vulnerabilities: new CVEs surface in
+# already-released images (mostly via the base image), without any change in this repository.
+name: Docker Scan
+
+on:
+ schedule:
+ - cron: '30 5 * * 1'
+ workflow_dispatch:
+
+permissions:
+ contents: read
+
+jobs:
+ scan:
+ # Do not run the scheduled scan in forks; manual runs are always allowed.
+ if: github.event_name == 'workflow_dispatch' || github.repository == 'OpenIdentityPlatform/OpenDJ'
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ security-events: write
+ strategy:
+ fail-fast: false
+ matrix:
+ tag: [ 'latest', 'alpine' ]
+ steps:
+ - uses: actions/checkout@v6
+ - name: Scan openidentityplatform/opendj:${{ matrix.tag }} (Trivy)
+ # unlike the build.yml gate, unfixed CVEs are reported too: surfacing them in
+ # already-released images is the point of this workflow
+ uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0
+ with:
+ image-ref: openidentityplatform/opendj:${{ matrix.tag }}
+ format: sarif
+ output: trivy-${{ matrix.tag }}.sarif
+ severity: CRITICAL,HIGH
+ limit-severities-for-sarif: true
+ scanners: vuln
+ cache: false
+ - name: Upload report to GitHub Security
+ uses: github/codeql-action/upload-sarif@v4
+ # upload even if a preceding step failed, but not without a report to upload
+ if: ${{ always() && hashFiles(format('trivy-{0}.sarif', matrix.tag)) != '' }}
+ with:
+ sarif_file: trivy-${{ matrix.tag }}.sarif
+ category: trivy-image-${{ matrix.tag }}
--
Gitblit v1.10.0