diff --git a/.github/workflows/config-ci.yml b/.github/workflows/config-ci.yml index 0f24405413..602c39e0cc 100644 --- a/.github/workflows/config-ci.yml +++ b/.github/workflows/config-ci.yml @@ -16,52 +16,50 @@ on: - release-4.* jobs: - config: - runs-on: ubuntu-latest - outputs: - go_versions: ${{ steps.config.outputs.go_versions }} - steps: - - id: config - run: | - echo 'go_versions=["1.20", "1.19"]' >> "$GITHUB_OUTPUT" - commit-check: name: Commit Check runs-on: ubuntu-latest steps: - - name: commit check + - name: Commit Check uses: gsactions/commit-message-checker@v2 with: pattern: | - ^(.*):\s*(.*)\n.*$ + ^[^:!]+: .+\n\n.*$ error: 'Commit must begin with : ' flags: 'gm' excludeTitle: true excludeDescription: true checkAllCommitMessages: true accessToken: ${{ secrets.GITHUB_TOKEN }} + tidy: name: Tidy - needs: ['config'] runs-on: ubuntu-latest - strategy: - matrix: - go: - - ${{ fromJSON(needs.config.outputs.go_versions)[0] }} steps: - - uses: actions/checkout@v4 - - uses: actions/setup-go@v5 - with: - go-version: ${{ matrix.go }} - - uses: ./.github/actions/go-tidy + - name: Checkout + id: checkout + if: ${{ !cancelled() }} + uses: actions/checkout@v4 + - name: Setup Go + id: setupgo + if: ${{ !cancelled() && steps.checkout.conclusion == 'success' }} + uses: actions/setup-go@v5 with: - go: ${{ matrix.go }} - dir: ./config + cache: false + go-version-file: ./config/go.mod + - name: Go Tidy + if: ${{ !cancelled() && steps.checkout.conclusion == 'success' && steps.setupgo.conclusion == 'success' }} + working-directory: ./config + run: | + trap 'echo "::error file=go.mod,title=Tidy Check::Commit would leave go.mod untidy"' ERR + go mod tidy + git diff --exit-code tests: - needs: ['config'] + name: Tests + if: ${{ !cancelled() }} uses: ./.github/workflows/tests.yml with: cd: config package_expr: ./... - go_versions: ${{ needs.config.outputs.go_versions }} + qemu: false diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b682388208..580f2118e7 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -12,63 +12,54 @@ on: - release-4.* jobs: - config: + lints: + name: Lints runs-on: ubuntu-latest - outputs: - go_versions: ${{ steps.config.outputs.go_versions }} steps: - - id: config - run: | - echo 'go_versions=["1.20"]' >> "$GITHUB_OUTPUT" - - commit-check: - name: Commit Check - runs-on: ubuntu-latest - steps: - - name: commit check + - name: Commit Check uses: gsactions/commit-message-checker@v2 with: pattern: | - ^(.*):\s*(.*)\n.*$ + ^[^:!]+: .+\n\n.*$ error: 'Commit must begin with : ' flags: 'gm' excludeTitle: true excludeDescription: true checkAllCommitMessages: true accessToken: ${{ secrets.GITHUB_TOKEN }} - - api-reference-check: - name: API Reference Check - runs-on: ubuntu-latest - steps: - name: Checkout + id: checkout + if: ${{ !cancelled() }} uses: actions/checkout@v4 - - name: gen api reference + - name: Check Filenames + if: ${{ !cancelled() && steps.checkout.conclusion == 'success' }} + run: | # Check for all the characters Windows hates. + git ls-files -- ':/:*[<>:"|?*]*' | while read -r file; do + printf '::error file=%s,title=Bad Filename::Disallowed character in file name\n' "$file" + done + exit $(git ls-files -- ':/:*[<>:"|?*]*' | wc -l) + - name: Check API Reference + if: ${{ !cancelled() && steps.checkout.conclusion == 'success' }} run: | npx widdershins --search false --language_tabs 'python:Python' 'go:Golang' 'javascript:Javascript' --summary ./openapi.yaml -o ./Documentation/reference/api.md - - name: diff - run: | git diff --exit-code - - tidy: - name: Tidy - needs: ['config'] - runs-on: ubuntu-latest - strategy: - matrix: - go: - - ${{ fromJSON(needs.config.outputs.go_versions)[0] }} - steps: - - uses: actions/setup-go@v5 + - name: Setup Go + id: 'setupgo' + if: ${{ !cancelled() && steps.checkout.conclusion == 'success' }} + uses: actions/setup-go@v5 with: - go-version: ${{ matrix.go }} - - uses: actions/checkout@v4 - - uses: ./.github/actions/go-tidy - with: - go: ${{ matrix.go }} + cache: false + go-version-file: ./go.mod + - name: Go Tidy + if: ${{ !cancelled() && steps.checkout.conclusion == 'success' && steps.setupgo.conclusion == 'success' }} + run: | + trap 'echo "::error file=go.mod,title=Tidy Check::Commit would leave go.mod untidy"' ERR + go mod tidy + git diff --exit-code documentation: name: Documentation + needs: ['lints'] runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -77,8 +68,9 @@ jobs: publish: false tests: - needs: ['config'] + name: Tests + needs: ['lints'] uses: ./.github/workflows/tests.yml with: package_expr: ./... - go_versions: ${{ needs.config.outputs.go_versions }} + qemu: false diff --git a/.github/workflows/nightly-ci.yml b/.github/workflows/nightly-ci.yml index 95ac5a91a6..41471d4719 100644 --- a/.github/workflows/nightly-ci.yml +++ b/.github/workflows/nightly-ci.yml @@ -10,46 +10,31 @@ on: required: false type: string description: 'Package expression(s) passed to `go test`' - go_versions: - required: false - type: string - description: 'JSON array of go versions to use for tests' - platforms: - required: false - type: string - description: 'JSON array of platforms to test' jobs: defaults: + name: Check Input runs-on: ubuntu-latest outputs: package_expr: ${{ steps.config.outputs.package_expr }} - go_versions: ${{ steps.config.outputs.go_versions }} - platforms: ${{ steps.config.outputs.platforms }} steps: - - uses: actions/checkout@v4 - - id: config + - name: Checkout + id: checkout + uses: actions/checkout@v4 + - name: Make package expressions + id: config + if: ${{ !cancelled() && steps.checkout.conclusion == 'success' }} run: | if test -n "${{ inputs.package_expr }}"; then printf 'package_expr=%s\n' '${{ inputs.package_expr }}' >> "$GITHUB_OUTPUT" else printf 'package_expr=%s\n' "$(go list -m github.com/quay/clair{core,}/... | awk '{printf("%s/... ",$1)}')" >> "$GITHUB_OUTPUT" fi - if test -n "${{ inputs.go_versions }}"; then - printf 'go_versions=%s\n' '${{ inputs.go_versions }}' >> "$GITHUB_OUTPUT" - else - printf 'go_versions=["1.20"]\n' >> "$GITHUB_OUTPUT" - fi - if test -n "${{ inputs.platforms }}"; then - printf 'platforms=%s\n' '${{ inputs.platforms }}' >> "$GITHUB_OUTPUT" - else - printf 'platforms=["linux/arm64", "linux/ppc64le", "linux/s390x"]\n' >> "$GITHUB_OUTPUT" - fi tests: + name: Tests needs: ['defaults'] uses: ./.github/workflows/tests.yml with: package_expr: ${{ needs.defaults.outputs.package_expr }} - go_versions: ${{ needs.defaults.outputs.go_versions }} - platforms: ${{ needs.defaults.outputs.platforms }} + qemu: true diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index ac16696b72..bcf8e5980a 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -8,18 +8,11 @@ on: required: true type: string description: 'Package expression(s) passed to `go test`' - go_versions: + qemu: required: false - type: string - default: | - ["1.20"] - description: 'JSON array of go versions to use for tests' - platforms: - required: false - type: string - default: | - ["linux/amd64"] - description: 'JSON array of platforms to test' + type: boolean + default: false + description: 'Run tests for additional architectures under qemu' cd: required: false type: string @@ -27,17 +20,96 @@ on: description: 'Change to this directory before running tests' jobs: + setup: + name: Setup + runs-on: ubuntu-latest + strategy: + matrix: + go: ['oldstable', 'stable'] + outputs: + go-cache: ${{ steps.check.outputs.cache-hit == 'true' || steps.setup-go.outputs.cache-hit == 'true' || steps.warm.conclusion == 'success' }} + runner-arch: ${{ steps.arch.outputs.result }} + steps: + - name: Map Arch + id: arch + uses: actions/github-script@v7 + with: + result-encoding: string + script: | + switch (process.env.RUNNER_ARCH) { + case "X64": + return "amd64"; + case "ARM64": + return "arm64"; + default: + core.setFailed(`unknown/unsupported architecture: ${process.env.RUNNER_ARCH}`); + } + return "" + - name: Checkout + if: ${{ inputs.cd == '' }} + id: checkout + uses: actions/checkout@v4 + - name: Check Go Version + if: ${{ inputs.cd == '' && steps.checkout.conclusion == 'success' }} + id: checkversion + uses: actions/setup-go@v5 + with: + go-version: ${{ matrix.go }} + cache: false + - name: Get ImageOS + # There's no way around this, because "ImageOS" is only available to + # processes, but the setup-go action uses it in its key. + if: ${{ inputs.cd == '' && steps.checkout.conclusion == 'success' }} + id: imageos + uses: actions/github-script@v7 + with: + result-encoding: string + script: | + return process.env.ImageOS + - name: Check Cache + if: ${{ inputs.cd == '' && steps.checkout.conclusion == 'success' }} + id: check + uses: actions/cache/restore@v4 + with: + key: >- + setup-go-${{ runner.os }}-${{ steps.imageos.outputs.result }}-go-${{ steps.checkversion.outputs.go-version }}-${{ hashFiles('go.sum') }} + lookup-only: true + path: | + ~/go/pkg/mod + ~/.cache/go-build + - name: Setup Go + if: ${{ inputs.cd == '' && steps.check.outputs.cache-hit != 'true' }} + id: setup-go + uses: actions/setup-go@v5 + with: + go-version: ${{ matrix.go }} + - name: Warm Cache on Miss + id: warm + if: ${{ inputs.cd == '' && steps.check.outputs.cache-hit != 'true' && steps.setup-go.outputs.cache-hit != 'true' }} + run: | + # Warm module+build cache + for GOARCH in amd64 arm64 ppc64le s390x; do + export GOARCH + for mod in '' github.com/quay/clair/config github.com/quay/claircore github.com/quay/claircore/toolkit; do + echo Downloading modules for "${mod-main}/$GOARCH" + go mod download $mod + done + echo Building '"std"' for "$GOARCH" + go build std + done + tests: name: Tests runs-on: ubuntu-latest + needs: ['setup'] strategy: matrix: - go: ${{ fromJSON(inputs.go_versions) }} - platform: ${{ fromJSON(inputs.platforms) }} + go: ['oldstable', 'stable'] + platform: ${{ inputs.qemu && fromJSON('["amd64","arm64","ppc64le","s390x"]') || fromJSON('["amd64"]')}} fail-fast: false services: postgres: - image: docker.io/library/postgres:11 + image: docker.io/library/postgres:15 env: POSTGRES_DB: "clair" POSTGRES_INITDB_ARGS: "--no-sync" @@ -60,63 +132,79 @@ jobs: steps: - name: Configure RabbitMQ + env: + brokername: ${{ matrix.platform == needs.setup.outputs.runner-arch && 'localhost' || 'rabbitmq' }} run: | docker exec ${{ job.services.rabbitmq.id }} rabbitmqctl await_startup docker exec ${{ job.services.rabbitmq.id }} rabbitmq-plugins enable rabbitmq_stomp docker exec ${{ job.services.rabbitmq.id }} rabbitmq-plugins disable rabbitmq_management_agent rabbitmq_prometheus rabbitmq_web_dispatch - docker exec ${{ job.services.rabbitmq.id }} rabbitmqctl add_vhost 'rabbitmq' - docker exec ${{ job.services.rabbitmq.id }} rabbitmqctl set_permissions -p 'rabbitmq' guest '.*' '.*' '.*' + docker exec ${{ job.services.rabbitmq.id }} rabbitmqctl add_vhost "${brokername}" + docker exec ${{ job.services.rabbitmq.id }} rabbitmqctl set_permissions -p "${brokername}" guest '.*' '.*' '.*' docker exec ${{ job.services.rabbitmq.id }} rabbitmqctl add_user clair password docker exec ${{ job.services.rabbitmq.id }} rabbitmqctl set_permissions -p '/' clair '.*' '.*' '.*' - docker exec ${{ job.services.rabbitmq.id }} rabbitmqctl set_permissions -p 'rabbitmq' clair '.*' '.*' '.*' + docker exec ${{ job.services.rabbitmq.id }} rabbitmqctl set_permissions -p "${brokername}" clair '.*' '.*' '.*' + - name: Checkout uses: actions/checkout@v4 - - uses: actions/setup-go@v5 + - name: Setup Go + id: setup-go + uses: actions/setup-go@v5 with: - cache: false # Set up with a finer-grained cache key below. go-version: ${{ matrix.go }} - - name: Check host - id: host - run: - printf 'platform=%s\n' "$(go env GOOS GOARCH | paste -s -d /)" >> "$GITHUB_OUTPUT" - - name: Cache go artifacts - uses: actions/cache@v4 - id: cache + cache: ${{ needs.setup.outputs.go-cache }} + - name: Assets Cache + id: assets + uses: actions/cache/restore@v4 with: - path: | - ~/.cache/go-build - ~/go/pkg/mod - key: ${{ runner.os }}-${{ matrix.platform }}-${{ matrix.go }}-${{ hashFiles('**/go.sum') }} + key: integration-assets-${{ hashFiles('go.sum') }} restore-keys: | - ${{ runner.os }}-${{ matrix.platform }}-${{ matrix.go }}- - - name: Warm the cache on miss - # This is faster to run outside the container, but the module cache - # can't easily be shared between runs because GOOS and GOARCH influence - # the dependency graph. - if: ${{ ! steps.cache.outputs.cache-hit }} + integration-assets- + path: | + ~/.cache/clair-testing + + - name: Tests + if: ${{ matrix.platform == needs.setup.outputs.runner-arch }} + env: + POSTGRES_CONNECTION_STRING: "host=localhost port=${{ job.services.postgres.ports[5432] }} user=clair dbname=clair password=password sslmode=disable" + RABBITMQ_CONNECTION_STRING: "amqp://clair:password@localhost:${{ job.services.rabbitmq.ports[5672] }}/" + STOMP_CONNECTION_STRING: "stomp://clair:password@localhost:${{ job.services.rabbitmq.ports[61613] }}/" + working-directory: ./${{ inputs.cd }} run: | - go env -w $(echo ${{ matrix.platform}} | awk -F / '{print "GOOS="$1, "GOARCH="$2}') - go mod download - go build -v std + # Go Tests + for expr in ${{ inputs.package_expr }}; do + printf '::group::go test %s\n' "$expr" + go test -tags integration "$expr" + printf '::endgroup::\n' + done + - name: Set up QEMU uses: docker/setup-qemu-action@v3 - if: ${{ steps.host.outputs.platform != matrix.platform }} + if: ${{ matrix.platform != needs.setup.outputs.runner-arch }} with: - platforms: ${{ matrix.platform }} - - name: Tests - run: >- - docker run - --rm - --network ${{ job.container.network }} - --platform ${{ matrix.platform }} - --mount "type=bind,src=$(go env GOMODCACHE),dst=/go/pkg/mod" - --mount "type=bind,src=$(go env GOCACHE),dst=/root/.cache/go-build" - --mount "type=bind,src=$(pwd),dst=/build" - --env "POSTGRES_CONNECTION_STRING=host=postgres port=5432 user=clair dbname=clair password=password sslmode=disable" - --env "RABBITMQ_CONNECTION_STRING=amqp://clair:password@rabbitmq:5672/" - --env "STOMP_CONNECTION_STRING=stomp://clair:password@rabbitmq:61613/" - -w "/build/${{ inputs.cd }}" - "quay.io/projectquay/golang:${{ matrix.go }}" - go test - -tags integration - ${{ inputs.package_expr }} + platforms: linux/${{ matrix.platform }} + - name: Qemu Tests + if: ${{ matrix.platform != needs.setup.outputs.runner-arch }} + env: + gover: ${{ steps.setup-go.outputs.go-version }} + run: | + # Go Tests + mkdir -p ~/.cache/clair-testing + docker run \ + --rm \ + --network ${{ job.container.network }} \ + --platform linux/${{ matrix.platform }} \ + --mount "type=bind,src=$(go env GOMODCACHE),dst=/go/pkg/mod" \ + --mount "type=bind,src=$(go env GOCACHE),dst=/root/.cache/go-build" \ + --mount "type=bind,src=${HOME}/.cache/clair-testing,dst=/root/.cache/clair-testing" \ + --mount "type=bind,src=$(pwd),dst=/build" \ + --env "POSTGRES_CONNECTION_STRING=host=postgres port=5432 user=clair dbname=clair password=password sslmode=disable" \ + --env "RABBITMQ_CONNECTION_STRING=amqp://clair:password@rabbitmq:5672/" \ + --env "STOMP_CONNECTION_STRING=stomp://clair:password@rabbitmq:61613/" \ + -w "/build/${{ inputs.cd }}" \ + "quay.io/projectquay/golang:${gover%.*}" \ + sh -c 'for expr in ${{ inputs.package_expr }}; do + printf '\''::group::go test %s\n'\'' "$expr" + go test -tags integration "$expr" + printf '\''::endgroup::\n'\'' + done;' + done diff --git a/config/go.mod b/config/go.mod index 170b2506aa..c29ca2c0a4 100644 --- a/config/go.mod +++ b/config/go.mod @@ -1,5 +1,5 @@ module github.com/quay/clair/config -go 1.17 +go 1.21.8 require github.com/google/go-cmp v0.6.0 diff --git a/go.mod b/go.mod index a2f0b2a302..c5aa9b8148 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/quay/clair/v4 -go 1.20 +go 1.21.8 require ( github.com/Masterminds/semver v1.5.0 diff --git a/go.sum b/go.sum index fc8447e15f..ef1117b47e 100644 --- a/go.sum +++ b/go.sum @@ -66,6 +66,7 @@ github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN github.com/google/go-containerregistry v0.19.1 h1:yMQ62Al6/V0Z7CqIrrS1iYoA5/oQCm88DeNujc7C1KY= github.com/google/go-containerregistry v0.19.1/go.mod h1:YCMFNQeeXeLF+dnhhWkqDItx/JSkH01j1Kis4PsjzFI= github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ= +github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= @@ -138,6 +139,7 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxv github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= @@ -160,6 +162,7 @@ github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APP github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= +github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= @@ -202,6 +205,7 @@ github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94 github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= @@ -234,6 +238,7 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 h1:nrZ3ySNYwJbSpD6ce9duiP+QkD3JuLCcWkdaehUS/3Y= github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80/go.mod h1:iFyPdL66DjUD96XmzVL3ZntbzcflLnznH0fr99w5VqE= github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= @@ -401,6 +406,7 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= +gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 h1:5D53IMaUuA5InSeMu9eJtlQXS2NxAhyWQvkKEgXZhHI= modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4=