Skip to content

CVE automation using a cli built with bubbletea#9060

Open
javorszky wants to merge 31 commits intomainfrom
chore/np-15-automate-cve-listing
Open

CVE automation using a cli built with bubbletea#9060
javorszky wants to merge 31 commits intomainfrom
chore/np-15-automate-cve-listing

Conversation

@javorszky
Copy link
Contributor

@javorszky javorszky commented Feb 4, 2026

Proposed changes

CLI to automate generate Exception Request lists.

Has two modes, either pure CLI, or a Terminal user interface that wraps the CLI.

It needs to be built in both cases, single binary, function depends on whether it gets passed flags or not.

To build

$ cd hack/cve-automation && make build

To run as a TUI (once you're in the hack/cve-automation directory and have built the binary):

$ ./cve-automation

To run it as CLI, ideal in CI context:

$ ./cve-automation --source=<github|docker> ...

or

$ ./cve-automation --sarif-files=<file1,file2,...> ...

There's a help with

$ ./cve-automation --help

You can also control the output directory. The default is hack/cve-automation/downloads/<date>-<random 6 char>/

$ ./cve-automation ... --output-dir ./foo

CLI mode

Report from GitHub from last successful workflow run on main branch

$ ./cve-automation --source=github --branch=main

Report from GitHub, release-5.3 branch

$ ./cve-automation --source=github --branch=release-5.3

Report from docker

$./cve-automation --source=docker --images=nginx/nginx-ingress:5.3.2-release-prep-ubi-image,nginx/nginx-ingress:5.3.2-release-prep-ubi-image-dos-plus,nginx/nginx-ingress:5.3.2-release-prep-ubi-image-nap-dos-plus

The images need to be the same as the output of docker image ls, and they are comma separated. Make sure there are no extra spaces.

Report from sarif files directly:

$ ./cve-automation --sarif-files=./downloads/20260303-132451-ZMVHWt/main-alpine-plus-fips-goreleaser-results.sarif.json,./downloads/20260303-132451-ZMVHWt/main-alpine-plus-goreleaser-results.sarif.json,./downloads/20260303-132451-ZMVHWt/main-alpine-plus-nap-fips-goreleaser-waf-results.sarif.json,./downloads/20260303-132451-ZMVHWt/main-alpine-plus-nap-v5-fips-goreleaser-waf-results.sarif.json

Paths are either absolute, or relative to the directory where you are calling it from. Same rules apply as with the docker images, comma separated, no spaces.

TUI mode

General flow:

  1. Start the cli: $ ./cve-automation. Make sure neither the source or the sarif-files flags are provided
  2. Select either Docker or GitHub
  3. For docker:
    1. select which images you want to generate sarif files for. It filters for images named nginx/*. Changing the filter in the CLI is not yet implemented
  4. For GitHub
    1. Choose which branch to use: main or release-*, the last one
    2. It will then download and unzip all the sarif files from the last successful run of the image promotion workflow
  5. Once we have the sarif files, select which ones to use to collate. If one is an outlier in its size, you can exclude it here (in case there's a weird image with a LOT of cves that you want to handle separately)
  6. It will then generate the report into the hack/cve-automation/reports directory with the current date and a random 6 char suffix
  7. It will also ask whether you want to keep the download directory with the sarif files. The directory will be hack/cve-automation/downloads with the current date and a 6 char suffix.

What are known gotchas so far?

  • I want it to be flexible when it comes to repo / owner / workflow id so other teams can also use this
  • changing the docker filter from the cli is not yet available, unless you directly give it the docker image names in cli
  • general tidy up of the code

Checklist

Before creating a PR, run through this checklist and mark each as complete.

  • I have read the CONTRIBUTING doc
  • I have added tests that prove my fix is effective or that my feature works
  • I have checked that all unit tests pass after adding my changes
  • I have updated necessary documentation
  • I have rebased my branch onto main
  • I will ensure my PR is targeting the main branch and pulling from my branch from my own fork

@github-actions github-actions bot added the chore Pull requests for routine tasks label Feb 4, 2026
@codecov
Copy link

codecov bot commented Feb 4, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 54.44%. Comparing base (c15ff6d) to head (d686d80).
⚠️ Report is 129 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #9060      +/-   ##
==========================================
+ Coverage   53.95%   54.44%   +0.48%     
==========================================
  Files          91       97       +6     
  Lines       18692    19359     +667     
==========================================
+ Hits        10086    10540     +454     
- Misses       8075     8238     +163     
- Partials      531      581      +50     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@javorszky javorszky force-pushed the chore/np-15-automate-cve-listing branch from 7deb9b6 to efc4088 Compare February 24, 2026 17:28
@github-actions github-actions bot added the go Pull requests that update Go code label Feb 24, 2026
@github-actions
Copy link
Contributor

github-actions bot commented Feb 24, 2026

Package Report

Details gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-ingress:t-a2c8d5da765b42ec56ffda93347f39c7, nginx, 1.29.5-1~trixie, amd64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-ingress:t-a2c8d5da765b42ec56ffda93347f39c7, nginx-module-njs, 1.29.5+0.9.5-1~trixie, amd64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-ingress:t-a2c8d5da765b42ec56ffda93347f39c7, nginx-module-otel, 1.29.5+0.1.2-1~trixie, amd64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-ingress:t-a2c8d5da765b42ec56ffda93347f39c7, nginx-agent, 3.7.2~trixie, amd64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-ingress:t-a2c8d5da765b42ec56ffda93347f39c7, nginx, 1.29.5-1~trixie, arm64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-ingress:t-a2c8d5da765b42ec56ffda93347f39c7, nginx-module-njs, 1.29.5+0.9.5-1~trixie, arm64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-ingress:t-a2c8d5da765b42ec56ffda93347f39c7, nginx-module-otel, 1.29.5+0.1.2-1~trixie, arm64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-ingress:t-a2c8d5da765b42ec56ffda93347f39c7, nginx-agent, 3.7.2~trixie, arm64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7, nginx-plus, 36-3~bookworm, amd64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7, nginx-plus-module-njs, 36+0.9.5-1~bookworm, amd64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7, nginx-plus-module-otel, 36+0.1.2-1~bookworm, amd64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7, nginx-plus-module-fips-check, 36+0.1-1~bookworm, amd64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7, nginx-agent, 3.7.2~bookworm, amd64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7, nginx-plus, 36-3~bookworm, arm64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7, nginx-plus-module-njs, 36+0.9.5-1~bookworm, arm64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7, nginx-plus-module-otel, 36+0.1.2-1~bookworm, arm64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7, nginx-plus-module-fips-check, 36+0.1-1~bookworm, arm64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7, nginx-agent, 3.7.2~bookworm, arm64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7, nginx-plus, 36-3~bookworm, amd64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7, nginx-plus-module-njs, 36+0.9.5-1~bookworm, amd64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7, nginx-plus-module-otel, 36+0.1.2-1~bookworm, amd64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7, nginx-plus-module-fips-check, 36+0.1-1~bookworm, amd64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7, nginx-plus-module-appprotect, 36+5.575.2-1~bookworm, amd64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7, app-protect, 36+5.575.2-1~bookworm, amd64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7, app-protect-attack-signatures, 2026.02.25-1~bookworm, amd64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7, app-protect-threat-campaigns, 2026.03.02-1~bookworm, amd64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7, nginx-agent, 2.45.2~bookworm, amd64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap-v5/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7, nginx-plus, 36-3~bookworm, amd64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap-v5/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7, nginx-plus-module-njs, 36+0.9.5-1~bookworm, amd64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap-v5/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7, nginx-plus-module-otel, 36+0.1.2-1~bookworm, amd64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap-v5/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7, nginx-plus-module-fips-check, 36+0.1-1~bookworm, amd64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap-v5/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7, nginx-plus-module-appprotect, 36+5.575.2-1~bookworm, amd64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap-v5/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7, app-protect-module-plus, 36+5.575.2-1~bookworm, amd64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap-v5/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7, app-protect-plugin, 6.25.0-1~bookworm, amd64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap-v5/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7, nginx-agent, 2.45.2~bookworm, amd64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-dos/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7, nginx-plus, 36-3~bookworm, amd64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-dos/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7, nginx-plus-module-njs, 36+0.9.5-1~bookworm, amd64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-dos/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7, nginx-plus-module-otel, 36+0.1.2-1~bookworm, amd64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-dos/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7, nginx-plus-module-fips-check, 36+0.1-1~bookworm, amd64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-dos/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7, nginx-plus-module-appprotectdos, 36+4.8.3-1~bookworm, amd64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-dos/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7, app-protect-dos, 36+4.8.3-1~bookworm, amd64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-dos-nap/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7, nginx-plus, 36-3~bookworm, amd64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-dos-nap/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7, nginx-plus-module-njs, 36+0.9.5-1~bookworm, amd64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-dos-nap/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7, nginx-plus-module-otel, 36+0.1.2-1~bookworm, amd64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-dos-nap/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7, nginx-plus-module-fips-check, 36+0.1-1~bookworm, amd64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-dos-nap/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7, nginx-plus-module-appprotect, 36+5.575.2-1~bookworm, amd64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-dos-nap/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7, app-protect, 36+5.575.2-1~bookworm, amd64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-dos-nap/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7, app-protect-attack-signatures, 2026.02.25-1~bookworm, amd64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-dos-nap/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7, app-protect-threat-campaigns, 2026.03.02-1~bookworm, amd64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-dos-nap/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7, nginx-plus-module-appprotectdos, 36+4.8.3-1~bookworm, amd64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-dos-nap/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7, app-protect-dos, 36+4.8.3-1~bookworm, amd64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-dos-nap/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7, nginx-agent, 2.45.2~bookworm, amd64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-alpine, nginx, 1.29.5-r1, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-alpine, nginx-module-njs, 1.29.5.0.9.5-r1, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-alpine, nginx-module-otel, 1.29.5.0.1.2-r1, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-alpine, nginx-agent, 3.7.2, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-alpine, nginx, 1.29.5-r1, aarch64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-alpine, nginx-module-njs, 1.29.5.0.9.5-r1, aarch64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-alpine, nginx-module-otel, 1.29.5.0.1.2-r1, aarch64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-alpine, nginx-agent, 3.7.2, aarch64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-alpine, nginx-plus, 36-r3, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-alpine, nginx-plus-module-njs, 36.0.9.5-r1, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-alpine, nginx-plus-module-otel, 36.0.1.2-r1, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-alpine, nginx-plus-module-fips-check, 36.0.1-r1, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-alpine, nginx-agent, 3.7.2, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-alpine, nginx-plus, 36-r3, aarch64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-alpine, nginx-plus-module-njs, 36.0.9.5-r1, aarch64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-alpine, nginx-plus-module-otel, 36.0.1.2-r1, aarch64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-alpine, nginx-plus-module-fips-check, 36.0.1-r1, aarch64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-alpine, nginx-agent, 3.7.2, aarch64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-alpine-fips, nginx-plus, 36-r3, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-alpine-fips, nginx-plus-module-njs, 36.0.9.5-r1, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-alpine-fips, nginx-plus-module-otel, 36.0.1.2-r1, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-alpine-fips, nginx-plus-module-fips-check, 36.0.1-r1, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-alpine-fips, nginx-agent, 3.7.2, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-alpine-fips, nginx-plus, 36-r3, aarch64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-alpine-fips, nginx-plus-module-njs, 36.0.9.5-r1, aarch64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-alpine-fips, nginx-plus-module-otel, 36.0.1.2-r1, aarch64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-alpine-fips, nginx-plus-module-fips-check, 36.0.1-r1, aarch64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-alpine-fips, nginx-agent, 3.7.2, aarch64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-alpine-fips, nginx-plus, 36-r3, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-alpine-fips, nginx-plus-module-njs, 36.0.9.5-r1, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-alpine-fips, nginx-plus-module-otel, 36.0.1.2-r1, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-alpine-fips, nginx-plus-module-fips-check, 36.0.1-r1, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-alpine-fips, nginx-agent, 2.45.2, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-alpine-fips, nginx-plus-module-appprotect, 36.5.575.2-r1, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-alpine-fips, app-protect, 36.5.575.2-r1, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-alpine-fips, app-protect-attack-signatures, 2026.02.25-r1, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-alpine-fips, app-protect-threat-campaigns, 2026.03.02-r1, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap-v5/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-alpine-fips, nginx-plus, 36-r3, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap-v5/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-alpine-fips, nginx-plus-module-njs, 36.0.9.5-r1, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap-v5/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-alpine-fips, nginx-plus-module-otel, 36.0.1.2-r1, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap-v5/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-alpine-fips, nginx-plus-module-fips-check, 36.0.1-r1, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap-v5/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-alpine-fips, nginx-agent, 2.45.2, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap-v5/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-alpine-fips, nginx-plus-module-appprotect, 36.5.575.2-r1, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap-v5/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-alpine-fips, app-protect-module-plus, 36.5.575.2-r1, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap-v5/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-alpine-fips, app-protect-plugin, 6.25.0-r1, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi, nginx, 1.29.5-1.el9.ngx, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi, nginx-module-njs, 1.29.5+0.9.6-1.el9.ngx, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi, nginx-module-otel, 1.29.5+0.1.2-1.el9.ngx, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi, nginx-agent, 3.7.2-1, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi, nginx, 1.29.5-1.el9.ngx, aarch64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi, nginx-module-njs, 1.29.5+0.9.6-1.el9.ngx, aarch64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi, nginx-module-otel, 1.29.5+0.1.2-1.el9.ngx, aarch64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi, nginx-agent, 3.7.2-1, aarch64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi, nginx-plus, 36-3.el9.ngx, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi, nginx-plus-module-njs, 36+0.9.5-1.el9.ngx, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi, nginx-plus-module-otel, 36+0.1.2-1.el9.ngx, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi, nginx-plus-module-fips-check, 36+0.1-1.el9.ngx, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi, nginx-agent, 3.7.2-1, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi, nginx-plus, 36-3.el9.ngx, aarch64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi, nginx-plus-module-njs, 36+0.9.5-1.el9.ngx, aarch64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi, nginx-plus-module-otel, 36+0.1.2-1.el9.ngx, aarch64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi, nginx-plus-module-fips-check, 36+0.1-1.el9.ngx, aarch64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi, nginx-agent, 3.7.2-1, aarch64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi, nginx-plus, 36-3.el9.ngx, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi, nginx-plus-module-njs, 36+0.9.5-1.el9.ngx, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi, nginx-plus-module-otel, 36+0.1.2-1.el9.ngx, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi, nginx-plus-module-fips-check, 36+0.1-1.el9.ngx, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi, nginx-agent, 2.45.2-1, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi, nginx-plus-module-appprotect, 36+5.575.2-1.el9.ngx, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi, app-protect, 36+5.575.2-1.el9.ngx, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi, app-protect-attack-signatures, 2026.02.25-1.el9.ngx, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi, app-protect-threat-campaigns, 2026.03.02-1.el9.ngx, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap-v5/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi, nginx-plus, 36-3.el9.ngx, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap-v5/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi, nginx-plus-module-njs, 36+0.9.5-1.el9.ngx, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap-v5/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi, nginx-plus-module-otel, 36+0.1.2-1.el9.ngx, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap-v5/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi, nginx-plus-module-fips-check, 36+0.1-1.el9.ngx, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap-v5/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi, nginx-agent, 2.45.2-1, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap-v5/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi, nginx-plus-module-appprotect, 36+5.575.2-1.el9.ngx, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap-v5/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi, app-protect-module-plus, 36+5.575.2-1.el9.ngx, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap-v5/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi, app-protect-plugin, 6.25.0-1.el9.ngx, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi8, nginx-plus, 36-3.el8.ngx, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi8, nginx-plus-module-njs, 36+0.9.5-1.el8.ngx, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi8, nginx-plus-module-otel, 36+0.1.2-1.el8.ngx, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi8, nginx-plus-module-fips-check, 36+0.1-1.el8.ngx, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi8, nginx-agent, 2.45.2-1, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi8, nginx-plus-module-appprotect, 36+5.575.2-1.el8.ngx, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi8, app-protect, 36+5.575.2-1.el8.ngx, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi8, app-protect-attack-signatures, 2026.02.25-1.el8.ngx, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi8, app-protect-threat-campaigns, 2026.03.02-1.el8.ngx, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap-v5/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi8, nginx-plus, 36-3.el8.ngx, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap-v5/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi8, nginx-plus-module-njs, 36+0.9.5-1.el8.ngx, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap-v5/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi8, nginx-plus-module-otel, 36+0.1.2-1.el8.ngx, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap-v5/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi8, nginx-plus-module-fips-check, 36+0.1-1.el8.ngx, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap-v5/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi8, nginx-agent, 2.45.2-1, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap-v5/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi8, nginx-plus-module-appprotect, 36+5.575.2-1.el8.ngx, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap-v5/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi8, app-protect-module-plus, 36+5.575.2-1.el8.ngx, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap-v5/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi8, app-protect-plugin, 6.25.0-1.el8.ngx, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-dos/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi, nginx-plus, 36-3.el9.ngx, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-dos/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi, nginx-plus-module-njs, 36+0.9.5-1.el9.ngx, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-dos/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi, nginx-plus-module-otel, 36+0.1.2-1.el9.ngx, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-dos/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi, nginx-plus-module-fips-check, 36+0.1-1.el9.ngx, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-dos/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi, nginx-plus-module-appprotectdos, 36+4.8.3-1.el9.ngx, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-dos/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi, app-protect-dos, 36+4.8.3-1.el9.ngx, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-dos-nap/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi, nginx-plus, 36-3.el9.ngx, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-dos-nap/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi, nginx-plus-module-njs, 36+0.9.5-1.el9.ngx, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-dos-nap/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi, nginx-plus-module-otel, 36+0.1.2-1.el9.ngx, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-dos-nap/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi, nginx-plus-module-fips-check, 36+0.1-1.el9.ngx, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-dos-nap/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi, nginx-plus-module-appprotect, 36+5.575.2-1.el9.ngx, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-dos-nap/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi, nginx-plus-module-appprotectdos, 36+4.8.3-1.el9.ngx, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-dos-nap/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi, nginx-agent, 2.45.2-1, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-dos-nap/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi, app-protect, 36+5.575.2-1.el9.ngx, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-dos-nap/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi, app-protect-attack-signatures, 2026.02.25-1.el9.ngx, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-dos-nap/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi, app-protect-threat-campaigns, 2026.03.02-1.el9.ngx, x86_64
gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-dos-nap/nginx-plus-ingress:t-a2c8d5da765b42ec56ffda93347f39c7-ubi, app-protect-dos, 36+4.8.3-1.el9.ngx, x86_64

@javorszky javorszky marked this pull request as ready for review February 25, 2026 09:23
@javorszky javorszky requested a review from a team as a code owner February 25, 2026 09:23
Copilot AI review requested due to automatic review settings February 25, 2026 09:23
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This draft PR introduces a CVE automation tool for generating vulnerability exception request documents. The tool provides a terminal UI (TUI) for two workflows: scanning local Docker images or downloading GitHub Actions artifacts containing SARIF vulnerability reports. It parses these SARIF files, deduplicates CVEs across multiple images, and generates markdown reports.

Changes:

  • Added a new TUI application in hack/cve-automation/ using Bubble Tea framework for interactive CVE report generation
  • Implemented two scanning workflows: local Docker image scanning via docker scout, and GitHub Actions artifact downloading
  • Added Makefile targets for batch image building and SARIF scanning
  • Introduced new dependencies for TUI (charmbracelet packages), Docker API client, and GitHub API client

Reviewed changes

Copilot reviewed 31 out of 33 changed files in this pull request and generated 23 comments.

Show a summary per file
File Description
hack/cve-automation/main.go Main entry point with workflow selector
hack/cve-automation/selector.go TUI for choosing between Docker and GitHub workflows
hack/cve-automation/dockerscan/* Docker image scanning workflow implementation
hack/cve-automation/githubscan/* GitHub artifact downloading and scanning workflow
hack/cve-automation/githubartifacts/* GitHub API integration and artifact download logic
hack/cve-automation/reporter/* SARIF parsing and markdown report generation
hack/cve-automation/ui/* Shared UI components and utilities
hack/cve-automation/templates/cve-report.md.tmpl Markdown template for CVE reports
Makefile Added targets for building all images and running docker scout scans
.github/scripts/merge-cves-with-jq.sh Shell script for merging CVE data using jq
go.mod, go.sum Added dependencies for TUI, Docker client, and GitHub client
.gitignore Excluded generated reports and downloads directories

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

}

// Generate markdown report
reportPath, err := reporter.RenderMarkdown(vulns, "/project/root")
Copy link

Copilot AI Feb 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The usage example shows RenderMarkdown being called with two arguments (line 67), but the function actually requires three arguments including a suffix parameter. This example code would not compile. Update the example to include the suffix parameter or pass an empty string if no suffix is desired.

Copilot uses AI. Check for mistakes.
Comment on lines +199 to +228
features := ""
if hasUbi8 {
features += string(archUbi8)
}
if hasUbi {
features += string(archUbi)
}
if hasDebian {
features += string(archDebian)
}
if hasAlpine {
features += string(archAlpine)
}

if hasNapV5 {
features += "-" + string(featureNapV5)
} else if hasNap {
features += "-" + string(featureNap)
}
if hasDos {
features += "-" + string(featureDos)
}
if hasPlus {
features += "-" + string(featurePlus)
}
if hasFips {
features += "-" + string(featureFips)
}

return features
Copy link

Copilot AI Feb 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The logic in sarifFilePathToFeatures constructs the output string by simple concatenation (lines 199-226) which could result in an empty string being returned if none of the conditions match. When features is initialized as an empty string and no arch matches (lines 200-211 all evaluate to false), and no feature flags are set (lines 213-226 all false), the function returns an empty string. This could happen for edge cases not covered by the expected naming patterns. Consider returning the original name or a default value when features remains empty.

Copilot uses AI. Check for mistakes.
@javorszky javorszky changed the title Draft: CVE automation using make and sh files CVE automation using a cli built with bubbletea Feb 25, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 30 out of 32 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +92 to +98
// Extract and process all zip files
for _, artifact := range artifacts {
zipPath := artifact.Path(tempDir)
if err := extractAndProcessZip(zipPath, artifact.Name, tempDir); err != nil {
return "", "", fmt.Errorf("processing zip file %s: %w", zipPath, err)
}
}
Copy link

Copilot AI Feb 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If any download fails and the context is cancelled, the function will exit early at line 88-90, but then the extraction loop at lines 93-98 will attempt to extract zip files that may not have been downloaded. This will cause errors when trying to extract non-existent files. The extraction should only be performed if all downloads succeeded. Consider checking if there was an error before proceeding to extraction, or track which artifacts were successfully downloaded.

Copilot uses AI. Check for mistakes.
@javorszky javorszky force-pushed the chore/np-15-automate-cve-listing branch from 2f11eed to 2322448 Compare February 26, 2026 09:59
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 31 out of 33 changed files in this pull request and generated 10 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +61 to +63
outputPath := filepath.Join(outputDir, filepath.Clean(artifactName)+sarifExtension)
outFile, err := os.Create(outputPath) //gosec:disable G304 - artifactName is controlled by us, not user input, so this is not a path traversal risk
if err != nil {
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

filepath.Clean(artifactName) does not prevent path traversal (e.g. "../x" stays "../x"), and if artifactName is absolute it will ignore outputDir when joined. Since artifact names come from the GitHub API, this can write files outside outputDir. Sanitize with filepath.Base (and ideally also reject any path separators) before joining, and update/remove the gosec justification accordingly.

Copilot uses AI. Check for mistakes.

.PHONY: run
run:
go run ./...
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

go run ./... will typically fail when the pattern matches multiple packages (including non-main packages under dockerscan/, engine/, etc.). Since hack/cve-automation has a single main package in this directory, go run . is the safer command for make run.

Suggested change
go run ./...
go run .

Copilot uses AI. Check for mistakes.
Comment on lines +50 to +56
_, _ = fmt.Fprintf(w, "%s %s %s\n", cursor, checked, title)
}

// Height returns the height of each item, which is 2 for this delegate
func (s SelectDelegate) Height() int {
return 2
}
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SelectDelegate.Render writes a single line per item, but Height() returns 2. In bubbles/list, Height must match the number of rendered rows per item; otherwise scrolling/layout will be incorrect (extra blank lines / skipped items). Set Height() to 1 (or render two lines consistently).

Copilot uses AI. Check for mistakes.
Comment on lines +93 to +97
// Use base64 encoding and filter to alphanumeric
randomSuffix := make([]byte, randomSuffixLen)
for i := range randomSuffix {
randomSuffix[i] = alphanumericChars[int(randomBytes[i])%len(alphanumericChars)]
}
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment says “Use base64 encoding and filter to alphanumeric”, but the code is not using base64 at all—it maps random bytes into alphanumericChars via modulo. Update the comment to match the actual implementation to avoid confusion when auditing randomness/uniqueness.

Copilot uses AI. Check for mistakes.
Comment on lines +58 to +59
fmt.Printf("cmd str is %s\n\n", cmdStr)
fmt.Printf("and command is %s\n\n", cmd.String())
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These fmt.Printf debug statements will write directly to stdout whenever the TUI triggers a scan, which will corrupt the Bubble Tea UI output and leak internal command details. Please remove these prints (or gate behind a debug flag/logging facility).

Suggested change
fmt.Printf("cmd str is %s\n\n", cmdStr)
fmt.Printf("and command is %s\n\n", cmd.String())
if os.Getenv("DOCKER_SCAN_DEBUG") == "1" {
fmt.Fprintf(os.Stderr, "dockerscan debug: cmd str is %s\n\n", cmdStr)
fmt.Fprintf(os.Stderr, "dockerscan debug: command is %s\n\n", cmd.String())
}

Copilot uses AI. Check for mistakes.
workflowRunID, branch, runs.WorkflowRuns[0].GetURL(), err)
}

resultsRe, err := regexp.Compile(fmt.Sprintf("^%s.+-results$", branch))
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The regex is built from the raw branch name; release branches like release-5.4 contain . which is a regex metacharacter, so this will match unintended artifact names. Use regexp.QuoteMeta(branch) when interpolating into the pattern (or avoid regex entirely and use strings.HasPrefix/HasSuffix).

Suggested change
resultsRe, err := regexp.Compile(fmt.Sprintf("^%s.+-results$", branch))
resultsRe, err := regexp.Compile(fmt.Sprintf("^%s.+-results$", regexp.QuoteMeta(branch)))

Copilot uses AI. Check for mistakes.
Comment on lines +13 to +16
const (
getImagesTimeout = 20 * time.Second
filterNGINX = "nginx/*"
)
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

filterNGINX is declared as a package-level const but is not referenced anywhere in the dockerscan package. In Go, unused package-level identifiers cause a compile error, so this will break the build. Remove the const or use it (e.g., as the default filter).

Copilot uses AI. Check for mistakes.
Comment on lines +52 to +62
ActiveButtonStyle = lipgloss.NewStyle().
Foreground(lipgloss.Color(colorWhite)).
Background(lipgloss.Color(colorPurple)).
Padding(buttonPaddingVert, buttonPaddingHorz).
Bold(true)

// InactiveButtonStyle is used for the non-selected button
InactiveButtonStyle = lipgloss.NewStyle().
Foreground(lipgloss.Color(colorLightGray)).
Background(lipgloss.Color(colorDarkGray)).
Padding(buttonPaddingVert, buttonPaddingHorz)
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This style block is not gofmt-formatted (the method chain indentation is off), which makes future diffs noisy and inconsistent with the rest of the repo. Please run gofmt on this file (and ideally the whole new hack/cve-automation module).

Copilot uses AI. Check for mistakes.
Comment on lines +69 to +76
defer func() {
apiErr := apiClient.Close()
if err != nil {
err = fmt.Errorf("closing docker api client: %w", apiErr)
} else {
err = fmt.Errorf("closing docker api client: %w, and previous error: %w", apiErr, err)
}
}()
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The deferred Close error handling is inverted and can drop the original error (and even set err to nil) when apiClient.Close() returns nil, because fmt.Errorf(...%w, nil) returns nil. Only wrap/override err when apiErr != nil, and when err is already non-nil, combine errors instead of replacing the original one.

Copilot uses AI. Check for mistakes.
Comment on lines +203 to +204
// No manifest: use original normalization logic.
return sarifFilePathToFeatures(sarifPath)
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When no manifest is provided, resolveImageName passes the full sarifPath into sarifFilePathToFeatures. If normalization fails, sarifFilePathToFeatures returns the input string, which would then be the full filesystem path (including directories) and pollute SourceImages/severity maps. Use filepath.Base(sarifPath) (and/or strip the .sarif.json extension) before calling sarifFilePathToFeatures.

Suggested change
// No manifest: use original normalization logic.
return sarifFilePathToFeatures(sarifPath)
// No manifest: use original normalization logic, but only on the basename
// to avoid leaking directory components if normalization fails.
return sarifFilePathToFeatures(filepath.Base(sarifPath))

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

chore Pull requests for routine tasks go Pull requests that update Go code

Projects

Status: Todo ☑

Development

Successfully merging this pull request may close these issues.

3 participants