Skip to content

Commit 61a1eeb

Browse files
pkaedingclaudekeelerm84
authored
ci: replace Trivy with Docker Scout for image scanning (#614)
## Summary - Replace `aquasecurity/trivy-action` with `docker/scout-action` (v1, pinned to SHA) across all 3 security scan workflows (CI, daily alpine, daily distroless) - Motivated by recent security incidents with Trivy as a vendor; Docker Scout is from Docker Inc., an existing vendor relationship - Added Docker Hub authentication via `release-secrets` (required for Scout API access) - Also pinned pre-existing `docker/setup-qemu-action` and `docker/setup-buildx-action` to commit SHAs in CI ## Test plan - [ ] Verify the CI `security-scan` job runs successfully on this PR - [ ] Confirm Docker Scout correctly identifies CVEs in the built images - [ ] Manually trigger daily scan workflows after merge to verify they work with published images - [ ] Verify `release-secrets` AWS role assumption works in the security-scan job context 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: Matthew M. Keeler <mkeeler@launchdarkly.com> Co-authored-by: Matthew M. Keeler <keelerm84@gmail.com>
1 parent d17afcb commit 61a1eeb

3 files changed

Lines changed: 58 additions & 48 deletions

File tree

.github/workflows/ci.yml

Lines changed: 34 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
name: CI
22
on:
33
push:
4-
branches: [ 'v8' ]
4+
branches: ["v8"]
55
paths-ignore:
6-
- '**.md' # Don't run CI on markdown changes.
6+
- "**.md" # Don't run CI on markdown changes.
77
pull_request:
8-
branches: [ 'v8', 'feat/**' ]
8+
branches: ["v8", "feat/**"]
99
paths-ignore:
10-
- '**.md'
10+
- "**.md"
1111

1212
jobs:
1313
go-versions:
@@ -51,65 +51,69 @@ jobs:
5151
id-token: write
5252
contents: read
5353
with:
54-
environment: 'staging'
54+
environment: "staging"
5555
go-version: ${{ needs.go-versions.outputs.latest }}
5656

57-
5857
security-scan:
5958
needs: go-versions
6059
runs-on: ubuntu-latest
61-
name: "Trivy Scan of Docker Image"
62-
env:
63-
# Avoid rate-limiting on ghcr.io (https://github.com/aquasecurity/trivy-action/issues/389)
64-
TRIVY_DB_REPOSITORY: public.ecr.aws/aquasecurity/trivy-db:2
60+
name: "Docker Scout Scan"
61+
permissions:
62+
contents: read
6563
steps:
6664
- uses: actions/checkout@v4
6765
with:
6866
fetch-depth: 0
69-
fetch-tags: 'true'
67+
fetch-tags: "true"
7068
- name: Setup Go ${{ inputs.go-version }}
7169
uses: actions/setup-go@v5
7270
with:
7371
go-version: ${{ needs.go-versions.outputs.latest }}
7472
- name: Set up QEMU
75-
uses: docker/setup-qemu-action@v3
73+
uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0
7674
- name: Setup Docker Buildx
77-
uses: docker/setup-buildx-action@v3
75+
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
7876
with:
7977
platforms: linux/amd64,linux/arm64/v8,linux/arm/v7,linux/386
8078
- name: Build Docker Images
8179
run: make products-for-release
8280
- name: Get current Relay version
8381
id: image-tag
84-
run:
85-
echo "value=$(jq -r '.version' < dist/metadata.json)" >> $GITHUB_OUTPUT
86-
- uses: aquasecurity/trivy-action@master
82+
run: echo "value=$(jq -r '.version' < dist/metadata.json)" >> $GITHUB_OUTPUT
83+
- uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0
84+
with:
85+
username: ${{ vars.DOCKER_USERNAME }}
86+
password: ${{ secrets.DOCKER_RO_TOKEN }}
87+
- uses: docker/scout-action@f8c776824083494ab0d56b8105ba2ca85c86e4de # v1.18.2
8788
id: scan-alpine
8889
continue-on-error: true
8990
with:
91+
command: cves
9092
# Using an explicit tag rather than ld-relay:latest to ensure we're scanning the local image that we just built.
9193
# It's not clear why, but it seems goreleaser doesn't create the :latest tag when skipping the publish step
9294
# as we do for CI, so the scan will end up checking the public image instead of the one we just built.
93-
image-ref: launchdarkly/ld-relay:${{ steps.image-tag.outputs.value }}-amd64
94-
format: 'table'
95-
exit-code: '1'
96-
ignore-unfixed: true
97-
- uses: aquasecurity/trivy-action@master
95+
image: local://launchdarkly/ld-relay:${{ steps.image-tag.outputs.value }}-amd64
96+
exit-code: true
97+
only-fixed: true
98+
write-comment: false
99+
- uses: docker/scout-action@f8c776824083494ab0d56b8105ba2ca85c86e4de # v1.18.2
98100
id: scan-distroless
99101
continue-on-error: true
100102
with:
101-
image-ref: launchdarkly/ld-relay:${{ steps.image-tag.outputs.value }}-static-debian12-nonroot-amd64
102-
format: 'table'
103-
exit-code: '1'
104-
ignore-unfixed: true
105-
- uses: aquasecurity/trivy-action@master
103+
command: cves
104+
image: local://launchdarkly/ld-relay:${{ steps.image-tag.outputs.value }}-static-debian12-nonroot-amd64
105+
exit-code: true
106+
only-fixed: true
107+
write-comment: false
108+
- uses: docker/scout-action@f8c776824083494ab0d56b8105ba2ca85c86e4de # v1.18.2
106109
continue-on-error: true
107110
id: scan-debug-distroless
108111
with:
109-
image-ref: launchdarkly/ld-relay:${{ steps.image-tag.outputs.value }}-static-debian12-debug-nonroot-amd64
110-
format: 'table'
111-
exit-code: '1'
112-
ignore-unfixed: true
112+
command: cves
113+
image: local://launchdarkly/ld-relay:${{ steps.image-tag.outputs.value }}-static-debian12-debug-nonroot-amd64
114+
exit-code: true
115+
only-fixed: true
116+
write-comment: false
113117
- name: Fail if any of scan-alpine, scan-distroless, or scan-distroless-debug failed
114118
if: ${{ steps.scan-alpine.outcome != 'success' || steps.scan-distroless.outcome != 'success' || steps.scan-debug-distroless.outcome != 'success' }}
115119
run: exit 1

.github/workflows/daily-security-scan-alpine.yml

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,17 @@ jobs:
1111
tag: ['latest', 'latest-alpine', 'v8', 'v8-alpine']
1212
fail-fast: false
1313
runs-on: ubuntu-latest
14+
permissions:
15+
contents: read
1416
steps:
15-
- uses: actions/checkout@v4
16-
- uses: aquasecurity/trivy-action@master
17-
env:
18-
# Avoid rate-limiting on ghcr.io (https://github.com/aquasecurity/trivy-action/issues/389)
19-
TRIVY_DB_REPOSITORY: public.ecr.aws/aquasecurity/trivy-db:2
17+
- uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0
2018
with:
21-
image-ref: launchdarkly/ld-relay:${{ matrix.tag }}
22-
format: 'table'
23-
exit-code: '1'
24-
ignore-unfixed: true
19+
username: ${{ vars.DOCKER_USERNAME }}
20+
password: ${{ secrets.DOCKER_RO_TOKEN }}
21+
- uses: docker/scout-action@f8c776824083494ab0d56b8105ba2ca85c86e4de # v1.18.2
22+
with:
23+
command: cves
24+
image: launchdarkly/ld-relay:${{ matrix.tag }}
25+
exit-code: true
26+
only-fixed: true
27+
write-comment: false

.github/workflows/daily-security-scan-distroless.yml

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,17 @@ jobs:
1111
tag: ['latest-static-debian12-nonroot', 'v8-static-debian12-debug-nonroot']
1212
fail-fast: false
1313
runs-on: ubuntu-latest
14+
permissions:
15+
contents: read
1416
steps:
15-
- uses: actions/checkout@v4
16-
- uses: aquasecurity/trivy-action@master
17-
env:
18-
# Avoid rate-limiting on ghcr.io (https://github.com/aquasecurity/trivy-action/issues/389)
19-
TRIVY_DB_REPOSITORY: public.ecr.aws/aquasecurity/trivy-db:2
17+
- uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0
2018
with:
21-
image-ref: launchdarkly/ld-relay:${{ matrix.tag }}
22-
format: 'table'
23-
exit-code: '1'
24-
ignore-unfixed: true
19+
username: ${{ vars.DOCKER_USERNAME }}
20+
password: ${{ secrets.DOCKER_RO_TOKEN }}
21+
- uses: docker/scout-action@f8c776824083494ab0d56b8105ba2ca85c86e4de # v1.18.2
22+
with:
23+
command: cves
24+
image: launchdarkly/ld-relay:${{ matrix.tag }}
25+
exit-code: true
26+
only-fixed: true
27+
write-comment: false

0 commit comments

Comments
 (0)