From 35530a4b06b36def27263f9a2b8a7f4a708ba399 Mon Sep 17 00:00:00 2001 From: Stephen Kitt Date: Fri, 10 Apr 2026 11:52:21 +0200 Subject: [PATCH] Switch to govulncheck for Go scanning govulncheck only reports vulnerabilities in reachable packages, which will greatly reduce the number of false positives. This changes CI linting to use govulncheck, and also provides local govulncheck and govulncheck-sarif targets in the linting Makefile. PR checks no longer upload SARIF reports, and SARIF uploads are changed to periodic rather than per-push. This ensures that security issues are caught in a timely fashion even if no development activity occurs in the repository. See https://words.filippo.io/dependabot/ for background. govulncheck segfaults if it is compressed with UPX, so it is skipped when compressing. Signed-off-by: Stephen Kitt --- .github/workflows/linting.yml | 19 +++----------- .github/workflows/periodic.yml | 30 ++++++++++++++++++++++ .github/workflows/report.yml | 33 ------------------------- .gitignore | 1 + Makefile | 2 +- Makefile.linting | 28 +++++++++++++++++++++ package/Dockerfile.shipyard-dapper-base | 3 ++- tools/go.mod | 3 +++ tools/go.sum | 8 ++++++ 9 files changed, 77 insertions(+), 50 deletions(-) delete mode 100644 .github/workflows/report.yml diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml index b43c358bf..601bb2296 100644 --- a/.github/workflows/linting.yml +++ b/.github/workflows/linting.yml @@ -108,24 +108,13 @@ jobs: vulnerability-scan: name: Vulnerability Scanning runs-on: ubuntu-latest + permissions: + contents: read steps: - name: Check out the repository uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd - - name: Run Anchore vulnerability scanner - uses: anchore/scan-action@e1165082ffb1fe366ebaf02d8526e7c4989ea9d2 - id: scan - with: - path: "." - fail-build: true - severity-cutoff: high - - name: Show Anchore scan SARIF report - if: always() - run: cat ${{ steps.scan.outputs.sarif }} - - name: Upload Anchore scan SARIF report - if: always() - uses: github/codeql-action/upload-sarif@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 - with: - sarif_file: ${{ steps.scan.outputs.sarif }} + - name: Run govulncheck (producing a text report and failing the build if necessary) + run: make govulncheck yaml-lint: name: YAML diff --git a/.github/workflows/periodic.yml b/.github/workflows/periodic.yml index ce99f3e88..922aa9eff 100644 --- a/.github/workflows/periodic.yml +++ b/.github/workflows/periodic.yml @@ -57,3 +57,33 @@ jobs: - name: Check for updates run: (cd ${{ matrix.project }}; go list -u -m -json all) | bin/go-mod-outdated -direct -update + + vulnerability-scan-periodic: + name: Vulnerability Scanning + if: github.repository_owner == 'submariner-io' + runs-on: ubuntu-latest + permissions: + security-events: write + contents: read + strategy: + fail-fast: false + matrix: + branch: [ + 'devel', 'release-0.18', 'release-0.19', 'release-0.20', 'release-0.21', 'release-0.22', 'release-0.23' + ] + steps: + - name: Check out the repository + id: checkout + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + ref: ${{ matrix.branch }} + - name: Run govulncheck (producing a SARIF report) + run: make govulncheck.sarif + - name: Upload SARIF report + if: always() + uses: github/codeql-action/upload-sarif@c10b8064de6f491fea524254123dbe5e09572f13 # v4.35.1 + with: + sarif_file: govulncheck.sarif + category: govulncheck-${{ matrix.branch }} + ref: ${{ steps.checkout.outputs.ref }} + sha: ${{ steps.checkout.outputs.commit }} diff --git a/.github/workflows/report.yml b/.github/workflows/report.yml deleted file mode 100644 index b2453a410..000000000 --- a/.github/workflows/report.yml +++ /dev/null @@ -1,33 +0,0 @@ ---- -name: Reporting - -on: - push: - branches: - - devel - - release-* - -permissions: {} - -jobs: - vulnerability-scan: - name: Vulnerability Scanning - if: github.repository_owner == 'submariner-io' - runs-on: ubuntu-latest - permissions: - security-events: write - steps: - - name: Check out the repository - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd - - name: Run Anchore vulnerability scanner - uses: anchore/scan-action@e1165082ffb1fe366ebaf02d8526e7c4989ea9d2 - id: scan - with: - path: "." - fail-build: false - - name: Show Anchore scan SARIF report - run: cat ${{ steps.scan.outputs.sarif }} - - name: Upload Anchore scan SARIF report - uses: github/codeql-action/upload-sarif@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 - with: - sarif_file: ${{ steps.scan.outputs.sarif }} diff --git a/.gitignore b/.gitignore index 49cfbda97..66af3ed7e 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ junit.xml *.coverprofile *~ /ovn-kubernetes +govulncheck.sarif diff --git a/Makefile b/Makefile index 36e7eeda7..d9763d970 100644 --- a/Makefile +++ b/Makefile @@ -57,7 +57,7 @@ include Makefile.versions # Shipyard-specific starts # We need to ensure images, including the Shipyard base image, are updated # before we start Dapper -clean-clusters cleanup cloud-prepare clusters deploy deploy-latest e2e golangci-lint post-mortem packagedoc-lint print-version scale unit upgrade-e2e: package/.image.shipyard-dapper-base +clean-clusters cleanup cloud-prepare clusters deploy deploy-latest e2e golangci-lint govulncheck govulncheck.sarif post-mortem packagedoc-lint print-version scale unit upgrade-e2e: package/.image.shipyard-dapper-base deploy deploy-latest e2e upgrade-e2e: package/.image.nettest .DEFAULT_GOAL := lint diff --git a/Makefile.linting b/Makefile.linting index 4fd162fa2..2c29fd291 100644 --- a/Makefile.linting +++ b/Makefile.linting @@ -29,6 +29,34 @@ else @echo 'There are no Go files to lint.' endif +# [govulncheck] checks the project for vulnerabilities +govulncheck: +ifneq (,$(shell find . -name go.mod)) + vulns=0; \ + for module in $$(find . -name go.mod -printf "%h\n"); do \ + echo Checking for vulnerabilities in module "$$module"; \ + (cd "$$module" && govulncheck ./...) || vulns=1; \ + done; \ + if [ "$$vulns" -ne 0 ]; then echo Vulnerabilities found; exit 1; fi +else + @echo 'There are no Go files to check.' +endif + +# [govulncheck.sarif] checks the project for vulnerabilities +govulncheck.sarif: +ifneq (,$(shell find . -name go.mod)) + printf '{"version": "2.1.0", "runs": []}' > $@ + for module in $$(find . -name go.mod -printf "%h\n"); do \ + echo Checking for vulnerabilities in module "$$module"; \ + module_sarif=$$(mktemp); \ + (cd "$$module" && govulncheck -format sarif ./...) >> "$$module_sarif"; \ + jq -s '.[0].runs += (.[1].runs // []) | .[0]' $@ "$$module_sarif" > $@.new && mv $@.new $@; \ + rm -f "$$module_sarif"; \ + done +else + @echo 'There are no Go files to check.' +endif + # [markdownlint] validates Markdown files in the project markdownlint: md_ignored=(); \ diff --git a/package/Dockerfile.shipyard-dapper-base b/package/Dockerfile.shipyard-dapper-base index 3b99e3534..3142a6363 100644 --- a/package/Dockerfile.shipyard-dapper-base +++ b/package/Dockerfile.shipyard-dapper-base @@ -90,9 +90,10 @@ COPY tools /tools # than the version used to analyse the code, so this rebuilds it. RUN go -C /tools install github.com/golangci/golangci-lint/v2/cmd/golangci-lint && \ go -C /tools install sigs.k8s.io/kind && \ + go -C /tools install golang.org/x/vuln/cmd/govulncheck && \ curl -L https://raw.githubusercontent.com/jonmosco/kube-ps1/1b8fe913b25ba857b84a94c3b1dbf7bb34f7caef/kube-ps1.sh -o /etc/profile.d/kube-ps1.sh && \ find /go/bin -type f -executable -newercm /go -exec strip {} + && \ - find /go/bin -type f -executable -newercm /go \( -execdir upx ${UPX_LEVEL} {} \; -o -true \) && \ + find /go/bin -type f -executable -newercm /go ! -name govulncheck \( -execdir upx ${UPX_LEVEL} {} \; -o -true \) && \ go clean -cache -modcache && rm -rf /tools # Link get-subctl script so it can be easily run inside a shell diff --git a/tools/go.mod b/tools/go.mod index 37a568796..8a9cf8cd2 100644 --- a/tools/go.mod +++ b/tools/go.mod @@ -206,8 +206,10 @@ require ( golang.org/x/mod v0.34.0 // indirect golang.org/x/sync v0.20.0 // indirect golang.org/x/sys v0.42.0 // indirect + golang.org/x/telemetry v0.0.0-20260311193753-579e4da9a98c // indirect golang.org/x/text v0.34.0 // indirect golang.org/x/tools v0.43.0 // indirect + golang.org/x/vuln v1.1.4 // indirect google.golang.org/protobuf v1.36.8 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect @@ -222,5 +224,6 @@ require ( tool ( github.com/golangci/golangci-lint/v2/cmd/golangci-lint github.com/psampaz/go-mod-outdated + golang.org/x/vuln/cmd/govulncheck sigs.k8s.io/kind/cmd/kind ) diff --git a/tools/go.sum b/tools/go.sum index 58fd89452..6645009c8 100644 --- a/tools/go.sum +++ b/tools/go.sum @@ -192,6 +192,8 @@ github.com/golangci/swaggoswag v0.0.0-20250504205917-77f2aca3143e h1:ai0EfmVYE2b github.com/golangci/swaggoswag v0.0.0-20250504205917-77f2aca3143e/go.mod h1:Vrn4B5oR9qRwM+f54koyeH3yzphlecwERs0el27Fr/s= github.com/golangci/unconvert v0.0.0-20250410112200-a129a6e6413e h1:gD6P7NEo7Eqtt0ssnqSJNNndxe69DOQ24A5h7+i3KpM= github.com/golangci/unconvert v0.0.0-20250410112200-a129a6e6413e/go.mod h1:h+wZwLjUTJnm/P2rwlbJdRPZXOzaT36/FwnPnY2inzc= +github.com/google/go-cmdtest v0.4.1-0.20220921163831-55ab3332a786 h1:rcv+Ippz6RAtvaGgKxc+8FQIpxHgsF+HBzPyYL2cyVU= +github.com/google/go-cmdtest v0.4.1-0.20220921163831-55ab3332a786/go.mod h1:apVn/GCasLZUVpAJ6oWAuyP7Ne7CEsQbTnc0plM3m+o= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= @@ -200,6 +202,8 @@ github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83 h1:z2ogiKUYzX5Is6zr/vP9vJGqPwcdqsWjOt+V8J7+bTc= github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83/go.mod h1:MxpfABSjhmINe3F1It9d+8exIHFvUqtLIRCdOGNXqiI= +github.com/google/renameio v0.1.0 h1:GOZbcHa3HfsPKPlmyPyN2KEohoMXOhdMbHrvbpl2QaA= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/gordonklaus/ineffassign v0.2.0 h1:Uths4KnmwxNJNzq87fwQQDDnbNb7De00VOk9Nu0TySs= @@ -550,6 +554,8 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/telemetry v0.0.0-20260311193753-579e4da9a98c h1:6a8FdnNk6bTXBjR4AGKFgUKuo+7GnR3FX5L7CbveeZc= +golang.org/x/telemetry v0.0.0-20260311193753-579e4da9a98c/go.mod h1:TpUTTEp9frx7rTdLpC9gFG9kdI7zVLFTFFlqaH2Cncw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= @@ -584,6 +590,8 @@ golang.org/x/tools/go/expect v0.1.1-deprecated h1:jpBZDwmgPhXsKZC6WhL20P4b/wmnps golang.org/x/tools/go/expect v0.1.1-deprecated/go.mod h1:eihoPOH+FgIqa3FpoTwguz/bVUSGBlGQU67vpBeOrBY= golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated h1:1h2MnaIAIXISqTFKdENegdpAgUXz6NrPEsbIeWaBRvM= golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated/go.mod h1:RVAQXBGNv1ib0J382/DPCRS/BPnsGebyM1Gj5VSDpG8= +golang.org/x/vuln v1.1.4 h1:Ju8QsuyhX3Hk8ma3CesTbO8vfJD9EvUBgHvkxHBzj0I= +golang.org/x/vuln v1.1.4/go.mod h1:F+45wmU18ym/ca5PLTPLsSzr2KppzswxPP603ldA67s= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=