diff --git a/.github/actions/cache-go-dependencies/action.yaml b/.github/actions/cache-go-dependencies/action.yaml index 43900bbb10a3f..b4696c0ecd0b4 100644 --- a/.github/actions/cache-go-dependencies/action.yaml +++ b/.github/actions/cache-go-dependencies/action.yaml @@ -15,8 +15,25 @@ runs: - name: Determine Go cache paths id: cache-paths run: | - echo "GOCACHE=$(go env GOCACHE)" >> "$GITHUB_OUTPUT" - echo "GOARCH=$(go env GOARCH)" >> "$GITHUB_OUTPUT" + # Keep assignments separate from echo so Go failures are not masked. + if ! gocache=$(go env GOCACHE); then + echo "::error::Failed to determine GOCACHE: go env GOCACHE failed. See the Go error above." + exit 1 + fi + if [[ -z "$gocache" ]]; then + echo "::error::go env GOCACHE returned an empty value. Cannot configure the Go build cache." + exit 1 + fi + if ! goarch=$(go env GOARCH); then + echo "::error::Failed to determine GOARCH: go env GOARCH failed. See the Go error above." + exit 1 + fi + if [[ -z "$goarch" ]]; then + echo "::error::go env GOARCH returned an empty value. Cannot configure the Go build cache." + exit 1 + fi + echo "GOCACHE=$gocache" >> "$GITHUB_OUTPUT" + echo "GOARCH=$goarch" >> "$GITHUB_OUTPUT" echo "TAG=${{ github.sha }}" >> "$GITHUB_OUTPUT" # Hash go.mod once for use in cache keys. When dependencies change, # the GOCACHE must be invalidated because Go's module index caches diff --git a/.github/actions/download-artifact-with-retry/action.yaml b/.github/actions/download-artifact-with-retry/action.yaml index 69d9d86ddeac6..6e5af7695b2f1 100644 --- a/.github/actions/download-artifact-with-retry/action.yaml +++ b/.github/actions/download-artifact-with-retry/action.yaml @@ -14,7 +14,7 @@ runs: using: composite steps: - id: download-artifact-try1 - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # ratchet:actions/download-artifact@v8 + uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # ratchet:actions/download-artifact@v8 with: name: ${{ inputs.name }} path: ${{ inputs.path }} @@ -22,14 +22,14 @@ runs: continue-on-error: true - id: download-artifact-try2 if: steps.download-artifact-try1.outcome == 'failure' - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # ratchet:actions/download-artifact@v8 + uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # ratchet:actions/download-artifact@v8 with: name: ${{ inputs.name }} path: ${{ inputs.path }} pattern: ${{ inputs.pattern }} continue-on-error: true - if: steps.download-artifact-try2.outcome == 'failure' - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # ratchet:actions/download-artifact@v8 + uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # ratchet:actions/download-artifact@v8 with: name: ${{ inputs.name }} path: ${{ inputs.path }} diff --git a/.github/actions/upload-artifact-with-retry/action.yaml b/.github/actions/upload-artifact-with-retry/action.yaml index 9d68c29d65e11..eb187bdbad2b0 100644 --- a/.github/actions/upload-artifact-with-retry/action.yaml +++ b/.github/actions/upload-artifact-with-retry/action.yaml @@ -24,7 +24,7 @@ runs: using: composite steps: - id: upload-artifact-try1 - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # ratchet:actions/upload-artifact@v7 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # ratchet:actions/upload-artifact@v7 with: name: ${{ inputs.name }} path: ${{ inputs.path }} @@ -33,7 +33,7 @@ runs: continue-on-error: true - id: upload-artifact-try2 if: steps.upload-artifact-try1.outcome == 'failure' - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # ratchet:actions/upload-artifact@v7 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # ratchet:actions/upload-artifact@v7 with: name: ${{ inputs.name }} path: ${{ inputs.path }} @@ -41,7 +41,7 @@ runs: compression-level: ${{ inputs.compression-level }} continue-on-error: true - if: steps.upload-artifact-try2.outcome == 'failure' - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # ratchet:actions/upload-artifact@v7 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # ratchet:actions/upload-artifact@v7 with: name: ${{ inputs.name }} path: ${{ inputs.path }} diff --git a/.github/docker/images.hcl b/.github/docker/images.hcl index 4e9de4284681e..b4b6d47ac7760 100644 --- a/.github/docker/images.hcl +++ b/.github/docker/images.hcl @@ -28,7 +28,7 @@ group "databases" { targets = ["central-db", "scanner-v4-db"] } -# Central database (PostgreSQL 15) +# Central database (PostgreSQL 16) target "central-db" { context = "image/postgres" dockerfile = "Dockerfile" diff --git a/.github/test-images/postgres.dockerfile b/.github/test-images/postgres.dockerfile index a1556f5177f31..bb498f0494622 100644 --- a/.github/test-images/postgres.dockerfile +++ b/.github/test-images/postgres.dockerfile @@ -1,3 +1,3 @@ -# Postgres 15 image for unit test CI. Referenced by unit-tests.yaml. +# Postgres 16 image for unit test CI. Referenced by unit-tests.yaml. # Dependabot auto-bumps this digest via the docker ecosystem config. -FROM quay.io/sclorg/postgresql-15-c9s@sha256:77c1e962234c598f3ed2b5e581f0845fca333bd262e9b0ee542bf8fa96fbc03d +FROM quay.io/sclorg/postgresql-16-c9s@sha256:d33717fd33c1a4b11afef94568d0c20812a19d62fb8c633fadee1e491e2edd4a diff --git a/.github/workflows/add-new-pr-to-oss-triaging.yml b/.github/workflows/add-new-pr-to-oss-triaging.yml index dfb5b52a95100..9d7a10996440f 100644 --- a/.github/workflows/add-new-pr-to-oss-triaging.yml +++ b/.github/workflows/add-new-pr-to-oss-triaging.yml @@ -9,7 +9,7 @@ env: jobs: check-pr-if-external: name: Add external label to pull request if outside StackRox - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 env: GH_TOKEN: ${{ github.token }} BASE_REPO: ${{ github.repository }} diff --git a/.github/workflows/add-vms-to-cluster.yml b/.github/workflows/add-vms-to-cluster.yml index 58eb968bd3a87..0ace3f5f384e7 100644 --- a/.github/workflows/add-vms-to-cluster.yml +++ b/.github/workflows/add-vms-to-cluster.yml @@ -1,5 +1,5 @@ -name: "Add VMs to Cluster" -run-name: "Add ${{ inputs.num-vms }} ${{ inputs.vm-os }} VMs to ${{ inputs.cluster-name }}" +name: "Ensure VMs on Cluster" +run-name: "Ensure ${{ inputs.num-vms }} ${{ inputs.vm-os }} VMs on ${{ inputs.cluster-name }}" on: workflow_dispatch: @@ -9,7 +9,7 @@ on: required: true type: string num-vms: - description: "Number of VMs to deploy" + description: "Desired count of {os}-1..N, not how many to add. Existing VMs are reused; 2 is a no-op if rhel9-1 and rhel9-2 already exist." required: false default: 1 type: number @@ -19,6 +19,7 @@ on: default: "rhel9" type: choice options: + - rhel8 - rhel9 - rhel10 ssh-public-key: @@ -29,7 +30,7 @@ on: jobs: add-vms: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 timeout-minutes: 60 env: INFRA_TOKEN: ${{ secrets.INFRA_TOKEN }} diff --git a/.github/workflows/audit-backport-prs.yml b/.github/workflows/audit-backport-prs.yml index 08ceefc68c375..b220cb7c4e725 100644 --- a/.github/workflows/audit-backport-prs.yml +++ b/.github/workflows/audit-backport-prs.yml @@ -29,7 +29,7 @@ env: jobs: properties: name: Read repository properties - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 outputs: slack-channel: ${{ fromJSON(format('["{0}","{1}"]', steps.properties.outputs.slack-channel, steps.properties.outputs.dry-slack-channel))[(github.event_name == 'workflow_dispatch' && inputs.dry_run) || github.event_name == 'pull_request'] }} steps: @@ -40,7 +40,7 @@ jobs: run: gh api -H "$ACCEPT_RAW" "$PROPERTIES_URL" >> "$GITHUB_OUTPUT" audit: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 needs: [properties] permissions: contents: read diff --git a/.github/workflows/auto-merge.yml b/.github/workflows/auto-merge.yml index 5ae4329f1151d..1a18592aebca3 100644 --- a/.github/workflows/auto-merge.yml +++ b/.github/workflows/auto-merge.yml @@ -16,7 +16,7 @@ concurrency: jobs: auto-merge: name: Enable auto-merge for eligible PRs - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 if: github.repository_owner == 'stackrox' steps: diff --git a/.github/workflows/backport-pr.yaml b/.github/workflows/backport-pr.yaml index 817043cc41ea0..dc54e31818fce 100644 --- a/.github/workflows/backport-pr.yaml +++ b/.github/workflows/backport-pr.yaml @@ -16,7 +16,7 @@ defaults: jobs: backport: name: Backport - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 # Only react to merged PRs for security reasons. # See https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target. if: > diff --git a/.github/workflows/batch-load-test-metrics.yml b/.github/workflows/batch-load-test-metrics.yml index 8168c7cfd63fd..f798db49af93d 100644 --- a/.github/workflows/batch-load-test-metrics.yml +++ b/.github/workflows/batch-load-test-metrics.yml @@ -10,7 +10,7 @@ concurrency: Batch load test metrics jobs: batch-load-test-metrics: if: ${{ github.repository_owner == 'stackrox' }} - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 container: image: quay.io/stackrox-io/apollo-ci:stackrox-test-0.5.11@sha256:df3459cf038e73775314b3a5d36d14dda41e6df438a0273c9efa8d23e0f2358a # ratchet:quay.io/stackrox-io/apollo-ci:stackrox-test-0.5.11 steps: diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 6776ef11d814c..607c34fe7803f 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -164,7 +164,7 @@ jobs: ROX_PRODUCT_BRANDING: ${{ matrix.branding }} # For consistency with `image/rhel/konflux.Dockerfile`, see comment there. UI_PKG_INSTALL_EXTRA_ARGS: --ignore-scripts - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Checkout uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v7.0.0 @@ -205,7 +205,7 @@ jobs: pre-build-cli: needs: define-job-matrix - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 env: BUILD_TAG: ${{ needs.define-job-matrix.outputs.build-tag }} SHORTCOMMIT: ${{ needs.define-job-matrix.outputs.short-commit }} @@ -283,7 +283,7 @@ jobs: # race-condition-debug - built with -race matrix: ${{ fromJson(needs.define-job-matrix.outputs.matrix).pre_build_go_binaries }} needs: define-job-matrix - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 env: BUILD_TAG: ${{ needs.define-job-matrix.outputs.build-tag }} SHORTCOMMIT: ${{ needs.define-job-matrix.outputs.short-commit }} @@ -363,7 +363,7 @@ jobs: compression-level: 1 pre-build-docs: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Checkout uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v7.0.0 @@ -394,7 +394,7 @@ jobs: image/rhel/docs pre-build-oss-notice: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Checkout uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v7.0.0 @@ -435,7 +435,7 @@ jobs: path: image/rhel/THIRD_PARTY_NOTICES build-and-push-db: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 needs: - define-job-matrix if: ${{ !cancelled() }} @@ -498,7 +498,7 @@ jobs: - name: Build and push DB images in parallel with bake if: | github.event_name == 'push' || !github.event.pull_request.head.repo.fork - uses: docker/bake-action@d3418bd7d0e9324001bca92fa8ba175ea7e6dc9b # ratchet:docker/bake-action@v7.3.0 + uses: docker/bake-action@018cb6412ab401ebaa809aa5f85966b74628600f # ratchet:docker/bake-action@v7.4.0 with: source: . files: .github/docker/images.hcl @@ -541,7 +541,7 @@ jobs: "docker://quay.io/rhacs-eng/scanner-v4-db:${{ env.BUILD_TAG }}" build-operator-bundle: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 env: QUAY_ORG: rhacs-eng QUAY_RHACS_ENG_RW_PASSWORD: ${{ secrets.QUAY_RHACS_ENG_RW_PASSWORD }} @@ -579,7 +579,7 @@ jobs: build-and-push-main: # Use native arm64 runner to avoid QEMU emulation overhead (~2x slower). - runs-on: ${{ (matrix.arch == 'arm64' && 'ubuntu-24.04-arm') || 'ubuntu-latest' }} + runs-on: ${{ (matrix.arch == 'arm64' && 'ubuntu-24.04-arm') || 'ubuntu-24.04' }} needs: - define-job-matrix - pre-build-cli @@ -755,7 +755,7 @@ jobs: push_main_image_set "$push_context" "${{ env.ROX_PRODUCT_BRANDING }}" "${{ matrix.arch }}" push-matching-collector-scanner: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 needs: - define-job-matrix if: ${{ !cancelled() }} @@ -788,7 +788,7 @@ jobs: push_matching_collector_scanner_images "${{ env.ROX_PRODUCT_BRANDING }}" push-main-manifests: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 needs: - define-job-matrix - build-and-push-main @@ -911,7 +911,7 @@ jobs: message-path: build-comment.md build-and-push-operator: - runs-on: ${{ (matrix.arch == 'arm64' && 'ubuntu-24.04-arm') || 'ubuntu-latest' }} + runs-on: ${{ (matrix.arch == 'arm64' && 'ubuntu-24.04-arm') || 'ubuntu-24.04' }} needs: - define-job-matrix - pre-build-go-binaries @@ -1027,7 +1027,7 @@ jobs: echo "Operator image push completed successfully" build-and-push-scanner: - runs-on: ${{ (matrix.arch == 'arm64' && 'ubuntu-24.04-arm') || 'ubuntu-latest' }} + runs-on: ${{ (matrix.arch == 'arm64' && 'ubuntu-24.04-arm') || 'ubuntu-24.04' }} needs: - define-job-matrix - build-and-push-db @@ -1111,7 +1111,7 @@ jobs: push_scanner_image_set "${{ matrix.registry }}" "${{ matrix.arch }}" push-scanner-manifests: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 needs: - define-job-matrix - build-and-push-scanner @@ -1171,7 +1171,7 @@ jobs: push_scanner_image_manifest_lists "${{ matrix.registry }}" "$architectures" push-operator-manifests: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 needs: - define-job-matrix - build-and-push-operator @@ -1228,7 +1228,7 @@ jobs: contains(github.event.pull_request.labels.*.name, 'scan-go-binaries') env: ARTIFACT_DIR: junit-reports/ - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 needs: - pre-build-cli - pre-build-go-binaries @@ -1289,7 +1289,7 @@ jobs: contains(github.event.pull_request.labels.*.name, 'ci-test-github-action-slack-messages') ) name: Post failure message to Slack - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 needs: - build-and-push-db - build-and-push-main diff --git a/.github/workflows/check-crd-compatibility.yaml b/.github/workflows/check-crd-compatibility.yaml index 95ba18adc4a75..d5d2ba0ffd62b 100644 --- a/.github/workflows/check-crd-compatibility.yaml +++ b/.github/workflows/check-crd-compatibility.yaml @@ -23,7 +23,7 @@ jobs: check-crd-compatibility: needs: detect-changes if: ${{ !needs.detect-changes.outputs.ui_only }} - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 container: image: quay.io/stackrox-io/apollo-ci:stackrox-test-0.5.11@sha256:df3459cf038e73775314b3a5d36d14dda41e6df438a0273c9efa8d23e0f2358a # ratchet:quay.io/stackrox-io/apollo-ci:stackrox-test-0.5.11 outputs: @@ -88,19 +88,17 @@ jobs: - name: Run crdify for platform operator run: | - set -e + set -euo pipefail old_path="$PWD/.old-stackrox/operator/config/crd/bases" new_path="$PWD/operator/config/crd/bases" - crdify="go run -C operator/tools/crdify sigs.k8s.io/crdify --config=config.yaml" - set -x - $crdify "file://${old_path}/platform.stackrox.io_securedclusters.yaml" "file://${new_path}/platform.stackrox.io_securedclusters.yaml" - $crdify "file://${old_path}/platform.stackrox.io_centrals.yaml" "file://${new_path}/platform.stackrox.io_centrals.yaml" + crdify=".github/workflows/scripts/crdify.sh" + $crdify "${old_path}/platform.stackrox.io_securedclusters.yaml" "${new_path}/platform.stackrox.io_securedclusters.yaml" + $crdify "${old_path}/platform.stackrox.io_centrals.yaml" "${new_path}/platform.stackrox.io_centrals.yaml" - name: Run crdify for config operator run: | - set -e + set -euo pipefail old_path="$PWD/.old-stackrox/config-controller/config/crd/bases" new_path="$PWD/config-controller/config/crd/bases" - crdify="go run -C operator/tools/crdify sigs.k8s.io/crdify --config=config.yaml" - set -x - $crdify "file://${old_path}/config.stackrox.io_securitypolicies.yaml" "file://${new_path}/config.stackrox.io_securitypolicies.yaml" + crdify=".github/workflows/scripts/crdify.sh" + $crdify "${old_path}/config.stackrox.io_securitypolicies.yaml" "${new_path}/config.stackrox.io_securitypolicies.yaml" diff --git a/.github/workflows/check-crd-frozen-on-release.yaml b/.github/workflows/check-crd-frozen-on-release.yaml index fa64eb4493aec..981253e8cfb15 100644 --- a/.github/workflows/check-crd-frozen-on-release.yaml +++ b/.github/workflows/check-crd-frozen-on-release.yaml @@ -35,7 +35,7 @@ permissions: jobs: check-crds-frozen: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Checkout stackrox/stackrox uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v7.0.0 diff --git a/.github/workflows/check-pr-title.yaml b/.github/workflows/check-pr-title.yaml index 5212dfd3ac09b..49afd75bf89a4 100644 --- a/.github/workflows/check-pr-title.yaml +++ b/.github/workflows/check-pr-title.yaml @@ -6,7 +6,7 @@ on: jobs: check-title: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 env: PR_TITLE: ${{ github.event.pull_request.title }} steps: diff --git a/.github/workflows/ci-failures-report.yml b/.github/workflows/ci-failures-report.yml index 9be7d94707cf8..a2e0e03d9a7bf 100644 --- a/.github/workflows/ci-failures-report.yml +++ b/.github/workflows/ci-failures-report.yml @@ -18,7 +18,7 @@ on: jobs: report-e2e-failures-to-slack: if: ${{ github.repository_owner == 'stackrox' }} - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Checkout uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v7.0.0 diff --git a/.github/workflows/create-clusters.yml b/.github/workflows/create-clusters.yml index 40d939145dfcc..2693c27c9311c 100644 --- a/.github/workflows/create-clusters.yml +++ b/.github/workflows/create-clusters.yml @@ -42,7 +42,7 @@ concurrency: Release automation ${{ inputs.version }} jobs: trim-cluster-names: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 outputs: cluster-with-fake-load-name-cleaned: ${{ steps.cluster-names.outputs.cluster-with-fake-load-name-cleaned }} cluster-with-real-load-name-cleaned: ${{ steps.cluster-names.outputs.cluster-with-real-load-name-cleaned }} @@ -64,7 +64,7 @@ jobs: clusters: name: Setup demo clusters needs: trim-cluster-names - uses: stackrox/actions/.github/workflows/create-demo-clusters.yml@43bb707aa4f32ead5bfb8d5ab11fb409f971ffc8 # ratchet:stackrox/actions/.github/workflows/create-demo-clusters.yml@v1 + uses: stackrox/actions/.github/workflows/create-demo-clusters.yml@f3893761af7aff7477e3dde7a4d9656b173fc687 # ratchet:stackrox/actions/.github/workflows/create-demo-clusters.yml@v1 secrets: inherit with: version: ${{github.event.inputs.version}} diff --git a/.github/workflows/cut-rc.yml b/.github/workflows/cut-rc.yml index 55870ab183efc..d28a3ce950815 100644 --- a/.github/workflows/cut-rc.yml +++ b/.github/workflows/cut-rc.yml @@ -37,6 +37,8 @@ on: default: true type: boolean +cache-mode: read + env: main_branch: ${{github.event.repository.default_branch}} script_url: /repos/${{github.repository}}/contents/.github/workflows/scripts/common.sh?ref=${{ github.ref_name }} @@ -60,7 +62,7 @@ concurrency: Release automation ${{ inputs.version }} jobs: properties: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 outputs: slack-channel: ${{ fromJSON(format('["{0}","{1}"]', steps.fetch.outputs.dry-slack-channel, steps.fetch.outputs.slack-channel))[github.event.inputs.dry-run != 'true'] }} jira-project: ${{ steps.fetch.outputs.jira-project }} @@ -73,7 +75,7 @@ jobs: run-parameters: name: Run parameters - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - run: | [ "$DRY_RUN" = "true" ] && echo "::warning::This is a dry run" @@ -96,7 +98,7 @@ jobs: check-jira: name: Check Jira tickets for release needs: [variables, properties] - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Query JIRA # Checking unequal with "false" because closed milestones have unset input values. @@ -117,7 +119,7 @@ jobs: postpone-prs: name: Postpone open PRs needs: variables - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Check open PRs id: check @@ -173,7 +175,7 @@ jobs: cut-rc: name: Tag RC for milestone ${{needs.variables.outputs.milestone}} - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 needs: [variables, properties, postpone-prs, check-jira] steps: - name: Check out code @@ -308,7 +310,7 @@ jobs: :arrow_right: Once all checks pass and you're ready for release, run the <${{ github.server_url }}/${{ github.repository }}/actions/workflows/finish-release.yml|Finish Release> workflow and delete the `${{ needs.variables.outputs.next-milestone }}` milestone to avoid confusion. trim-cluster-names: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 outputs: cluster-with-fake-load-name-cleaned: ${{ steps.cluster-names.outputs.cluster-with-fake-load-name-cleaned }} cluster-with-real-load-name-cleaned: ${{ steps.cluster-names.outputs.cluster-with-real-load-name-cleaned }} @@ -331,7 +333,7 @@ jobs: name: Setup demo clusters secrets: inherit needs: [variables, cut-rc, trim-cluster-names] - uses: stackrox/actions/.github/workflows/create-demo-clusters.yml@4efb76aa74694b9ee55e95c4ead57fdf50d79ddf # ratchet:stackrox/actions/.github/workflows/create-demo-clusters.yml@v1 + uses: stackrox/actions/.github/workflows/create-demo-clusters.yml@f3893761af7aff7477e3dde7a4d9656b173fc687 # ratchet:stackrox/actions/.github/workflows/create-demo-clusters.yml@v1 if: >- # Skip if no clusters are going to be created. Checking unequal with "false" because closed milestones have unset input values. github.event.inputs.create-k8s-cluster != 'false' || github.event.inputs.create-os4-cluster != 'false' || diff --git a/.github/workflows/detect-changes.yml b/.github/workflows/detect-changes.yml index b36dab630fc9f..8cced67cfd949 100644 --- a/.github/workflows/detect-changes.yml +++ b/.github/workflows/detect-changes.yml @@ -39,7 +39,7 @@ on: jobs: detect: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 outputs: files: ${{ steps.list.outputs.files }} ui_only: ${{ steps.list.outputs.ui_only }} diff --git a/.github/workflows/e2e-byodb-tests.yaml b/.github/workflows/e2e-byodb-tests.yaml index 55831a9784654..f9a52ad5547a6 100644 --- a/.github/workflows/e2e-byodb-tests.yaml +++ b/.github/workflows/e2e-byodb-tests.yaml @@ -29,7 +29,7 @@ defaults: jobs: gke-byodb-qa-e2e-tests: if: github.event_name == 'workflow_dispatch' || inputs.should-run - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 env: MAIN_IMAGE_TAG: ${{ inputs.tag }} BUILD_TAG: ${{ inputs.tag }} @@ -39,6 +39,7 @@ jobs: LOAD_BALANCER: lb ORCHESTRATOR_FLAVOR: k8s KUBERNETES_PROVIDER: gke + SCANNER_V4_DB_STORAGE_CLASS: stackrox-gke-ssd POSTGRES_VERSION: "17" LONGTERM_LICENSE: "unused" BYODB_TEST: "true" @@ -75,7 +76,7 @@ jobs: - name: Create GKE cluster env: MACHINE_TYPE: e2-standard-8 - NUM_NODES: "3" + NUM_NODES: "1" GKE_SPOT: "false" timeout-minutes: 20 run: | @@ -98,6 +99,16 @@ jobs: - name: Create artifact directory run: mkdir -p "$ARTIFACT_DIR" + - name: Retrieve roxie version from repository + id: roxie-version + run: echo "version=$(cat ROXIE_VERSION)" >> "$GITHUB_OUTPUT" + + - name: Install roxie + uses: stackrox/actions/roxie/install-cli@bcda9b2d6d2b644c267e699479656973e84ef7fa # ratchet:stackrox/actions@v1 + with: + version: "v${{ steps.roxie-version.outputs.version }}" + gh-token: ${{ github.token }} + - name: Run pre-test shell: python env: @@ -134,12 +145,14 @@ jobs: QUAY_RHACS_ENG_BEARER_TOKEN: ${{ secrets.QUAY_RHACS_ENG_BEARER_TOKEN }} REDHAT_USERNAME: ${{ secrets.RH_REGISTRY_USERNAME_RO }} REDHAT_PASSWORD: ${{ secrets.RH_REGISTRY_PASSWORD_RO }} + SLACK_FIXABLE_VULNS_CHANNEL: ${{ secrets.SLACK_FIXABLE_VULNS_CHANNEL }} SLACK_MAIN_WEBHOOK: ${{ secrets.SLACK_MAIN_WEBHOOK }} SLACK_ALT_WEBHOOK: ${{ secrets.SLACK_ALT_WEBHOOK }} OCM_OFFLINE_TOKEN: ${{ secrets.OCM_OFFLINE_TOKEN }} CLOUD_SOURCES_TEST_OCM_CLIENT_ID: ${{ secrets.CLOUD_SOURCES_TEST_OCM_CLIENT_ID }} CLOUD_SOURCES_TEST_OCM_CLIENT_SECRET: ${{ secrets.CLOUD_SOURCES_TEST_OCM_CLIENT_SECRET }} BUILD_ID: ${{ github.run_id }} + USE_ROXIE_DEPLOY: true timeout-minutes: 245 run: tests/byodb/run.sh /tmp/byodb-test-logs diff --git a/.github/workflows/e2e-db-backup-restore-tests.yaml b/.github/workflows/e2e-db-backup-restore-tests.yaml index eff0bfcb79fda..7ea0636f763b1 100644 --- a/.github/workflows/e2e-db-backup-restore-tests.yaml +++ b/.github/workflows/e2e-db-backup-restore-tests.yaml @@ -29,15 +29,13 @@ defaults: jobs: gke-db-backup-restore-tests: if: github.event_name == 'workflow_dispatch' || inputs.should-run - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 env: MAIN_IMAGE_TAG: ${{ inputs.tag }} BUILD_TAG: ${{ inputs.tag }} CI_JOB_NAME: gke-db-backup-restore-tests ARTIFACT_DIR: ./junit-reports - LOAD_BALANCER: lb ROX_SCANNER_V4: "false" - STORAGE: pvc STORAGE_CLASS: faster PYTHONUNBUFFERED: "1" timeout-minutes: 60 @@ -62,7 +60,7 @@ jobs: - name: Create GKE cluster env: MACHINE_TYPE: e2-standard-8 - NUM_NODES: "3" + NUM_NODES: "1" GKE_SPOT: "false" timeout-minutes: 20 run: | @@ -75,6 +73,16 @@ jobs: make roxctl_linux-amd64 echo "$(pwd)/bin/linux_amd64" >> "$GITHUB_PATH" + - name: Retrieve roxie version from repository + id: roxie-version + run: echo "version=$(cat ROXIE_VERSION)" >> "$GITHUB_OUTPUT" + + - name: Install roxie + uses: stackrox/actions/roxie/install-cli@bcda9b2d6d2b644c267e699479656973e84ef7fa # ratchet:stackrox/actions@v1 + with: + version: "v${{ steps.roxie-version.outputs.version }}" + gh-token: ${{ secrets.GITHUB_TOKEN }} + - name: Verify kubectl access and wait for cluster to stabilize timeout-minutes: 5 run: | @@ -101,16 +109,24 @@ jobs: QUAY_RHACS_ENG_RO_PASSWORD: ${{ secrets.QUAY_RHACS_ENG_RO_PASSWORD }} REGISTRY_USERNAME: ${{ secrets.QUAY_RHACS_ENG_RO_USERNAME }} REGISTRY_PASSWORD: ${{ secrets.QUAY_RHACS_ENG_RO_PASSWORD }} - ORCHESTRATOR_FLAVOR: k8s run: | source tests/e2e/lib.sh source tests/scripts/setup-certs.sh source scripts/ci/sensor-wait.sh + export_test_environment setup_deployment_env false false - deploy_stackrox - # Persist API_ENDPOINT for post-test steps (ci_export only sets it in this shell) - echo "API_ENDPOINT=${API_ENDPOINT}" >> "$GITHUB_ENV" + + roxie_config="$(mktemp)" + merge_yaml "$roxie_config" <<'EOF' + central: + resourceProfile: ci + securedCluster: + resourceProfile: ci + EOF + deploy_stackrox_with_roxie_compat "$roxie_config" + rm -f "$roxie_config" + db_backup_and_restore_test /tmp/db-backup-restore-test - name: Run post-test diff --git a/.github/workflows/e2e-dispatch.yaml b/.github/workflows/e2e-dispatch.yaml index 50696c5561e63..4335fefeb05cb 100644 --- a/.github/workflows/e2e-dispatch.yaml +++ b/.github/workflows/e2e-dispatch.yaml @@ -105,13 +105,14 @@ jobs: print(f'{k} = {v}') jobs_registry = [ - Job(name='e2e-byodb-tests'), + Job(name='e2e-byodb-tests', require_pr_label=True), Job(name='e2e-db-backup-restore-tests'), Job(name='e2e-gke-upgrade-tests'), - Job(name='e2e-nongroovy-tests'), + Job(name='e2e-nongroovy-tests-gke'), + Job(name='e2e-nongroovy-tests-gke-konflux', require_konflux_build=True), Job(name='e2e-qa-tests-gke', require_pr_label=True), Job(name='e2e-qa-tests-gke-konflux', require_konflux_build=True), - Job(name='e2e-qa-tests-ocp-4-22', require_pr_label=True), + Job(name='e2e-qa-tests-ocp-fips-konflux', require_konflux_build=True), ] with open(os.environ['GITHUB_OUTPUT'], mode='at', encoding='utf-8') as file: @@ -135,7 +136,7 @@ jobs: wait-for-images: needs: [ should-dispatch ] if: needs.should-dispatch.outputs.wait-for-gha-images == 'true' - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 env: MAIN_IMAGE_TAG_DIR: "." IMAGE_PREFIX: "" @@ -198,7 +199,7 @@ jobs: wait-for-konflux-images: needs: [ should-dispatch ] if: needs.should-dispatch.outputs.wait-for-konflux-images == 'true' - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 env: MAIN_IMAGE_TAG_DIR: "operator" IMAGE_PREFIX: "release-" @@ -262,15 +263,26 @@ jobs: group: e2e-gke-upgrade-tests-${{ github.workflow }}-${{ github.head_ref || github.run_id }} cancel-in-progress: true - e2e-nongroovy-tests: + e2e-nongroovy-tests-gke: needs: [ wait-for-images, should-dispatch ] - uses: ./.github/workflows/e2e-nongroovy-tests.yaml + uses: ./.github/workflows/e2e-nongroovy-tests-gke.yaml with: tag: ${{ needs.wait-for-images.outputs.tag }} - should-run: ${{ fromJSON(needs.should-dispatch.outputs.jobs).e2e-nongroovy-tests }} + should-run: ${{ fromJSON(needs.should-dispatch.outputs.jobs).e2e-nongroovy-tests-gke }} secrets: inherit concurrency: - group: e2e-nongroovy-tests-${{ github.workflow }}-${{ github.head_ref || github.run_id }} + group: e2e-nongroovy-tests-gke-${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + + e2e-nongroovy-tests-gke-konflux: + needs: [ wait-for-konflux-images, should-dispatch ] + uses: ./.github/workflows/e2e-nongroovy-tests-gke-konflux.yaml + with: + tag: ${{ needs.wait-for-konflux-images.outputs.tag }}${{ needs.wait-for-konflux-images.outputs.tag_suffix }} + should-run: ${{ fromJSON(needs.should-dispatch.outputs.jobs).e2e-nongroovy-tests-gke-konflux }} + secrets: inherit + concurrency: + group: e2e-nongroovy-tests-gke-konflux-${{ github.workflow }}-${{ github.head_ref || github.run_id }} cancel-in-progress: true e2e-qa-tests-gke: @@ -284,15 +296,15 @@ jobs: group: e2e-qa-tests-gke-${{ github.workflow }}-${{ github.head_ref || github.run_id }} cancel-in-progress: true - e2e-qa-tests-ocp-4-22: - needs: [ wait-for-images, should-dispatch ] - uses: ./.github/workflows/e2e-qa-tests-ocp-4-22.yaml + e2e-qa-tests-ocp-fips-konflux: + needs: [ wait-for-konflux-images, should-dispatch ] + uses: ./.github/workflows/e2e-qa-tests-ocp-fips-konflux.yaml with: - tag: ${{ needs.wait-for-images.outputs.tag }} - should-run: ${{ fromJSON(needs.should-dispatch.outputs.jobs).e2e-qa-tests-ocp-4-22 }} + tag: ${{ needs.wait-for-konflux-images.outputs.tag }}${{ needs.wait-for-konflux-images.outputs.tag_suffix }} + should-run: ${{ fromJSON(needs.should-dispatch.outputs.jobs).e2e-qa-tests-ocp-fips-konflux }} secrets: inherit concurrency: - group: e2e-qa-tests-ocp-4-22-${{ github.workflow }}-${{ github.head_ref || github.run_id }} + group: e2e-qa-tests-ocp-fips-konflux-${{ github.workflow }}-${{ github.head_ref || github.run_id }} cancel-in-progress: true e2e-qa-tests-gke-konflux: diff --git a/.github/workflows/e2e-gke-upgrade-tests.yaml b/.github/workflows/e2e-gke-upgrade-tests.yaml index 9d33fc971103d..bf779c3a02626 100644 --- a/.github/workflows/e2e-gke-upgrade-tests.yaml +++ b/.github/workflows/e2e-gke-upgrade-tests.yaml @@ -31,7 +31,7 @@ jobs: # Verifies Central DB upgrades/rollbacks. gke-upgrade-tests-central: if: github.event_name == 'workflow_dispatch' || inputs.should-run - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 env: MAIN_IMAGE_TAG: ${{ inputs.tag }} BUILD_TAG: ${{ inputs.tag }} @@ -39,7 +39,6 @@ jobs: # gke-upgrade-tests expect all sensor, central and postgres tests to run together in a single sequence. CI_JOB_NAME: gke-upgrade-tests-central ARTIFACT_DIR: ./junit-reports - SCANNER_V4_DB_STORAGE_CLASS: faster # Make sure Python steps don't buffer stdout/stderr. PYTHONUNBUFFERED: "1" timeout-minutes: 180 # Keep in sync with cluster's lifespan @@ -59,7 +58,8 @@ jobs: - name: Create GKE cluster env: MACHINE_TYPE: e2-standard-8 - NUM_NODES: "3" + # Leave room for the scale workload alongside both Scanner versions. + NUM_NODES: "4" GKE_SPOT: "false" timeout-minutes: 20 run: | @@ -80,6 +80,16 @@ jobs: - name: Build roxctl run: make roxctl_linux-amd64 + - name: Retrieve roxie version from repository + id: roxie-version + run: echo "version=$(cat ROXIE_VERSION)" >> "$GITHUB_OUTPUT" + + - name: Install roxie + uses: stackrox/actions/roxie/install-cli@bcda9b2d6d2b644c267e699479656973e84ef7fa # ratchet:stackrox/actions@v1 + with: + version: "v${{ steps.roxie-version.outputs.version }}" + gh-token: ${{ secrets.GITHUB_TOKEN }} + - name: Verify kubectl access and wait for cluster to stabilize timeout-minutes: 5 run: | @@ -108,7 +118,6 @@ jobs: - name: Run central upgrade test env: - LONGTERM_LICENSE: todo - remove me QUAY_RHACS_ENG_RO_USERNAME: ${{ secrets.QUAY_RHACS_ENG_RO_USERNAME }} QUAY_RHACS_ENG_RO_PASSWORD: ${{ secrets.QUAY_RHACS_ENG_RO_PASSWORD }} REGISTRY_USERNAME: ${{ secrets.QUAY_RHACS_ENG_RO_USERNAME }} @@ -117,7 +126,6 @@ jobs: GOOGLE_ARTIFACT_REGISTRY_SERVICE_ACCOUNT_V2: ${{ secrets.GOOGLE_ARTIFACT_REGISTRY_SERVICE_ACCOUNT_V2 }} REDHAT_USERNAME: ${{ secrets.RH_REGISTRY_USERNAME_RO }} REDHAT_PASSWORD: ${{ secrets.RH_REGISTRY_PASSWORD_RO }} - LOAD_BALANCER: lb run: | tests/upgrade/postgres_run.sh /tmp/postgres-upgrade-test-logs # This makes sure Stackrox_Deployment / Was Stackrox deployed to the cluster? test does not fail. @@ -180,10 +188,27 @@ jobs: gcp-account: ${{ secrets.GCP_SERVICE_ACCOUNT_STACKROX_CI }} directory: ${{ env.ARTIFACT_DIR }} - # Verifies we can do Postgres major version upgrade. - gke-upgrade-tests-postgres: + check-postgres-upgrade: if: github.event_name == 'workflow_dispatch' || inputs.should-run runs-on: ubuntu-latest + outputs: + required: ${{ steps.check.outputs.required }} + steps: + - name: Checkout repo + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v7.0.0 + with: + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha || github.sha }} + persist-credentials: false + - name: Check whether PostgreSQL needs a major-version upgrade + id: check + run: tests/upgrade/postgres_upgrade_run.sh --check + + # Verifies we can do Postgres major version upgrade. + gke-upgrade-tests-postgres: + needs: check-postgres-upgrade + if: needs.check-postgres-upgrade.outputs.required == 'true' + runs-on: ubuntu-24.04 env: MAIN_IMAGE_TAG: ${{ inputs.tag }} BUILD_TAG: ${{ inputs.tag }} @@ -210,7 +235,8 @@ jobs: - name: Create GKE cluster env: MACHINE_TYPE: e2-standard-8 - NUM_NODES: "3" + # Leave room for the scale workload alongside both Scanner versions. + NUM_NODES: "4" GKE_SPOT: "false" timeout-minutes: 20 run: | @@ -231,6 +257,16 @@ jobs: - name: Build roxctl run: make roxctl_linux-amd64 + - name: Retrieve roxie version from repository + id: roxie-version + run: echo "version=$(cat ROXIE_VERSION)" >> "$GITHUB_OUTPUT" + + - name: Install roxie + uses: stackrox/actions/roxie/install-cli@bcda9b2d6d2b644c267e699479656973e84ef7fa # ratchet:stackrox/actions@v1 + with: + version: "v${{ steps.roxie-version.outputs.version }}" + gh-token: ${{ secrets.GITHUB_TOKEN }} + - name: Verify kubectl access and wait for cluster to stabilize timeout-minutes: 5 run: | @@ -259,7 +295,6 @@ jobs: - name: Run postgres version upgrade test env: - LONGTERM_LICENSE: todo - remove me QUAY_RHACS_ENG_RO_USERNAME: ${{ secrets.QUAY_RHACS_ENG_RO_USERNAME }} QUAY_RHACS_ENG_RO_PASSWORD: ${{ secrets.QUAY_RHACS_ENG_RO_PASSWORD }} REGISTRY_USERNAME: ${{ secrets.QUAY_RHACS_ENG_RO_USERNAME }} @@ -267,7 +302,6 @@ jobs: GOOGLE_CREDENTIALS_GCR_SCANNER_V2: ${{ secrets.GOOGLE_CREDENTIALS_GCR_SCANNER_V2 }} REDHAT_USERNAME: ${{ secrets.RH_REGISTRY_USERNAME_RO }} REDHAT_PASSWORD: ${{ secrets.RH_REGISTRY_PASSWORD_RO }} - LOAD_BALANCER: lb run: | tests/upgrade/postgres_upgrade_run.sh /tmp/postgres-version-upgrade-test-logs # This makes sure Stackrox_Deployment / Was Stackrox deployed to the cluster? test does not fail. @@ -333,7 +367,7 @@ jobs: # Verifies Sensor/Secured Cluster `upgrader` (applicable to manifest installations only). gke-upgrade-tests-sensor: if: github.event_name == 'workflow_dispatch' || inputs.should-run - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 env: MAIN_IMAGE_TAG: ${{ inputs.tag }} BUILD_TAG: ${{ inputs.tag }} @@ -360,7 +394,7 @@ jobs: - name: Create GKE cluster env: MACHINE_TYPE: e2-standard-8 - NUM_NODES: "3" + NUM_NODES: "1" GKE_SPOT: "false" timeout-minutes: 20 run: | diff --git a/.github/workflows/e2e-nongroovy-tests-gke-konflux.yaml b/.github/workflows/e2e-nongroovy-tests-gke-konflux.yaml new file mode 100644 index 0000000000000..1a7c511cb7970 --- /dev/null +++ b/.github/workflows/e2e-nongroovy-tests-gke-konflux.yaml @@ -0,0 +1,38 @@ +name: e2e-nongroovy-tests-gke-konflux + +on: + workflow_call: + inputs: + tag: + description: | + Image tag to test. The caller needs to make sure that the tag carries the + "-fast" Konflux suffix if required (e.g. for development builds). + type: string + required: true + should-run: + description: true if should really run the job. false - otherwise, i.e. the job should be skipped. + type: boolean + required: true + workflow_dispatch: + inputs: + tag: + description: | + Image tag to test. You need to make sure that the tag carries the + "-fast" Konflux suffix if required (e.g. for development builds). + type: string + required: true + +permissions: + contents: read + pull-requests: read + +jobs: + run: + uses: ./.github/workflows/e2e-nongroovy-tests.yaml + with: + should-run: ${{ github.event_name == 'workflow_dispatch' || inputs.should-run }} + tag: ${{ inputs.tag }} + ci-job-name: gke-nongroovy-e2e-tests-konflux + extra-env-vars: | + USE_KONFLUX_IMAGES=true + secrets: inherit diff --git a/.github/workflows/e2e-nongroovy-tests-gke.yaml b/.github/workflows/e2e-nongroovy-tests-gke.yaml new file mode 100644 index 0000000000000..d0370a2f6ace0 --- /dev/null +++ b/.github/workflows/e2e-nongroovy-tests-gke.yaml @@ -0,0 +1,32 @@ +name: e2e-nongroovy-tests-gke + +on: + workflow_call: + inputs: + tag: + description: Image tag to test. + type: string + required: true + should-run: + description: true if should really run the job. false - otherwise, i.e. the job should be skipped. + type: boolean + required: true + workflow_dispatch: + inputs: + tag: + description: Image tag to test. + type: string + required: true + +permissions: + contents: read + pull-requests: read + +jobs: + run: + uses: ./.github/workflows/e2e-nongroovy-tests.yaml + with: + should-run: ${{ github.event_name == 'workflow_dispatch' || inputs.should-run }} + tag: ${{ inputs.tag }} + ci-job-name: gke-nongroovy-e2e-tests + secrets: inherit diff --git a/.github/workflows/e2e-nongroovy-tests.yaml b/.github/workflows/e2e-nongroovy-tests.yaml index a26a14434d63a..768d5dfea1439 100644 --- a/.github/workflows/e2e-nongroovy-tests.yaml +++ b/.github/workflows/e2e-nongroovy-tests.yaml @@ -11,12 +11,14 @@ on: description: true if should really run the job. false - otherwise, i.e. the job should be skipped. type: boolean required: true - workflow_dispatch: - inputs: - tag: - description: Image tag to test. + ci-job-name: + description: Unique job name, e.g. gke-nongroovy-e2e-tests-konflux. Propagated to tests as CI_JOB_NAME for test dispatching. type: string required: true + extra-env-vars: + description: Additional environment variables as multi-line KEY=VALUE pairs (e.g., USE_ROXIE_DEPLOY=true) + type: string + required: false permissions: contents: read @@ -28,13 +30,13 @@ defaults: jobs: gke-nongroovy-e2e-tests: - if: github.event_name == 'workflow_dispatch' || inputs.should-run - runs-on: ubuntu-latest + if: inputs.should-run + runs-on: ubuntu-24.04 env: MAIN_IMAGE_TAG: ${{ inputs.tag }} BUILD_TAG: ${{ inputs.tag }} GCP_SERVICE_ACCOUNT_STACKROX_CI: ${{ secrets.GCP_SERVICE_ACCOUNT_STACKROX_CI }} - CI_JOB_NAME: gke-nongroovy-e2e-tests + CI_JOB_NAME: ${{ inputs.ci-job-name }} ARTIFACT_DIR: ./junit-reports LOAD_BALANCER: lb ORCHESTRATOR_FLAVOR: k8s @@ -42,12 +44,12 @@ jobs: SENSOR_SCANNER_V4_SUPPORT: "true" ROX_DEPLOY_SENSOR_WITH_CRS: "true" SENSOR_HELM_MANAGED: "true" - SCANNER_V4_DB_STORAGE_CLASS: faster STORAGE: pvc STORAGE_CLASS: faster + SCANNER_V4_DB_STORAGE_CLASS: faster ROX_SCANNER_V4: "true" PYTHONUNBUFFERED: "1" - timeout-minutes: 120 + timeout-minutes: 361 steps: - name: Checkout repo @@ -61,6 +63,17 @@ jobs: with: gcp-account: ${{ secrets.GCP_SERVICE_ACCOUNT_STACKROX_CI }} + - name: Set additional env vars + if: inputs.extra-env-vars != '' + env: + EXTRA_ENV_VARS: ${{ inputs.extra-env-vars }} + run: | + while IFS= read -r line; do + if [[ -n "$line" ]]; then + echo "$line" >> "$GITHUB_ENV" + fi + done <<< "$EXTRA_ENV_VARS" + - name: Docker login to Quay.io env: REGISTRY_USERNAME: ${{ secrets.QUAY_RHACS_ENG_RO_USERNAME }} @@ -75,13 +88,22 @@ jobs: - name: Create GKE cluster env: MACHINE_TYPE: e2-standard-8 - NUM_NODES: "3" + NUM_NODES: "1" GKE_SPOT: "false" timeout-minutes: 20 run: | scripts/ci/gke.sh provision_gke_cluster nongroovy echo "KUBECONFIG=${HOME}/.kube/config" >> "$GITHUB_ENV" + - name: Retrieving roxie version from repository + id: roxie-version + run: echo "version=$(cat ROXIE_VERSION)" >> "$GITHUB_OUTPUT" + + - name: Install roxie + uses: stackrox/actions/roxie/install-cli@43bb707aa4f32ead5bfb8d5ab11fb409f971ffc8 # ratchet:stackrox/actions@v1 + with: + version: "v${{ steps.roxie-version.outputs.version }}" + - name: Build roxctl # roxctl is used for generate (deploy) and CLI e2e tests (token-file, etc). # Copy to /usr/local/bin so it survives bats tests which mv the binary out of bin/. @@ -150,16 +172,14 @@ jobs: QUAY_RHACS_ENG_RO_USERNAME: ${{ secrets.QUAY_RHACS_ENG_RO_USERNAME }} REGISTRY_PASSWORD: ${{ secrets.QUAY_RHACS_ENG_RO_PASSWORD }} REGISTRY_USERNAME: ${{ secrets.QUAY_RHACS_ENG_RO_USERNAME }} - timeout-minutes: 90 + timeout-minutes: 245 run: tests/e2e/run.sh /tmp/e2e-test-logs - - name: Persist env vars for post-test + - name: Ensure central stability before post-test if: always() run: | source tests/e2e/lib.sh wait_for_api - echo "API_ENDPOINT=${API_ENDPOINT}" >> "$GITHUB_ENV" - echo "ROX_ADMIN_PASSWORD=$(cat deploy/k8s/central-deploy/password)" >> "$GITHUB_ENV" - name: Run post-test if: always() diff --git a/.github/workflows/e2e-qa-tests-gke-konflux.yaml b/.github/workflows/e2e-qa-tests-gke-konflux.yaml index cf816fcc4232a..8b050adcc6ef9 100644 --- a/.github/workflows/e2e-qa-tests-gke-konflux.yaml +++ b/.github/workflows/e2e-qa-tests-gke-konflux.yaml @@ -35,4 +35,6 @@ jobs: ORCHESTRATOR_FLAVOR=k8s KUBERNETES_PROVIDER=gke USE_KONFLUX_IMAGES=true + STORAGE_CLASS=stackrox-gke-ssd + SCANNER_V4_DB_STORAGE_CLASS=stackrox-gke-ssd secrets: inherit diff --git a/.github/workflows/e2e-qa-tests-gke.yaml b/.github/workflows/e2e-qa-tests-gke.yaml index b575161117c70..6fb0aca91414d 100644 --- a/.github/workflows/e2e-qa-tests-gke.yaml +++ b/.github/workflows/e2e-qa-tests-gke.yaml @@ -30,4 +30,6 @@ jobs: extra-env-vars: | ORCHESTRATOR_FLAVOR=k8s KUBERNETES_PROVIDER=gke + STORAGE_CLASS=stackrox-gke-ssd + SCANNER_V4_DB_STORAGE_CLASS=stackrox-gke-ssd secrets: inherit diff --git a/.github/workflows/e2e-qa-tests-ocp-4-22.yaml b/.github/workflows/e2e-qa-tests-ocp-fips-konflux.yaml similarity index 62% rename from .github/workflows/e2e-qa-tests-ocp-4-22.yaml rename to .github/workflows/e2e-qa-tests-ocp-fips-konflux.yaml index 45d41397f18c4..7670ec997452d 100644 --- a/.github/workflows/e2e-qa-tests-ocp-4-22.yaml +++ b/.github/workflows/e2e-qa-tests-ocp-fips-konflux.yaml @@ -1,10 +1,12 @@ -name: e2e-qa-tests-ocp-4-22 +name: e2e-qa-tests-ocp-fips-konflux on: workflow_call: inputs: tag: - description: Image tag to test. + description: | + Image tag to test. The caller needs to make sure that the tag carries the + "-fast" Konflux suffix if required (e.g. for development builds). type: string required: true should-run: @@ -14,7 +16,9 @@ on: workflow_dispatch: inputs: tag: - description: Image tag to test. + description: | + Image tag to test. You need to make sure that the tag carries the + "-fast" Konflux suffix if required (e.g. for development builds). type: string required: true @@ -24,18 +28,19 @@ jobs: with: should-run: ${{ github.event_name == 'workflow_dispatch' || inputs.should-run }} tag: ${{ inputs.tag }} - ci-job-name: ocp-4-22-qa-e2e-tests - cluster-name-prefix: e2e-qa-tests-ocp422 + ci-job-name: ocp-qa-e2e-tests-fips-konflux + cluster-name-prefix: e2e-qa-ocp-fps-knflx cluster-provisioning-method: infra - cluster-wait-timeout-minutes: 50 + cluster-wait-timeout-minutes: 60 infra-flavor: openshift-4 infra-args: | - openshift-version=ocp/stable-4.22 + openshift-version=ocp/stable master-node-type=e2-standard-4 master-node-count=3 worker-node-type=e2-standard-8 worker-node-count=3 ssd-storage-class=true + fips-enabled=true infra-lifespan: 5h # TODO(ROX-36332): setup workload identities # SETUP_WORKLOAD_IDENTITIES=true @@ -43,4 +48,5 @@ jobs: ORCHESTRATOR_FLAVOR=openshift KUBERNETES_PROVIDER=ocp SFA_AGENT=true + USE_KONFLUX_IMAGES=true secrets: inherit diff --git a/.github/workflows/e2e-qa-tests.yaml b/.github/workflows/e2e-qa-tests.yaml index 56b47f044edf6..78e145ac3c238 100644 --- a/.github/workflows/e2e-qa-tests.yaml +++ b/.github/workflows/e2e-qa-tests.yaml @@ -72,7 +72,7 @@ defaults: jobs: qa-e2e-tests: if: inputs.should-run - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 env: MAIN_IMAGE_TAG: ${{ inputs.tag }} BUILD_TAG: ${{ inputs.tag }} @@ -136,7 +136,7 @@ jobs: - name: Trigger cluster creation via infra if: inputs.cluster-provisioning-method == 'infra' - uses: stackrox/actions/infra/create-cluster@9238e423c3ae1ac4eb0f254cbb98da9daae24d86 # ratchet:stackrox/actions/infra/create-cluster@v1 + uses: stackrox/actions/infra/create-cluster@f3893761af7aff7477e3dde7a4d9656b173fc687 # ratchet:stackrox/actions/infra/create-cluster@v1 with: token: ${{ secrets.INFRA_TOKEN }} flavor: ${{ inputs.infra-flavor }} @@ -189,9 +189,10 @@ jobs: run: echo "version=$(cat ROXIE_VERSION)" >> "$GITHUB_OUTPUT" - name: Install roxie - uses: stackrox/actions/roxie/install-cli@43bb707aa4f32ead5bfb8d5ab11fb409f971ffc8 # ratchet:stackrox/actions@v1 + uses: stackrox/actions/roxie/install-cli@bcda9b2d6d2b644c267e699479656973e84ef7fa # ratchet:stackrox/actions@v1 with: version: "v${{ steps.roxie-version.outputs.version }}" + gh-token: ${{ github.token }} - name: Install oc if: startsWith(inputs.infra-flavor, 'openshift') diff --git a/.github/workflows/emailsender-central-compatibility.yaml b/.github/workflows/emailsender-central-compatibility.yaml index 7dd300125b10e..f5d3f3952dae0 100644 --- a/.github/workflows/emailsender-central-compatibility.yaml +++ b/.github/workflows/emailsender-central-compatibility.yaml @@ -27,7 +27,7 @@ jobs: e2e-test-on-kind: timeout-minutes: 60 name: "Test on kind cluster" - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 if: ${{ !github.event.pull_request.head.repo.fork }} # do not run for PRs from forks permissions: id-token: write @@ -68,12 +68,13 @@ jobs: run: echo "version=$(cat stackrox/ROXIE_VERSION)" >> "$GITHUB_OUTPUT" - name: Install roxie - uses: stackrox/actions/roxie/install-cli@43bb707aa4f32ead5bfb8d5ab11fb409f971ffc8 # ratchet:stackrox/actions@v1 + uses: stackrox/actions/roxie/install-cli@bcda9b2d6d2b644c267e699479656973e84ef7fa # ratchet:stackrox/actions@v1 with: version: "v${{ steps.roxie-version.outputs.version }}" + gh-token: ${{ github.token }} - name: Create Kind cluster - uses: helm/kind-action@ef37e7f390d99f746eb8b610417061a60e82a6cc # ratchet:helm/kind-action@v1 + uses: helm/kind-action@06c1ae10762d3b9c1644e7fe69596ae519e015a2 # ratchet:helm/kind-action@v1.15.0 with: cluster_name: kind version: v0.32.0 diff --git a/.github/workflows/finish-release.yml b/.github/workflows/finish-release.yml index 480a4b67d6bfc..3e7a22ecaeed7 100644 --- a/.github/workflows/finish-release.yml +++ b/.github/workflows/finish-release.yml @@ -34,7 +34,7 @@ concurrency: Release automation ${{ inputs.version }} jobs: properties: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 outputs: slack-channel: ${{ fromJSON(format('["{0}","{1}"]', steps.fetch.outputs.dry-slack-channel, steps.fetch.outputs.slack-channel))[github.event.inputs.dry-run != 'true'] }} steps: @@ -47,7 +47,7 @@ jobs: run-parameters: if: github.event_name == 'workflow_dispatch' name: Run parameters - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - run: | [ "$DRY_RUN" = "true" ] && echo "::warning::This is a dry run" @@ -70,7 +70,7 @@ jobs: preflight-checks: needs: [variables] - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Verify that this release is listed in scanner’s RELEASE_VERSION file on master run: | @@ -81,7 +81,7 @@ jobs: publish-release: name: Tag Release ${{ needs.variables.outputs.named-release-patch }} - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 needs: [variables, properties, preflight-checks] steps: - name: Check out code @@ -183,7 +183,7 @@ jobs: update-infra-demo-version: name: Update infra demo default versions - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 needs: [publish-release] env: BRANCH: "bump-demo-versions-${{ inputs.version }}" diff --git a/.github/workflows/fixxxer.yaml b/.github/workflows/fixxxer.yaml index d581a1ae15229..f2706f6355ef5 100644 --- a/.github/workflows/fixxxer.yaml +++ b/.github/workflows/fixxxer.yaml @@ -15,7 +15,7 @@ jobs: name: Run PR Fixxxer # TODO: support leading and trailing whitespace too if: ${{ github.event.issue.pull_request && github.event.comment.body == '/fixxx' }} - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 container: image: quay.io/stackrox-io/apollo-ci:stackrox-test-0.5.11@sha256:df3459cf038e73775314b3a5d36d14dda41e6df438a0273c9efa8d23e0f2358a # ratchet:quay.io/stackrox-io/apollo-ci:stackrox-test-0.5.11 steps: diff --git a/.github/workflows/konflux-auto-retest.yml b/.github/workflows/konflux-auto-retest.yml index 03dcac1d1f6a5..d875d9ccbbf71 100644 --- a/.github/workflows/konflux-auto-retest.yml +++ b/.github/workflows/konflux-auto-retest.yml @@ -7,7 +7,7 @@ on: jobs: retest: - uses: stackrox/actions/.github/workflows/periodic-retest-konflux-builds.yml@f4660e8ce6bd7558e782e8e7cd26bad8cfbb6b9f # ratchet:stackrox/actions/.github/workflows/periodic-retest-konflux-builds.yml@v1 + uses: stackrox/actions/.github/workflows/periodic-retest-konflux-builds.yml@f3893761af7aff7477e3dde7a4d9656b173fc687 # ratchet:stackrox/actions/.github/workflows/periodic-retest-konflux-builds.yml@v1 permissions: pull-requests: write issues: write diff --git a/.github/workflows/labeler.yaml b/.github/workflows/labeler.yaml index 3a48fb21bfee2..53e135c2eebf5 100644 --- a/.github/workflows/labeler.yaml +++ b/.github/workflows/labeler.yaml @@ -8,7 +8,7 @@ on: jobs: label-pr: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 if: ${{ github.actor != 'dependabot[bot]' && !github.event.pull_request.head.repo.fork }} steps: - uses: actions/labeler@b8dd2d9be0f68b860e7dae5dae7d772984eacd6d # ratchet:actions/labeler@v6 diff --git a/.github/workflows/nightly-tag.yml b/.github/workflows/nightly-tag.yml index d030b195015b5..6ef44bae5fd8f 100644 --- a/.github/workflows/nightly-tag.yml +++ b/.github/workflows/nightly-tag.yml @@ -2,11 +2,11 @@ name: Create nightly tag on: workflow_dispatch: schedule: - - cron: 0 0 * * 1-5 + - cron: 0 2 * * 1-5 jobs: create-nightly-tag: if: ${{ github.repository_owner == 'stackrox' }} - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Checkout uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v7.0.0 @@ -20,7 +20,7 @@ jobs: slack-on-failure: needs: create-nightly-tag if: failure() - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Slack on failure uses: slackapi/slack-github-action@45a88b9581bfab2566dc881e2cd66d334e621e2c # ratchet:slackapi/slack-github-action@v3.0.3 diff --git a/.github/workflows/notify-milestone-change.yml b/.github/workflows/notify-milestone-change.yml index a6a648b50dec0..dc327ead0b241 100644 --- a/.github/workflows/notify-milestone-change.yml +++ b/.github/workflows/notify-milestone-change.yml @@ -18,7 +18,7 @@ env: jobs: properties: name: Read repository properties - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 outputs: docs-repository: ${{ steps.properties.outputs.docs-repository }} slack-channel: ${{ fromJSON(format('["{0}","{1}"]', steps.properties.outputs.dry-slack-channel, steps.properties.outputs.slack-channel))[github.repository == 'stackrox/stackrox'] }} @@ -31,7 +31,7 @@ jobs: run: gh api -H "$ACCEPT_RAW" "$PROPERTIES_URL" >> "$GITHUB_OUTPUT" notify: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 needs: [properties] steps: - name: Determine Jira context for PR diff --git a/.github/workflows/performance-tests.yml b/.github/workflows/performance-tests.yml index c1561db61871e..8fabc727634ce 100644 --- a/.github/workflows/performance-tests.yml +++ b/.github/workflows/performance-tests.yml @@ -10,7 +10,7 @@ concurrency: performance-tests-${{ github.ref }} jobs: wait-for-images: name: Wait for images - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 if: ${{ contains(github.event.pull_request.labels.*.name, 'ci-performance-tests') }} steps: - name: Checkout repo @@ -33,7 +33,7 @@ jobs: run-k6-performance-tests: needs: [wait-for-images] name: Run k6 performance tests - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 if: ${{ contains(github.event.pull_request.labels.*.name, 'ci-performance-tests') }} env: USE_GKE_GCLOUD_AUTH_PLUGIN: "True" @@ -57,9 +57,19 @@ jobs: repository: "stackrox/workflow" path: workflow + - name: Retrieve roxie version from repository + id: roxie-version + run: echo "version=$(cat ROXIE_VERSION)" >> "$GITHUB_OUTPUT" + + - name: Install roxie + uses: stackrox/actions/roxie/install-cli@bcda9b2d6d2b644c267e699479656973e84ef7fa # ratchet:stackrox/actions@v1 + with: + version: "v${{ steps.roxie-version.outputs.version }}" + gh-token: ${{ secrets.GITHUB_TOKEN }} + # Create scale cluster with larger nodes. - name: Create testing cluster - uses: stackrox/actions/infra/create-cluster@9238e423c3ae1ac4eb0f254cbb98da9daae24d86 # ratchet:stackrox/actions/infra/create-cluster@v1 + uses: stackrox/actions/infra/create-cluster@f3893761af7aff7477e3dde7a4d9656b173fc687 # ratchet:stackrox/actions/infra/create-cluster@v1 with: token: ${{ secrets.INFRA_TOKEN }} flavor: gke-default @@ -97,12 +107,8 @@ jobs: - name: Clean previous installation run: | source ./workflow/env.sh - ./scripts/k8s/cleanup.sh stackrox - - # Delete all namespaces created by scale script. - for i in $(seq 1 "${SCALE_WORKLOAD_CLUSTERS}"); do - ./scripts/k8s/cleanup.sh "stackrox${i}" - done + roxie teardown central --single-namespace + ./scale/dev/kill-sensors.sh - name: Get PR image tag run: | @@ -112,37 +118,29 @@ jobs: # Install Central + CentralDB - name: Launch central services env: - LOAD_BALANCER: lb - ROX_POSTGRES_DATASTORE: "true" - MONITORING_SUPPORT: "false" REGISTRY_USERNAME: ${{ secrets.QUAY_RHACS_ENG_RO_USERNAME }} REGISTRY_PASSWORD: ${{ secrets.QUAY_RHACS_ENG_RO_PASSWORD }} run: | - source ./workflow/env.sh + set -euo pipefail - # ROX-29641: We are facing issues with workload generation on GKE when Scanner v4 is enabled. - export ROX_SCANNER_V4=false ./scale/dev/launch_central.sh - + source .roxie.env # Required for k6 tests to run. - echo "ROX_ADMIN_PASSWORD=$(cat ./deploy/k8s/central-deploy/password)" >> "$GITHUB_ENV" - echo "ROX_PASSWORD=$(cat ./deploy/k8s/central-deploy/password)" >> "$GITHUB_ENV" - echo "::add-mask::$(cat ./deploy/k8s/central-deploy/password)" + echo "ROX_ADMIN_PASSWORD=${ROX_ADMIN_PASSWORD}" >> "$GITHUB_ENV" + echo "ROX_PASSWORD=${ROX_ADMIN_PASSWORD}" >> "$GITHUB_ENV" + echo "::add-mask::${ROX_ADMIN_PASSWORD}" - LB_IP="$(kubectl -n stackrox get svc/central-loadbalancer -o json | jq -r '.status.loadBalancer.ingress[0] | .ip // .hostname')" - echo "HOST=https://${LB_IP}:443" >> "$GITHUB_ENV" - echo "API_ENDPOINT=${LB_IP}:443" >> "$GITHUB_ENV" - echo "::add-mask::${LB_IP}" + echo "HOST=${ROX_BASE_URL}" >> "$GITHUB_ENV" + echo "API_ENDPOINT=${API_ENDPOINT}" >> "$GITHUB_ENV" + echo "::add-mask::${API_ENDPOINT}" - name: Generate workload env: - LOAD_BALANCER: lb - ROX_POSTGRES_DATASTORE: "true" - MONITORING_SUPPORT: "false" REGISTRY_USERNAME: ${{ secrets.QUAY_RHACS_ENG_RO_USERNAME }} REGISTRY_PASSWORD: ${{ secrets.QUAY_RHACS_ENG_RO_PASSWORD }} run: | source ./workflow/env.sh + source .roxie.env ./scale/dev/run-many.sh "${SCALE_WORKLOAD_TYPE}" "${SCALE_WORKLOAD_CLUSTERS}" num_deployments=$(yq '.deploymentWorkload[] | select(.deploymentType == "Deployment") | .numDeployments' "./scale/workloads/${SCALE_WORKLOAD_TYPE}.yaml") diff --git a/.github/workflows/release-ci.yaml b/.github/workflows/release-ci.yaml index ea7cc7238d2b6..7a631fd36b3ad 100644 --- a/.github/workflows/release-ci.yaml +++ b/.github/workflows/release-ci.yaml @@ -9,19 +9,23 @@ on: jobs: run-parameters: name: Run parameters - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - run: | echo "Event: ${{ github.event_name }}" >> "$GITHUB_STEP_SUMMARY" echo "Ref: ${{ github.ref_name }}" >> "$GITHUB_STEP_SUMMARY" build: + permissions: + actions: read + contents: read + pull-requests: write name: Build uses: ./.github/workflows/build.yaml secrets: inherit check-is-release: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 outputs: is_release: ${{ steps.is_release_check.outputs.is_release }} steps: @@ -40,7 +44,7 @@ jobs: fi check-collector-version: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Checkout uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v7.0.0 @@ -53,7 +57,7 @@ jobs: check_collector_version check-fact-version: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Checkout uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v7.0.0 @@ -68,7 +72,7 @@ jobs: publish-helm-charts: needs: [build, check-collector-version, check-fact-version, check-is-release] if: needs.check-is-release.outputs.is_release == 'true' - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Checkout uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v7.0.0 @@ -97,7 +101,7 @@ jobs: publish-cli: needs: [build, check-collector-version, check-fact-version, check-is-release] if: needs.check-is-release.outputs.is_release == 'true' - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Checkout uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v7.0.0 @@ -123,7 +127,7 @@ jobs: publish-openapispec: needs: [build, check-collector-version, check-fact-version, check-is-release] if: needs.check-is-release.outputs.is_release == 'true' - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Checkout uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v7.0.0 diff --git a/.github/workflows/retest_periodic.yml b/.github/workflows/retest_periodic.yml index d30e223e91813..3c371a6102804 100644 --- a/.github/workflows/retest_periodic.yml +++ b/.github/workflows/retest_periodic.yml @@ -10,7 +10,7 @@ jobs: retest: if: ${{ github.repository_owner == 'stackrox' }} timeout-minutes: 10 - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Checkout uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v7.0.0 diff --git a/.github/workflows/scan-image-vulnerabilities.yaml b/.github/workflows/scan-image-vulnerabilities.yaml index 2ee393ab6b219..1d978ee94f840 100644 --- a/.github/workflows/scan-image-vulnerabilities.yaml +++ b/.github/workflows/scan-image-vulnerabilities.yaml @@ -21,7 +21,7 @@ run-name: ${{ format('Scan images for vulnerabilities ({0})', inputs.version || jobs: run-parameters: name: Run parameters - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 outputs: wait-for-images-limit: ${{ steps.run-parameters.outputs.wait-for-images-limit }} version: ${{ steps.run-parameters.outputs.version }} @@ -47,7 +47,7 @@ jobs: scan-image-vulnerabilities-upstream: name: "Upstream: ${{ matrix.image }}:${{ needs.run-parameters.outputs.version }}" - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 needs: [run-parameters] permissions: # Needed for stackrox/central-login to create the JWT token. @@ -79,7 +79,7 @@ jobs: echo "tag=${tag}" >> "${GITHUB_OUTPUT}" - name: Scan image vulnerabilities - uses: stackrox/actions/release/scan-image-vulnerabilities@df8c8f5830fc09d37908be1a9744365a93c5b3cc # ratchet:stackrox/actions/release/scan-image-vulnerabilities@v1 + uses: stackrox/actions/release/scan-image-vulnerabilities@f3893761af7aff7477e3dde7a4d9656b173fc687 # ratchet:stackrox/actions/release/scan-image-vulnerabilities@v1 id: scan-image with: image: rhacs-eng/${{ matrix.image }} @@ -99,7 +99,7 @@ jobs: scan-image-vulnerabilities-konflux: name: "Konflux: ${{ matrix.image }}:${{ needs.run-parameters.outputs.version }}" - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 needs: [run-parameters] permissions: # Needed for stackrox/central-login to create the JWT token. @@ -133,7 +133,7 @@ jobs: echo "tag=${tag}" >> "${GITHUB_OUTPUT}" - name: Scan image vulnerabilities - uses: stackrox/actions/release/scan-image-vulnerabilities@df8c8f5830fc09d37908be1a9744365a93c5b3cc # ratchet:stackrox/actions/release/scan-image-vulnerabilities@v1 + uses: stackrox/actions/release/scan-image-vulnerabilities@f3893761af7aff7477e3dde7a4d9656b173fc687 # ratchet:stackrox/actions/release/scan-image-vulnerabilities@v1 id: scan-image with: image: rhacs-eng/${{ matrix.image }} diff --git a/.github/workflows/scanner-db-integration-tests.yaml b/.github/workflows/scanner-db-integration-tests.yaml index 785f47924b715..effbe1190271e 100644 --- a/.github/workflows/scanner-db-integration-tests.yaml +++ b/.github/workflows/scanner-db-integration-tests.yaml @@ -20,7 +20,7 @@ jobs: db-integration-tests: needs: detect-changes if: ${{ !needs.detect-changes.outputs.ui_only }} - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 container: image: quay.io/stackrox-io/apollo-ci:scanner-test-0.5.11@sha256:cea78f2b3a5a38c9ccda678712daaed90b7c372d6b5df963feb758b32dccebe1 # ratchet:quay.io/stackrox-io/apollo-ci:scanner-test-0.5.11 steps: diff --git a/.github/workflows/scanner-e2e-test.yaml b/.github/workflows/scanner-e2e-test.yaml index e4ee1333e3964..b2d0e9670e165 100644 --- a/.github/workflows/scanner-e2e-test.yaml +++ b/.github/workflows/scanner-e2e-test.yaml @@ -14,7 +14,7 @@ jobs: if: > github.event_name != 'pull_request' || contains(github.event.pull_request.labels.*.name, 'scanner-functional-tests') - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Checkout repo uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v7.0.0 @@ -36,7 +36,7 @@ jobs: name: Deploy and run needs: - scanner-ft-images - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 env: SCANNER_E2E_QUAY_USERNAME: ${{ secrets.QUAY_RHACS_ENG_RO_USERNAME }} SCANNER_E2E_QUAY_PASSWORD: ${{ secrets.QUAY_RHACS_ENG_RO_PASSWORD }} diff --git a/.github/workflows/scanner-mapping-update.yaml b/.github/workflows/scanner-mapping-update.yaml index 9883bf11b4c04..236c427937429 100644 --- a/.github/workflows/scanner-mapping-update.yaml +++ b/.github/workflows/scanner-mapping-update.yaml @@ -7,7 +7,7 @@ on: jobs: update-scanner-mappings: if: ${{ github.repository_owner == 'stackrox' }} - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 env: REPOMAPPING_DIR: repomapping steps: @@ -37,7 +37,7 @@ jobs: send-notification: needs: update-scanner-mappings if: failure() - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 permissions: contents: read checks: read diff --git a/.github/workflows/scanner-nvd-update.yaml b/.github/workflows/scanner-nvd-update.yaml index 0a29f375363c7..8294ffb27ab71 100644 --- a/.github/workflows/scanner-nvd-update.yaml +++ b/.github/workflows/scanner-nvd-update.yaml @@ -12,7 +12,7 @@ on: jobs: fetch-nvd-feeds: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 if: > github.repository_owner == 'stackrox' && github.event_name == 'schedule' || @@ -51,7 +51,7 @@ jobs: if-no-files-found: error fetch-nvd-api: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 if: > github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' || @@ -94,7 +94,7 @@ jobs: upload-pr-nvd-feeds: needs: - fetch-nvd-feeds - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 if: github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'pr-update-scanner-nvd') steps: # Checkout master to get the latest local actions @@ -153,7 +153,7 @@ jobs: upload-nvd-feeds: needs: - fetch-nvd-feeds - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 if: github.event_name != 'pull_request' steps: - name: Checkout repository @@ -182,7 +182,7 @@ jobs: upload-nvd-api: needs: - fetch-nvd-api - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 if: github.event_name != 'pull_request' steps: - name: Checkout repository @@ -212,7 +212,7 @@ jobs: needs: - upload-nvd-feeds - upload-nvd-api - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 if: ${{ failure() && github.ref_name == 'master' }} permissions: contents: read diff --git a/.github/workflows/scanner-offline-bundle-update.yaml b/.github/workflows/scanner-offline-bundle-update.yaml index 657246451eb02..10213e553e435 100644 --- a/.github/workflows/scanner-offline-bundle-update.yaml +++ b/.github/workflows/scanner-offline-bundle-update.yaml @@ -11,7 +11,7 @@ on: jobs: offline-bundle-matrix: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 if: > github.repository_owner == 'stackrox' && github.event_name == 'schedule' || @@ -36,7 +36,7 @@ jobs: offline-bundle-generate: needs: offline-bundle-matrix - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 strategy: fail-fast: false matrix: @@ -69,7 +69,7 @@ jobs: if-no-files-found: error offline-bundle-upload: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 needs: - offline-bundle-generate steps: @@ -125,7 +125,7 @@ jobs: - offline-bundle-matrix - offline-bundle-generate - offline-bundle-upload - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 if: github.event_name == 'schedule' && failure() permissions: contents: read diff --git a/.github/workflows/scanner-updater-bundle.yaml b/.github/workflows/scanner-updater-bundle.yaml index 8f26a5e8e6ba4..de4e98dc7c40a 100644 --- a/.github/workflows/scanner-updater-bundle.yaml +++ b/.github/workflows/scanner-updater-bundle.yaml @@ -21,7 +21,7 @@ permissions: jobs: build-matrix: if: github.repository_owner == 'stackrox' - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 outputs: streams: ${{ steps.emit.outputs.streams }} steps: @@ -40,7 +40,7 @@ jobs: bundle: needs: build-matrix - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 container: image: quay.io/stackrox-io/apollo-ci:scanner-test-0.5.11@sha256:cea78f2b3a5a38c9ccda678712daaed90b7c372d6b5df963feb758b32dccebe1 volumes: @@ -216,7 +216,7 @@ jobs: notify: needs: [bundle] if: always() && needs.bundle.result == 'failure' - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 permissions: contents: read checks: read diff --git a/.github/workflows/scanner-updater-export.yaml b/.github/workflows/scanner-updater-export.yaml index e986e6b4a0afa..cbe0b3a3fa41c 100644 --- a/.github/workflows/scanner-updater-export.yaml +++ b/.github/workflows/scanner-updater-export.yaml @@ -40,7 +40,7 @@ permissions: jobs: recheck: if: ${{ !inputs.skip_freshness_check }} - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 outputs: result: ${{ steps.check.outputs.result }} concurrency: @@ -89,7 +89,7 @@ jobs: update: needs: recheck if: always() && (needs.recheck.result == 'skipped' || needs.recheck.outputs.result == 'run') - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 concurrency: group: scanner-updater-export-${{ inputs.object }} cancel-in-progress: false @@ -104,6 +104,7 @@ jobs: ROX_GIT_REF: ${{ inputs.ref }} GCS_OBJECT: ${{ inputs.object }} STACKROX_RHEL_VEX_COMPRESSED_FILE_TIMEOUT: "10m" + STACKROX_RHEL_VEX_IGNORE_KERNEL_PACKAGES: "true" steps: - name: Checkout repository (master for local actions) uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v7.0.0 @@ -194,7 +195,7 @@ jobs: !inputs.skip_freshness_check && always() && (needs.recheck.result == 'failure' || needs.update.result == 'failure') - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 permissions: contents: read checks: read diff --git a/.github/workflows/scanner-updater-schedule.yaml b/.github/workflows/scanner-updater-schedule.yaml index 7999ec6045cbc..7cdf390562a86 100644 --- a/.github/workflows/scanner-updater-schedule.yaml +++ b/.github/workflows/scanner-updater-schedule.yaml @@ -16,12 +16,15 @@ permissions: jobs: build-matrix: + permissions: + contents: read + actions: read if: >- github.repository_owner == 'stackrox' && ( github.event_name != 'pull_request' || contains(github.event.pull_request.labels.*.name, 'pr-update-scanner-vulns') ) - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 outputs: needs-notification: ${{ steps.matrix-scheduled.outputs.has_errors }} steps: @@ -48,6 +51,9 @@ jobs: SOURCE_CONFIG: scanner/updater/ci/source-config.yaml run: | set -euo pipefail + # Keep cadence eligibility stable if this job is queued or rerun. + schedule_time=$(GH_TOKEN="${{ github.token }}" gh api "repos/${{ github.repository }}/actions/runs/${{ github.run_id }}" --jq '.created_at') + export SCHEDULE_TIME="$schedule_time" result=$(./.github/workflows/scripts/scanner-updater-matrix.sh) { echo "has_errors=$(echo "$result" | jq -r '.has_errors')" @@ -98,7 +104,7 @@ jobs: plan: needs: build-matrix - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 outputs: has_due: ${{ steps.emit.outputs.has_due }} matrix: ${{ steps.emit.outputs.matrix }} @@ -152,7 +158,7 @@ jobs: if: >- github.event_name != 'pull_request' && (failure() || needs.build-matrix.outputs.needs-notification == 'true') - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 permissions: contents: read checks: read diff --git a/.github/workflows/scanner-versioned-definitions-update.yaml b/.github/workflows/scanner-versioned-definitions-update.yaml index 3216f74a5bcf5..c9ba26d32df8f 100644 --- a/.github/workflows/scanner-versioned-definitions-update.yaml +++ b/.github/workflows/scanner-versioned-definitions-update.yaml @@ -43,7 +43,7 @@ on: jobs: parse-versions: if: github.repository_owner == 'stackrox' && github.event_name != 'pull_request' || contains(github.event.pull_request.labels.*.name, 'pr-update-scanner-vulns') - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 outputs: versions: ${{ steps.set-versions.outputs.versions }} steps: @@ -102,7 +102,7 @@ jobs: prepare-environment: if: github.event_name != 'pull_request' || contains(github.event.pull_request.labels.*.name, 'pr-update-scanner-vulns') - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 outputs: manual_url: ${{ steps.set-manual-url.outputs.manual_url }} steps: @@ -187,7 +187,7 @@ jobs: needs: - parse-versions - prepare-environment - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 container: image: quay.io/stackrox-io/apollo-ci:scanner-test-0.5.11@sha256:cea78f2b3a5a38c9ccda678712daaed90b7c372d6b5df963feb758b32dccebe1 # ratchet:quay.io/stackrox-io/apollo-ci:scanner-test-0.5.11 volumes: @@ -340,7 +340,7 @@ jobs: if: github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'pr-update-scanner-vulns') needs: - prepare-environment - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 container: image: quay.io/stackrox-io/apollo-ci:scanner-test-0.5.11@sha256:cea78f2b3a5a38c9ccda678712daaed90b7c372d6b5df963feb758b32dccebe1 # ratchet:quay.io/stackrox-io/apollo-ci:scanner-test-0.5.11 volumes: @@ -430,7 +430,7 @@ jobs: needs: - build-and-run if: ${{ (failure() || success()) && (github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && github.event.inputs.dry_run == 'false')) }} - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: # Checkout to run ./.github/actions/download-artifact-with-retry - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v7.0.0 @@ -510,7 +510,7 @@ jobs: needs: - build-and-run - upload-definitions - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 if: ${{ failure() && github.ref_name == 'master' && (github.event_name == 'schedule' || github.event.inputs.dry_run == 'false') }} permissions: checks: read diff --git a/.github/workflows/scripts/crdify.sh b/.github/workflows/scripts/crdify.sh new file mode 100755 index 0000000000000..37e9ce64b545f --- /dev/null +++ b/.github/workflows/scripts/crdify.sh @@ -0,0 +1,75 @@ +#!/usr/bin/env bash +# Run crdify on copies of CRDs after stripping out known false positives. +# Usage: +# crdify.sh [crdify flags] + +set -euo pipefail + +ROOT_DIR="$(dirname "${BASH_SOURCE[0]}")/../../.." +readonly ROOT_DIR + +if [[ $# -lt 2 ]]; then + echo "usage: $0 [crdify flags]" >&2 + exit 2 +fi + +old_crd="${1:?missing required argument 'old-crd'}" +new_crd="${2:?missing required argument 'new-crd'}" +shift +shift + +if [[ ! -f "$old_crd" ]]; then + echo "::error::CRD file not found: $old_crd" >&2 + exit 1 +fi + +if [[ ! -f "$new_crd" ]]; then + echo "::error::CRD file not found: $new_crd" >&2 + exit 1 +fi + + +# The addition of this particular validation rule, even though considered a breaking change by definition +# (https://github.com/kubernetes/community/blob/main/contributors/devel/sig-architecture/api_changes.md#backward-compatibility-gotchas) +# is fine in practice, since the `excludeByKind` branch is being added in the same release cycle as the rule itself, +# meaning no production CRS could have existed that violated the validation. +filter_spec_exclusions_one_of() { + local input="$1" + local output="$2" + + local message='at most one of the fields in [deployment excludeByKind] may be set' + local rule='(has(self.deployment)?1:0)+(has(self.excludeByKind)?1:0) <= 1' + + # Remove matching rule, and the validations list if empty afterwards. + message="${message}" rule="${rule}" \ + go run -C "${ROOT_DIR}/operator/tools/yq" github.com/mikefarah/yq/v4 eval ' + del( + .spec.versions[].schema.openAPIV3Schema.properties.spec.properties.exclusions.items."x-kubernetes-validations"[] + | select(.message == strenv(message) and .rule == strenv(rule)) + ) + | del( + .spec.versions[].schema.openAPIV3Schema.properties.spec.properties.exclusions.items."x-kubernetes-validations" + | select(length == 0) + ) + ' "$input" > "$output" +} + + +crd_basename="$(basename "${old_crd}")" +case "$crd_basename" in +config.stackrox.io_securitypolicies.yaml) + filtered_dir="$(mktemp -d)" + echo >&2 "Filtering known false positives from ${old_crd} and ${new_crd}" + filter_spec_exclusions_one_of "${old_crd}" "${filtered_dir}/old-${crd_basename}" + filter_spec_exclusions_one_of "${new_crd}" "${filtered_dir}/new-${crd_basename}" + old_crd="${filtered_dir}/old-${crd_basename}" + new_crd="${filtered_dir}/new-${crd_basename}" + ;; +*) + echo >&2 "No filtering rules for ${old_crd}, running crdify on original CRDs." + ;; +esac + +set -x +go run -C "${ROOT_DIR}/operator/tools/crdify" sigs.k8s.io/crdify --config=config.yaml "$@" \ + "file://${old_crd}" "file://${new_crd}" diff --git a/.github/workflows/scripts/scanner-updater-config.sh b/.github/workflows/scripts/scanner-updater-config.sh index 6af97f972a0bd..95a63e7200a3a 100755 --- a/.github/workflows/scripts/scanner-updater-config.sh +++ b/.github/workflows/scripts/scanner-updater-config.sh @@ -11,6 +11,7 @@ # source-object GCS object path for a source. # bundle-object GCS object path for a bundle. # interval-secs Updater refresh interval in seconds. +# attempt-cadence-secs Attempt cadence in seconds; 0 if unset. # # Inputs (environment): # SOURCE_CONFIG — path to source-config.yaml @@ -26,7 +27,7 @@ if [[ ! -f "$config" ]]; then exit 1 fi -if ! yq '.' "$config" > /dev/null 2>&1; then +if ! yq eval '.' "$config" > /dev/null 2>&1; then echo "::error::config file is not valid YAML: $config" >&2 exit 1 fi @@ -52,34 +53,48 @@ command="${1:?missing required argument 'command'}"; shift case "$command" in bucket) - yq '.storage.bucket' "$config" + yq eval '.storage.bucket' "$config" ;; prefix) - yq '.storage.prefix' "$config" + yq eval '.storage.prefix' "$config" ;; sources) stream="${1:?missing required argument 'stream'}"; shift - yq ".bundles.\"${stream}\"[]" "$config" + yq eval ".bundles.\"${stream}\"[]" "$config" ;; source-object) stream="${1:?missing required argument 'stream'}"; shift source="${1:?missing required argument 'source'}"; shift - bucket=$(yq '.storage.bucket' "$config") - prefix=$(yq '.storage.prefix' "$config") + bucket=$(yq eval '.storage.bucket' "$config") + prefix=$(yq eval '.storage.prefix' "$config") echo "gs://${bucket}/${prefix}/${stream}/sources/${source}.json.zst" ;; bundle-object) stream="${1:?missing required argument 'stream'}"; shift - bucket=$(yq '.storage.bucket' "$config") - prefix=$(yq '.storage.prefix' "$config") + bucket=$(yq eval '.storage.bucket' "$config") + prefix=$(yq eval '.storage.prefix' "$config") echo "gs://${bucket}/${prefix}/${stream}/vulnerabilities.zip" ;; interval-secs) source="${1:?missing required argument 'source'}"; shift - default_interval=$(yq '.updaters.default.interval // "4h"' "$config") - interval=$(yq ".updaters.\"${source}\".interval // \"$default_interval\"" "$config") + default_interval=$(yq eval '.updaters.default.interval // "4h"' "$config") + interval=$(yq eval ".updaters.\"${source}\".interval // \"$default_interval\"" "$config") duration_to_seconds "$interval" ;; + attempt-cadence-secs) + source="${1:?missing required argument 'source'}"; shift + cadence=$(yq eval ".updaters.\"${source}\".attempt_cadence // .updaters.default.attempt_cadence // \"\"" "$config") + if [[ -z "$cadence" ]]; then + echo 0 + exit 0 + fi + cadence_secs=$(duration_to_seconds "$cadence") + if (( cadence_secs <= 0 || cadence_secs % 3600 != 0 )); then + echo "::error::attempt_cadence must be a positive whole-hour duration: $cadence" >&2 + exit 1 + fi + echo "$cadence_secs" + ;; *) echo "::error::unknown command: $command" >&2 exit 1 diff --git a/.github/workflows/scripts/scanner-updater-matrix.sh b/.github/workflows/scripts/scanner-updater-matrix.sh index a4fd4b0e1a744..4e99bfd923e37 100755 --- a/.github/workflows/scripts/scanner-updater-matrix.sh +++ b/.github/workflows/scripts/scanner-updater-matrix.sh @@ -10,6 +10,7 @@ # # Inputs (environment): # SOURCE_CONFIG — path to source-config.yaml +# SCHEDULE_TIME — workflow run creation time; defaults to the current time. # # Outputs (stdout): # JSON object with "has_due", "has_errors", "errors", and "matrix" @@ -32,6 +33,9 @@ sc="$(dirname "$0")/scanner-updater-config.sh" bucket=$("$sc" bucket) prefix=$("$sc" prefix) +schedule_epoch=$(date -u -d "${SCHEDULE_TIME:-now}" +%s) +schedule_hour=$(( schedule_epoch / 3600 )) + # Expand stream/ref/updater triples, check freshness, emit due pairs. ./.github/workflows/scripts/scanner-get-released-tags.sh \ | jq -r '.[] | "\(.version) \(.ref)"' \ @@ -44,10 +48,17 @@ prefix=$("$sc" prefix) | while read -r stream ref updater; do object="gs://${bucket}/${prefix}/${stream}/sources/${updater}.json.zst" interval_secs=$("$sc" interval-secs "$updater") + cadence_secs=$("$sc" attempt-cadence-secs "$updater") + if (( cadence_secs > 0 )); then + cadence_hours=$(( cadence_secs / 3600 )) + if (( schedule_hour % cadence_hours != 0 )); then + continue + fi + fi fresh=$(GCS_OBJECT="$object" \ ./.github/workflows/scripts/scanner-updater-check-freshness.sh --max-age "$interval_secs") || { - echo "::error::${object}: freshness check failed" + echo "::error::${object}: freshness check failed" >&2 jq -n --arg msg "${object}: freshness check failed" '{error: $msg}' continue } diff --git a/.github/workflows/scripts/verify-release.sh b/.github/workflows/scripts/verify-release.sh index 6e9f0f0b2c200..528cf5c4660ad 100644 --- a/.github/workflows/scripts/verify-release.sh +++ b/.github/workflows/scripts/verify-release.sh @@ -102,7 +102,7 @@ validate_images() { validate_docs() { RELEASE="$1" - check_url_page_exists "https://docs.openshift.com/acs/${RELEASE}/welcome/index.html" + check_url_page_exists "https://docs.redhat.com/en/documentation/red_hat_advanced_cluster_security_for_kubernetes/${RELEASE}" } validate_jira_release() { diff --git a/.github/workflows/signing-key-bundle-update.yaml b/.github/workflows/signing-key-bundle-update.yaml index d456185299106..fda57fde6bd44 100644 --- a/.github/workflows/signing-key-bundle-update.yaml +++ b/.github/workflows/signing-key-bundle-update.yaml @@ -18,7 +18,7 @@ concurrency: jobs: validate-and-upload: if: ${{ github.repository_owner == 'stackrox' }} - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Checkout repository uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v7.0.0 @@ -48,7 +48,7 @@ jobs: send-notification: needs: - validate-and-upload - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 if: failure() permissions: contents: read diff --git a/.github/workflows/start-release.yml b/.github/workflows/start-release.yml index 34116d543db82..d23caf47e4a8b 100644 --- a/.github/workflows/start-release.yml +++ b/.github/workflows/start-release.yml @@ -42,7 +42,7 @@ concurrency: Release automation ${{ inputs.version }} jobs: start-sha: name: Find commit for release branch - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 outputs: start-sha: ${{ fromJSON(format('["{0}","{1}"]', env.USER_REF, steps.find.outputs.merge_base))[env.USER_REF == ''] }} steps: @@ -67,7 +67,7 @@ jobs: properties: name: Read repository properties - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 outputs: docs-repository: ${{ steps.properties.outputs.docs-repository }} slack-channel: ${{ fromJSON(format('["{0}","{1}"]', steps.properties.outputs.dry-slack-channel, steps.properties.outputs.slack-channel))[github.event.inputs.dry-run != 'true'] }} @@ -81,7 +81,7 @@ jobs: run-parameters: name: Run parameters - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - run: | [ "$DRY_RUN" = "true" ] && echo "::warning::This is a dry run" @@ -102,7 +102,7 @@ jobs: check-jira: name: Check Jira release needs: [variables, properties] - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 outputs: release-date: ${{steps.check-jira-release.outputs.date}} steps: @@ -122,7 +122,7 @@ jobs: branch: name: Prepare release branch needs: [variables, start-sha, check-jira] - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Check out code (normal release) if: needs.variables.outputs.patch == 0 @@ -193,7 +193,7 @@ jobs: name: Configure OpenShift CI jobs needs: [variables, branch] if: needs.variables.outputs.patch == 0 - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 env: RELEASE: "${{needs.variables.outputs.release}}" BRANCH: "stackrox-release-${{needs.variables.outputs.release}}" @@ -262,7 +262,7 @@ jobs: name: Patch CHANGELOG.md on the default branch needs: [variables, branch, start-sha] if: needs.variables.outputs.patch == 0 - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Check out code uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v7.0.0 @@ -288,7 +288,7 @@ jobs: patch-scanner-versions: name: Patch Scanner updater configuration needs: [variables, branch] - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Check out code uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v7.0.0 @@ -310,7 +310,7 @@ jobs: milestone: name: Create milestone needs: [variables] - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Create ${{needs.variables.outputs.next-milestone}} milestone if: env.DRY_RUN == 'false' @@ -336,7 +336,7 @@ jobs: notify: name: Notify everybody needs: [variables, properties, branch, milestone] - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Post to Slack (normal release) if: needs.variables.outputs.patch == 0 diff --git a/.github/workflows/style.yaml b/.github/workflows/style.yaml index 0cfe9f54c7978..3989115a09bab 100644 --- a/.github/workflows/style.yaml +++ b/.github/workflows/style.yaml @@ -27,7 +27,7 @@ jobs: if: ${{ !needs.detect-changes.outputs.ui_only }} env: ARTIFACT_DIR: junit-reports/ - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Checkout uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v7.0.0 @@ -54,7 +54,7 @@ jobs: misc-checks: env: ARTIFACT_DIR: junit-reports/ - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Checkout uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v7.0.0 @@ -97,7 +97,7 @@ jobs: run: if [ -s scripts/ci/jobs/check-dependabot-gomod.sh ]; then scripts/ci/jobs/check-dependabot-gomod.sh; fi style-check: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Checkout uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v7.0.0 @@ -159,7 +159,7 @@ jobs: needs: detect-changes if: ${{ !needs.detect-changes.outputs.ui_only }} timeout-minutes: 240 - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Checkout uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v7.0.0 @@ -208,7 +208,7 @@ jobs: # This job ensures that COLLECTOR_VERSION or FACT_VERSION files cannot be updated to a version # for which the image was not successfully built on Konflux (suffix "-fast"). It also verifies that GHA-built image # is there (no suffix) so that the failure also happens in this job. - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Checkout repo uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v7.0.0 @@ -253,7 +253,7 @@ jobs: if: >- !needs.detect-changes.outputs.files || contains(needs.detect-changes.outputs.files, '^.github/') - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v7.0.0 - uses: ./.github/actions/job-preamble @@ -267,7 +267,7 @@ jobs: if: >- !needs.detect-changes.outputs.files || contains(needs.detect-changes.outputs.files, '^.github/') - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v7.0.0 - uses: ./.github/actions/job-preamble @@ -281,7 +281,7 @@ jobs: if: >- !needs.detect-changes.outputs.files || contains(needs.detect-changes.outputs.files, '^.openshift-ci/') - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Checkout uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v7.0.0 @@ -313,7 +313,7 @@ jobs: contains(github.event.pull_request.labels.*.name, 'ci-test-github-action-slack-messages') ) name: Post failure message to Slack - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 needs: - check-generated-files - misc-checks diff --git a/.github/workflows/tag-more-reviewers.yaml b/.github/workflows/tag-more-reviewers.yaml index f6ce74aac7c50..4b94157c38a6d 100644 --- a/.github/workflows/tag-more-reviewers.yaml +++ b/.github/workflows/tag-more-reviewers.yaml @@ -18,7 +18,7 @@ jobs: github.event.pull_request.user.login != 'red-hat-konflux[bot]' env: GH_TOKEN: ${{ secrets.RHACS_BOT_GITHUB_TOKEN }} - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Tag Konflux Maintainers for review run: | diff --git a/.github/workflows/tagged-ci.yaml b/.github/workflows/tagged-ci.yaml index 028412d071aa8..e936f4f4ea0ca 100644 --- a/.github/workflows/tagged-ci.yaml +++ b/.github/workflows/tagged-ci.yaml @@ -8,7 +8,7 @@ on: jobs: slack-tagged-notice: name: Slack Tagged Notice - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Checkout uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v7.0.0 diff --git a/.github/workflows/triage-report_periodic.yml b/.github/workflows/triage-report_periodic.yml index 4843660c8ab0b..2df7169befde0 100644 --- a/.github/workflows/triage-report_periodic.yml +++ b/.github/workflows/triage-report_periodic.yml @@ -6,7 +6,7 @@ on: jobs: triage-report: if: ${{ github.repository_owner == 'stackrox' }} - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Checkout uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v7.0.0 diff --git a/.github/workflows/unit-tests.yaml b/.github/workflows/unit-tests.yaml index d5ca5b28812be..48ea27c9d0873 100644 --- a/.github/workflows/unit-tests.yaml +++ b/.github/workflows/unit-tests.yaml @@ -41,7 +41,7 @@ jobs: gotags: [ 'GOTAGS=""', 'GOTAGS=release' ] exclude: - gotags: ${{ github.event_name == 'pull_request' && !contains(github.event.pull_request.labels.*.name, 'ci-release-build') && 'GOTAGS=release' }} - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 outputs: new-jiras: ${{ steps.junit2jira.outputs.new-jiras }} steps: @@ -61,7 +61,7 @@ jobs: - name: Go Unit Tests run: ${{ matrix.gotags }} make go-unit-tests - - uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # ratchet:codecov/codecov-action@v7.0.0 + - uses: codecov/codecov-action@303a32d7a59b442fa8d48b6a1cc6825c09c847a5 # ratchet:codecov/codecov-action@v7.1.1 with: token: ${{ secrets.CODECOV_TOKEN }} flags: go-unit-tests @@ -112,11 +112,10 @@ jobs: fail-fast: false matrix: gotags: [ 'GOTAGS=""', 'GOTAGS=release' ] - pg: [ 'default', '15' ] + pg: [ '16' ] exclude: - gotags: ${{ github.event_name == 'pull_request' && !contains(github.event.pull_request.labels.*.name, 'ci-release-build') && 'GOTAGS=release' }} - - pg: ${{ github.event_name == 'pull_request' && !contains(github.event.pull_request.labels.*.name, 'ci-postgres-tests') && 'default' }} - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 outputs: new-jiras: ${{ steps.junit2jira.outputs.new-jiras }} env: @@ -173,7 +172,7 @@ jobs: - name: Go Unit Tests run: ${{ matrix.gotags }} make go-postgres-unit-tests - - uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # ratchet:codecov/codecov-action@v7.0.0 + - uses: codecov/codecov-action@303a32d7a59b442fa8d48b6a1cc6825c09c847a5 # ratchet:codecov/codecov-action@v7.1.1 with: token: ${{ secrets.CODECOV_TOKEN }} flags: go-unit-tests @@ -205,7 +204,7 @@ jobs: go-bench: needs: detect-changes if: ${{ !needs.detect-changes.outputs.ui_only }} - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Checkout uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v7.0.0 @@ -264,7 +263,7 @@ jobs: !needs.detect-changes.outputs.files || contains(needs.detect-changes.outputs.files, '^ui/') || contains(needs.detect-changes.outputs.files, '^.github/actions/cache-ui-dependencies/') - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 outputs: new-jiras: ${{ steps.junit2jira.outputs.new-jiras }} steps: @@ -318,7 +317,7 @@ jobs: !needs.detect-changes.outputs.files || contains(needs.detect-changes.outputs.files, '^ui/') || contains(needs.detect-changes.outputs.files, '^.github/actions/cache-ui-dependencies/') - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 outputs: new-jiras: ${{ steps.junit2jira.outputs.new-jiras }} steps: @@ -380,7 +379,7 @@ jobs: local-roxctl-tests: needs: detect-changes if: ${{ !needs.detect-changes.outputs.ui_only }} - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 outputs: new-jiras: ${{ steps.junit2jira.outputs.new-jiras }} container: @@ -426,7 +425,7 @@ jobs: shell-unit-tests: needs: detect-changes if: ${{ !needs.detect-changes.outputs.ui_only }} - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 outputs: new-jiras: ${{ steps.junit2jira.outputs.new-jiras }} container: @@ -464,7 +463,7 @@ jobs: openshift-ci-unit-tests: needs: detect-changes if: ${{ !needs.detect-changes.outputs.ui_only }} - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 container: image: quay.io/stackrox-io/apollo-ci:stackrox-test-0.5.11@sha256:df3459cf038e73775314b3a5d36d14dda41e6df438a0273c9efa8d23e0f2358a # ratchet:quay.io/stackrox-io/apollo-ci:stackrox-test-0.5.11 steps: @@ -486,7 +485,7 @@ jobs: if: ${{ !needs.detect-changes.outputs.ui_only }} env: KUBECONFIG: "/tmp/kubeconfig" - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 outputs: new-jiras: ${{ steps.junit2jira.outputs.new-jiras }} steps: @@ -508,7 +507,7 @@ jobs: password: ${{ secrets.QUAY_RHACS_ENG_RO_PASSWORD }} - name: Create k8s Kind Cluster - uses: helm/kind-action@ef37e7f390d99f746eb8b610417061a60e82a6cc # ratchet:helm/kind-action@v1 + uses: helm/kind-action@06c1ae10762d3b9c1644e7fe69596ae519e015a2 # ratchet:helm/kind-action@v1.15.0 with: kubeconfig: "${{ env.KUBECONFIG }}" @@ -565,7 +564,7 @@ jobs: contains(github.event.pull_request.labels.*.name, 'ci-test-github-action-slack-messages') ) name: Post failure message to Slack - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 needs: - go - go-bench diff --git a/.github/workflows/update_collector_periodic.yaml b/.github/workflows/update_collector_periodic.yaml index aca8fd0cf0f3e..6eec999095b3d 100644 --- a/.github/workflows/update_collector_periodic.yaml +++ b/.github/workflows/update_collector_periodic.yaml @@ -6,7 +6,7 @@ on: jobs: update-collector: if: ${{ github.repository_owner == 'stackrox' }} - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v7.0.0 with: diff --git a/.github/workflows/update_fact_periodic.yaml b/.github/workflows/update_fact_periodic.yaml index 12ec44dd22b65..1ba1644308290 100644 --- a/.github/workflows/update_fact_periodic.yaml +++ b/.github/workflows/update_fact_periodic.yaml @@ -6,7 +6,7 @@ on: jobs: update-fact: if: ${{ github.repository_owner == 'stackrox' }} - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v7.0.0 with: diff --git a/.github/workflows/upgrade-test.yml b/.github/workflows/upgrade-test.yml index 78ddcbeb0c98d..eb3e76ee88d2d 100644 --- a/.github/workflows/upgrade-test.yml +++ b/.github/workflows/upgrade-test.yml @@ -40,7 +40,7 @@ concurrency: Release automation ${{ inputs.milestone }} jobs: properties: name: Read repository properties - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 outputs: slack-channel: ${{ fromJSON(format('["{0}","{1}"]', steps.properties.outputs.dry-slack-channel, steps.properties.outputs.slack-channel))[inputs.dry-run != 'true'] }} steps: @@ -52,7 +52,7 @@ jobs: run-parameters: name: Run parameters - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - run: | [ "$DRY_RUN" = "true" ] && echo "::warning::This is a dry run" @@ -66,13 +66,13 @@ jobs: create-clusters: needs: [properties] if: github.event.inputs.dry-run != 'true' - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 strategy: matrix: name: [test1, test2] steps: - name: Create the ${{ matrix.name }} cluster - uses: stackrox/actions/infra/create-cluster@9238e423c3ae1ac4eb0f254cbb98da9daae24d86 # ratchet:stackrox/actions/infra/create-cluster@v1 + uses: stackrox/actions/infra/create-cluster@f3893761af7aff7477e3dde7a4d9656b173fc687 # ratchet:stackrox/actions/infra/create-cluster@v1 with: token: ${{ secrets.INFRA_TOKEN }} flavor: gke-default @@ -83,7 +83,7 @@ jobs: prepare-clusters: needs: [properties, create-clusters] - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Check out code uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v7.0.0 @@ -136,7 +136,7 @@ jobs: name: Notify about failed cluster creation needs: [properties, prepare-clusters] if: always() && needs.prepare-clusters.result == 'failure' - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Post to Slack uses: slackapi/slack-github-action@45a88b9581bfab2566dc881e2cd66d334e621e2c # ratchet:slackapi/slack-github-action@v3.0.3 diff --git a/.github/workflows/variables.yml b/.github/workflows/variables.yml index f574eec48faa4..6fedd4d7f5546 100644 --- a/.github/workflows/variables.yml +++ b/.github/workflows/variables.yml @@ -56,7 +56,7 @@ on: jobs: parse: name: Parse ${{inputs.version}} - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 outputs: release: ${{steps.parse.outputs.release}} major: ${{steps.parse.outputs.major}} diff --git a/.github/workflows/verify-release.yml b/.github/workflows/verify-release.yml index 5751a5121b968..3792e9c80958b 100644 --- a/.github/workflows/verify-release.yml +++ b/.github/workflows/verify-release.yml @@ -32,7 +32,7 @@ concurrency: Release automation ${{ inputs.version }} jobs: run-parameters: name: Run parameters - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - run: | { @@ -52,7 +52,7 @@ jobs: properties: name: Read repository properties - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 outputs: jira-project: ${{ steps.properties.outputs.jira-project }} steps: @@ -64,7 +64,7 @@ jobs: verify-release: name: Verify all artifacts for release ${{ needs.variables.outputs.named-release-patch }} are published - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 needs: [variables, properties] env: JIRA_USER: ${{ vars.RHACS_BOT_GITHUB_EMAIL }} diff --git a/.openshift-ci/ci_tests.py b/.openshift-ci/ci_tests.py index 0acc24bc895ab..b3d602f46e2ec 100755 --- a/.openshift-ci/ci_tests.py +++ b/.openshift-ci/ci_tests.py @@ -162,7 +162,7 @@ def run(self): class UIE2eTest(BaseTest): - TEST_TIMEOUT = 2 * 60 * 60 + TEST_TIMEOUT = 3 * 60 * 60 def run(self): print("Executing UI e2e test") @@ -192,7 +192,7 @@ def run(self): class NonGroovyE2e(BaseTest): - TEST_TIMEOUT = 120 * 60 + TEST_TIMEOUT = 3 * 60 * 60 TEST_OUTPUT_DIR = "/tmp/e2e-test-logs" def run(self): @@ -261,7 +261,7 @@ def run(self): class BYODBTest(BaseTest): - TEST_TIMEOUT = 60 * 60 * 2 + TEST_TIMEOUT = 60 * 60 * 3 TEST_OUTPUT_DIR = "/tmp/byodb-test-logs" def run(self): diff --git a/.openshift-ci/common.py b/.openshift-ci/common.py index 06cebaab6985b..fdf0d0bd212e5 100644 --- a/.openshift-ci/common.py +++ b/.openshift-ci/common.py @@ -39,6 +39,14 @@ def enable_sfa_for_ocp(): """ try: ocp_variant = os.environ.get("CLUSTER_FLAVOR_VARIANT", "") + + # A special case, OCP release candidate version. Most certainly newer + # than we require. + if ocp_variant == "openshift-4-ocp/candidate": + os.environ["SFA_AGENT"] = "true" + log_print("Enabled SFA agent for OCP", ocp_variant) + return + expr = r"openshift-4-ocp/\w+-(?P\d+)\.(?P\d+)" m = re.match(expr, ocp_variant) if m: diff --git a/.openshift-ci/post_tests.py b/.openshift-ci/post_tests.py index 10f8ed4947ace..64f27674b5204 100644 --- a/.openshift-ci/post_tests.py +++ b/.openshift-ci/post_tests.py @@ -34,6 +34,7 @@ class PostTestsConstants: DIAGNOSTIC_OUTPUT = "diagnostic-bundle" CENTRAL_DATA_OUTPUT = "central-data" STACKROX_LOG_DIR = "/tmp/stackrox-logs" + VM_GUEST_LOG_DIR = "/tmp/vm-diagnostics" class NullPostTest: @@ -151,12 +152,13 @@ def _store_osci_artifact(self, source): class PostClusterTest(StoreArtifacts): """The standard cluster test suite of debug gathering and analysis""" - # pylint: disable=too-many-arguments + # pylint: disable=too-many-arguments,too-many-positional-arguments def __init__( self, collect_collector_metrics=True, collect_central_artifacts=True, collect_service_logs=True, + collect_vm_guest_logs=False, check_stackrox_logs=False, artifact_destination_prefix=None, ): @@ -169,6 +171,7 @@ def __init__( self.service_logs_destination = self.K8S_LOG_DIR self._collect_collector_metrics = collect_collector_metrics self._collect_service_logs = collect_service_logs + self._collect_vm_guest_logs = collect_vm_guest_logs self._check_stackrox_logs = check_stackrox_logs self.k8s_namespaces = [ "stackrox", @@ -202,6 +205,8 @@ def run(self, test_outputs=None): self.grab_central_data() if self._collect_service_logs: self.collect_service_logs() + if self._collect_vm_guest_logs: + self.collect_vm_guest_logs() if self._check_stackrox_logs: self.check_stackrox_logs() self.store_artifacts(test_outputs) @@ -232,6 +237,23 @@ def collect_service_logs(self): ) self.data_to_store.append(self.service_logs_destination) + def collect_vm_guest_logs(self): + # Per-VM virtctl ssh is capped in the script. Cleanup is a second + # process because a collect timeout SIGKILLs the first before it can + # delete namespaces. + self.run_with_best_effort( + [ + "scripts/ci/collect-vm-guest-logs.sh", + self.VM_GUEST_LOG_DIR, + ], + timeout=10 * 60, + ) + self.data_to_store.append(self.VM_GUEST_LOG_DIR) + self.run_with_best_effort( + ["scripts/ci/delete-vm-ns.sh"], + timeout=60, + ) + def collect_collector_metrics(self): self.run_with_best_effort( [ diff --git a/.tekton/basic-component-pipeline.yaml b/.tekton/basic-component-pipeline.yaml index a53013f1bd5b9..642db21c6996b 100644 --- a/.tekton/basic-component-pipeline.yaml +++ b/.tekton/basic-component-pipeline.yaml @@ -35,7 +35,7 @@ spec: - name: name value: post-bigquery-metrics - name: bundle - value: quay.io/rhacs-eng/konflux-tasks:latest@sha256:8fd043b9dd843d627e82237ddafe544a31c05ba4bd9278a7b96f6f2e07e8635a + value: quay.io/rhacs-eng/konflux-tasks:latest@sha256:18defc6b58a3792ef4d1c7268ce22167c833e7846523b97e0f3219094df0d510 - name: kind value: task resolver: bundles @@ -168,7 +168,7 @@ spec: - name: name value: init - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-init:0.4.3@sha256:c6c414a3b5dcd827720f3443a128a02d27a0a5071ea3e4dc0063d578f1f73a74 + value: quay.io/konflux-ci/tekton-catalog/task-init:0.4.3@sha256:7854d7babe4136e53e337f6433d952532314433b48bb62b422ddc02700934d85 - name: kind value: task resolver: bundles @@ -192,7 +192,7 @@ spec: - name: name value: git-clone-oci-ta - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-git-clone-oci-ta:0.2.6@sha256:1d7ba568ae6e9e26800054f3942779de8abc80ddc48f0e44df6b1c2f098161dc + value: quay.io/konflux-ci/tekton-catalog/task-git-clone-oci-ta:0.2.6@sha256:a3678910c2bf9187a66a96066193cb41046fbb7097160bf2be6a374ed5e49d30 - name: kind value: task resolver: bundles @@ -211,7 +211,7 @@ spec: - name: name value: determine-image-expiration - name: bundle - value: quay.io/rhacs-eng/konflux-tasks:latest@sha256:8fd043b9dd843d627e82237ddafe544a31c05ba4bd9278a7b96f6f2e07e8635a + value: quay.io/rhacs-eng/konflux-tasks:latest@sha256:18defc6b58a3792ef4d1c7268ce22167c833e7846523b97e0f3219094df0d510 - name: kind value: task resolver: bundles @@ -227,7 +227,7 @@ spec: - name: name value: determine-image-tag - name: bundle - value: quay.io/rhacs-eng/konflux-tasks:latest@sha256:8fd043b9dd843d627e82237ddafe544a31c05ba4bd9278a7b96f6f2e07e8635a + value: quay.io/rhacs-eng/konflux-tasks:latest@sha256:18defc6b58a3792ef4d1c7268ce22167c833e7846523b97e0f3219094df0d510 - name: kind value: task resolver: bundles @@ -251,7 +251,7 @@ spec: - name: name value: prefetch-dependencies-oci-ta - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-prefetch-dependencies-oci-ta:0.10.3@sha256:9fd7d251f92250d89a5465756e278e053af28c6356e5ccdedc4be87bbb13c190 + value: quay.io/konflux-ci/tekton-catalog/task-prefetch-dependencies-oci-ta:0.10.3@sha256:0c386f2c26b46b978280c5c54caac26bcd524975f8f7cc06bb080ba00eae3ad4 - name: kind value: task resolver: bundles @@ -310,7 +310,7 @@ spec: - name: name value: buildah-remote-oci-ta - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-buildah-remote-oci-ta:0.12.1@sha256:9afb0e30b1b5b49a5a934a09ce3b55baf892da99a784387ff72ec92bd2c374c2 + value: quay.io/konflux-ci/tekton-catalog/task-buildah-remote-oci-ta:0.12.2@sha256:a68dce8ed79be8d9e10d98bd2b56895c27fc34f1ed7d67cbc9ec0a91d64cf641 - name: kind value: task resolver: bundles @@ -329,7 +329,7 @@ spec: - name: name value: build-image-index - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-build-image-index:0.3.1@sha256:6ead03ca82a1b970dc60eaadae86adf374e8e70f8d951902e1fac7411dbe0550 + value: quay.io/konflux-ci/tekton-catalog/task-build-image-index:0.4@sha256:654446d8ec028b20ed6ada8a96486ff16692a25192755aa04a99cea8e0afb7e2 - name: kind value: task resolver: bundles @@ -350,7 +350,7 @@ spec: - name: name value: source-build-oci-ta - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-source-build-oci-ta:0.3.1@sha256:bbad5bfd67d1263320a0c4d3f062a18ae611e081b009fd96117c2a00a6ce8dd9 + value: quay.io/konflux-ci/tekton-catalog/task-source-build-oci-ta:0.3.2@sha256:45091b5022754d452b4de60c7d7f4c6e03626efff55f96e9af937400fe3506eb - name: kind value: task resolver: bundles @@ -459,7 +459,7 @@ spec: - name: name value: sast-shell-check-oci-ta - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-sast-shell-check-oci-ta:0.1@sha256:d9b01530ce3c20287714e64980f154e28c0e94d17e2dbfbaf3c8bf77b1844b9e + value: quay.io/konflux-ci/tekton-catalog/task-sast-shell-check-oci-ta:0.1@sha256:d00c884c78489a52dc638e6ced0a01429670d0754f5b1305ad576709cf660312 - name: kind value: task resolver: bundles @@ -485,7 +485,7 @@ spec: - name: name value: sast-unicode-check-oci-ta - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-sast-unicode-check-oci-ta:0.4@sha256:381750451fbcc86d90fa83579a48e0e6555d7cf374fe2c4af3f9262a17fc3c89 + value: quay.io/konflux-ci/tekton-catalog/task-sast-unicode-check-oci-ta:0.4@sha256:15d654c9576b9c4ee1f78b09fce541acf9afe33f1c2363fd6219a79dbf62c95d - name: kind value: task resolver: bundles @@ -511,7 +511,7 @@ spec: - name: name value: sast-snyk-check-oci-ta - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-sast-snyk-check-oci-ta:0.5@sha256:a973b32f0e11958aba08a635981e4d4e7eb200c417492371a1e692ff589b4e8f + value: quay.io/konflux-ci/tekton-catalog/task-sast-snyk-check-oci-ta:0.5@sha256:17b9587eba53fabaab35061275306bfe1f99661d55e14e22f62321fa7cb5ff3e - name: kind value: task resolver: bundles @@ -556,7 +556,7 @@ spec: - name: name value: rpms-signature-scan - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-rpms-signature-scan:0.2.2@sha256:64bb1cf7d875157e68043a411f00e7852afffc68f50881fb041ba994109f4763 + value: quay.io/konflux-ci/tekton-catalog/task-rpms-signature-scan:0.2.2@sha256:d9df5d325f81a9fa132cb597c465aa9210b9b0fa3716b85b32be98d92c9c881a - name: kind value: task resolver: bundles @@ -582,7 +582,7 @@ spec: - name: name value: push-dockerfile-oci-ta - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-push-dockerfile-oci-ta:0.3.1@sha256:3e59d6303ca031c27fab079f7c743fbdecc53d007b8d86e32227de5164f06e31 + value: quay.io/konflux-ci/tekton-catalog/task-push-dockerfile-oci-ta:0.3.1@sha256:4c567d11296850230fe32e76d129834d3bf337a0cae9989b64279b7cfaa4e735 - name: kind value: task resolver: bundles diff --git a/.tekton/checks.yaml b/.tekton/checks.yaml index 73b1685975265..5e7ce9e0f1912 100644 --- a/.tekton/checks.yaml +++ b/.tekton/checks.yaml @@ -66,7 +66,7 @@ spec: - name: name value: post-bigquery-metrics - name: bundle - value: quay.io/rhacs-eng/konflux-tasks:latest@sha256:8fd043b9dd843d627e82237ddafe544a31c05ba4bd9278a7b96f6f2e07e8635a + value: quay.io/rhacs-eng/konflux-tasks:latest@sha256:18defc6b58a3792ef4d1c7268ce22167c833e7846523b97e0f3219094df0d510 - name: kind value: task resolver: bundles @@ -117,7 +117,7 @@ spec: - name: name value: git-clone-oci-ta - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-git-clone-oci-ta:0.2.6@sha256:1d7ba568ae6e9e26800054f3942779de8abc80ddc48f0e44df6b1c2f098161dc + value: quay.io/konflux-ci/tekton-catalog/task-git-clone-oci-ta:0.2.6@sha256:a3678910c2bf9187a66a96066193cb41046fbb7097160bf2be6a374ed5e49d30 - name: kind value: task resolver: bundles @@ -146,7 +146,7 @@ spec: - name: name value: buildah-oci-ta - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-buildah-oci-ta:0.12.1@sha256:dd0c817c0e3ded8ff52b6c227681ea542e17211bf85de38101b9b11029d16bac + value: quay.io/konflux-ci/tekton-catalog/task-buildah-oci-ta:0.12.2@sha256:e1bbe61a3a4bc543be9b5f6fc4174acaa2dd08fb5f7fe4d9db9f3193a7e1b03c - name: kind value: task resolver: bundles diff --git a/.tekton/create-custom-snapshot.yaml b/.tekton/create-custom-snapshot.yaml index 3c5d495406e3d..b96b14d7b28b3 100644 --- a/.tekton/create-custom-snapshot.yaml +++ b/.tekton/create-custom-snapshot.yaml @@ -75,7 +75,7 @@ spec: - name: name value: post-bigquery-metrics - name: bundle - value: quay.io/rhacs-eng/konflux-tasks:latest@sha256:8fd043b9dd843d627e82237ddafe544a31c05ba4bd9278a7b96f6f2e07e8635a + value: quay.io/rhacs-eng/konflux-tasks:latest@sha256:18defc6b58a3792ef4d1c7268ce22167c833e7846523b97e0f3219094df0d510 - name: kind value: task resolver: bundles @@ -132,7 +132,7 @@ spec: - name: SHOULD_REALLY_WORK steps: - name: determine - image: registry.redhat.io/ubi9-minimal:latest@sha256:7fbeae18dc9476399f565e68255f602a3374ea8614ba3d14843565131a13ff93 + image: registry.redhat.io/ubi9-minimal:latest@sha256:c4c285d42941ebb2bd4da878479008e1e4536bb599aad1dbe568f89de9053661 imagePullPolicy: IfNotPresent # The script expresses the same condition as pipelinesascode.tekton.dev/on-cel-expression in other pipelines # but in a more verbose way because, as it turns out, both syntax and fields of CEL expressions are slightly @@ -201,7 +201,7 @@ spec: - name: name value: git-clone-oci-ta - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-git-clone-oci-ta:0.2.6@sha256:1d7ba568ae6e9e26800054f3942779de8abc80ddc48f0e44df6b1c2f098161dc + value: quay.io/konflux-ci/tekton-catalog/task-git-clone-oci-ta:0.2.6@sha256:a3678910c2bf9187a66a96066193cb41046fbb7097160bf2be6a374ed5e49d30 - name: kind value: task resolver: bundles @@ -224,7 +224,7 @@ spec: - name: name value: determine-image-tag - name: bundle - value: quay.io/rhacs-eng/konflux-tasks:latest@sha256:8fd043b9dd843d627e82237ddafe544a31c05ba4bd9278a7b96f6f2e07e8635a + value: quay.io/rhacs-eng/konflux-tasks:latest@sha256:18defc6b58a3792ef4d1c7268ce22167c833e7846523b97e0f3219094df0d510 - name: kind value: task resolver: bundles @@ -242,7 +242,7 @@ spec: - name: name value: wait-for-image - name: bundle - value: quay.io/rhacs-eng/konflux-tasks:latest@sha256:8fd043b9dd843d627e82237ddafe544a31c05ba4bd9278a7b96f6f2e07e8635a + value: quay.io/rhacs-eng/konflux-tasks:latest@sha256:18defc6b58a3792ef4d1c7268ce22167c833e7846523b97e0f3219094df0d510 - name: kind value: task resolver: bundles @@ -315,7 +315,7 @@ spec: - name: name value: create-snapshot-from-bundle - name: bundle - value: quay.io/rhacs-eng/konflux-tasks:latest@sha256:8fd043b9dd843d627e82237ddafe544a31c05ba4bd9278a7b96f6f2e07e8635a + value: quay.io/rhacs-eng/konflux-tasks:latest@sha256:18defc6b58a3792ef4d1c7268ce22167c833e7846523b97e0f3219094df0d510 - name: kind value: task resolver: bundles diff --git a/.tekton/main-pipeline.yaml b/.tekton/main-pipeline.yaml index f9f15e8fd095e..fb022d858b32c 100644 --- a/.tekton/main-pipeline.yaml +++ b/.tekton/main-pipeline.yaml @@ -35,7 +35,7 @@ spec: - name: name value: post-bigquery-metrics - name: bundle - value: quay.io/rhacs-eng/konflux-tasks:latest@sha256:8fd043b9dd843d627e82237ddafe544a31c05ba4bd9278a7b96f6f2e07e8635a + value: quay.io/rhacs-eng/konflux-tasks:latest@sha256:18defc6b58a3792ef4d1c7268ce22167c833e7846523b97e0f3219094df0d510 - name: kind value: task resolver: bundles @@ -169,7 +169,7 @@ spec: - name: name value: init - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-init:0.4.3@sha256:c6c414a3b5dcd827720f3443a128a02d27a0a5071ea3e4dc0063d578f1f73a74 + value: quay.io/konflux-ci/tekton-catalog/task-init:0.4.3@sha256:7854d7babe4136e53e337f6433d952532314433b48bb62b422ddc02700934d85 - name: kind value: task resolver: bundles @@ -193,7 +193,7 @@ spec: - name: name value: git-clone-oci-ta - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-git-clone-oci-ta:0.2.6@sha256:1d7ba568ae6e9e26800054f3942779de8abc80ddc48f0e44df6b1c2f098161dc + value: quay.io/konflux-ci/tekton-catalog/task-git-clone-oci-ta:0.2.6@sha256:a3678910c2bf9187a66a96066193cb41046fbb7097160bf2be6a374ed5e49d30 - name: kind value: task resolver: bundles @@ -212,7 +212,7 @@ spec: - name: name value: determine-image-expiration - name: bundle - value: quay.io/rhacs-eng/konflux-tasks:latest@sha256:8fd043b9dd843d627e82237ddafe544a31c05ba4bd9278a7b96f6f2e07e8635a + value: quay.io/rhacs-eng/konflux-tasks:latest@sha256:18defc6b58a3792ef4d1c7268ce22167c833e7846523b97e0f3219094df0d510 - name: kind value: task resolver: bundles @@ -228,7 +228,7 @@ spec: - name: name value: determine-image-tag - name: bundle - value: quay.io/rhacs-eng/konflux-tasks:latest@sha256:8fd043b9dd843d627e82237ddafe544a31c05ba4bd9278a7b96f6f2e07e8635a + value: quay.io/rhacs-eng/konflux-tasks:latest@sha256:18defc6b58a3792ef4d1c7268ce22167c833e7846523b97e0f3219094df0d510 - name: kind value: task resolver: bundles @@ -248,7 +248,7 @@ spec: - name: name value: fetch-external-networks - name: bundle - value: quay.io/rhacs-eng/konflux-tasks:latest@sha256:8fd043b9dd843d627e82237ddafe544a31c05ba4bd9278a7b96f6f2e07e8635a + value: quay.io/rhacs-eng/konflux-tasks:latest@sha256:18defc6b58a3792ef4d1c7268ce22167c833e7846523b97e0f3219094df0d510 - name: kind value: task resolver: bundles @@ -272,7 +272,7 @@ spec: - name: name value: prefetch-dependencies-oci-ta - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-prefetch-dependencies-oci-ta:0.10.3@sha256:9fd7d251f92250d89a5465756e278e053af28c6356e5ccdedc4be87bbb13c190 + value: quay.io/konflux-ci/tekton-catalog/task-prefetch-dependencies-oci-ta:0.10.3@sha256:0c386f2c26b46b978280c5c54caac26bcd524975f8f7cc06bb080ba00eae3ad4 - name: kind value: task resolver: bundles @@ -331,7 +331,7 @@ spec: - name: name value: buildah-remote-oci-ta - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-buildah-remote-oci-ta:0.12.1@sha256:9afb0e30b1b5b49a5a934a09ce3b55baf892da99a784387ff72ec92bd2c374c2 + value: quay.io/konflux-ci/tekton-catalog/task-buildah-remote-oci-ta:0.12.2@sha256:a68dce8ed79be8d9e10d98bd2b56895c27fc34f1ed7d67cbc9ec0a91d64cf641 - name: kind value: task resolver: bundles @@ -351,7 +351,7 @@ spec: - name: name value: build-image-index - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-build-image-index:0.3.1@sha256:6ead03ca82a1b970dc60eaadae86adf374e8e70f8d951902e1fac7411dbe0550 + value: quay.io/konflux-ci/tekton-catalog/task-build-image-index:0.4@sha256:654446d8ec028b20ed6ada8a96486ff16692a25192755aa04a99cea8e0afb7e2 - name: kind value: task resolver: bundles @@ -372,7 +372,7 @@ spec: - name: name value: source-build-oci-ta - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-source-build-oci-ta:0.3.1@sha256:bbad5bfd67d1263320a0c4d3f062a18ae611e081b009fd96117c2a00a6ce8dd9 + value: quay.io/konflux-ci/tekton-catalog/task-source-build-oci-ta:0.3.2@sha256:45091b5022754d452b4de60c7d7f4c6e03626efff55f96e9af937400fe3506eb - name: kind value: task resolver: bundles @@ -481,7 +481,7 @@ spec: - name: name value: sast-shell-check-oci-ta - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-sast-shell-check-oci-ta:0.1@sha256:d9b01530ce3c20287714e64980f154e28c0e94d17e2dbfbaf3c8bf77b1844b9e + value: quay.io/konflux-ci/tekton-catalog/task-sast-shell-check-oci-ta:0.1@sha256:d00c884c78489a52dc638e6ced0a01429670d0754f5b1305ad576709cf660312 - name: kind value: task resolver: bundles @@ -507,7 +507,7 @@ spec: - name: name value: sast-unicode-check-oci-ta - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-sast-unicode-check-oci-ta:0.4@sha256:381750451fbcc86d90fa83579a48e0e6555d7cf374fe2c4af3f9262a17fc3c89 + value: quay.io/konflux-ci/tekton-catalog/task-sast-unicode-check-oci-ta:0.4@sha256:15d654c9576b9c4ee1f78b09fce541acf9afe33f1c2363fd6219a79dbf62c95d - name: kind value: task resolver: bundles @@ -533,7 +533,7 @@ spec: - name: name value: sast-snyk-check-oci-ta - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-sast-snyk-check-oci-ta:0.5@sha256:a973b32f0e11958aba08a635981e4d4e7eb200c417492371a1e692ff589b4e8f + value: quay.io/konflux-ci/tekton-catalog/task-sast-snyk-check-oci-ta:0.5@sha256:17b9587eba53fabaab35061275306bfe1f99661d55e14e22f62321fa7cb5ff3e - name: kind value: task resolver: bundles @@ -578,7 +578,7 @@ spec: - name: name value: rpms-signature-scan - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-rpms-signature-scan:0.2.2@sha256:64bb1cf7d875157e68043a411f00e7852afffc68f50881fb041ba994109f4763 + value: quay.io/konflux-ci/tekton-catalog/task-rpms-signature-scan:0.2.2@sha256:d9df5d325f81a9fa132cb597c465aa9210b9b0fa3716b85b32be98d92c9c881a - name: kind value: task resolver: bundles @@ -604,7 +604,7 @@ spec: - name: name value: push-dockerfile-oci-ta - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-push-dockerfile-oci-ta:0.3.1@sha256:3e59d6303ca031c27fab079f7c743fbdecc53d007b8d86e32227de5164f06e31 + value: quay.io/konflux-ci/tekton-catalog/task-push-dockerfile-oci-ta:0.3.1@sha256:4c567d11296850230fe32e76d129834d3bf337a0cae9989b64279b7cfaa4e735 - name: kind value: task resolver: bundles diff --git a/.tekton/operator-bundle-pipeline.yaml b/.tekton/operator-bundle-pipeline.yaml index 33c9e19716946..f7da2ba4be86b 100644 --- a/.tekton/operator-bundle-pipeline.yaml +++ b/.tekton/operator-bundle-pipeline.yaml @@ -35,7 +35,7 @@ spec: - name: name value: post-bigquery-metrics - name: bundle - value: quay.io/rhacs-eng/konflux-tasks:latest@sha256:8fd043b9dd843d627e82237ddafe544a31c05ba4bd9278a7b96f6f2e07e8635a + value: quay.io/rhacs-eng/konflux-tasks:latest@sha256:18defc6b58a3792ef4d1c7268ce22167c833e7846523b97e0f3219094df0d510 - name: kind value: task resolver: bundles @@ -229,7 +229,7 @@ spec: - name: name value: init - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-init:0.4.3@sha256:c6c414a3b5dcd827720f3443a128a02d27a0a5071ea3e4dc0063d578f1f73a74 + value: quay.io/konflux-ci/tekton-catalog/task-init:0.4.3@sha256:7854d7babe4136e53e337f6433d952532314433b48bb62b422ddc02700934d85 - name: kind value: task resolver: bundles @@ -253,7 +253,7 @@ spec: - name: name value: git-clone-oci-ta - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-git-clone-oci-ta:0.2.6@sha256:1d7ba568ae6e9e26800054f3942779de8abc80ddc48f0e44df6b1c2f098161dc + value: quay.io/konflux-ci/tekton-catalog/task-git-clone-oci-ta:0.2.6@sha256:a3678910c2bf9187a66a96066193cb41046fbb7097160bf2be6a374ed5e49d30 - name: kind value: task resolver: bundles @@ -272,7 +272,7 @@ spec: - name: name value: determine-image-expiration - name: bundle - value: quay.io/rhacs-eng/konflux-tasks:latest@sha256:8fd043b9dd843d627e82237ddafe544a31c05ba4bd9278a7b96f6f2e07e8635a + value: quay.io/rhacs-eng/konflux-tasks:latest@sha256:18defc6b58a3792ef4d1c7268ce22167c833e7846523b97e0f3219094df0d510 - name: kind value: task resolver: bundles @@ -288,7 +288,7 @@ spec: - name: name value: determine-image-tag - name: bundle - value: quay.io/rhacs-eng/konflux-tasks:latest@sha256:8fd043b9dd843d627e82237ddafe544a31c05ba4bd9278a7b96f6f2e07e8635a + value: quay.io/rhacs-eng/konflux-tasks:latest@sha256:18defc6b58a3792ef4d1c7268ce22167c833e7846523b97e0f3219094df0d510 - name: kind value: task resolver: bundles @@ -312,7 +312,7 @@ spec: - name: name value: prefetch-dependencies-oci-ta - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-prefetch-dependencies-oci-ta:0.10.3@sha256:9fd7d251f92250d89a5465756e278e053af28c6356e5ccdedc4be87bbb13c190 + value: quay.io/konflux-ci/tekton-catalog/task-prefetch-dependencies-oci-ta:0.10.3@sha256:0c386f2c26b46b978280c5c54caac26bcd524975f8f7cc06bb080ba00eae3ad4 - name: kind value: task resolver: bundles @@ -329,7 +329,7 @@ spec: - name: name value: wait-for-image - name: bundle - value: quay.io/rhacs-eng/konflux-tasks:latest@sha256:8fd043b9dd843d627e82237ddafe544a31c05ba4bd9278a7b96f6f2e07e8635a + value: quay.io/rhacs-eng/konflux-tasks:latest@sha256:18defc6b58a3792ef4d1c7268ce22167c833e7846523b97e0f3219094df0d510 - name: kind value: task resolver: bundles @@ -445,7 +445,7 @@ spec: - name: name value: buildah-oci-ta - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-buildah-oci-ta:0.12.1@sha256:dd0c817c0e3ded8ff52b6c227681ea542e17211bf85de38101b9b11029d16bac + value: quay.io/konflux-ci/tekton-catalog/task-buildah-oci-ta:0.12.2@sha256:e1bbe61a3a4bc543be9b5f6fc4174acaa2dd08fb5f7fe4d9db9f3193a7e1b03c - name: kind value: task resolver: bundles @@ -464,7 +464,7 @@ spec: - name: name value: apply-tags - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-apply-tags:0.3.1@sha256:b1c71d83be8e6d0e44f9b6e58e1ad491396d4c287be9291802c9be69d9441f2f + value: quay.io/konflux-ci/tekton-catalog/task-apply-tags:0.3.1@sha256:c177fc2b2482b1299e713c51bf258eba4972c016ef260d9f45335c2550dc7b2b - name: kind value: task resolver: bundles @@ -484,7 +484,7 @@ spec: - name: name value: source-build-oci-ta - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-source-build-oci-ta:0.3.1@sha256:bbad5bfd67d1263320a0c4d3f062a18ae611e081b009fd96117c2a00a6ce8dd9 + value: quay.io/konflux-ci/tekton-catalog/task-source-build-oci-ta:0.3.2@sha256:45091b5022754d452b4de60c7d7f4c6e03626efff55f96e9af937400fe3506eb - name: kind value: task resolver: bundles @@ -592,7 +592,7 @@ spec: - name: name value: sast-shell-check-oci-ta - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-sast-shell-check-oci-ta:0.1@sha256:d9b01530ce3c20287714e64980f154e28c0e94d17e2dbfbaf3c8bf77b1844b9e + value: quay.io/konflux-ci/tekton-catalog/task-sast-shell-check-oci-ta:0.1@sha256:d00c884c78489a52dc638e6ced0a01429670d0754f5b1305ad576709cf660312 - name: kind value: task resolver: bundles @@ -618,7 +618,7 @@ spec: - name: name value: sast-unicode-check-oci-ta - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-sast-unicode-check-oci-ta:0.4@sha256:381750451fbcc86d90fa83579a48e0e6555d7cf374fe2c4af3f9262a17fc3c89 + value: quay.io/konflux-ci/tekton-catalog/task-sast-unicode-check-oci-ta:0.4@sha256:15d654c9576b9c4ee1f78b09fce541acf9afe33f1c2363fd6219a79dbf62c95d - name: kind value: task resolver: bundles @@ -644,7 +644,7 @@ spec: - name: name value: sast-snyk-check-oci-ta - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-sast-snyk-check-oci-ta:0.5@sha256:a973b32f0e11958aba08a635981e4d4e7eb200c417492371a1e692ff589b4e8f + value: quay.io/konflux-ci/tekton-catalog/task-sast-snyk-check-oci-ta:0.5@sha256:17b9587eba53fabaab35061275306bfe1f99661d55e14e22f62321fa7cb5ff3e - name: kind value: task resolver: bundles @@ -684,7 +684,7 @@ spec: - name: name value: rpms-signature-scan - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-rpms-signature-scan:0.2.2@sha256:64bb1cf7d875157e68043a411f00e7852afffc68f50881fb041ba994109f4763 + value: quay.io/konflux-ci/tekton-catalog/task-rpms-signature-scan:0.2.2@sha256:d9df5d325f81a9fa132cb597c465aa9210b9b0fa3716b85b32be98d92c9c881a - name: kind value: task resolver: bundles @@ -710,7 +710,7 @@ spec: - name: name value: push-dockerfile-oci-ta - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-push-dockerfile-oci-ta:0.3.1@sha256:3e59d6303ca031c27fab079f7c743fbdecc53d007b8d86e32227de5164f06e31 + value: quay.io/konflux-ci/tekton-catalog/task-push-dockerfile-oci-ta:0.3.1@sha256:4c567d11296850230fe32e76d129834d3bf337a0cae9989b64279b7cfaa4e735 - name: kind value: task resolver: bundles diff --git a/.tekton/operator-index-build.yaml b/.tekton/operator-index-build.yaml index 9bffaa9136075..3d4a96d8d9a0b 100644 --- a/.tekton/operator-index-build.yaml +++ b/.tekton/operator-index-build.yaml @@ -98,7 +98,7 @@ spec: - name: name value: post-bigquery-metrics - name: bundle - value: quay.io/rhacs-eng/konflux-tasks:latest@sha256:8fd043b9dd843d627e82237ddafe544a31c05ba4bd9278a7b96f6f2e07e8635a + value: quay.io/rhacs-eng/konflux-tasks:latest@sha256:18defc6b58a3792ef4d1c7268ce22167c833e7846523b97e0f3219094df0d510 - name: kind value: task resolver: bundles @@ -195,7 +195,7 @@ spec: - name: name value: git-clone-oci-ta - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-git-clone-oci-ta:0.2.6@sha256:1d7ba568ae6e9e26800054f3942779de8abc80ddc48f0e44df6b1c2f098161dc + value: quay.io/konflux-ci/tekton-catalog/task-git-clone-oci-ta:0.2.6@sha256:a3678910c2bf9187a66a96066193cb41046fbb7097160bf2be6a374ed5e49d30 - name: kind value: task resolver: bundles @@ -214,7 +214,7 @@ spec: - name: name value: determine-image-expiration - name: bundle - value: quay.io/rhacs-eng/konflux-tasks:latest@sha256:8fd043b9dd843d627e82237ddafe544a31c05ba4bd9278a7b96f6f2e07e8635a + value: quay.io/rhacs-eng/konflux-tasks:latest@sha256:18defc6b58a3792ef4d1c7268ce22167c833e7846523b97e0f3219094df0d510 - name: kind value: task resolver: bundles @@ -230,7 +230,7 @@ spec: - name: name value: determine-image-tag - name: bundle - value: quay.io/rhacs-eng/konflux-tasks:latest@sha256:8fd043b9dd843d627e82237ddafe544a31c05ba4bd9278a7b96f6f2e07e8635a + value: quay.io/rhacs-eng/konflux-tasks:latest@sha256:18defc6b58a3792ef4d1c7268ce22167c833e7846523b97e0f3219094df0d510 - name: kind value: task resolver: bundles @@ -249,7 +249,7 @@ spec: description: Full operator-index image tag with v prefix and -fast suffix to avoid collision with GHA builds steps: - name: compute-index-tag - image: registry.access.redhat.com/ubi9-minimal:latest@sha256:7fbeae18dc9476399f565e68255f602a3374ea8614ba3d14843565131a13ff93 + image: registry.access.redhat.com/ubi9-minimal:latest@sha256:c4c285d42941ebb2bd4da878479008e1e4536bb599aad1dbe568f89de9053661 imagePullPolicy: IfNotPresent script: | #!/bin/bash @@ -276,7 +276,7 @@ spec: - name: name value: wait-for-image - name: bundle - value: quay.io/rhacs-eng/konflux-tasks:latest@sha256:8fd043b9dd843d627e82237ddafe544a31c05ba4bd9278a7b96f6f2e07e8635a + value: quay.io/rhacs-eng/konflux-tasks:latest@sha256:18defc6b58a3792ef4d1c7268ce22167c833e7846523b97e0f3219094df0d510 - name: kind value: task resolver: bundles @@ -334,7 +334,7 @@ spec: - use - $(params.SOURCE_ARTIFACT)=/var/workdir/source - name: build-index-content - image: registry.access.redhat.com/ubi9/go-toolset:9.8-1788409979@sha256:5e68f09a652ac6627a83c57655e42e24575efb278b54336039c9308607fc6b21 + image: registry.access.redhat.com/ubi9/go-toolset:9.8-1792010711@sha256:60fd6fb2998c40ad0d6561c34e83588b986a0cf7771f64e5e5c295ba87101f9b imagePullPolicy: IfNotPresent workingDir: /var/workdir/source/operator securityContext: @@ -414,7 +414,7 @@ spec: - name: name value: buildah-remote-oci-ta - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-buildah-remote-oci-ta:0.12.1@sha256:9afb0e30b1b5b49a5a934a09ce3b55baf892da99a784387ff72ec92bd2c374c2 + value: quay.io/konflux-ci/tekton-catalog/task-buildah-remote-oci-ta:0.12.2@sha256:a68dce8ed79be8d9e10d98bd2b56895c27fc34f1ed7d67cbc9ec0a91d64cf641 - name: kind value: task resolver: bundles @@ -433,7 +433,7 @@ spec: - name: name value: build-image-index - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-build-image-index:0.3.1@sha256:6ead03ca82a1b970dc60eaadae86adf374e8e70f8d951902e1fac7411dbe0550 + value: quay.io/konflux-ci/tekton-catalog/task-build-image-index:0.4@sha256:654446d8ec028b20ed6ada8a96486ff16692a25192755aa04a99cea8e0afb7e2 - name: kind value: task resolver: bundles diff --git a/.tekton/retag-pipeline.yaml b/.tekton/retag-pipeline.yaml index f58c8a7e7df52..023b634a93706 100644 --- a/.tekton/retag-pipeline.yaml +++ b/.tekton/retag-pipeline.yaml @@ -35,7 +35,7 @@ spec: - name: name value: post-bigquery-metrics - name: bundle - value: quay.io/rhacs-eng/konflux-tasks:latest@sha256:8fd043b9dd843d627e82237ddafe544a31c05ba4bd9278a7b96f6f2e07e8635a + value: quay.io/rhacs-eng/konflux-tasks:latest@sha256:18defc6b58a3792ef4d1c7268ce22167c833e7846523b97e0f3219094df0d510 - name: kind value: task resolver: bundles @@ -117,7 +117,7 @@ spec: - name: name value: git-clone-oci-ta - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-git-clone-oci-ta:0.2.6@sha256:1d7ba568ae6e9e26800054f3942779de8abc80ddc48f0e44df6b1c2f098161dc + value: quay.io/konflux-ci/tekton-catalog/task-git-clone-oci-ta:0.2.6@sha256:a3678910c2bf9187a66a96066193cb41046fbb7097160bf2be6a374ed5e49d30 - name: kind value: task resolver: bundles @@ -136,7 +136,7 @@ spec: - name: name value: determine-image-tag - name: bundle - value: quay.io/rhacs-eng/konflux-tasks:latest@sha256:8fd043b9dd843d627e82237ddafe544a31c05ba4bd9278a7b96f6f2e07e8635a + value: quay.io/rhacs-eng/konflux-tasks:latest@sha256:18defc6b58a3792ef4d1c7268ce22167c833e7846523b97e0f3219094df0d510 - name: kind value: task resolver: bundles @@ -154,7 +154,7 @@ spec: - name: name value: determine-dependency-image-tag - name: bundle - value: quay.io/rhacs-eng/konflux-tasks:latest@sha256:8fd043b9dd843d627e82237ddafe544a31c05ba4bd9278a7b96f6f2e07e8635a + value: quay.io/rhacs-eng/konflux-tasks:latest@sha256:18defc6b58a3792ef4d1c7268ce22167c833e7846523b97e0f3219094df0d510 - name: kind value: task resolver: bundles @@ -170,7 +170,7 @@ spec: - name: name value: wait-for-image - name: bundle - value: quay.io/rhacs-eng/konflux-tasks:latest@sha256:8fd043b9dd843d627e82237ddafe544a31c05ba4bd9278a7b96f6f2e07e8635a + value: quay.io/rhacs-eng/konflux-tasks:latest@sha256:18defc6b58a3792ef4d1c7268ce22167c833e7846523b97e0f3219094df0d510 - name: kind value: task resolver: bundles @@ -195,7 +195,7 @@ spec: - name: name value: retag-image - name: bundle - value: quay.io/rhacs-eng/konflux-tasks:latest@sha256:8fd043b9dd843d627e82237ddafe544a31c05ba4bd9278a7b96f6f2e07e8635a + value: quay.io/rhacs-eng/konflux-tasks:latest@sha256:18defc6b58a3792ef4d1c7268ce22167c833e7846523b97e0f3219094df0d510 - name: kind value: task resolver: bundles diff --git a/.tekton/scanner-v4-pipeline.yaml b/.tekton/scanner-v4-pipeline.yaml index 274a27b751c08..05368bff8ca56 100644 --- a/.tekton/scanner-v4-pipeline.yaml +++ b/.tekton/scanner-v4-pipeline.yaml @@ -35,7 +35,7 @@ spec: - name: name value: post-bigquery-metrics - name: bundle - value: quay.io/rhacs-eng/konflux-tasks:latest@sha256:8fd043b9dd843d627e82237ddafe544a31c05ba4bd9278a7b96f6f2e07e8635a + value: quay.io/rhacs-eng/konflux-tasks:latest@sha256:18defc6b58a3792ef4d1c7268ce22167c833e7846523b97e0f3219094df0d510 - name: kind value: task resolver: bundles @@ -168,7 +168,7 @@ spec: - name: name value: init - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-init:0.4.3@sha256:c6c414a3b5dcd827720f3443a128a02d27a0a5071ea3e4dc0063d578f1f73a74 + value: quay.io/konflux-ci/tekton-catalog/task-init:0.4.3@sha256:7854d7babe4136e53e337f6433d952532314433b48bb62b422ddc02700934d85 - name: kind value: task resolver: bundles @@ -192,7 +192,7 @@ spec: - name: name value: git-clone-oci-ta - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-git-clone-oci-ta:0.2.6@sha256:1d7ba568ae6e9e26800054f3942779de8abc80ddc48f0e44df6b1c2f098161dc + value: quay.io/konflux-ci/tekton-catalog/task-git-clone-oci-ta:0.2.6@sha256:a3678910c2bf9187a66a96066193cb41046fbb7097160bf2be6a374ed5e49d30 - name: kind value: task resolver: bundles @@ -211,7 +211,7 @@ spec: - name: name value: determine-image-expiration - name: bundle - value: quay.io/rhacs-eng/konflux-tasks:latest@sha256:8fd043b9dd843d627e82237ddafe544a31c05ba4bd9278a7b96f6f2e07e8635a + value: quay.io/rhacs-eng/konflux-tasks:latest@sha256:18defc6b58a3792ef4d1c7268ce22167c833e7846523b97e0f3219094df0d510 - name: kind value: task resolver: bundles @@ -227,7 +227,7 @@ spec: - name: name value: determine-image-tag - name: bundle - value: quay.io/rhacs-eng/konflux-tasks:latest@sha256:8fd043b9dd843d627e82237ddafe544a31c05ba4bd9278a7b96f6f2e07e8635a + value: quay.io/rhacs-eng/konflux-tasks:latest@sha256:18defc6b58a3792ef4d1c7268ce22167c833e7846523b97e0f3219094df0d510 - name: kind value: task resolver: bundles @@ -247,7 +247,7 @@ spec: - name: name value: fetch-scanner-v4-vuln-mappings - name: bundle - value: quay.io/rhacs-eng/konflux-tasks:latest@sha256:8fd043b9dd843d627e82237ddafe544a31c05ba4bd9278a7b96f6f2e07e8635a + value: quay.io/rhacs-eng/konflux-tasks:latest@sha256:18defc6b58a3792ef4d1c7268ce22167c833e7846523b97e0f3219094df0d510 - name: kind value: task resolver: bundles @@ -271,7 +271,7 @@ spec: - name: name value: prefetch-dependencies-oci-ta - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-prefetch-dependencies-oci-ta:0.10.3@sha256:9fd7d251f92250d89a5465756e278e053af28c6356e5ccdedc4be87bbb13c190 + value: quay.io/konflux-ci/tekton-catalog/task-prefetch-dependencies-oci-ta:0.10.3@sha256:0c386f2c26b46b978280c5c54caac26bcd524975f8f7cc06bb080ba00eae3ad4 - name: kind value: task resolver: bundles @@ -330,7 +330,7 @@ spec: - name: name value: buildah-remote-oci-ta - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-buildah-remote-oci-ta:0.12.1@sha256:9afb0e30b1b5b49a5a934a09ce3b55baf892da99a784387ff72ec92bd2c374c2 + value: quay.io/konflux-ci/tekton-catalog/task-buildah-remote-oci-ta:0.12.2@sha256:a68dce8ed79be8d9e10d98bd2b56895c27fc34f1ed7d67cbc9ec0a91d64cf641 - name: kind value: task resolver: bundles @@ -349,7 +349,7 @@ spec: - name: name value: build-image-index - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-build-image-index:0.3.1@sha256:6ead03ca82a1b970dc60eaadae86adf374e8e70f8d951902e1fac7411dbe0550 + value: quay.io/konflux-ci/tekton-catalog/task-build-image-index:0.4@sha256:654446d8ec028b20ed6ada8a96486ff16692a25192755aa04a99cea8e0afb7e2 - name: kind value: task resolver: bundles @@ -370,7 +370,7 @@ spec: - name: name value: source-build-oci-ta - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-source-build-oci-ta:0.3.1@sha256:bbad5bfd67d1263320a0c4d3f062a18ae611e081b009fd96117c2a00a6ce8dd9 + value: quay.io/konflux-ci/tekton-catalog/task-source-build-oci-ta:0.3.2@sha256:45091b5022754d452b4de60c7d7f4c6e03626efff55f96e9af937400fe3506eb - name: kind value: task resolver: bundles @@ -479,7 +479,7 @@ spec: - name: name value: sast-shell-check-oci-ta - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-sast-shell-check-oci-ta:0.1@sha256:d9b01530ce3c20287714e64980f154e28c0e94d17e2dbfbaf3c8bf77b1844b9e + value: quay.io/konflux-ci/tekton-catalog/task-sast-shell-check-oci-ta:0.1@sha256:d00c884c78489a52dc638e6ced0a01429670d0754f5b1305ad576709cf660312 - name: kind value: task resolver: bundles @@ -505,7 +505,7 @@ spec: - name: name value: sast-unicode-check-oci-ta - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-sast-unicode-check-oci-ta:0.4@sha256:381750451fbcc86d90fa83579a48e0e6555d7cf374fe2c4af3f9262a17fc3c89 + value: quay.io/konflux-ci/tekton-catalog/task-sast-unicode-check-oci-ta:0.4@sha256:15d654c9576b9c4ee1f78b09fce541acf9afe33f1c2363fd6219a79dbf62c95d - name: kind value: task resolver: bundles @@ -531,7 +531,7 @@ spec: - name: name value: sast-snyk-check-oci-ta - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-sast-snyk-check-oci-ta:0.5@sha256:a973b32f0e11958aba08a635981e4d4e7eb200c417492371a1e692ff589b4e8f + value: quay.io/konflux-ci/tekton-catalog/task-sast-snyk-check-oci-ta:0.5@sha256:17b9587eba53fabaab35061275306bfe1f99661d55e14e22f62321fa7cb5ff3e - name: kind value: task resolver: bundles @@ -576,7 +576,7 @@ spec: - name: name value: rpms-signature-scan - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-rpms-signature-scan:0.2.2@sha256:64bb1cf7d875157e68043a411f00e7852afffc68f50881fb041ba994109f4763 + value: quay.io/konflux-ci/tekton-catalog/task-rpms-signature-scan:0.2.2@sha256:d9df5d325f81a9fa132cb597c465aa9210b9b0fa3716b85b32be98d92c9c881a - name: kind value: task resolver: bundles @@ -602,7 +602,7 @@ spec: - name: name value: push-dockerfile-oci-ta - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-push-dockerfile-oci-ta:0.3.1@sha256:3e59d6303ca031c27fab079f7c743fbdecc53d007b8d86e32227de5164f06e31 + value: quay.io/konflux-ci/tekton-catalog/task-push-dockerfile-oci-ta:0.3.1@sha256:4c567d11296850230fe32e76d129834d3bf337a0cae9989b64279b7cfaa4e735 - name: kind value: task resolver: bundles diff --git a/AGENTS.md b/AGENTS.md index b3d59803da998..52856e8ddb89a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -147,6 +147,11 @@ StackRox is a Kubernetes-native security platform with a distributed microservic - **Secured Cluster Services**: Deployed per monitored cluster (Sensor, Admission Controller) - **Multi-cluster support**: One Central instance monitors multiple Kubernetes clusters +### CI Image (Prow / OpenShift CI) +- The CI image is built from the **[stackrox/rox-ci-image](https://github.com/stackrox/rox-ci-image)** repo, not this repo. +- Tool versions bundled in the CI image (e.g. roxie, helm, docker) are pinned in Dockerfiles in that repo. +- `.openshift-ci/Dockerfile.build_root` in this repo only references the resulting image for validation purposes. + ### Key Directories - `/central/` - Central management service code - `/sensor/` - Sensor agent code for cluster monitoring diff --git a/CHANGELOG.md b/CHANGELOG.md index 1845e3cc8ea68..8dd5a22344fff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,29 @@ Changes should still be described appropriately in JIRA/doc input pages, for inc ### Added Features +- ROX-33524: New predefined User PKI auth provider, role, empty permission set and a Central cluster access scope for OpenShift Prometheus server access to custom metrics. Administrator action required: grant the permission set read access to the resources user by custom metrics you want to collect. + +### Removed Features + +- ROX-35079: The `app.k8s.io/v1beta1/Application` CR is no longer shipped. + +### Deprecated Features + +### Technical Changes + +- ROX-36950: Central DB cleans up recognized physical backups from earlier PostgreSQL major-version upgrades after verifying the new backup, or earlier if needed to reclaim upgrade space. The current upgrade's rollback backup is retained without age-based expiration. +- ROX-36534: roxctl binaries in the Central image are now stored as `.tar.gz` archives. Central extracts and streams the binary on download, so the user-facing download behavior is unchanged. +- ROX-35137: Central now prunes deployments whose cluster no longer exists in the database. +- ROX-37048: Central writes its version in `Rh-Central-Version` gRPC response header to authenticated clients. `roxctl` compares this version with its own version and reports a warning to stderr if the version skew is outside of a supported range. +- ROX-37315: Image exclusions no longer turn off deploy-time checks. Previously, an image exclusion on a policy with Build and Deploy stages stopped that policy from raising deploy-time violations or blocking any deployment. Image exclusions now apply only at Build, so after upgrading, affected policies raise deploy-time violations again and block deployments if enforcement is on. To skip apps at deploy time, use deployment exclusions. +- ROX-37265: Feature flag `ROX_SCANNER_V4_RED_HAT_LAYERS_RED_HAT_VULNS_ONLY` will now correctly filter non Red Hat vulnerabilities from RH image layers in newer Konflux built images where it previously had no affect. The flag must now be set on Central INSTEAD of Scanner V4 Matcher. +- ROX-37385: Scanner V4 node scans now record the operating system (for example `rhcos:9.6`) for OpenShift 4.19 and later nodes. RHCOS switched to RHEL-based dotted versions such as `9.6.20250701-0` in OpenShift 4.19, and Central previously stored an empty operating system for these nodes. +- ROX-37149: `roxctl` now honors the `HTTP_PROXY`/`HTTPS_PROXY`/`NO_PROXY` environment variables when connecting to Central over HTTP, so it works where direct egress to Central is blocked but a proxy is available. + +## [5.0.0] + +### Added Features + - ROX-32148: Virtual machine scanning is now enabled by default. RHEL VMs created with OpenShift Virtualization can be scanned for package vulnerabilities after installing roxagent in the guest. - ROX-34997: The Central CR now supports `spec.central.rolloutStrategy` (`Recreate` or `RollingUpdate`) to configure the central deployment rollout strategy. Default remains `Recreate`. - ROX-35181: Administrative events are now exposed as configurable custom Prometheus metrics (`rox_central_admin_event_*`), aggregated by Type, Level, Domain, ResourceType, and ResourceName. Requires permission to read Administration resource, globally scoped. @@ -37,6 +60,7 @@ Changes should still be described appropriately in JIRA/doc input pages, for inc - ROX-26281: block creation of new GCR integrations. Users are directed to use Google Artifact Registry instead. - ROX-35079: installation of the `app.k8s.io/v1beta1/Application` resource when central is installed is deprecated. It will be removed in a future release. - The `priority` field on API responses for deployments, images, nodes, and components is deprecated and will be removed in a future release. Use the `risk_score` field on the same objects instead. Sorting by "Risk Priority" in search queries is also deprecated; sort by "Risk Score" instead. For clusters and namespaces, the `priority` field will be removed and replaced by a `risk_score` field where applicable. +- ROX-37014: The Images by severity, Nodes by severity, CVEs by severity, and Virtual machines by severity counts—including summary widgets and table columns—are deprecated and will be removed in a future release to improve page performance ### Technical Changes - ROX-36784: Scanner V4 node indexing on OpenShift now reads the host RPM database Claircore reports: SQLite on RHEL 9+ (`/usr/share/rpm`, `/usr/lib/sysimage/rpm`) and Berkeley DB on RHEL 8 (`/usr/share/rpm`, `/usr/lib/sysimage/rpm-ostree-base-db`). @@ -50,6 +74,7 @@ Changes should still be described appropriately in JIRA/doc input pages, for inc - ROX-34535: Fixes an issue where if ScannerV2 is disabled or unavailable on initial startup the central deployment leaks GRPC connections until the scanner becomes available. - ROX-36509: Improved Central memory efficiency by optimizing process filter data structures in high-cardinality scenarios. The `ROX_PROCESS_FILTER_FAN_OUT_LEVELS` environment variable now accepts values up to 255; higher values are automatically clamped with a warning. +- ROX-36432: Fixed node scan results (`scan.scanTime`) silently freezing on installs whose default Scanner V4 integration lacked the `NODE_SCANNER` category. Central now restores the default categories on startup. Affected nodes move from Scanner V2 results to Scanner V4 results, so their vulnerability counts may change. ## [4.11.0] diff --git a/COLLECTOR_VERSION b/COLLECTOR_VERSION index f8fdde8c81c08..3125a22fe6f85 100644 --- a/COLLECTOR_VERSION +++ b/COLLECTOR_VERSION @@ -1 +1 @@ -3.25.0-136-g9c3e5263c6 +3.25.0-201-gd4402228d0 diff --git a/Makefile b/Makefile index 387480c0b6c8b..71590230d18bf 100644 --- a/Makefile +++ b/Makefile @@ -138,7 +138,7 @@ $(call go-tool, MOCKGEN_BIN, go.uber.org/mock/mockgen) $(call go-tool, GO_JUNIT_REPORT_BIN, github.com/jstemmer/go-junit-report/v2, tools/test) $(call go-tool, PROTOLOCK_BIN, github.com/nilslice/protolock/cmd/protolock, tools/linters) $(call go-tool, RATCHET_BIN, github.com/sethvargo/ratchet, tools/linters) -$(call go-tool, ACTIONLINT_BIN, github.com/rhysd/actionlint/cmd/actionlint, tools/linters) +$(call go-tool, ACTIONLINT_BIN, actionlint.kjanat.dev/cmd/actionlint, tools/linters) $(call go-tool, GOVULNCHECK_BIN, golang.org/x/vuln/cmd/govulncheck, tools/linters) $(call go-tool, IMAGE_PREFETCHER_DEPLOY_BIN, github.com/stackrox/image-prefetcher/deploy, tools/test) $(call go-tool, PROMETHEUS_METRIC_PARSER_BIN, github.com/stackrox/prometheus-metric-parser, tools/test) @@ -575,7 +575,7 @@ test-prep: go-unit-tests: build-prep test-prep set -o pipefail ; \ CGO_ENABLED=1 GOEXPERIMENT=cgocheck2 MUTEX_WATCHDOG_TIMEOUT_SECS=30 GOTAGS=$(GOTAGS),test scripts/go-test.sh -timeout 25m -race -cover -coverprofile test-output/coverage.out -v \ - $(shell git ls-files -- '*_test.go' | grep -v -E '^($(NESTED_GO_MODULE_REGEX))(/|$$)' | sed -e 's@^@./@g' | xargs -n 1 dirname | sort | uniq | xargs go list| grep -v '^github.com/stackrox/rox/tests$$' | grep -Ev $(UNIT_TEST_IGNORE)) \ + $(shell git ls-files -- '*_test.go' | grep -v -E '^($(NESTED_GO_MODULE_REGEX))(/|$$)' | scripts/go-files-to-packages.sh | grep -Ev $(UNIT_TEST_IGNORE)) \ | tee $(GO_TEST_OUTPUT_PATH) # Nested modules have independent coverage profiles, so keep their coverage # out of the root profile while including their verbose output in JUnit. @@ -604,19 +604,19 @@ sensor-pipeline-benchmark: build-prep test-prep go-postgres-unit-tests: build-prep test-prep set -o pipefail ; \ CGO_ENABLED=1 GOEXPERIMENT=cgocheck2 MUTEX_WATCHDOG_TIMEOUT_SECS=30 GOTAGS=$(GOTAGS),test,sql_integration scripts/go-test.sh -timeout 15m -race -cover -coverprofile test-output/coverage.out -v \ - $(shell git grep -rl "//go:build sql_integration" central pkg tools | sed -e 's@^@./@g' | xargs -n 1 dirname | sort | uniq | xargs go list -tags sql_integration | grep -v '^github.com/stackrox/rox/tests$$' | grep -Ev $(UNIT_TEST_IGNORE)) \ + $(shell git grep -rl "//go:build sql_integration" central pkg tools | scripts/go-files-to-packages.sh -tags sql_integration | grep -Ev $(UNIT_TEST_IGNORE)) \ | tee $(GO_TEST_OUTPUT_PATH) @# The -p 1 passed to go test is required to ensure that tests of different packages are not run in parallel, so as to avoid conflicts when interacting with the DB. set -o pipefail ; \ CGO_ENABLED=1 GOEXPERIMENT=cgocheck2 MUTEX_WATCHDOG_TIMEOUT_SECS=30 GOTAGS=$(GOTAGS),test,sql_integration scripts/go-test.sh -p 1 -race -cover -coverprofile test-output/migrator-coverage.out -v \ - $(shell git grep -rl "//go:build sql_integration" migrator | sed -e 's@^@./@g' | xargs -n 1 dirname | sort | uniq | xargs go list -tags sql_integration | grep -v '^github.com/stackrox/rox/tests$$' | grep -Ev $(UNIT_TEST_IGNORE)) \ + $(shell git grep -rl "//go:build sql_integration" migrator | scripts/go-files-to-packages.sh -tags sql_integration | grep -Ev $(UNIT_TEST_IGNORE)) \ | tee -a $(GO_TEST_OUTPUT_PATH) .PHONY: go-postgres-bench-tests go-postgres-bench-tests: build-prep test-prep set -o pipefail ; \ CGO_ENABLED=1 GOEXPERIMENT=cgocheck2 MUTEX_WATCHDOG_TIMEOUT_SECS=30 GOTAGS=$(GOTAGS),test,sql_integration scripts/go-test.sh -run=nonthing -bench=. -benchtime=$(BENCHTIME) -benchmem -timeout $(BENCHTIMEOUT) -count $(BENCHCOUNT) -v \ - $(shell git grep -rl "testing.B" central pkg migrator tools | sed -e 's@^@./@g' | xargs -n 1 dirname | sort | uniq | xargs go list -tags sql_integration | grep -v '^github.com/stackrox/rox/tests$$' | grep -Ev $(UNIT_TEST_IGNORE)) \ + $(shell git grep -rl "testing.B" central pkg migrator tools | scripts/go-files-to-packages.sh -tags sql_integration | grep -Ev $(UNIT_TEST_IGNORE)) \ | tee $(GO_TEST_OUTPUT_PATH) .PHONY: shell-unit-tests @@ -624,6 +624,8 @@ shell-unit-tests: @echo "+ $@" $(SILENT)mkdir -p shell-test-output bats --print-output-on-failure --verbose-run --recursive --report-formatter junit --output shell-test-output \ + scanner/image/db/bats \ + image/postgres/scripts \ scripts \ tests/e2e/bats @@ -871,14 +873,6 @@ roxvet: $(ROXVET_BIN) ########## ## Misc ## ########## -.PHONY: clean-offline-bundle -clean-offline-bundle: - $(SILENT)find scripts/offline-bundle -name '*.img' -delete -o -name '*.tgz' -delete -o -name 'bin' -type d -exec rm -r "{}" \; - -.PHONY: offline-bundle -offline-bundle: clean-offline-bundle - $(SILENT)./scripts/offline-bundle/create.sh - .PHONY: check-debugger check-debugger: /usr/bin/env DEBUG_BUILD="$(DEBUG_BUILD)" BUILD_TAG="$(BUILD_TAG)" TAG="$(TAG)" ./scripts/check-debugger.sh diff --git a/ROXIE_VERSION b/ROXIE_VERSION index 5f749c13663ae..1f77169993b92 100644 --- a/ROXIE_VERSION +++ b/ROXIE_VERSION @@ -1 +1 @@ -0.4.11 +0.4.13 diff --git a/central/auth/openshift/metrics_auth.go b/central/auth/openshift/metrics_auth.go new file mode 100644 index 0000000000000..926f1bc9aa52a --- /dev/null +++ b/central/auth/openshift/metrics_auth.go @@ -0,0 +1,288 @@ +package openshift + +import ( + "context" + + "github.com/stackrox/rox/central/globaldb" + groupDataStore "github.com/stackrox/rox/central/group/datastore" + roleDataStore "github.com/stackrox/rox/central/role/datastore" + postgresSimpleAccessScopeStore "github.com/stackrox/rox/central/role/store/simpleaccessscope/postgres" + "github.com/stackrox/rox/central/tlsconfig" + "github.com/stackrox/rox/generated/storage" + "github.com/stackrox/rox/pkg/auth/authproviders" + "github.com/stackrox/rox/pkg/auth/authproviders/userpki" + permissionsUtils "github.com/stackrox/rox/pkg/auth/permissions/utils" + "github.com/stackrox/rox/pkg/declarativeconfig" + "github.com/stackrox/rox/pkg/env" + "github.com/stackrox/rox/pkg/k8scfgwatch" + "github.com/stackrox/rox/pkg/k8sutil" + "github.com/stackrox/rox/pkg/logging" + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" +) + +const ( + authProviderID = "b3070020-ecc3-4f34-a3f6-ad28ffc9b80f" + permissionSetID = "b3070020-ecc3-4f34-a3f6-ad28ffc9b80e" + accessScopeID = "b3070020-ecc3-4f34-a3f6-ad28ffc9b80c" + + // Auth provider is hidden from the login screen but visible in Access Control. + // It trusts the Kubernetes client CA from extension-apiserver-authentication, + // which signs Prometheus client certs. This adds the CA to userTrustRoots on the + // public :8443 endpoint (optional client cert verification). + authProviderName = "OpenShift Platform Client Certificates" + roleName = "OpenShift Prometheus Metrics Reader" + permissionSetName = "OpenShift Prometheus Metrics Reader" + accessScopeName = "OpenShift Central Cluster" + + centralColocatedLabelKey = "stackrox.io/central-colocated" +) + +var log = logging.LoggerForModule() + +// SeedMetricsAuthProvider ensures that the userpki auth provider, permission set, role, +// and group mapping required for OpenShift Prometheus to scrape /metrics exist. +// +// The access scope, permission set, and role have static content with no dependency on +// the client CA, so they are seeded unconditionally at startup. The auth provider's +// config and the group's auth-provider reference, however, need the Kubernetes client CA +// from the extension-apiserver-authentication ConfigMap (same CA that signs Prometheus +// client certs), which may not be available yet; a ConfigMap watcher keeps the CA current +// across rotations. +// +// The access scope uses DEFAULT origin (not user-modifiable) and is seeded the same way +// as the other built-in DEFAULT access scopes (Unrestricted, Deny All): an idempotent +// upsert straight to the underlying store, self-healing across restarts and upgrades. +// The auth provider and group also use DEFAULT origin: the group can't be repointed to a +// different role or deleted, which in turn keeps the role permanently referenced so it +// can't be deleted either. Role and permission set use IMPERATIVE origin so operators can +// still adjust their permissions or which access scope the role grants; they are only +// created if missing, never overwritten. +func SeedMetricsAuthProvider(ctx context.Context, registry authproviders.Registry, roleDS roleDataStore.DataStore, groupDS groupDataStore.DataStore) { + if !tlsconfig.OpenShiftTLSConfigured() { + return + } + + seedAccessScope(ctx) + ensurePermissionSet(ctx, roleDS) + ensureRole(ctx, roleDS) + + clientset, err := newK8sClient() + if err != nil { + log.Warnf("Cannot create Kubernetes client for OpenShift metrics auth: %v", err) + return + } + + onCA := func(caPEM string) { + // Auth provider uses DEFAULT origin. + defaultCtx := declarativeconfig.WithModifyDefaultResource(ctx) + ensureAuthProvider(defaultCtx, registry, caPEM) + ensureGroup(ctx, groupDS) + } + + if caPEM := readClientCA(ctx, clientset); caPEM != "" { + onCA(caPEM) + } + + watchClientCA(ctx, clientset, onCA) +} + +func newK8sClient() (kubernetes.Interface, error) { + config, err := k8sutil.GetK8sInClusterConfig() + if err != nil { + return nil, err + } + return kubernetes.NewForConfig(config) +} + +func readClientCA(ctx context.Context, clientset kubernetes.Interface) string { + cm, err := clientset.CoreV1().ConfigMaps( + env.SecureMetricsClientCANamespace.Setting(), + ).Get(ctx, env.SecureMetricsClientCAConfigMap.Setting(), metav1.GetOptions{}) + if err != nil { + log.Warnf("Cannot read client CA ConfigMap %s/%s: %v", + env.SecureMetricsClientCANamespace.Setting(), + env.SecureMetricsClientCAConfigMap.Setting(), err) + return "" + } + pem, ok := cm.Data[env.SecureMetricsClientCAKey.Setting()] + if !ok || pem == "" { + log.Warnf("Client CA key %q not found in ConfigMap %s/%s", + env.SecureMetricsClientCAKey.Setting(), + env.SecureMetricsClientCANamespace.Setting(), + env.SecureMetricsClientCAConfigMap.Setting()) + return "" + } + return pem +} + +func watchClientCA(ctx context.Context, clientset kubernetes.Interface, onCA func(string)) { + watcher := k8scfgwatch.NewConfigMapWatcher(clientset, func(cm *v1.ConfigMap) { + if cm == nil { + return + } + pem, ok := cm.Data[env.SecureMetricsClientCAKey.Setting()] + if !ok || pem == "" { + return + } + onCA(pem) + }) + watcher.Watch( + ctx, + env.SecureMetricsClientCANamespace.Setting(), + env.SecureMetricsClientCAConfigMap.Setting(), + ) +} + +func refreshCA(ctx context.Context, registry authproviders.Registry, provider authproviders.Provider, caPEM string) { + config := provider.StorageView().GetConfig() + if config[userpki.ConfigKeys] == caPEM { + return + } + log.Info("Client CA changed, updating OpenShift metrics auth provider") + config[userpki.ConfigKeys] = caPEM + + factory := provider.BackendFactory() + if factory == nil { + log.Warn("Auth provider has no backend factory, cannot apply the new client CA") + return + } + // WithConfig on its own only rewrites the stored config. The provider keeps its + // existing backend, which parsed the certificates once at construction time, and the + // registry then re-registers those same stale certificates with the client CA + // manager. Central would keep advertising the superseded CA until restart, so the + // backend has to be rebuilt from the new config as part of the same update. + if _, err := registry.UpdateProvider(declarativeconfig.WithModifyDefaultResource(ctx), authProviderID, + authproviders.WithConfig(config), + authproviders.WithBackendFromFactory(ctx, factory), + ); err != nil { + log.Warnf("Failed to update client CA in auth provider: %v", err) + } +} + +// seedAccessScope upserts the OpenShift metrics access scope directly into the +// underlying store, the same way the built-in DEFAULT access scopes (Unrestricted, Deny +// All) are seeded in central/role/datastore/singleton.go. This keeps the scope's content +// always in sync with the code (self-healing across restarts and upgrades) without going +// through the datastore's DEFAULT-origin write protection, which is meant to guard +// against API callers, not this kind of internal, static, boot-time seeding. +func seedAccessScope(ctx context.Context) { + scope := &storage.SimpleAccessScope{ + Id: accessScopeID, + Name: accessScopeName, + Description: "Scoped to the cluster that runs Central", + Traits: &storage.Traits{ + Origin: storage.Traits_DEFAULT, + }, + Rules: &storage.SimpleAccessScope_Rules{ + ClusterLabelSelectors: []*storage.SetBasedLabelSelector{ + { + Requirements: []*storage.SetBasedLabelSelector_Requirement{ + { + Key: centralColocatedLabelKey, + Op: storage.SetBasedLabelSelector_EXISTS, + }, + }, + }, + }, + }, + } + store := postgresSimpleAccessScopeStore.New(globaldb.GetPostgres()) + if err := store.Upsert(ctx, scope); err != nil { + log.Warnf("Failed to seed OpenShift metrics access scope: %v", err) + } +} + +func ensurePermissionSet(ctx context.Context, roleDS roleDataStore.DataStore) { + if _, exists, err := roleDS.GetPermissionSet(ctx, permissionSetID); err != nil { + log.Warnf("Failed to check OpenShift metrics permission set: %v", err) + return + } else if exists { + return + } + + ps := &storage.PermissionSet{ + Id: permissionSetID, + Name: permissionSetName, + Description: "For OpenShift Prometheus: read access to Administration for /metrics scraping", + // Let's give no permissions by default to avoid unexpected sensitive data exposure. + ResourceToAccess: permissionsUtils.FromResourcesWithAccess(), + } + if err := roleDS.AddPermissionSet(ctx, ps); err != nil { + log.Warnf("Failed to create OpenShift metrics permission set: %v", err) + } +} + +func ensureRole(ctx context.Context, roleDS roleDataStore.DataStore) { + if _, exists, err := roleDS.GetRole(ctx, roleName); err != nil { + log.Warnf("Failed to check OpenShift metrics role: %v", err) + return + } else if exists { + return + } + + role := &storage.Role{ + Name: roleName, + Description: "Maps OpenShift Prometheus service account to /metrics read access", + PermissionSetId: permissionSetID, + AccessScopeId: accessScopeID, + } + if err := roleDS.AddRole(ctx, role); err != nil { + log.Warnf("Failed to create OpenShift metrics role: %v", err) + } +} + +func ensureAuthProvider(ctx context.Context, registry authproviders.Registry, caPEM string) { + if existing := registry.GetProvider(authProviderID); existing != nil { + refreshCA(ctx, registry, existing, caPEM) + return + } + + _, err := registry.CreateProvider(declarativeconfig.WithModifyDefaultResource(ctx), + authproviders.WithType(userpki.TypeName), + authproviders.WithID(authProviderID), + authproviders.WithName(authProviderName), + authproviders.WithEnabled(true), + authproviders.WithActive(true), + authproviders.WithVisibility(storage.Traits_HIDDEN), + authproviders.WithOrigin(storage.Traits_DEFAULT), + authproviders.WithConfig(map[string]string{ + userpki.ConfigKeys: caPEM, + }), + ) + if err != nil { + log.Warnf("Failed to create OpenShift metrics auth provider: %v", err) + } +} + +func ensureGroup(ctx context.Context, groupDS groupDataStore.DataStore) { + cn := env.SecureMetricsClientCertCN.Setting() + existing, err := groupDS.GetFiltered(ctx, func(g *storage.Group) bool { + p := g.GetProps() + return p.GetAuthProviderId() == authProviderID && p.GetKey() == "name" && p.GetValue() == cn + }) + if err != nil { + log.Warnf("Failed to check OpenShift metrics group: %v", err) + return + } + if len(existing) > 0 { + return + } + group := &storage.Group{ + Props: &storage.GroupProperties{ + AuthProviderId: authProviderID, + Key: "name", + Value: cn, + Traits: &storage.Traits{ + Origin: storage.Traits_DEFAULT, + }, + }, + RoleName: roleName, + } + // Group uses DEFAULT origin so a user can't repoint or delete the mapping and thereby + // orphan (and delete) the role out from under it. + if err := groupDS.Add(declarativeconfig.WithModifyDefaultResource(ctx), group); err != nil { + log.Warnf("Failed to create OpenShift metrics group: %v", err) + } +} diff --git a/central/auth/openshift/metrics_auth_pg_test.go b/central/auth/openshift/metrics_auth_pg_test.go new file mode 100644 index 0000000000000..00fe51d87a109 --- /dev/null +++ b/central/auth/openshift/metrics_auth_pg_test.go @@ -0,0 +1,49 @@ +//go:build sql_integration + +package openshift + +import ( + "context" + "testing" + + "github.com/stackrox/rox/central/globaldb" + postgresSimpleAccessScopeStore "github.com/stackrox/rox/central/role/store/simpleaccessscope/postgres" + "github.com/stackrox/rox/generated/storage" + "github.com/stackrox/rox/pkg/postgres/pgtest" + "github.com/stackrox/rox/pkg/sac" + "github.com/stackrox/rox/pkg/sac/resources" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestSeedAccessScope(t *testing.T) { + pgTest := pgtest.ForT(t) + require.NotNil(t, pgTest) + defer pgTest.Close() + globaldb.SetPostgresTest(t, pgTest.DB) + + ctx := sac.WithGlobalAccessScopeChecker(context.Background(), + sac.AllowFixedScopes( + sac.AccessModeScopeKeys(storage.Access_READ_ACCESS, storage.Access_READ_WRITE_ACCESS), + sac.ResourceScopeKeys(resources.Access))) + + seedAccessScope(ctx) + + store := postgresSimpleAccessScopeStore.New(pgTest.DB) + stored, found, err := store.Get(ctx, accessScopeID) + require.NoError(t, err) + require.True(t, found) + assert.Equal(t, accessScopeName, stored.GetName()) + assert.Equal(t, storage.Traits_DEFAULT, stored.GetTraits().GetOrigin()) + require.Len(t, stored.GetRules().GetClusterLabelSelectors(), 1) + req := stored.GetRules().GetClusterLabelSelectors()[0].GetRequirements()[0] + assert.Equal(t, centralColocatedLabelKey, req.GetKey()) + assert.Equal(t, storage.SetBasedLabelSelector_EXISTS, req.GetOp()) + + // Re-seeding is idempotent, matching the boot-time self-healing behavior. + seedAccessScope(ctx) + stored, found, err = store.Get(ctx, accessScopeID) + require.NoError(t, err) + require.True(t, found) + assert.Equal(t, accessScopeName, stored.GetName()) +} diff --git a/central/auth/openshift/metrics_auth_test.go b/central/auth/openshift/metrics_auth_test.go new file mode 100644 index 0000000000000..9355236e8d6d4 --- /dev/null +++ b/central/auth/openshift/metrics_auth_test.go @@ -0,0 +1,264 @@ +package openshift + +import ( + "context" + "crypto/x509" + "errors" + "testing" + + groupMocks "github.com/stackrox/rox/central/group/datastore/mocks" + roleMocks "github.com/stackrox/rox/central/role/datastore/mocks" + "github.com/stackrox/rox/generated/storage" + "github.com/stackrox/rox/pkg/auth/authproviders" + providerMocks "github.com/stackrox/rox/pkg/auth/authproviders/mocks" + "github.com/stackrox/rox/pkg/auth/authproviders/userpki" + "github.com/stackrox/rox/pkg/auth/permissions" + "github.com/stackrox/rox/pkg/auth/tokens" + "github.com/stackrox/rox/pkg/certgen" + "github.com/stackrox/rox/pkg/declarativeconfig" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" +) + +const testCAPEM = "-----BEGIN CERTIFICATE-----\ntest\n-----END CERTIFICATE-----\n" + +func setupMocks(t *testing.T) (*providerMocks.MockRegistry, *roleMocks.MockDataStore, *groupMocks.MockDataStore) { + ctrl := gomock.NewController(t) + return providerMocks.NewMockRegistry(ctrl), + roleMocks.NewMockDataStore(ctrl), + groupMocks.NewMockDataStore(ctrl) +} + +func TestSeed_FirstBoot_CreatesAllObjects(t *testing.T) { + registry, roleDS, groupDS := setupMocks(t) + ctx := context.Background() + + roleDS.EXPECT().GetPermissionSet(gomock.Any(), permissionSetID).Return(nil, false, nil) + roleDS.EXPECT().AddPermissionSet(gomock.Any(), gomock.Any()).Return(nil) + roleDS.EXPECT().GetRole(gomock.Any(), roleName).Return(nil, false, nil) + roleDS.EXPECT().AddRole(gomock.Any(), gomock.Any()).Return(nil) + + providerCreated := false + registry.EXPECT().GetProvider(authProviderID).Return(nil) + registry.EXPECT().CreateProvider(gomock.Any(), gomock.Any()).DoAndReturn( + func(_ context.Context, _ ...interface{}) (interface{}, error) { + providerCreated = true + return nil, nil + }) + groupDS.EXPECT().GetFiltered(gomock.Any(), gomock.Any()).Return(nil, nil) + groupDS.EXPECT().Add(gomock.Any(), gomock.Any()).DoAndReturn( + func(_ context.Context, _ *storage.Group) error { + if !providerCreated { + t.Error("group Add called before provider creation") + } + return nil + }) + + ensurePermissionSet(ctx, roleDS) + ensureRole(ctx, roleDS) + ensureAuthProvider(ctx, registry, testCAPEM) + ensureGroup(ctx, groupDS) +} + +func TestSeed_SubsequentBoot_CAUnchanged_NoUpdate(t *testing.T) { + registry, _, _ := setupMocks(t) + ctx := context.Background() + + existing := providerMocks.NewMockProvider(gomock.NewController(t)) + existing.EXPECT().StorageView().Return(&storage.AuthProvider{ + Config: map[string]string{userpki.ConfigKeys: testCAPEM}, + }) + registry.EXPECT().GetProvider(authProviderID).Return(existing) + + ensureAuthProvider(ctx, registry, testCAPEM) +} + +func TestSeed_PartialRecovery_PermissionSetExists_RoleMissing(t *testing.T) { + registry, roleDS, groupDS := setupMocks(t) + ctx := context.Background() + + roleDS.EXPECT().GetPermissionSet(gomock.Any(), permissionSetID).Return(&storage.PermissionSet{}, true, nil) + roleDS.EXPECT().GetRole(gomock.Any(), roleName).Return(nil, false, nil) + roleDS.EXPECT().AddRole(gomock.Any(), gomock.Any()).Return(nil) + registry.EXPECT().GetProvider(authProviderID).Return(nil) + registry.EXPECT().CreateProvider(gomock.Any(), gomock.Any()).Return(nil, nil) + groupDS.EXPECT().GetFiltered(gomock.Any(), gomock.Any()).Return(nil, nil) + groupDS.EXPECT().Add(gomock.Any(), gomock.Any()).Return(nil) + + ensurePermissionSet(ctx, roleDS) + ensureRole(ctx, roleDS) + ensureAuthProvider(ctx, registry, testCAPEM) + ensureGroup(ctx, groupDS) +} + +func TestSeed_Group_IsDefaultOriginAndImmutable(t *testing.T) { + _, _, groupDS := setupMocks(t) + ctx := context.Background() + + groupDS.EXPECT().GetFiltered(gomock.Any(), gomock.Any()).Return(nil, nil) + groupDS.EXPECT().Add(gomock.Any(), gomock.Any()).DoAndReturn( + func(addCtx context.Context, group *storage.Group) error { + if group.GetProps().GetTraits().GetOrigin() != storage.Traits_DEFAULT { + t.Errorf("expected group to use DEFAULT origin, got %v", group.GetProps().GetTraits().GetOrigin()) + } + assert.False(t, declarativeconfig.CanModifyResource(ctx, group.GetProps())) + if !declarativeconfig.CanModifyResource(addCtx, group.GetProps()) { + t.Error("expected ensureGroup to pass a context that can modify DEFAULT-origin resources") + } + return nil + }) + + ensureGroup(ctx, groupDS) +} + +func TestSeed_SubsequentBoot_GroupExists_NotOverwritten(t *testing.T) { + _, _, groupDS := setupMocks(t) + ctx := context.Background() + + groupDS.EXPECT().GetFiltered(gomock.Any(), gomock.Any()).Return([]*storage.Group{{ + Props: &storage.GroupProperties{AuthProviderId: authProviderID, Key: "name", Value: "system:serviceaccount:openshift-monitoring:prometheus-k8s"}, + RoleName: "User Modified Role", + }}, nil) + + ensureGroup(ctx, groupDS) +} + +// TestSeed_CARotation_RegistersNewCA runs against a real auth provider registry because +// the interesting part of a rotation happens past the registry: a mocked registry only +// shows that UpdateProvider was called, not whether the new CA reached the client CA +// manager. Persisting the bundle without also rebuilding the provider backend leaves +// Central advertising the superseded CA until restart, breaking Prometheus scrapes +// roughly monthly when OpenShift rotates its CSR signer. +func TestSeed_CARotation_RegistersNewCA(t *testing.T) { + ctx := context.Background() + caManager := &recordingCAManager{} + store := &inMemoryAuthProviderStore{providers: map[string]*storage.AuthProvider{}} + + registry := authproviders.NewStoreBackedRegistry("/sso/", "/auth/response/generic", + store, noopIssuerFactory{}, noopRoleMapperFactory{}, nil) + require.NoError(t, registry.RegisterBackendFactory(ctx, userpki.TypeName, + userpki.NewFactoryFactory(caManager))) + require.NoError(t, registry.Init()) + + oldCAPEM, oldCA := generateCA(t) + newCAPEM, newCA := generateCA(t) + + ensureAuthProvider(ctx, registry, oldCAPEM) + require.Equal(t, []string{oldCA.Subject.String()}, registeredSubjects(caManager.certs)) + + ensureAuthProvider(ctx, registry, newCAPEM) + + provider := registry.GetProvider(authProviderID) + require.NotNil(t, provider) + assert.Equal(t, storage.Traits_DEFAULT, provider.StorageView().GetTraits().GetOrigin()) + assert.Equal(t, newCAPEM, provider.StorageView().GetConfig()[userpki.ConfigKeys], + "rotated CA should be persisted in the auth provider config") + assert.Equal(t, []string{newCA.Subject.String()}, registeredSubjects(caManager.certs), + "rotated CA should also be registered with the client CA manager") +} + +func generateCA(t *testing.T) (string, *x509.Certificate) { + ca, err := certgen.GenerateCA() + require.NoError(t, err) + return string(ca.CertPEM()), ca.Certificate() +} + +func registeredSubjects(certs []*x509.Certificate) []string { + subjects := make([]string, 0, len(certs)) + for _, cert := range certs { + subjects = append(subjects, cert.Subject.String()) + } + return subjects +} + +// recordingCAManager stands in for central/tlsconfig.Manager, which is what Central wires +// into the userpki backend factory. It records the certificates the backend hands over, +// i.e. what ends up in the client CA pool advertised during the TLS handshake. +type recordingCAManager struct { + certs []*x509.Certificate +} + +func (c *recordingCAManager) RegisterAuthProvider(_ authproviders.Provider, certs []*x509.Certificate) { + c.certs = certs +} + +func (c *recordingCAManager) UnregisterAuthProvider(authproviders.Provider) { + c.certs = nil +} + +func (c *recordingCAManager) GetProviderForFingerprint(string) authproviders.Provider { + return nil +} + +type inMemoryAuthProviderStore struct { + providers map[string]*storage.AuthProvider +} + +func (s *inMemoryAuthProviderStore) GetAuthProvider(_ context.Context, id string) (*storage.AuthProvider, bool, error) { + provider, found := s.providers[id] + return provider, found, nil +} + +func (s *inMemoryAuthProviderStore) ForEachAuthProvider(_ context.Context, fn func(*storage.AuthProvider) error) error { + for _, provider := range s.providers { + if err := fn(provider); err != nil { + return err + } + } + return nil +} + +func (s *inMemoryAuthProviderStore) GetAuthProvidersFiltered(_ context.Context, + filter func(*storage.AuthProvider) bool) ([]*storage.AuthProvider, error) { + var filtered []*storage.AuthProvider + for _, provider := range s.providers { + if filter(provider) { + filtered = append(filtered, provider) + } + } + return filtered, nil +} + +func (s *inMemoryAuthProviderStore) AuthProviderExistsWithName(_ context.Context, name string) (bool, error) { + for _, provider := range s.providers { + if provider.GetName() == name { + return true, nil + } + } + return false, nil +} + +func (s *inMemoryAuthProviderStore) AddAuthProvider(ctx context.Context, provider *storage.AuthProvider) error { + if !declarativeconfig.CanModifyResource(ctx, provider) { + return errors.New("cannot create provider with this origin context") + } + s.providers[provider.GetId()] = provider.CloneVT() + return nil +} + +func (s *inMemoryAuthProviderStore) UpdateAuthProvider(ctx context.Context, provider *storage.AuthProvider) error { + if !declarativeconfig.CanModifyResource(ctx, s.providers[provider.GetId()]) || + !declarativeconfig.CanModifyResource(ctx, provider) { + return errors.New("cannot update provider with this origin context") + } + s.providers[provider.GetId()] = provider.CloneVT() + return nil +} + +func (s *inMemoryAuthProviderStore) RemoveAuthProvider(_ context.Context, id string, _ bool) error { + delete(s.providers, id) + return nil +} + +type noopIssuerFactory struct{} + +func (noopIssuerFactory) CreateIssuer(tokens.Source, ...tokens.Option) (tokens.Issuer, error) { + return nil, nil +} + +func (noopIssuerFactory) UnregisterSource(tokens.Source) error { return nil } + +type noopRoleMapperFactory struct{} + +func (noopRoleMapperFactory) GetRoleMapper(string) permissions.RoleMapper { return nil } diff --git a/central/baseimage/service/service_impl.go b/central/baseimage/service/service_impl.go index daa0e46b4a470..2c163a6817495 100644 --- a/central/baseimage/service/service_impl.go +++ b/central/baseimage/service/service_impl.go @@ -5,6 +5,8 @@ import ( "errors" "fmt" "path" + "strings" + "unicode" "github.com/distribution/reference" "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" @@ -189,12 +191,28 @@ func (s *serviceImpl) validateBaseImageRepository(ctx context.Context, repoPath return nil } -// isValidTagPattern checks if the given string is a valid [path.Match] glob pattern. +// maxTagPatternLength bounds a tag pattern to the maximum length of a container image +// tag: one leading character plus up to 127 more (see [reference.TagRegexp]). +const maxTagPatternLength = 128 + +// isValidTagPattern checks that the given string is a glob pattern that could match a +// container image tag. Besides validating the [path.Match] glob syntax, it rejects +// characters that are illegal in a tag ('/', ':', '@', whitespace). Their presence +// signals that the repository path or a registry port leaked into the tag field - +// common when the registry includes a port and the user mistypes the input. Such a +// pattern can never match a real tag, so it is rejected here instead of silently +// matching nothing. func isValidTagPattern(tagPattern string) (bool, error) { // Reject empty tag patterns. Use * to match all tags. if tagPattern == "" { return false, errox.InvalidArgs.New("tag pattern cannot be empty") } + if len(tagPattern) > maxTagPatternLength { + return false, errox.InvalidArgs.Newf("tag pattern is too long: %d bytes (max %d)", len(tagPattern), maxTagPatternLength) + } + if strings.ContainsAny(tagPattern, "/:@") || strings.ContainsFunc(tagPattern, unicode.IsSpace) { + return false, errox.InvalidArgs.Newf("tag pattern '%s' must not contain '/', ':', '@' or whitespace - for a registry with a port, set baseImageRepoPath to 'registry:port/repo' and baseImageTagPattern to the tag pattern (e.g. '1.*')", tagPattern) + } // path.Match validates the pattern and returns an error for malformed input. _, err := path.Match(tagPattern, "") if err != nil { diff --git a/central/baseimage/service/service_impl_test.go b/central/baseimage/service/service_impl_test.go index 8064d7a8753db..5c94a73ec53f6 100644 --- a/central/baseimage/service/service_impl_test.go +++ b/central/baseimage/service/service_impl_test.go @@ -233,6 +233,42 @@ func (suite *ServiceTestSuite) TestIsValidTagPattern() { expectedValid: true, expectedErrMsg: "", }, + { + description: "rejects pattern with slash (repo path leaked into tag field)", + input: "5000/library/ubuntu*", + expectedValid: false, + expectedErrMsg: "set baseImageRepoPath to 'registry:port/repo' and baseImageTagPattern to the tag pattern", + }, + { + description: "rejects pattern with colon (registry port leaked into tag field)", + input: "5000:latest", + expectedValid: false, + expectedErrMsg: "must not contain", + }, + { + description: "rejects pattern with digest separator", + input: "sha256@abc", + expectedValid: false, + expectedErrMsg: "must not contain", + }, + { + description: "rejects pattern with whitespace", + input: "1. *", + expectedValid: false, + expectedErrMsg: "must not contain", + }, + { + description: "rejects pattern with non-ASCII whitespace", + input: "1.\u00a0*", + expectedValid: false, + expectedErrMsg: "must not contain", + }, + { + description: "rejects pattern longer than max tag length", + input: strings.Repeat("a", maxTagPatternLength+1), + expectedValid: false, + expectedErrMsg: "129 bytes (max 128)", + }, } for _, tt := range tests { diff --git a/central/baseimage/service/singleton.go b/central/baseimage/service/singleton.go index a3ad7d955ed19..6b7f5ef540112 100644 --- a/central/baseimage/service/singleton.go +++ b/central/baseimage/service/singleton.go @@ -27,6 +27,7 @@ func initialize() { scanwaiter.Singleton(), scanwaiterv2.Singleton(), sachelper.NewClusterNamespaceSacHelper(clusterDataStore.Singleton(), namespaceDataStore.Singleton()), + clusterDataStore.Singleton(), ) as = New(repository.Singleton(), imageintegration.Set(), scanDelegator) diff --git a/central/baseimage/watcher/singleton.go b/central/baseimage/watcher/singleton.go index 0cb56659572ed..5d48ef671fa25 100644 --- a/central/baseimage/watcher/singleton.go +++ b/central/baseimage/watcher/singleton.go @@ -32,6 +32,7 @@ func Singleton() Watcher { scanwaiter.Singleton(), scanwaiterv2.Singleton(), sachelper.NewClusterNamespaceSacHelper(clusterDataStore.Singleton(), namespaceDataStore.Singleton()), + clusterDataStore.Singleton(), ) watcher = New( diff --git a/central/cli/download.go b/central/cli/download.go index e0ad06abf0ecc..cdc705a28dcb3 100644 --- a/central/cli/download.go +++ b/central/cli/download.go @@ -1,17 +1,85 @@ package cli import ( + "archive/tar" + "compress/gzip" + "fmt" + "io" "net/http" + "os" "path/filepath" + "strconv" + "strings" + + "github.com/stackrox/rox/pkg/logging" + "github.com/stackrox/rox/pkg/utils" ) const downloadPath = "/assets/downloads/cli" -// Handler returns a handler for serving files from Central's downloads folder +var log = logging.LoggerForModule() + +// Handler serves roxctl binaries from Central UI. +// Binaries are stored as .tar.gz and extracted on the fly on each request. func Handler() http.HandlerFunc { + return handlerWithDir(downloadPath) +} + +func handlerWithDir(dir string) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - // Need to remove the rest of the URL path so that it just contains the file wanted - r.URL.Path = filepath.Base(r.URL.Path) - http.FileServer(http.Dir(downloadPath)).ServeHTTP(w, r) + if r.Method != http.MethodGet && r.Method != http.MethodHead { + w.Header().Set("Allow", http.MethodGet+", "+http.MethodHead) + http.Error(w, fmt.Sprintf("method %s not allowed", r.Method), http.StatusMethodNotAllowed) + return + } + + filename := filepath.Base(r.URL.Path) + tarPath := filepath.Join(dir, strings.TrimSuffix(filename, ".exe")+".tar.gz") + + f, err := os.Open(tarPath) + if err != nil { + log.Warnf("error opening tarball for requested binary %q: %v", filename, err) + http.Error(w, "not found", http.StatusNotFound) + return + } + defer utils.IgnoreError(f.Close) + + gz, err := gzip.NewReader(f) + if err != nil { + log.Warnf("error opening gzip reader for %s: %v", tarPath, err) + http.Error(w, "invalid archive", http.StatusInternalServerError) + return + } + defer utils.IgnoreError(gz.Close) + + tr := tar.NewReader(gz) + for { + hdr, err := tr.Next() + if err == io.EOF { + log.Warnf("binary %q not found in %s; tarball entry name may not match the requested filename", filename, tarPath) + http.Error(w, "not found", http.StatusNotFound) + return + } + if err != nil { + log.Warnf("error reading archive %s: %v", tarPath, err) + http.Error(w, "error reading archive", http.StatusInternalServerError) + return + } + if hdr.Name != filename { + continue + } + w.Header().Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, filename)) + w.Header().Set("Content-Type", "application/octet-stream") + w.Header().Set("Content-Length", strconv.FormatInt(hdr.Size, 10)) + w.Header().Set("Accept-Ranges", "none") + w.Header().Set("Cache-Control", "no-cache") + if r.Method == http.MethodGet { + if _, err = io.Copy(w, tr); err != nil { + log.Warnf("failed to stream %s: %v", filename, err) + panic(http.ErrAbortHandler) + } + } + return + } } } diff --git a/central/cli/download_test.go b/central/cli/download_test.go new file mode 100644 index 0000000000000..7a32eee16e2d3 --- /dev/null +++ b/central/cli/download_test.go @@ -0,0 +1,139 @@ +package cli + +import ( + "archive/tar" + "compress/gzip" + "net/http" + "net/http/httptest" + "os" + "path/filepath" + "testing" + + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" +) + +func writeTarball(t *testing.T, dir, tarName, entryName string, content []byte) { + t.Helper() + f, err := os.Create(filepath.Join(dir, tarName+".tar.gz")) + require.NoError(t, err) + + gz := gzip.NewWriter(f) + tw := tar.NewWriter(gz) + err = tw.WriteHeader(&tar.Header{ + Name: entryName, + Size: int64(len(content)), + Mode: 0755, + }) + require.NoError(t, err) + _, err = tw.Write(content) + require.NoError(t, err) + require.NoError(t, tw.Close()) + require.NoError(t, gz.Close()) + require.NoError(t, f.Close()) +} + +type HandlerSuite struct { + suite.Suite + dir string + handler http.HandlerFunc + payload []byte +} + +func TestHandlerSuite(t *testing.T) { + suite.Run(t, new(HandlerSuite)) +} + +func (s *HandlerSuite) SetupTest() { + s.dir = s.T().TempDir() + s.handler = handlerWithDir(s.dir) + s.payload = []byte("fake roxctl binary content") + writeTarball(s.T(), s.dir, "roxctl-linux-amd64", "roxctl-linux-amd64", s.payload) + // Windows: tarball strips .exe from the name (required by release pipeline), + // but the entry inside the tarball preserves .exe. + writeTarball(s.T(), s.dir, "roxctl-windows-amd64", "roxctl-windows-amd64.exe", s.payload) +} + +func (s *HandlerSuite) TestServesLinuxBinaryViaGET() { + req := httptest.NewRequest(http.MethodGet, "/api/cli/download/roxctl-linux-amd64", nil) + rr := httptest.NewRecorder() + s.handler(rr, req) + s.Equal(http.StatusOK, rr.Code) + s.Equal(`attachment; filename="roxctl-linux-amd64"`, rr.Header().Get("Content-Disposition")) + s.Equal("application/octet-stream", rr.Header().Get("Content-Type")) + s.Equal("26", rr.Header().Get("Content-Length")) + s.Equal("none", rr.Header().Get("Accept-Ranges")) + s.Equal("no-cache", rr.Header().Get("Cache-Control")) + s.Equal(s.payload, rr.Body.Bytes()) +} + +func (s *HandlerSuite) TestServesWindowsBinaryViaGET() { + req := httptest.NewRequest(http.MethodGet, "/api/cli/download/roxctl-windows-amd64.exe", nil) + rr := httptest.NewRecorder() + s.handler(rr, req) + s.Equal(http.StatusOK, rr.Code) + s.Equal(`attachment; filename="roxctl-windows-amd64.exe"`, rr.Header().Get("Content-Disposition")) + s.Equal(s.payload, rr.Body.Bytes()) +} + +func (s *HandlerSuite) TestReturnsHeadersButNoBodyForHEAD() { + req := httptest.NewRequest(http.MethodHead, "/api/cli/download/roxctl-linux-amd64", nil) + rr := httptest.NewRecorder() + s.handler(rr, req) + s.Equal(http.StatusOK, rr.Code) + s.Equal("26", rr.Header().Get("Content-Length")) + s.Empty(rr.Body.Bytes()) +} + +func (s *HandlerSuite) TestReturns404ForMissingTarball() { + req := httptest.NewRequest(http.MethodGet, "/api/cli/download/roxctl-darwin-amd64", nil) + rr := httptest.NewRecorder() + s.handler(rr, req) + s.Equal(http.StatusNotFound, rr.Code) +} + +func (s *HandlerSuite) TestReturns404WhenBinaryNotInTarball() { + dir := s.T().TempDir() + // Tarball exists but entry name does not match the requested filename. + writeTarball(s.T(), dir, "roxctl-linux-amd64", "wrong-entry-name", s.payload) + handler := handlerWithDir(dir) + req := httptest.NewRequest(http.MethodGet, "/api/cli/download/roxctl-linux-amd64", nil) + rr := httptest.NewRecorder() + handler(rr, req) + s.Equal(http.StatusNotFound, rr.Code) +} + +func (s *HandlerSuite) TestReturns405ForUnsupportedMethod() { + req := httptest.NewRequest(http.MethodPost, "/api/cli/download/roxctl-linux-amd64", nil) + rr := httptest.NewRecorder() + s.handler(rr, req) + s.Equal(http.StatusMethodNotAllowed, rr.Code) + s.Equal("GET, HEAD", rr.Header().Get("Allow")) +} + +func (s *HandlerSuite) TestReturns500ForCorruptedGzip() { + dir := s.T().TempDir() + err := os.WriteFile(filepath.Join(dir, "roxctl-linux-amd64.tar.gz"), []byte("not a gzip"), 0600) + s.Require().NoError(err) + handler := handlerWithDir(dir) + req := httptest.NewRequest(http.MethodGet, "/api/cli/download/roxctl-linux-amd64", nil) + rr := httptest.NewRecorder() + handler(rr, req) + s.Equal(http.StatusInternalServerError, rr.Code) +} + +func (s *HandlerSuite) TestReturns500ForCorruptedTar() { + dir := s.T().TempDir() + f, err := os.Create(filepath.Join(dir, "roxctl-linux-amd64.tar.gz")) + s.Require().NoError(err) + gz := gzip.NewWriter(f) + _, err = gz.Write([]byte("valid gzip but not a tar")) + s.Require().NoError(err) + s.Require().NoError(gz.Close()) + s.Require().NoError(f.Close()) + handler := handlerWithDir(dir) + req := httptest.NewRequest(http.MethodGet, "/api/cli/download/roxctl-linux-amd64", nil) + rr := httptest.NewRecorder() + handler(rr, req) + s.Equal(http.StatusInternalServerError, rr.Code) +} diff --git a/central/cluster/datastore/datastore_impl.go b/central/cluster/datastore/datastore_impl.go index 62ed1dbc6dc4f..e5ba6cd046a0c 100644 --- a/central/cluster/datastore/datastore_impl.go +++ b/central/cluster/datastore/datastore_impl.go @@ -12,6 +12,7 @@ import ( "github.com/pkg/errors" alertDataStore "github.com/stackrox/rox/central/alert/datastore" + "github.com/stackrox/rox/central/cluster/lifecycle" clusterStore "github.com/stackrox/rox/central/cluster/store/cluster" clusterHealthStore "github.com/stackrox/rox/central/cluster/store/clusterhealth" clusterInitStore "github.com/stackrox/rox/central/clusterinit/store" @@ -207,18 +208,23 @@ func (ds *datastoreImpl) buildCache(ctx context.Context) error { ds.idToNameCache.Add(c.GetId(), c.GetName()) ds.nameToIDCache.Add(c.GetName(), c.GetId()) - if filter := clusterPkg.GetNamespaceFilter(c); filter != nil { + configuredFilterErr := clusterPkg.ValidateConfiguredNamespaceFilter(c) + if configuredFilterErr != nil { + log.Errorf("Could not compile filter regexp: %v", configuredFilterErr) + } + // Keep NoPersistence in effect even when the stored filter is invalid. + filter := clusterPkg.GetNamespaceFilter(c) + if filter != nil && (configuredFilterErr == nil || clusterPkg.IsNoPersistenceEnabled(c)) { compiledFilter, err := regexp.Compile(*filter) if err == nil { ds.idToNamespaceFilterCache.Add(c.GetId(), compiledFilter) } else { log.Errorf("Could not compile filter regexp: %v", err) + ds.idToNamespaceFilterCache.Remove(c.GetId()) } } else { - // We got empty filter building the cluster. There should be no - // prior cache at this point, but just in case make sure it's - // invalidated. + // Empty or invalid filters must not leave a stale cache entry. ds.idToNamespaceFilterCache.Remove(c.GetId()) } @@ -658,7 +664,9 @@ func (ds *datastoreImpl) RemoveCluster(ctx context.Context, id string, done *con return err } + release := lifecycle.Singleton().BeginDeletion(id) if err := ds.clusterStorage.Delete(ctx, id); err != nil { + release() return errors.Wrapf(err, "failed to remove cluster %q", id) } ds.idToNameCache.Remove(id) @@ -666,11 +674,12 @@ func (ds *datastoreImpl) RemoveCluster(ctx context.Context, id string, done *con ds.nameToIDCache.Remove(cluster.GetName()) deleteRelatedCtx := sac.WithAllAccess(context.Background()) - go ds.postRemoveCluster(deleteRelatedCtx, cluster, done) + go ds.postRemoveCluster(deleteRelatedCtx, cluster, done, release) return nil } -func (ds *datastoreImpl) postRemoveCluster(ctx context.Context, cluster *storage.Cluster, done *concurrency.Signal) { +func (ds *datastoreImpl) postRemoveCluster(ctx context.Context, cluster *storage.Cluster, done *concurrency.Signal, release func()) { + defer release() // Terminate the cluster connection to prevent new data from being stored. if ds.cm != nil { ds.cm.CloseConnection(cluster.GetId()) @@ -1054,6 +1063,7 @@ func (ds *datastoreImpl) updateClusterNoLock(ctx context.Context, cluster *stora ds.idToNamespaceFilterCache.Add(cluster.GetId(), compiledFilter) } else { log.Errorf("Could not compile filter regexp: %v", err) + ds.idToNamespaceFilterCache.Remove(cluster.GetId()) } } else { // We got empty filter updating the cluster. Make sure the cache is diff --git a/central/cluster/datastore/datastore_impl_test.go b/central/cluster/datastore/datastore_impl_test.go index 757824b7fa839..76a7a3ac57204 100644 --- a/central/cluster/datastore/datastore_impl_test.go +++ b/central/cluster/datastore/datastore_impl_test.go @@ -1,6 +1,7 @@ package datastore import ( + "context" "errors" "math" "regexp" @@ -434,7 +435,7 @@ func (s *clusterDataStoreTestSuite) TestPostRemoveCluster() { ctx := sac.WithAllAccess(s.T().Context()) doneSignal := concurrency.NewSignal() - s.datastore.postRemoveCluster(ctx, removedCluster, &doneSignal) + s.datastore.postRemoveCluster(ctx, removedCluster, &doneSignal, func() {}) doneSignal.Wait() }) @@ -987,8 +988,10 @@ func (s *clusterDataStoreTestSuite) TestUpdateCluster() { assert.Equal(s.T(), filter.(*regexp.Regexp).String(), "test-.*") } -func (s *clusterDataStoreTestSuite) TestUpdateClusterIncorrectFilter() { +func (s *clusterDataStoreTestSuite) TestUpdateClusterIncorrectFilterPreservesCache() { clusterID := fixtureconsts.Cluster1 + s.datastore.idToNamespaceFilterCache.Add(clusterID, regexp.MustCompile("previously-valid-.*")) + testCluster := &storage.Cluster{ Id: clusterID, Name: "test", @@ -1006,12 +1009,101 @@ func (s *clusterDataStoreTestSuite) TestUpdateClusterIncorrectFilter() { ctx := sac.WithAllAccess(s.T().Context()) - s.clusterStore.EXPECT(). - Upsert(gomock.Any(), gomock.Any()). - Return(nil) + err := s.datastore.updateClusterNoLock(ctx, testCluster) + s.ErrorContains(err, "invalid excluded namespaces filter") + + filter, ok := s.datastore.idToNamespaceFilterCache.Get(clusterID) + s.True(ok) + s.Equal("previously-valid-.*", filter.(*regexp.Regexp).String()) +} + +func (s *clusterDataStoreTestSuite) TestBuildCacheIncorrectFilter() { + clusterID := fixtureconsts.Cluster1 + s.datastore.idToNamespaceFilterCache.Add(clusterID, regexp.MustCompile("previously-valid-.*")) + + testCluster := &storage.Cluster{ + Id: clusterID, + Name: "test", + ManagedBy: storage.ManagerType_MANAGER_TYPE_HELM_CHART, + HelmConfig: &storage.CompleteClusterConfig{ + DynamicConfig: &storage.DynamicClusterConfig{ + ProcessIndicators: &storage.DynamicClusterConfig_ProcessIndicatorsConfig{ + ExcludeNamespaceFilter: "[", + }, + }, + }, + } + + s.clusterStore.EXPECT().Walk(gomock.Any(), gomock.Any()). + DoAndReturn(func(_ context.Context, fn func(*storage.Cluster) error) error { + return fn(testCluster) + }) + s.clusterHealthStore.EXPECT().Walk(gomock.Any(), gomock.Any()).Return(nil) + + err := s.datastore.buildCache(sac.WithAllAccess(s.T().Context())) + s.Require().NoError(err) + _, ok := s.datastore.idToNamespaceFilterCache.Get(clusterID) + s.False(ok) +} + +func (s *clusterDataStoreTestSuite) TestBuildCacheIncorrectFilterWithNoPersistence() { + clusterID := fixtureconsts.Cluster1 + testCluster := &storage.Cluster{ + Id: clusterID, + Name: "test", + ManagedBy: storage.ManagerType_MANAGER_TYPE_HELM_CHART, + HelmConfig: &storage.CompleteClusterConfig{ + DynamicConfig: &storage.DynamicClusterConfig{ + ProcessIndicators: &storage.DynamicClusterConfig_ProcessIndicatorsConfig{ + ExcludeNamespaceFilter: "[", + NoPersistence: true, + }, + }, + }, + } + s.datastore.idToNamespaceFilterCache.Add(clusterID, regexp.MustCompile("previously-valid-.*")) + s.clusterStore.EXPECT().Walk(gomock.Any(), gomock.Any()). + DoAndReturn(func(_ context.Context, fn func(*storage.Cluster) error) error { + return fn(testCluster) + }) + s.clusterHealthStore.EXPECT().Walk(gomock.Any(), gomock.Any()).Return(nil) + + err := s.datastore.buildCache(sac.WithAllAccess(s.T().Context())) + s.Require().NoError(err) + _, ok := s.datastore.idToNamespaceFilterCache.Get(clusterID) + s.Require().True(ok) + for _, namespace := range []string{"", "any-namespace"} { + matched, matchErr := s.datastore.MatchProcessIndicator(sac.WithAllAccess(s.T().Context()), + &storage.ProcessIndicator{ClusterId: clusterID, Namespace: namespace}) + s.NoError(matchErr) + s.True(matched) + } + name, ok := s.datastore.idToNameCache.Get(clusterID) + s.True(ok) + s.Equal("test", name) +} + +func (s *clusterDataStoreTestSuite) TestUpdateClusterIncorrectFilter() { + clusterID := fixtureconsts.Cluster1 + testCluster := &storage.Cluster{ + Id: clusterID, + Name: "test", + ManagedBy: storage.ManagerType_MANAGER_TYPE_HELM_CHART, + MainImage: "docker.io/stackrox/rox:latest", + HelmConfig: &storage.CompleteClusterConfig{ + DynamicConfig: &storage.DynamicClusterConfig{ + ProcessIndicators: &storage.DynamicClusterConfig_ProcessIndicatorsConfig{ + ExcludeNamespaceFilter: "[", + NoPersistence: false, + }, + }, + }, + } + + ctx := sac.WithAllAccess(s.T().Context()) err := s.datastore.updateClusterNoLock(ctx, testCluster) - s.NoError(err) + s.ErrorContains(err, "invalid excluded namespaces filter") filter, ok := s.datastore.idToNamespaceFilterCache.Get(clusterID) assert.False(s.T(), ok) diff --git a/central/cluster/lifecycle/gate.go b/central/cluster/lifecycle/gate.go new file mode 100644 index 0000000000000..cb1513f543220 --- /dev/null +++ b/central/cluster/lifecycle/gate.go @@ -0,0 +1,93 @@ +package lifecycle + +import ( + "github.com/stackrox/rox/pkg/concurrency" + "github.com/stackrox/rox/pkg/sync" +) + +// Gate serializes cluster deletion with writes that must not outlive the cluster. +type Gate struct { + mu sync.Mutex + entries map[string]*entry +} + +type entry struct { + mu sync.RWMutex + stateMu sync.Mutex + deleting bool + refs int +} + +var singleton = New() + +// Singleton returns the process-wide cluster lifecycle gate. +func Singleton() *Gate { + return singleton +} + +// New creates a cluster lifecycle gate. +func New() *Gate { + return &Gate{entries: make(map[string]*entry)} +} + +// Enter acquires a shared lifecycle lease unless deletion has started. The +// returned release function must be called when active is true. +func (g *Gate) Enter(clusterID string) (active bool, release func()) { + e := g.retain(clusterID) + + active = concurrency.WithLock1(&e.stateMu, func() bool { + if e.deleting { + return false + } + e.mu.RLock() + return true + }) + if !active { + g.release(clusterID, e) + return false, nil + } + + return true, func() { + concurrency.UnsafeRUnlock(&e.mu) + g.release(clusterID, e) + } +} + +// BeginDeletion prevents new active writes and waits for in-flight writes to finish. +// The returned function must be called once cluster cleanup completes. +func (g *Gate) BeginDeletion(clusterID string) func() { + e := g.retain(clusterID) + concurrency.WithLock(&e.stateMu, func() { + e.deleting = true + }) + // Drain in-flight read locks, then release. + concurrency.WithLock(&e.mu, func() {}) + + return func() { + concurrency.WithLock(&e.stateMu, func() { + e.deleting = false + }) + g.release(clusterID, e) + } +} + +func (g *Gate) retain(clusterID string) *entry { + g.mu.Lock() + defer g.mu.Unlock() + e := g.entries[clusterID] + if e == nil { + e = &entry{} + g.entries[clusterID] = e + } + e.refs++ + return e +} + +func (g *Gate) release(clusterID string, e *entry) { + g.mu.Lock() + defer g.mu.Unlock() + e.refs-- + if e.refs == 0 && !e.deleting { + delete(g.entries, clusterID) + } +} diff --git a/central/cluster/lifecycle/gate_test.go b/central/cluster/lifecycle/gate_test.go new file mode 100644 index 0000000000000..5ad0da55a097f --- /dev/null +++ b/central/cluster/lifecycle/gate_test.go @@ -0,0 +1,72 @@ +package lifecycle + +import ( + "runtime" + "testing" + "time" + + "github.com/stretchr/testify/require" +) + +func TestGateBlocksDeletionUntilActiveWriteCompletes(t *testing.T) { + clusterID := "cluster-id" + + gate := New() + writeStarted := make(chan struct{}) + releaseWrite := make(chan struct{}) + writeFinished := make(chan struct{}) + go func() { + active, release := gate.Enter(clusterID) + if !active { + t.Error("active write was rejected") + return + } + defer release() + close(writeStarted) + <-releaseWrite + close(writeFinished) + }() + <-writeStarted + + deletionStarted := make(chan func(), 1) + go func() { deletionStarted <- gate.BeginDeletion(clusterID) }() + require.Eventually(t, func() bool { + active, release := gate.Enter(clusterID) + if release != nil { + release() + } + + return !active + }, time.Second, 5*time.Millisecond) + + // yield -> to give additional cycles to BeginDeletion. + runtime.Gosched() + require.Empty(t, deletionStarted) + + close(releaseWrite) + <-writeFinished + releaseDeletion := <-deletionStarted + releaseDeletion() + + active, release := gate.Enter(clusterID) + require.True(t, active) + release() +} + +// TestBeginDeletionDropsWriteLockBeforeCleanup checks that BeginDeletion only +// holds the write lock long enough to drain in-flight leases. The dev mutex +// watchdog aborts the process if that lock stays held through cleanup. +func TestBeginDeletionDropsWriteLockBeforeCleanup(t *testing.T) { + gate := New() + releaseDeletion := gate.BeginDeletion("cluster-id") + t.Cleanup(releaseDeletion) + + e := gate.entries["cluster-id"] + require.NotNil(t, e) + require.True(t, e.mu.TryLock(), "write lock still held after BeginDeletion returned") + e.mu.Unlock() + + active, release := gate.Enter("cluster-id") + require.False(t, active) + require.Nil(t, release) +} diff --git a/central/clusters/deployer.go b/central/clusters/deployer.go index 8e01487cf2385..c7a8f1f38b449 100644 --- a/central/clusters/deployer.go +++ b/central/clusters/deployer.go @@ -32,7 +32,6 @@ func FieldsFromClusterAndRenderOpts(c *storage.Cluster, imageFlavor *defaults.Im baseValues := getBaseMetaValues(c, imageFlavor, imageFlavor.ChartRepo, &opts) setMainOverride(mainImage, baseValues) - deriveScannerRemoteFromMain(mainImage, baseValues) baseValues.EnablePodSecurityPolicies = !opts.DisablePodSecurityPolicies collector := determineCollectorImage(mainImage, collectorImage, imageFlavor) @@ -61,15 +60,6 @@ func MakeClusterImageNames(flavor *defaults.ImageFlavor, c *storage.Cluster) (*s return mainImageName, collectorImageName, nil } -// deriveScannerRemoteFromMain sets scanner-slim image remote, so that it comes from the same location as the main image -func deriveScannerRemoteFromMain(mainImage *storage.ImageName, metaValues *charts.MetaValues) { - scannerRemoteSlice := strings.Split(mainImage.GetRemote(), "/") - if len(scannerRemoteSlice) > 0 { - scannerRemoteSlice[len(scannerRemoteSlice)-1] = metaValues.ScannerSlimImageRemote - metaValues.ScannerSlimImageRemote = strings.Join(scannerRemoteSlice, "/") - } -} - // setMainOverride adds main image values to meta values as defined in secured cluster object. func setMainOverride(mainImage *storage.ImageName, metaValues *charts.MetaValues) { metaValues.MainRegistry = mainImage.GetRegistry() @@ -151,9 +141,6 @@ func getBaseMetaValues(c *storage.Cluster, imageFlavor *defaults.ImageFlavor, ch FactImageTag: versions.FactVersion, FactImageRemote: imageFlavor.FactImageName, - ScannerImageTag: versions.ScannerVersion, - ScannerSlimImageRemote: imageFlavor.ScannerSlimImageName, - KubectlOutput: true, Versions: versions, diff --git a/central/clusters/deployer_test.go b/central/clusters/deployer_test.go index c0b7ed70d8ef2..08e800b6dc56d 100644 --- a/central/clusters/deployer_test.go +++ b/central/clusters/deployer_test.go @@ -18,10 +18,6 @@ func getCollectorImage(fields *charts.MetaValues) string { return fmt.Sprintf("%s/%s:%s", fields.CollectorRegistry, fields.CollectorImageRemote, fields.CollectorImageTag) } -func getScannerSlim(fields *charts.MetaValues) string { - return fmt.Sprintf("%s/%s:%s", fields.MainRegistry, fields.ScannerSlimImageRemote, fields.ScannerImageTag) -} - func getMain(fields *charts.MetaValues) string { return fmt.Sprintf("%s/%s:%s", fields.MainRegistry, fields.ImageRemote, fields.ImageTag) } @@ -114,121 +110,102 @@ func testMetaValueGenerationWithImageFlavor(s *deployerTestSuite, flavor default defaultMainImage := flavor.MainImage() defaultCollectorImageNoTag := flavor.CollectorImageNoTag() defaultCollectorImage := flavor.CollectorImage() - defaultScannerSlimImage := flavor.ScannerSlimImage() var cases = map[string]struct { - cluster *storage.Cluster - expectedErrorMessage string - expectedMain string - expectedCollectorRef string - expectedScannerSlimRef string + cluster *storage.Cluster + expectedErrorMessage string + expectedMain string + expectedCollectorRef string }{ // we're testing possible main & collector combinations, grouped by main image setting // default main image "default main / no collector": { - cluster: makeTestCluster(defaultMainImageNoTag, ""), - expectedMain: defaultMainImage, - expectedCollectorRef: defaultCollectorImage, - expectedScannerSlimRef: defaultScannerSlimImage, + cluster: makeTestCluster(defaultMainImageNoTag, ""), + expectedMain: defaultMainImage, + expectedCollectorRef: defaultCollectorImage, }, "default main / default collector": { - cluster: makeTestCluster(defaultMainImageNoTag, defaultCollectorImageNoTag), - expectedMain: defaultMainImage, - expectedCollectorRef: defaultCollectorImage, - expectedScannerSlimRef: defaultScannerSlimImage, + cluster: makeTestCluster(defaultMainImageNoTag, defaultCollectorImageNoTag), + expectedMain: defaultMainImage, + expectedCollectorRef: defaultCollectorImage, }, "default main / default collector: custom tag": { - cluster: makeTestCluster(defaultMainImageNoTag, fmt.Sprintf("%s:custom", defaultCollectorImageNoTag)), - expectedMain: defaultMainImage, - expectedCollectorRef: flavor.CollectorImage(), - expectedScannerSlimRef: defaultScannerSlimImage, + cluster: makeTestCluster(defaultMainImageNoTag, fmt.Sprintf("%s:custom", defaultCollectorImageNoTag)), + expectedMain: defaultMainImage, + expectedCollectorRef: flavor.CollectorImage(), }, "default main / custom collector: with namespace": { - cluster: makeTestCluster(defaultMainImage, "quay.io/rhacs/collector"), - expectedMain: defaultMainImage, - expectedCollectorRef: fmt.Sprintf("quay.io/rhacs/collector:%s", flavor.CollectorImageTag), - expectedScannerSlimRef: defaultScannerSlimImage, + cluster: makeTestCluster(defaultMainImage, "quay.io/rhacs/collector"), + expectedMain: defaultMainImage, + expectedCollectorRef: fmt.Sprintf("quay.io/rhacs/collector:%s", flavor.CollectorImageTag), }, "default main / custom collector: with namespace & custom tag": { - cluster: makeTestCluster(defaultMainImage, "quay.io/rhacs/collector:custom"), - expectedMain: defaultMainImage, - expectedCollectorRef: fmt.Sprintf("quay.io/rhacs/collector:%s", flavor.CollectorImageTag), - expectedScannerSlimRef: defaultScannerSlimImage, + cluster: makeTestCluster(defaultMainImage, "quay.io/rhacs/collector:custom"), + expectedMain: defaultMainImage, + expectedCollectorRef: fmt.Sprintf("quay.io/rhacs/collector:%s", flavor.CollectorImageTag), }, "default main / custom collector: without namespace": { - cluster: makeTestCluster(defaultMainImage, "example.io/collector"), - expectedMain: defaultMainImage, - expectedCollectorRef: fmt.Sprintf("example.io/collector:%s", flavor.CollectorImageTag), - expectedScannerSlimRef: defaultScannerSlimImage, + cluster: makeTestCluster(defaultMainImage, "example.io/collector"), + expectedMain: defaultMainImage, + expectedCollectorRef: fmt.Sprintf("example.io/collector:%s", flavor.CollectorImageTag), }, "default main / custom collector: without namespace & custom tag": { - cluster: makeTestCluster(defaultMainImage, "example.io/collector:custom"), - expectedMain: defaultMainImage, - expectedCollectorRef: fmt.Sprintf("example.io/collector:%s", flavor.CollectorImageTag), - expectedScannerSlimRef: defaultScannerSlimImage, + cluster: makeTestCluster(defaultMainImage, "example.io/collector:custom"), + expectedMain: defaultMainImage, + expectedCollectorRef: fmt.Sprintf("example.io/collector:%s", flavor.CollectorImageTag), }, "default main: custom tag / no collector": { - cluster: makeTestCluster(fmt.Sprintf("%s:custom", defaultMainImageNoTag), ""), - expectedMain: fmt.Sprintf("%s:custom", defaultMainImageNoTag), - expectedCollectorRef: defaultCollectorImage, - expectedScannerSlimRef: defaultScannerSlimImage, + cluster: makeTestCluster(fmt.Sprintf("%s:custom", defaultMainImageNoTag), ""), + expectedMain: fmt.Sprintf("%s:custom", defaultMainImageNoTag), + expectedCollectorRef: defaultCollectorImage, }, "default main: custom tag / default collector": { - cluster: makeTestCluster(fmt.Sprintf("%s:custom", defaultMainImageNoTag), ""), - expectedMain: fmt.Sprintf("%s:custom", defaultMainImageNoTag), - expectedCollectorRef: defaultCollectorImage, - expectedScannerSlimRef: defaultScannerSlimImage, + cluster: makeTestCluster(fmt.Sprintf("%s:custom", defaultMainImageNoTag), ""), + expectedMain: fmt.Sprintf("%s:custom", defaultMainImageNoTag), + expectedCollectorRef: defaultCollectorImage, }, "default main: custom registry / no collector": { - cluster: makeTestCluster("quay.io/rhacs/"+flavor.MainImageName, ""), - expectedMain: fmt.Sprintf("quay.io/rhacs/%s:%s", flavor.MainImageName, flavor.MainImageTag), - expectedCollectorRef: fmt.Sprintf("quay.io/rhacs/%s:%s", flavor.CollectorImageName, flavor.CollectorImageTag), - expectedScannerSlimRef: fmt.Sprintf("quay.io/rhacs/%s:%s", flavor.ScannerSlimImageName, flavor.ScannerImageTag), + cluster: makeTestCluster("quay.io/rhacs/"+flavor.MainImageName, ""), + expectedMain: fmt.Sprintf("quay.io/rhacs/%s:%s", flavor.MainImageName, flavor.MainImageTag), + expectedCollectorRef: fmt.Sprintf("quay.io/rhacs/%s:%s", flavor.CollectorImageName, flavor.CollectorImageTag), }, // custom main image "custom main: with namespace / no collector": { - cluster: makeTestCluster("quay.io/rhacs/main", ""), - expectedMain: fmt.Sprintf("quay.io/rhacs/main:%s", flavor.MainImageTag), - expectedCollectorRef: fmt.Sprintf("quay.io/rhacs/%s:%s", flavor.CollectorImageName, flavor.CollectorImageTag), - expectedScannerSlimRef: fmt.Sprintf("quay.io/rhacs/%s:%s", flavor.ScannerSlimImageName, flavor.ScannerImageTag), + cluster: makeTestCluster("quay.io/rhacs/main", ""), + expectedMain: fmt.Sprintf("quay.io/rhacs/main:%s", flavor.MainImageTag), + expectedCollectorRef: fmt.Sprintf("quay.io/rhacs/%s:%s", flavor.CollectorImageName, flavor.CollectorImageTag), }, "custom main: without namespace / no collector": { - cluster: makeTestCluster("example.io/main", ""), - expectedMain: fmt.Sprintf("example.io/main:%s", flavor.MainImageTag), - expectedCollectorRef: fmt.Sprintf("example.io/%s:%s", flavor.CollectorImageName, flavor.CollectorImageTag), - expectedScannerSlimRef: fmt.Sprintf("example.io/%s:%s", flavor.ScannerSlimImageName, flavor.ScannerImageTag), + cluster: makeTestCluster("example.io/main", ""), + expectedMain: fmt.Sprintf("example.io/main:%s", flavor.MainImageTag), + expectedCollectorRef: fmt.Sprintf("example.io/%s:%s", flavor.CollectorImageName, flavor.CollectorImageTag), }, "custom main / default collector": { - cluster: makeTestCluster("quay.io/rhacs/main", defaultCollectorImageNoTag), - expectedMain: fmt.Sprintf("quay.io/rhacs/main:%s", flavor.MainImageTag), - expectedCollectorRef: defaultCollectorImage, - expectedScannerSlimRef: fmt.Sprintf("quay.io/rhacs/%s:%s", flavor.ScannerSlimImageName, flavor.ScannerImageTag), + cluster: makeTestCluster("quay.io/rhacs/main", defaultCollectorImageNoTag), + expectedMain: fmt.Sprintf("quay.io/rhacs/main:%s", flavor.MainImageTag), + expectedCollectorRef: defaultCollectorImage, }, "custom main / custom collector: with namespace": { - cluster: makeTestCluster("quay.io/rhacs/main", "quay.io/rhacs/collector"), - expectedMain: fmt.Sprintf("quay.io/rhacs/main:%s", flavor.MainImageTag), - expectedCollectorRef: fmt.Sprintf("quay.io/rhacs/collector:%s", flavor.CollectorImageTag), - expectedScannerSlimRef: fmt.Sprintf("quay.io/rhacs/%s:%s", flavor.ScannerSlimImageName, flavor.ScannerImageTag), + cluster: makeTestCluster("quay.io/rhacs/main", "quay.io/rhacs/collector"), + expectedMain: fmt.Sprintf("quay.io/rhacs/main:%s", flavor.MainImageTag), + expectedCollectorRef: fmt.Sprintf("quay.io/rhacs/collector:%s", flavor.CollectorImageTag), }, "custom main / custom collector: with namespace & custom tag": { - cluster: makeTestCluster("quay.io/rhacs/main", "quay.io/rhacs/collector:custom"), - expectedMain: fmt.Sprintf("quay.io/rhacs/main:%s", flavor.MainImageTag), - expectedCollectorRef: fmt.Sprintf("quay.io/rhacs/collector:%s", flavor.CollectorImageTag), - expectedScannerSlimRef: fmt.Sprintf("quay.io/rhacs/%s:%s", flavor.ScannerSlimImageName, flavor.ScannerImageTag), + cluster: makeTestCluster("quay.io/rhacs/main", "quay.io/rhacs/collector:custom"), + expectedMain: fmt.Sprintf("quay.io/rhacs/main:%s", flavor.MainImageTag), + expectedCollectorRef: fmt.Sprintf("quay.io/rhacs/collector:%s", flavor.CollectorImageTag), }, "custom main / custom collector: without namespace": { - cluster: makeTestCluster("quay.io/rhacs/main", "example.io/collector"), - expectedMain: fmt.Sprintf("quay.io/rhacs/main:%s", flavor.MainImageTag), - expectedCollectorRef: fmt.Sprintf("example.io/collector:%s", flavor.CollectorImageTag), - expectedScannerSlimRef: fmt.Sprintf("quay.io/rhacs/%s:%s", flavor.ScannerSlimImageName, flavor.ScannerImageTag), + cluster: makeTestCluster("quay.io/rhacs/main", "example.io/collector"), + expectedMain: fmt.Sprintf("quay.io/rhacs/main:%s", flavor.MainImageTag), + expectedCollectorRef: fmt.Sprintf("example.io/collector:%s", flavor.CollectorImageTag), }, "custom main / custom collector: without namespace & custom tag": { - cluster: makeTestCluster("quay.io/rhacs/main", "example.io/collector:custom"), - expectedMain: fmt.Sprintf("quay.io/rhacs/main:%s", flavor.MainImageTag), - expectedCollectorRef: fmt.Sprintf("example.io/collector:%s", flavor.CollectorImageTag), - expectedScannerSlimRef: fmt.Sprintf("quay.io/rhacs/%s:%s", flavor.ScannerSlimImageName, flavor.ScannerImageTag), + cluster: makeTestCluster("quay.io/rhacs/main", "example.io/collector:custom"), + expectedMain: fmt.Sprintf("quay.io/rhacs/main:%s", flavor.MainImageTag), + expectedCollectorRef: fmt.Sprintf("example.io/collector:%s", flavor.CollectorImageTag), }, /* // These tests are failing right now but should succeed after ROX-15691 has been implemented @@ -244,16 +221,14 @@ func testMetaValueGenerationWithImageFlavor(s *deployerTestSuite, flavor default }, */ "custom main / custom collector: same registry, different namespaces": { - cluster: makeTestCluster("quay.io/namespace-a/main", "quay.io/namespace-b/collector"), - expectedMain: fmt.Sprintf("quay.io/namespace-a/main:%s", flavor.MainImageTag), - expectedCollectorRef: fmt.Sprintf("quay.io/namespace-b/collector:%s", flavor.CollectorImageTag), - expectedScannerSlimRef: fmt.Sprintf("quay.io/namespace-a/%s:%s", flavor.ScannerSlimImageName, flavor.ScannerImageTag), + cluster: makeTestCluster("quay.io/namespace-a/main", "quay.io/namespace-b/collector"), + expectedMain: fmt.Sprintf("quay.io/namespace-a/main:%s", flavor.MainImageTag), + expectedCollectorRef: fmt.Sprintf("quay.io/namespace-b/collector:%s", flavor.CollectorImageTag), }, "custom main: non-default name / no collector": { - cluster: makeTestCluster("quay.io/rhacs/customname", ""), - expectedMain: fmt.Sprintf("quay.io/rhacs/customname:%s", flavor.MainImageTag), - expectedCollectorRef: fmt.Sprintf("quay.io/rhacs/%s:%s", flavor.CollectorImageName, flavor.CollectorImageTag), - expectedScannerSlimRef: fmt.Sprintf("quay.io/rhacs/%s:%s", flavor.ScannerSlimImageName, flavor.ScannerImageTag), + cluster: makeTestCluster("quay.io/rhacs/customname", ""), + expectedMain: fmt.Sprintf("quay.io/rhacs/customname:%s", flavor.MainImageTag), + expectedCollectorRef: fmt.Sprintf("quay.io/rhacs/%s:%s", flavor.CollectorImageName, flavor.CollectorImageTag), }, // Expected fail cases "expectedError: empty main image": { @@ -280,7 +255,6 @@ func testMetaValueGenerationWithImageFlavor(s *deployerTestSuite, flavor default s.NoError(err) s.Equal(c.expectedMain, getMain(fields), "Main image does not match") s.Equal(c.expectedCollectorRef, getCollectorImage(fields), "Collector image does not match") - s.Equal(c.expectedScannerSlimRef, getScannerSlim(fields), "Scanner slim image does not match") } }) } @@ -338,7 +312,6 @@ func TestRequiredFieldsArePresent(t *testing.T) { assert.NotEmpty(t, fields.Versions.ChartVersion) assert.NotEmpty(t, fields.Versions.MainVersion) assert.NotEmpty(t, fields.Versions.CollectorVersion) - assert.NotEmpty(t, fields.Versions.ScannerVersion) assert.NotEmpty(t, fields.ChartRepo.URL) } diff --git a/central/delegatedregistryconfig/delegator/delegator.go b/central/delegatedregistryconfig/delegator/delegator.go index 00af344df8377..c1e128ad0ed97 100644 --- a/central/delegatedregistryconfig/delegator/delegator.go +++ b/central/delegatedregistryconfig/delegator/delegator.go @@ -6,6 +6,7 @@ import ( "time" "github.com/pkg/errors" + clusterDS "github.com/stackrox/rox/central/cluster/datastore" "github.com/stackrox/rox/central/delegatedregistryconfig/datastore" deleConnection "github.com/stackrox/rox/central/delegatedregistryconfig/util/connection" centralMetrics "github.com/stackrox/rox/central/metrics" @@ -31,13 +32,14 @@ var ( ) // New creates a new delegator. -func New(deleRegConfigDS datastore.DataStore, connManager connection.Manager, scanWaiterManager waiter.Manager[*storage.Image], scanWaiterManagerV2 waiter.Manager[*storage.ImageV2], namespaceSACHelper sachelper.ClusterNamespaceSacHelper) *delegatorImpl { +func New(deleRegConfigDS datastore.DataStore, connManager connection.Manager, scanWaiterManager waiter.Manager[*storage.Image], scanWaiterManagerV2 waiter.Manager[*storage.ImageV2], namespaceSACHelper sachelper.ClusterNamespaceSacHelper, clusterDataStore clusterDS.DataStore) *delegatorImpl { return &delegatorImpl{ deleRegConfigDS: deleRegConfigDS, connManager: connManager, scanWaiterManager: scanWaiterManager, scanWaiterManagerV2: scanWaiterManagerV2, namespaceSACHelper: namespaceSACHelper, + clusterDataStore: clusterDataStore, } } @@ -48,6 +50,10 @@ type delegatorImpl struct { // namespaceSACHelper for confirming namespace exists and user has access. namespaceSACHelper sachelper.ClusterNamespaceSacHelper + // clusterDataStore for resolving cluster names in user-facing messages within + // the requester's scope. + clusterDataStore clusterDS.DataStore + // connManager for sending scan requests to secured clusters and ensuring // clusters are valid for delegation. connManager connection.Manager @@ -79,7 +85,7 @@ func (d *delegatorImpl) GetDelegateClusterID(ctx context.Context, imgName *stora return "", true, delegatedregistry.ErrNoClusterSpecified } - if err := d.ValidateCluster(clusterID); err != nil { + if err := d.ValidateCluster(ctx, clusterID); err != nil { return "", true, err } @@ -264,19 +270,34 @@ func (d *delegatorImpl) shouldDelegate(imgName *storage.ImageName, config *stora } // ValidateCluster returns nil if a cluster is a valid target for delegation, otherwise returns an error. -func (d *delegatorImpl) ValidateCluster(clusterID string) error { +func (d *delegatorImpl) ValidateCluster(ctx context.Context, clusterID string) error { conn := d.connManager.GetConnection(clusterID) if conn == nil { - return errors.Errorf("no connection to %q", clusterID) + return errors.Errorf("no connection to cluster %q (%s), verify the cluster is healthy and connected", d.clusterName(ctx, clusterID), clusterID) } if !deleConnection.ValidForDelegation(conn) { - return errors.Errorf("cluster %q does not support delegated scanning", clusterID) + return errors.Errorf("cluster %q (%s) does not support delegated scanning", d.clusterName(ctx, clusterID), clusterID) } return nil } +// clusterName resolves a human-readable cluster name for user-facing messages, +// falling back to the cluster ID when the name cannot be resolved within the +// requester's scope. +func (d *delegatorImpl) clusterName(ctx context.Context, clusterID string) string { + // GetClusterName enforces a cluster-read SAC check against the passed context, so + // resolving under the requester's own (non-elevated) context reveals the name only + // to callers allowed to view this cluster. Everyone else keeps the opaque ID. + name, exists, err := d.clusterDataStore.GetClusterName(ctx, clusterID) + if err != nil || !exists { + return clusterID + } + + return name +} + // withAdminRead elevates a context to include admin read access. func withAdminRead(ctx context.Context) context.Context { elevatedCtx := sac.WithGlobalAccessScopeChecker( diff --git a/central/delegatedregistryconfig/delegator/delegator_test.go b/central/delegatedregistryconfig/delegator/delegator_test.go index 3f955add7c913..9532d6a952e9b 100644 --- a/central/delegatedregistryconfig/delegator/delegator_test.go +++ b/central/delegatedregistryconfig/delegator/delegator_test.go @@ -6,6 +6,7 @@ import ( "fmt" "testing" + clusterDSMocks "github.com/stackrox/rox/central/cluster/datastore/mocks" deleDSMocks "github.com/stackrox/rox/central/delegatedregistryconfig/datastore/mocks" sacHelperMocks "github.com/stackrox/rox/central/role/sachelper/mocks" connMocks "github.com/stackrox/rox/central/sensor/service/connection/mocks" @@ -51,7 +52,9 @@ func TestGetDelegateClusterID(t *testing.T) { connMgr = connMocks.NewMockManager(ctrl) waiterMgr = waiterMocks.NewMockManager[*storage.Image](ctrl) deleClusterDS = deleDSMocks.NewMockDataStore(ctrl) - d = New(deleClusterDS, connMgr, waiterMgr, nil, nil) + clusterDS := clusterDSMocks.NewMockDataStore(ctrl) + clusterDS.EXPECT().GetClusterName(gomock.Any(), gomock.Any()).Return("fake-cluster-name", true, nil).AnyTimes() + d = New(deleClusterDS, connMgr, waiterMgr, nil, nil, clusterDS) } t.Run("error get config", func(t *testing.T) { @@ -111,7 +114,7 @@ func TestGetDelegateClusterID(t *testing.T) { connMgr.EXPECT().GetConnection(gomock.Any()).Return(nil) _, shouldDelegate, err := d.GetDelegateClusterID(ctxBG, nil) assert.True(t, shouldDelegate) - assert.ErrorContains(t, err, "no connection") + assert.ErrorContains(t, err, "no connection to cluster") }) t.Run("all def cluster id conn no cap", func(t *testing.T) { @@ -263,7 +266,7 @@ func TestDelegateEnrichImage(t *testing.T) { namespaceSACHelper = sacHelperMocks.NewMockClusterNamespaceSacHelper(ctrl) waiter.EXPECT().ID().Return(fakeWaiterID).AnyTimes() - d = New(deleClusterDS, connMgr, waiterMgr, nil, namespaceSACHelper) + d = New(deleClusterDS, connMgr, waiterMgr, nil, namespaceSACHelper, nil) } t.Run("empty cluster id", func(t *testing.T) { @@ -357,7 +360,7 @@ func TestDelegateScanImageV2(t *testing.T) { namespaceSACHelper = sacHelperMocks.NewMockClusterNamespaceSacHelper(ctrl) waiter.EXPECT().ID().Return(fakeWaiterID).AnyTimes() - d = New(deleClusterDS, connMgr, nil, waiterMgr, namespaceSACHelper) + d = New(deleClusterDS, connMgr, nil, waiterMgr, namespaceSACHelper, nil) } t.Run("empty cluster id", func(t *testing.T) { @@ -440,7 +443,7 @@ func TestInferNamespace(t *testing.T) { ctrl := gomock.NewController(t) namespaceSACHelper = sacHelperMocks.NewMockClusterNamespaceSacHelper(ctrl) - d = New(nil, nil, nil, nil, namespaceSACHelper) + d = New(nil, nil, nil, nil, namespaceSACHelper, nil) } t.Run("no namespace on error", func(t *testing.T) { diff --git a/central/deployment/datastore/datastore.go b/central/deployment/datastore/datastore.go index 67210757b8e23..8b9bb033ff99c 100644 --- a/central/deployment/datastore/datastore.go +++ b/central/deployment/datastore/datastore.go @@ -34,6 +34,8 @@ type DataStore interface { ListDeployment(ctx context.Context, id string) (*storage.ListDeployment, bool, error) GetDeployment(ctx context.Context, id string) (*storage.Deployment, bool, error) + // DeploymentExists reports whether the deployment is stored, without fetching or copying it. + DeploymentExists(ctx context.Context, id string) (bool, error) GetDeployments(ctx context.Context, ids []string) ([]*storage.Deployment, error) CountDeployments(ctx context.Context) (int, error) // UpsertDeployment adds or updates a deployment. If the deployment exists, the tags in the deployment are taken from diff --git a/central/deployment/datastore/datastore_impl.go b/central/deployment/datastore/datastore_impl.go index 196a6af2b98fa..4c69aa96b9a0b 100644 --- a/central/deployment/datastore/datastore_impl.go +++ b/central/deployment/datastore/datastore_impl.go @@ -227,6 +227,11 @@ func (ds *datastoreImpl) GetDeployment(ctx context.Context, id string) (*storage return deployment, true, nil } +// DeploymentExists +func (ds *datastoreImpl) DeploymentExists(ctx context.Context, id string) (bool, error) { + return ds.deploymentStore.Exists(ctx, id) +} + // GetDeployments func (ds *datastoreImpl) GetDeployments(ctx context.Context, ids []string) ([]*storage.Deployment, error) { var deployments []*storage.Deployment @@ -361,7 +366,8 @@ func (ds *datastoreImpl) RemoveDeployment(ctx context.Context, clusterID, id str return sac.ErrResourceAccessDenied } // Dedupe the removed deployments. This can happen because Pods have many completion states - // and we may receive multiple Remove calls + // and we may receive multiple Remove calls. Marking up front also stops concurrent UpsertFlows + // from writing flows for the deployment while it is being removed. if ds.deletedDeploymentCache != nil { if ds.deletedDeploymentCache.Contains(id) { return nil @@ -387,22 +393,20 @@ func (ds *datastoreImpl) RemoveDeployment(ctx context.Context, clusterID, id str errorList.AddError(err) } - flowStore, err := ds.networkFlows.GetFlowStore(deleteRelatedCtx, clusterID) - if err != nil { - errorList.AddError(err) - return errorList.ToError() - } - - if err := flowStore.RemoveFlowsForDeployment(deleteRelatedCtx, id); err != nil { - errorList.AddError(err) + // clusterID is nullable in the DB; guard against an empty value to avoid an error from flow store. + if clusterID != "" { + // A missing flow store must not block the delete, else deployments of a deleted cluster + // could never be pruned. + if flowStore, err := ds.networkFlows.GetFlowStore(deleteRelatedCtx, clusterID); err != nil { + errorList.AddError(err) + } else if err := flowStore.RemoveFlowsForDeployment(deleteRelatedCtx, id); err != nil { + errorList.AddError(err) + } } // Delete should be last to ensure that the above is always cleaned up even in the case of crash - err = ds.keyedMutex.DoStatusWithLock(id, func() error { - if err := ds.deploymentStore.Delete(ctx, id); err != nil { - return err - } - return nil + err := ds.keyedMutex.DoStatusWithLock(id, func() error { + return ds.deploymentStore.Delete(ctx, id) }) if err != nil { errorList.AddError(err) diff --git a/central/deployment/datastore/datastore_impl_test.go b/central/deployment/datastore/datastore_impl_test.go index 04c1d610f3f37..4440e5631294f 100644 --- a/central/deployment/datastore/datastore_impl_test.go +++ b/central/deployment/datastore/datastore_impl_test.go @@ -2,10 +2,13 @@ package datastore import ( "context" + "errors" "testing" storeMocks "github.com/stackrox/rox/central/deployment/datastore/internal/store/mocks" + flowMocks "github.com/stackrox/rox/central/networkgraph/flow/datastore/mocks" matcherMocks "github.com/stackrox/rox/central/platform/matcher/mocks" + baselineMocks "github.com/stackrox/rox/central/processbaseline/datastore/mocks" "github.com/stackrox/rox/central/ranking" riskMocks "github.com/stackrox/rox/central/risk/datastore/mocks" v1 "github.com/stackrox/rox/generated/api/v1" @@ -98,6 +101,50 @@ func (suite *DeploymentDataStoreTestSuite) TestInitializeRanker() { suite.Equal(int64(3), deploymentRanker.GetRankForID("3")) } +// Regression: a failed flow store lookup must not block the row delete, else +// deployments of an already-deleted cluster could never be pruned. +func (suite *DeploymentDataStoreTestSuite) TestRemoveDeploymentDeletesRowWhenFlowStoreLookupFails() { + baselines := baselineMocks.NewMockDataStore(suite.mockCtrl) + flows := flowMocks.NewMockClusterDataStore(suite.mockCtrl) + + ds := newDatastoreImpl(suite.storage, nil, nil, baselines, flows, suite.riskStore, nil, suite.filter, + ranking.NewRanker(), ranking.NewRanker(), ranking.NewRanker(), suite.matcher) + + const clusterID = "c1" + const deploymentID = "d1" + + suite.riskStore.EXPECT().RemoveRisk(gomock.Any(), deploymentID, gomock.Any()).Return(nil) + baselines.EXPECT().RemoveProcessBaselinesByDeployment(gomock.Any(), deploymentID).Return(nil) + flows.EXPECT().GetFlowStore(gomock.Any(), clusterID).Return(nil, errors.New("flow store gone")) + // The deployment row must still be deleted despite the flow-store failure. + suite.storage.EXPECT().Delete(gomock.Any(), deploymentID).Return(nil) + + err := ds.RemoveDeployment(suite.ctx, clusterID, deploymentID) + suite.Require().Error(err) + suite.ErrorContains(err, "flow store gone") +} + +// An empty clusterID (e.g. an orphaned deployment whose clusterid column is NULL) has no +// flow partition, so the flow store lookup must be skipped rather than dereferencing a nil +// store, while the row is still deleted. +func (suite *DeploymentDataStoreTestSuite) TestRemoveDeploymentSkipsFlowStoreWhenClusterIDEmpty() { + baselines := baselineMocks.NewMockDataStore(suite.mockCtrl) + flows := flowMocks.NewMockClusterDataStore(suite.mockCtrl) + + ds := newDatastoreImpl(suite.storage, nil, nil, baselines, flows, suite.riskStore, nil, suite.filter, + ranking.NewRanker(), ranking.NewRanker(), ranking.NewRanker(), suite.matcher) + + const deploymentID = "d1" + + suite.riskStore.EXPECT().RemoveRisk(gomock.Any(), deploymentID, gomock.Any()).Return(nil) + baselines.EXPECT().RemoveProcessBaselinesByDeployment(gomock.Any(), deploymentID).Return(nil) + // flows.GetFlowStore must not be called for an empty clusterID; the mock has no + // expectation set, so any call would fail the test. + suite.storage.EXPECT().Delete(gomock.Any(), deploymentID).Return(nil) + + suite.Require().NoError(ds.RemoveDeployment(suite.ctx, "", deploymentID)) +} + func walkMockFunc(deployments []*storage.Deployment) func(_ context.Context, _ *v1.Query, fn func(group *storage.Deployment) error) error { return func(_ context.Context, _ *v1.Query, fn func(deployment *storage.Deployment) error) error { for _, g := range deployments { diff --git a/central/deployment/datastore/internal/store/mocks/store.go b/central/deployment/datastore/internal/store/mocks/store.go index 455b7c14e2d08..10a0a236b9c4c 100644 --- a/central/deployment/datastore/internal/store/mocks/store.go +++ b/central/deployment/datastore/internal/store/mocks/store.go @@ -73,6 +73,21 @@ func (mr *MockStoreMockRecorder) Delete(ctx, id any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockStore)(nil).Delete), ctx, id) } +// Exists mocks base method. +func (m *MockStore) Exists(ctx context.Context, id string) (bool, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Exists", ctx, id) + ret0, _ := ret[0].(bool) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Exists indicates an expected call of Exists. +func (mr *MockStoreMockRecorder) Exists(ctx, id any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Exists", reflect.TypeOf((*MockStore)(nil).Exists), ctx, id) +} + // Get mocks base method. func (m *MockStore) Get(ctx context.Context, id string) (*storage.Deployment, bool, error) { m.ctrl.T.Helper() diff --git a/central/deployment/datastore/internal/store/store.go b/central/deployment/datastore/internal/store/store.go index 19a7d3ea50ca5..b2f155aa1cf6e 100644 --- a/central/deployment/datastore/internal/store/store.go +++ b/central/deployment/datastore/internal/store/store.go @@ -18,6 +18,7 @@ type Store interface { SearchListDeployments(ctx context.Context, q *v1.Query) ([]*storage.ListDeployment, error) Get(ctx context.Context, id string) (*storage.Deployment, bool, error) + Exists(ctx context.Context, id string) (bool, error) GetMany(ctx context.Context, ids []string) ([]*storage.Deployment, []int, error) Walk(ctx context.Context, fn func(deployment *storage.Deployment) error) error WalkByQuery(ctx context.Context, query *v1.Query, fn func(deployment *storage.Deployment) error) error diff --git a/central/deployment/datastore/mocks/datastore.go b/central/deployment/datastore/mocks/datastore.go index 4f4ec023ee7c9..206d20c2f17fd 100644 --- a/central/deployment/datastore/mocks/datastore.go +++ b/central/deployment/datastore/mocks/datastore.go @@ -74,6 +74,21 @@ func (mr *MockDataStoreMockRecorder) CountDeployments(ctx any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CountDeployments", reflect.TypeOf((*MockDataStore)(nil).CountDeployments), ctx) } +// DeploymentExists mocks base method. +func (m *MockDataStore) DeploymentExists(ctx context.Context, id string) (bool, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeploymentExists", ctx, id) + ret0, _ := ret[0].(bool) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// DeploymentExists indicates an expected call of DeploymentExists. +func (mr *MockDataStoreMockRecorder) DeploymentExists(ctx, id any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeploymentExists", reflect.TypeOf((*MockDataStore)(nil).DeploymentExists), ctx, id) +} + // GetContainerImageViews mocks base method. func (m *MockDataStore) GetContainerImageViews(ctx context.Context, q *v1.Query) ([]*views.ContainerImageView, error) { m.ctrl.T.Helper() diff --git a/central/deployment/service/ai_prompt.go b/central/deployment/service/ai_prompt.go index 69efe593c68e0..35863fcc83529 100644 --- a/central/deployment/service/ai_prompt.go +++ b/central/deployment/service/ai_prompt.go @@ -6,19 +6,14 @@ Cluster Security. A security operator is investigating a deployment flagged for review. AUDIENCE: Kubernetes cluster admin managing thousands of deployments. -They have oc access and want to reduce risk fast. TONE: Brief incident report. Short declarative sentences. No filler. CONTEXT ALREADY VISIBLE TO THE USER: The user already sees the deployment name, namespace, cluster, -risk score, and a stat summary bar (policy violations, CVE count, -image age, component count) in the UI. Process arguments are redacted. Do NOT restate any of that. -Start with the insight. - -If the deployment has no significant risk factors (normalized score -below 5), state that in one sentence. Do not generate a risk -breakdown or actions. +risk score, container images, and a stat summary bar (policy +violations, CVE count, image age, component count) in the UI. +Do NOT restate any of that. Start with the insight. Use these exact section labels with no additional text: @@ -28,31 +23,20 @@ finding. Name specific images, permission levels, and CVE counts where relevant. Start with the insight, not the deployment metadata. RISK BREAKDOWN -Max 4 bullets. Top risk factors ordered by score impact. One -sentence per bullet, max 20 words. Group related findings under -one bullet (e.g., image age + image CVEs). Skip factors scoring -below 1.5. - -IMMEDIATE ACTIONS -Max 4 numbered items. Concrete steps to reduce the risk score now. -Each action: one sentence describing what to do, followed by the -oc command on its own line. - -Rules for commands: -- Each command must be a single line, runnable as-is. -- Use oc (not kubectl). Scope to the correct namespace and - deployment name from the data. -- Only use real oc subcommands: patch, set resources, set image, - create, delete, annotate, label. -- If a value depends on information not in the data (e.g., a new - image tag), do NOT include a command. State the action in plain - text and note what the user must determine first. -- If an action could break the workload, prefix the description - with "⚠ May affect application behavior:" and state what to - verify before applying. +Max 4 bullets, each on its own line starting with "- ". Top risk +factors ordered by score impact. One sentence per bullet, max 20 +words. Group related findings under one bullet (e.g., image age + +image CVEs). Skip factors scoring below 1.5. CONSTRAINTS: - Plain text only. No markdown: no **, no backticks, no #. +- Refer to container images by name only or container name; + never include the exact tag or version. +- Report suspicious processes by executable name only; strip any + technical suffix (e.g. write "runc", not "runc:[1:CHILD]"). +- When a finding references a policy or compliance guideline + (e.g. CIS, NIST, BSI, PCI-DSS), describe the security risk it + represents, not the guideline name or code. - Do NOT explain ACS, risk scoring, or how the system works. - Do NOT hedge. Be direct. - Do NOT echo these instructions or section descriptions in diff --git a/central/deployment/service/risk_ai_summary_test.go b/central/deployment/service/risk_ai_summary_test.go index faf65f83c5a32..2273fbc66c9f3 100644 --- a/central/deployment/service/risk_ai_summary_test.go +++ b/central/deployment/service/risk_ai_summary_test.go @@ -179,7 +179,7 @@ func TestGetDeploymentRiskAISummary_SensitiveFieldsStripped(t *testing.T) { risk := &storage.Risk{ Id: "risk-2", - Score: 4.0, + Score: 6.0, Subject: &storage.RiskSubject{ Id: "dep-2", Namespace: "operations", @@ -270,7 +270,7 @@ func TestGetDeploymentRiskAISummary_OLSError(t *testing.T) { ClusterName: "test-cluster", Type: "Deployment", } - risk := &storage.Risk{Score: 2.0} + risk := &storage.Risk{Score: 8.0} mockDS.EXPECT().GetDeployment(gomock.Any(), "dep-3").Return(deployment, true, nil) mockRisks.EXPECT().GetRiskForDeployment(gomock.Any(), deployment).Return(risk, true, nil) @@ -311,19 +311,45 @@ func TestGetDeploymentRiskAISummary_NilRisk(t *testing.T) { mockDS.EXPECT().GetDeployment(gomock.Any(), "dep-4").Return(deployment, true, nil) mockRisks.EXPECT().GetRiskForDeployment(gomock.Any(), deployment).Return(nil, false, nil) - olsMock := &mockOLSClient{ - response: &olsClient.QueryResponse{Response: "No significant risk factors identified."}, + // OLS client should NOT be called for nil/low risk - no mock needed + svc := &serviceImpl{ + datastore: mockDS, + risks: mockRisks, } + resp, err := svc.GetDeploymentRiskAISummary(context.Background(), &v1.ResourceByID{Id: "dep-4"}) + require.NoError(t, err) + // Nil risk returns a specific message without calling OLS + assert.Equal(t, "No risk data available for this deployment.", resp.GetSummary()) +} + +func TestGetDeploymentRiskAISummary_LowRiskScore(t *testing.T) { + ctrl := gomock.NewController(t) + mockDS := deploymentMocks.NewMockDataStore(ctrl) + mockRisks := riskMocks.NewMockDataStore(ctrl) + + deployment := &storage.Deployment{ + Id: "dep-5", + Name: "low-risk-app", + Namespace: "default", + ClusterName: "test-cluster", + Type: "Deployment", + } + + risk := &storage.Risk{Score: 3.5} // Below threshold of 5.0 + + mockDS.EXPECT().GetDeployment(gomock.Any(), "dep-5").Return(deployment, true, nil) + mockRisks.EXPECT().GetRiskForDeployment(gomock.Any(), deployment).Return(risk, true, nil) + + // OLS client should NOT be called for low risk scores svc := &serviceImpl{ - datastore: mockDS, - risks: mockRisks, - lightspeedClient: olsMock, + datastore: mockDS, + risks: mockRisks, } - resp, err := svc.GetDeploymentRiskAISummary(context.Background(), &v1.ResourceByID{Id: "dep-4"}) + resp, err := svc.GetDeploymentRiskAISummary(context.Background(), &v1.ResourceByID{Id: "dep-5"}) require.NoError(t, err) - assert.Equal(t, "No significant risk factors identified.", resp.GetSummary()) + assert.Equal(t, "Skipping AI summary since this is a low risk deployment with normalized risk score below 5.", resp.GetSummary()) } func TestBuildSanitizedRiskContext_FieldSelection(t *testing.T) { diff --git a/central/deployment/service/service_impl.go b/central/deployment/service/service_impl.go index e23fc453a496b..3ba4f12a378f5 100644 --- a/central/deployment/service/service_impl.go +++ b/central/deployment/service/service_impl.go @@ -37,6 +37,7 @@ import ( const ( maxDeploymentsReturned = 1000 + lowRiskThreshold = 5.0 ) var log = logging.LoggerForModule() @@ -303,6 +304,20 @@ func (s *serviceImpl) GetDeploymentRiskAISummary(ctx context.Context, request *v return nil, err } + // Skip LLM call for deployments without risk data. + if risk == nil { + return &v1.DeploymentRiskAISummaryResponse{ + Summary: "No risk data available for this deployment.", + }, nil + } + + // Skip LLM call for low-risk deployments. + if risk.GetScore() < lowRiskThreshold { + return &v1.DeploymentRiskAISummaryResponse{ + Summary: "Skipping AI summary since this is a low risk deployment with normalized risk score below 5.", + }, nil + } + contextJSON, err := buildSanitizedRiskContext(deployment, risk) if err != nil { return nil, errors.Wrap(err, "building risk context for AI summary") diff --git a/central/detection/alertmanager/alert_manager_impl_test.go b/central/detection/alertmanager/alert_manager_impl_test.go index d5aadcd1eb135..aecff5c1961c8 100644 --- a/central/detection/alertmanager/alert_manager_impl_test.go +++ b/central/detection/alertmanager/alert_manager_impl_test.go @@ -730,6 +730,47 @@ func (suite *AlertManagerTestSuite) TestDeploymentMarkedInactiveOnRemoval() { suite.True(modified.Contains("dep-to-remove"), "removed deployment should appear in modified set") } +func (suite *AlertManagerTestSuite) TestRepeatedDeploymentRemovalPreservesRuntimeAlert() { + stored := &storage.Alert{ + Id: "runtime-alert-1", + Policy: fixtures.GetNetworkFlowPolicy(), + Entity: &storage.Alert_Deployment_{Deployment: &storage.Alert_Deployment{Id: "dep-to-remove"}}, + LifecycleStage: storage.LifecycleStage_RUNTIME, + State: storage.ViolationState_ACTIVE, + Time: protocompat.GetProtoTimestampFromSeconds(100), + } + suite.Require().NoError(suite.policySet.UpsertPolicy(stored.GetPolicy())) + suite.runtimeDetectorMock.EXPECT().PolicySet().Return(suite.policySet).AnyTimes() + + // Each removal reads the current persisted state. Only the first should write. + suite.alertsMock.EXPECT().SearchAlertMatchKeys(suite.ctx, gomock.Any(), true). + DoAndReturn(func(context.Context, *v1.Query, bool) ([]*alertviews.AlertMatchKey, error) { + return alertsToMatchKeys([]*storage.Alert{stored}), nil + }).Times(2) + suite.alertsMock.EXPECT().SearchRawAlerts(suite.ctx, gomock.Any(), false). + Return([]*storage.Alert{stored.CloneVT()}, nil) + suite.alertsMock.EXPECT().UpsertAlert(suite.ctx, gomock.Any()). + DoAndReturn(func(_ context.Context, a *storage.Alert) error { + suite.True(a.GetDeployment().GetInactive()) + suite.Equal(storage.ViolationState_ACTIVE, a.GetState()) + stored = a.CloneVT() + return nil + }) + suite.notifierMock.EXPECT().ProcessAlert(gomock.Any(), gomock.Any()).Return() + + modified, err := suite.alertManager.AlertAndNotify(suite.ctx, nil, + WithDeploymentID("dep-to-remove", true)) + suite.Require().NoError(err) + suite.True(modified.Contains("dep-to-remove")) + + modified, err = suite.alertManager.AlertAndNotify(suite.ctx, nil, + WithDeploymentID("dep-to-remove", true)) + suite.Require().NoError(err) + suite.Empty(modified.AsSlice()) + suite.True(stored.GetDeployment().GetInactive()) + suite.Equal(storage.ViolationState_ACTIVE, stored.GetState()) +} + // TestNewRuntimeAlertMarkedInactiveWhenDeploymentGone covers a first runtime // alert arriving after the deployment is already gone. func (suite *AlertManagerTestSuite) TestNewRuntimeAlertMarkedInactiveWhenDeploymentGone() { @@ -773,6 +814,29 @@ func (suite *AlertManagerTestSuite) TestMergedRuntimeAlertMarkedInactiveWhenDepl suite.True(modified.Contains("dep-gone")) } +func (suite *AlertManagerTestSuite) TestUnchangedRuntimeAlertMarkedInactiveWhenDeploymentGone() { + previous := runtimeDeploymentAlert("runtime-alert-1", "dep-gone", false, yesterdayProcess) + incoming := runtimeDeploymentAlert("runtime-alert-incoming", "dep-gone", false, yesterdayProcess) + + suite.alertsMock.EXPECT().SearchAlertMatchKeys(suite.ctx, gomock.Any(), true). + Return(alertsToMatchKeys([]*storage.Alert{previous}), nil) + suite.alertsMock.EXPECT().SearchRawAlerts(suite.ctx, gomock.Any(), false). + Return([]*storage.Alert{previous.CloneVT()}, nil) + suite.runtimeDetectorMock.EXPECT().DeploymentInactive("dep-gone").Return(true) + suite.alertsMock.EXPECT().SearchRawAlerts(suite.ctx, gomock.Any(), false). + Return([]*storage.Alert{previous.CloneVT()}, nil) + suite.alertsMock.EXPECT().UpsertAlert(suite.ctx, gomock.Any()).DoAndReturn(func(_ context.Context, stored *storage.Alert) error { + suite.Equal(previous.GetId(), stored.GetId()) + suite.True(stored.GetDeployment().GetInactive(), "stored runtime alert should be marked inactive") + return nil + }) + suite.notifierMock.EXPECT().ProcessAlert(gomock.Any(), gomock.Any()).Return() + + modified, err := suite.alertManager.AlertAndNotify(suite.ctx, []*storage.Alert{incoming}) + suite.NoError(err) + suite.True(modified.Contains("dep-gone")) +} + func (suite *AlertManagerTestSuite) TestResolvedDeploymentAlertReturnsDeploymentID() { alerts := getAlerts() diff --git a/central/detection/runtime/detector_impl.go b/central/detection/runtime/detector_impl.go index c7cbc63af811c..5746c5927b238 100644 --- a/central/detection/runtime/detector_impl.go +++ b/central/detection/runtime/detector_impl.go @@ -50,7 +50,7 @@ func (d *detectorImpl) DeploymentWhitelistedForPolicy(deploymentID, policyID str } func (d *detectorImpl) DeploymentInactive(deploymentID string) bool { - _, exists, err := d.deployments.ListDeployment(detectorCtx, deploymentID) + exists, err := d.deployments.DeploymentExists(detectorCtx, deploymentID) if err != nil { log.Errorf("Couldn't determine inactive state of deployment %q: %v", deploymentID, err) return false diff --git a/central/detection/runtime/detector_impl_test.go b/central/detection/runtime/detector_impl_test.go new file mode 100644 index 0000000000000..53cd5d5f228d2 --- /dev/null +++ b/central/detection/runtime/detector_impl_test.go @@ -0,0 +1,42 @@ +package runtime + +import ( + "errors" + "testing" + + "github.com/stackrox/rox/central/deployment/datastore/mocks" + "github.com/stretchr/testify/assert" + "go.uber.org/mock/gomock" +) + +func TestDeploymentInactive(t *testing.T) { + tests := map[string]struct { + exists bool + err error + inactive bool + }{ + "present deployment": { + exists: true, + inactive: false, + }, + "missing deployment": { + exists: false, + inactive: true, + }, + // A failed lookup must not mark live deployments' alerts inactive. + "datastore error": { + err: errors.New("database unavailable"), + inactive: false, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + deployments := mocks.NewMockDataStore(gomock.NewController(t)) + deployments.EXPECT().DeploymentExists(gomock.Any(), "deployment-id").Return(test.exists, test.err) + + detector := NewDetector(nil, deployments) + assert.Equal(t, test.inactive, detector.DeploymentInactive("deployment-id")) + }) + } +} diff --git a/central/enrichment/singleton.go b/central/enrichment/singleton.go index ba236d20af19c..598731bd43634 100644 --- a/central/enrichment/singleton.go +++ b/central/enrichment/singleton.go @@ -57,6 +57,7 @@ func initialize() { scanwaiterv2.Singleton(), sachelper.NewClusterNamespaceSacHelper(clusterDataStore.Singleton(), namespaceDataStore.Singleton()), + clusterDataStore.Singleton(), ) if !features.FlattenImageData.Enabled() { diff --git a/central/graphql/generator/codegen/typewalk.go b/central/graphql/generator/codegen/typewalk.go index 80c5cb3a0140b..b1a1bcb84d58b 100644 --- a/central/graphql/generator/codegen/typewalk.go +++ b/central/graphql/generator/codegen/typewalk.go @@ -126,6 +126,9 @@ func (ctx *walkState) walkField(td *typeData, p reflect.Type, sf reflect.StructF if !td.IsInputType && protoreflect.IsInternalGeneratorField(sf) { return } + if _, ok := sf.Tag.Lookup("protobuf_oneof"); ok { + return + } if strings.HasPrefix(sf.Name, "DEPRECATED") { return } diff --git a/central/graphql/resolvers/generated.go b/central/graphql/resolvers/generated.go index 38b997da3faf7..1e9ccedb56b07 100644 --- a/central/graphql/resolvers/generated.go +++ b/central/graphql/resolvers/generated.go @@ -669,17 +669,27 @@ func registerGeneratedTypes(builder generator.SchemaBuilder) { generator.RegisterProtoEnum(builder, reflect.TypeOf(storage.EventSource(0))) utils.Must(builder.AddType("Exclusion", []string{ "deployment: Exclusion_Deployment", + "excludeByKind: Exclusion_ExcludeByKind", "expiration: Time", "image: Exclusion_Image", "name: String!", + "matcher: ExclusionMatcher", + })) + utils.Must(builder.AddUnionType("ExclusionMatcher", []string{ + "Exclusion_Deployment", + "Exclusion_ExcludeByKind", })) utils.Must(builder.AddType("Exclusion_Deployment", []string{ "name: String!", "scope: Scope", })) + utils.Must(builder.AddType("Exclusion_ExcludeByKind", []string{ + "kinds: [Exclusion_WorkloadKind!]!", + })) utils.Must(builder.AddType("Exclusion_Image", []string{ "name: String!", })) + generator.RegisterProtoEnum(builder, reflect.TypeOf(storage.Exclusion_WorkloadKind(0))) utils.Must(builder.AddType("Exploit", []string{ "dateAdded: String!", "dueDate: String!", @@ -8033,6 +8043,11 @@ func (resolver *exclusionResolver) Deployment(ctx context.Context) (*exclusion_D return resolver.root.wrapExclusion_Deployment(value, true, nil) } +func (resolver *exclusionResolver) ExcludeByKind(ctx context.Context) (*exclusion_ExcludeByKindResolver, error) { + value := resolver.data.GetExcludeByKind() + return resolver.root.wrapExclusion_ExcludeByKind(value, true, nil) +} + func (resolver *exclusionResolver) Expiration(ctx context.Context) (*graphql.Time, error) { value := resolver.data.GetExpiration() return protocompat.ConvertTimestampToGraphqlTimeOrError(value) @@ -8048,6 +8063,34 @@ func (resolver *exclusionResolver) Name(ctx context.Context) string { return value } +type exclusionMatcherResolver struct { + resolver interface{} +} + +func (resolver *exclusionResolver) Matcher() *exclusionMatcherResolver { + if val := resolver.data.GetDeployment(); val != nil { + return &exclusionMatcherResolver{ + resolver: &exclusion_DeploymentResolver{root: resolver.root, data: val}, + } + } + if val := resolver.data.GetExcludeByKind(); val != nil { + return &exclusionMatcherResolver{ + resolver: &exclusion_ExcludeByKindResolver{root: resolver.root, data: val}, + } + } + return nil +} + +func (resolver *exclusionMatcherResolver) ToExclusion_Deployment() (*exclusion_DeploymentResolver, bool) { + res, ok := resolver.resolver.(*exclusion_DeploymentResolver) + return res, ok +} + +func (resolver *exclusionMatcherResolver) ToExclusion_ExcludeByKind() (*exclusion_ExcludeByKindResolver, bool) { + res, ok := resolver.resolver.(*exclusion_ExcludeByKindResolver) + return res, ok +} + type exclusion_DeploymentResolver struct { ctx context.Context root *Resolver @@ -8100,6 +8143,53 @@ func (resolver *exclusion_DeploymentResolver) Scope(ctx context.Context) (*scope return resolver.root.wrapScope(value, true, nil) } +type exclusion_ExcludeByKindResolver struct { + ctx context.Context + root *Resolver + data *storage.Exclusion_ExcludeByKind +} + +func (resolver *Resolver) wrapExclusion_ExcludeByKind(value *storage.Exclusion_ExcludeByKind, ok bool, err error) (*exclusion_ExcludeByKindResolver, error) { + if !ok || err != nil || value == nil { + return nil, err + } + return &exclusion_ExcludeByKindResolver{root: resolver, data: value}, nil +} + +func (resolver *Resolver) wrapExclusion_ExcludeByKinds(values []*storage.Exclusion_ExcludeByKind, err error) ([]*exclusion_ExcludeByKindResolver, error) { + if err != nil || len(values) == 0 { + return nil, err + } + output := make([]*exclusion_ExcludeByKindResolver, len(values)) + for i, v := range values { + output[i] = &exclusion_ExcludeByKindResolver{root: resolver, data: v} + } + return output, nil +} + +func (resolver *Resolver) wrapExclusion_ExcludeByKindWithContext(ctx context.Context, value *storage.Exclusion_ExcludeByKind, ok bool, err error) (*exclusion_ExcludeByKindResolver, error) { + if !ok || err != nil || value == nil { + return nil, err + } + return &exclusion_ExcludeByKindResolver{ctx: ctx, root: resolver, data: value}, nil +} + +func (resolver *Resolver) wrapExclusion_ExcludeByKindsWithContext(ctx context.Context, values []*storage.Exclusion_ExcludeByKind, err error) ([]*exclusion_ExcludeByKindResolver, error) { + if err != nil || len(values) == 0 { + return nil, err + } + output := make([]*exclusion_ExcludeByKindResolver, len(values)) + for i, v := range values { + output[i] = &exclusion_ExcludeByKindResolver{ctx: ctx, root: resolver, data: v} + } + return output, nil +} + +func (resolver *exclusion_ExcludeByKindResolver) Kinds(ctx context.Context) []string { + value := resolver.data.GetKinds() + return stringSlice(value) +} + type exclusion_ImageResolver struct { ctx context.Context root *Resolver @@ -8147,6 +8237,24 @@ func (resolver *exclusion_ImageResolver) Name(ctx context.Context) string { return value } +func toExclusion_WorkloadKind(value *string) storage.Exclusion_WorkloadKind { + if value != nil { + return storage.Exclusion_WorkloadKind(storage.Exclusion_WorkloadKind_value[*value]) + } + return storage.Exclusion_WorkloadKind(0) +} + +func toExclusion_WorkloadKinds(values *[]string) []storage.Exclusion_WorkloadKind { + if values == nil { + return nil + } + output := make([]storage.Exclusion_WorkloadKind, len(*values)) + for i, v := range *values { + output[i] = toExclusion_WorkloadKind(&v) + } + return output +} + type exploitResolver struct { ctx context.Context root *Resolver diff --git a/central/imageintegration/datastore/singleton.go b/central/imageintegration/datastore/singleton.go index a3d683a1b9258..f54a5acc8fd93 100644 --- a/central/imageintegration/datastore/singleton.go +++ b/central/imageintegration/datastore/singleton.go @@ -2,6 +2,7 @@ package datastore import ( "context" + "slices" "github.com/pkg/errors" "github.com/stackrox/rox/central/globaldb" @@ -132,19 +133,46 @@ func setupScannerV4Integration(ctx context.Context, iiStore store.Store, iis []* } // createDefaultScannerV4Integration will create the default Scanner V4 integration if it does -// not currently exist. +// not currently exist, or reconcile its categories if they differ from the default. func createDefaultScannerV4Integration(ctx context.Context, iiStore store.Store) { - if _, exists, err := iiStore.Get(ctx, store.DefaultScannerV4Integration.GetId()); err != nil { + defaultID := store.DefaultScannerV4Integration.GetId() + existing, exists, err := iiStore.Get(ctx, defaultID) + if err != nil { utils.Should(errors.Wrap(err, "unable to detect if default Scanner V4 integration exists")) return - } else if exists { - // Nothing to do, integration exists. + } + + if !exists { + log.Infof("Upserting default Scanner V4 integration %q (%s)", store.DefaultScannerV4Integration.GetName(), defaultID) + err := iiStore.Upsert(ctx, store.DefaultScannerV4Integration) + utils.Should(errors.Wrap(err, "unable to upsert default ScannerV4 integration")) + return + } + + // Restore default categories on records that predate them. The API rejects category changes, + // so this only repairs older data. Preserve other settings. + if categoriesMatch(existing.GetCategories(), store.DefaultScannerV4Integration.GetCategories()) { return } - log.Infof("Upserting default Scanner V4 integration %q (%s)", store.DefaultScannerV4Integration.GetName(), store.DefaultScannerV4Integration.GetId()) - err := iiStore.Upsert(ctx, store.DefaultScannerV4Integration) - utils.Should(errors.Wrap(err, "unable to upsert default ScannerV4 integration")) + log.Warnf("Reconciling categories for default Scanner V4 integration %q (%s): updating from %v to %v", + existing.GetName(), defaultID, existing.GetCategories(), store.DefaultScannerV4Integration.GetCategories()) + + existing.Categories = store.DefaultScannerV4Integration.GetCategories() + err = iiStore.Upsert(ctx, existing) + utils.Should(errors.Wrap(err, "unable to reconcile default ScannerV4 integration categories")) +} + +// categoriesMatch returns true if two category slices contain the same elements (order-independent). +func categoriesMatch(a, b []storage.ImageIntegrationCategory) bool { + if len(a) != len(b) { + return false + } + a = slices.Clone(a) + b = slices.Clone(b) + slices.Sort(a) + slices.Sort(b) + return slices.Equal(a, b) } // deleteScannerV4Integrations will delete all Scanner V4 integrations except for diff --git a/central/imageintegration/datastore/singleton_test.go b/central/imageintegration/datastore/singleton_test.go index cbbf1e712e097..94b79b4e8b4d2 100644 --- a/central/imageintegration/datastore/singleton_test.go +++ b/central/imageintegration/datastore/singleton_test.go @@ -149,11 +149,23 @@ func TestSetupScannerV4Integration(t *testing.T) { } }) - t.Run("do not try upsert if default integration exists", func(t *testing.T) { + t.Run("do not try upsert if default integration exists with correct categories", func(t *testing.T) { testutils.MustUpdateFeature(t, features.ScannerV4, true) s := mockIIStore.NewMockStore(gomock.NewController(t)) - s.EXPECT().Get(ctx, defID).Return(nil, true, nil) + existingCorrect := &storage.ImageIntegration{ + Id: defID, + Name: "Scanner V4", + Type: scannerTypes.ScannerV4, + Categories: []storage.ImageIntegrationCategory{ + storage.ImageIntegrationCategory_SCANNER, + storage.ImageIntegrationCategory_NODE_SCANNER, + }, + IntegrationConfig: &storage.ImageIntegration_ScannerV4{ + ScannerV4: &storage.ScannerV4Config{}, + }, + } + s.EXPECT().Get(ctx, defID).Return(existingCorrect, true, nil) s.EXPECT().PruneMany(ctx, []string{"ID-Other-ScannerV4"}) setupScannerV4Integration(ctx, s, iis) }) @@ -212,3 +224,177 @@ func TestSetupLegacyScannerIntegration(t *testing.T) { setupLegacyScannerIntegration(ctx, s, h, iis) }) } + +func TestCreateDefaultScannerV4Integration(t *testing.T) { + ctx := context.Background() + defaultID := store.DefaultScannerV4Integration.GetId() + + t.Run("create default integration when it does not exist", func(t *testing.T) { + s := mockIIStore.NewMockStore(gomock.NewController(t)) + + s.EXPECT().Get(ctx, defaultID).Return(nil, false, nil) + s.EXPECT().Upsert(ctx, store.DefaultScannerV4Integration).Return(nil) + + createDefaultScannerV4Integration(ctx, s) + }) + + t.Run("reconcile categories when existing integration has SCANNER only", func(t *testing.T) { + s := mockIIStore.NewMockStore(gomock.NewController(t)) + + existingScannerOnly := &storage.ImageIntegration{ + Id: defaultID, + Name: "Scanner V4", + Type: scannerTypes.ScannerV4, + Categories: []storage.ImageIntegrationCategory{ + storage.ImageIntegrationCategory_SCANNER, + }, + IntegrationConfig: &storage.ImageIntegration_ScannerV4{ + ScannerV4: &storage.ScannerV4Config{ + IndexerEndpoint: "custom-indexer:8443", + MatcherEndpoint: "custom-matcher:8443", + }, + }, + } + + s.EXPECT().Get(ctx, defaultID).Return(existingScannerOnly, true, nil) + s.EXPECT().Upsert(ctx, gomock.Any()).DoAndReturn(func(_ context.Context, ii *storage.ImageIntegration) error { + assert.ElementsMatch(t, store.DefaultScannerV4Integration.GetCategories(), ii.GetCategories()) + assert.Equal(t, "custom-indexer:8443", ii.GetScannerV4().GetIndexerEndpoint()) + assert.Equal(t, "custom-matcher:8443", ii.GetScannerV4().GetMatcherEndpoint()) + return nil + }) + + createDefaultScannerV4Integration(ctx, s) + }) + + t.Run("reconcile categories when existing integration has wrong categories", func(t *testing.T) { + s := mockIIStore.NewMockStore(gomock.NewController(t)) + + existingNodeOnly := &storage.ImageIntegration{ + Id: defaultID, + Name: "Scanner V4", + Type: scannerTypes.ScannerV4, + Categories: []storage.ImageIntegrationCategory{ + storage.ImageIntegrationCategory_NODE_SCANNER, + }, + IntegrationConfig: &storage.ImageIntegration_ScannerV4{ + ScannerV4: &storage.ScannerV4Config{ + IndexerEndpoint: "indexer:8080", + MatcherEndpoint: "matcher:8080", + }, + }, + } + + s.EXPECT().Get(ctx, defaultID).Return(existingNodeOnly, true, nil) + s.EXPECT().Upsert(ctx, gomock.Any()).DoAndReturn(func(_ context.Context, ii *storage.ImageIntegration) error { + assert.ElementsMatch(t, store.DefaultScannerV4Integration.GetCategories(), ii.GetCategories()) + assert.Equal(t, "indexer:8080", ii.GetScannerV4().GetIndexerEndpoint()) + return nil + }) + + createDefaultScannerV4Integration(ctx, s) + }) + + t.Run("reconcile categories when existing integration has nil categories", func(t *testing.T) { + s := mockIIStore.NewMockStore(gomock.NewController(t)) + + existingNilCategories := &storage.ImageIntegration{ + Id: defaultID, + Name: "Scanner V4", + Type: scannerTypes.ScannerV4, + Categories: nil, + IntegrationConfig: &storage.ImageIntegration_ScannerV4{ + ScannerV4: &storage.ScannerV4Config{ + IndexerEndpoint: "legacy-indexer:8443", + }, + }, + } + + s.EXPECT().Get(ctx, defaultID).Return(existingNilCategories, true, nil) + s.EXPECT().Upsert(ctx, gomock.Any()).DoAndReturn(func(_ context.Context, ii *storage.ImageIntegration) error { + assert.ElementsMatch(t, store.DefaultScannerV4Integration.GetCategories(), ii.GetCategories()) + assert.Equal(t, "legacy-indexer:8443", ii.GetScannerV4().GetIndexerEndpoint()) + return nil + }) + + createDefaultScannerV4Integration(ctx, s) + }) + + t.Run("do nothing when Get returns error", func(t *testing.T) { + s := mockIIStore.NewMockStore(gomock.NewController(t)) + + s.EXPECT().Get(ctx, defaultID).Return(nil, false, errors.New("database error")) + + if buildinfo.ReleaseBuild { + createDefaultScannerV4Integration(ctx, s) + } else { + assert.Panics(t, func() { createDefaultScannerV4Integration(ctx, s) }) + } + }) +} + +func TestCategoriesMatch(t *testing.T) { + testCases := map[string]struct { + a []storage.ImageIntegrationCategory + b []storage.ImageIntegrationCategory + expected bool + }{ + "empty slices match": { + []storage.ImageIntegrationCategory{}, + []storage.ImageIntegrationCategory{}, + true, + }, + "nil and empty slice match": { + nil, + []storage.ImageIntegrationCategory{}, + true, + }, + "same single element": { + []storage.ImageIntegrationCategory{storage.ImageIntegrationCategory_SCANNER}, + []storage.ImageIntegrationCategory{storage.ImageIntegrationCategory_SCANNER}, + true, + }, + "same multiple elements in same order": { + []storage.ImageIntegrationCategory{ + storage.ImageIntegrationCategory_SCANNER, + storage.ImageIntegrationCategory_NODE_SCANNER, + }, + []storage.ImageIntegrationCategory{ + storage.ImageIntegrationCategory_SCANNER, + storage.ImageIntegrationCategory_NODE_SCANNER, + }, + true, + }, + "same multiple elements in different order": { + []storage.ImageIntegrationCategory{ + storage.ImageIntegrationCategory_NODE_SCANNER, + storage.ImageIntegrationCategory_SCANNER, + }, + []storage.ImageIntegrationCategory{ + storage.ImageIntegrationCategory_SCANNER, + storage.ImageIntegrationCategory_NODE_SCANNER, + }, + true, + }, + "different lengths do not match": { + []storage.ImageIntegrationCategory{storage.ImageIntegrationCategory_SCANNER}, + []storage.ImageIntegrationCategory{ + storage.ImageIntegrationCategory_SCANNER, + storage.ImageIntegrationCategory_NODE_SCANNER, + }, + false, + }, + "different elements do not match": { + []storage.ImageIntegrationCategory{storage.ImageIntegrationCategory_SCANNER}, + []storage.ImageIntegrationCategory{storage.ImageIntegrationCategory_NODE_SCANNER}, + false, + }, + } + + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { + result := categoriesMatch(tc.a, tc.b) + assert.Equal(t, tc.expected, result) + }) + } +} diff --git a/central/imageintegration/service/service_impl.go b/central/imageintegration/service/service_impl.go index 9ba22efa473cb..57eccf6e553c7 100644 --- a/central/imageintegration/service/service_impl.go +++ b/central/imageintegration/service/service_impl.go @@ -2,6 +2,7 @@ package service import ( "context" + "slices" "sort" "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" @@ -131,6 +132,18 @@ func sortCategories(categories []storage.ImageIntegrationCategory) { }) } +// sameCategories returns true if both slices contain the same categories, ignoring order. +func sameCategories(a, b []storage.ImageIntegrationCategory) bool { + if len(a) != len(b) { + return false + } + a = slices.Clone(a) + b = slices.Clone(b) + slices.Sort(a) + slices.Sort(b) + return slices.Equal(a, b) +} + func (s *serviceImpl) validateTestAndNormalize(ctx context.Context, request *storage.ImageIntegration) error { if err := s.validateIntegration(ctx, request); err != nil { return err @@ -404,6 +417,9 @@ func (s *serviceImpl) reconcileUpdateImageIntegrationRequest(ctx context.Context if newType != oldType && (newType == scannerTypes.ScannerV4 || oldType == scannerTypes.ScannerV4) { return errors.Wrap(errox.InvalidArgs, "cannot change integration type to/from scanner V4") } + if oldType == scannerTypes.ScannerV4 && !sameCategories(integration.GetCategories(), updateRequest.GetConfig().GetCategories()) { + return errors.Wrap(errox.InvalidArgs, "cannot change categories of scanner V4 integration") + } // Note that integrations of type "azure" support both `DockerConfig` (deprecated in 4.7) and `AzureConfig`. // Here we migrate requests with type "azure" and `DockerConfig` on the fly to type `AzureConfig`. diff --git a/central/imageintegration/service/service_impl_test.go b/central/imageintegration/service/service_impl_test.go index 623dc7ed4a152..7d930eb0e97a8 100644 --- a/central/imageintegration/service/service_impl_test.go +++ b/central/imageintegration/service/service_impl_test.go @@ -513,6 +513,44 @@ func TestScannerV4Restrictions(t *testing.T) { _, err := s.UpdateImageIntegration(context.Background(), &v1.UpdateImageIntegrationRequest{Config: iiNew}) assert.ErrorContains(t, err, "scanner V4") }) + + t.Run("prevent category change on scannerv4", func(t *testing.T) { + ctrl := gomock.NewController(t) + iiDS := integrationMocks.NewMockDataStore(ctrl) + s := &serviceImpl{datastore: iiDS} + + iiNew := ii.CloneVT() + iiNew.Categories = append(iiNew.Categories, storage.ImageIntegrationCategory_NODE_SCANNER) + + iiDS.EXPECT().GetImageIntegrations(gomock.Any(), gomock.Any()).Return([]*storage.ImageIntegration{ii}, nil) + iiDS.EXPECT().GetImageIntegration(gomock.Any(), gomock.Any()).Return(ii, true, nil) + + _, err := s.UpdateImageIntegration(context.Background(), &v1.UpdateImageIntegrationRequest{Config: iiNew}) + assert.ErrorIs(t, err, errox.InvalidArgs) + assert.ErrorContains(t, err, "categories of scanner V4") + }) +} + +func TestSameCategories(t *testing.T) { + scanner := storage.ImageIntegrationCategory_SCANNER + nodeScanner := storage.ImageIntegrationCategory_NODE_SCANNER + + cases := map[string]struct { + a, b []storage.ImageIntegrationCategory + expected bool + }{ + "both empty": {expected: true}, + "same order": {a: []storage.ImageIntegrationCategory{scanner, nodeScanner}, b: []storage.ImageIntegrationCategory{scanner, nodeScanner}, expected: true}, + "different order": {a: []storage.ImageIntegrationCategory{nodeScanner, scanner}, b: []storage.ImageIntegrationCategory{scanner, nodeScanner}, expected: true}, + "category added": {a: []storage.ImageIntegrationCategory{scanner}, b: []storage.ImageIntegrationCategory{scanner, nodeScanner}, expected: false}, + "category removed": {a: []storage.ImageIntegrationCategory{scanner, nodeScanner}, b: []storage.ImageIntegrationCategory{scanner}, expected: false}, + "category swapped": {a: []storage.ImageIntegrationCategory{scanner}, b: []storage.ImageIntegrationCategory{nodeScanner}, expected: false}, + } + for name, c := range cases { + t.Run(name, func(t *testing.T) { + assert.Equal(t, c.expected, sameCategories(c.a, c.b)) + }) + } } func TestGCRCreationBlocked(t *testing.T) { diff --git a/central/main.go b/central/main.go index 11bf834c78731..cb3bb5d8a53a4 100755 --- a/central/main.go +++ b/central/main.go @@ -24,6 +24,7 @@ import ( "github.com/stackrox/rox/central/audit" authDS "github.com/stackrox/rox/central/auth/datastore" internalTokenAuthService "github.com/stackrox/rox/central/auth/internaltokens/service" + openshiftAuth "github.com/stackrox/rox/central/auth/openshift" authService "github.com/stackrox/rox/central/auth/service" "github.com/stackrox/rox/central/auth/userpass" authProviderRegistry "github.com/stackrox/rox/central/authprovider/registry" @@ -218,6 +219,7 @@ import ( "github.com/stackrox/rox/pkg/grpc/errors" "github.com/stackrox/rox/pkg/grpc/ratelimit" "github.com/stackrox/rox/pkg/grpc/routes" + "github.com/stackrox/rox/pkg/grpc/versionheader" "github.com/stackrox/rox/pkg/httputil/proxy" "github.com/stackrox/rox/pkg/logging" "github.com/stackrox/rox/pkg/memlimit" @@ -382,11 +384,7 @@ func startServices() { reprocessor.Singleton().Start() suppress.Singleton().Start() - if !env.CentralWorkerEnabled.BooleanSetting() { - pruning.Singleton().Start() - } else { - log.Info("Pruning is managed by central-worker, skipping start in Central") - } + pruning.Singleton().Start() if baseImageWatcher.Enabled() { baseImageWatcher.Singleton().Start() } @@ -590,10 +588,6 @@ func startGRPCServer() { } } - if features.ACMAccessControlDelegation.Enabled() { - authProviderBackendFactories[oidc.TypeNameWithACMAccessControlDelegation] = oidc.NewFactory - } - for typeName, factoryCreator := range authProviderBackendFactories { if err := registry.RegisterBackendFactory(authProviderRegisteringCtx, typeName, factoryCreator); err != nil { log.Panicf("Could not register %s auth provider factory: %v", typeName, err) @@ -610,6 +604,8 @@ func startGRPCServer() { basicAuthProvider := userpass.RegisterAuthProviderOrPanic(authProviderRegisteringCtx, basicAuthMgr, registry) + openshiftAuth.SeedMetricsAuthProvider(authProviderRegisteringCtx, registry, roleDataStore.Singleton(), groupDataStore.Singleton()) + clusterInitBackend := backend.Singleton() serviceMTLSExtractor, err := service.NewExtractorWithCertValidation(clusterInitBackend) if err != nil { @@ -669,6 +665,8 @@ func startGRPCServer() { centralSAC.GetEnricher().GetPreAuthContextEnricher(authzTraceSink), ) + config.UnaryInterceptors = append(config.UnaryInterceptors, versionheader.CentralVersionServerInterceptor()) + // Telemetry client has to add interceptors before starting the server. c := phonehomeClient.Singleton() config.HTTPInterceptors = append(config.HTTPInterceptors, c.GetHTTPInterceptor()) @@ -1068,9 +1066,7 @@ func waitForTerminationSignal() { {reprocessor.Singleton(), "reprocessor loop"}, {suppress.Singleton(), "cve unsuppress loop"}, } - if !env.CentralWorkerEnabled.BooleanSetting() { - stoppables = append(stoppables, stoppableWithName{pruning.Singleton(), "garbage collector"}) - } + stoppables = append(stoppables, stoppableWithName{pruning.Singleton(), "garbage collector"}) stoppables = append(stoppables, []stoppableWithName{ {gatherer.Singleton(), "network graph default external sources gatherer"}, {vulnRequestManager.Singleton(), "vuln deferral requests expiry loop"}, diff --git a/central/node/datastore/store/postgres/store_test.go b/central/node/datastore/store/postgres/store_test.go index 07ff3e3018783..8c3ca0de4cc41 100644 --- a/central/node/datastore/store/postgres/store_test.go +++ b/central/node/datastore/store/postgres/store_test.go @@ -284,7 +284,7 @@ func (s *NodesStoreSuite) TestStore_OrphanedCVEs() { s.NoError(err) s.NotEmpty(orphanedCVEs) for _, cve := range orphanedCVEs { - s.NotNil(cve.OrphanedTime) + s.NotNil(cve.GetOrphanedTime()) s.True(vulnNames.Contains(cve.GetCveBaseInfo().GetCve())) } @@ -311,8 +311,8 @@ func (s *NodesStoreSuite) TestStore_OrphanedCVEs() { s.NoError(err) s.NotEmpty(nodeCVEs) for _, cve := range nodeCVEs { - s.False(cve.Orphaned) - s.Nil(cve.OrphanedTime) + s.False(cve.GetOrphaned()) + s.Nil(cve.GetOrphanedTime()) val, ok := orphanedCveIDToCve[cve.GetId()] s.True(ok) s.Equal(val.GetCveBaseInfo().GetCreatedAt(), cve.GetCveBaseInfo().GetCreatedAt()) diff --git a/central/policy/customresource/custom_resource_test.go b/central/policy/customresource/custom_resource_test.go index 94cf6c6f9e545..b5462769f16bb 100644 --- a/central/policy/customresource/custom_resource_test.go +++ b/central/policy/customresource/custom_resource_test.go @@ -24,6 +24,29 @@ func TestConvertToCR(t *testing.T) { assert.YAMLEq(t, templateFile, converted) } +func TestConvertExcludeByKind(t *testing.T) { + policy := fixtures.GetPolicy() + policy.Exclusions = []*storage.Exclusion{ + { + Name: "skip-batch", + Matcher: &storage.Exclusion_ExcludeByKind_{ + ExcludeByKind: &storage.Exclusion_ExcludeByKind{ + Kinds: []storage.Exclusion_WorkloadKind{ + storage.Exclusion_CRON_JOB, + storage.Exclusion_JOB, + }, + }, + }, + }, + } + cr := ConvertPolicyToCustomResource(policy) + require.Len(t, cr.SecurityPolicySpec.Exclusions, 1) + exclusion := cr.SecurityPolicySpec.Exclusions[0] + require.NotNil(t, exclusion.ExcludeByKind) + assert.Equal(t, []string{"CRON_JOB", "JOB"}, exclusion.ExcludeByKind.Kinds) + assert.Nil(t, exclusion.Deployment) +} + func getTestPolicy() *storage.Policy { p := fixtures.GetPolicy() p.Notifiers = []string{ @@ -45,8 +68,7 @@ func getTestPolicy() *storage.Policy { } p.Exclusions = []*storage.Exclusion{ { - Name: "exclusionName1", - Deployment: &storage.Exclusion_Deployment{ + Name: "exclusionName1", Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{ Name: "deployment1", Scope: &storage.Scope{ Cluster: "cluster1", @@ -56,12 +78,10 @@ func getTestPolicy() *storage.Policy { Value: "value1", }, }, - }, - Expiration: protocompat.GetProtoTimestampFromSeconds(2334221123), + }}, Expiration: protocompat.GetProtoTimestampFromSeconds(2334221123), }, { - Name: "exclusionName2", - Deployment: &storage.Exclusion_Deployment{ + Name: "exclusionName2", Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{ Name: "deployment2", Scope: &storage.Scope{ Cluster: "cluster2", @@ -71,13 +91,16 @@ func getTestPolicy() *storage.Policy { Value: "value2", }, }, - }, + }}, }, } p.Scope = append(p.Scope, &storage.Scope{ ClusterLabel: &storage.Scope_Label{Key: "env", Value: "prod"}, NamespaceLabel: &storage.Scope_Label{Key: "team", Value: "platform"}, }) + p.EvaluationFilter = &storage.EvaluationFilter{ + SkipContainerTypes: []storage.ContainerType{storage.ContainerType_REGULAR, storage.ContainerType_INIT}, + } return p } diff --git a/central/policy/customresource/policy.go b/central/policy/customresource/policy.go index 233b500a5c66c..e4f6dae68366d 100644 --- a/central/policy/customresource/policy.go +++ b/central/policy/customresource/policy.go @@ -23,11 +23,11 @@ func convertScope(p *storage.Scope) *Scope { } return &Scope{ - Cluster: p.Cluster, - Namespace: p.Namespace, - Label: p.Label, - ClusterLabel: p.ClusterLabel, - NamespaceLabel: p.NamespaceLabel, + Cluster: p.GetCluster(), + Namespace: p.GetNamespace(), + Label: p.GetLabel(), + ClusterLabel: p.GetClusterLabel(), + NamespaceLabel: p.GetNamespaceLabel(), } } @@ -44,17 +44,34 @@ func convertExclusion_Deployment(p *storage.Exclusion_Deployment) *Exclusion_Dep } return &Exclusion_Deployment{ - Name: p.Name, - Scope: convertScope(p.Scope), + Name: p.GetName(), + Scope: convertScope(p.GetScope()), + } +} + +// Exclusion_ExcludeByKind represents storage.Exclusion_ExcludeByKind in the Custom Resource. +type Exclusion_ExcludeByKind struct { + Kinds []string `yaml:",omitempty"` +} + +// convertExclusion_ExcludeByKind Converts storage.Exclusion_ExcludeByKind to *Exclusion_ExcludeByKind +func convertExclusion_ExcludeByKind(p *storage.Exclusion_ExcludeByKind) *Exclusion_ExcludeByKind { + if p == nil { + return nil + } + + return &Exclusion_ExcludeByKind{ + Kinds: sliceutils.StringSlice(p.GetKinds()...), } } // Exclusion represents storage.Exclusion in the Custom Resource. type Exclusion struct { - Name string `yaml:",omitempty"` - Deployment *Exclusion_Deployment `yaml:",omitempty"` - Image *storage.Exclusion_Image `yaml:",omitempty"` - Expiration string `yaml:",omitempty"` + Name string `yaml:",omitempty"` + Image *storage.Exclusion_Image `yaml:",omitempty"` + Expiration string `yaml:",omitempty"` + Deployment *Exclusion_Deployment `yaml:",omitempty"` + ExcludeByKind *Exclusion_ExcludeByKind `yaml:"excludeByKind,omitempty"` } // convertExclusion Converts storage.Exclusion to *Exclusion @@ -64,10 +81,11 @@ func convertExclusion(p *storage.Exclusion) *Exclusion { } return &Exclusion{ - Name: p.Name, - Deployment: convertExclusion_Deployment(p.Deployment), - Image: p.Image, - Expiration: timestampToFormatRFC3339(p.Expiration), + Name: p.GetName(), + Image: p.GetImage(), + Expiration: timestampToFormatRFC3339(p.GetExpiration()), + Deployment: convertExclusion_Deployment(p.GetDeployment()), + ExcludeByKind: convertExclusion_ExcludeByKind(p.GetExcludeByKind()), } } @@ -86,10 +104,10 @@ func convertPolicyGroup(p *storage.PolicyGroup) *PolicyGroup { } return &PolicyGroup{ - FieldName: p.FieldName, - BooleanOperator: p.BooleanOperator.String(), - Negate: p.Negate, - Values: p.Values, + FieldName: p.GetFieldName(), + BooleanOperator: p.GetBooleanOperator().String(), + Negate: p.GetNegate(), + Values: p.GetValues(), } } @@ -106,8 +124,24 @@ func convertPolicySection(p *storage.PolicySection) *PolicySection { } return &PolicySection{ - SectionName: p.SectionName, - PolicyGroups: sliceutils.ConvertSlice(p.PolicyGroups, convertPolicyGroup), + SectionName: p.GetSectionName(), + PolicyGroups: sliceutils.ConvertSlice(p.GetPolicyGroups(), convertPolicyGroup), + } +} + +// EvaluationFilter represents storage.EvaluationFilter in the Custom Resource. +type EvaluationFilter struct { + SkipContainerTypes []string `yaml:"skipContainerTypes,omitempty"` +} + +// convertEvaluationFilter Converts storage.EvaluationFilter to *EvaluationFilter +func convertEvaluationFilter(p *storage.EvaluationFilter) *EvaluationFilter { + if p == nil { + return nil + } + + return &EvaluationFilter{ + SkipContainerTypes: sliceutils.StringSlice(p.GetSkipContainerTypes()...), } } @@ -131,7 +165,7 @@ type Policy struct { CriteriaLocked bool `yaml:"criteriaLocked"` MitreVectorsLocked bool `yaml:"mitreVectorsLocked"` IsDefault bool `yaml:"isDefault"` - EvaluationFilter *storage.EvaluationFilter `yaml:"evaluationFilter,omitempty"` + EvaluationFilter *EvaluationFilter `yaml:"evaluationFilter,omitempty"` } // convertPolicy Converts storage.Policy to *Policy @@ -141,25 +175,25 @@ func convertPolicy(p *storage.Policy) *Policy { } return &Policy{ - Name: p.Name, - Description: p.Description, - Rationale: p.Rationale, - Remediation: p.Remediation, - Disabled: p.Disabled, - Categories: p.Categories, - LifecycleStages: sliceutils.StringSlice(p.LifecycleStages...), - EventSource: p.EventSource.String(), - Exclusions: sliceutils.ConvertSlice(p.Exclusions, convertExclusion), - Scope: sliceutils.ConvertSlice(p.Scope, convertScope), - Severity: p.Severity.String(), - EnforcementActions: sliceutils.StringSlice(p.EnforcementActions...), - Notifiers: p.Notifiers, - PolicySections: sliceutils.ConvertSlice(p.PolicySections, convertPolicySection), - MitreAttackVectors: p.MitreAttackVectors, - CriteriaLocked: p.CriteriaLocked, - MitreVectorsLocked: p.MitreVectorsLocked, - IsDefault: p.IsDefault, - EvaluationFilter: p.EvaluationFilter, + Name: p.GetName(), + Description: p.GetDescription(), + Rationale: p.GetRationale(), + Remediation: p.GetRemediation(), + Disabled: p.GetDisabled(), + Categories: p.GetCategories(), + LifecycleStages: sliceutils.StringSlice(p.GetLifecycleStages()...), + EventSource: p.GetEventSource().String(), + Exclusions: sliceutils.ConvertSlice(p.GetExclusions(), convertExclusion), + Scope: sliceutils.ConvertSlice(p.GetScope(), convertScope), + Severity: p.GetSeverity().String(), + EnforcementActions: sliceutils.StringSlice(p.GetEnforcementActions()...), + Notifiers: p.GetNotifiers(), + PolicySections: sliceutils.ConvertSlice(p.GetPolicySections(), convertPolicySection), + MitreAttackVectors: p.GetMitreAttackVectors(), + CriteriaLocked: p.GetCriteriaLocked(), + MitreVectorsLocked: p.GetMitreVectorsLocked(), + IsDefault: p.GetIsDefault(), + EvaluationFilter: convertEvaluationFilter(p.GetEvaluationFilter()), } } diff --git a/central/policy/customresource/testdata/custom_resource.yaml b/central/policy/customresource/testdata/custom_resource.yaml index 4de610ec37a80..bce167fd2d230 100644 --- a/central/policy/customresource/testdata/custom_resource.yaml +++ b/central/policy/customresource/testdata/custom_resource.yaml @@ -147,3 +147,7 @@ spec: criteriaLocked: false mitreVectorsLocked: false isDefault: false + evaluationFilter: + skipContainerTypes: + - INIT + - REGULAR diff --git a/central/policy/datastore/datastore_impl_test.go b/central/policy/datastore/datastore_impl_test.go index 607c4fb1f32fc..e8008bf94966c 100644 --- a/central/policy/datastore/datastore_impl_test.go +++ b/central/policy/datastore/datastore_impl_test.go @@ -318,12 +318,11 @@ func (s *PolicyDatastoreTestSuite) TestRemoveScopesAndNotifiers() { }, }, Exclusions: []*storage.Exclusion{ - { - Deployment: &storage.Exclusion_Deployment{ - Scope: &storage.Scope{ - Cluster: clusterName, - }, + {Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{ + Scope: &storage.Scope{ + Cluster: clusterName, }, + }}, }, }, Notifiers: []string{notifierName}, @@ -369,12 +368,11 @@ func (s *PolicyDatastoreTestSuite) TestDoesNotRemoveScopesAndNotifiers() { }, }, Exclusions: []*storage.Exclusion{ - { - Deployment: &storage.Exclusion_Deployment{ - Scope: &storage.Scope{ - Cluster: clusterID, - }, + {Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{ + Scope: &storage.Scope{ + Cluster: clusterID, }, + }}, }, }, Notifiers: []string{notifierName}, diff --git a/central/policy/matcher/cluster.go b/central/policy/matcher/cluster.go index b1b57f1bf151a..7196d41589c9b 100644 --- a/central/policy/matcher/cluster.go +++ b/central/policy/matcher/cluster.go @@ -48,6 +48,12 @@ func (m *clusterMatcher) anyExclusionMatches(exclusions []*storage.Exclusion) bo } func (m *clusterMatcher) exclusionMatches(exclusion *storage.Exclusion) bool { + // A kind exclusion does not take the policy off the cluster. Image-only exclusions have no + // deployment scope, and a nil scope would otherwise match every cluster. + if exclusion.GetDeployment() == nil { + return false + } + cs, err := scopecomp.CompileScope(exclusion.GetDeployment().GetScope(), nil, nil) if err != nil { utils.Should(errors.Wrap(err, "could not compile excluded scopes")) diff --git a/central/policy/matcher/cluster_test.go b/central/policy/matcher/cluster_test.go index 6ac6fe74ad1aa..e0b5532d19e4e 100644 --- a/central/policy/matcher/cluster_test.go +++ b/central/policy/matcher/cluster_test.go @@ -138,12 +138,11 @@ func TestClusterMatcherWithExclusion(t *testing.T) { }, }, Exclusions: []*storage.Exclusion{ - { - Deployment: &storage.Exclusion_Deployment{ - Scope: &storage.Scope{ - Namespace: "ns.*", - }, + {Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{ + Scope: &storage.Scope{ + Namespace: "ns.*", }, + }}, }, }, }, @@ -167,12 +166,11 @@ func TestClusterMatcherWithExclusion(t *testing.T) { }, }, Exclusions: []*storage.Exclusion{ - { - Deployment: &storage.Exclusion_Deployment{ - Scope: &storage.Scope{ - Namespace: "ns.*", - }, + {Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{ + Scope: &storage.Scope{ + Namespace: "ns.*", }, + }}, }, }, }, @@ -195,12 +193,11 @@ func TestClusterMatcherWithExclusion(t *testing.T) { }, }, Exclusions: []*storage.Exclusion{ - { - Deployment: &storage.Exclusion_Deployment{ - Scope: &storage.Scope{ - Cluster: "cluster1", - }, + {Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{ + Scope: &storage.Scope{ + Cluster: "cluster1", }, + }}, }, }, }, @@ -218,12 +215,11 @@ func TestClusterMatcherWithExclusion(t *testing.T) { }, policy: &storage.Policy{ Exclusions: []*storage.Exclusion{ - { - Deployment: &storage.Exclusion_Deployment{ - Scope: &storage.Scope{ - Namespace: "ns2.*", - }, + {Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{ + Scope: &storage.Scope{ + Namespace: "ns2.*", }, + }}, }, }, }, diff --git a/central/policy/matcher/deployment.go b/central/policy/matcher/deployment.go index 6058438bc79e8..86e035585a65f 100644 --- a/central/policy/matcher/deployment.go +++ b/central/policy/matcher/deployment.go @@ -56,6 +56,15 @@ func (m *deploymentMatcher) anyExclusionMatches(ctx context.Context, exclusions } func (m *deploymentMatcher) exclusionMatches(ctx context.Context, exclusion *storage.Exclusion) bool { + if !appliesToDeployments(exclusion) { + return false + } + // Kind exclusions have no deployment scope. Falling through would treat the nil scope as + // matching every deployment. + if exclusion.GetExcludeByKind() != nil { + return kindExclusionMatches(exclusion, m.deployment.GetType()) + } + // If excluded scope does not match the deployment then no need to check for deployment name if !m.scopeMatches(ctx, exclusion.GetDeployment().GetScope()) { return false diff --git a/central/policy/matcher/deployment_test.go b/central/policy/matcher/deployment_test.go index 5512d0339120d..1221d49a70e1b 100644 --- a/central/policy/matcher/deployment_test.go +++ b/central/policy/matcher/deployment_test.go @@ -101,12 +101,11 @@ func TestDeploymentWithExclusion(t *testing.T) { }, }, Exclusions: []*storage.Exclusion{ - { - Deployment: &storage.Exclusion_Deployment{ - Scope: &storage.Scope{ - Namespace: "ns.*", - }, + {Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{ + Scope: &storage.Scope{ + Namespace: "ns.*", }, + }}, }, }, }, @@ -126,13 +125,12 @@ func TestDeploymentWithExclusion(t *testing.T) { }, }, Exclusions: []*storage.Exclusion{ - { - Deployment: &storage.Exclusion_Deployment{ - Name: "deployment2", - Scope: &storage.Scope{ - Namespace: "ns.*", - }, + {Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{ + Name: "deployment2", + Scope: &storage.Scope{ + Namespace: "ns.*", }, + }}, }, }, }, @@ -151,18 +149,16 @@ func TestDeploymentWithExclusion(t *testing.T) { }, }, Exclusions: []*storage.Exclusion{ - { - Deployment: &storage.Exclusion_Deployment{ - Name: "deployment2", - Scope: &storage.Scope{ - Namespace: "ns1", - }, + {Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{ + Name: "deployment2", + Scope: &storage.Scope{ + Namespace: "ns1", }, + }}, }, - { - Deployment: &storage.Exclusion_Deployment{ - Name: "deployment1", - }, + {Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{ + Name: "deployment1", + }}, }, }, }, @@ -181,20 +177,18 @@ func TestDeploymentWithExclusion(t *testing.T) { }, }, Exclusions: []*storage.Exclusion{ - { - Deployment: &storage.Exclusion_Deployment{ - Name: "deployment2", - Scope: &storage.Scope{ - Namespace: "ns1", - }, + {Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{ + Name: "deployment2", + Scope: &storage.Scope{ + Namespace: "ns1", }, + }}, }, - { - Deployment: &storage.Exclusion_Deployment{ - Scope: &storage.Scope{ - Namespace: "ns1", - }, + {Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{ + Scope: &storage.Scope{ + Namespace: "ns1", }, + }}, }, }, }, diff --git a/central/policy/matcher/matcher.go b/central/policy/matcher/matcher.go index a80cd6c64ad54..c94097cd287c7 100644 --- a/central/policy/matcher/matcher.go +++ b/central/policy/matcher/matcher.go @@ -4,6 +4,8 @@ import ( "context" "github.com/stackrox/rox/generated/storage" + "github.com/stackrox/rox/pkg/features" + "github.com/stackrox/rox/pkg/kubernetes" ) // Matcher provides functionality to evaluate whether or not policies are applicable to an entity. @@ -11,3 +13,32 @@ type Matcher interface { FilterApplicablePolicies(ctx context.Context, policies []*storage.Policy) (applicable []*storage.Policy, notApplicable []*storage.Policy) IsPolicyApplicable(ctx context.Context, policy *storage.Policy) bool } + +// appliesToDeployments reports whether the exclusion can take a deployment out of policy scope. +// A deployment name/scope exclusion and a workload-kind exclusion both can. An image-only exclusion +// cannot: its nil deployment scope matches every deployment and would make the policy look +// inapplicable everywhere. +func appliesToDeployments(exclusion *storage.Exclusion) bool { + return exclusion.GetDeployment() != nil || exclusion.GetExcludeByKind() != nil +} + +// kindExclusionMatches reports whether a kind exclusion excludes this deployment. +// The feature flag gates it. A disabled flag leaves the policy applicable, matching detection. +func kindExclusionMatches(exclusion *storage.Exclusion, deploymentType string) bool { + if !features.PolicyWorkloadKindExclusion.Enabled() { + return false + } + for _, kind := range exclusion.GetExcludeByKind().GetKinds() { + switch kind { + case storage.Exclusion_CRON_JOB: + if deploymentType == kubernetes.CronJob { + return true + } + case storage.Exclusion_JOB: + if deploymentType == kubernetes.Job { + return true + } + } + } + return false +} diff --git a/central/policy/matcher/matcher_test.go b/central/policy/matcher/matcher_test.go new file mode 100644 index 0000000000000..0642a5308378c --- /dev/null +++ b/central/policy/matcher/matcher_test.go @@ -0,0 +1,79 @@ +package matcher + +import ( + "context" + "testing" + + "github.com/stackrox/rox/generated/storage" + "github.com/stackrox/rox/pkg/features" + "github.com/stackrox/rox/pkg/kubernetes" + "github.com/stackrox/rox/pkg/testutils" + "github.com/stretchr/testify/assert" +) + +// TestImageOnlyExclusionDoesNotExcludeEntities checks that an image-only exclusion leaves the policy +// applicable to every deployment, namespace, and cluster, while a deployment exclusion still excludes. +func TestImageOnlyExclusionDoesNotExcludeEntities(t *testing.T) { + ctx := context.Background() + deployment := &storage.Deployment{Name: "payments", ClusterId: "cluster1", Namespace: "shop"} + namespace := &storage.NamespaceMetadata{Name: "shop", ClusterId: "cluster1"} + cluster := &storage.Cluster{Id: "cluster1"} + + matchers := map[string]Matcher{ + "deployment": NewDeploymentMatcher(deployment, nil, nil), + "namespace": NewNamespaceMatcher(namespace), + "cluster": NewClusterMatcher(cluster, []*storage.NamespaceMetadata{namespace}), + } + + imageOnly := &storage.Policy{Exclusions: []*storage.Exclusion{ + {Image: &storage.Exclusion_Image{Name: "docker.io/library/nginx"}}, + }} + clusterExclusion := &storage.Policy{Exclusions: []*storage.Exclusion{ + {Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{Scope: &storage.Scope{Cluster: "cluster1"}}}}, + }} + + for name, m := range matchers { + t.Run(name, func(t *testing.T) { + assert.True(t, m.IsPolicyApplicable(ctx, imageOnly), "image-only exclusion should not exclude") + assert.False(t, m.IsPolicyApplicable(ctx, clusterExclusion), "cluster-scoped exclusion should exclude") + }) + } +} + +func TestKindExclusionExcludesMatchingDeploymentsOnly(t *testing.T) { + testutils.MustUpdateFeature(t, features.PolicyWorkloadKindExclusion, true) + ctx := context.Background() + namespace := &storage.NamespaceMetadata{Name: "shop", ClusterId: "cluster1"} + cluster := &storage.Cluster{Id: "cluster1"} + policy := &storage.Policy{Exclusions: []*storage.Exclusion{{ + Matcher: &storage.Exclusion_ExcludeByKind_{ + ExcludeByKind: &storage.Exclusion_ExcludeByKind{ + Kinds: []storage.Exclusion_WorkloadKind{storage.Exclusion_JOB, storage.Exclusion_CRON_JOB}, + }, + }, + }}} + + job := &storage.Deployment{Name: "batch", Type: kubernetes.Job, ClusterId: "cluster1", Namespace: "shop"} + cronJob := &storage.Deployment{Name: "nightly", Type: kubernetes.CronJob, ClusterId: "cluster1", Namespace: "shop"} + deploy := &storage.Deployment{Name: "web", Type: kubernetes.Deployment, ClusterId: "cluster1", Namespace: "shop"} + + assert.False(t, NewDeploymentMatcher(job, nil, nil).IsPolicyApplicable(ctx, policy)) + assert.False(t, NewDeploymentMatcher(cronJob, nil, nil).IsPolicyApplicable(ctx, policy)) + assert.True(t, NewDeploymentMatcher(deploy, nil, nil).IsPolicyApplicable(ctx, policy)) + assert.True(t, NewNamespaceMatcher(namespace).IsPolicyApplicable(ctx, policy)) + assert.True(t, NewClusterMatcher(cluster, []*storage.NamespaceMetadata{namespace}).IsPolicyApplicable(ctx, policy)) +} + +func TestKindExclusionFlagOffLeavesPolicyApplicable(t *testing.T) { + testutils.MustUpdateFeature(t, features.PolicyWorkloadKindExclusion, false) + job := &storage.Deployment{Name: "batch", Type: kubernetes.Job, ClusterId: "cluster1", Namespace: "shop"} + policy := &storage.Policy{Exclusions: []*storage.Exclusion{{ + Matcher: &storage.Exclusion_ExcludeByKind_{ + ExcludeByKind: &storage.Exclusion_ExcludeByKind{ + Kinds: []storage.Exclusion_WorkloadKind{storage.Exclusion_JOB}, + }, + }, + }}} + + assert.True(t, NewDeploymentMatcher(job, nil, nil).IsPolicyApplicable(context.Background(), policy)) +} diff --git a/central/policy/matcher/namespace.go b/central/policy/matcher/namespace.go index 1cf53532e9f72..6bd6ee7e7f2aa 100644 --- a/central/policy/matcher/namespace.go +++ b/central/policy/matcher/namespace.go @@ -46,6 +46,12 @@ func (m *namespaceMatcher) anyExclusionMatches(exclusions []*storage.Exclusion) } func (m *namespaceMatcher) exclusionMatches(exclusion *storage.Exclusion) bool { + // A kind exclusion does not take the policy off the namespace: other workload kinds there + // are still in scope. Image-only exclusions have no deployment scope, and a nil scope would + // otherwise match every namespace. + if exclusion.GetDeployment() == nil { + return false + } return m.scopeMatches(exclusion.GetDeployment().GetScope()) } diff --git a/central/policy/matcher/namespace_test.go b/central/policy/matcher/namespace_test.go index 4ca67b8d2755c..23bc5edb1b26a 100644 --- a/central/policy/matcher/namespace_test.go +++ b/central/policy/matcher/namespace_test.go @@ -114,12 +114,11 @@ func TestNamespaceMatcherWithWhitespace(t *testing.T) { }, }, Exclusions: []*storage.Exclusion{ - { - Deployment: &storage.Exclusion_Deployment{ - Scope: &storage.Scope{ - Namespace: "ns.*", - }, + {Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{ + Scope: &storage.Scope{ + Namespace: "ns.*", }, + }}, }, }, }, @@ -137,13 +136,12 @@ func TestNamespaceMatcherWithWhitespace(t *testing.T) { }, }, Exclusions: []*storage.Exclusion{ - { - Deployment: &storage.Exclusion_Deployment{ - Scope: &storage.Scope{ - Cluster: "cluster1", - Namespace: "ns1", - }, + {Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{ + Scope: &storage.Scope{ + Cluster: "cluster1", + Namespace: "ns1", }, + }}, }, }, }, @@ -161,12 +159,11 @@ func TestNamespaceMatcherWithWhitespace(t *testing.T) { }, }, Exclusions: []*storage.Exclusion{ - { - Deployment: &storage.Exclusion_Deployment{ - Scope: &storage.Scope{ - Cluster: "cluster1", - }, + {Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{ + Scope: &storage.Scope{ + Cluster: "cluster1", }, + }}, }, }, }, diff --git a/central/policy/service/validator.go b/central/policy/service/validator.go index 90f6dc87ddc97..38c93dec4bb9a 100644 --- a/central/policy/service/validator.go +++ b/central/policy/service/validator.go @@ -286,7 +286,7 @@ func (s *policyValidator) validateExclusions(policy *storage.Policy) error { } func (s *policyValidator) validateExclusion(policy *storage.Policy, exclusion *storage.Exclusion) error { - if exclusion.GetDeployment() == nil && exclusion.GetImage() == nil { + if exclusion.GetDeployment() == nil && exclusion.GetImage() == nil && exclusion.GetExcludeByKind() == nil { return errors.New("all excluded scopes must have some criteria to match on") } if exclusion.GetDeployment() != nil { @@ -297,6 +297,17 @@ func (s *policyValidator) validateExclusion(policy *storage.Policy, exclusion *s return err } } + if exclusion.GetExcludeByKind() != nil { + if !features.PolicyWorkloadKindExclusion.Enabled() { + return errors.New("exclude_by_kind requires feature flag ROX_POLICY_WORKLOAD_KIND_EXCLUSION to be enabled") + } + if !policies.AppliesAtDeployTime(policy) && !policies.AppliesAtRunTime(policy) { + return errors.New("excluding by workload kind is only valid during the DEPLOY and RUNTIME lifecycles") + } + if err := validateExcludeByKind(exclusion.GetExcludeByKind()); err != nil { + return err + } + } if exclusion.GetImage() != nil { if !policies.AppliesAtBuildTime(policy) { return errors.New("excluding an image is only valid during the BUILD lifecycle") @@ -308,6 +319,22 @@ func (s *policyValidator) validateExclusion(policy *storage.Policy, exclusion *s return nil } +func validateExcludeByKind(excludeByKind *storage.Exclusion_ExcludeByKind) error { + kinds := excludeByKind.GetKinds() + if len(kinds) == 0 { + return errors.New("exclude_by_kind must specify at least one workload kind") + } + for _, kind := range kinds { + if kind == storage.Exclusion_WORKLOAD_KIND_UNSPECIFIED { + return errors.New("exclude_by_kind cannot include WORKLOAD_KIND_UNSPECIFIED") + } + if kind != storage.Exclusion_CRON_JOB && kind != storage.Exclusion_JOB { + return errors.Errorf("exclude_by_kind contains unknown workload kind %s", kind) + } + } + return nil +} + func (s *policyValidator) validateDeploymentExclusion(exclusion *storage.Exclusion) error { deployment := exclusion.GetDeployment() if deployment.GetScope() == nil && deployment.GetName() == "" { @@ -510,14 +537,15 @@ func (s *policyValidator) validateEvaluationFilter(policy *storage.Policy) error if len(policy.GetEvaluationFilter().GetSkipContainerTypes()) == 0 { return nil } - if policies.AppliesAtBuildTime(policy) && !policies.AppliesAtDeployTime(policy) && !policies.AppliesAtRunTime(policy) { - return errors.New("container type filters in the evaluation filter are not applicable to build-only policies") - } - if s.isAuditEventPolicy(policy) { - return errors.New("container type filters in the evaluation filter are not applicable to audit log event policies") - } - if s.isNodeEventPolicy(policy) { - return errors.New("container type filters in the evaluation filter are not applicable to node event policies") + if !containerTypeFilterApplicable(policy) { + return errors.New("container type filters apply only to deploy-time policies and runtime policies with a deployment event source") } return nil } + +func containerTypeFilterApplicable(policy *storage.Policy) bool { + if policies.AppliesAtDeployTime(policy) { + return true + } + return policies.AppliesAtRunTime(policy) && policy.GetEventSource() == storage.EventSource_DEPLOYMENT_EVENT +} diff --git a/central/policy/service/validator_test.go b/central/policy/service/validator_test.go index 1e317de9785e4..784601206355f 100644 --- a/central/policy/service/validator_test.go +++ b/central/policy/service/validator_test.go @@ -614,9 +614,7 @@ func (s *PolicyValidatorTestSuite) TestValidateExclusions() { deployment := &storage.Exclusion_Deployment{ Name: "that phat cluster", } - deploymentExclusion := &storage.Exclusion{ - Deployment: deployment, - } + deploymentExclusion := &storage.Exclusion{Matcher: &storage.Exclusion_Deployment_{Deployment: deployment}} policy = &storage.Policy{ LifecycleStages: []storage.LifecycleStage{ storage.LifecycleStage_DEPLOY, @@ -661,14 +659,13 @@ func (s *PolicyValidatorTestSuite) TestValidateExclusions() { err = s.validator.validateExclusions(policy) s.Error(err, "excluded scope requires either container or deployment configuration") - emptyLabelExclusion := &storage.Exclusion{ - Deployment: &storage.Exclusion_Deployment{ - Scope: &storage.Scope{ - Label: &storage.Scope_Label{ - Key: "", - }, + emptyLabelExclusion := &storage.Exclusion{Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{ + Scope: &storage.Scope{ + Label: &storage.Scope_Label{ + Key: "", }, }, + }}, } policy = &storage.Policy{ Exclusions: []*storage.Exclusion{ @@ -678,15 +675,14 @@ func (s *PolicyValidatorTestSuite) TestValidateExclusions() { err = s.validator.validateExclusions(policy) s.Error(err, "label regex in excluded scope, if not nil, must be non-empty") - anyKeyLabelExclusion := &storage.Exclusion{ - Deployment: &storage.Exclusion_Deployment{ - Scope: &storage.Scope{ - Label: &storage.Scope_Label{ - Key: ".*", - Value: "", - }, + anyKeyLabelExclusion := &storage.Exclusion{Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{ + Scope: &storage.Scope{ + Label: &storage.Scope_Label{ + Key: ".*", + Value: "", }, }, + }}, } policy = &storage.Policy{ LifecycleStages: []storage.LifecycleStage{ @@ -698,15 +694,14 @@ func (s *PolicyValidatorTestSuite) TestValidateExclusions() { } s.NoError(s.validator.validateExclusions(policy)) - anyLabelExclusion := &storage.Exclusion{ - Deployment: &storage.Exclusion_Deployment{ - Scope: &storage.Scope{ - Label: &storage.Scope_Label{ - Key: ".*", - Value: ".*", - }, + anyLabelExclusion := &storage.Exclusion{Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{ + Scope: &storage.Scope{ + Label: &storage.Scope_Label{ + Key: ".*", + Value: ".*", }, }, + }}, } policy = &storage.Policy{ LifecycleStages: []storage.LifecycleStage{ @@ -719,6 +714,79 @@ func (s *PolicyValidatorTestSuite) TestValidateExclusions() { s.NoError(s.validator.validateExclusions(policy)) } +func (s *PolicyValidatorTestSuite) TestValidateExcludeByKind() { + kindExclusion := func(kinds ...storage.Exclusion_WorkloadKind) *storage.Exclusion { + return &storage.Exclusion{ + Matcher: &storage.Exclusion_ExcludeByKind_{ + ExcludeByKind: &storage.Exclusion_ExcludeByKind{Kinds: kinds}, + }, + } + } + deployPolicy := func(exclusion *storage.Exclusion) *storage.Policy { + return &storage.Policy{ + LifecycleStages: []storage.LifecycleStage{storage.LifecycleStage_DEPLOY}, + Exclusions: []*storage.Exclusion{exclusion}, + } + } + + s.ErrorContains(s.validator.validateExclusions(deployPolicy(kindExclusion(storage.Exclusion_JOB))), "ROX_POLICY_WORKLOAD_KIND_EXCLUSION") + + testutils.MustUpdateFeature(s.T(), features.PolicyWorkloadKindExclusion, true) + + for name, tc := range map[string]struct { + policy *storage.Policy + errContains string + }{ + "JOB is valid": { + policy: deployPolicy(kindExclusion(storage.Exclusion_JOB)), + }, + "CRON_JOB is valid": { + policy: deployPolicy(kindExclusion(storage.Exclusion_CRON_JOB)), + }, + "JOB and CRON_JOB are valid": { + policy: deployPolicy(kindExclusion(storage.Exclusion_CRON_JOB, storage.Exclusion_JOB)), + }, + "empty kind list is rejected": { + policy: deployPolicy(kindExclusion()), + errContains: "at least one workload kind", + }, + "UNSPECIFIED is rejected": { + policy: deployPolicy(kindExclusion(storage.Exclusion_WORKLOAD_KIND_UNSPECIFIED)), + errContains: "WORKLOAD_KIND_UNSPECIFIED", + }, + "unknown kind is rejected": { + policy: deployPolicy(kindExclusion(storage.Exclusion_WorkloadKind(99))), + errContains: "unknown workload kind", + }, + "mixed valid and unknown kinds are rejected": { + policy: deployPolicy(kindExclusion(storage.Exclusion_JOB, storage.Exclusion_WorkloadKind(99))), + errContains: "unknown workload kind", + }, + "RUNTIME lifecycle is valid": { + policy: &storage.Policy{ + LifecycleStages: []storage.LifecycleStage{storage.LifecycleStage_RUNTIME}, + Exclusions: []*storage.Exclusion{kindExclusion(storage.Exclusion_JOB)}, + }, + }, + "BUILD lifecycle is rejected": { + policy: &storage.Policy{ + LifecycleStages: []storage.LifecycleStage{storage.LifecycleStage_BUILD}, + Exclusions: []*storage.Exclusion{kindExclusion(storage.Exclusion_JOB)}, + }, + errContains: "DEPLOY and RUNTIME", + }, + } { + s.T().Run(name, func(t *testing.T) { + err := s.validator.validateExclusions(tc.policy) + if tc.errContains == "" { + assert.NoError(t, err) + } else { + assert.ErrorContains(t, err, tc.errContains) + } + }) + } +} + func (s *PolicyValidatorTestSuite) TestValidateExclusionRejectsLabels() { for name, tc := range map[string]struct { exclusion *storage.Exclusion @@ -726,44 +794,40 @@ func (s *PolicyValidatorTestSuite) TestValidateExclusionRejectsLabels() { errContains string }{ "cluster_label on exclusion scope is rejected": { - exclusion: &storage.Exclusion{ - Deployment: &storage.Exclusion_Deployment{ - Scope: &storage.Scope{ - ClusterLabel: &storage.Scope_Label{Key: "env", Value: "prod"}, - }, + exclusion: &storage.Exclusion{Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{ + Scope: &storage.Scope{ + ClusterLabel: &storage.Scope_Label{Key: "env", Value: "prod"}, }, + }}, }, errExpected: true, errContains: "cluster labels", }, "namespace_label on exclusion scope is rejected": { - exclusion: &storage.Exclusion{ - Deployment: &storage.Exclusion_Deployment{ - Scope: &storage.Scope{ - NamespaceLabel: &storage.Scope_Label{Key: "team", Value: "backend"}, - }, + exclusion: &storage.Exclusion{Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{ + Scope: &storage.Scope{ + NamespaceLabel: &storage.Scope_Label{Key: "team", Value: "backend"}, }, + }}, }, errExpected: true, errContains: "namespace labels", }, "deployment label on exclusion scope is allowed": { - exclusion: &storage.Exclusion{ - Deployment: &storage.Exclusion_Deployment{ - Scope: &storage.Scope{ - Label: &storage.Scope_Label{Key: "app", Value: "nginx"}, - }, + exclusion: &storage.Exclusion{Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{ + Scope: &storage.Scope{ + Label: &storage.Scope_Label{Key: "app", Value: "nginx"}, }, + }}, }, errExpected: false, }, "cluster ID on exclusion scope is allowed": { - exclusion: &storage.Exclusion{ - Deployment: &storage.Exclusion_Deployment{ - Scope: &storage.Scope{ - Cluster: "cluster-1", - }, + exclusion: &storage.Exclusion{Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{ + Scope: &storage.Scope{ + Cluster: "cluster-1", }, + }}, }, errExpected: false, }, @@ -1391,19 +1455,25 @@ func (s *PolicyValidatorTestSuite) TestValidateEvaluationFilter() { lifecycleStages: []storage.LifecycleStage{storage.LifecycleStage_DEPLOY}, skipContainerTypes: []storage.ContainerType{storage.ContainerType_INIT}, }, + "deploy with skip regular is allowed": { + lifecycleStages: []storage.LifecycleStage{storage.LifecycleStage_DEPLOY}, + skipContainerTypes: []storage.ContainerType{storage.ContainerType_REGULAR}, + }, "build + deploy with skip init is allowed": { lifecycleStages: []storage.LifecycleStage{storage.LifecycleStage_BUILD, storage.LifecycleStage_DEPLOY}, skipContainerTypes: []storage.ContainerType{storage.ContainerType_INIT}, }, - "runtime with skip init is allowed": { - lifecycleStages: []storage.LifecycleStage{storage.LifecycleStage_RUNTIME}, - skipContainerTypes: []storage.ContainerType{storage.ContainerType_INIT}, - }, "build-only with no filter is allowed": { lifecycleStages: []storage.LifecycleStage{storage.LifecycleStage_BUILD}, }, - "no lifecycle stages with skip init is allowed": { + "runtime without event source with skip init is rejected": { + lifecycleStages: []storage.LifecycleStage{storage.LifecycleStage_RUNTIME}, + skipContainerTypes: []storage.ContainerType{storage.ContainerType_INIT}, + expectError: true, + }, + "no lifecycle stages with skip init is rejected": { skipContainerTypes: []storage.ContainerType{storage.ContainerType_INIT}, + expectError: true, }, "audit log event with skip init is rejected": { lifecycleStages: []storage.LifecycleStage{storage.LifecycleStage_RUNTIME}, @@ -1422,6 +1492,11 @@ func (s *PolicyValidatorTestSuite) TestValidateEvaluationFilter() { eventSource: storage.EventSource_DEPLOYMENT_EVENT, skipContainerTypes: []storage.ContainerType{storage.ContainerType_INIT}, }, + "deployment event with skip regular is allowed": { + lifecycleStages: []storage.LifecycleStage{storage.LifecycleStage_RUNTIME}, + eventSource: storage.EventSource_DEPLOYMENT_EVENT, + skipContainerTypes: []storage.ContainerType{storage.ContainerType_REGULAR}, + }, } for name, tc := range tests { diff --git a/central/postgres/pruning.go b/central/postgres/pruning.go index 14cdad7d9e2b3..2bb614e068468 100644 --- a/central/postgres/pruning.go +++ b/central/postgres/pruning.go @@ -29,6 +29,9 @@ const ( getAllOrphanedNodes = `SELECT id FROM nodes WHERE NOT EXISTS (SELECT 1 FROM clusters WHERE nodes.clusterid = clusters.Id)` + getAllOrphanedDeployments = `SELECT id, clusterid FROM deployments WHERE NOT EXISTS + (SELECT 1 FROM clusters WHERE deployments.clusterid = clusters.Id)` + getOrphanedProcessesByDeployment = `SELECT id FROM process_indicators pi WHERE NOT EXISTS (SELECT 1 FROM deployments WHERE pi.deploymentid = deployments.Id) AND (signal_time < now() AT time zone 'utc' - INTERVAL '%d MINUTES' OR signal_time IS NULL)` @@ -189,6 +192,37 @@ func GetOrphanedNodeIDs(ctx context.Context, pool postgres.DB) ([]string, error) }) } +// OrphanedDeployment holds a deployment id with its clusterid +type OrphanedDeployment struct { + ID string + ClusterID string +} + +// GetOrphanedDeploymentIDs returns the deployments that have a cluster that has been removed. +func GetOrphanedDeploymentIDs(ctx context.Context, pool postgres.DB) ([]OrphanedDeployment, error) { + return pgutils.Retry2(ctx, func() ([]OrphanedDeployment, error) { + ctx, cancel := context.WithTimeout(ctx, orphanedQueryTimeout) + defer cancel() + + rows, err := pool.Query(ctx, getAllOrphanedDeployments) + if err != nil { + return nil, errors.Wrap(err, "failed to get orphaned deployments") + } + return pgx.CollectRows(rows, func(r pgx.CollectableRow) (OrphanedDeployment, error) { + var d OrphanedDeployment + // clusterid is nullable; scan into a pointer so a NULL does not abort the pruning cycle. + var clusterID *string + if err := r.Scan(&d.ID, &clusterID); err != nil { + return OrphanedDeployment{}, errors.Wrap(err, "scanning orphaned deployment") + } + if clusterID != nil { + d.ClusterID = *clusterID + } + return d, nil + }) + }) +} + // GetOrphanedProcessIDsByDeployment returns the process ids that have a deployment that has been removed. func GetOrphanedProcessIDsByDeployment(ctx context.Context, pool postgres.DB, orphanWindow time.Duration) ([]string, error) { return pgutils.Retry2(ctx, func() ([]string, error) { diff --git a/central/postgres/pruning_test.go b/central/postgres/pruning_test.go index c788459a7588d..ade6dd5c22796 100644 --- a/central/postgres/pruning_test.go +++ b/central/postgres/pruning_test.go @@ -233,6 +233,68 @@ func (s *PostgresPruningSuite) TestGetOrphanedPodIDs() { s.Equal(len(idsToPrune), cluster2PodCount) } +func (s *PostgresPruningSuite) TestGetOrphanedDeploymentIDs() { + deploymentDS, err := deploymentStore.GetTestPostgresDataStore(s.T(), s.testDB.DB) + s.Require().NoError(err) + + clusterDS, err := clusterStore.GetTestPostgresDataStore(s.T(), s.testDB.DB) + s.Require().NoError(err) + + liveClusterID, err := clusterDS.AddCluster(s.ctx, &storage.Cluster{Name: "testOrphanDeploymentCluster", MainImage: "docker.io/stackrox/rox:latest"}) + s.Require().NoError(err) + + // Deployment tied to a live cluster - never orphaned. + liveDeploymentID := uuid.NewV4().String() + s.Require().NoError(deploymentDS.UpsertDeployment(s.ctx, &storage.Deployment{Id: liveDeploymentID, ClusterId: liveClusterID})) + + // Deployments whose clusterid has no matching cluster row - orphaned. This mirrors + // the field scenario where a cluster is hard-deleted but its deployments survive. + orphanClusterID := fixtureconsts.Cluster1 + orphanedIDs := set.NewStringSet() + for range 3 { + id := uuid.NewV4().String() + orphanedIDs.Add(id) + s.Require().NoError(deploymentDS.UpsertDeployment(s.ctx, &storage.Deployment{Id: id, ClusterId: orphanClusterID})) + } + + orphaned, err := GetOrphanedDeploymentIDs(s.ctx, s.testDB.DB) + s.Require().NoError(err) + + got := set.NewStringSet() + for _, d := range orphaned { + got.Add(d.ID) + s.Equal(orphanClusterID, d.ClusterID) + } + s.Equal(orphanedIDs, got) + s.NotContains(got.AsSlice(), liveDeploymentID) +} + +// A deployment with a NULL clusterid must not abort the sweep; it is orphaned (no matching +// cluster row) and must be returned with an empty ClusterID. +func (s *PostgresPruningSuite) TestGetOrphanedDeploymentIDsHandlesNullClusterID() { + deploymentDS, err := deploymentStore.GetTestPostgresDataStore(s.T(), s.testDB.DB) + s.Require().NoError(err) + + // Upsert with a non-matching cluster id, then null out the collumn, to verify + // the pruning works in the unlikely case deployments without clusterid made it to the DB + nullClusterDeploymentID := uuid.NewV4().String() + s.Require().NoError(deploymentDS.UpsertDeployment(s.ctx, &storage.Deployment{Id: nullClusterDeploymentID, ClusterId: fixtureconsts.Cluster1})) + _, err = s.testDB.DB.Exec(s.ctx, "UPDATE deployments SET clusterid = NULL WHERE id = $1", nullClusterDeploymentID) + s.Require().NoError(err) + + orphaned, err := GetOrphanedDeploymentIDs(s.ctx, s.testDB.DB) + s.Require().NoError(err) + + got := set.NewStringSet() + for _, d := range orphaned { + got.Add(d.ID) + if d.ID == nullClusterDeploymentID { + s.Empty(d.ClusterID) + } + } + s.Contains(got.AsSlice(), nullClusterDeploymentID) +} + func (s *PostgresPruningSuite) TestRemoveOrphanedProcesses() { cases := []struct { name string diff --git a/central/processlisteningonport/datastore/datastore.go b/central/processlisteningonport/datastore/datastore.go index d7744f88b2b32..f7308a5a418ed 100644 --- a/central/processlisteningonport/datastore/datastore.go +++ b/central/processlisteningonport/datastore/datastore.go @@ -29,12 +29,9 @@ type DataStore interface { deployment string, ) ([]*storage.ProcessListeningOnPort, error) WalkAll(ctx context.Context, fn WalkFn) error - RemoveProcessListeningOnPort(ctx context.Context, ids []string) error RemovePlopsByPod(ctx context.Context, id string) error PruneOrphanedPLOPs(ctx context.Context, orphanWindow time.Duration) int64 - PruneOrphanedPLOPsByProcessIndicators(ctx context.Context, orphanWindow time.Duration) RemovePLOPsWithoutProcessIndicatorOrProcessInfo(ctx context.Context) (int64, error) - RemovePLOPsWithoutPodUID(ctx context.Context) (int64, error) } // New creates a data store object to access the database. Since some diff --git a/central/processlisteningonport/datastore/datastore_impl.go b/central/processlisteningonport/datastore/datastore_impl.go index cd8219320a726..3783a97139f7b 100644 --- a/central/processlisteningonport/datastore/datastore_impl.go +++ b/central/processlisteningonport/datastore/datastore_impl.go @@ -306,25 +306,6 @@ func (ds *datastoreImpl) WalkAll(ctx context.Context, fn WalkFn) error { return ds.storage.Walk(ctx, fn) } -func (ds *datastoreImpl) RemoveProcessListeningOnPort(ctx context.Context, ids []string) error { - if ok, err := plopSAC.WriteAllowed(ctx); err != nil { - return err - } else if !ok { - return sac.ErrResourceAccessDenied - } - - return ds.removePLOP(ctx, ids) -} - -func (ds *datastoreImpl) removePLOP(ctx context.Context, ids []string) error { - - if len(ids) == 0 { - return nil - } - - return ds.storage.DeleteMany(ctx, ids) -} - func (ds *datastoreImpl) fetchExistingPLOPs( ctx context.Context, indicatorIds []string, @@ -596,27 +577,6 @@ func (ds *datastoreImpl) PruneOrphanedPLOPs(ctx context.Context, orphanWindow ti return commandTag.RowsAffected() } -// PruneOrphanedPLOPsByProcessIndicators prunes PLOPs that match process indicators without pods -func (ds *datastoreImpl) PruneOrphanedPLOPsByProcessIndicators(ctx context.Context, orphanWindow time.Duration) { - // TODO(ROX-22443): Once it is guaranteed that all listening endpoints have PodUIDs, remove this function - ds.mutex.Lock() - defer ds.mutex.Unlock() - - // Delete processes listening on ports orphaned because process indicators are orphaned due to - // missing deployments - query := fmt.Sprintf(deleteOrphanedPLOPDeploymentsAndPI, int(orphanWindow.Minutes())) - if _, err := ds.pool.Exec(ctx, query); err != nil { - log.Errorf("failed to prune process listening on ports by deployment: %v", err) - } - - // Delete processes listening on ports orphaned because process indicators are orphaned due to - // missing pods. - query = fmt.Sprintf(deleteOrphanedPLOPPods, int(orphanWindow.Minutes())) - if _, err := ds.pool.Exec(ctx, query); err != nil { - log.Errorf("failed to prune process listening on ports by pods: %v", err) - } -} - func (ds *datastoreImpl) readRowsToFindPLOPsWithNoProcessInformation(rows pgx.Rows) ([]string, error) { var ids []string @@ -672,89 +632,3 @@ func (ds *datastoreImpl) RemovePLOPsWithoutProcessIndicatorOrProcessInfo(ctx con return int64(len(plopsToDelete)), nil } - -// Removes PLOPs without poduids between a range of ids. -func (ds *datastoreImpl) removePLOPsWithoutPodUIDOnePage(ctx context.Context, prevId string, nextId string) (int64, error) { - ds.mutex.Lock() - defer ds.mutex.Unlock() - - query := fmt.Sprintf(deletePLOPsWithoutPoduidInPage, prevId, nextId) - commandTag, err := ds.pool.Exec(ctx, query) - - if err != nil { - return 0, err - } - - return commandTag.RowsAffected(), nil -} - -// Given a set of rows with ids, returns the id of the last row. This is useful for pagination. -func (ds *datastoreImpl) getLastIdFromRows(ctx context.Context, rows pgx.Rows) (string, error) { - id := "" - - for rows.Next() { - if err := rows.Scan(&id); err != nil { - return "", pgutils.ErrNilIfNoRows(err) - } - } - - return id, rows.Err() -} - -// Given an id and a limit, returns the id a limit number of rows after the given id. This is useful -// for efficient pagination. -func (ds *datastoreImpl) getNextPageId(ctx context.Context, prevId string, limit int) (string, error) { - ds.mutex.Lock() - defer ds.mutex.Unlock() - - query := fmt.Sprintf(getLastIdFromPage, prevId, limit) - rows, err := ds.pool.Query(ctx, query) - - if err != nil { - // Do not be alarmed if the error is simply NoRows - err = pgutils.ErrNilIfNoRows(err) - if err != nil { - log.Warnf("%s: %s", query, err) - } - return "", err - } - defer rows.Close() - - nextId, err := ds.getLastIdFromRows(ctx, rows) - - if err != nil { - return "", err - } - - return nextId, nil -} - -func (ds *datastoreImpl) retryableRemovePLOPsWithoutPodUID(ctx context.Context) (int64, error) { - limit := 10000 - totalRows := int64(0) - - prevId := "00000000-0000-0000-0000-000000000000" - for { - nextId, err := ds.getNextPageId(ctx, prevId, limit) - if err != nil { - return totalRows, err - } - if nextId == "" { - break - } - nrows, err := ds.removePLOPsWithoutPodUIDOnePage(ctx, prevId, nextId) - if err != nil { - return totalRows, err - } - totalRows += nrows - prevId = nextId - } - - return totalRows, nil -} - -func (ds *datastoreImpl) RemovePLOPsWithoutPodUID(ctx context.Context) (int64, error) { - return pgutils.Retry2(ctx, func() (int64, error) { - return ds.retryableRemovePLOPsWithoutPodUID(ctx) - }) -} diff --git a/central/processlisteningonport/datastore/datastore_impl_test.go b/central/processlisteningonport/datastore/datastore_impl_test.go index 6acfb31cf64af..66d5619a04dac 100644 --- a/central/processlisteningonport/datastore/datastore_impl_test.go +++ b/central/processlisteningonport/datastore/datastore_impl_test.go @@ -6,7 +6,6 @@ import ( "context" "fmt" "math/rand" - "slices" "testing" "time" @@ -2500,174 +2499,6 @@ func (suite *PLOPDataStoreTestSuite) TestRemoveOrphanedPLOPs() { } } -func newIndicatorWithDeployment(id string, age time.Duration, deploymentID string) *storage.ProcessIndicator { - return &storage.ProcessIndicator{ - Id: id, - DeploymentId: deploymentID, - ContainerName: "", - PodId: "", - Signal: &storage.ProcessSignal{ - Time: protoconv.NowMinus(age), - }, - } -} - -func newIndicatorWithDeploymentAndPod(id string, age time.Duration, deploymentID, podUID string) *storage.ProcessIndicator { - indicator := newIndicatorWithDeployment(id, age, deploymentID) - indicator.PodUid = podUID - return indicator -} - -func (suite *PLOPDataStoreTestSuite) TestRemoveOrphanedPLOPsByProcesses() { - orphanWindow := 30 * time.Minute - - cases := []struct { - name string - initialProcesses []*storage.ProcessIndicator - initialPlops []*storage.ProcessListeningOnPortStorage - deployments set.FrozenStringSet - pods set.FrozenStringSet - expectedPlopDeletions []string - }{ - { - name: "no deployments nor pods - remove all old indicators", - initialProcesses: []*storage.ProcessIndicator{ - newIndicatorWithDeploymentAndPod(fixtureconsts.ProcessIndicatorID1, 1*time.Hour, fixtureconsts.Deployment6, fixtureconsts.PodUID1), - newIndicatorWithDeploymentAndPod(fixtureconsts.ProcessIndicatorID2, 1*time.Hour, fixtureconsts.Deployment5, fixtureconsts.PodUID2), - newIndicatorWithDeploymentAndPod(fixtureconsts.ProcessIndicatorID3, 1*time.Hour, fixtureconsts.Deployment3, fixtureconsts.PodUID3), - }, - initialPlops: []*storage.ProcessListeningOnPortStorage{ - fixtures.GetPlopStorage1(), - fixtures.GetPlopStorage2(), - fixtures.GetPlopStorage3(), - fixtures.GetPlopStorage4(), - fixtures.GetPlopStorage5(), - fixtures.GetPlopStorage6(), - }, - deployments: set.NewFrozenStringSet(), - pods: set.NewFrozenStringSet(), - expectedPlopDeletions: []string{ - fixtureconsts.PlopUID1, - fixtureconsts.PlopUID2, - fixtureconsts.PlopUID3, - fixtureconsts.PlopUID4, - fixtureconsts.PlopUID5, - fixtureconsts.PlopUID6, - }, - }, - { - name: "no deployments nor pods - remove no new orphaned indicators", - initialProcesses: []*storage.ProcessIndicator{ - newIndicatorWithDeploymentAndPod(fixtureconsts.ProcessIndicatorID1, 20*time.Minute, fixtureconsts.Deployment6, fixtureconsts.PodUID1), - newIndicatorWithDeploymentAndPod(fixtureconsts.ProcessIndicatorID2, 20*time.Minute, fixtureconsts.Deployment5, fixtureconsts.PodUID2), - newIndicatorWithDeploymentAndPod(fixtureconsts.ProcessIndicatorID3, 20*time.Minute, fixtureconsts.Deployment3, fixtureconsts.PodUID3), - }, - initialPlops: []*storage.ProcessListeningOnPortStorage{ - fixtures.GetPlopStorage1(), - fixtures.GetPlopStorage2(), - fixtures.GetPlopStorage3(), - }, - deployments: set.NewFrozenStringSet(), - pods: set.NewFrozenStringSet(), - expectedPlopDeletions: nil, - }, - { - name: "all pods separate deployments - remove no indicators", - initialProcesses: []*storage.ProcessIndicator{ - newIndicatorWithDeploymentAndPod(fixtureconsts.ProcessIndicatorID1, 1*time.Hour, fixtureconsts.Deployment6, fixtureconsts.PodUID1), - newIndicatorWithDeploymentAndPod(fixtureconsts.ProcessIndicatorID2, 1*time.Hour, fixtureconsts.Deployment5, fixtureconsts.PodUID2), - newIndicatorWithDeploymentAndPod(fixtureconsts.ProcessIndicatorID3, 1*time.Hour, fixtureconsts.Deployment3, fixtureconsts.PodUID3), - }, - initialPlops: []*storage.ProcessListeningOnPortStorage{ - fixtures.GetPlopStorage1(), - fixtures.GetPlopStorage2(), - fixtures.GetPlopStorage3(), - }, - deployments: set.NewFrozenStringSet(fixtureconsts.Deployment6, fixtureconsts.Deployment5, fixtureconsts.Deployment3), - pods: set.NewFrozenStringSet(fixtureconsts.PodUID1, fixtureconsts.PodUID2, fixtureconsts.PodUID3), - expectedPlopDeletions: nil, - }, - { - name: "all pods same deployment - remove no indicators", - initialProcesses: []*storage.ProcessIndicator{ - newIndicatorWithDeploymentAndPod(fixtureconsts.ProcessIndicatorID1, 1*time.Hour, fixtureconsts.Deployment6, fixtureconsts.PodUID1), - newIndicatorWithDeploymentAndPod(fixtureconsts.ProcessIndicatorID2, 1*time.Hour, fixtureconsts.Deployment6, fixtureconsts.PodUID2), - newIndicatorWithDeploymentAndPod(fixtureconsts.ProcessIndicatorID3, 1*time.Hour, fixtureconsts.Deployment6, fixtureconsts.PodUID3), - }, - deployments: set.NewFrozenStringSet(fixtureconsts.Deployment6), - pods: set.NewFrozenStringSet(fixtureconsts.PodUID1, fixtureconsts.PodUID2, fixtureconsts.PodUID3), - expectedPlopDeletions: nil, - }, - { - name: "some pods separate deployments - remove some indicators", - initialProcesses: []*storage.ProcessIndicator{ - newIndicatorWithDeploymentAndPod(fixtureconsts.ProcessIndicatorID1, 1*time.Hour, fixtureconsts.Deployment6, fixtureconsts.PodUID1), - newIndicatorWithDeploymentAndPod(fixtureconsts.ProcessIndicatorID2, 20*time.Minute, fixtureconsts.Deployment5, fixtureconsts.PodUID2), - newIndicatorWithDeploymentAndPod(fixtureconsts.ProcessIndicatorID3, 1*time.Hour, fixtureconsts.Deployment3, fixtureconsts.PodUID3), - }, - initialPlops: []*storage.ProcessListeningOnPortStorage{ - fixtures.GetPlopStorage1(), - fixtures.GetPlopStorage2(), - fixtures.GetPlopStorage3(), - }, - deployments: set.NewFrozenStringSet(fixtureconsts.Deployment3), - pods: set.NewFrozenStringSet(fixtureconsts.PodUID3), - expectedPlopDeletions: []string{fixtureconsts.PlopUID1}, - }, - { - name: "some pods same deployment - remove some indicators", - initialProcesses: []*storage.ProcessIndicator{ - newIndicatorWithDeploymentAndPod(fixtureconsts.ProcessIndicatorID1, 1*time.Hour, fixtureconsts.Deployment6, fixtureconsts.PodUID1), - newIndicatorWithDeploymentAndPod(fixtureconsts.ProcessIndicatorID2, 20*time.Minute, fixtureconsts.Deployment6, fixtureconsts.PodUID2), - newIndicatorWithDeploymentAndPod(fixtureconsts.ProcessIndicatorID3, 1*time.Hour, fixtureconsts.Deployment6, fixtureconsts.PodUID3), - }, - initialPlops: []*storage.ProcessListeningOnPortStorage{ - fixtures.GetPlopStorage1(), - fixtures.GetPlopStorage2(), - fixtures.GetPlopStorage3(), - }, - deployments: set.NewFrozenStringSet(fixtureconsts.Deployment6), - pods: set.NewFrozenStringSet(fixtureconsts.PodUID3), - expectedPlopDeletions: []string{fixtureconsts.PlopUID1}, - }, - } - for _, c := range cases { - suite.T().Run(c.name, func(t *testing.T) { - suite.SetupTest() - // Add deployments if necessary - deploymentDS, err := deploymentStore.GetTestPostgresDataStore(suite.T(), suite.postgres.DB) - suite.Nil(err) - for deploymentID := range c.deployments.All() { - suite.NoError(deploymentDS.UpsertDeployment(suite.hasAllCtx, &storage.Deployment{Id: deploymentID, ClusterId: fixtureconsts.Cluster1})) - } - - for podID := range c.pods.All() { - insertPod := fmt.Sprintf("INSERT INTO pods (id, clusterid) VALUES ('%s', '%s')", podID, fixtureconsts.Cluster1) - _, err := suite.postgres.DB.Exec(suite.hasWriteCtx, insertPod) - suite.Nil(err) - } - - suite.NoError(suite.indicatorDataStore.AddProcessIndicators(suite.hasWriteCtx, c.initialProcesses...)) - countFromDB, err := suite.indicatorDataStore.Count(suite.hasAllCtx, nil) - suite.NoError(err) - suite.Equal(len(c.initialProcesses), countFromDB) - - err = suite.store.UpsertMany(suite.hasWriteCtx, c.initialPlops) - suite.NoError(err) - plopCount, err := suite.store.Count(suite.hasReadCtx, search.EmptyQuery()) - suite.NoError(err) - suite.Equal(len(c.initialPlops), plopCount) - - suite.datastore.PruneOrphanedPLOPsByProcessIndicators(suite.hasAllCtx, orphanWindow) - - plopCount, err = suite.store.Count(suite.hasReadCtx, search.EmptyQuery()) - suite.NoError(err) - suite.Equal(len(c.initialPlops)-len(c.expectedPlopDeletions), plopCount) - - }) - } -} - // RemovePLOPsWithoutProcessIndicatorOrProcessInfo Adds a PLOP with a matching process indicator. // The process indicator is then deleted. This means that the PLOP has no matching // process indicator and does not have any process information. A pruning function @@ -2702,176 +2533,3 @@ func (suite *PLOPDataStoreTestSuite) RemovePLOPsWithoutProcessIndicatorOrProcess newPlopsFromDB := suite.getPlopsFromDB() suite.Len(newPlopsFromDB, 0) } - -func (suite *PLOPDataStoreTestSuite) TestRemovePLOPsWithoutPodUID() { - initialPlops := []*storage.ProcessListeningOnPortStorage{ - fixtures.GetPlopStorage1(), - fixtures.GetPlopStorage2(), - fixtures.GetPlopStorage3(), - fixtures.GetPlopStorage4(), - fixtures.GetPlopStorage5(), - fixtures.GetPlopStorage6(), - } - expectedPlopDeletions := []string{fixtureconsts.PlopUID1, fixtureconsts.PlopUID2, fixtureconsts.PlopUID3} - - err := suite.store.UpsertMany(suite.hasWriteCtx, initialPlops) - suite.NoError(err) - plopCount, err := suite.store.Count(suite.hasReadCtx, search.EmptyQuery()) - suite.NoError(err) - suite.Equal(len(initialPlops), plopCount) - - prunedCount, err := suite.datastore.RemovePLOPsWithoutPodUID(suite.hasWriteCtx) - suite.NoError(err) - suite.Equal(int64(3), prunedCount) - - plopCount, err = suite.store.Count(suite.hasReadCtx, search.EmptyQuery()) - suite.NoError(err) - suite.Equal(len(initialPlops)-len(expectedPlopDeletions), plopCount) - - ids, err := suite.store.GetIDs(suite.hasReadCtx) - suite.NoError(err) - for id := range ids { - suite.NotContains(expectedPlopDeletions, id) - } -} - -func (suite *PLOPDataStoreTestSuite) addTooMany(plops []*storage.ProcessListeningOnPortFromSensor) error { - batchSize := 30000 - - for plopBatch := range slices.Chunk(plops, batchSize) { - // Per-batch deadline so ContextWithTimeoutIfNotExists skips the - // 60-second default without sharing one budget across all batches. - ctx, cancel := context.WithTimeout(suite.hasWriteCtx, 5*time.Minute) - err := suite.datastore.AddProcessListeningOnPort(ctx, fixtureconsts.Cluster1, plopBatch...) - cancel() - if err != nil { - return err - } - } - return nil -} - -func (suite *PLOPDataStoreTestSuite) RemovePLOPsWithoutPodUIDScale(nport int, nprocess int, npod int) { - plopObjects := makeRandomPlops(nport, nprocess, npod, fixtureconsts.Deployment1) - - plopsWithoutPodUids := 0 - for _, plop := range plopObjects { - p := rand.Float32() - if p < 0.5 { - plop.PodUid = "" - plopsWithoutPodUids++ - } - } - - // Add the PLOPs - suite.Require().NoError(suite.addTooMany(plopObjects)) - - plopCount, err := suite.store.Count(suite.hasReadCtx, search.EmptyQuery()) - suite.Equal(plopCount, 2*nport*nprocess*npod) - suite.NoError(err) - - start := time.Now() - prunedCount, err := suite.datastore.RemovePLOPsWithoutPodUID(suite.hasWriteCtx) - suite.Equal(int64(plopsWithoutPodUids), prunedCount) - duration := time.Since(start) - suite.NoError(err) - log.Infof("Pruning %d plops took %s", prunedCount, duration) - _, err = suite.datastore.RemovePLOPsWithoutPodUID(suite.hasWriteCtx) - suite.NoError(err) -} - -func (suite *PLOPDataStoreTestSuite) TestRemovePLOPsWithoutPodUIDScale27K() { - nport := 30 - nprocess := 30 - npod := 30 - - suite.RemovePLOPsWithoutPodUIDScale(nport, nprocess, npod) -} - -func (suite *PLOPDataStoreTestSuite) TestRemovePLOPsWithoutPodUIDScale125K() { - nport := 50 - nprocess := 50 - npod := 50 - - suite.RemovePLOPsWithoutPodUIDScale(nport, nprocess, npod) -} - -func (suite *PLOPDataStoreTestSuite) TestRemovePLOPsWithoutPodUIDScaleRaceCondition() { - var mutex sync.RWMutex - var wg sync.WaitGroup - wg.Add(1) - - running := true - plopsWithoutPodUids := 0 - go func() { - defer wg.Done() - iterations := 3 - for range iterations { - nport := 30 - nprocess := 30 - npod := 30 - plopObjects := makeRandomPlops(nport, nprocess, npod, fixtureconsts.Deployment1) - - for _, plop := range plopObjects { - p := rand.Float32() - if p < 0.5 { - plop.PodUid = "" - plopsWithoutPodUids += 1 - } else { - plop.PodUid = uuid.NewV4().String() - } - } - - // Add the open PLOPs - suite.NoError(suite.addTooMany(plopObjects)) - - // Close the PLOPs - // This is so that UpsertMany will trigger deletes - for _, plop := range plopObjects { - plop.CloseTimestamp = protoconv.ConvertTimeToTimestamp(time.Now()) - } - - // Add the closed PLOPs - suite.NoError(suite.addTooMany(plopObjects)) - } - }() - - totalPrunedCount := 0 - - var wgPrune sync.WaitGroup - wgPrune.Go(func() { - for { - mutex.Lock() - stop := !running - mutex.Unlock() - - if stop { - break - } - - prunedCount, err := suite.datastore.RemovePLOPsWithoutPodUID(suite.hasWriteCtx) - suite.NoError(err) - totalPrunedCount += int(prunedCount) - } - }) - - wg.Wait() - - mutex.Lock() - running = false - mutex.Unlock() - - wgPrune.Wait() - - prunedCount, err := suite.datastore.RemovePLOPsWithoutPodUID(suite.hasWriteCtx) - suite.NoError(err) - totalPrunedCount += int(prunedCount) - - // Each PLOP is opened and closed. If a PLOP is opened then pruned, then closed, - // and pruned again, then it will be pruned twice. If a PLOP is opened, then closed, - // and pruned, then it will be pruned once. Therefore the number of rows pruned will - // be between the number of PLOPs that don't have poduids that were added and twice - // that number. - suite.GreaterOrEqual(plopsWithoutPodUids, totalPrunedCount/2) - suite.LessOrEqual(plopsWithoutPodUids, totalPrunedCount) -} diff --git a/central/processlisteningonport/datastore/mocks/datastore.go b/central/processlisteningonport/datastore/mocks/datastore.go index bc71a23f3157e..053977e9f8ed7 100644 --- a/central/processlisteningonport/datastore/mocks/datastore.go +++ b/central/processlisteningonport/datastore/mocks/datastore.go @@ -91,33 +91,6 @@ func (mr *MockDataStoreMockRecorder) PruneOrphanedPLOPs(ctx, orphanWindow any) * return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PruneOrphanedPLOPs", reflect.TypeOf((*MockDataStore)(nil).PruneOrphanedPLOPs), ctx, orphanWindow) } -// PruneOrphanedPLOPsByProcessIndicators mocks base method. -func (m *MockDataStore) PruneOrphanedPLOPsByProcessIndicators(ctx context.Context, orphanWindow time.Duration) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "PruneOrphanedPLOPsByProcessIndicators", ctx, orphanWindow) -} - -// PruneOrphanedPLOPsByProcessIndicators indicates an expected call of PruneOrphanedPLOPsByProcessIndicators. -func (mr *MockDataStoreMockRecorder) PruneOrphanedPLOPsByProcessIndicators(ctx, orphanWindow any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PruneOrphanedPLOPsByProcessIndicators", reflect.TypeOf((*MockDataStore)(nil).PruneOrphanedPLOPsByProcessIndicators), ctx, orphanWindow) -} - -// RemovePLOPsWithoutPodUID mocks base method. -func (m *MockDataStore) RemovePLOPsWithoutPodUID(ctx context.Context) (int64, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "RemovePLOPsWithoutPodUID", ctx) - ret0, _ := ret[0].(int64) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// RemovePLOPsWithoutPodUID indicates an expected call of RemovePLOPsWithoutPodUID. -func (mr *MockDataStoreMockRecorder) RemovePLOPsWithoutPodUID(ctx any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemovePLOPsWithoutPodUID", reflect.TypeOf((*MockDataStore)(nil).RemovePLOPsWithoutPodUID), ctx) -} - // RemovePLOPsWithoutProcessIndicatorOrProcessInfo mocks base method. func (m *MockDataStore) RemovePLOPsWithoutProcessIndicatorOrProcessInfo(ctx context.Context) (int64, error) { m.ctrl.T.Helper() @@ -147,20 +120,6 @@ func (mr *MockDataStoreMockRecorder) RemovePlopsByPod(ctx, id any) *gomock.Call return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemovePlopsByPod", reflect.TypeOf((*MockDataStore)(nil).RemovePlopsByPod), ctx, id) } -// RemoveProcessListeningOnPort mocks base method. -func (m *MockDataStore) RemoveProcessListeningOnPort(ctx context.Context, ids []string) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "RemoveProcessListeningOnPort", ctx, ids) - ret0, _ := ret[0].(error) - return ret0 -} - -// RemoveProcessListeningOnPort indicates an expected call of RemoveProcessListeningOnPort. -func (mr *MockDataStoreMockRecorder) RemoveProcessListeningOnPort(ctx, ids any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveProcessListeningOnPort", reflect.TypeOf((*MockDataStore)(nil).RemoveProcessListeningOnPort), ctx, ids) -} - // WalkAll mocks base method. func (m *MockDataStore) WalkAll(ctx context.Context, fn datastore.WalkFn) error { m.ctrl.T.Helper() diff --git a/central/processlisteningonport/datastore/pruning.go b/central/processlisteningonport/datastore/pruning.go index 1d4da65fcbc26..0b9a484590e9e 100644 --- a/central/processlisteningonport/datastore/pruning.go +++ b/central/processlisteningonport/datastore/pruning.go @@ -1,15 +1,6 @@ package datastore const ( - // Explain Analyze indicated that 2 statements for PLOP is faster than one. - deleteOrphanedPLOPDeploymentsAndPI = `DELETE FROM listening_endpoints WHERE processindicatorid in (SELECT id from process_indicators pi WHERE NOT EXISTS - (SELECT 1 FROM deployments WHERE pi.deploymentid = deployments.Id) AND - (signal_time < now() at time zone 'utc' - INTERVAL '%d MINUTES' OR signal_time is NULL))` - - deleteOrphanedPLOPPods = `DELETE FROM listening_endpoints WHERE processindicatorid in (SELECT id from process_indicators pi WHERE NOT EXISTS - (SELECT 1 FROM pods WHERE pi.poduid = pods.Id) AND - (signal_time < now() at time zone 'utc' - INTERVAL '%d MINUTES' OR signal_time is NULL))` - // Unfortunately if a listening endpoint is marked as being open there is no indication of how old it is. // This leads to a possible race condition where a listening endpoint reaches the database before the deployment, // and the pruning job happens to run before the deployment information arrives in the database. @@ -31,17 +22,4 @@ const ( // if the serialized data has process information. PLOPs without process information are then deleted. getPotentiallyOrphanedPLOPs = `SELECT plop.serialized FROM listening_endpoints plop where NOT EXISTS (select 1 FROM process_indicators proc where plop.processindicatorid = proc.id)` - - // This is used to make pagination more efficient compared to using offset. The ids obtained using this query are used for deleting - // PLOPs without poduids in batches. See the query below this query. - getLastIdFromPage = `WITH tmp as ( - SELECT id FROM listening_endpoints WHERE id > '%s' ORDER BY id LIMIT %d - ) - SELECT id FROM tmp ORDER BY id DESC LIMIT 1` - - // Deletes PLOPs without poduids in batches according to id, which is more efficient than using offset. - // It is possible that new rows may be inserted between the starting and ending ids, after the two ids - // are obtained. Meaning that the number of rows in the page may be different than what is expected for - // the page. This should not cause a problem. - deletePLOPsWithoutPoduidInPage = "DELETE FROM listening_endpoints WHERE poduid is null AND id >= '%s' AND id <= '%s'" ) diff --git a/central/pruning/pruning.go b/central/pruning/pruning.go index 5673b35d77fff..a1b82548091de 100644 --- a/central/pruning/pruning.go +++ b/central/pruning/pruning.go @@ -61,8 +61,7 @@ const ( logImbueGCFreq = 24 * time.Hour logImbueWindow = 24 * 7 * time.Hour - alertQueryTimeout = 10 * time.Minute - alertDeleteBatchSize = 5000 + alertQueryTimeout = 10 * time.Minute flowsSemaphoreWeight = 5 @@ -74,14 +73,13 @@ const ( ) var ( - log = logging.LoggerForModule() - pruningCtx = sac.WithAllAccess(context.Background()) - lastClusterPruneTime time.Time - lastLogImbuePruneTime time.Time - lastV1ImagePruneTime time.Time - lastPrunedV1ImageID string - pruningTimeout = env.PostgresDefaultPruningStatementTimeout.DurationSetting() - prunedPLOPsWithoutPodUIDs = false + log = logging.LoggerForModule() + pruningCtx = sac.WithAllAccess(context.Background()) + lastClusterPruneTime time.Time + lastLogImbuePruneTime time.Time + lastV1ImagePruneTime time.Time + lastPrunedV1ImageID string + pruningTimeout = env.PostgresDefaultPruningStatementTimeout.DurationSetting() pruneInterval = env.PruneInterval.DurationSetting() orphanWindow = env.PruneOrphanedWindow.DurationSetting() @@ -515,6 +513,30 @@ func (g *garbageCollectorImpl) removeOrphanedPods() { } } +// Remove deployments whose cluster has been deleted: fire-and-forget cluster-deletion cleanup can orphan them. No orphan window needed - cluster deletion is a hard delete that +// never re-adopts its deployments. +func (g *garbageCollectorImpl) removeOrphanedDeployments() { + defer metrics.SetPruningDuration(time.Now(), "Deployments") + deploymentsToRemove, err := postgres.GetOrphanedDeploymentIDs(pruningCtx, g.postgres) + if err != nil { + log.Errorf("Error finding orphaned deployments: %v", err) + return + } + + if len(deploymentsToRemove) == 0 { + log.Info("[Pruning] Found no orphaned deployments...") + return + } + log.Infof("[Pruning] Found %d orphaned deployments (from formerly deleted clusters). Deleting...", + len(deploymentsToRemove)) + + for _, d := range deploymentsToRemove { + if err := g.deployments.RemoveDeployment(pruningCtx, d.ClusterID, d.ID); err != nil { + log.Errorf("Failed to remove deployment with id %s: %v", d.ID, err) + } + } +} + // Remove nodes where the cluster has been deleted. func (g *garbageCollectorImpl) removeOrphanedNodes() { defer metrics.SetPruningDuration(time.Now(), "Nodes") @@ -588,6 +610,10 @@ func (g *garbageCollectorImpl) removeOrphanedResources() { } clusterIDSet := set.NewFrozenStringSet(clusterIDs...) + // Before the deploymentSet snapshot and alert/process/risk sweeps so they observe the + // deletions this cycle. Child rows (deployments_containers, etc.) cascade. + g.removeOrphanedDeployments() + deploymentIDs, err := g.deployments.GetDeploymentIDs(pruningCtx) if err != nil { log.Error(errors.Wrap(err, "unable to fetch deployment IDs in pruning")) @@ -643,9 +669,6 @@ func clusterIDsToNegationQuery(clusterIDSet set.FrozenStringSet) *v1.Query { func (g *garbageCollectorImpl) removeOrphanedProcesses() { defer metrics.SetPruningDuration(time.Now(), "Processes") - g.plops.PruneOrphanedPLOPsByProcessIndicators(pruningCtx, orphanWindow) - - log.Info("[PLOP pruning by processes] Pruning of orphaned PLOPs by processes complete") // Prune processes in chunks. First get the ones orphaned by deployments and then go back and // do the same for those orphaned by pod @@ -762,15 +785,6 @@ func (g *garbageCollectorImpl) removeOrphanedPLOPs() { log.Errorf("error removing PLOPs with no matching process indicator or process information: %v", err) } log.Infof("[PLOP pruning] Pruning of %d orphaned PLOPs with no matching process indicator or process information complete", prunedCount) - - // Only run once since we don't expect any new PLOPs without poduids. - if !prunedPLOPsWithoutPodUIDs { - prunedCount, err = g.plops.RemovePLOPsWithoutPodUID(pruningCtx) - if err != nil { - log.Errorf("error removing PLOPs without poduid: %v", err) - } - log.Infof("[PLOP pruning] Prunned %d orphaned PLOPs with no poduid", prunedCount) - } } func (g *garbageCollectorImpl) removeExpiredAdministrationEvents(config *storage.PrivateConfig) { diff --git a/central/pruning/pruning_test.go b/central/pruning/pruning_test.go index 6cd525a70115c..7810806dee076 100644 --- a/central/pruning/pruning_test.go +++ b/central/pruning/pruning_test.go @@ -1683,30 +1683,6 @@ func (s *PruningTestSuite) TestRemoveOrphanedPLOPs() { pods: set.NewFrozenStringSet(fixtureconsts.PodUID1), expectedDeletions: []string{}, }, - { - name: "Plop does not have a poduid so it is removed", - initialPlops: []*storage.ProcessListeningOnPortStorage{ - { - Id: plopID1, - Port: 1234, - Protocol: storage.L4Protocol_L4_PROTOCOL_TCP, - CloseTimestamp: nil, - ProcessIndicatorId: fixtureconsts.ProcessIndicatorID1, - Closed: false, - Process: &storage.ProcessIndicatorUniqueKey{ - PodId: fixtureconsts.PodUID1, - ContainerName: "test_container1", - ProcessName: "test_process1", - ProcessArgs: "test_arguments1", - ProcessExecFilePath: "test_path1", - }, - DeploymentId: fixtureconsts.Deployment1, - }, - }, - deployments: set.NewFrozenStringSet(fixtureconsts.Deployment1), - pods: set.NewFrozenStringSet(fixtureconsts.PodUID1), - expectedDeletions: []string{plopID1}, - }, } for _, c := range cases { @@ -1718,7 +1694,6 @@ func (s *PruningTestSuite) TestRemoveOrphanedPLOPs() { postgres: db, plops: plopDS, } - prunedPLOPsWithoutPodUIDs = false // Populate some actual data so the query returns what needs deleted deploymentDS, err := deploymentDatastore.GetTestPostgresDataStore(t, db.DB) @@ -2406,6 +2381,94 @@ func (s *PruningTestSuite) TestRemoveOrphanedPods() { s.Equal(updatedCount, podCount-cluster2PodCount) } +func (s *PruningTestSuite) TestRemoveOrphanedDeployments() { + ctrl := gomock.NewController(s.T()) + + mockRisk := riskDatastoreMocks.NewMockDataStore(ctrl) + mockRisk.EXPECT().RemoveRisk(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return(nil) + mockBaseline := processBaselineDatastoreMocks.NewMockDataStore(ctrl) + mockBaseline.EXPECT().RemoveProcessBaselinesByDeployment(gomock.Any(), gomock.Any()).AnyTimes().Return(nil) + mockFilter := filterMocks.NewMockFilter(ctrl) + mockFilter.EXPECT().Delete(gomock.Any()).AnyTimes() + + flowStore := networkFlowDatastoreMocks.NewMockFlowDataStore(ctrl) + flowStore.EXPECT().RemoveFlowsForDeployment(gomock.Any(), gomock.Any()).AnyTimes().Return(nil) + flows := networkFlowDatastoreMocks.NewMockClusterDataStore(ctrl) + flows.EXPECT().GetFlowStore(gomock.Any(), gomock.Any()).AnyTimes().Return(flowStore, nil) + + deployments, err := deploymentDatastore.New(s.pool, nil, nil, mockBaseline, flows, mockRisk, nil, mockFilter, + ranking.NewRanker(), ranking.NewRanker(), ranking.NewRanker(), + platformmatcher.GetTestPlatformMatcherWithDefaultPlatformComponentConfig(ctrl)) + s.Require().NoError(err) + + _, _, clusterDS := s.generateClusterDataStructures() + liveClusterID, err := clusterDS.AddCluster(s.ctx, &storage.Cluster{Name: "testOrphanDeploymentCluster", MainImage: "docker.io/stackrox/rox:latest"}) + s.Require().NoError(err) + + // Deployment on a live (healthy) cluster - must survive the sweep. + liveDeployment := newDeployment("id1") + liveDeployment.Id = fixtureconsts.Deployment2 + liveDeployment.ClusterId = liveClusterID + s.Require().NoError(deployments.UpsertDeployment(s.ctx, liveDeployment)) + + // Clusters still in the DB but unhealthy/disconnected must keep their deployments - + // the sweep keys on the cluster row existing, not on health. + unhealthyClusters := []struct { + name string + deploymentID string + status storage.ClusterHealthStatus_HealthStatusLabel + }{ + {"testUnhealthyDeploymentCluster", fixtureconsts.Deployment3, storage.ClusterHealthStatus_UNHEALTHY}, + {"testDisconnectedDeploymentCluster", fixtureconsts.Deployment4, storage.ClusterHealthStatus_UNAVAILABLE}, + } + var unhealthyDeployments []*storage.Deployment + for _, c := range unhealthyClusters { + clusterID, err := clusterDS.AddCluster(s.ctx, &storage.Cluster{Name: c.name, MainImage: "docker.io/stackrox/rox:latest"}) + s.Require().NoError(err) + s.Require().NoError(clusterDS.UpdateClusterHealth(s.ctx, clusterID, + &storage.ClusterHealthStatus{SensorHealthStatus: c.status})) + + dep := newDeployment("img") + dep.Id = c.deploymentID + dep.ClusterId = clusterID + s.Require().NoError(deployments.UpsertDeployment(s.ctx, dep)) + unhealthyDeployments = append(unhealthyDeployments, dep) + } + + // Deployment whose clusterid has no cluster row - orphaned. + orphanedDeployment := newDeployment("id2") + orphanedDeployment.ClusterId = fixtureconsts.Cluster1 + s.Require().NoError(deployments.UpsertDeployment(s.ctx, orphanedDeployment)) + + gci := &garbageCollectorImpl{ + deployments: deployments, + postgres: s.pool, + } + + gci.removeOrphanedDeployments() + + _, exists, err := deployments.GetDeployment(s.ctx, orphanedDeployment.GetId()) + s.Require().NoError(err) + s.False(exists, "orphaned deployment should be pruned") + + _, exists, err = deployments.GetDeployment(s.ctx, liveDeployment.GetId()) + s.Require().NoError(err) + s.True(exists, "deployment of a live cluster must not be pruned") + + for _, dep := range unhealthyDeployments { + _, exists, err = deployments.GetDeployment(s.ctx, dep.GetId()) + s.Require().NoError(err) + s.True(exists, "deployment of a cluster still in the DB must not be pruned") + } + + // Cascaded deletion of deployments_containers rows is what makes the referenced + // image prunable - assert none remain. + var containerCount int + err = s.pool.QueryRow(s.ctx, "SELECT count(*) FROM deployments_containers WHERE deployments_id = $1", orphanedDeployment.GetId()).Scan(&containerCount) + s.Require().NoError(err) + s.Zero(containerCount) +} + func (s *PruningTestSuite) TestRemoveOrphanedNodes() { _, _, clusterDS := s.generateClusterDataStructures() diff --git a/central/reports/scheduler/v2/reportgenerator/csv_gen.go b/central/reports/scheduler/v2/reportgenerator/csv_gen.go index 45da7e5234165..490b53aa6ed9f 100644 --- a/central/reports/scheduler/v2/reportgenerator/csv_gen.go +++ b/central/reports/scheduler/v2/reportgenerator/csv_gen.go @@ -92,7 +92,13 @@ func formatCSVRow(r *ImageCVEQueryResponse) []string { } else { cisaKev = "Not Available" } - csvRow = append(csvRow, cisaKev) + var knownRansomware string + if r.GetKnownRansomwareCampaign() != nil { + knownRansomware = strconv.FormatBool(*r.GetKnownRansomwareCampaign()) + } else { + knownRansomware = "Not Available" + } + csvRow = append(csvRow, cisaKev, knownRansomware) } csvRow = append(csvRow, diff --git a/central/reports/scheduler/v2/reportgenerator/csv_gen_test.go b/central/reports/scheduler/v2/reportgenerator/csv_gen_test.go index 76f479f02c936..3de7b466a8b13 100644 --- a/central/reports/scheduler/v2/reportgenerator/csv_gen_test.go +++ b/central/reports/scheduler/v2/reportgenerator/csv_gen_test.go @@ -8,6 +8,7 @@ import ( "time" "github.com/stackrox/rox/generated/storage" + "github.com/stackrox/rox/pkg/features" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -62,27 +63,64 @@ func TestFormatCSVRow(t *testing.T) { Link: "https://nvd.nist.gov/vuln/detail/CVE-2024-1234", } - row := formatCSVRow(r) - assert.Equal(t, len(csvHeader), len(row), "row should have same number of columns as header") - assert.Equal(t, "test-cluster", row[0]) - assert.Equal(t, "test-ns", row[1]) - assert.Equal(t, "test-deploy", row[2]) - assert.Equal(t, "CVE-2024-1234", row[6]) - assert.Equal(t, "true", row[7]) - assert.Equal(t, "CRITICAL", row[9]) - assert.Equal(t, "95.000", row[12]) - assert.Equal(t, "Not Available", row[14]) // Image Created Date (nil → "Not Available") - assert.Equal(t, "https://nvd.nist.gov/vuln/detail/CVE-2024-1234", row[15]) + t.Run("KEV disabled", func(t *testing.T) { + t.Setenv(features.KnownExploitedVulnerabilities.EnvVar(), "false") + + row := formatCSVRow(r) + assert.Equal(t, len(formatCol()), len(row), "row should have same number of columns as header") + assert.Equal(t, "test-cluster", row[0]) + assert.Equal(t, "test-ns", row[1]) + assert.Equal(t, "test-deploy", row[2]) + assert.Equal(t, "CVE-2024-1234", row[6]) + assert.Equal(t, "true", row[7]) + assert.Equal(t, "CRITICAL", row[9]) + assert.Equal(t, "95.000", row[12]) + assert.Equal(t, "Not Available", row[14]) // Image Created Date (nil → "Not Available") + assert.Equal(t, "https://nvd.nist.gov/vuln/detail/CVE-2024-1234", row[15]) + }) + + t.Run("KEV enabled", func(t *testing.T) { + t.Setenv(features.KnownExploitedVulnerabilities.EnvVar(), "true") + + // The two KEV columns are inserted after EPSS (index 12), shifting all + // trailing columns right by two. + row := formatCSVRow(r) + assert.Equal(t, len(formatCol()), len(row), "row should have same number of columns as header") + assert.Equal(t, "test-cluster", row[0]) + assert.Equal(t, "95.000", row[12]) + assert.Equal(t, "Not Available", row[13]) // CISA KEV (nil → "Not Available") + assert.Equal(t, "Not Available", row[14]) // Known Ransomware Campaign (nil → "Not Available") + assert.Equal(t, "Not Available", row[16]) // Image Created Date (nil → "Not Available") + assert.Equal(t, "https://nvd.nist.gov/vuln/detail/CVE-2024-1234", row[17]) + }) } func TestFormatCSVRow_NilFields(t *testing.T) { r := &ImageCVEQueryResponse{} - row := formatCSVRow(r) - assert.Equal(t, len(csvHeader), len(row)) - assert.Equal(t, "", row[0]) - assert.Equal(t, "Not Available", row[12]) // EPSS Probability Percentage - assert.Equal(t, "Not Available", row[13]) // Discovered At - assert.Equal(t, "Not Available", row[14]) // Image Created Date + + t.Run("KEV disabled", func(t *testing.T) { + t.Setenv(features.KnownExploitedVulnerabilities.EnvVar(), "false") + + row := formatCSVRow(r) + assert.Equal(t, len(formatCol()), len(row)) + assert.Equal(t, "", row[0]) + assert.Equal(t, "Not Available", row[12]) // EPSS Probability Percentage + assert.Equal(t, "Not Available", row[13]) // Discovered At + assert.Equal(t, "Not Available", row[14]) // Image Created Date + }) + + t.Run("KEV enabled", func(t *testing.T) { + t.Setenv(features.KnownExploitedVulnerabilities.EnvVar(), "true") + + row := formatCSVRow(r) + assert.Equal(t, len(formatCol()), len(row)) + assert.Equal(t, "", row[0]) + assert.Equal(t, "Not Available", row[12]) // EPSS Probability Percentage + assert.Equal(t, "Not Available", row[13]) // CISA KEV + assert.Equal(t, "Not Available", row[14]) // Known Ransomware Campaign + assert.Equal(t, "Not Available", row[15]) // Discovered At + assert.Equal(t, "Not Available", row[16]) // Image Created Date + }) } func TestCsvReportName(t *testing.T) { diff --git a/central/reports/scheduler/v2/reportgenerator/report_gen_transaction_integration_test.go b/central/reports/scheduler/v2/reportgenerator/report_gen_transaction_integration_test.go index 837ba00486a36..d34af5f597329 100644 --- a/central/reports/scheduler/v2/reportgenerator/report_gen_transaction_integration_test.go +++ b/central/reports/scheduler/v2/reportgenerator/report_gen_transaction_integration_test.go @@ -8,6 +8,7 @@ import ( "context" "encoding/csv" "io" + "slices" "time" blobDS "github.com/stackrox/rox/central/blob/datastore" @@ -19,28 +20,31 @@ import ( "github.com/stackrox/rox/pkg/uuid" ) -// CSV column indices matching csvHeader in csv_gen.go. +// CSV column indices for the fixed prefix that precedes any feature-flag-gated +// columns (see csvHeader in csv_gen.go). Columns after EPSS can shift depending +// on enabled features, so look those up with colOf instead of hardcoding them. const ( - colCluster = 0 - colNamespace = 1 - colDeployment = 2 - colImage = 3 - colComponent = 4 - colCompVersion = 5 - colCVE = 6 - colFixable = 7 - colFixedBy = 8 - colSeverity = 9 - colCVSS = 10 - colNVDCVSS = 11 - colEPSS = 12 - colDiscoveredAt = 13 - colImageCreated = 14 - colReference = 15 - colAdvName = 16 - colAdvLink = 17 + colCluster = 0 + colNamespace = 1 + colDeployment = 2 + colImage = 3 + colComponent = 4 + colCompVersion = 5 + colCVE = 6 + colFixable = 7 + colFixedBy = 8 + colSeverity = 9 + colCVSS = 10 + colNVDCVSS = 11 + colEPSS = 12 ) +// colOf returns the index of the named column in the current CSV layout, which +// depends on which feature-flag-gated columns formatCol includes. +func colOf(name string) int { + return slices.Index(formatCol(), name) +} + // collectColumn extracts a single column from all rows. func collectColumn(rows [][]string, col int) []string { out := make([]string, len(rows)) @@ -163,7 +167,7 @@ func (s *NewDataModelEnhancedReportingTestSuite) TestGenerateReportTransaction_A rows := s.readBlobCSV(blobStore, snap.GetReportConfigurationId(), snap.GetReportId()) s.Require().Len(rows, 9, "1 header + 8 data rows") - s.Equal(csvHeader, rows[0]) + s.Equal(formatCol(), rows[0]) dataRows := rows[1:] s.ElementsMatch([]string{ @@ -240,7 +244,7 @@ func (s *NewDataModelEnhancedReportingTestSuite) TestGenerateReportTransaction_E rows := s.readBlobCSV(blobStore, snap.GetReportConfigurationId(), snap.GetReportId()) s.Require().Len(rows, 1, "only header row for empty result") - s.Equal(csvHeader, rows[0]) + s.Equal(formatCol(), rows[0]) } // TestGenerateReportTransaction_CSVFieldValues spot-checks individual CSV field @@ -276,9 +280,9 @@ func (s *NewDataModelEnhancedReportingTestSuite) TestGenerateReportTransaction_C s.Equal("9.00", row[colCVSS]) s.Equal("10.00", row[colNVDCVSS]) s.Equal("70.000", row[colEPSS]) - s.NotEqual("Not Available", row[colDiscoveredAt]) - s.Equal("RHSA-2025-CVE-fixable", row[colAdvName]) - s.Equal("test-rhsa-link", row[colAdvLink]) + s.NotEqual("Not Available", row[colOf("Discovered At")]) + s.Equal("RHSA-2025-CVE-fixable", row[colOf("Advisory Name")]) + s.Equal("test-rhsa-link", row[colOf("Advisory Link")]) } // TestGenerateReportTransaction_ReportStatusUpdated verifies that the report diff --git a/central/reports/service/v2/node/service_impl_test.go b/central/reports/service/v2/node/service_impl_test.go index f641f171e586e..8de5b2e97c062 100644 --- a/central/reports/service/v2/node/service_impl_test.go +++ b/central/reports/service/v2/node/service_impl_test.go @@ -23,6 +23,7 @@ import ( "github.com/stackrox/rox/pkg/grpc/authn" mockIdentity "github.com/stackrox/rox/pkg/grpc/authn/mocks" "github.com/stackrox/rox/pkg/grpc/testutils" + "github.com/stackrox/rox/pkg/notifiers" postgresMocks "github.com/stackrox/rox/pkg/postgres/mocks" pgNotify "github.com/stackrox/rox/pkg/postgres/notify" "github.com/stackrox/rox/pkg/protoassert" @@ -103,7 +104,7 @@ func (s *NodeReportServiceTestSuite) getValidNodeReportConfig() *apiV2.ReportCon Rules: []*apiV2.EntityScopeRule{ { Entity: apiV2.ScopeEntity_SCOPE_ENTITY_CLUSTER, - Field: apiV2.ScopeField_FIELD_ID, + Field: apiV2.ScopeField_FIELD_NAME, Values: []*apiV2.RuleValue{ { Value: "cluster-1", @@ -160,7 +161,8 @@ func (s *NodeReportServiceTestSuite) TestPostNodeReportConfiguration() { mockRole.EXPECT().GetAccessScope().Return(accessScope).Times(1) mockID.EXPECT().Roles().Return([]permissions.ResolvedRole{mockRole}).Times(1) - s.notifierDataStore.EXPECT().Exists(gomock.Any(), "email-notifier-id").Return(true, nil).Times(1) + s.notifierDataStore.EXPECT().GetScrubbedNotifier(gomock.Any(), "email-notifier-id"). + Return(&storage.Notifier{Type: notifiers.EmailType}, true, nil).Times(1) s.reportConfigDataStore.EXPECT().AddReportConfiguration(gomock.Any(), gomock.Any()). DoAndReturn(func(_ context.Context, cfg *storage.ReportConfiguration) (string, error) { @@ -202,7 +204,8 @@ func (s *NodeReportServiceTestSuite) TestPostNodeReportConfiguration_GetAfterCre requestConfig := s.getValidNodeReportConfig() ctx := s.getContextForUser(creator) - s.notifierDataStore.EXPECT().Exists(gomock.Any(), "email-notifier-id").Return(true, nil).Times(1) + s.notifierDataStore.EXPECT().GetScrubbedNotifier(gomock.Any(), "email-notifier-id"). + Return(&storage.Notifier{Type: notifiers.EmailType}, true, nil).Times(1) s.reportConfigDataStore.EXPECT().AddReportConfiguration(gomock.Any(), gomock.Any()). Return(requestConfig.GetId(), nil).Times(1) s.reportConfigDataStore.EXPECT().GetReportConfiguration(gomock.Any(), requestConfig.GetId()). @@ -228,7 +231,8 @@ func (s *NodeReportServiceTestSuite) TestPostNodeReportConfiguration_ValidationE }, } - s.notifierDataStore.EXPECT().Exists(gomock.Any(), "email-notifier-id").Return(true, nil).Times(1) + s.notifierDataStore.EXPECT().GetScrubbedNotifier(gomock.Any(), "email-notifier-id"). + Return(&storage.Notifier{Type: notifiers.EmailType}, true, nil).Times(1) _, err := s.service.PostNodeReportConfiguration(ctx, invalidConfig) s.Error(err) @@ -595,7 +599,8 @@ func (s *NodeReportServiceTestSuite) TestUpdateNodeReportConfiguration() { mockRole.EXPECT().GetAccessScope().Return(accessScope).AnyTimes() mockID.EXPECT().Roles().Return([]permissions.ResolvedRole{mockRole}).AnyTimes() - s.notifierDataStore.EXPECT().Exists(gomock.Any(), "email-notifier-id").Return(true, nil).Times(1) + s.notifierDataStore.EXPECT().GetScrubbedNotifier(gomock.Any(), "email-notifier-id"). + Return(&storage.Notifier{Type: notifiers.EmailType}, true, nil).Times(1) existingConfig := &storage.ReportConfiguration{ Id: updateConfig.GetId(), @@ -989,7 +994,8 @@ func (s *NodeReportServiceTestSuite) TestUpdateNodeReportConfiguration_NotFound( updateConfig := s.getValidNodeReportConfig() - s.notifierDataStore.EXPECT().Exists(gomock.Any(), "email-notifier-id").Return(true, nil).Times(1) + s.notifierDataStore.EXPECT().GetScrubbedNotifier(gomock.Any(), "email-notifier-id"). + Return(&storage.Notifier{Type: notifiers.EmailType}, true, nil).Times(1) s.reportConfigDataStore.EXPECT().GetReportConfiguration(gomock.Any(), updateConfig.GetId()). Return(nil, false, nil).Times(1) @@ -1215,7 +1221,8 @@ func (s *NodeReportServiceTestSuite) TestPostNodeReportConfigurationWithCentralW mockRole.EXPECT().GetAccessScope().Return(accessScope).Times(1) mockID.EXPECT().Roles().Return([]permissions.ResolvedRole{mockRole}).Times(1) - s.notifierDataStore.EXPECT().Exists(gomock.Any(), "email-notifier-id").Return(true, nil).Times(1) + s.notifierDataStore.EXPECT().GetScrubbedNotifier(gomock.Any(), "email-notifier-id"). + Return(&storage.Notifier{Type: notifiers.EmailType}, true, nil).Times(1) s.reportConfigDataStore.EXPECT().AddReportConfiguration(gomock.Any(), gomock.Any()). DoAndReturn(func(_ context.Context, cfg *storage.ReportConfiguration) (string, error) { return cfg.GetId(), nil @@ -1247,7 +1254,8 @@ func (s *NodeReportServiceTestSuite) TestUpdateNodeReportConfigurationWithCentra updateConfig := s.getValidNodeReportConfig() ctx := s.getContextForUser(creator) - s.notifierDataStore.EXPECT().Exists(gomock.Any(), "email-notifier-id").Return(true, nil).Times(1) + s.notifierDataStore.EXPECT().GetScrubbedNotifier(gomock.Any(), "email-notifier-id"). + Return(&storage.Notifier{Type: notifiers.EmailType}, true, nil).Times(1) s.reportConfigDataStore.EXPECT().GetReportConfiguration(gomock.Any(), updateConfig.GetId()). Return(&storage.ReportConfiguration{ Id: updateConfig.GetId(), diff --git a/central/reports/service/v2/service_impl_test.go b/central/reports/service/v2/service_impl_test.go index 94f63715281e1..5f574ba81d094 100644 --- a/central/reports/service/v2/service_impl_test.go +++ b/central/reports/service/v2/service_impl_test.go @@ -26,6 +26,7 @@ import ( "github.com/stackrox/rox/pkg/grpc/authn" mockIdentity "github.com/stackrox/rox/pkg/grpc/authn/mocks" "github.com/stackrox/rox/pkg/grpc/testutils" + "github.com/stackrox/rox/pkg/notifiers" postgresMocks "github.com/stackrox/rox/pkg/postgres/mocks" pgNotify "github.com/stackrox/rox/pkg/postgres/notify" "github.com/stackrox/rox/pkg/protoassert" @@ -158,7 +159,8 @@ func (s *ReportServiceTestSuite) TestUpdateReportConfiguration_RejectsNodeType() s.reportConfigDataStore.EXPECT().GetReportConfiguration(gomock.Any(), "node-config"). Return(protoReportConfig, true, nil).Times(1) s.collectionDataStore.EXPECT().Exists(gomock.Any(), gomock.Any()).Return(true, nil).AnyTimes() - s.notifierDataStore.EXPECT().Exists(gomock.Any(), gomock.Any()).Return(true, nil).AnyTimes() + s.notifierDataStore.EXPECT().GetScrubbedNotifier(gomock.Any(), gomock.Any()). + Return(&storage.Notifier{Type: notifiers.EmailType}, true, nil).AnyTimes() requestConfig := fixtures.GetValidV2ReportConfigWithMultipleNotifiers() requestConfig.Id = "node-config" @@ -850,11 +852,11 @@ func (s *ReportServiceTestSuite) upsertReportConfigTestCases(isUpdate bool) []up func (s *ReportServiceTestSuite) mockNotifierStoreCalls(reqNotifier *apiV2.NotifierConfiguration, notifierIDExits, isValidationError, isUpdate bool) { if notifierIDExits { - s.notifierDataStore.EXPECT().Exists(gomock.Any(), reqNotifier.GetEmailConfig().GetNotifierId()). - Return(true, nil).Times(1) + s.notifierDataStore.EXPECT().GetScrubbedNotifier(gomock.Any(), reqNotifier.GetEmailConfig().GetNotifierId()). + Return(&storage.Notifier{Type: notifiers.EmailType}, true, nil).Times(1) } else { - s.notifierDataStore.EXPECT().Exists(gomock.Any(), reqNotifier.GetEmailConfig().GetNotifierId()). - Return(false, nil).Times(1) + s.notifierDataStore.EXPECT().GetScrubbedNotifier(gomock.Any(), reqNotifier.GetEmailConfig().GetNotifierId()). + Return(nil, false, nil).Times(1) } if !isValidationError && !isUpdate { diff --git a/central/reports/validation/entity_scope_boundary_test.go b/central/reports/validation/entity_scope_boundary_test.go new file mode 100644 index 0000000000000..26ddadc18da91 --- /dev/null +++ b/central/reports/validation/entity_scope_boundary_test.go @@ -0,0 +1,63 @@ +package validation + +import ( + "testing" + + apiV2 "github.com/stackrox/rox/generated/api/v2" + "github.com/stackrox/rox/pkg/errox" + "github.com/stretchr/testify/require" +) + +func TestValidateEntityScopeRejectsUnsupportedRulesAndValues(t *testing.T) { + tests := map[string]struct { + entity apiV2.ScopeEntity + field apiV2.ScopeField + value *apiV2.RuleValue + }{ + "unsupported cluster ID": { + entity: apiV2.ScopeEntity_SCOPE_ENTITY_CLUSTER, + field: apiV2.ScopeField_FIELD_ID, + value: &apiV2.RuleValue{Value: "cluster-id"}, + }, + "unknown entity": { + entity: apiV2.ScopeEntity(99), + field: apiV2.ScopeField_FIELD_NAME, + value: &apiV2.RuleValue{Value: "prod"}, + }, + "unknown field": { + entity: apiV2.ScopeEntity_SCOPE_ENTITY_CLUSTER, + field: apiV2.ScopeField(99), + value: &apiV2.RuleValue{Value: "prod"}, + }, + "unknown match type": { + entity: apiV2.ScopeEntity_SCOPE_ENTITY_CLUSTER, + field: apiV2.ScopeField_FIELD_NAME, + value: &apiV2.RuleValue{Value: "prod", MatchType: apiV2.MatchType(99)}, + }, + "nil value": { + entity: apiV2.ScopeEntity_SCOPE_ENTITY_CLUSTER, + field: apiV2.ScopeField_FIELD_NAME, + }, + "empty scalar value": { + entity: apiV2.ScopeEntity_SCOPE_ENTITY_CLUSTER, + field: apiV2.ScopeField_FIELD_NAME, + value: &apiV2.RuleValue{}, + }, + "invalid regex key": { + entity: apiV2.ScopeEntity_SCOPE_ENTITY_CLUSTER, + field: apiV2.ScopeField_FIELD_LABEL, + value: &apiV2.RuleValue{Value: "[=prod", MatchType: apiV2.MatchType_REGEX}, + }, + } + + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + err := validateEntityScope(&apiV2.EntityScope{Rules: []*apiV2.EntityScopeRule{{ + Entity: tc.entity, + Field: tc.field, + Values: []*apiV2.RuleValue{tc.value}, + }}}) + require.ErrorIs(t, err, errox.InvalidArgs) + }) + } +} diff --git a/central/reports/validation/filter_enum_boundary_test.go b/central/reports/validation/filter_enum_boundary_test.go new file mode 100644 index 0000000000000..b1e707cbbc4f6 --- /dev/null +++ b/central/reports/validation/filter_enum_boundary_test.go @@ -0,0 +1,55 @@ +package validation + +import ( + "testing" + + reportConfigDSMocks "github.com/stackrox/rox/central/reports/config/datastore/mocks" + apiV2 "github.com/stackrox/rox/generated/api/v2" + "github.com/stackrox/rox/generated/storage" + "github.com/stackrox/rox/pkg/errox" + "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" +) + +func TestValidateAndGenerateReportRequestRejectsInvalidNotificationMethodBeforeLookup(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + validator := &Validator{reportConfigDatastore: reportConfigDSMocks.NewMockDataStore(ctrl)} + + _, err := validator.ValidateAndGenerateReportRequest( + "config", + storage.ReportStatus_NotificationMethod(99), + storage.ReportStatus_ON_DEMAND, + nil, + ) + require.ErrorIs(t, err, errox.InvalidArgs) +} + +func TestValidateImageFiltersRejectsInvalidEnumsAndDates(t *testing.T) { + tests := map[string]*apiV2.VulnerabilityReportFilters{ + "image type": { + ImageTypes: []apiV2.VulnerabilityReportFilters_ImageType{apiV2.VulnerabilityReportFilters_ImageType(99)}, + CvesSince: &apiV2.VulnerabilityReportFilters_AllVuln{AllVuln: true}, + }, + "fixability": { + ImageTypes: []apiV2.VulnerabilityReportFilters_ImageType{apiV2.VulnerabilityReportFilters_DEPLOYED}, + Fixability: apiV2.VulnerabilityReportFilters_Fixability(99), + CvesSince: &apiV2.VulnerabilityReportFilters_AllVuln{AllVuln: true}, + }, + "severity": { + ImageTypes: []apiV2.VulnerabilityReportFilters_ImageType{apiV2.VulnerabilityReportFilters_DEPLOYED}, + Severities: []apiV2.VulnerabilityReportFilters_VulnerabilitySeverity{apiV2.VulnerabilityReportFilters_VulnerabilitySeverity(99)}, + CvesSince: &apiV2.VulnerabilityReportFilters_AllVuln{AllVuln: true}, + }, + "nil start date": { + ImageTypes: []apiV2.VulnerabilityReportFilters_ImageType{apiV2.VulnerabilityReportFilters_DEPLOYED}, + CvesSince: &apiV2.VulnerabilityReportFilters_SinceStartDate{}, + }, + } + + for name, filters := range tests { + t.Run(name, func(t *testing.T) { + require.ErrorIs(t, (&Validator{}).validateImageFilters(filters), errox.InvalidArgs) + }) + } +} diff --git a/central/reports/validation/notifier_type_boundary_test.go b/central/reports/validation/notifier_type_boundary_test.go new file mode 100644 index 0000000000000..56825c94b2cd3 --- /dev/null +++ b/central/reports/validation/notifier_type_boundary_test.go @@ -0,0 +1,24 @@ +package validation + +import ( + "testing" + + notifierDSMocks "github.com/stackrox/rox/central/notifier/datastore/mocks" + apiV2 "github.com/stackrox/rox/generated/api/v2" + "github.com/stackrox/rox/generated/storage" + "github.com/stackrox/rox/pkg/errox" + "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" +) + +func TestValidateEmailConfigRejectsNonEmailNotifier(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + notifierDS := notifierDSMocks.NewMockDataStore(ctrl) + notifierDS.EXPECT().GetScrubbedNotifier(gomock.Any(), "notifier").Return(&storage.Notifier{Type: "slack"}, true, nil) + + err := (&Validator{notifierDatastore: notifierDS}).validateEmailConfig(&apiV2.EmailNotifierConfiguration{ + NotifierId: "notifier", MailingLists: []string{"reader@example.com"}, + }) + require.ErrorIs(t, err, errox.InvalidArgs) +} diff --git a/central/reports/validation/schedule_boundary_test.go b/central/reports/validation/schedule_boundary_test.go new file mode 100644 index 0000000000000..459d8a7ca4729 --- /dev/null +++ b/central/reports/validation/schedule_boundary_test.go @@ -0,0 +1,28 @@ +package validation + +import ( + "testing" + + apiV2 "github.com/stackrox/rox/generated/api/v2" + "github.com/stackrox/rox/pkg/errox" + "github.com/stretchr/testify/require" +) + +func TestValidateScheduleRejectsInvalidBoundsAndIntervals(t *testing.T) { + tests := map[string]*apiV2.ReportSchedule{ + "negative hour": {IntervalType: apiV2.ReportSchedule_DAILY, Hour: -1}, + "hour 24": {IntervalType: apiV2.ReportSchedule_DAILY, Hour: 24}, + "negative minute": {IntervalType: apiV2.ReportSchedule_DAILY, Minute: -1}, + "minute 60": {IntervalType: apiV2.ReportSchedule_DAILY, Minute: 60}, + "unknown interval": { + IntervalType: apiV2.ReportSchedule_IntervalType(99), + }, + } + + for name, schedule := range tests { + t.Run(name, func(t *testing.T) { + err := (&Validator{}).validateSchedule(&apiV2.ReportConfiguration{Schedule: schedule}) + require.ErrorIs(t, err, errox.InvalidArgs) + }) + } +} diff --git a/central/reports/validation/validate.go b/central/reports/validation/validate.go index fef9a6ea322fe..4c00f9431d603 100644 --- a/central/reports/validation/validate.go +++ b/central/reports/validation/validate.go @@ -23,6 +23,7 @@ import ( "github.com/stackrox/rox/pkg/errox" "github.com/stackrox/rox/pkg/features" "github.com/stackrox/rox/pkg/grpc/authn" + "github.com/stackrox/rox/pkg/notifiers" "github.com/stackrox/rox/pkg/protocompat" "github.com/stackrox/rox/pkg/sac" "github.com/stackrox/rox/pkg/search" @@ -83,8 +84,14 @@ func (v *Validator) validateSchedule(config *apiV2.ReportConfiguration) error { if schedule == nil { return nil } + if schedule.GetHour() < 0 || schedule.GetHour() > 23 { + return errox.InvalidArgs.New("schedule hour must be within 0-23") + } + if schedule.GetMinute() < 0 || schedule.GetMinute() > 59 { + return errox.InvalidArgs.New("schedule minute must be within 0-59") + } switch schedule.GetIntervalType() { - case apiV2.ReportSchedule_UNSET: + default: return errox.InvalidArgs.New("report configuration schedule must be one of DAILY, WEEKLY, or MONTHLY") case apiV2.ReportSchedule_DAILY: if schedule.GetDaysOfWeek() != nil || schedule.GetDaysOfMonth() != nil { @@ -158,13 +165,16 @@ func (v *Validator) validateEmailConfig(emailConfig *apiV2.EmailNotifierConfigur } // Use allAccessCtx since report creator/updater might not have permissions for integrationSAC - exists, err := v.notifierDatastore.Exists(allAccessCtx, emailConfig.GetNotifierId()) + notifier, exists, err := v.notifierDatastore.GetScrubbedNotifier(allAccessCtx, emailConfig.GetNotifierId()) if err != nil { return errors.Errorf("Error looking up attached notifier, Notifier ID: %s, Error: %s", emailConfig.GetNotifierId(), err) } if !exists { return errors.Wrapf(errox.NotFound, "Notifier with ID %s not found.", emailConfig.GetNotifierId()) } + if notifier.GetType() != notifiers.EmailType && notifier.GetType() != notifiers.ACSCSEmailType { + return errox.InvalidArgs.New("report configuration requires an email notifier") + } return nil } @@ -249,12 +259,19 @@ func validateEntityScope(es *apiV2.EntityScope) error { } seen := set.NewSet[entityFieldKey]() for _, rule := range es.GetRules() { - if rule.GetEntity() == apiV2.ScopeEntity_SCOPE_ENTITY_UNSET { + switch rule.GetEntity() { + case apiV2.ScopeEntity_SCOPE_ENTITY_CLUSTER, apiV2.ScopeEntity_SCOPE_ENTITY_NAMESPACE, apiV2.ScopeEntity_SCOPE_ENTITY_DEPLOYMENT: + default: return errox.InvalidArgs.Newf("unexpected entity scope rule: %s", rule.GetEntity()) } if rule.GetField() == apiV2.ScopeField_FIELD_UNSET { return errox.InvalidArgs.Newf("unexpected entity in scope rule for %s with an unset field", rule.GetEntity()) } + switch rule.GetField() { + case apiV2.ScopeField_FIELD_NAME, apiV2.ScopeField_FIELD_LABEL, apiV2.ScopeField_FIELD_ANNOTATION: + default: + return errox.InvalidArgs.Newf("unsupported field %s for entity scope", rule.GetField()) + } // Cluster annotation is not indexed and therefore unsupported. if rule.GetEntity() == apiV2.ScopeEntity_SCOPE_ENTITY_CLUSTER && rule.GetField() == apiV2.ScopeField_FIELD_ANNOTATION { return errox.InvalidArgs.New("annotation field is not supported for cluster entity scope rules") @@ -271,6 +288,12 @@ func validateEntityScope(es *apiV2.EntityScope) error { isMapField := rule.GetField() == apiV2.ScopeField_FIELD_LABEL || rule.GetField() == apiV2.ScopeField_FIELD_ANNOTATION for _, rv := range rule.GetValues() { valOfValue := rv.GetValue() + if valOfValue == "" { + return errox.InvalidArgs.New("entity scope rule values must not be empty") + } + if rv.GetMatchType() != apiV2.MatchType_EXACT && rv.GetMatchType() != apiV2.MatchType_REGEX { + return errox.InvalidArgs.Newf("unsupported match type %s", rv.GetMatchType()) + } if isMapField { mapKey, mapValue, found := strings.Cut(valOfValue, "=") if !found { @@ -281,6 +304,8 @@ func validateEntityScope(es *apiV2.EntityScope) error { if errs := k8sValidation.IsLabelKey(mapKey); len(errs) > 0 { return errox.InvalidArgs.Newf("invalid %v key %q: %s", rule.GetField(), mapKey, strings.Join(errs, "; ")) } + } else if _, err := regexp.Compile(mapKey); err != nil { + return errox.InvalidArgs.CausedByf("invalid regex key %q: %v", mapKey, err) } valOfValue = mapValue } @@ -314,6 +339,24 @@ func (v *Validator) validateImageFilters(filters *apiV2.VulnerabilityReportFilte return errox.InvalidArgs.New("vulnerability report filters should specify which image types to scan for CVEs; " + "the valid options are 'DEPLOYED' and 'WATCHED'") } + for _, imageType := range filters.GetImageTypes() { + if _, ok := apiV2.VulnerabilityReportFilters_ImageType_name[int32(imageType)]; !ok { + return errox.InvalidArgs.Newf("unsupported image type %d", imageType) + } + } + if _, ok := apiV2.VulnerabilityReportFilters_Fixability_name[int32(filters.GetFixability())]; !ok { + return errox.InvalidArgs.Newf("unsupported fixability %d", filters.GetFixability()) + } + for _, severity := range filters.GetSeverities() { + if _, ok := apiV2.VulnerabilityReportFilters_VulnerabilitySeverity_name[int32(severity)]; !ok { + return errox.InvalidArgs.Newf("unsupported severity %d", severity) + } + } + if since, ok := filters.GetCvesSince().(*apiV2.VulnerabilityReportFilters_SinceStartDate); ok { + if since.SinceStartDate == nil || since.SinceStartDate.CheckValid() != nil { + return errox.InvalidArgs.New("invalid CVE start date") + } + } if filters.GetCvesSince() == nil { return errox.InvalidArgs.New("vulnerability report filters must specify how far back in time to look for CVEs; " + @@ -363,6 +406,9 @@ func (v *Validator) ValidateAndGenerateReportRequest( requestType storage.ReportStatus_RunMethod, requesterID authn.Identity, ) (*reportGen.ReportRequest, error) { + if notificationMethod != storage.ReportStatus_EMAIL && notificationMethod != storage.ReportStatus_DOWNLOAD { + return nil, errox.InvalidArgs.Newf("unsupported notification method %d", notificationMethod) + } config, found, err := v.reportConfigDatastore.GetReportConfiguration(allAccessCtx, configID) if err != nil { return nil, errors.Wrapf(err, "Error finding report configuration %s", configID) diff --git a/central/reports/validation/validate_comprehensive_test.go b/central/reports/validation/validate_comprehensive_test.go index 868227e87a24f..809b8c9a66be6 100644 --- a/central/reports/validation/validate_comprehensive_test.go +++ b/central/reports/validation/validate_comprehensive_test.go @@ -161,7 +161,7 @@ func TestValidateNotifiers(t *testing.T) { }, }, setupMocks: func() { - notifierDS.EXPECT().Exists(gomock.Any(), "notifier-1").Return(true, nil) + notifierDS.EXPECT().GetScrubbedNotifier(gomock.Any(), "notifier-1").Return(&storage.Notifier{Type: "email"}, true, nil) }, expectError: false, }, @@ -221,7 +221,7 @@ func TestValidateEmailConfig(t *testing.T) { MailingLists: []string{"user@example.com"}, }, setupMocks: func(notifierDS *notifierDSMocks.MockDataStore) { - notifierDS.EXPECT().Exists(gomock.Any(), "missing-notifier").Return(false, nil) + notifierDS.EXPECT().GetScrubbedNotifier(gomock.Any(), "missing-notifier").Return(nil, false, nil) }, expectError: true, errContains: "not found", @@ -234,7 +234,7 @@ func TestValidateEmailConfig(t *testing.T) { CustomBody: "Report body", }, setupMocks: func(notifierDS *notifierDSMocks.MockDataStore) { - notifierDS.EXPECT().Exists(gomock.Any(), "notifier-1").Return(true, nil) + notifierDS.EXPECT().GetScrubbedNotifier(gomock.Any(), "notifier-1").Return(&storage.Notifier{Type: "email"}, true, nil) }, expectError: false, }, diff --git a/central/reports/validation/validate_test.go b/central/reports/validation/validate_test.go index 3328409deffcd..da51f83371d26 100644 --- a/central/reports/validation/validate_test.go +++ b/central/reports/validation/validate_test.go @@ -52,6 +52,12 @@ func TestValidateEntityScope(t *testing.T) { ), expectError: false, }, + "label key with empty value is valid": { + scope: makeEntityScope( + makeRule(apiV2.ScopeEntity_SCOPE_ENTITY_NAMESPACE, apiV2.ScopeField_FIELD_LABEL, exactValue("required=")), + ), + expectError: false, + }, "valid multiple rules different entities": { scope: makeEntityScope( makeRule(apiV2.ScopeEntity_SCOPE_ENTITY_CLUSTER, apiV2.ScopeField_FIELD_NAME, exactValue("prod")), diff --git a/central/risk/multipliers/image/vulnerabilities.go b/central/risk/multipliers/image/vulnerabilities.go index f99dd7a3abb90..b37950fd5bfee 100644 --- a/central/risk/multipliers/image/vulnerabilities.go +++ b/central/risk/multipliers/image/vulnerabilities.go @@ -8,6 +8,7 @@ import ( "github.com/stackrox/rox/central/risk/scorer/vulns" "github.com/stackrox/rox/generated/storage" "github.com/stackrox/rox/pkg/scancomponent" + "github.com/stackrox/rox/pkg/set" ) const ( @@ -21,7 +22,7 @@ const ( // vulnerabilitiesMultiplier is a scorer for the vulnerabilities in an image type vulnerabilitiesMultiplier struct{} -// NewVulnerabilities provides a multiplier that scores the data based on the CVSS scores and number of CVEs +// NewVulnerabilities provides a multiplier that scores known-severity vulnerability findings across image components. func NewVulnerabilities() Multiplier { return &vulnerabilitiesMultiplier{} } @@ -43,8 +44,8 @@ func (c *vulnerabilitiesMultiplier) Score(_ context.Context, image *storage.Imag Name: VulnerabilitiesHeading, Factors: []*storage.Risk_Result_Factor{ { - Message: fmt.Sprintf("Image %q contains %d CVEs with severities ranging between %s and %s", - image.GetName().GetFullName(), num, min.Severity, max.Severity), + Message: fmt.Sprintf("Image %q contains %d distinct CVEs with severities ranging between %s and %s", + image.GetName().GetFullName(), countDistinctCVEs(imgComponents), min.Severity, max.Severity), }, }, Score: score, @@ -68,10 +69,23 @@ func (c *vulnerabilitiesMultiplier) ScoreV2(_ context.Context, image *storage.Im Name: VulnerabilitiesHeading, Factors: []*storage.Risk_Result_Factor{ { - Message: fmt.Sprintf("Image %q contains %d CVEs with severities ranging between %s and %s", - image.GetName().GetFullName(), num, min.Severity, max.Severity), + Message: fmt.Sprintf("Image %q contains %d distinct CVEs with severities ranging between %s and %s", + image.GetName().GetFullName(), countDistinctCVEs(imgComponents), min.Severity, max.Severity), }, }, Score: score, } } + +// countDistinctCVEs includes unknown-severity findings, which do not affect the risk score. +func countDistinctCVEs(components []*storage.EmbeddedImageScanComponent) int { + cves := set.NewStringSet() + for _, component := range components { + for _, vuln := range component.GetVulns() { + if cve := vuln.GetCve(); cve != "" { + cves.Add(cve) + } + } + } + return cves.Cardinality() +} diff --git a/central/risk/multipliers/image/vulnerabilities_test.go b/central/risk/multipliers/image/vulnerabilities_test.go index 959ac3af49969..5a7460316dda3 100644 --- a/central/risk/multipliers/image/vulnerabilities_test.go +++ b/central/risk/multipliers/image/vulnerabilities_test.go @@ -18,6 +18,7 @@ func TestVulnerabilitiesScore(t *testing.T) { images := multipliers.GetMockImages() result := mult.Score(ctx, images[0]) assert.Equal(t, float32(1.59025), result.GetScore()) + assert.Equal(t, "Image \"docker.io/library/nginx:1.10\" contains 2 distinct CVEs with severities ranging between Low and Critical", result.GetFactors()[0].GetMessage()) // Changing CVSS score should not affect result. images[0].GetScan().GetComponents()[0].GetVulns()[0].Cvss = 0 @@ -27,7 +28,14 @@ func TestVulnerabilitiesScore(t *testing.T) { result = mult.Score(ctx, images[0]) assert.Equal(t, float32(1.59025), result.GetScore()) - // Set both severity to unknown and then there should be a nil RiskResult + // Unknown-severity CVEs are displayed, but do not contribute to the score. + images[0].GetScan().GetComponents()[0].Vulns = append(images[0].GetScan().GetComponents()[0].GetVulns(), + &storage.EmbeddedVulnerability{Cve: "CVE-2019-0003", Severity: storage.VulnerabilitySeverity_UNKNOWN_VULNERABILITY_SEVERITY}) + result = mult.Score(ctx, images[0]) + assert.Equal(t, float32(1.59025), result.GetScore()) + assert.Equal(t, "Image \"docker.io/library/nginx:1.10\" contains 3 distinct CVEs with severities ranging between Low and Critical", result.GetFactors()[0].GetMessage()) + + // Only unknown-severity vulnerabilities remain, so there is no risk result. images[0].GetScan().GetComponents()[0].GetVulns()[0].Severity = storage.VulnerabilitySeverity_UNKNOWN_VULNERABILITY_SEVERITY images[0].GetScan().GetComponents()[0].GetVulns()[1].Severity = storage.VulnerabilitySeverity_UNKNOWN_VULNERABILITY_SEVERITY images[0].GetScan().GetComponents()[1].GetVulns()[0].Severity = storage.VulnerabilitySeverity_UNKNOWN_VULNERABILITY_SEVERITY @@ -44,6 +52,7 @@ func TestVulnerabilitiesScoreV2(t *testing.T) { images := multipliers.GetMockImagesV2() result := mult.ScoreV2(ctx, images[0]) assert.Equal(t, float32(1.59025), result.GetScore()) + assert.Equal(t, "Image \"docker.io/library/nginx:1.10\" contains 2 distinct CVEs with severities ranging between Low and Critical", result.GetFactors()[0].GetMessage()) // Changing CVSS score should not affect result. images[0].GetScan().GetComponents()[0].GetVulns()[0].Cvss = 0 @@ -53,7 +62,14 @@ func TestVulnerabilitiesScoreV2(t *testing.T) { result = mult.ScoreV2(ctx, images[0]) assert.Equal(t, float32(1.59025), result.GetScore()) - // Set both severity to unknown and then there should be a nil RiskResult + // Unknown-severity CVEs are displayed, but do not contribute to the score. + images[0].GetScan().GetComponents()[0].Vulns = append(images[0].GetScan().GetComponents()[0].GetVulns(), + &storage.EmbeddedVulnerability{Cve: "CVE-2019-0003", Severity: storage.VulnerabilitySeverity_UNKNOWN_VULNERABILITY_SEVERITY}) + result = mult.ScoreV2(ctx, images[0]) + assert.Equal(t, float32(1.59025), result.GetScore()) + assert.Equal(t, "Image \"docker.io/library/nginx:1.10\" contains 3 distinct CVEs with severities ranging between Low and Critical", result.GetFactors()[0].GetMessage()) + + // Only unknown-severity vulnerabilities remain, so there is no risk result. images[0].GetScan().GetComponents()[0].GetVulns()[0].Severity = storage.VulnerabilitySeverity_UNKNOWN_VULNERABILITY_SEVERITY images[0].GetScan().GetComponents()[0].GetVulns()[1].Severity = storage.VulnerabilitySeverity_UNKNOWN_VULNERABILITY_SEVERITY images[0].GetScan().GetComponents()[1].GetVulns()[0].Severity = storage.VulnerabilitySeverity_UNKNOWN_VULNERABILITY_SEVERITY diff --git a/central/risk/scorer/deployment/scorer_test.go b/central/risk/scorer/deployment/scorer_test.go index 59a5838e41802..faf919428da8e 100644 --- a/central/risk/scorer/deployment/scorer_test.go +++ b/central/risk/scorer/deployment/scorer_test.go @@ -62,7 +62,7 @@ func TestScore(t *testing.T) { { Name: imageMultiplier.VulnerabilitiesHeading, Factors: []*storage.Risk_Result_Factor{ - {Message: "Image \"docker.io/library/nginx:1.10\" contains 3 CVEs with severities ranging between Moderate and Critical"}, + {Message: "Image \"docker.io/library/nginx:1.10\" contains 3 distinct CVEs with severities ranging between Moderate and Critical"}, }, Score: 1.5535, }, diff --git a/central/risk/scorer/image/scorer_test.go b/central/risk/scorer/image/scorer_test.go index c89e474ce1f2c..902014711f510 100644 --- a/central/risk/scorer/image/scorer_test.go +++ b/central/risk/scorer/image/scorer_test.go @@ -28,7 +28,7 @@ func TestScore(t *testing.T) { { Name: imageMultiplier.VulnerabilitiesHeading, Factors: []*storage.Risk_Result_Factor{ - {Message: "Image \"docker.io/library/nginx:1.10\" contains 3 CVEs with severities ranging between Moderate and Critical"}, + {Message: "Image \"docker.io/library/nginx:1.10\" contains 3 distinct CVEs with severities ranging between Moderate and Critical"}, }, Score: 1.5535, }, @@ -67,7 +67,7 @@ func TestScoreV2(t *testing.T) { { Name: imageMultiplier.VulnerabilitiesHeading, Factors: []*storage.Risk_Result_Factor{ - {Message: "Image \"docker.io/library/nginx:1.10\" contains 3 CVEs with severities ranging between Moderate and Critical"}, + {Message: "Image \"docker.io/library/nginx:1.10\" contains 3 distinct CVEs with severities ranging between Moderate and Critical"}, }, Score: 1.5535, }, diff --git a/central/scanner/handler.go b/central/scanner/handler.go index 9890f5209aeed..9728df49a6a08 100644 --- a/central/scanner/handler.go +++ b/central/scanner/handler.go @@ -93,8 +93,6 @@ func generateFilesForScannerV1(params *apiparams.Scanner, clusterType storage.Cl ClusterType: clusterType, K8sConfig: &renderer.K8sConfig{ CommonConfig: renderer.CommonConfig{ - ScannerImage: stringutils.OrDefault(params.ScannerImage, flavor.ScannerImage()), - ScannerDBImage: stringutils.OrDefault(params.ScannerDBImage, flavor.ScannerDBImage()), ScannerV4Image: stringutils.OrDefault(params.ScannerV4Image, flavor.ScannerV4Image()), ScannerV4DBImage: stringutils.OrDefault(params.ScannerV4DBImage, flavor.ScannerV4DBImage()), }, diff --git a/central/search/category.go b/central/search/category.go index 97ee74cf890e4..418f0eb32a2ce 100644 --- a/central/search/category.go +++ b/central/search/category.go @@ -2,13 +2,19 @@ package search import ( v1 "github.com/stackrox/rox/generated/api/v1" - "github.com/stackrox/rox/pkg/features" "github.com/stackrox/rox/pkg/set" ) // GetGlobalSearchCategories returns a set of search categories func GetGlobalSearchCategories() set.Set[v1.SearchCategory] { // globalSearchCategories is exposed for e2e options test + // + // IMAGES_V2 is intentionally omitted. With FlattenImageData enabled, IMAGES is + // already routed to the imagesV2 store (see central/search/service), so adding + // IMAGES_V2 here would run the same image search twice and return every image + // twice (both labeled IMAGES). IMAGES remains the public category used by the UI + // and API clients; IMAGES_V2 is the internal storage/schema category and is still + // searchable when requested explicitly. globalSearchCategories := set.NewSet( v1.SearchCategory_ALERTS, v1.SearchCategory_CLUSTERS, @@ -25,8 +31,5 @@ func GetGlobalSearchCategories() set.Set[v1.SearchCategory] { v1.SearchCategory_IMAGE_INTEGRATIONS, v1.SearchCategory_POLICY_CATEGORIES, ) - if features.FlattenImageData.Enabled() { - globalSearchCategories.Add(v1.SearchCategory_IMAGES_V2) - } return globalSearchCategories } diff --git a/central/sensor/service/connection/connection_impl.go b/central/sensor/service/connection/connection_impl.go index 5be9321a48f0f..b59fdec096b88 100644 --- a/central/sensor/service/connection/connection_impl.go +++ b/central/sensor/service/connection/connection_impl.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "math" + "slices" "github.com/pkg/errors" compScanSetting "github.com/stackrox/rox/central/complianceoperator/v2/scanconfigurations/datastore" @@ -544,6 +545,13 @@ func (c *sensorConnection) getPolicySyncMsgFromPolicies(policies []*storage.Poli // Otherwise, sensor supports the same version or newer as central } + // Remove exclude_by_kind exclusions before syncing to a Sensor that + // lacks WorkloadKindExclusionCap. Sensor forwards this same list to + // the admission controller, so AC evaluates the same copy. + if !c.HasCapability(centralsensor.WorkloadKindExclusionCap) { + policies = stripExcludeByKindExclusions(policies) + } + return ¢ral.MsgToSensor{ Msg: ¢ral.MsgToSensor_PolicySync{ PolicySync: ¢ral.PolicySync{ @@ -553,6 +561,32 @@ func (c *sensorConnection) getPolicySyncMsgFromPolicies(policies []*storage.Poli }, nil } +// stripExcludeByKindExclusions returns a copy of policies with every exclusion +// that sets exclude_by_kind removed. Stored policies are not mutated. An old +// Sensor compiles an exclude_by_kind item as an unconstrained exclusion (nil +// name and nil scope match every workload). Sensor does not evaluate image +// exclusions, so an image+kind item with only the kind matcher removed is that +// same unconstrained exclusion and is removed entirely. An exclusion with no +// kind matcher is kept, including an image combined with a deployment name or +// scope. +func stripExcludeByKindExclusions(policies []*storage.Policy) []*storage.Policy { + out := make([]*storage.Policy, 0, len(policies)) + for _, p := range policies { + if !slices.ContainsFunc(p.GetExclusions(), exclusionSetsExcludeByKind) { + out = append(out, p) + continue + } + cloned := p.CloneVT() + cloned.Exclusions = slices.DeleteFunc(cloned.GetExclusions(), exclusionSetsExcludeByKind) + out = append(out, cloned) + } + return out +} + +func exclusionSetsExcludeByKind(e *storage.Exclusion) bool { + return e.GetExcludeByKind() != nil +} + func (c *sensorConnection) getNetworkBaselineSyncMsg(ctx context.Context) (*central.MsgToSensor, error) { var networkBaselines []*storage.NetworkBaseline walkFn := func() error { diff --git a/central/sensor/service/connection/connection_test.go b/central/sensor/service/connection/connection_test.go index a8fd0d52fd2fc..eaf8523107feb 100644 --- a/central/sensor/service/connection/connection_test.go +++ b/central/sensor/service/connection/connection_test.go @@ -365,6 +365,102 @@ func (s *testSuite) TestGetPolicySyncMsgFromPoliciesDoesntDowngradeInvalidVersio s.Equal(policyversion.CurrentVersion().String(), policySync.GetPolicies()[0].GetPolicyVersion()) } +func (s *testSuite) TestGetPolicySyncMsgFromPoliciesStripsExcludeByKind() { + kindExclusion := &storage.Exclusion{ + Name: "skip-cronjobs", + Matcher: &storage.Exclusion_ExcludeByKind_{ + ExcludeByKind: &storage.Exclusion_ExcludeByKind{ + Kinds: []storage.Exclusion_WorkloadKind{storage.Exclusion_CRON_JOB}, + }, + }, + } + nameExclusion := &storage.Exclusion{ + Name: "skip-web", + Matcher: &storage.Exclusion_Deployment_{ + Deployment: &storage.Exclusion_Deployment{Name: "web"}, + }, + } + imageExclusion := &storage.Exclusion{ + Name: "skip-image", + Image: &storage.Exclusion_Image{Name: "stackrox.io"}, + } + imageAndKindExclusion := &storage.Exclusion{ + Name: "skip-image-and-jobs", + Image: &storage.Exclusion_Image{Name: "example.io"}, + Matcher: &storage.Exclusion_ExcludeByKind_{ + ExcludeByKind: &storage.Exclusion_ExcludeByKind{ + Kinds: []storage.Exclusion_WorkloadKind{storage.Exclusion_JOB}, + }, + }, + } + imageAndDeploymentExclusion := &storage.Exclusion{ + Name: "skip-image-and-web", + Image: &storage.Exclusion_Image{Name: "nginx"}, + Matcher: &storage.Exclusion_Deployment_{ + Deployment: &storage.Exclusion_Deployment{Name: "web-image"}, + }, + } + policy := &storage.Policy{ + Name: "test-policy", + Exclusions: []*storage.Exclusion{ + kindExclusion, + nameExclusion, + imageExclusion, + imageAndKindExclusion, + imageAndDeploymentExclusion, + }, + } + + s.Run("without capability strips kind items and keeps others", func() { + original := policy.CloneVT() + msg, err := (&sensorConnection{}).getPolicySyncMsgFromPolicies([]*storage.Policy{policy}) + s.Require().NoError(err) + + synced := msg.GetPolicySync().GetPolicies() + s.Require().Len(synced, 1) + got := synced[0].GetExclusions() + s.Require().Len(got, 3) + s.Equal("skip-web", got[0].GetName()) + s.Equal("web", got[0].GetDeployment().GetName()) + s.Equal("skip-image", got[1].GetName()) + s.Equal("stackrox.io", got[1].GetImage().GetName()) + s.Equal("skip-image-and-web", got[2].GetName()) + s.Equal("nginx", got[2].GetImage().GetName()) + s.Equal("web-image", got[2].GetDeployment().GetName()) + protoassert.Equal(s.T(), original, policy) + }) + + s.Run("with capability keeps kind items", func() { + conn := &sensorConnection{ + capabilities: set.NewSet(centralsensor.WorkloadKindExclusionCap), + } + msg, err := conn.getPolicySyncMsgFromPolicies([]*storage.Policy{policy}) + s.Require().NoError(err) + + got := msg.GetPolicySync().GetPolicies()[0].GetExclusions() + s.Require().Len(got, 5) + s.NotNil(got[0].GetExcludeByKind()) + s.NotNil(got[3].GetExcludeByKind()) + s.Equal(storage.Exclusion_JOB, got[3].GetExcludeByKind().GetKinds()[0]) + s.Equal("example.io", got[3].GetImage().GetName()) + s.Equal("web-image", got[4].GetDeployment().GetName()) + }) + + s.Run("later capable sensor still sees original kind items", func() { + // PreparePoliciesAndBroadcast reuses the same slice across connections. + input := []*storage.Policy{policy} + _, err := (&sensorConnection{}).getPolicySyncMsgFromPolicies(input) + s.Require().NoError(err) + + capable := &sensorConnection{ + capabilities: set.NewSet(centralsensor.WorkloadKindExclusionCap), + } + msg, err := capable.getPolicySyncMsgFromPolicies(input) + s.Require().NoError(err) + s.NotNil(msg.GetPolicySync().GetPolicies()[0].GetExclusions()[0].GetExcludeByKind()) + }) +} + func (s *testSuite) TestSendsAuditLogSyncMessageIfEnabledOnRun() { ctx := context.Background() clusterID := "this-cluster" diff --git a/central/sensor/service/pipeline/nodeindex/pipeline.go b/central/sensor/service/pipeline/nodeindex/pipeline.go index 18eeea9cf16ab..dc032fe4cbf36 100644 --- a/central/sensor/service/pipeline/nodeindex/pipeline.go +++ b/central/sensor/service/pipeline/nodeindex/pipeline.go @@ -6,6 +6,7 @@ import ( "github.com/pkg/errors" clusterDataStore "github.com/stackrox/rox/central/cluster/datastore" + "github.com/stackrox/rox/central/cluster/lifecycle" "github.com/stackrox/rox/central/enrichment" countMetrics "github.com/stackrox/rox/central/metrics" nodeDatastore "github.com/stackrox/rox/central/node/datastore" @@ -120,7 +121,7 @@ func (p *pipelineImpl) Run(ctx context.Context, _ string, msg *central.MsgFromSe incomingScanTime := node.GetScan().GetScanTime() // Update the whole node in the database with the new and previous information. - err = p.riskManager.CalculateRiskAndUpsertNode(node) + err = p.upsertNodeIfClusterActive(ctx, node) if err != nil { return errors.Wrapf(err, "failed calculating risk and upserting node %s", nodeDatastore.NodeString(node)) } @@ -156,6 +157,20 @@ func (p *pipelineImpl) Run(ctx context.Context, _ string, msg *central.MsgFromSe return nil } +func (p *pipelineImpl) upsertNodeIfClusterActive(ctx context.Context, node *storage.Node) error { + active, release := lifecycle.Singleton().Enter(node.GetClusterId()) + if !active { + return nil + } + defer release() + + _, exists, err := p.clusterStore.GetClusterName(ctx, node.GetClusterId()) + if err != nil || !exists { + return err + } + return p.riskManager.CalculateRiskAndUpsertNode(node) +} + func sendComplianceAck(ctx context.Context, node *storage.Node, injector common.MessageInjector) { if injector == nil { return diff --git a/central/sensor/service/pipeline/nodeindex/pipeline_test.go b/central/sensor/service/pipeline/nodeindex/pipeline_test.go index 539199eadcb6f..7d98420ce86bc 100644 --- a/central/sensor/service/pipeline/nodeindex/pipeline_test.go +++ b/central/sensor/service/pipeline/nodeindex/pipeline_test.go @@ -5,6 +5,7 @@ import ( "time" clusterDatastoreMocks "github.com/stackrox/rox/central/cluster/datastore/mocks" + "github.com/stackrox/rox/central/cluster/lifecycle" nodeDatastoreMocks "github.com/stackrox/rox/central/node/datastore/mocks" riskManagerMocks "github.com/stackrox/rox/central/risk/manager/mocks" "github.com/stackrox/rox/generated/internalapi/central" @@ -75,6 +76,7 @@ func TestPipelineWarnsWhenPersistedScanTimeRegresses(t *testing.T) { node := &storage.Node{Id: "1", Name: "node-name", ClusterId: "cluster-id"} ctrl := gomock.NewController(t) + clusterStore := clusterDatastoreMocks.NewMockDataStore(ctrl) nodeDatastore := nodeDatastoreMocks.NewMockDataStore(ctrl) riskManager := riskManagerMocks.NewMockManager(ctrl) enricher := nodesEnricherMocks.NewMockNodeEnricher(ctrl) @@ -94,8 +96,10 @@ func TestPipelineWarnsWhenPersistedScanTimeRegresses(t *testing.T) { return nil }), ) + clusterStore.EXPECT().GetClusterName(gomock.Any(), gomock.Eq(node.GetClusterId())).Return("", true, nil) p := &pipelineImpl{ + clusterStore: clusterStore, nodeDatastore: nodeDatastore, riskManager: riskManager, enricher: enricher, @@ -157,6 +161,7 @@ func TestPipelineEnrichesAndUpserts(t *testing.T) { } ctrl := gomock.NewController(t) clusterStore := clusterDatastoreMocks.NewMockDataStore(ctrl) + clusterStore.EXPECT().GetClusterName(gomock.Any(), gomock.Any()).AnyTimes().Return("", true, nil) nodeDatastore := nodeDatastoreMocks.NewMockDataStore(ctrl) nodeDatastore.EXPECT().GetNode(gomock.Any(), gomock.Eq("1")).Times(2).Return(&node, true, nil) riskManager := riskManagerMocks.NewMockManager(ctrl) @@ -183,12 +188,34 @@ func TestPipelineEnrichesAndUpserts(t *testing.T) { } } +func TestPipelineSkipsUpsertAfterClusterDeletionBegins(t *testing.T) { + t.Setenv(features.NodeIndexEnabled.EnvVar(), "true") + t.Setenv(features.ScannerV4.EnvVar(), "true") + + ctrl := gomock.NewController(t) + node := &storage.Node{Id: "1", Name: "node-name", ClusterId: "cluster-id"} + nodeDatastore := nodeDatastoreMocks.NewMockDataStore(ctrl) + nodeDatastore.EXPECT().GetNode(gomock.Any(), gomock.Eq(node.GetId())).Return(node, true, nil) + enricher := nodesEnricherMocks.NewMockNodeEnricher(ctrl) + enricher.EXPECT().EnrichNodeWithVulnerabilities(gomock.Any(), nil, gomock.Any()).Return(nil) + + releaseDeletion := lifecycle.Singleton().BeginDeletion(node.GetClusterId()) + defer releaseDeletion() + + p := &pipelineImpl{ + nodeDatastore: nodeDatastore, + enricher: enricher, + } + require.NoError(t, p.Run(t.Context(), node.GetClusterId(), createMsg(mockIndexReport), nil)) +} + func TestPipelineSendsSensorAndLegacyACKs(t *testing.T) { t.Setenv(features.NodeIndexEnabled.EnvVar(), "true") t.Setenv(features.ScannerV4.EnvVar(), "true") ctrl := gomock.NewController(t) clusterStore := clusterDatastoreMocks.NewMockDataStore(ctrl) + clusterStore.EXPECT().GetClusterName(gomock.Any(), gomock.Any()).AnyTimes().Return("", true, nil) nodeDatastore := nodeDatastoreMocks.NewMockDataStore(ctrl) riskManager := riskManagerMocks.NewMockManager(ctrl) enricher := nodesEnricherMocks.NewMockNodeEnricher(ctrl) @@ -245,6 +272,7 @@ func TestPipelineSkipsSensorACKWhenCapabilityMissing(t *testing.T) { ctrl := gomock.NewController(t) clusterStore := clusterDatastoreMocks.NewMockDataStore(ctrl) + clusterStore.EXPECT().GetClusterName(gomock.Any(), gomock.Any()).AnyTimes().Return("", true, nil) nodeDatastore := nodeDatastoreMocks.NewMockDataStore(ctrl) riskManager := riskManagerMocks.NewMockManager(ctrl) enricher := nodesEnricherMocks.NewMockNodeEnricher(ctrl) diff --git a/central/sensor/service/pipeline/nodeindex/three_pipelines_test.go b/central/sensor/service/pipeline/nodeindex/three_pipelines_test.go index 32f96a4cdf149..069ed968a6fbf 100644 --- a/central/sensor/service/pipeline/nodeindex/three_pipelines_test.go +++ b/central/sensor/service/pipeline/nodeindex/three_pipelines_test.go @@ -360,6 +360,7 @@ func Test_ThreePipelines_Run(t *testing.T) { if tt.setUpMocksAndEnv != nil { tt.setUpMocksAndEnv(t, tt.mocks) } + tt.mocks.clusterStore.EXPECT().GetClusterName(gomock.Any(), gomock.Any()).AnyTimes().Return("", true, nil) pNode := nodes.NewPipeline(tt.mocks.clusterStore, tt.mocks.nodeDatastore, tt.enricher, tt.riskManager) pNodeInv := nodeinventory.NewPipeline(tt.mocks.clusterStore, tt.mocks.nodeDatastore, tt.enricher, tt.riskManager) pNodeIdx := newPipeline(tt.mocks.clusterStore, tt.mocks.nodeDatastore, tt.enricher, tt.riskManager) diff --git a/central/sensor/service/pipeline/nodeinventory/pipeline.go b/central/sensor/service/pipeline/nodeinventory/pipeline.go index cc03d75aaa2d4..f9cfff63913f0 100644 --- a/central/sensor/service/pipeline/nodeinventory/pipeline.go +++ b/central/sensor/service/pipeline/nodeinventory/pipeline.go @@ -6,6 +6,7 @@ import ( "github.com/pkg/errors" clusterDataStore "github.com/stackrox/rox/central/cluster/datastore" + "github.com/stackrox/rox/central/cluster/lifecycle" "github.com/stackrox/rox/central/enrichment" countMetrics "github.com/stackrox/rox/central/metrics" nodeDatastore "github.com/stackrox/rox/central/node/datastore" @@ -115,7 +116,7 @@ func (p *pipelineImpl) Run(ctx context.Context, _ string, msg *central.MsgFromSe len(node.GetScan().GetComponents())) // Update the whole node in the database with the new and previous information. - err = p.riskManager.CalculateRiskAndUpsertNode(node) + err = p.calculateRiskAndUpsertNodeIfClusterActive(ctx, node) if err != nil { log.Error(err) return err @@ -125,6 +126,20 @@ func (p *pipelineImpl) Run(ctx context.Context, _ string, msg *central.MsgFromSe return nil } +func (p *pipelineImpl) calculateRiskAndUpsertNodeIfClusterActive(ctx context.Context, node *storage.Node) error { + active, release := lifecycle.Singleton().Enter(node.GetClusterId()) + if !active { + return nil + } + defer release() + + _, exists, err := p.clusterStore.GetClusterName(ctx, node.GetClusterId()) + if err != nil || !exists { + return err + } + return p.riskManager.CalculateRiskAndUpsertNode(node) +} + // shouldDiscardMsg returns true if the pipeline should discard an incoming message or false if it should keep processing it. func shouldDiscardMsg(node *storage.Node) bool { // In a mixed environment, there might be v2-only clusters, so there is no Scanner v4 scan available for that cluster. diff --git a/central/sensor/service/pipeline/nodeinventory/pipeline_test.go b/central/sensor/service/pipeline/nodeinventory/pipeline_test.go index b2ed240fef7cd..a6e70ea76acfc 100644 --- a/central/sensor/service/pipeline/nodeinventory/pipeline_test.go +++ b/central/sensor/service/pipeline/nodeinventory/pipeline_test.go @@ -171,6 +171,7 @@ func Test_pipelineImpl_Run(t *testing.T) { if tt.setUp != nil { tt.setUp(t, &tt.args, &tt.mocks) } + tt.mocks.clusterStore.EXPECT().GetClusterName(gomock.Any(), gomock.Any()).AnyTimes().Return("", true, nil) p := &pipelineImpl{ clusterStore: tt.mocks.clusterStore, nodeDatastore: tt.mocks.nodeDatastore, @@ -196,6 +197,7 @@ func Test_pipelineImpl_Run_SendsSensorAndLegacyACKs(t *testing.T) { testutils.MustUpdateFeature(t, features.LegacyScanner, true) ctrl := gomock.NewController(t) clusterStore := clusterDatastoreMocks.NewMockDataStore(ctrl) + clusterStore.EXPECT().GetClusterName(gomock.Any(), gomock.Any()).AnyTimes().Return("", true, nil) nodeDatastore := nodeDatastoreMocks.NewMockDataStore(ctrl) riskManager := riskManagerMocks.NewMockManager(ctrl) enricher := nodesEnricherMocks.NewMockNodeEnricher(ctrl) @@ -263,6 +265,7 @@ func Test_pipelineImpl_Run_SkipsSensorACKWhenCapabilityMissing(t *testing.T) { testutils.MustUpdateFeature(t, features.LegacyScanner, true) ctrl := gomock.NewController(t) clusterStore := clusterDatastoreMocks.NewMockDataStore(ctrl) + clusterStore.EXPECT().GetClusterName(gomock.Any(), gomock.Any()).AnyTimes().Return("", true, nil) nodeDatastore := nodeDatastoreMocks.NewMockDataStore(ctrl) riskManager := riskManagerMocks.NewMockManager(ctrl) enricher := nodesEnricherMocks.NewMockNodeEnricher(ctrl) diff --git a/central/sensor/service/pipeline/nodeinventory/two_pipelines_test.go b/central/sensor/service/pipeline/nodeinventory/two_pipelines_test.go index ce04f4ed06ff5..9f8b72efd5fa8 100644 --- a/central/sensor/service/pipeline/nodeinventory/two_pipelines_test.go +++ b/central/sensor/service/pipeline/nodeinventory/two_pipelines_test.go @@ -230,6 +230,7 @@ func Test_TwoPipelines_Run(t *testing.T) { if tt.setUpMocks != nil { tt.setUpMocks(t, tt.mocks) } + tt.mocks.clusterStore.EXPECT().GetClusterName(gomock.Any(), gomock.Any()).AnyTimes().Return("", true, nil) pNode := nodes.NewPipeline(tt.mocks.clusterStore, tt.mocks.nodeDatastore, tt.enricher, tt.riskManager) pNodeInv := NewPipeline(tt.mocks.clusterStore, tt.mocks.nodeDatastore, tt.enricher, tt.riskManager) diff --git a/central/sensor/service/pipeline/nodes/pipeline.go b/central/sensor/service/pipeline/nodes/pipeline.go index a59efc0c8cb7f..9bf5a7e053ab4 100644 --- a/central/sensor/service/pipeline/nodes/pipeline.go +++ b/central/sensor/service/pipeline/nodes/pipeline.go @@ -5,6 +5,7 @@ import ( "github.com/pkg/errors" clusterDataStore "github.com/stackrox/rox/central/cluster/datastore" + "github.com/stackrox/rox/central/cluster/lifecycle" "github.com/stackrox/rox/central/enrichment" countMetrics "github.com/stackrox/rox/central/metrics" nodeDatastore "github.com/stackrox/rox/central/node/datastore" @@ -103,14 +104,13 @@ func (p *pipelineImpl) Run(ctx context.Context, clusterID string, msg *central.M // ROX-22002: Remove invalid null characters in annotations stringutils.SanitizeMapValues(node.GetAnnotations()) - if enricher.SupportsNodeScanning(node) { // If supports node scanning, this pipeline should only update the node's // metadata. We call upsert without scan. Upsert will read scan information from // the database before writing. This is safe because NodeInventory and Node // pipelines never run concurrently by the Sensor Event worker queues. node.Scan = nil - if err := p.nodeDatastore.UpsertNode(ctx, node); err != nil { + if err := p.upsertNodeIfClusterActive(ctx, clusterID, node); err != nil { err = errors.Wrapf(err, "upserting node %s", nodeDatastore.NodeString(node)) log.Error(err) return err @@ -125,7 +125,7 @@ func (p *pipelineImpl) Run(ctx context.Context, clusterID string, msg *central.M ScanTime: protocompat.TimestampNow(), Notes: []storage.NodeScan_Note{storage.NodeScan_UNSUPPORTED}, } - if err := p.nodeDatastore.UpsertNode(ctx, node); err != nil { + if err := p.upsertNodeIfClusterActive(ctx, clusterID, node); err != nil { err = errors.Wrapf(err, "upserting node %s", nodeDatastore.NodeString(node)) log.Error(err) return err @@ -139,7 +139,7 @@ func (p *pipelineImpl) Run(ctx context.Context, clusterID string, msg *central.M "risk information will not be updated): %v", nodeDatastore.NodeString(node), err) } - if err := p.riskManager.CalculateRiskAndUpsertNode(node); err != nil { + if err := p.calculateRiskAndUpsertNodeIfClusterActive(ctx, clusterID, node); err != nil { log.Error(err) return err } @@ -147,4 +147,30 @@ func (p *pipelineImpl) Run(ctx context.Context, clusterID string, msg *central.M return nil } +func (p *pipelineImpl) upsertNodeIfClusterActive(ctx context.Context, clusterID string, node *storage.Node) error { + return p.withActiveCluster(ctx, clusterID, func() error { + return p.nodeDatastore.UpsertNode(ctx, node) + }) +} + +func (p *pipelineImpl) calculateRiskAndUpsertNodeIfClusterActive(ctx context.Context, clusterID string, node *storage.Node) error { + return p.withActiveCluster(ctx, clusterID, func() error { + return p.riskManager.CalculateRiskAndUpsertNode(node) + }) +} + +func (p *pipelineImpl) withActiveCluster(ctx context.Context, clusterID string, write func() error) error { + active, release := lifecycle.Singleton().Enter(clusterID) + if !active { + return nil + } + defer release() + + _, exists, err := p.clusterStore.GetClusterName(ctx, clusterID) + if err != nil || !exists { + return err + } + return write() +} + func (p *pipelineImpl) OnFinish(_ string) {} diff --git a/central/sensor/service/pipeline/nodes/pipeline_test.go b/central/sensor/service/pipeline/nodes/pipeline_test.go index c6ba35109fdae..c673578f9288b 100644 --- a/central/sensor/service/pipeline/nodes/pipeline_test.go +++ b/central/sensor/service/pipeline/nodes/pipeline_test.go @@ -133,6 +133,7 @@ func Test_pipelineImpl_Run(t *testing.T) { if tt.setUp != nil { tt.setUp(t, &tt.args, &tt.mocks) } + tt.mocks.clusterStore.EXPECT().GetClusterName(gomock.Any(), gomock.Any()).AnyTimes().Return("test cluster name", true, nil) p := &pipelineImpl{ clusterStore: tt.mocks.clusterStore, nodeDatastore: tt.mocks.nodeDatastore, diff --git a/central/sensor/service/pipeline/virtualmachineindex/pipeline_test.go b/central/sensor/service/pipeline/virtualmachineindex/pipeline_test.go index 1f22c58aa9416..e5bfdbca75e8c 100644 --- a/central/sensor/service/pipeline/virtualmachineindex/pipeline_test.go +++ b/central/sensor/service/pipeline/virtualmachineindex/pipeline_test.go @@ -925,9 +925,12 @@ func TestLookupGuestOS(t *testing.T) { }, "v2 unknown guest OS leaves scan OS empty": { v2Enabled: true, - v2VM: &storage.VirtualMachineV2{GuestOs: pkgVM.UnknownGuestOS}, - v2Found: true, - wantOS: "", + v2VM: &storage.VirtualMachineV2{ + GuestOs: pkgVM.UnknownGuestOS, + Facts: map[string]string{pkgVM.GuestOSKey: pkgVM.UnknownGuestOS}, + }, + v2Found: true, + wantOS: "", }, "v1 store error leaves scan OS empty": { v1Err: errors.New("db error"), diff --git a/central/splunk/violations_test.go b/central/splunk/violations_test.go index a5c7baa7fd128..6a6397caddd3a 100644 --- a/central/splunk/violations_test.go +++ b/central/splunk/violations_test.go @@ -53,19 +53,17 @@ var ( }, LifecycleStages: []storage.LifecycleStage{storage.LifecycleStage_BUILD, storage.LifecycleStage_DEPLOY}, Exclusions: []*storage.Exclusion{{ - Name: "Don't alert on kube-system namespace", - Deployment: &storage.Exclusion_Deployment{ + Name: "Don't alert on kube-system namespace", Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{ Scope: &storage.Scope{ Namespace: "kube-system", }, - }, + }}, }, { - Name: "Don't alert on istio-system namespace", - Deployment: &storage.Exclusion_Deployment{ + Name: "Don't alert on istio-system namespace", Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{ Scope: &storage.Scope{ Namespace: "istio-system", }, - }, + }}, }}, Severity: storage.Severity_LOW_SEVERITY, SORTName: "90-Day Image Age", diff --git a/central/tlsconfig/openshift_tls.go b/central/tlsconfig/openshift_tls.go index 1fbb703e21039..8e35aa9bfe869 100644 --- a/central/tlsconfig/openshift_tls.go +++ b/central/tlsconfig/openshift_tls.go @@ -16,6 +16,9 @@ func OpenShiftTLSConfigured() bool { return false } exists, err := fileutils.Exists(env.OpenShiftTLSCertDir.Setting()) + if err != nil { + log.Warnf("Cannot check OpenShift TLS certificate directory %s: %v", env.OpenShiftTLSCertDir.Setting(), err) + } return exists && err == nil } diff --git a/central/virtualmachine/v2/datastore/datastore.go b/central/virtualmachine/v2/datastore/datastore.go index 940a03a9dddbd..296e00c821dfd 100644 --- a/central/virtualmachine/v2/datastore/datastore.go +++ b/central/virtualmachine/v2/datastore/datastore.go @@ -18,6 +18,8 @@ type DataStore interface { // GetVirtualMachine returns the VM with the given ID. GetVirtualMachine(ctx context.Context, id string) (*storage.VirtualMachineV2, bool, error) + // GetVirtualMachineWithLatestScan returns the VM and its latest scan together. + GetVirtualMachineWithLatestScan(ctx context.Context, id string) (*common.VMWithLatestScan, bool, error) // GetManyVirtualMachines returns the VMs with the given IDs. GetManyVirtualMachines(ctx context.Context, ids []string) ([]*storage.VirtualMachineV2, []int, error) diff --git a/central/virtualmachine/v2/datastore/datastore_impl.go b/central/virtualmachine/v2/datastore/datastore_impl.go index b0f091070620b..d3ef7fdff5509 100644 --- a/central/virtualmachine/v2/datastore/datastore_impl.go +++ b/central/virtualmachine/v2/datastore/datastore_impl.go @@ -47,6 +47,11 @@ func (ds *datastoreImpl) GetManyVirtualMachines(ctx context.Context, ids []strin return ds.store.GetMany(ctx, ids) } +func (ds *datastoreImpl) GetVirtualMachineWithLatestScan(ctx context.Context, id string) (*common.VMWithLatestScan, bool, error) { + defer metrics.SetDatastoreFunctionDuration(time.Now(), "VirtualMachineV2", "GetVirtualMachineWithLatestScan") + return ds.store.GetWithLatestScan(ctx, id) +} + func (ds *datastoreImpl) EnsureVirtualMachineExists(ctx context.Context, vmID string, clusterID string) error { defer metrics.SetDatastoreFunctionDuration(time.Now(), "VirtualMachineV2", "EnsureVirtualMachineExists") diff --git a/central/virtualmachine/v2/datastore/mocks/datastore.go b/central/virtualmachine/v2/datastore/mocks/datastore.go index 57be91ac410ed..d2bddff113c49 100644 --- a/central/virtualmachine/v2/datastore/mocks/datastore.go +++ b/central/virtualmachine/v2/datastore/mocks/datastore.go @@ -124,6 +124,22 @@ func (mr *MockDataStoreMockRecorder) GetVirtualMachine(ctx, id any) *gomock.Call return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetVirtualMachine", reflect.TypeOf((*MockDataStore)(nil).GetVirtualMachine), ctx, id) } +// GetVirtualMachineWithLatestScan mocks base method. +func (m *MockDataStore) GetVirtualMachineWithLatestScan(ctx context.Context, id string) (*common.VMWithLatestScan, bool, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetVirtualMachineWithLatestScan", ctx, id) + ret0, _ := ret[0].(*common.VMWithLatestScan) + ret1, _ := ret[1].(bool) + ret2, _ := ret[2].(error) + return ret0, ret1, ret2 +} + +// GetVirtualMachineWithLatestScan indicates an expected call of GetVirtualMachineWithLatestScan. +func (mr *MockDataStoreMockRecorder) GetVirtualMachineWithLatestScan(ctx, id any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetVirtualMachineWithLatestScan", reflect.TypeOf((*MockDataStore)(nil).GetVirtualMachineWithLatestScan), ctx, id) +} + // Search mocks base method. func (m *MockDataStore) Search(ctx context.Context, query *v1.Query) ([]search.Result, error) { m.ctrl.T.Helper() diff --git a/central/virtualmachine/v2/datastore/store/common/parts.go b/central/virtualmachine/v2/datastore/store/common/parts.go index 75ca8e978a2a7..f36d2761b65fd 100644 --- a/central/virtualmachine/v2/datastore/store/common/parts.go +++ b/central/virtualmachine/v2/datastore/store/common/parts.go @@ -2,6 +2,13 @@ package common import "github.com/stackrox/rox/generated/storage" +// VMWithLatestScan contains VM metadata and its latest scan from one database snapshot. +// Scan is nil when the VM has not been scanned. +type VMWithLatestScan struct { + VM *storage.VirtualMachineV2 + Scan *storage.VirtualMachineScanV2 +} + // VMScanParts groups the scan, components, and CVEs that together represent // a single VM scan result. UpsertScan consumes this structure. type VMScanParts struct { diff --git a/central/virtualmachine/v2/datastore/store/mocks/store.go b/central/virtualmachine/v2/datastore/store/mocks/store.go index 2c2e21dd692cc..8230b9540a9de 100644 --- a/central/virtualmachine/v2/datastore/store/mocks/store.go +++ b/central/virtualmachine/v2/datastore/store/mocks/store.go @@ -133,6 +133,22 @@ func (mr *MockStoreMockRecorder) GetMany(ctx, ids any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetMany", reflect.TypeOf((*MockStore)(nil).GetMany), ctx, ids) } +// GetWithLatestScan mocks base method. +func (m *MockStore) GetWithLatestScan(ctx context.Context, id string) (*common.VMWithLatestScan, bool, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetWithLatestScan", ctx, id) + ret0, _ := ret[0].(*common.VMWithLatestScan) + ret1, _ := ret[1].(bool) + ret2, _ := ret[2].(error) + return ret0, ret1, ret2 +} + +// GetWithLatestScan indicates an expected call of GetWithLatestScan. +func (mr *MockStoreMockRecorder) GetWithLatestScan(ctx, id any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWithLatestScan", reflect.TypeOf((*MockStore)(nil).GetWithLatestScan), ctx, id) +} + // Search mocks base method. func (m *MockStore) Search(ctx context.Context, q *v1.Query) ([]search.Result, error) { m.ctrl.T.Helper() diff --git a/central/virtualmachine/v2/datastore/store/postgres/get_vm_bench_test.go b/central/virtualmachine/v2/datastore/store/postgres/get_vm_bench_test.go new file mode 100644 index 0000000000000..af78f48867913 --- /dev/null +++ b/central/virtualmachine/v2/datastore/store/postgres/get_vm_bench_test.go @@ -0,0 +1,64 @@ +//go:build sql_integration + +package postgres + +import ( + "context" + "fmt" + "testing" + + "github.com/stackrox/rox/generated/storage" + "github.com/stackrox/rox/pkg/concurrency" + "github.com/stackrox/rox/pkg/features" + "github.com/stackrox/rox/pkg/postgres/pgtest" + "github.com/stackrox/rox/pkg/sac" + "github.com/stackrox/rox/pkg/uuid" + "github.com/stretchr/testify/require" + "google.golang.org/protobuf/types/known/timestamppb" +) + +// BenchmarkGetVM measures the joined VM and latest-scan lookup. +// Only VM metadata and scans are seeded; the lookup does not read components or CVEs. +func BenchmarkGetVM(b *testing.B) { + b.Setenv(features.VirtualMachinesEnhancedDataModel.EnvVar(), "true") + ctx := sac.WithAllAccess(context.Background()) + testDB := pgtest.ForT(b) + vmStore := New(testDB.DB, concurrency.NewKeyFence()).(*storeImpl) + for _, vmCount := range []int{1000, 3000} { + b.Run(fmt.Sprintf("VMs%d", vmCount), func(b *testing.B) { + _, err := testDB.Exec(ctx, "TRUNCATE virtual_machine_v2 CASCADE") + require.NoError(b, err) + ids := make([]string, vmCount) + clusterID := uuid.NewV4().String() + tx, err := testDB.Begin(ctx) + require.NoError(b, err) + defer func() { _ = tx.Rollback(ctx) }() + for i := range ids { + ids[i] = uuid.NewV4().String() + require.NoError(b, vmStore.insertVM(ctx, tx, &storage.VirtualMachineV2{ + Id: ids[i], Name: fmt.Sprintf("vm-%d", i), Namespace: "default", + ClusterId: clusterID, ClusterName: "test-cluster", GuestOs: "rhel:9", + State: storage.VirtualMachineV2_RUNNING, LastUpdated: timestamppb.Now(), + })) + require.NoError(b, vmStore.insertScan(ctx, tx, &storage.VirtualMachineScanV2{ + Id: uuid.NewV7().String(), VmV2Id: ids[i], ScanOs: "rhel:9", + ScanTime: timestamppb.Now(), TopCvss: 9.8, + })) + } + require.NoError(b, tx.Commit(ctx)) + _, err = testDB.Exec(ctx, "ANALYZE virtual_machine_v2, virtual_machine_scan_v2") + require.NoError(b, err) + b.Run("JoinedQuery", func(b *testing.B) { + b.ReportAllocs() + i := 0 + for b.Loop() { + result, found, err := vmStore.GetWithLatestScan(ctx, ids[i%len(ids)]) + i++ + require.NoError(b, err) + require.True(b, found) + require.NotNil(b, result.Scan) + } + }) + }) + } +} diff --git a/central/virtualmachine/v2/datastore/store/postgres/store.go b/central/virtualmachine/v2/datastore/store/postgres/store.go index f54c1f0990c29..b42d8871aebbc 100644 --- a/central/virtualmachine/v2/datastore/store/postgres/store.go +++ b/central/virtualmachine/v2/datastore/store/postgres/store.go @@ -13,12 +13,16 @@ import ( v1 "github.com/stackrox/rox/generated/api/v1" "github.com/stackrox/rox/generated/storage" "github.com/stackrox/rox/pkg/concurrency" + "github.com/stackrox/rox/pkg/contextutil" + "github.com/stackrox/rox/pkg/env" "github.com/stackrox/rox/pkg/errox" ops "github.com/stackrox/rox/pkg/metrics" "github.com/stackrox/rox/pkg/postgres" "github.com/stackrox/rox/pkg/postgres/pgutils" pkgSchema "github.com/stackrox/rox/pkg/postgres/schema" "github.com/stackrox/rox/pkg/protocompat" + "github.com/stackrox/rox/pkg/sac" + "github.com/stackrox/rox/pkg/sac/resources" "github.com/stackrox/rox/pkg/search" pgSearch "github.com/stackrox/rox/pkg/search/postgres" "google.golang.org/protobuf/types/known/timestamppb" @@ -32,10 +36,17 @@ const ( getVMStmt = "SELECT serialized FROM " + vmTable + " WHERE Id = $1" getScanStmt = "SELECT serialized FROM " + scanTable + " WHERE VmV2Id = $1" + + // VM facts, notes, and VSOCK CID, plus scan notes, require the serialized blobs. + // LATERAL selects the newest UUIDv7 scan ID; LEFT JOIN retains VMs without scans. + getVMWithLatestScanStmt = "SELECT vm.serialized, scan.serialized FROM " + vmTable + " AS vm" + + " LEFT JOIN LATERAL (SELECT serialized FROM " + scanTable + + " WHERE VmV2Id = vm.Id ORDER BY Id DESC LIMIT 1) AS scan ON true WHERE vm.Id = $1" ) var ( schema = pkgSchema.VirtualMachineV2Schema + vmSAC = sac.ForResource(resources.VirtualMachine) ) // New returns a new Store instance using the provided sql instance. @@ -699,6 +710,44 @@ func (s *storeImpl) Get(ctx context.Context, id string) (*storage.VirtualMachine }) } +// GetWithLatestScan reads the VM and its latest scan in one snapshot. +func (s *storeImpl) GetWithLatestScan(ctx context.Context, id string) (*common.VMWithLatestScan, bool, error) { + defer metrics.SetPostgresOperationDurationTime(time.Now(), ops.Get, "VirtualMachineV2WithLatestScan") + queryCtx, cancel := contextutil.ContextWithTimeoutIfNotExists(ctx, env.PostgresVMStatementTimeout.DurationSetting()) + defer cancel() + return pgutils.Retry3(queryCtx, func() (*common.VMWithLatestScan, bool, error) { + var db postgres.Queryable = s.db + if tx, exists := postgres.TxFromContext(queryCtx); exists { + db = tx + } + var vmBytes, scanBytes []byte + err := db.QueryRow(queryCtx, getVMWithLatestScanStmt, pgutils.NilOrUUID(id)).Scan(&vmBytes, &scanBytes) + if errors.Is(err, pgx.ErrNoRows) { + return nil, false, nil + } + if err != nil { + return nil, false, errors.Wrap(err, "reading VM and latest scan") + } + vm := &storage.VirtualMachineV2{} + if err := vm.UnmarshalVT(vmBytes); err != nil { + return nil, false, errors.Wrap(err, "decoding VM") + } + // Match the scope filtering of Get: inaccessible VMs are not found, and + // neither their metadata nor their scan is returned to the caller. + if allowed, err := vmSAC.ReadAllowed(queryCtx, sac.ClusterScopeKey(vm.GetClusterId()), sac.NamespaceScopeKey(vm.GetNamespace())); err != nil || !allowed { + return nil, false, err + } + result := &common.VMWithLatestScan{VM: vm} + if scanBytes != nil { + result.Scan = &storage.VirtualMachineScanV2{} + if err := result.Scan.UnmarshalVT(scanBytes); err != nil { + return nil, false, errors.Wrap(err, "decoding latest VM scan") + } + } + return result, true, nil + }) +} + func (s *storeImpl) GetMany(ctx context.Context, ids []string) ([]*storage.VirtualMachineV2, []int, error) { defer metrics.SetPostgresOperationDurationTime(time.Now(), ops.GetMany, "VirtualMachineV2") diff --git a/central/virtualmachine/v2/datastore/store/postgres/store_test.go b/central/virtualmachine/v2/datastore/store/postgres/store_test.go index 8f9faf9624030..a62422a05fe48 100644 --- a/central/virtualmachine/v2/datastore/store/postgres/store_test.go +++ b/central/virtualmachine/v2/datastore/store/postgres/store_test.go @@ -4,6 +4,7 @@ package postgres import ( "context" + "slices" "testing" "time" @@ -16,6 +17,7 @@ import ( "github.com/stackrox/rox/pkg/postgres/pgutils" "github.com/stackrox/rox/pkg/protoassert" "github.com/stackrox/rox/pkg/sac" + "github.com/stackrox/rox/pkg/sac/resources" "github.com/stackrox/rox/pkg/search" "github.com/stackrox/rox/pkg/uuid" "github.com/stretchr/testify/suite" @@ -48,6 +50,117 @@ func (s *VMStoreTestSuite) SetupTest() { s.store = New(s.testDB.DB, concurrency.NewKeyFence()).(*storeImpl) } +func (s *VMStoreTestSuite) TestGetWithLatestScan_MissingVM() { + result, found, err := s.store.GetWithLatestScan(s.ctx, uuid.NewV4().String()) + s.Require().NoError(err) + s.False(found) + s.Nil(result) +} + +func (s *VMStoreTestSuite) TestGetWithLatestScan_NoScan() { + vm := s.newVM() + vm.Facts = map[string]string{"agentVersion": "1.0"} + s.Require().NoError(s.store.UpsertVM(s.ctx, vm)) + expected, found, err := s.store.Get(s.ctx, vm.GetId()) + s.Require().NoError(err) + s.Require().True(found) + result, found, err := s.store.GetWithLatestScan(s.ctx, vm.GetId()) + s.Require().NoError(err) + s.Require().True(found) + protoassert.Equal(s.T(), expected, result.VM) + s.Nil(result.Scan) +} + +func (s *VMStoreTestSuite) TestGetWithLatestScan_UsesScanID() { + vm := s.newVM() + s.Require().NoError(s.store.UpsertVM(s.ctx, vm)) + expected, found, err := s.store.Get(s.ctx, vm.GetId()) + s.Require().NoError(err) + s.Require().True(found) + ids := []string{uuid.NewV7().String(), uuid.NewV7().String()} + slices.Sort(ids) + old := &storage.VirtualMachineScanV2{ + Id: ids[0], VmV2Id: vm.GetId(), ScanTime: timestamppb.Now(), + } + latest := &storage.VirtualMachineScanV2{ + Id: ids[1], VmV2Id: vm.GetId(), ScanOs: "rhel:9", TopCvss: 9.8, + ScanTime: timestamppb.New(time.Now().Add(-time.Hour)), + Notes: []storage.VirtualMachineScanV2_Note{storage.VirtualMachineScanV2_OS_UNKNOWN}, + } + tx, err := s.testDB.Begin(s.ctx) + s.Require().NoError(err) + defer func() { _ = tx.Rollback(s.ctx) }() + s.Require().NoError(s.store.insertScan(s.ctx, tx, old)) + s.Require().NoError(s.store.insertScan(s.ctx, tx, latest)) + s.Require().NoError(tx.Commit(s.ctx)) + result, found, err := s.store.GetWithLatestScan(s.ctx, vm.GetId()) + s.Require().NoError(err) + s.Require().True(found) + protoassert.Equal(s.T(), expected, result.VM) + protoassert.Equal(s.T(), latest, result.Scan) +} + +func (s *VMStoreTestSuite) TestGetWithLatestScan_ScopedAccess() { + vm := s.newVM() + s.Require().NoError(s.store.UpsertVM(s.ctx, vm)) + s.Require().NoError(s.store.UpsertScan(s.ctx, vm.GetId(), s.newScanParts(vm.GetId()))) + allowedScope := func(cluster, namespace string) context.Context { + return sac.WithGlobalAccessScopeChecker(context.Background(), sac.AllowFixedScopes( + sac.AccessModeScopeKeys(storage.Access_READ_ACCESS), + sac.ResourceScopeKeys(resources.VirtualMachine), + sac.ClusterScopeKeys(cluster), + sac.NamespaceScopeKeys(namespace), + )) + } + tests := map[string]struct { + ctx context.Context + found bool + }{ + "all access": {ctx: s.ctx, found: true}, + "own namespace": {ctx: allowedScope(vm.GetClusterId(), vm.GetNamespace()), found: true}, + "different namespace": {ctx: allowedScope(vm.GetClusterId(), "other")}, + "different cluster": {ctx: allowedScope(uuid.NewV4().String(), vm.GetNamespace())}, + "no access": {ctx: sac.WithNoAccess(context.Background())}, + } + for name, tt := range tests { + s.Run(name, func() { + result, found, err := s.store.GetWithLatestScan(tt.ctx, vm.GetId()) + s.Require().NoError(err) + s.Equal(tt.found, found) + if tt.found { + s.NotNil(result.VM) + s.NotNil(result.Scan) + } else { + s.Nil(result, "VM metadata and scan must both be hidden") + } + _, oldFound, err := s.store.Get(tt.ctx, vm.GetId()) + s.Require().NoError(err) + s.Equal(oldFound, found, "joined read must match existing Get scope filtering") + }) + } +} + +func (s *VMStoreTestSuite) TestGetWithLatestScan_TransactionContext() { + vm := s.newVM() + scan := s.newScanParts(vm.GetId()).Scan + tx, txCtx, err := s.store.begin(s.ctx) + s.Require().NoError(err) + defer func() { _ = tx.Rollback(s.ctx) }() + s.Require().NoError(s.store.insertVM(txCtx, tx, vm)) + s.Require().NoError(s.store.insertScan(txCtx, tx, scan)) + + result, found, err := s.store.GetWithLatestScan(txCtx, vm.GetId()) + s.Require().NoError(err) + s.Require().True(found) + protoassert.Equal(s.T(), vm, result.VM) + protoassert.Equal(s.T(), scan, result.Scan) + + s.Require().NoError(tx.Rollback(s.ctx)) + _, found, err = s.store.GetWithLatestScan(s.ctx, vm.GetId()) + s.Require().NoError(err) + s.False(found, "uncommitted VM must only be visible through the transaction context") +} + func (s *VMStoreTestSuite) newVM() *storage.VirtualMachineV2 { return &storage.VirtualMachineV2{ Id: uuid.NewV4().String(), diff --git a/central/virtualmachine/v2/datastore/store/store.go b/central/virtualmachine/v2/datastore/store/store.go index c16f45b452d39..08b3ac8d05729 100644 --- a/central/virtualmachine/v2/datastore/store/store.go +++ b/central/virtualmachine/v2/datastore/store/store.go @@ -43,6 +43,8 @@ type Store interface { Search(ctx context.Context, q *v1.Query) ([]search.Result, error) // Get returns the VM with the given ID. Get(ctx context.Context, id string) (*storage.VirtualMachineV2, bool, error) + // GetWithLatestScan returns a VM and its latest scan in one query. + GetWithLatestScan(ctx context.Context, id string) (*common.VMWithLatestScan, bool, error) // GetMany returns the VMs with the given IDs. GetMany(ctx context.Context, ids []string) ([]*storage.VirtualMachineV2, []int, error) diff --git a/central/virtualmachine/v2/service/service_impl.go b/central/virtualmachine/v2/service/service_impl.go index 69775fe103509..855bdc9d4db8c 100644 --- a/central/virtualmachine/v2/service/service_impl.go +++ b/central/virtualmachine/v2/service/service_impl.go @@ -14,7 +14,6 @@ import ( cveDS "github.com/stackrox/rox/central/virtualmachine/cve/v2/datastore" scanDS "github.com/stackrox/rox/central/virtualmachine/scan/v2/datastore" vmDS "github.com/stackrox/rox/central/virtualmachine/v2/datastore" - v1 "github.com/stackrox/rox/generated/api/v1" v2 "github.com/stackrox/rox/generated/api/v2" "github.com/stackrox/rox/generated/storage" "github.com/stackrox/rox/pkg/auth/permissions" @@ -680,7 +679,7 @@ func (s *serviceImpl) GetVM(ctx context.Context, request *v2.GetVMRequest) (*v2. return nil, status.Errorf(codes.InvalidArgument, "id must be a valid UUID (got: %q)", request.GetId()) } - vm, exists, err := s.vmDS.GetVirtualMachine(ctx, request.GetId()) + vmWithScan, exists, err := s.vmDS.GetVirtualMachineWithLatestScan(ctx, request.GetId()) if err != nil { return nil, err } @@ -688,6 +687,7 @@ func (s *serviceImpl) GetVM(ctx context.Context, request *v2.GetVMRequest) (*v2. return nil, status.Errorf(codes.NotFound, "virtual machine %q not found", request.GetId()) } + vm := vmWithScan.VM detail := storagetov2.VirtualMachineV2ToDetail(vm) detail.AgentStatus = storagetov2.AgentStatusFromLastContact( vm.GetLastAgentContact(), @@ -695,22 +695,7 @@ func (s *serviceImpl) GetVM(ctx context.Context, request *v2.GetVMRequest) (*v2. env.VirtualMachinesAgentStaleAfter.DurationSetting(), ) - // Get the latest scan for this VM. Scan IDs are UUIDv7 (time-sortable), - // so sorting by the primary key is equivalent to sorting by time and avoids - // a separate index scan. - scanQuery := search.NewQueryBuilder().AddExactMatches(search.VirtualMachineID, request.GetId()).ProtoQuery() - scanQuery.Pagination = &v1.QueryPagination{ - Limit: 1, - SortOptions: []*v1.QuerySortOption{ - {Field: search.VirtualMachineScanID.String(), Reversed: true}, - }, - } - scans, err := s.scanDS.SearchRawVMScans(ctx, scanQuery) - if err != nil { - return nil, err - } - if len(scans) > 0 { - scan := scans[0] + if scan := vmWithScan.Scan; scan != nil { scanNotes := make([]v2.VMScanNote, 0, len(scan.GetNotes())) for _, n := range scan.GetNotes() { scanNotes = append(scanNotes, storagetov2.ConvertScanNote(n)) diff --git a/central/virtualmachine/v2/service/service_impl_test.go b/central/virtualmachine/v2/service/service_impl_test.go index f94c9b130c7ee..1dd1ae8eb09ea 100644 --- a/central/virtualmachine/v2/service/service_impl_test.go +++ b/central/virtualmachine/v2/service/service_impl_test.go @@ -14,6 +14,7 @@ import ( cveDSMocks "github.com/stackrox/rox/central/virtualmachine/cve/v2/datastore/mocks" scanDSMocks "github.com/stackrox/rox/central/virtualmachine/scan/v2/datastore/mocks" vmDSMocks "github.com/stackrox/rox/central/virtualmachine/v2/datastore/mocks" + "github.com/stackrox/rox/central/virtualmachine/v2/datastore/store/common" v2 "github.com/stackrox/rox/generated/api/v2" "github.com/stackrox/rox/generated/storage" "github.com/stackrox/rox/pkg/fixtures/fixtureconsts" @@ -722,7 +723,7 @@ func TestGetVM(t *testing.T) { Id: testVMID, }, setupMock: func(mockVM *vmDSMocks.MockDataStore, mockCVE *cveDSMocks.MockDataStore, mockComp *componentDSMocks.MockDataStore, mockScan *scanDSMocks.MockDataStore, mockView *cveViewMocks.MockCveView) { - mockVM.EXPECT().GetVirtualMachine(ctx, testVMID).Return(nil, false, nil) + mockVM.EXPECT().GetVirtualMachineWithLatestScan(ctx, testVMID).Return(nil, false, nil) }, expectedError: "not found", }, @@ -731,8 +732,7 @@ func TestGetVM(t *testing.T) { Id: testVMID, }, setupMock: func(mockVM *vmDSMocks.MockDataStore, mockCVE *cveDSMocks.MockDataStore, mockComp *componentDSMocks.MockDataStore, mockScan *scanDSMocks.MockDataStore, mockView *cveViewMocks.MockCveView) { - mockVM.EXPECT().GetVirtualMachine(ctx, testVMID).Return(vm1, true, nil) - mockScan.EXPECT().SearchRawVMScans(ctx, gomock.Any()).Return([]*storage.VirtualMachineScanV2{scan1}, nil) + mockVM.EXPECT().GetVirtualMachineWithLatestScan(ctx, testVMID).Return(&common.VMWithLatestScan{VM: vm1, Scan: scan1}, true, nil) }, expectedResult: func() *v2.VMDetail { detail := storagetov2.VirtualMachineV2ToDetail(vm1) @@ -750,8 +750,7 @@ func TestGetVM(t *testing.T) { Id: testVMID, }, setupMock: func(mockVM *vmDSMocks.MockDataStore, mockCVE *cveDSMocks.MockDataStore, mockComp *componentDSMocks.MockDataStore, mockScan *scanDSMocks.MockDataStore, mockView *cveViewMocks.MockCveView) { - mockVM.EXPECT().GetVirtualMachine(ctx, testVMID).Return(vm1, true, nil) - mockScan.EXPECT().SearchRawVMScans(ctx, gomock.Any()).Return(nil, nil) + mockVM.EXPECT().GetVirtualMachineWithLatestScan(ctx, testVMID).Return(&common.VMWithLatestScan{VM: vm1}, true, nil) }, expectedResult: storagetov2.VirtualMachineV2ToDetail(vm1), }, @@ -767,8 +766,7 @@ func TestGetVM(t *testing.T) { VsockCid: 42, Facts: map[string]string{"agentVersion": "5.0.x-174-g6b7ccc2192"}, } - mockVM.EXPECT().GetVirtualMachine(ctx, testVMID).Return(neverScraped, true, nil) - mockScan.EXPECT().SearchRawVMScans(ctx, gomock.Any()).Return(nil, nil) + mockVM.EXPECT().GetVirtualMachineWithLatestScan(ctx, testVMID).Return(&common.VMWithLatestScan{VM: neverScraped}, true, nil) }, expectedResult: func() *v2.VMDetail { detail := storagetov2.VirtualMachineV2ToDetail(&storage.VirtualMachineV2{ @@ -789,8 +787,7 @@ func TestGetVM(t *testing.T) { setupMock: func(mockVM *vmDSMocks.MockDataStore, mockCVE *cveDSMocks.MockDataStore, mockComp *componentDSMocks.MockDataStore, mockScan *scanDSMocks.MockDataStore, mockView *cveViewMocks.MockCveView) { fresh := vm1.CloneVT() fresh.LastAgentContact = timestamppb.New(time.Now().Add(-time.Hour)) - mockVM.EXPECT().GetVirtualMachine(ctx, testVMID).Return(fresh, true, nil) - mockScan.EXPECT().SearchRawVMScans(ctx, gomock.Any()).Return(nil, nil) + mockVM.EXPECT().GetVirtualMachineWithLatestScan(ctx, testVMID).Return(&common.VMWithLatestScan{VM: fresh}, true, nil) }, expectedResult: func() *v2.VMDetail { detail := storagetov2.VirtualMachineV2ToDetail(vm1) @@ -806,8 +803,7 @@ func TestGetVM(t *testing.T) { fresh := vm1.CloneVT() fresh.Facts = map[string]string{"activationStatus": "inactive"} fresh.LastAgentContact = timestamppb.New(time.Now().Add(-time.Hour)) - mockVM.EXPECT().GetVirtualMachine(ctx, testVMID).Return(fresh, true, nil) - mockScan.EXPECT().SearchRawVMScans(ctx, gomock.Any()).Return(nil, nil) + mockVM.EXPECT().GetVirtualMachineWithLatestScan(ctx, testVMID).Return(&common.VMWithLatestScan{VM: fresh}, true, nil) }, expectedResult: func() *v2.VMDetail { detail := storagetov2.VirtualMachineV2ToDetail(vm1) @@ -824,8 +820,7 @@ func TestGetVM(t *testing.T) { stale := vm1.CloneVT() stale.Facts = map[string]string{"agentVersion": "5.0.x-174-g6b7ccc2192"} stale.LastAgentContact = timestamppb.New(time.Now().Add(-13 * time.Hour)) - mockVM.EXPECT().GetVirtualMachine(ctx, testVMID).Return(stale, true, nil) - mockScan.EXPECT().SearchRawVMScans(ctx, gomock.Any()).Return(nil, nil) + mockVM.EXPECT().GetVirtualMachineWithLatestScan(ctx, testVMID).Return(&common.VMWithLatestScan{VM: stale}, true, nil) }, expectedResult: func() *v2.VMDetail { detail := storagetov2.VirtualMachineV2ToDetail(vm1) @@ -839,17 +834,16 @@ func TestGetVM(t *testing.T) { Id: testVMID, }, setupMock: func(mockVM *vmDSMocks.MockDataStore, mockCVE *cveDSMocks.MockDataStore, mockComp *componentDSMocks.MockDataStore, mockScan *scanDSMocks.MockDataStore, mockView *cveViewMocks.MockCveView) { - mockVM.EXPECT().GetVirtualMachine(ctx, testVMID).Return(nil, false, errors.New("db error")) + mockVM.EXPECT().GetVirtualMachineWithLatestScan(ctx, testVMID).Return(nil, false, errors.New("db error")) }, expectedError: "db error", }, - "scan search error": { + "scan decoding error": { request: &v2.GetVMRequest{ Id: testVMID, }, setupMock: func(mockVM *vmDSMocks.MockDataStore, mockCVE *cveDSMocks.MockDataStore, mockComp *componentDSMocks.MockDataStore, mockScan *scanDSMocks.MockDataStore, mockView *cveViewMocks.MockCveView) { - mockVM.EXPECT().GetVirtualMachine(ctx, testVMID).Return(vm1, true, nil) - mockScan.EXPECT().SearchRawVMScans(ctx, gomock.Any()).Return(nil, errors.New("scan error")) + mockVM.EXPECT().GetVirtualMachineWithLatestScan(ctx, testVMID).Return(nil, false, errors.New("scan error")) }, expectedError: "scan error", }, diff --git a/central/worker/main.go b/central/worker/main.go index 0493c0d6355ad..0818932478d55 100644 --- a/central/worker/main.go +++ b/central/worker/main.go @@ -14,7 +14,6 @@ import ( notifierDS "github.com/stackrox/rox/central/notifier/datastore" notifierProcessor "github.com/stackrox/rox/central/notifier/processor" _ "github.com/stackrox/rox/central/notifiers/all" - "github.com/stackrox/rox/central/pruning" reportConfigDS "github.com/stackrox/rox/central/reports/config/datastore" vulnReportV2Scheduler "github.com/stackrox/rox/central/reports/scheduler/v2" reportSnapshotDS "github.com/stackrox/rox/central/reports/snapshot/datastore" @@ -55,15 +54,11 @@ func main() { log.Infof("DB pool initialized with max_conns=%d", poolVal) waitForMigrations(ctx) - ensureDBCurrent() startHealthServer() go startMetricsServer() - pruning.Singleton().Start() - log.Infof("Pruning GC started") - scheduler := vulnReportV2Scheduler.Singleton() scheduler.Start(globaldb.GetPostgres()) log.Infof("Vulnerability report scheduler started") @@ -87,13 +82,13 @@ func main() { log.Infof("central-worker shutting down") - pruning.Singleton().Stop() scheduler.Stop() globaldb.Close() } func waitForMigrations(ctx context.Context) { + versionStore := vStore.NewPostgres(globaldb.GetPostgres()) err := retry.WithRetry(func() error { acquired, release, err := dblock.TryAcquireAdvisoryLock(ctx, globaldb.GetPostgres(), dblock.MigrationLockID) if err != nil { @@ -102,10 +97,14 @@ func waitForMigrations(ctx context.Context) { if !acquired { return retry.MakeRetryable(errMigratorRunning) } - release() + defer release() + + if err := version.Ensure(versionStore); err != nil { + return retry.MakeRetryable(err) + } return nil }, retry.Tries(30), retry.BetweenAttempts(func(attempt int) { - log.Infof("Migrator lock held, waiting for migrations to complete (attempt %d)...", attempt+1) + log.Infof("Migrations not yet complete, waiting (attempt %d)...", attempt+1) time.Sleep(10 * time.Second) })) if err != nil { @@ -120,14 +119,6 @@ type retryableError string func (e retryableError) Error() string { return string(e) } -func ensureDBCurrent() { - versionStore := vStore.NewPostgres(globaldb.GetPostgres()) - if err := version.Ensure(versionStore); err != nil { - log.Fatalf("DB version check failed. Migrations may not be complete: %v", err) - } - log.Infof("DB version verified") -} - func startHealthServer() { mux := http.NewServeMux() mux.HandleFunc("/healthz", func(w http.ResponseWriter, _ *http.Request) { diff --git a/config-controller/api/v1alpha1/policy_types.go b/config-controller/api/v1alpha1/policy_types.go index c21b47a620ea6..3563ae52b0f4c 100644 --- a/config-controller/api/v1alpha1/policy_types.go +++ b/config-controller/api/v1alpha1/policy_types.go @@ -90,15 +90,29 @@ type SecurityPolicySpec struct { MitreVectorsLocked bool `json:"mitreVectorsLocked,omitempty"` } +// +kubebuilder:validation:AtMostOneOf=deployment;excludeByKind type Exclusion struct { - Name string `json:"name,omitempty"` - Deployment Deployment `json:"deployment,omitempty"` + Name string `json:"name,omitempty"` + // +optional + Deployment Deployment `json:"deployment,omitzero"` Image Image `json:"image,omitempty"` // +optional + // ExcludeByKind excludes all workloads of the selected Kubernetes kinds. + ExcludeByKind *ExcludeByKind `json:"excludeByKind,omitempty"` + // +optional // +kubebuilder:validation:Format="date-time" Expiration string `json:"expiration,omitempty"` } +// +kubebuilder:validation:Enum=CRON_JOB;JOB +type WorkloadKind string + +type ExcludeByKind struct { + // +kubebuilder:validation:MinItems=1 + // Kinds is the list of Kubernetes workload kinds to exclude. + Kinds []WorkloadKind `json:"kinds"` +} + type Deployment struct { Name string `json:"name,omitempty"` Scope Scope `json:"scope,omitempty"` @@ -152,10 +166,14 @@ type MitreAttackVectors struct { Techniques []string `json:"techniques,omitempty"` } +// ContainerType lists container kinds a policy may skip during evaluation. // +kubebuilder:validation:Enum=REGULAR;INIT type ContainerType string +// EvaluationFilter pre-filters which entities a policy evaluates. type EvaluationFilter struct { + // SkipContainerTypes lists container kinds to skip during evaluation. + // +optional SkipContainerTypes []ContainerType `json:"skipContainerTypes,omitempty"` } @@ -296,14 +314,18 @@ func (p SecurityPolicySpec) ToProtobuf(caches map[CacheType]map[string]string) ( protoExclusion.Expiration = protoTS } + if exclusion.Deployment != (Deployment{}) && exclusion.ExcludeByKind != nil { + return nil, errors.New("exclusion cannot set both 'deployment' and 'excludeByKind'") + } + if exclusion.Deployment != (Deployment{}) { - protoExclusion.Deployment = &storage.Exclusion_Deployment{ + dep := &storage.Exclusion_Deployment{ Name: exclusion.Deployment.Name, } scope := exclusion.Deployment.Scope if scope != (Scope{}) { - protoExclusion.Deployment.Scope = &storage.Scope{ + dep.Scope = &storage.Scope{ Namespace: scope.Namespace, } if scope.Cluster != "" { @@ -311,31 +333,53 @@ func (p SecurityPolicySpec) ToProtobuf(caches map[CacheType]map[string]string) ( if err != nil { return nil, errors.New(fmt.Sprintf("Cluster '%s' does not exist", scope.Cluster)) } - protoExclusion.Deployment.Scope.Cluster = clusterID + dep.Scope.Cluster = clusterID } } if scope.Label != (Label{}) { - protoExclusion.Deployment.Scope.Label = &storage.Scope_Label{ + dep.Scope.Label = &storage.Scope_Label{ Key: scope.Label.Key, Value: scope.Label.Value, } } if scope.ClusterLabel != (Label{}) { - protoExclusion.Deployment.Scope.ClusterLabel = &storage.Scope_Label{ + dep.Scope.ClusterLabel = &storage.Scope_Label{ Key: scope.ClusterLabel.Key, Value: scope.ClusterLabel.Value, } } if scope.NamespaceLabel != (Label{}) { - protoExclusion.Deployment.Scope.NamespaceLabel = &storage.Scope_Label{ + dep.Scope.NamespaceLabel = &storage.Scope_Label{ Key: scope.NamespaceLabel.Key, Value: scope.NamespaceLabel.Value, } } + protoExclusion.Matcher = &storage.Exclusion_Deployment_{ + Deployment: dep, + } + } + + if exclusion.ExcludeByKind != nil { + if len(exclusion.ExcludeByKind.Kinds) == 0 { + return nil, errors.New("excludeByKind must specify at least one workload kind") + } + kinds := make([]storage.Exclusion_WorkloadKind, 0, len(exclusion.ExcludeByKind.Kinds)) + for _, kind := range exclusion.ExcludeByKind.Kinds { + val, found := storage.Exclusion_WorkloadKind_value[string(kind)] + if !found || storage.Exclusion_WorkloadKind(val) == storage.Exclusion_WORKLOAD_KIND_UNSPECIFIED { + return nil, errors.Errorf("excludeByKind contains unknown workload kind %q", kind) + } + kinds = append(kinds, storage.Exclusion_WorkloadKind(val)) + } + protoExclusion.Matcher = &storage.Exclusion_ExcludeByKind_{ + ExcludeByKind: &storage.Exclusion_ExcludeByKind{ + Kinds: kinds, + }, + } } proto.Exclusions = append(proto.Exclusions, &protoExclusion) diff --git a/config-controller/api/v1alpha1/policy_types_test.go b/config-controller/api/v1alpha1/policy_types_test.go index 2c69dabf34afd..2e95d9bb1e5a2 100644 --- a/config-controller/api/v1alpha1/policy_types_test.go +++ b/config-controller/api/v1alpha1/policy_types_test.go @@ -1,6 +1,7 @@ package v1alpha1 import ( + "encoding/json" "testing" "github.com/stackrox/rox/generated/storage" @@ -106,22 +107,24 @@ func TestToProtobuf(t *testing.T) { Exclusions: []*storage.Exclusion{ { Name: "Don't alert on deployment collector in namespace stackrox", - Deployment: &storage.Exclusion_Deployment{ - Name: "collector", - Scope: &storage.Scope{ - Namespace: "stackrox", - Cluster: clusterID, - Label: &storage.Scope_Label{ - Key: "app", - Value: "collector", - }, - ClusterLabel: &storage.Scope_Label{ - Key: "env", - Value: "dev", - }, - NamespaceLabel: &storage.Scope_Label{ - Key: "team", - Value: "platform", + Matcher: &storage.Exclusion_Deployment_{ + Deployment: &storage.Exclusion_Deployment{ + Name: "collector", + Scope: &storage.Scope{ + Namespace: "stackrox", + Cluster: clusterID, + Label: &storage.Scope_Label{ + Key: "app", + Value: "collector", + }, + ClusterLabel: &storage.Scope_Label{ + Key: "env", + Value: "dev", + }, + NamespaceLabel: &storage.Scope_Label{ + Key: "team", + Value: "platform", + }, }, }, }, @@ -239,6 +242,14 @@ func TestToProtobufEvaluationFilter(t *testing.T) { filter: &EvaluationFilter{SkipContainerTypes: []ContainerType{"INIT"}}, expectedTypes: []storage.ContainerType{storage.ContainerType_INIT}, }, + "skip regular containers": { + filter: &EvaluationFilter{SkipContainerTypes: []ContainerType{"REGULAR"}}, + expectedTypes: []storage.ContainerType{storage.ContainerType_REGULAR}, + }, + "skip both container types": { + filter: &EvaluationFilter{SkipContainerTypes: []ContainerType{"REGULAR", "INIT"}}, + expectedTypes: []storage.ContainerType{storage.ContainerType_REGULAR, storage.ContainerType_INIT}, + }, "nil filter": { filter: nil, expectNilProto: true, @@ -279,3 +290,90 @@ func TestToProtobufEvaluationFilter(t *testing.T) { }) } } + +func TestToProtobufRejectsDeploymentAndExcludeByKind(t *testing.T) { + spec := SecurityPolicySpec{ + PolicyName: "both-matchers", + Categories: []string{"Security Best Practices"}, + LifecycleStages: []LifecycleStage{"DEPLOY"}, + Severity: "LOW_SEVERITY", + Exclusions: []Exclusion{ + { + Name: "invalid dual matcher", + Deployment: Deployment{ + Name: "collector", + }, + ExcludeByKind: &ExcludeByKind{ + Kinds: []WorkloadKind{"JOB"}, + }, + }, + }, + } + + _, err := spec.ToProtobuf(map[CacheType]map[string]string{ + Notifier: {}, + Cluster: {}, + }) + assert.EqualError(t, err, "exclusion cannot set both 'deployment' and 'excludeByKind'") +} + +func TestToProtobufExcludeByKind(t *testing.T) { + caches := map[CacheType]map[string]string{ + Notifier: {}, + Cluster: {}, + } + baseSpec := func(exclude *ExcludeByKind) SecurityPolicySpec { + return SecurityPolicySpec{ + PolicyName: "kind-exclusion", + Categories: []string{"Security Best Practices"}, + LifecycleStages: []LifecycleStage{"DEPLOY"}, + Severity: "LOW_SEVERITY", + Exclusions: []Exclusion{{ + Name: "by kind", + ExcludeByKind: exclude, + }}, + } + } + + t.Run("converts JOB and CRON_JOB", func(t *testing.T) { + proto, err := baseSpec(&ExcludeByKind{Kinds: []WorkloadKind{"JOB", "CRON_JOB"}}).ToProtobuf(caches) + assert.NoError(t, err) + assert.Equal(t, []storage.Exclusion_WorkloadKind{ + storage.Exclusion_JOB, + storage.Exclusion_CRON_JOB, + }, proto.GetExclusions()[0].GetExcludeByKind().GetKinds()) + }) + + t.Run("rejects empty kind list", func(t *testing.T) { + _, err := baseSpec(&ExcludeByKind{}).ToProtobuf(caches) + assert.EqualError(t, err, "excludeByKind must specify at least one workload kind") + }) + + t.Run("rejects unknown kind", func(t *testing.T) { + _, err := baseSpec(&ExcludeByKind{Kinds: []WorkloadKind{"CRONJOB"}}).ToProtobuf(caches) + assert.EqualError(t, err, `excludeByKind contains unknown workload kind "CRONJOB"`) + }) + + t.Run("rejects mixed valid and unknown kinds", func(t *testing.T) { + _, err := baseSpec(&ExcludeByKind{Kinds: []WorkloadKind{"JOB", "CRONJOB"}}).ToProtobuf(caches) + assert.EqualError(t, err, `excludeByKind contains unknown workload kind "CRONJOB"`) + }) +} + +func TestExclusionJSONOmitsZeroDeployment(t *testing.T) { + kindOnly, err := json.Marshal(Exclusion{ + Name: "skip jobs", + ExcludeByKind: &ExcludeByKind{Kinds: []WorkloadKind{"JOB"}}, + }) + assert.NoError(t, err) + assert.NotContains(t, string(kindOnly), `"deployment"`) + assert.Contains(t, string(kindOnly), `"excludeByKind"`) + + withDeployment, err := json.Marshal(Exclusion{ + Name: "skip web", + Deployment: Deployment{Name: "web"}, + }) + assert.NoError(t, err) + assert.Contains(t, string(withDeployment), `"deployment"`) + assert.Contains(t, string(withDeployment), `"web"`) +} diff --git a/config-controller/api/v1alpha1/zz_generated.deepcopy.go b/config-controller/api/v1alpha1/zz_generated.deepcopy.go index 89f899775ea59..93085d27ed0d5 100644 --- a/config-controller/api/v1alpha1/zz_generated.deepcopy.go +++ b/config-controller/api/v1alpha1/zz_generated.deepcopy.go @@ -60,11 +60,36 @@ func (in *EvaluationFilter) DeepCopy() *EvaluationFilter { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ExcludeByKind) DeepCopyInto(out *ExcludeByKind) { + *out = *in + if in.Kinds != nil { + in, out := &in.Kinds, &out.Kinds + *out = make([]WorkloadKind, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExcludeByKind. +func (in *ExcludeByKind) DeepCopy() *ExcludeByKind { + if in == nil { + return nil + } + out := new(ExcludeByKind) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Exclusion) DeepCopyInto(out *Exclusion) { *out = *in out.Deployment = in.Deployment out.Image = in.Image + if in.ExcludeByKind != nil { + in, out := &in.ExcludeByKind, &out.ExcludeByKind + *out = new(ExcludeByKind) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Exclusion. @@ -314,7 +339,9 @@ func (in *SecurityPolicySpec) DeepCopyInto(out *SecurityPolicySpec) { if in.Exclusions != nil { in, out := &in.Exclusions, &out.Exclusions *out = make([]Exclusion, len(*in)) - copy(*out, *in) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } } if in.Scope != nil { in, out := &in.Scope, &out.Scope diff --git a/config-controller/config/crd/bases/config.stackrox.io_securitypolicies.yaml b/config-controller/config/crd/bases/config.stackrox.io_securitypolicies.yaml index 6329c0e2b6373..d3a1254eabdb2 100644 --- a/config-controller/config/crd/bases/config.stackrox.io_securitypolicies.yaml +++ b/config-controller/config/crd/bases/config.stackrox.io_securitypolicies.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.21.0 + controller-gen.kubebuilder.io/version: v0.22.0 name: securitypolicies.config.stackrox.io spec: group: config.stackrox.io @@ -82,7 +82,11 @@ spec: evaluates. properties: skipContainerTypes: + description: SkipContainerTypes lists container kinds to skip + during evaluation. items: + description: ContainerType lists container kinds a policy may + skip during evaluation. enum: - REGULAR - INIT @@ -138,6 +142,23 @@ spec: type: object type: object type: object + excludeByKind: + description: ExcludeByKind excludes all workloads of the selected + Kubernetes kinds. + properties: + kinds: + description: Kinds is the list of Kubernetes workload kinds + to exclude. + items: + enum: + - CRON_JOB + - JOB + type: string + minItems: 1 + type: array + required: + - kinds + type: object expiration: format: date-time type: string @@ -149,6 +170,11 @@ spec: name: type: string type: object + x-kubernetes-validations: + - message: at most one of the fields in [deployment excludeByKind] + may be set + rule: (has(self.deployment)?1:0)+(has(self.excludeByKind)?1:0) + <= 1 type: array isDefault: description: IsDefault is unused diff --git a/deploy/README.md b/deploy/README.md index 34cda08abfe6c..6f41a41b11f3a 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -24,8 +24,9 @@ Installation of roxie is straightforward: the hood. 1. there is also a containerized version of roxie living at quay.io/rhacs-eng/roxie, which can be used ad-hoc. -Furthermore, the `deploy/deploy.sh` shell script supports a roxie backend: set `USE_ROXIE_DEPLOY=true` in the -environment and it will automatically download and run the roxie version specified in the `ROXIE_VERSION` file. +Furthermore, the `deploy/deploy.sh` shell script uses a roxie backend by default. It will automatically +download and run the roxie version specified in the `ROXIE_VERSION` file. To fall back to the legacy +deploy flow, set `USE_ROXIE_DEPLOY=false` in the environment. Any extra arguments you pass to `deploy.sh` are forwarded directly to roxie, so you can use roxie CLI flags even with `deploy.sh`, e.g.: @@ -34,8 +35,8 @@ so you can use roxie CLI flags even with `deploy.sh`, e.g.: ./deploy/deploy.sh --tag 4.11.0 ``` -The roxie backend in `deploy.sh` is **opt-in** for now. Over time, we expect it to -become opt-out, and eventually the legacy deployment scripts will be removed entirely. +The roxie backend in `deploy.sh` is **opt-out**. Set `USE_ROXIE_DEPLOY=false` to fall +back to the legacy flow. The legacy deployment scripts will be removed entirely soon. If you would like to use roxie directly, but roxie is not installed on your system, all `roxie` commands below can also be run via `scripts/roxie.sh` instead: @@ -124,7 +125,6 @@ roxie deploy [ ... ] --tag
``` or alternatively ``` -export USE_ROXIE_DEPLOY=true MAIN_IMAGE_TAG=
./deploy/deploy.sh [ ... ] ``` @@ -294,4 +294,5 @@ Most environment variables can be found in [common/env.sh](common/env.sh). | `ROX_LOCAL_SOURCE_PATH` | `string` | When `ROX_HOTRELOAD` is enabled this variable sets the path to the local binary. This is useful when the `hostPath` mount links into a VM or container, e.g. when using KIND. | | `ROX_INIT_BUNDLE_PATH` | `string` | Sets a custom init-bundle file path for Sensor. | | `ROX_CENTRAL_EXTRA_HELM_VALUES_FILE` | `string` | Adds a custom value file path to the Central Helm chart. | +| `SCANNER_V4_DB_CLAIM_NAME` | `string` | Sets the Scanner V4 DB PVC claim name in both Central and bundled monitoring when using classic Helm deploy. | | `ROX_SENSOR_EXTRA_HELM_VALUES_FILE` | `string` | Adds a custom value file path to the Sensor Helm chart. | diff --git a/deploy/charts/monitoring/README.md b/deploy/charts/monitoring/README.md index 603f743ea3503..81ffd4f82d17a 100644 --- a/deploy/charts/monitoring/README.md +++ b/deploy/charts/monitoring/README.md @@ -21,6 +21,8 @@ On OpenShift, Helm may fail an upgrade with a ServiceAccount `imagePullSecrets` Roxie can install the same chart as add-on release `roxie-addon-monitoring` via `central.availableAddOns.monitoring`. +For a custom Scanner V4 DB PVC, set `scannerV4DbPvcClaimName` to the same name as Central's `scannerV4.db.persistence.persistentVolumeClaim.claimName` when installing monitoring. Classic deploy can set `SCANNER_V4_DB_CLAIM_NAME` to pass the same name to both charts; a custom claim specified only in `ROX_CENTRAL_EXTRA_HELM_VALUES_FILE` will not change the monitoring chart. + ## OpenShift When the cluster exposes `security.openshift.io/v1/SecurityContextConstraints`, the chart: diff --git a/deploy/charts/monitoring/templates/prometheus.yaml b/deploy/charts/monitoring/templates/prometheus.yaml index 0f81a5b2835c9..849f65facc268 100644 --- a/deploy/charts/monitoring/templates/prometheus.yaml +++ b/deploy/charts/monitoring/templates/prometheus.yaml @@ -58,6 +58,28 @@ data: {{ toYaml .Values.cadvisorMetricRelabelConfigs | indent 10 }} {{- end }} + # Kubelet /metrics exposes kubelet_volume_stats_* (PVC used/capacity), + # which cadvisor does not. Used for central-db and scanner-v4-db PVC space + # alerting. + - job_name: "kubernetes-kubelet" + scheme: https + metrics_path: /metrics + tls_config: + ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt + insecure_skip_verify: true + authorization: + credentials_file: /var/run/secrets/kubernetes.io/serviceaccount/token + kubernetes_sd_configs: + - role: node + relabel_configs: + - action: labelmap + regex: __meta_kubernetes_node_label_(.+) + metric_relabel_configs: + # Keep only the StackRox DB PVC volume stats needed for space alerting. + - source_labels: [__name__, persistentvolumeclaim] + action: keep + regex: kubelet_volume_stats_(used|capacity)_bytes;(central-db|{{ .Values.scannerV4DbPvcClaimName | regexQuoteMeta }}) + - job_name: stackrox tls_config: insecure_skip_verify: false @@ -109,3 +131,55 @@ data: annotations: summary: Kubernetes ReplicaSet mismatch (replicaset {{ "{{" }} $labels.replicaset {{ "}}" }}) description: "Replicas mismatch in ReplicaSet {{ "{{" }} $labels.exported_namespace {{ "}}" }}/{{ "{{" }} $labels.replicaset {{ "}}" }}" + + rules_alerts_stackrox.yml: |- + groups: + - name: StackRox + rules: + # Central DB PVC space utilization (used / filesystem capacity) from the + # kubelet volume stats. Exposed as a stable metric for dashboards and + # reused by the alerts below. + - record: stackrox:central_db_pvc_usage_ratio + expr: kubelet_volume_stats_used_bytes{persistentvolumeclaim="central-db"} / kubelet_volume_stats_capacity_bytes{persistentvolumeclaim="central-db"} + + - alert: StackRoxCentralDbPvcSpaceWarning + expr: stackrox:central_db_pvc_usage_ratio > {{ .Values.centralDbPvcUsageWarningRatio }} + for: 5m + labels: + severity: warning + annotations: + summary: Central DB PVC filling up (pvc {{ "{{" }} $labels.persistentvolumeclaim {{ "}}" }}) + description: "Central DB PVC {{ "{{" }} $labels.namespace {{ "}}" }}/{{ "{{" }} $labels.persistentvolumeclaim {{ "}}" }} is {{ "{{" }} $value | humanizePercentage {{ "}}" }} full." + + - alert: StackRoxCentralDbPvcSpaceCritical + expr: stackrox:central_db_pvc_usage_ratio > {{ .Values.centralDbPvcUsageCriticalRatio }} + for: 5m + labels: + severity: critical + annotations: + summary: Central DB PVC almost full (pvc {{ "{{" }} $labels.persistentvolumeclaim {{ "}}" }}) + description: "Central DB PVC {{ "{{" }} $labels.namespace {{ "}}" }}/{{ "{{" }} $labels.persistentvolumeclaim {{ "}}" }} is {{ "{{" }} $value | humanizePercentage {{ "}}" }} full." + + # Scanner V4 DB PVC space utilization (used / filesystem capacity) from the + # kubelet volume stats. Exposed as a stable metric for dashboards and + # reused by the alerts below. + - record: stackrox:scanner_v4_db_pvc_usage_ratio + expr: kubelet_volume_stats_used_bytes{persistentvolumeclaim={{ .Values.scannerV4DbPvcClaimName | quote }}} / kubelet_volume_stats_capacity_bytes{persistentvolumeclaim={{ .Values.scannerV4DbPvcClaimName | quote }}} + + - alert: StackRoxScannerV4DbPvcSpaceWarning + expr: stackrox:scanner_v4_db_pvc_usage_ratio > {{ .Values.scannerV4DbPvcUsageWarningRatio }} + for: 1h + labels: + severity: warning + annotations: + summary: Scanner V4 DB PVC filling up (pvc {{ "{{" }} $labels.persistentvolumeclaim {{ "}}" }}) + description: "Scanner V4 DB PVC {{ "{{" }} $labels.namespace {{ "}}" }}/{{ "{{" }} $labels.persistentvolumeclaim {{ "}}" }} is {{ "{{" }} $value | humanizePercentage {{ "}}" }} full." + + - alert: StackRoxScannerV4DbPvcSpaceCritical + expr: stackrox:scanner_v4_db_pvc_usage_ratio > {{ .Values.scannerV4DbPvcUsageCriticalRatio }} + for: 5m + labels: + severity: critical + annotations: + summary: Scanner V4 DB PVC almost full (pvc {{ "{{" }} $labels.persistentvolumeclaim {{ "}}" }}) + description: "Scanner V4 DB PVC {{ "{{" }} $labels.namespace {{ "}}" }}/{{ "{{" }} $labels.persistentvolumeclaim {{ "}}" }} is {{ "{{" }} $value | humanizePercentage {{ "}}" }} full." diff --git a/deploy/charts/monitoring/values.yaml b/deploy/charts/monitoring/values.yaml index 2b644d260b240..e84192fbcfc43 100644 --- a/deploy/charts/monitoring/values.yaml +++ b/deploy/charts/monitoring/values.yaml @@ -27,6 +27,19 @@ nodeSelector: {} # Metric relabel configs for kubernetes-cadvisor job to filter out metrics cadvisorMetricRelabelConfigs: [] +# Central DB PVC space-usage alerting. Utilization is used/capacity from the +# kubelet volume stats (scraped by the kubernetes-kubelet job). The warning and +# critical alerts fire when the central-db PVC exceeds these fill ratios. +centralDbPvcUsageWarningRatio: 0.8 +centralDbPvcUsageCriticalRatio: 0.9 + +# Scanner V4 DB PVC space-usage alerting. Same mechanism as central-db above; the +# warning and critical alerts fire when this PVC exceeds these fill ratios. +# Match scannerV4.db.persistence.persistentVolumeClaim.claimName in the Central chart. +scannerV4DbPvcClaimName: scanner-v4-db +scannerV4DbPvcUsageWarningRatio: 0.8 +scannerV4DbPvcUsageCriticalRatio: 0.9 + kube-state-metrics: releaseNamespace: true # Align with the parent monitoring Deployment UIDs. Upstream defaults use diff --git a/deploy/common/ci-values.yaml b/deploy/common/ci-values.yaml index d56a7324c3b75..cf0dfe7fc85d4 100644 --- a/deploy/common/ci-values.yaml +++ b/deploy/common/ci-values.yaml @@ -27,9 +27,9 @@ scannerV4: resources: requests: cpu: "400m" - memory: "4Gi" + memory: "6Gi" limits: - memory: "4Gi" + memory: "6Gi" indexer: replicas: 1 autoscaling: diff --git a/deploy/common/k8sbased.sh b/deploy/common/k8sbased.sh index 9a946e7ca0c29..a205b6eb430f2 100644 --- a/deploy/common/k8sbased.sh +++ b/deploy/common/k8sbased.sh @@ -322,6 +322,9 @@ function launch_central { --set persistence.type="${STORAGE}" --set exposure.type="${MONITORING_LOAD_BALANCER}" ) + if [[ -n "${SCANNER_V4_DB_CLAIM_NAME:-}" ]]; then + helm_args+=(--set-string "scannerV4DbPvcClaimName=${SCANNER_V4_DB_CLAIM_NAME}") + fi if [[ "${is_local_dev}" == "true" ]]; then helm_args+=(-f "${COMMON_DIR}/monitoring-values-local.yaml") fi @@ -515,6 +518,9 @@ function launch_central { if [[ -n "${SCANNER_V4_DB_STORAGE_CLASS}" ]]; then helm_args+=(--set "scannerV4.db.persistence.persistentVolumeClaim.storageClass=${SCANNER_V4_DB_STORAGE_CLASS}") fi + if [[ -n "${SCANNER_V4_DB_CLAIM_NAME:-}" ]]; then + helm_args+=(--set-string "scannerV4.db.persistence.persistentVolumeClaim.claimName=${SCANNER_V4_DB_CLAIM_NAME}") + fi # Add a custom values file to Helm if [[ -n "$ROX_CENTRAL_EXTRA_HELM_VALUES_FILE" ]]; then @@ -635,7 +641,11 @@ function launch_central { # On some systems there's a race condition when port-forward connects to central but its pod then gets deleted due # to ongoing modifications to the central deployment. This port-forward dies and the script hangs "Waiting for # Central to respond" until it times out. Waiting for rollout status should help not get into such situation. + # Central-db is waited first because it needs to be online before Central can start. rollout_wait_timeout="10m" + if [[ -z "$EXTERNAL_DB" ]]; then + kubectl -n "${central_namespace}" rollout status deploy/central-db --timeout="${rollout_wait_timeout}" + fi kubectl -n "${central_namespace}" rollout status deploy/central --timeout="${rollout_wait_timeout}" # if we have specified that we want to use a load balancer, then use that endpoint instead of localhost @@ -940,20 +950,18 @@ function launch_sensor { extra_helm_config+=(--set "virtualMachines.enabled=false") fi - # Shorten node-scan cadence for e2e (production: 5m initial, 4h interval). - # Matcher-not-ready drops the first index as unretryable; a short interval - # covers the next scan without restarting collector. - helm_args+=( - --set customize.envVars.ROX_NODE_SCANNING_MAX_INITIAL_WAIT=1s - --set customize.envVars.ROX_NODE_SCANNING_INTERVAL=30s - ) - if [[ -n "$LOGLEVEL" ]]; then helm_args+=( --set customize.envVars.LOGLEVEL="${LOGLEVEL}" ) fi + # Scan every 9-11 minutes with Helm deployments. + helm_args+=( + --set customize.envVars.ROX_NODE_SCANNING_INTERVAL=10m + --set customize.envVars.ROX_NODE_SCANNING_INTERVAL_DEVIATION=60s + ) + if [[ -n "${ROX_NETFLOW_BATCHING:-}" ]]; then helm_args+=( --set customize.envVars.ROX_NETFLOW_BATCHING="${ROX_NETFLOW_BATCHING}" @@ -999,7 +1007,7 @@ function launch_sensor { if [[ "${sensor_namespace}" != "stackrox" ]]; then kubectl create namespace "${sensor_namespace}" &>/dev/null || true - kubectl -n "${sensor_namespace}" get secret stackrox &>/dev/null || kubectl -n "${sensor_namespace}" create -f - < <("${common_dir}/pull-secret.sh" stackrox docker.io) + kubectl -n "${sensor_namespace}" get secret stackrox &>/dev/null || kubectl -n "${sensor_namespace}" create -f - < <("${common_dir}/../../scripts/pull-secret.sh" stackrox docker.io) fi if [[ -n "${ROX_PROCESS_INDICATORS_PER_NAMESPACE}" ]]; then @@ -1099,6 +1107,10 @@ function launch_sensor { if [[ "${#sensor_env[@]}" -gt 0 ]]; then kubectl -n "${sensor_namespace}" set env deploy/sensor "${sensor_env[@]}" fi + + # Scan every 9-11 minutes with manifest deployments. + kubectl -n "${sensor_namespace}" set env ds/collector --containers=compliance \ + ROX_NODE_SCANNING_INTERVAL=10m ROX_NODE_SCANNING_INTERVAL_DEVIATION=60s fi collector_env=() diff --git a/deploy/common/scanner-v4-matcher-patch.yaml b/deploy/common/scanner-v4-matcher-patch.yaml index 50fdadabc6f25..557949164ff6b 100644 --- a/deploy/common/scanner-v4-matcher-patch.yaml +++ b/deploy/common/scanner-v4-matcher-patch.yaml @@ -6,6 +6,3 @@ spec: resources: requests: cpu: "400m" - memory: "4Gi" - limits: - memory: "4Gi" diff --git a/deploy/deploy.sh b/deploy/deploy.sh index d431739141589..a9b091f08ccbd 100755 --- a/deploy/deploy.sh +++ b/deploy/deploy.sh @@ -3,13 +3,13 @@ set -e DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)" -if [[ "${USE_ROXIE_DEPLOY:-false}" == "true" ]]; then +if [[ "${USE_ROXIE_DEPLOY:-true}" == "true" ]]; then ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." && pwd)" if [[ "${SKIP_ROXIE_DEPLOY_BANNER:-false}" != "true" ]]; then cat <,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" }, "v1AdministrationEvent": { diff --git a/generated/api/v1/administration_usage_service.pb.go b/generated/api/v1/administration_usage_service.pb.go index 6e92409a7e7e3..8d53d6e5cd51f 100644 --- a/generated/api/v1/administration_usage_service.pb.go +++ b/generated/api/v1/administration_usage_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/administration_usage_service.proto diff --git a/generated/api/v1/administration_usage_service.pb.gw.go b/generated/api/v1/administration_usage_service.pb.gw.go index 0889ec45c387c..b9dec12d1b966 100644 --- a/generated/api/v1/administration_usage_service.pb.gw.go +++ b/generated/api/v1/administration_usage_service.pb.gw.go @@ -63,15 +63,15 @@ func request_AdministrationUsageService_GetMaxSecuredUnitsUsage_0(ctx context.Co protoReq TimeRange metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_AdministrationUsageService_GetMaxSecuredUnitsUsage_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetMaxSecuredUnitsUsage(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } diff --git a/generated/api/v1/administration_usage_service.swagger.json b/generated/api/v1/administration_usage_service.swagger.json index a17c1c2c9f6c2..7d3ba1b401d2a 100644 --- a/generated/api/v1/administration_usage_service.swagger.json +++ b/generated/api/v1/administration_usage_service.swagger.json @@ -109,7 +109,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" }, "v1MaxSecuredUnitsUsageResponse": { diff --git a/generated/api/v1/alert_service.pb.go b/generated/api/v1/alert_service.pb.go index 3e23235d9c681..7c6cfa1d39954 100644 --- a/generated/api/v1/alert_service.pb.go +++ b/generated/api/v1/alert_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/alert_service.proto diff --git a/generated/api/v1/alert_service.pb.gw.go b/generated/api/v1/alert_service.pb.gw.go index 07c4e44e552ba..1f46e3201bf5a 100644 --- a/generated/api/v1/alert_service.pb.gw.go +++ b/generated/api/v1/alert_service.pb.gw.go @@ -41,9 +41,6 @@ func request_AlertService_GetAlert_0(ctx context.Context, marshaler runtime.Mars metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -52,6 +49,9 @@ func request_AlertService_GetAlert_0(ctx context.Context, marshaler runtime.Mars if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetAlert(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -81,15 +81,15 @@ func request_AlertService_CountAlerts_0(ctx context.Context, marshaler runtime.M protoReq RawQuery metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_AlertService_CountAlerts_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.CountAlerts(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -116,15 +116,15 @@ func request_AlertService_ListAlerts_0(ctx context.Context, marshaler runtime.Ma protoReq ListAlertsRequest metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_AlertService_ListAlerts_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.ListAlerts(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -151,15 +151,15 @@ func request_AlertService_GetAlertsGroup_0(ctx context.Context, marshaler runtim protoReq ListAlertsRequest metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_AlertService_GetAlertsGroup_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetAlertsGroup(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -186,15 +186,15 @@ func request_AlertService_GetAlertsCounts_0(ctx context.Context, marshaler runti protoReq GetAlertsCountsRequest metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_AlertService_GetAlertsCounts_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetAlertsCounts(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -221,15 +221,15 @@ func request_AlertService_GetAlertTimeseries_0(ctx context.Context, marshaler ru protoReq ListAlertsRequest metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_AlertService_GetAlertTimeseries_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetAlertTimeseries(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -258,9 +258,6 @@ func request_AlertService_ResolveAlert_0(ctx context.Context, marshaler runtime. if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -269,6 +266,9 @@ func request_AlertService_ResolveAlert_0(ctx context.Context, marshaler runtime. if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.ResolveAlert(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -328,15 +328,15 @@ func request_AlertService_DeleteAlerts_0(ctx context.Context, marshaler runtime. protoReq DeleteAlertsRequest metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_AlertService_DeleteAlerts_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.DeleteAlerts(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } diff --git a/generated/api/v1/alert_service.swagger.json b/generated/api/v1/alert_service.swagger.json index 2134c2e45324b..85fa125ebe54b 100644 --- a/generated/api/v1/alert_service.swagger.json +++ b/generated/api/v1/alert_service.swagger.json @@ -6,7 +6,8 @@ }, "tags": [ { - "name": "AlertService" + "name": "AlertService", + "description": "AlertService APIs can be used to manage alerts." } ], "consumes": [ @@ -762,6 +763,18 @@ } } }, + "ExclusionExcludeByKind": { + "type": "object", + "properties": { + "kinds": { + "type": "array", + "items": { + "$ref": "#/definitions/ExclusionWorkloadKind" + } + } + }, + "description": "ExcludeByKind excludes all workloads of the selected Kubernetes kinds." + }, "ExclusionImage": { "type": "object", "properties": { @@ -770,6 +783,16 @@ } } }, + "ExclusionWorkloadKind": { + "type": "string", + "enum": [ + "WORKLOAD_KIND_UNSPECIFIED", + "CRON_JOB", + "JOB" + ], + "default": "WORKLOAD_KIND_UNSPECIFIED", + "description": "WorkloadKind is a Kubernetes workload kind that can be excluded from a policy in bulk." + }, "FileAccessFileMetadata": { "type": "object", "properties": { @@ -1018,7 +1041,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" }, "storageAclEntry": { @@ -1294,15 +1317,18 @@ "name": { "type": "string" }, - "deployment": { - "$ref": "#/definitions/storageExclusionDeployment" - }, "image": { "$ref": "#/definitions/ExclusionImage" }, "expiration": { "type": "string", "format": "date-time" + }, + "deployment": { + "$ref": "#/definitions/storageExclusionDeployment" + }, + "excludeByKind": { + "$ref": "#/definitions/ExclusionExcludeByKind" } } }, @@ -1518,7 +1544,7 @@ "NODE" ], "default": "DEPLOYMENT", - "title": "A special ListAlert-only enumeration of all resource types. Unlike Alert.Resource.ResourceType this also includes deployment and node as types\nThis must be kept in sync with Alert.Resource.ResourceType (excluding the deployment and node values)" + "description": "A special ListAlert-only enumeration of all resource types. Unlike Alert.Resource.ResourceType this also includes deployment and node as types\nThis must be kept in sync with Alert.Resource.ResourceType (excluding the deployment and node values)" }, "storageNetworkEntityInfoType": { "type": "string", @@ -1531,7 +1557,7 @@ "INTERNAL_ENTITIES" ], "default": "UNKNOWN_TYPE", - "title": "- INTERNAL_ENTITIES: INTERNAL_ENTITIES is for grouping all internal entities under a single network graph node" + "description": "- INTERNAL_ENTITIES: INTERNAL_ENTITIES is for grouping all internal entities under a single network graph node" }, "storagePolicy": { "type": "object", @@ -1582,7 +1608,7 @@ "type": "object", "$ref": "#/definitions/storageExclusion" }, - "description": "Define deployments or images that should be excluded from this policy." + "description": "Define deployments, images, or workload kinds that should be excluded from this policy." }, "scope": { "type": "array", diff --git a/generated/api/v1/api_token_service.pb.go b/generated/api/v1/api_token_service.pb.go index bf9a3a7a27e33..fc0a1e08254a5 100644 --- a/generated/api/v1/api_token_service.pb.go +++ b/generated/api/v1/api_token_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/api_token_service.proto diff --git a/generated/api/v1/api_token_service.pb.gw.go b/generated/api/v1/api_token_service.pb.gw.go index ad7c42e56b2e6..dc9007767ffa3 100644 --- a/generated/api/v1/api_token_service.pb.gw.go +++ b/generated/api/v1/api_token_service.pb.gw.go @@ -41,9 +41,6 @@ func request_APITokenService_GetAPIToken_0(ctx context.Context, marshaler runtim metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -52,6 +49,9 @@ func request_APITokenService_GetAPIToken_0(ctx context.Context, marshaler runtim if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetAPIToken(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -81,15 +81,15 @@ func request_APITokenService_GetAPITokens_0(ctx context.Context, marshaler runti protoReq GetAPITokensRequest metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_APITokenService_GetAPITokens_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetAPITokens(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -142,9 +142,6 @@ func request_APITokenService_RevokeToken_0(ctx context.Context, marshaler runtim metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -153,6 +150,9 @@ func request_APITokenService_RevokeToken_0(ctx context.Context, marshaler runtim if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.RevokeToken(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } diff --git a/generated/api/v1/api_token_service.swagger.json b/generated/api/v1/api_token_service.swagger.json index 96a411c1f51bb..2c759accb7acb 100644 --- a/generated/api/v1/api_token_service.swagger.json +++ b/generated/api/v1/api_token_service.swagger.json @@ -6,7 +6,8 @@ }, "tags": [ { - "name": "APITokenService" + "name": "APITokenService", + "description": "APITokenService APIs can be used to manage API tokens." } ], "consumes": [ @@ -194,7 +195,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" }, "storageTokenMetadata": { diff --git a/generated/api/v1/audit.pb.go b/generated/api/v1/audit.pb.go index d6061d0c60a33..21ac701c05122 100644 --- a/generated/api/v1/audit.pb.go +++ b/generated/api/v1/audit.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/audit.proto diff --git a/generated/api/v1/audit.swagger.json b/generated/api/v1/audit.swagger.json index 713fd20b0be90..bcc50e3221067 100644 --- a/generated/api/v1/audit.swagger.json +++ b/generated/api/v1/audit.swagger.json @@ -39,7 +39,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" } } diff --git a/generated/api/v1/auth_service.pb.go b/generated/api/v1/auth_service.pb.go index a1a9293bb741a..f73e92a603e26 100644 --- a/generated/api/v1/auth_service.pb.go +++ b/generated/api/v1/auth_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/auth_service.proto diff --git a/generated/api/v1/auth_service.pb.gw.go b/generated/api/v1/auth_service.pb.gw.go index e8c4600adf4ec..fea8409f5290c 100644 --- a/generated/api/v1/auth_service.pb.gw.go +++ b/generated/api/v1/auth_service.pb.gw.go @@ -83,9 +83,6 @@ func request_AuthService_GetAuthMachineToMachineConfig_0(ctx context.Context, ma metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -94,6 +91,9 @@ func request_AuthService_GetAuthMachineToMachineConfig_0(ctx context.Context, ma if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetAuthMachineToMachineConfig(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -152,9 +152,6 @@ func request_AuthService_UpdateAuthMachineToMachineConfig_0(ctx context.Context, if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["config.id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "config.id") @@ -163,6 +160,9 @@ func request_AuthService_UpdateAuthMachineToMachineConfig_0(ctx context.Context, if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "config.id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.UpdateAuthMachineToMachineConfig(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -194,9 +194,6 @@ func request_AuthService_DeleteAuthMachineToMachineConfig_0(ctx context.Context, metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -205,6 +202,9 @@ func request_AuthService_DeleteAuthMachineToMachineConfig_0(ctx context.Context, if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.DeleteAuthMachineToMachineConfig(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } diff --git a/generated/api/v1/auth_service.swagger.json b/generated/api/v1/auth_service.swagger.json index a4a0ca235ca17..2ea9e4d2003f2 100644 --- a/generated/api/v1/auth_service.swagger.json +++ b/generated/api/v1/auth_service.swagger.json @@ -334,7 +334,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" }, "storageAccess": { diff --git a/generated/api/v1/authprovider_service.pb.go b/generated/api/v1/authprovider_service.pb.go index 6a330cdf80dfb..f8d8f077c2924 100644 --- a/generated/api/v1/authprovider_service.pb.go +++ b/generated/api/v1/authprovider_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/authprovider_service.proto diff --git a/generated/api/v1/authprovider_service.pb.gw.go b/generated/api/v1/authprovider_service.pb.gw.go index 6f928439c544c..2de8e8e0edd2c 100644 --- a/generated/api/v1/authprovider_service.pb.gw.go +++ b/generated/api/v1/authprovider_service.pb.gw.go @@ -63,9 +63,6 @@ func request_AuthProviderService_GetAuthProvider_0(ctx context.Context, marshale metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -74,6 +71,9 @@ func request_AuthProviderService_GetAuthProvider_0(ctx context.Context, marshale if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetAuthProvider(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -124,15 +124,15 @@ func request_AuthProviderService_GetAuthProviders_0(ctx context.Context, marshal protoReq GetAuthProvidersRequest metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_AuthProviderService_GetAuthProviders_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetAuthProviders(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -188,9 +188,6 @@ func request_AuthProviderService_UpdateAuthProvider_0(ctx context.Context, marsh if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -199,6 +196,9 @@ func request_AuthProviderService_UpdateAuthProvider_0(ctx context.Context, marsh if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.UpdateAuthProvider(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -233,9 +233,6 @@ func request_AuthProviderService_PutAuthProvider_0(ctx context.Context, marshale if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -244,6 +241,9 @@ func request_AuthProviderService_PutAuthProvider_0(ctx context.Context, marshale if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.PutAuthProvider(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -277,9 +277,6 @@ func request_AuthProviderService_DeleteAuthProvider_0(ctx context.Context, marsh metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -294,6 +291,9 @@ func request_AuthProviderService_DeleteAuthProvider_0(ctx context.Context, marsh if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_AuthProviderService_DeleteAuthProvider_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.DeleteAuthProvider(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } diff --git a/generated/api/v1/authprovider_service.swagger.json b/generated/api/v1/authprovider_service.swagger.json index c6d83c657690e..fb8d798f33e9a 100644 --- a/generated/api/v1/authprovider_service.swagger.json +++ b/generated/api/v1/authprovider_service.swagger.json @@ -454,7 +454,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" }, "storageAccess": { diff --git a/generated/api/v1/backup_service.pb.go b/generated/api/v1/backup_service.pb.go index d34c9aa786c8c..7517816852110 100644 --- a/generated/api/v1/backup_service.pb.go +++ b/generated/api/v1/backup_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/backup_service.proto diff --git a/generated/api/v1/backup_service.pb.gw.go b/generated/api/v1/backup_service.pb.gw.go index 114272eb9be8f..e2d80b0f41032 100644 --- a/generated/api/v1/backup_service.pb.gw.go +++ b/generated/api/v1/backup_service.pb.gw.go @@ -42,9 +42,6 @@ func request_ExternalBackupService_GetExternalBackup_0(ctx context.Context, mars metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -53,6 +50,9 @@ func request_ExternalBackupService_GetExternalBackup_0(ctx context.Context, mars if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetExternalBackup(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -132,9 +132,6 @@ func request_ExternalBackupService_PutExternalBackup_0(ctx context.Context, mars if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -143,6 +140,9 @@ func request_ExternalBackupService_PutExternalBackup_0(ctx context.Context, mars if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.PutExternalBackup(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -201,9 +201,6 @@ func request_ExternalBackupService_DeleteExternalBackup_0(ctx context.Context, m metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -212,6 +209,9 @@ func request_ExternalBackupService_DeleteExternalBackup_0(ctx context.Context, m if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.DeleteExternalBackup(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -240,9 +240,6 @@ func request_ExternalBackupService_TriggerExternalBackup_0(ctx context.Context, metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -251,6 +248,9 @@ func request_ExternalBackupService_TriggerExternalBackup_0(ctx context.Context, if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.TriggerExternalBackup(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -282,9 +282,6 @@ func request_ExternalBackupService_UpdateExternalBackup_0(ctx context.Context, m if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["external_backup.id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "external_backup.id") @@ -293,6 +290,9 @@ func request_ExternalBackupService_UpdateExternalBackup_0(ctx context.Context, m if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "external_backup.id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.UpdateExternalBackup(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } diff --git a/generated/api/v1/backup_service.swagger.json b/generated/api/v1/backup_service.swagger.json index d2b08da1642d8..d32610bb92924 100644 --- a/generated/api/v1/backup_service.swagger.json +++ b/generated/api/v1/backup_service.swagger.json @@ -446,7 +446,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" }, "storageExternalBackup": { diff --git a/generated/api/v1/central_health_service.pb.go b/generated/api/v1/central_health_service.pb.go index f4c9e38293be9..bbdcdc6d51ef4 100644 --- a/generated/api/v1/central_health_service.pb.go +++ b/generated/api/v1/central_health_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/central_health_service.proto diff --git a/generated/api/v1/central_health_service.swagger.json b/generated/api/v1/central_health_service.swagger.json index 8f503d22ee80c..4b25029150f5c 100644 --- a/generated/api/v1/central_health_service.swagger.json +++ b/generated/api/v1/central_health_service.swagger.json @@ -67,7 +67,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" }, "v1CentralUpgradeStatus": { diff --git a/generated/api/v1/cloud_source_service.pb.go b/generated/api/v1/cloud_source_service.pb.go index e6835b0d88b25..dbbd311948e97 100644 --- a/generated/api/v1/cloud_source_service.pb.go +++ b/generated/api/v1/cloud_source_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/cloud_source_service.proto diff --git a/generated/api/v1/cloud_source_service.pb.gw.go b/generated/api/v1/cloud_source_service.pb.gw.go index 510f5f44218c0..2334cf4b1faa6 100644 --- a/generated/api/v1/cloud_source_service.pb.gw.go +++ b/generated/api/v1/cloud_source_service.pb.gw.go @@ -42,15 +42,15 @@ func request_CloudSourcesService_CountCloudSources_0(ctx context.Context, marsha protoReq CountCloudSourcesRequest metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_CloudSourcesService_CountCloudSources_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.CountCloudSources(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -76,9 +76,6 @@ func request_CloudSourcesService_GetCloudSource_0(ctx context.Context, marshaler metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -87,6 +84,9 @@ func request_CloudSourcesService_GetCloudSource_0(ctx context.Context, marshaler if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetCloudSource(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -116,15 +116,15 @@ func request_CloudSourcesService_ListCloudSources_0(ctx context.Context, marshal protoReq ListCloudSourcesRequest metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_CloudSourcesService_ListCloudSources_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.ListCloudSources(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -180,9 +180,6 @@ func request_CloudSourcesService_UpdateCloudSource_0(ctx context.Context, marsha if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["cloud_source.id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "cloud_source.id") @@ -191,6 +188,9 @@ func request_CloudSourcesService_UpdateCloudSource_0(ctx context.Context, marsha if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "cloud_source.id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.UpdateCloudSource(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -222,9 +222,6 @@ func request_CloudSourcesService_DeleteCloudSource_0(ctx context.Context, marsha metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -233,6 +230,9 @@ func request_CloudSourcesService_DeleteCloudSource_0(ctx context.Context, marsha if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.DeleteCloudSource(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } diff --git a/generated/api/v1/cloud_source_service.swagger.json b/generated/api/v1/cloud_source_service.swagger.json index 2dcf635c25ed1..8e1291f014b8f 100644 --- a/generated/api/v1/cloud_source_service.swagger.json +++ b/generated/api/v1/cloud_source_service.swagger.json @@ -407,7 +407,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" }, "v1AggregateBy": { diff --git a/generated/api/v1/cluster_init_service.pb.go b/generated/api/v1/cluster_init_service.pb.go index 85a88915e3a19..c62740345a676 100644 --- a/generated/api/v1/cluster_init_service.pb.go +++ b/generated/api/v1/cluster_init_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/cluster_init_service.proto diff --git a/generated/api/v1/cluster_init_service.swagger.json b/generated/api/v1/cluster_init_service.swagger.json index 9e4773f0410d0..ea8903f691f65 100644 --- a/generated/api/v1/cluster_init_service.swagger.json +++ b/generated/api/v1/cluster_init_service.swagger.json @@ -6,7 +6,8 @@ }, "tags": [ { - "name": "ClusterInitService" + "name": "ClusterInitService", + "description": "ClusterInitService manages cluster init bundles and CRSs." } ], "consumes": [ @@ -312,7 +313,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" }, "storageUser": { diff --git a/generated/api/v1/cluster_service.pb.go b/generated/api/v1/cluster_service.pb.go index 6426337fbb739..aa892aa0471b7 100644 --- a/generated/api/v1/cluster_service.pb.go +++ b/generated/api/v1/cluster_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/cluster_service.proto diff --git a/generated/api/v1/cluster_service.pb.gw.go b/generated/api/v1/cluster_service.pb.gw.go index d0ed73dd50c9c..55f9e25111dc7 100644 --- a/generated/api/v1/cluster_service.pb.gw.go +++ b/generated/api/v1/cluster_service.pb.gw.go @@ -43,15 +43,15 @@ func request_ClustersService_GetClusters_0(ctx context.Context, marshaler runtim protoReq GetClustersRequest metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ClustersService_GetClusters_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetClusters(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -77,9 +77,6 @@ func request_ClustersService_GetCluster_0(ctx context.Context, marshaler runtime metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -88,6 +85,9 @@ func request_ClustersService_GetCluster_0(ctx context.Context, marshaler runtime if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetCluster(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -146,9 +146,6 @@ func request_ClustersService_PutCluster_0(ctx context.Context, marshaler runtime if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -157,6 +154,9 @@ func request_ClustersService_PutCluster_0(ctx context.Context, marshaler runtime if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.PutCluster(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -188,9 +188,6 @@ func request_ClustersService_DeleteCluster_0(ctx context.Context, marshaler runt metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -199,6 +196,9 @@ func request_ClustersService_DeleteCluster_0(ctx context.Context, marshaler runt if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.DeleteCluster(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } diff --git a/generated/api/v1/cluster_service.swagger.json b/generated/api/v1/cluster_service.swagger.json index e7cb5f337dafc..1e8a2ed8f7d55 100644 --- a/generated/api/v1/cluster_service.swagger.json +++ b/generated/api/v1/cluster_service.swagger.json @@ -229,7 +229,7 @@ "HEALTHY" ], "default": "UNINITIALIZED", - "title": "- UNAVAILABLE: Only collector can have unavailable status" + "description": "- UNAVAILABLE: Only collector can have unavailable status" }, "ClusterUpgradeStatusUpgradability": { "type": "string", @@ -436,7 +436,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" }, "storageAWSProviderMetadata": { diff --git a/generated/api/v1/common.pb.go b/generated/api/v1/common.pb.go index 015f336224cb2..a459f0aed74a5 100644 --- a/generated/api/v1/common.pb.go +++ b/generated/api/v1/common.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/common.proto diff --git a/generated/api/v1/common.swagger.json b/generated/api/v1/common.swagger.json index 97669590fb57b..40f82ac3fd23a 100644 --- a/generated/api/v1/common.swagger.json +++ b/generated/api/v1/common.swagger.json @@ -39,7 +39,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" } } diff --git a/generated/api/v1/compliance_management_service.pb.go b/generated/api/v1/compliance_management_service.pb.go index 5216c51320609..88b806e2b0d08 100644 --- a/generated/api/v1/compliance_management_service.pb.go +++ b/generated/api/v1/compliance_management_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/compliance_management_service.proto diff --git a/generated/api/v1/compliance_management_service.pb.gw.go b/generated/api/v1/compliance_management_service.pb.gw.go index d07c28da3c7c6..85beb2bcc2ed7 100644 --- a/generated/api/v1/compliance_management_service.pb.gw.go +++ b/generated/api/v1/compliance_management_service.pb.gw.go @@ -42,15 +42,15 @@ func request_ComplianceManagementService_GetRecentRuns_0(ctx context.Context, ma protoReq GetRecentComplianceRunsRequest metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ComplianceManagementService_GetRecentRuns_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetRecentRuns(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -104,15 +104,15 @@ func request_ComplianceManagementService_GetRunStatuses_0(ctx context.Context, m protoReq GetComplianceRunStatusesRequest metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ComplianceManagementService_GetRunStatuses_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetRunStatuses(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } diff --git a/generated/api/v1/compliance_management_service.swagger.json b/generated/api/v1/compliance_management_service.swagger.json index e243bbe6ff9f5..33746563f5167 100644 --- a/generated/api/v1/compliance_management_service.swagger.json +++ b/generated/api/v1/compliance_management_service.swagger.json @@ -6,7 +6,8 @@ }, "tags": [ { - "name": "ComplianceManagementService" + "name": "ComplianceManagementService", + "description": "BEGIN EXPERIMENTAL/UNSTABLE API" } ], "consumes": [ @@ -160,7 +161,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" }, "v1ComplianceRun": { diff --git a/generated/api/v1/compliance_service.pb.go b/generated/api/v1/compliance_service.pb.go index 0e79d14433e1e..312ec3a6e252c 100644 --- a/generated/api/v1/compliance_service.pb.go +++ b/generated/api/v1/compliance_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/compliance_service.proto diff --git a/generated/api/v1/compliance_service.pb.gw.go b/generated/api/v1/compliance_service.pb.gw.go index 519f5634ac267..a4f8692fd62f2 100644 --- a/generated/api/v1/compliance_service.pb.gw.go +++ b/generated/api/v1/compliance_service.pb.gw.go @@ -62,9 +62,6 @@ func request_ComplianceService_GetStandard_0(ctx context.Context, marshaler runt metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -73,6 +70,9 @@ func request_ComplianceService_GetStandard_0(ctx context.Context, marshaler runt if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetStandard(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -102,15 +102,15 @@ func request_ComplianceService_GetRunResults_0(ctx context.Context, marshaler ru protoReq GetComplianceRunResultsRequest metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ComplianceService_GetRunResults_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetRunResults(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -137,15 +137,15 @@ func request_ComplianceService_GetAggregatedResults_0(ctx context.Context, marsh protoReq ComplianceAggregationRequest metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ComplianceService_GetAggregatedResults_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetAggregatedResults(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -174,9 +174,6 @@ func request_ComplianceService_UpdateComplianceStandardConfig_0(ctx context.Cont if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -185,6 +182,9 @@ func request_ComplianceService_UpdateComplianceStandardConfig_0(ctx context.Cont if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.UpdateComplianceStandardConfig(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } diff --git a/generated/api/v1/compliance_service.swagger.json b/generated/api/v1/compliance_service.swagger.json index a185da8b8b6e4..50f24e40849a5 100644 --- a/generated/api/v1/compliance_service.swagger.json +++ b/generated/api/v1/compliance_service.swagger.json @@ -421,7 +421,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" }, "storageComplianceAggregationResponse": { diff --git a/generated/api/v1/config_service.pb.go b/generated/api/v1/config_service.pb.go index 40837fbde2163..babbb3f1f7cd8 100644 --- a/generated/api/v1/config_service.pb.go +++ b/generated/api/v1/config_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/config_service.proto diff --git a/generated/api/v1/config_service.swagger.json b/generated/api/v1/config_service.swagger.json index ceb25909aa01f..ea3383fddb4cc 100644 --- a/generated/api/v1/config_service.swagger.json +++ b/generated/api/v1/config_service.swagger.json @@ -6,7 +6,8 @@ }, "tags": [ { - "name": "ConfigService" + "name": "ConfigService", + "description": "ConfigService APIs can be used to manage Central config." } ], "consumes": [ @@ -341,7 +342,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" }, "storageAdministrationEventsConfig": { diff --git a/generated/api/v1/credential_expiry_service.pb.go b/generated/api/v1/credential_expiry_service.pb.go index a5f7347929bf2..caaf77268effa 100644 --- a/generated/api/v1/credential_expiry_service.pb.go +++ b/generated/api/v1/credential_expiry_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/credential_expiry_service.proto diff --git a/generated/api/v1/credential_expiry_service.pb.gw.go b/generated/api/v1/credential_expiry_service.pb.gw.go index 6429afb93f087..30b40f12b9633 100644 --- a/generated/api/v1/credential_expiry_service.pb.gw.go +++ b/generated/api/v1/credential_expiry_service.pb.gw.go @@ -42,15 +42,15 @@ func request_CredentialExpiryService_GetCertExpiry_0(ctx context.Context, marsha protoReq GetCertExpiry_Request metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_CredentialExpiryService_GetCertExpiry_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetCertExpiry(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } diff --git a/generated/api/v1/credential_expiry_service.swagger.json b/generated/api/v1/credential_expiry_service.swagger.json index f5c32c154bd68..4a7d0e7ebcc13 100644 --- a/generated/api/v1/credential_expiry_service.swagger.json +++ b/generated/api/v1/credential_expiry_service.swagger.json @@ -6,7 +6,8 @@ }, "tags": [ { - "name": "CredentialExpiryService" + "name": "CredentialExpiryService", + "description": "CredentialExpiryService APIs can be used to retrieve information related to expiry\nof credentials of various StackRox services." } ], "consumes": [ @@ -84,7 +85,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" }, "v1GetCertExpiryComponent": { diff --git a/generated/api/v1/cve_service.pb.go b/generated/api/v1/cve_service.pb.go index c7793cfc68520..353f0bb81dd31 100644 --- a/generated/api/v1/cve_service.pb.go +++ b/generated/api/v1/cve_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/cve_service.proto diff --git a/generated/api/v1/cve_service.swagger.json b/generated/api/v1/cve_service.swagger.json index 53503c19cd0a3..559c5b5eacbf4 100644 --- a/generated/api/v1/cve_service.swagger.json +++ b/generated/api/v1/cve_service.swagger.json @@ -6,10 +6,12 @@ }, "tags": [ { - "name": "NodeCVEService" + "name": "NodeCVEService", + "description": "NodeCVEService APIs can be used to manage node cves." }, { - "name": "ClusterCVEService" + "name": "ClusterCVEService", + "description": "ClusterCVEService APIs can be used to manage cluster cves." } ], "consumes": [ @@ -180,7 +182,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" }, "v1Empty": { diff --git a/generated/api/v1/db_service.pb.go b/generated/api/v1/db_service.pb.go index 30c74ac743f8c..1c38c412fd736 100644 --- a/generated/api/v1/db_service.pb.go +++ b/generated/api/v1/db_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/db_service.proto diff --git a/generated/api/v1/db_service.pb.gw.go b/generated/api/v1/db_service.pb.gw.go index 0979bd8be0048..7e864977dc57b 100644 --- a/generated/api/v1/db_service.pb.gw.go +++ b/generated/api/v1/db_service.pb.gw.go @@ -83,9 +83,6 @@ func request_DBService_InterruptRestoreProcess_0(ctx context.Context, marshaler metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["process_id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "process_id") @@ -102,6 +99,9 @@ func request_DBService_InterruptRestoreProcess_0(ctx context.Context, marshaler if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "attempt_id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.InterruptRestoreProcess(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -138,9 +138,6 @@ func request_DBService_CancelRestoreProcess_0(ctx context.Context, marshaler run metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -149,6 +146,9 @@ func request_DBService_CancelRestoreProcess_0(ctx context.Context, marshaler run if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.CancelRestoreProcess(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } diff --git a/generated/api/v1/db_service.swagger.json b/generated/api/v1/db_service.swagger.json index eff15bc22e485..e452759010492 100644 --- a/generated/api/v1/db_service.swagger.json +++ b/generated/api/v1/db_service.swagger.json @@ -189,7 +189,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" }, "v1DBExportFormat": { @@ -323,7 +323,7 @@ "COMPLETED" ], "default": "UNKNOWN", - "title": "- COMPLETED: successful if error is empty, unsuccessful otherwise" + "description": "- COMPLETED: successful if error is empty, unsuccessful otherwise" }, "v1DBRestoreRequestHeader": { "type": "object", diff --git a/generated/api/v1/debug_service.pb.go b/generated/api/v1/debug_service.pb.go index aae29f1d51dd2..6e4848efff030 100644 --- a/generated/api/v1/debug_service.pb.go +++ b/generated/api/v1/debug_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/debug_service.proto diff --git a/generated/api/v1/debug_service.pb.gw.go b/generated/api/v1/debug_service.pb.gw.go index f12ab6475098f..8dab0495d0993 100644 --- a/generated/api/v1/debug_service.pb.gw.go +++ b/generated/api/v1/debug_service.pb.gw.go @@ -42,15 +42,15 @@ func request_DebugService_GetLogLevel_0(ctx context.Context, marshaler runtime.M protoReq GetLogLevelRequest metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_DebugService_GetLogLevel_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetLogLevel(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } diff --git a/generated/api/v1/debug_service.swagger.json b/generated/api/v1/debug_service.swagger.json index 3749e09c0718f..d7f32da5be57b 100644 --- a/generated/api/v1/debug_service.swagger.json +++ b/generated/api/v1/debug_service.swagger.json @@ -6,7 +6,8 @@ }, "tags": [ { - "name": "DebugService" + "name": "DebugService", + "description": "APIs for debugging." } ], "consumes": [ @@ -349,7 +350,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" }, "storageAccess": { diff --git a/generated/api/v1/declarative_config_health_service.pb.go b/generated/api/v1/declarative_config_health_service.pb.go index 6059cda2d6cb0..b5d64e94f95cf 100644 --- a/generated/api/v1/declarative_config_health_service.pb.go +++ b/generated/api/v1/declarative_config_health_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/declarative_config_health_service.proto diff --git a/generated/api/v1/declarative_config_health_service.swagger.json b/generated/api/v1/declarative_config_health_service.swagger.json index 14ef10a3ad2c6..988bd404efcf4 100644 --- a/generated/api/v1/declarative_config_health_service.swagger.json +++ b/generated/api/v1/declarative_config_health_service.swagger.json @@ -81,7 +81,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" }, "storageDeclarativeConfigHealth": { diff --git a/generated/api/v1/delegated_registry_config_service.pb.go b/generated/api/v1/delegated_registry_config_service.pb.go index 86984982c6e58..1c02c02d58982 100644 --- a/generated/api/v1/delegated_registry_config_service.pb.go +++ b/generated/api/v1/delegated_registry_config_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/delegated_registry_config_service.proto diff --git a/generated/api/v1/delegated_registry_config_service.swagger.json b/generated/api/v1/delegated_registry_config_service.swagger.json index 00f59b70a2a22..aecd11f2f81d3 100644 --- a/generated/api/v1/delegated_registry_config_service.swagger.json +++ b/generated/api/v1/delegated_registry_config_service.swagger.json @@ -6,7 +6,8 @@ }, "tags": [ { - "name": "DelegatedRegistryConfigService" + "name": "DelegatedRegistryConfigService", + "description": "DelegatedRegistryConfigService APIs can be used to control how to route image scans amongst\ncentral and secured clusters" } ], "consumes": [ @@ -117,7 +118,7 @@ "SPECIFIC" ], "default": "NONE", - "title": "- NONE: Scan all images via central services except for images from the OCP integrated registry\n - ALL: Scan all images via the secured clusters\n - SPECIFIC: Scan images that match `registries` or are from the OCP integrated registry via the secured clusters\notherwise scan via central services" + "description": "- NONE: Scan all images via central services except for images from the OCP integrated registry\n - ALL: Scan all images via the secured clusters\n - SPECIFIC: Scan images that match `registries` or are from the OCP integrated registry via the secured clusters\notherwise scan via central services" }, "googleRpcStatus": { "type": "object", @@ -146,7 +147,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" }, "v1DelegatedRegistryCluster": { diff --git a/generated/api/v1/deployment_service.pb.go b/generated/api/v1/deployment_service.pb.go index 2003993071140..ef061a27ec403 100644 --- a/generated/api/v1/deployment_service.pb.go +++ b/generated/api/v1/deployment_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/deployment_service.proto diff --git a/generated/api/v1/deployment_service.pb.gw.go b/generated/api/v1/deployment_service.pb.gw.go index 004e1ad0b7d70..ae0d3da2eab9a 100644 --- a/generated/api/v1/deployment_service.pb.gw.go +++ b/generated/api/v1/deployment_service.pb.gw.go @@ -41,9 +41,6 @@ func request_DeploymentService_GetDeployment_0(ctx context.Context, marshaler ru metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -52,6 +49,9 @@ func request_DeploymentService_GetDeployment_0(ctx context.Context, marshaler ru if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetDeployment(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -80,9 +80,6 @@ func request_DeploymentService_GetDeploymentWithRisk_0(ctx context.Context, mars metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -91,6 +88,9 @@ func request_DeploymentService_GetDeploymentWithRisk_0(ctx context.Context, mars if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetDeploymentWithRisk(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -119,9 +119,6 @@ func request_DeploymentService_GetDeploymentRiskAISummary_0(ctx context.Context, metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -130,6 +127,9 @@ func request_DeploymentService_GetDeploymentRiskAISummary_0(ctx context.Context, if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetDeploymentRiskAISummary(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -159,15 +159,15 @@ func request_DeploymentService_CountDeployments_0(ctx context.Context, marshaler protoReq RawQuery metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_DeploymentService_CountDeployments_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.CountDeployments(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -194,15 +194,15 @@ func request_DeploymentService_ListDeployments_0(ctx context.Context, marshaler protoReq RawQuery metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_DeploymentService_ListDeployments_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.ListDeployments(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -229,15 +229,15 @@ func request_DeploymentService_ListDeploymentsWithProcessInfo_0(ctx context.Cont protoReq RawQuery metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_DeploymentService_ListDeploymentsWithProcessInfo_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.ListDeploymentsWithProcessInfo(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -285,15 +285,15 @@ func request_DeploymentService_ExportDeployments_0(ctx context.Context, marshale protoReq ExportDeploymentRequest metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_DeploymentService_ExportDeployments_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } stream, err := client.ExportDeployments(ctx, &protoReq) if err != nil { return nil, metadata, err diff --git a/generated/api/v1/deployment_service.swagger.json b/generated/api/v1/deployment_service.swagger.json index f5e9523e7e413..1cba2ea58425a 100644 --- a/generated/api/v1/deployment_service.swagger.json +++ b/generated/api/v1/deployment_service.swagger.json @@ -6,7 +6,8 @@ }, "tags": [ { - "name": "DeploymentService" + "name": "DeploymentService", + "description": "DeploymentService APIs can be used to manage deployments." } ], "consumes": [ @@ -456,7 +457,7 @@ "UNKNOWN" ], "default": "UNSET", - "title": "For any update to EnvVarSource, please also update 'ui/src/messages/common.js'" + "description": "For any update to EnvVarSource, please also update 'ui/src/messages/common.js'" }, "LabelSelectorRequirement": { "type": "object", @@ -647,7 +648,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" }, "storageContainer": { @@ -1027,7 +1028,7 @@ "CLUSTER_ADMIN" ], "default": "UNSET", - "title": "For any update to PermissionLevel, also update:\n- pkg/searchbasedpolicies/builders/k8s_rbac.go\n- ui/src/messages/common.js" + "description": "For any update to PermissionLevel, also update:\n- pkg/searchbasedpolicies/builders/k8s_rbac.go\n- ui/src/messages/common.js" }, "storagePortConfig": { "type": "object", @@ -1141,7 +1142,7 @@ "SERVICEACCOUNT" ], "default": "UNKNOWN", - "title": "Next tag: 9" + "description": "Next tag: 9" }, "storageSecurityContext": { "type": "object", diff --git a/generated/api/v1/detection_service.pb.go b/generated/api/v1/detection_service.pb.go index c38b91ddd1363..d031244214079 100644 --- a/generated/api/v1/detection_service.pb.go +++ b/generated/api/v1/detection_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/detection_service.proto diff --git a/generated/api/v1/detection_service.swagger.json b/generated/api/v1/detection_service.swagger.json index 4bfb593f41f83..9dac31c37873e 100644 --- a/generated/api/v1/detection_service.swagger.json +++ b/generated/api/v1/detection_service.swagger.json @@ -6,7 +6,8 @@ }, "tags": [ { - "name": "DetectionService" + "name": "DetectionService", + "description": "DetectionService APIs can be used to check for build and deploy time policy violations." } ], "consumes": [ @@ -279,7 +280,19 @@ "UNKNOWN" ], "default": "UNSET", - "title": "For any update to EnvVarSource, please also update 'ui/src/messages/common.js'" + "description": "For any update to EnvVarSource, please also update 'ui/src/messages/common.js'" + }, + "ExclusionExcludeByKind": { + "type": "object", + "properties": { + "kinds": { + "type": "array", + "items": { + "$ref": "#/definitions/ExclusionWorkloadKind" + } + } + }, + "description": "ExcludeByKind excludes all workloads of the selected Kubernetes kinds." }, "ExclusionImage": { "type": "object", @@ -289,6 +302,16 @@ } } }, + "ExclusionWorkloadKind": { + "type": "string", + "enum": [ + "WORKLOAD_KIND_UNSPECIFIED", + "CRON_JOB", + "JOB" + ], + "default": "WORKLOAD_KIND_UNSPECIFIED", + "description": "WorkloadKind is a Kubernetes workload kind that can be excluded from a policy in bulk." + }, "FileAccessFileMetadata": { "type": "object", "properties": { @@ -584,7 +607,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" }, "storageAclEntry": { @@ -1092,15 +1115,18 @@ "name": { "type": "string" }, - "deployment": { - "$ref": "#/definitions/storageExclusionDeployment" - }, "image": { "$ref": "#/definitions/ExclusionImage" }, "expiration": { "type": "string", "format": "date-time" + }, + "deployment": { + "$ref": "#/definitions/storageExclusionDeployment" + }, + "excludeByKind": { + "$ref": "#/definitions/ExclusionExcludeByKind" } } }, @@ -1250,7 +1276,7 @@ "INTERNAL_ENTITIES" ], "default": "UNKNOWN_TYPE", - "title": "- INTERNAL_ENTITIES: INTERNAL_ENTITIES is for grouping all internal entities under a single network graph node" + "description": "- INTERNAL_ENTITIES: INTERNAL_ENTITIES is for grouping all internal entities under a single network graph node" }, "storagePermissionLevel": { "type": "string", @@ -1263,7 +1289,7 @@ "CLUSTER_ADMIN" ], "default": "UNSET", - "title": "For any update to PermissionLevel, also update:\n- pkg/searchbasedpolicies/builders/k8s_rbac.go\n- ui/src/messages/common.js" + "description": "For any update to PermissionLevel, also update:\n- pkg/searchbasedpolicies/builders/k8s_rbac.go\n- ui/src/messages/common.js" }, "storagePolicy": { "type": "object", @@ -1314,7 +1340,7 @@ "type": "object", "$ref": "#/definitions/storageExclusion" }, - "description": "Define deployments or images that should be excluded from this policy." + "description": "Define deployments, images, or workload kinds that should be excluded from this policy." }, "scope": { "type": "array", diff --git a/generated/api/v1/discovered_cluster_service.pb.go b/generated/api/v1/discovered_cluster_service.pb.go index d67e410e47c81..d90390f43f837 100644 --- a/generated/api/v1/discovered_cluster_service.pb.go +++ b/generated/api/v1/discovered_cluster_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/discovered_cluster_service.proto diff --git a/generated/api/v1/discovered_cluster_service.pb.gw.go b/generated/api/v1/discovered_cluster_service.pb.gw.go index 10892f9ceb505..db873c116ff01 100644 --- a/generated/api/v1/discovered_cluster_service.pb.gw.go +++ b/generated/api/v1/discovered_cluster_service.pb.gw.go @@ -42,15 +42,15 @@ func request_DiscoveredClustersService_CountDiscoveredClusters_0(ctx context.Con protoReq CountDiscoveredClustersRequest metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_DiscoveredClustersService_CountDiscoveredClusters_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.CountDiscoveredClusters(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -76,9 +76,6 @@ func request_DiscoveredClustersService_GetDiscoveredCluster_0(ctx context.Contex metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -87,6 +84,9 @@ func request_DiscoveredClustersService_GetDiscoveredCluster_0(ctx context.Contex if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetDiscoveredCluster(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -116,15 +116,15 @@ func request_DiscoveredClustersService_ListDiscoveredClusters_0(ctx context.Cont protoReq ListDiscoveredClustersRequest metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_DiscoveredClustersService_ListDiscoveredClusters_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.ListDiscoveredClusters(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } diff --git a/generated/api/v1/discovered_cluster_service.swagger.json b/generated/api/v1/discovered_cluster_service.swagger.json index 3ae228bd8d480..309a09f862b21 100644 --- a/generated/api/v1/discovered_cluster_service.swagger.json +++ b/generated/api/v1/discovered_cluster_service.swagger.json @@ -313,7 +313,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" }, "v1AggregateBy": { diff --git a/generated/api/v1/empty.pb.go b/generated/api/v1/empty.pb.go index 29b2451dc443b..58f3dd273b55d 100644 --- a/generated/api/v1/empty.pb.go +++ b/generated/api/v1/empty.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/empty.proto diff --git a/generated/api/v1/empty.swagger.json b/generated/api/v1/empty.swagger.json index c12984dc079b7..a282263596360 100644 --- a/generated/api/v1/empty.swagger.json +++ b/generated/api/v1/empty.swagger.json @@ -39,7 +39,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" } } diff --git a/generated/api/v1/feature_flag_service.pb.go b/generated/api/v1/feature_flag_service.pb.go index 71964de453878..7054015e5656b 100644 --- a/generated/api/v1/feature_flag_service.pb.go +++ b/generated/api/v1/feature_flag_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/feature_flag_service.proto diff --git a/generated/api/v1/feature_flag_service.swagger.json b/generated/api/v1/feature_flag_service.swagger.json index 795e4e2532902..610610188d74a 100644 --- a/generated/api/v1/feature_flag_service.swagger.json +++ b/generated/api/v1/feature_flag_service.swagger.json @@ -6,7 +6,8 @@ }, "tags": [ { - "name": "FeatureFlagService" + "name": "FeatureFlagService", + "description": "FeatureFlagService retrieves information about feature flags." } ], "consumes": [ @@ -67,7 +68,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" }, "v1FeatureFlag": { diff --git a/generated/api/v1/group_service.pb.go b/generated/api/v1/group_service.pb.go index 79eee42cb6a1a..3a10dba133c19 100644 --- a/generated/api/v1/group_service.pb.go +++ b/generated/api/v1/group_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/group_service.proto diff --git a/generated/api/v1/group_service.pb.gw.go b/generated/api/v1/group_service.pb.gw.go index e1d807e755e26..4b73b238ea96b 100644 --- a/generated/api/v1/group_service.pb.gw.go +++ b/generated/api/v1/group_service.pb.gw.go @@ -43,15 +43,15 @@ func request_GroupService_GetGroups_0(ctx context.Context, marshaler runtime.Mar protoReq GetGroupsRequest metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_GroupService_GetGroups_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetGroups(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -78,15 +78,15 @@ func request_GroupService_GetGroup_0(ctx context.Context, marshaler runtime.Mars protoReq storage.GroupProperties metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_GroupService_GetGroup_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetGroup(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -170,15 +170,15 @@ func request_GroupService_UpdateGroup_0(ctx context.Context, marshaler runtime.M if err := marshaler.NewDecoder(req.Body).Decode(&protoReq.Group); err != nil && !errors.Is(err, io.EOF) { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_GroupService_UpdateGroup_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.UpdateGroup(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -208,15 +208,15 @@ func request_GroupService_DeleteGroup_0(ctx context.Context, marshaler runtime.M protoReq DeleteGroupRequest metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_GroupService_DeleteGroup_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.DeleteGroup(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } diff --git a/generated/api/v1/group_service.swagger.json b/generated/api/v1/group_service.swagger.json index f625fddcf5e00..2f03fb349dd68 100644 --- a/generated/api/v1/group_service.swagger.json +++ b/generated/api/v1/group_service.swagger.json @@ -338,7 +338,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" }, "storageGroup": { diff --git a/generated/api/v1/grpc_preference_service.pb.go b/generated/api/v1/grpc_preference_service.pb.go index 8e57e5ea24a42..4fa4723aa6ba1 100644 --- a/generated/api/v1/grpc_preference_service.pb.go +++ b/generated/api/v1/grpc_preference_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/grpc_preference_service.proto diff --git a/generated/api/v1/grpc_preference_service.swagger.json b/generated/api/v1/grpc_preference_service.swagger.json index dc3c236fd6264..32bdce78116ca 100644 --- a/generated/api/v1/grpc_preference_service.swagger.json +++ b/generated/api/v1/grpc_preference_service.swagger.json @@ -67,7 +67,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" }, "v1Preferences": { diff --git a/generated/api/v1/image_integration_service.pb.go b/generated/api/v1/image_integration_service.pb.go index 9d464ac7f4274..990fcb98237f5 100644 --- a/generated/api/v1/image_integration_service.pb.go +++ b/generated/api/v1/image_integration_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/image_integration_service.proto diff --git a/generated/api/v1/image_integration_service.pb.gw.go b/generated/api/v1/image_integration_service.pb.gw.go index 2d5fab0235a4b..1be46ef0ea676 100644 --- a/generated/api/v1/image_integration_service.pb.gw.go +++ b/generated/api/v1/image_integration_service.pb.gw.go @@ -42,9 +42,6 @@ func request_ImageIntegrationService_GetImageIntegration_0(ctx context.Context, metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -53,6 +50,9 @@ func request_ImageIntegrationService_GetImageIntegration_0(ctx context.Context, if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetImageIntegration(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -82,15 +82,15 @@ func request_ImageIntegrationService_GetImageIntegrations_0(ctx context.Context, protoReq GetImageIntegrationsRequest metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ImageIntegrationService_GetImageIntegrations_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetImageIntegrations(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -146,9 +146,6 @@ func request_ImageIntegrationService_PutImageIntegration_0(ctx context.Context, if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -157,6 +154,9 @@ func request_ImageIntegrationService_PutImageIntegration_0(ctx context.Context, if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.PutImageIntegration(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -215,9 +215,6 @@ func request_ImageIntegrationService_DeleteImageIntegration_0(ctx context.Contex metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -226,6 +223,9 @@ func request_ImageIntegrationService_DeleteImageIntegration_0(ctx context.Contex if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.DeleteImageIntegration(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -257,9 +257,6 @@ func request_ImageIntegrationService_UpdateImageIntegration_0(ctx context.Contex if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["config.id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "config.id") @@ -268,6 +265,9 @@ func request_ImageIntegrationService_UpdateImageIntegration_0(ctx context.Contex if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "config.id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.UpdateImageIntegration(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } diff --git a/generated/api/v1/image_integration_service.swagger.json b/generated/api/v1/image_integration_service.swagger.json index 1385bd1518eb2..57a2503c634a8 100644 --- a/generated/api/v1/image_integration_service.swagger.json +++ b/generated/api/v1/image_integration_service.swagger.json @@ -6,7 +6,8 @@ }, "tags": [ { - "name": "ImageIntegrationService" + "name": "ImageIntegrationService", + "description": "ImageIntegrationService APIs manage image registry and image scanner integration." } ], "consumes": [ @@ -473,7 +474,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" }, "storageAzureConfig": { diff --git a/generated/api/v1/image_service.pb.go b/generated/api/v1/image_service.pb.go index 5175ee8c5578b..debf248ab5af0 100644 --- a/generated/api/v1/image_service.pb.go +++ b/generated/api/v1/image_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/image_service.proto diff --git a/generated/api/v1/image_service.pb.gw.go b/generated/api/v1/image_service.pb.gw.go index b90487a79c248..bd047a05a4f2a 100644 --- a/generated/api/v1/image_service.pb.gw.go +++ b/generated/api/v1/image_service.pb.gw.go @@ -43,9 +43,6 @@ func request_ImageService_GetImage_0(ctx context.Context, marshaler runtime.Mars metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -60,6 +57,9 @@ func request_ImageService_GetImage_0(ctx context.Context, marshaler runtime.Mars if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ImageService_GetImage_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetImage(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -95,15 +95,15 @@ func request_ImageService_CountImages_0(ctx context.Context, marshaler runtime.M protoReq RawQuery metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ImageService_CountImages_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.CountImages(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -130,15 +130,15 @@ func request_ImageService_ListImages_0(ctx context.Context, marshaler runtime.Ma protoReq RawQuery metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ImageService_ListImages_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.ListImages(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -213,15 +213,15 @@ func request_ImageService_DeleteImages_0(ctx context.Context, marshaler runtime. protoReq DeleteImagesRequest metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ImageService_DeleteImages_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.DeleteImages(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -275,15 +275,15 @@ func request_ImageService_UnwatchImage_0(ctx context.Context, marshaler runtime. protoReq UnwatchImageRequest metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ImageService_UnwatchImage_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.UnwatchImage(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -331,15 +331,15 @@ func request_ImageService_ExportImages_0(ctx context.Context, marshaler runtime. protoReq ExportImageRequest metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ImageService_ExportImages_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } stream, err := client.ExportImages(ctx, &protoReq) if err != nil { return nil, metadata, err diff --git a/generated/api/v1/image_service.swagger.json b/generated/api/v1/image_service.swagger.json index 51036b8b504f4..8aeee71a817ba 100644 --- a/generated/api/v1/image_service.swagger.json +++ b/generated/api/v1/image_service.swagger.json @@ -6,7 +6,8 @@ }, "tags": [ { - "name": "ImageService" + "name": "ImageService", + "description": "ImageService APIs manages image metadata." } ], "consumes": [ @@ -591,7 +592,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" }, "storageAdvisory": { diff --git a/generated/api/v1/integration_health_service.pb.go b/generated/api/v1/integration_health_service.pb.go index d0bcf266f4728..f30cbde79c49f 100644 --- a/generated/api/v1/integration_health_service.pb.go +++ b/generated/api/v1/integration_health_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/integration_health_service.proto diff --git a/generated/api/v1/integration_health_service.pb.gw.go b/generated/api/v1/integration_health_service.pb.gw.go index 3e0b4c0bf7568..14e6b575d6a80 100644 --- a/generated/api/v1/integration_health_service.pb.gw.go +++ b/generated/api/v1/integration_health_service.pb.gw.go @@ -126,15 +126,15 @@ func request_IntegrationHealthService_GetVulnDefinitionsInfo_0(ctx context.Conte protoReq VulnDefinitionsInfoRequest metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_IntegrationHealthService_GetVulnDefinitionsInfo_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetVulnDefinitionsInfo(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } diff --git a/generated/api/v1/integration_health_service.swagger.json b/generated/api/v1/integration_health_service.swagger.json index 272471a6b5b69..7e652b60944d9 100644 --- a/generated/api/v1/integration_health_service.swagger.json +++ b/generated/api/v1/integration_health_service.swagger.json @@ -168,7 +168,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" }, "storageIntegrationHealth": { diff --git a/generated/api/v1/metadata_service.pb.go b/generated/api/v1/metadata_service.pb.go index a0c8c7b88991c..c472242c142a9 100644 --- a/generated/api/v1/metadata_service.pb.go +++ b/generated/api/v1/metadata_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/metadata_service.proto diff --git a/generated/api/v1/metadata_service.pb.gw.go b/generated/api/v1/metadata_service.pb.gw.go index 59807b91a4e92..30f10d2b48a76 100644 --- a/generated/api/v1/metadata_service.pb.gw.go +++ b/generated/api/v1/metadata_service.pb.gw.go @@ -63,15 +63,15 @@ func request_MetadataService_TLSChallenge_0(ctx context.Context, marshaler runti protoReq TLSChallengeRequest metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_MetadataService_TLSChallenge_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.TLSChallenge(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } diff --git a/generated/api/v1/metadata_service.swagger.json b/generated/api/v1/metadata_service.swagger.json index a5fd57814c65f..dfb0fea418eac 100644 --- a/generated/api/v1/metadata_service.swagger.json +++ b/generated/api/v1/metadata_service.swagger.json @@ -218,7 +218,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" }, "storageBackupInfo": { diff --git a/generated/api/v1/mitre_service.pb.go b/generated/api/v1/mitre_service.pb.go index d16ed7fb3822d..d1b698411d4b4 100644 --- a/generated/api/v1/mitre_service.pb.go +++ b/generated/api/v1/mitre_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/mitre_service.proto diff --git a/generated/api/v1/mitre_service.pb.gw.go b/generated/api/v1/mitre_service.pb.gw.go index 20d08c6b0f6f3..b28db6432449f 100644 --- a/generated/api/v1/mitre_service.pb.gw.go +++ b/generated/api/v1/mitre_service.pb.gw.go @@ -62,9 +62,6 @@ func request_MitreAttackService_GetMitreAttackVector_0(ctx context.Context, mars metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -73,6 +70,9 @@ func request_MitreAttackService_GetMitreAttackVector_0(ctx context.Context, mars if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetMitreAttackVector(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } diff --git a/generated/api/v1/mitre_service.swagger.json b/generated/api/v1/mitre_service.swagger.json index 79ccd8044ec9b..284489e8370c7 100644 --- a/generated/api/v1/mitre_service.swagger.json +++ b/generated/api/v1/mitre_service.swagger.json @@ -6,7 +6,8 @@ }, "tags": [ { - "name": "MitreAttackService" + "name": "MitreAttackService", + "description": "MitreAttackService can be used to retrieve information about MITRE ATT&CK matrix." } ], "consumes": [ @@ -99,7 +100,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" }, "storageMitreAttackVector": { diff --git a/generated/api/v1/namespace_service.pb.go b/generated/api/v1/namespace_service.pb.go index 9987f3a8e3b8d..479f1d2b05855 100644 --- a/generated/api/v1/namespace_service.pb.go +++ b/generated/api/v1/namespace_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/namespace_service.proto diff --git a/generated/api/v1/namespace_service.pb.gw.go b/generated/api/v1/namespace_service.pb.gw.go index 0234b1f9b1610..83f6246c36824 100644 --- a/generated/api/v1/namespace_service.pb.gw.go +++ b/generated/api/v1/namespace_service.pb.gw.go @@ -42,15 +42,15 @@ func request_NamespaceService_GetNamespaces_0(ctx context.Context, marshaler run protoReq GetNamespaceRequest metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_NamespaceService_GetNamespaces_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetNamespaces(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -76,9 +76,6 @@ func request_NamespaceService_GetNamespace_0(ctx context.Context, marshaler runt metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -87,6 +84,9 @@ func request_NamespaceService_GetNamespace_0(ctx context.Context, marshaler runt if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetNamespace(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } diff --git a/generated/api/v1/namespace_service.swagger.json b/generated/api/v1/namespace_service.swagger.json index 3574ad8fb145a..69c82ab3e9ddc 100644 --- a/generated/api/v1/namespace_service.swagger.json +++ b/generated/api/v1/namespace_service.swagger.json @@ -150,7 +150,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" }, "storageNamespaceMetadata": { diff --git a/generated/api/v1/network_baseline_service.pb.go b/generated/api/v1/network_baseline_service.pb.go index f7898440bda13..63cba2bb08abf 100644 --- a/generated/api/v1/network_baseline_service.pb.go +++ b/generated/api/v1/network_baseline_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/network_baseline_service.proto diff --git a/generated/api/v1/network_baseline_service.pb.gw.go b/generated/api/v1/network_baseline_service.pb.gw.go index b8351ab14126a..a5b1194bc3030 100644 --- a/generated/api/v1/network_baseline_service.pb.gw.go +++ b/generated/api/v1/network_baseline_service.pb.gw.go @@ -44,9 +44,6 @@ func request_NetworkBaselineService_GetNetworkBaselineStatusForFlows_0(ctx conte if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["deployment_id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "deployment_id") @@ -55,6 +52,9 @@ func request_NetworkBaselineService_GetNetworkBaselineStatusForFlows_0(ctx conte if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "deployment_id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetNetworkBaselineStatusForFlows(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -88,9 +88,6 @@ func request_NetworkBaselineService_GetNetworkBaselineStatusForExternalFlows_0(c metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["deployment_id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "deployment_id") @@ -105,6 +102,9 @@ func request_NetworkBaselineService_GetNetworkBaselineStatusForExternalFlows_0(c if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_NetworkBaselineService_GetNetworkBaselineStatusForExternalFlows_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetNetworkBaselineStatusForExternalFlows(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -139,9 +139,6 @@ func request_NetworkBaselineService_GetNetworkBaseline_0(ctx context.Context, ma metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -150,6 +147,9 @@ func request_NetworkBaselineService_GetNetworkBaseline_0(ctx context.Context, ma if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetNetworkBaseline(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -181,9 +181,6 @@ func request_NetworkBaselineService_ModifyBaselineStatusForPeers_0(ctx context.C if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["deployment_id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "deployment_id") @@ -192,6 +189,9 @@ func request_NetworkBaselineService_ModifyBaselineStatusForPeers_0(ctx context.C if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "deployment_id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.ModifyBaselineStatusForPeers(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -226,9 +226,6 @@ func request_NetworkBaselineService_LockNetworkBaseline_0(ctx context.Context, m if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -237,6 +234,9 @@ func request_NetworkBaselineService_LockNetworkBaseline_0(ctx context.Context, m if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.LockNetworkBaseline(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -271,9 +271,6 @@ func request_NetworkBaselineService_UnlockNetworkBaseline_0(ctx context.Context, if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -282,6 +279,9 @@ func request_NetworkBaselineService_UnlockNetworkBaseline_0(ctx context.Context, if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.UnlockNetworkBaseline(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } diff --git a/generated/api/v1/network_baseline_service.swagger.json b/generated/api/v1/network_baseline_service.swagger.json index 38d7a0bb1d716..afdf90d8201de 100644 --- a/generated/api/v1/network_baseline_service.swagger.json +++ b/generated/api/v1/network_baseline_service.swagger.json @@ -398,7 +398,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" }, "storageL4Protocol": { @@ -531,7 +531,7 @@ "INTERNAL_ENTITIES" ], "default": "UNKNOWN_TYPE", - "title": "- INTERNAL_ENTITIES: INTERNAL_ENTITIES is for grouping all internal entities under a single network graph node" + "description": "- INTERNAL_ENTITIES: INTERNAL_ENTITIES is for grouping all internal entities under a single network graph node" }, "storageNetworkEntityScope": { "type": "object", @@ -627,7 +627,7 @@ "ANOMALOUS" ], "default": "BASELINE", - "title": "Status of this peer connection. As of now we only have two statuses:\n - BASELINE: the connection is in the current deployment baseline\n - ANOMALOUS: the connection is not recognized by the current deployment baseline" + "description": "Status of this peer connection. As of now we only have two statuses:\n - BASELINE: the connection is in the current deployment baseline\n - ANOMALOUS: the connection is not recognized by the current deployment baseline" }, "v1NetworkBaselineStatusPeer": { "type": "object", diff --git a/generated/api/v1/network_graph_service.pb.go b/generated/api/v1/network_graph_service.pb.go index 561bb0d436488..14675ce92dad9 100644 --- a/generated/api/v1/network_graph_service.pb.go +++ b/generated/api/v1/network_graph_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/network_graph_service.proto diff --git a/generated/api/v1/network_graph_service.pb.gw.go b/generated/api/v1/network_graph_service.pb.gw.go index f4854fbfcd6c8..7fbc8d1069b0d 100644 --- a/generated/api/v1/network_graph_service.pb.gw.go +++ b/generated/api/v1/network_graph_service.pb.gw.go @@ -43,9 +43,6 @@ func request_NetworkGraphService_GetNetworkGraph_0(ctx context.Context, marshale metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["cluster_id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "cluster_id") @@ -60,6 +57,9 @@ func request_NetworkGraphService_GetNetworkGraph_0(ctx context.Context, marshale if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_NetworkGraphService_GetNetworkGraph_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetNetworkGraph(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -96,9 +96,6 @@ func request_NetworkGraphService_GetExternalNetworkEntities_0(ctx context.Contex metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["cluster_id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "cluster_id") @@ -113,6 +110,9 @@ func request_NetworkGraphService_GetExternalNetworkEntities_0(ctx context.Contex if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_NetworkGraphService_GetExternalNetworkEntities_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetExternalNetworkEntities(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -149,9 +149,6 @@ func request_NetworkGraphService_GetExternalNetworkFlows_0(ctx context.Context, metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["cluster_id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "cluster_id") @@ -174,6 +171,9 @@ func request_NetworkGraphService_GetExternalNetworkFlows_0(ctx context.Context, if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_NetworkGraphService_GetExternalNetworkFlows_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetExternalNetworkFlows(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -218,9 +218,6 @@ func request_NetworkGraphService_GetExternalNetworkFlowsMetadata_0(ctx context.C metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["cluster_id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "cluster_id") @@ -235,6 +232,9 @@ func request_NetworkGraphService_GetExternalNetworkFlowsMetadata_0(ctx context.C if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_NetworkGraphService_GetExternalNetworkFlowsMetadata_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetExternalNetworkFlowsMetadata(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -272,9 +272,6 @@ func request_NetworkGraphService_CreateExternalNetworkEntity_0(ctx context.Conte if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["cluster_id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "cluster_id") @@ -283,6 +280,9 @@ func request_NetworkGraphService_CreateExternalNetworkEntity_0(ctx context.Conte if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "cluster_id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.CreateExternalNetworkEntity(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -317,9 +317,6 @@ func request_NetworkGraphService_PatchExternalNetworkEntity_0(ctx context.Contex if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -328,6 +325,9 @@ func request_NetworkGraphService_PatchExternalNetworkEntity_0(ctx context.Contex if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.PatchExternalNetworkEntity(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -359,9 +359,6 @@ func request_NetworkGraphService_DeleteExternalNetworkEntity_0(ctx context.Conte metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -370,6 +367,9 @@ func request_NetworkGraphService_DeleteExternalNetworkEntity_0(ctx context.Conte if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.DeleteExternalNetworkEntity(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } diff --git a/generated/api/v1/network_graph_service.swagger.json b/generated/api/v1/network_graph_service.swagger.json index 841f6bd97449b..752da378f7964 100644 --- a/generated/api/v1/network_graph_service.swagger.json +++ b/generated/api/v1/network_graph_service.swagger.json @@ -547,7 +547,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" }, "storageL4Protocol": { @@ -603,7 +603,7 @@ "INTERNAL_ENTITIES" ], "default": "UNKNOWN_TYPE", - "title": "- INTERNAL_ENTITIES: INTERNAL_ENTITIES is for grouping all internal entities under a single network graph node" + "description": "- INTERNAL_ENTITIES: INTERNAL_ENTITIES is for grouping all internal entities under a single network graph node" }, "storageNetworkEntityScope": { "type": "object", diff --git a/generated/api/v1/network_policy_service.pb.go b/generated/api/v1/network_policy_service.pb.go index 134a03b6f236e..1bb454e9459f5 100644 --- a/generated/api/v1/network_policy_service.pb.go +++ b/generated/api/v1/network_policy_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/network_policy_service.proto diff --git a/generated/api/v1/network_policy_service.pb.gw.go b/generated/api/v1/network_policy_service.pb.gw.go index c472d6ec1006f..5575bdd5119b1 100644 --- a/generated/api/v1/network_policy_service.pb.gw.go +++ b/generated/api/v1/network_policy_service.pb.gw.go @@ -41,9 +41,6 @@ func request_NetworkPolicyService_GetNetworkPolicy_0(ctx context.Context, marsha metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -52,6 +49,9 @@ func request_NetworkPolicyService_GetNetworkPolicy_0(ctx context.Context, marsha if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetNetworkPolicy(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -81,15 +81,15 @@ func request_NetworkPolicyService_GetNetworkPolicies_0(ctx context.Context, mars protoReq GetNetworkPoliciesRequest metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_NetworkPolicyService_GetNetworkPolicies_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetNetworkPolicies(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -117,9 +117,6 @@ func request_NetworkPolicyService_GetNetworkGraph_0(ctx context.Context, marshal metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["cluster_id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "cluster_id") @@ -134,6 +131,9 @@ func request_NetworkPolicyService_GetNetworkGraph_0(ctx context.Context, marshal if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_NetworkPolicyService_GetNetworkGraph_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetNetworkGraph(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -169,15 +169,15 @@ func request_NetworkPolicyService_GetNetworkGraphEpoch_0(ctx context.Context, ma protoReq GetNetworkGraphEpochRequest metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_NetworkPolicyService_GetNetworkGraphEpoch_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetNetworkGraphEpoch(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -206,9 +206,6 @@ func request_NetworkPolicyService_ApplyNetworkPolicy_0(ctx context.Context, mars if err := marshaler.NewDecoder(req.Body).Decode(&protoReq.Modification); err != nil && !errors.Is(err, io.EOF) { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["cluster_id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "cluster_id") @@ -217,6 +214,9 @@ func request_NetworkPolicyService_ApplyNetworkPolicy_0(ctx context.Context, mars if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "cluster_id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.ApplyNetworkPolicy(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -248,9 +248,6 @@ func request_NetworkPolicyService_GetUndoModification_0(ctx context.Context, mar metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["cluster_id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "cluster_id") @@ -259,6 +256,9 @@ func request_NetworkPolicyService_GetUndoModification_0(ctx context.Context, mar if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "cluster_id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetUndoModification(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -292,9 +292,6 @@ func request_NetworkPolicyService_SimulateNetworkGraph_0(ctx context.Context, ma if err := marshaler.NewDecoder(req.Body).Decode(&protoReq.Modification); err != nil && !errors.Is(err, io.EOF) { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["cluster_id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "cluster_id") @@ -309,6 +306,9 @@ func request_NetworkPolicyService_SimulateNetworkGraph_0(ctx context.Context, ma if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_NetworkPolicyService_SimulateNetworkGraph_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.SimulateNetworkGraph(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -351,9 +351,6 @@ func request_NetworkPolicyService_SendNetworkPolicyYAML_0(ctx context.Context, m if err := marshaler.NewDecoder(req.Body).Decode(&protoReq.Modification); err != nil && !errors.Is(err, io.EOF) { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["cluster_id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "cluster_id") @@ -368,6 +365,9 @@ func request_NetworkPolicyService_SendNetworkPolicyYAML_0(ctx context.Context, m if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_NetworkPolicyService_SendNetworkPolicyYAML_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.SendNetworkPolicyYAML(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -407,9 +407,6 @@ func request_NetworkPolicyService_GenerateNetworkPolicies_0(ctx context.Context, metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["cluster_id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "cluster_id") @@ -424,6 +421,9 @@ func request_NetworkPolicyService_GenerateNetworkPolicies_0(ctx context.Context, if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_NetworkPolicyService_GenerateNetworkPolicies_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GenerateNetworkPolicies(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -461,9 +461,6 @@ func request_NetworkPolicyService_GetBaselineGeneratedNetworkPolicyForDeployment if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["deployment_id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "deployment_id") @@ -472,6 +469,9 @@ func request_NetworkPolicyService_GetBaselineGeneratedNetworkPolicyForDeployment if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "deployment_id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetBaselineGeneratedNetworkPolicyForDeployment(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -503,9 +503,6 @@ func request_NetworkPolicyService_GetAllowedPeersFromCurrentPolicyForDeployment_ metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -514,6 +511,9 @@ func request_NetworkPolicyService_GetAllowedPeersFromCurrentPolicyForDeployment_ if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetAllowedPeersFromCurrentPolicyForDeployment(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -545,9 +545,6 @@ func request_NetworkPolicyService_ApplyNetworkPolicyYamlForDeployment_0(ctx cont if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["deployment_id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "deployment_id") @@ -556,6 +553,9 @@ func request_NetworkPolicyService_ApplyNetworkPolicyYamlForDeployment_0(ctx cont if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "deployment_id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.ApplyNetworkPolicyYamlForDeployment(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -587,9 +587,6 @@ func request_NetworkPolicyService_GetUndoModificationForDeployment_0(ctx context metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -598,6 +595,9 @@ func request_NetworkPolicyService_GetUndoModificationForDeployment_0(ctx context if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetUndoModificationForDeployment(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -626,9 +626,6 @@ func request_NetworkPolicyService_GetDiffFlowsBetweenPolicyAndBaselineForDeploym metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -637,6 +634,9 @@ func request_NetworkPolicyService_GetDiffFlowsBetweenPolicyAndBaselineForDeploym if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetDiffFlowsBetweenPolicyAndBaselineForDeployment(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -665,9 +665,6 @@ func request_NetworkPolicyService_GetDiffFlowsFromUndoModificationForDeployment_ metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -676,6 +673,9 @@ func request_NetworkPolicyService_GetDiffFlowsFromUndoModificationForDeployment_ if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetDiffFlowsFromUndoModificationForDeployment(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } diff --git a/generated/api/v1/network_policy_service.swagger.json b/generated/api/v1/network_policy_service.swagger.json index 6cae046bb1aa1..604a00d35a6f2 100644 --- a/generated/api/v1/network_policy_service.swagger.json +++ b/generated/api/v1/network_policy_service.swagger.json @@ -746,7 +746,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" }, "storageIPBlock": { @@ -843,7 +843,7 @@ "INTERNAL_ENTITIES" ], "default": "UNKNOWN_TYPE", - "title": "- INTERNAL_ENTITIES: INTERNAL_ENTITIES is for grouping all internal entities under a single network graph node" + "description": "- INTERNAL_ENTITIES: INTERNAL_ENTITIES is for grouping all internal entities under a single network graph node" }, "storageNetworkPolicy": { "type": "object", diff --git a/generated/api/v1/node_service.pb.go b/generated/api/v1/node_service.pb.go index c4d46819af44a..d4e6d727974aa 100644 --- a/generated/api/v1/node_service.pb.go +++ b/generated/api/v1/node_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/node_service.proto diff --git a/generated/api/v1/node_service.pb.gw.go b/generated/api/v1/node_service.pb.gw.go index 02ab873b2bdf9..59afbd7b8a3e8 100644 --- a/generated/api/v1/node_service.pb.gw.go +++ b/generated/api/v1/node_service.pb.gw.go @@ -41,9 +41,6 @@ func request_NodeService_ListNodes_0(ctx context.Context, marshaler runtime.Mars metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["cluster_id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "cluster_id") @@ -52,6 +49,9 @@ func request_NodeService_ListNodes_0(ctx context.Context, marshaler runtime.Mars if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "cluster_id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.ListNodes(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -80,9 +80,6 @@ func request_NodeService_GetNode_0(ctx context.Context, marshaler runtime.Marsha metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["cluster_id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "cluster_id") @@ -99,6 +96,9 @@ func request_NodeService_GetNode_0(ctx context.Context, marshaler runtime.Marsha if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "node_id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetNode(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -136,15 +136,15 @@ func request_NodeService_ExportNodes_0(ctx context.Context, marshaler runtime.Ma protoReq ExportNodeRequest metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_NodeService_ExportNodes_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } stream, err := client.ExportNodes(ctx, &protoReq) if err != nil { return nil, metadata, err diff --git a/generated/api/v1/node_service.swagger.json b/generated/api/v1/node_service.swagger.json index a50f3bc54ff87..474d079d9d32d 100644 --- a/generated/api/v1/node_service.swagger.json +++ b/generated/api/v1/node_service.swagger.json @@ -6,7 +6,8 @@ }, "tags": [ { - "name": "NodeService" + "name": "NodeService", + "description": "storage.Node represents information about a node in the cluster." } ], "consumes": [ @@ -234,7 +235,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" }, "storageAdvisory": { diff --git a/generated/api/v1/notifications.pb.go b/generated/api/v1/notifications.pb.go index d1e211b7ca879..3793361470541 100644 --- a/generated/api/v1/notifications.pb.go +++ b/generated/api/v1/notifications.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/notifications.proto diff --git a/generated/api/v1/notifications.swagger.json b/generated/api/v1/notifications.swagger.json index bf06cde08ea7f..cab5e382a0d12 100644 --- a/generated/api/v1/notifications.swagger.json +++ b/generated/api/v1/notifications.swagger.json @@ -39,7 +39,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" } } diff --git a/generated/api/v1/notifier_service.pb.go b/generated/api/v1/notifier_service.pb.go index 17f3804e00d72..c49f9e1b2ab43 100644 --- a/generated/api/v1/notifier_service.pb.go +++ b/generated/api/v1/notifier_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/notifier_service.proto diff --git a/generated/api/v1/notifier_service.pb.gw.go b/generated/api/v1/notifier_service.pb.gw.go index a6efe55dc4d07..efc7340a7a505 100644 --- a/generated/api/v1/notifier_service.pb.gw.go +++ b/generated/api/v1/notifier_service.pb.gw.go @@ -42,9 +42,6 @@ func request_NotifierService_GetNotifier_0(ctx context.Context, marshaler runtim metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -53,6 +50,9 @@ func request_NotifierService_GetNotifier_0(ctx context.Context, marshaler runtim if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetNotifier(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -105,9 +105,6 @@ func request_NotifierService_PutNotifier_0(ctx context.Context, marshaler runtim if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -116,6 +113,9 @@ func request_NotifierService_PutNotifier_0(ctx context.Context, marshaler runtim if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.PutNotifier(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -203,9 +203,6 @@ func request_NotifierService_DeleteNotifier_0(ctx context.Context, marshaler run metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -220,6 +217,9 @@ func request_NotifierService_DeleteNotifier_0(ctx context.Context, marshaler run if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_NotifierService_DeleteNotifier_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.DeleteNotifier(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -257,9 +257,6 @@ func request_NotifierService_UpdateNotifier_0(ctx context.Context, marshaler run if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["notifier.id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "notifier.id") @@ -268,6 +265,9 @@ func request_NotifierService_UpdateNotifier_0(ctx context.Context, marshaler run if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "notifier.id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.UpdateNotifier(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } diff --git a/generated/api/v1/notifier_service.swagger.json b/generated/api/v1/notifier_service.swagger.json index 2f8c1b5efbed0..2fec9119a4568 100644 --- a/generated/api/v1/notifier_service.swagger.json +++ b/generated/api/v1/notifier_service.swagger.json @@ -519,7 +519,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" }, "storageAWSSecurityHub": { diff --git a/generated/api/v1/pagination.pb.go b/generated/api/v1/pagination.pb.go index 67fcced57bd45..673948679eab8 100644 --- a/generated/api/v1/pagination.pb.go +++ b/generated/api/v1/pagination.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/pagination.proto diff --git a/generated/api/v1/pagination.swagger.json b/generated/api/v1/pagination.swagger.json index be9172d3eac84..1f866d13617dc 100644 --- a/generated/api/v1/pagination.swagger.json +++ b/generated/api/v1/pagination.swagger.json @@ -39,7 +39,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" } } diff --git a/generated/api/v1/ping_service.pb.go b/generated/api/v1/ping_service.pb.go index bff82ac06521c..a82b6d3e58ea7 100644 --- a/generated/api/v1/ping_service.pb.go +++ b/generated/api/v1/ping_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/ping_service.proto diff --git a/generated/api/v1/ping_service.swagger.json b/generated/api/v1/ping_service.swagger.json index 192bd11d5784b..9b5be2ed6f396 100644 --- a/generated/api/v1/ping_service.swagger.json +++ b/generated/api/v1/ping_service.swagger.json @@ -67,7 +67,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" }, "v1PongMessage": { diff --git a/generated/api/v1/pod_service.pb.go b/generated/api/v1/pod_service.pb.go index 4908e85d853a3..3e7d8429e9531 100644 --- a/generated/api/v1/pod_service.pb.go +++ b/generated/api/v1/pod_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/pod_service.proto diff --git a/generated/api/v1/pod_service.pb.gw.go b/generated/api/v1/pod_service.pb.gw.go index 39b12fc48f088..2ce4c45231940 100644 --- a/generated/api/v1/pod_service.pb.gw.go +++ b/generated/api/v1/pod_service.pb.gw.go @@ -42,15 +42,15 @@ func request_PodService_GetPods_0(ctx context.Context, marshaler runtime.Marshal protoReq RawQuery metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_PodService_GetPods_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetPods(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -77,15 +77,15 @@ func request_PodService_ExportPods_0(ctx context.Context, marshaler runtime.Mars protoReq ExportPodRequest metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_PodService_ExportPods_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } stream, err := client.ExportPods(ctx, &protoReq) if err != nil { return nil, metadata, err diff --git a/generated/api/v1/pod_service.swagger.json b/generated/api/v1/pod_service.swagger.json index cb2ff3dfc3dd6..16fa308fc51e5 100644 --- a/generated/api/v1/pod_service.swagger.json +++ b/generated/api/v1/pod_service.swagger.json @@ -6,7 +6,8 @@ }, "tags": [ { - "name": "PodService" + "name": "PodService", + "description": "PodService APIs can be used to manage pods." } ], "consumes": [ @@ -179,7 +180,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" }, "storageContainerInstance": { diff --git a/generated/api/v1/policy_category_service.pb.go b/generated/api/v1/policy_category_service.pb.go index 3243cb76f0ce5..a02160b93036c 100644 --- a/generated/api/v1/policy_category_service.pb.go +++ b/generated/api/v1/policy_category_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/policy_category_service.proto diff --git a/generated/api/v1/policy_category_service.pb.gw.go b/generated/api/v1/policy_category_service.pb.gw.go index 86e759ec0dbdc..a5a74a2474bfb 100644 --- a/generated/api/v1/policy_category_service.pb.gw.go +++ b/generated/api/v1/policy_category_service.pb.gw.go @@ -41,9 +41,6 @@ func request_PolicyCategoryService_GetPolicyCategory_0(ctx context.Context, mars metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -52,6 +49,9 @@ func request_PolicyCategoryService_GetPolicyCategory_0(ctx context.Context, mars if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetPolicyCategory(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -81,15 +81,15 @@ func request_PolicyCategoryService_GetPolicyCategories_0(ctx context.Context, ma protoReq RawQuery metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_PolicyCategoryService_GetPolicyCategories_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetPolicyCategories(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -169,9 +169,6 @@ func request_PolicyCategoryService_DeletePolicyCategory_0(ctx context.Context, m metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -180,6 +177,9 @@ func request_PolicyCategoryService_DeletePolicyCategory_0(ctx context.Context, m if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.DeletePolicyCategory(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } diff --git a/generated/api/v1/policy_category_service.swagger.json b/generated/api/v1/policy_category_service.swagger.json index 7c631508e36af..190c4e8c237cf 100644 --- a/generated/api/v1/policy_category_service.swagger.json +++ b/generated/api/v1/policy_category_service.swagger.json @@ -6,7 +6,8 @@ }, "tags": [ { - "name": "PolicyCategoryService" + "name": "PolicyCategoryService", + "description": "PolicyCategoryService APIs can be used to manage policy categories." } ], "consumes": [ @@ -243,7 +244,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" }, "v1AggregateBy": { diff --git a/generated/api/v1/policy_service.pb.go b/generated/api/v1/policy_service.pb.go index d650c2722cc4f..503c54a5edf39 100644 --- a/generated/api/v1/policy_service.pb.go +++ b/generated/api/v1/policy_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/policy_service.proto diff --git a/generated/api/v1/policy_service.pb.gw.go b/generated/api/v1/policy_service.pb.gw.go index 2477addfe0469..0d08aab492beb 100644 --- a/generated/api/v1/policy_service.pb.gw.go +++ b/generated/api/v1/policy_service.pb.gw.go @@ -42,9 +42,6 @@ func request_PolicyService_GetPolicy_0(ctx context.Context, marshaler runtime.Ma metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -53,6 +50,9 @@ func request_PolicyService_GetPolicy_0(ctx context.Context, marshaler runtime.Ma if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetPolicy(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -83,9 +83,6 @@ func request_PolicyService_GetPolicyMitreVectors_0(ctx context.Context, marshale metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -100,6 +97,9 @@ func request_PolicyService_GetPolicyMitreVectors_0(ctx context.Context, marshale if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_PolicyService_GetPolicyMitreVectors_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetPolicyMitreVectors(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -135,15 +135,15 @@ func request_PolicyService_ListPolicies_0(ctx context.Context, marshaler runtime protoReq RawQuery metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_PolicyService_ListPolicies_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.ListPolicies(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -173,15 +173,15 @@ func request_PolicyService_PostPolicy_0(ctx context.Context, marshaler runtime.M if err := marshaler.NewDecoder(req.Body).Decode(&protoReq.Policy); err != nil && !errors.Is(err, io.EOF) { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_PolicyService_PostPolicy_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.PostPolicy(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -213,9 +213,6 @@ func request_PolicyService_PutPolicy_0(ctx context.Context, marshaler runtime.Ma if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -224,6 +221,9 @@ func request_PolicyService_PutPolicy_0(ctx context.Context, marshaler runtime.Ma if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.PutPolicy(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -258,9 +258,6 @@ func request_PolicyService_PatchPolicy_0(ctx context.Context, marshaler runtime. if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -269,6 +266,9 @@ func request_PolicyService_PatchPolicy_0(ctx context.Context, marshaler runtime. if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.PatchPolicy(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -300,9 +300,6 @@ func request_PolicyService_DeletePolicy_0(ctx context.Context, marshaler runtime metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -311,6 +308,9 @@ func request_PolicyService_DeletePolicy_0(ctx context.Context, marshaler runtime if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.DeletePolicy(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -342,9 +342,6 @@ func request_PolicyService_EnableDisablePolicyNotification_0(ctx context.Context if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["policy_id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "policy_id") @@ -353,6 +350,9 @@ func request_PolicyService_EnableDisablePolicyNotification_0(ctx context.Context if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "policy_id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.EnableDisablePolicyNotification(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -459,9 +459,6 @@ func request_PolicyService_QueryDryRunJobStatus_0(ctx context.Context, marshaler metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["job_id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "job_id") @@ -470,6 +467,9 @@ func request_PolicyService_QueryDryRunJobStatus_0(ctx context.Context, marshaler if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "job_id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.QueryDryRunJobStatus(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -498,9 +498,6 @@ func request_PolicyService_CancelDryRunJob_0(ctx context.Context, marshaler runt metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["job_id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "job_id") @@ -509,6 +506,9 @@ func request_PolicyService_CancelDryRunJob_0(ctx context.Context, marshaler runt if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "job_id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.CancelDryRunJob(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } diff --git a/generated/api/v1/policy_service.swagger.json b/generated/api/v1/policy_service.swagger.json index faeb58adf12cf..00e2440771e1b 100644 --- a/generated/api/v1/policy_service.swagger.json +++ b/generated/api/v1/policy_service.swagger.json @@ -6,7 +6,8 @@ }, "tags": [ { - "name": "PolicyService" + "name": "PolicyService", + "description": "PolicyService APIs can be used to manage policies." } ], "consumes": [ @@ -634,6 +635,18 @@ } } }, + "ExclusionExcludeByKind": { + "type": "object", + "properties": { + "kinds": { + "type": "array", + "items": { + "$ref": "#/definitions/ExclusionWorkloadKind" + } + } + }, + "description": "ExcludeByKind excludes all workloads of the selected Kubernetes kinds." + }, "ExclusionImage": { "type": "object", "properties": { @@ -642,6 +655,16 @@ } } }, + "ExclusionWorkloadKind": { + "type": "string", + "enum": [ + "WORKLOAD_KIND_UNSPECIFIED", + "CRON_JOB", + "JOB" + ], + "default": "WORKLOAD_KIND_UNSPECIFIED", + "description": "WorkloadKind is a Kubernetes workload kind that can be excluded from a policy in bulk." + }, "PolicyMitreAttackVectors": { "type": "object", "properties": { @@ -724,7 +747,7 @@ "type": "object", "$ref": "#/definitions/storageExclusion" }, - "description": "Define deployments or images that should be excluded from this policy." + "description": "Define deployments, images, or workload kinds that should be excluded from this policy." }, "scope": { "type": "array", @@ -835,7 +858,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" }, "storageBooleanOperator": { @@ -897,15 +920,18 @@ "name": { "type": "string" }, - "deployment": { - "$ref": "#/definitions/ExclusionDeployment" - }, "image": { "$ref": "#/definitions/ExclusionImage" }, "expiration": { "type": "string", "format": "date-time" + }, + "deployment": { + "$ref": "#/definitions/ExclusionDeployment" + }, + "excludeByKind": { + "$ref": "#/definitions/ExclusionExcludeByKind" } } }, @@ -1071,7 +1097,7 @@ "type": "object", "$ref": "#/definitions/storageExclusion" }, - "description": "Define deployments or images that should be excluded from this policy." + "description": "Define deployments, images, or workload kinds that should be excluded from this policy." }, "scope": { "type": "array", diff --git a/generated/api/v1/probe_upload_service.pb.go b/generated/api/v1/probe_upload_service.pb.go index 46a14a15bc233..a38038150ccba 100644 --- a/generated/api/v1/probe_upload_service.pb.go +++ b/generated/api/v1/probe_upload_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/probe_upload_service.proto diff --git a/generated/api/v1/probe_upload_service.pb.gw.go b/generated/api/v1/probe_upload_service.pb.gw.go index f35454c7cde77..526b315d8a40e 100644 --- a/generated/api/v1/probe_upload_service.pb.gw.go +++ b/generated/api/v1/probe_upload_service.pb.gw.go @@ -42,15 +42,15 @@ func request_ProbeUploadService_GetExistingProbes_0(ctx context.Context, marshal protoReq GetExistingProbesRequest metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ProbeUploadService_GetExistingProbes_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetExistingProbes(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } diff --git a/generated/api/v1/probe_upload_service.swagger.json b/generated/api/v1/probe_upload_service.swagger.json index 9a6a0c138ca85..5b651003fa58b 100644 --- a/generated/api/v1/probe_upload_service.swagger.json +++ b/generated/api/v1/probe_upload_service.swagger.json @@ -79,7 +79,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" }, "v1GetExistingProbesResponse": { diff --git a/generated/api/v1/process_baseline_service.pb.go b/generated/api/v1/process_baseline_service.pb.go index e078981337d5a..40c8f1b92aa6c 100644 --- a/generated/api/v1/process_baseline_service.pb.go +++ b/generated/api/v1/process_baseline_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/process_baseline_service.proto diff --git a/generated/api/v1/process_baseline_service.pb.gw.go b/generated/api/v1/process_baseline_service.pb.gw.go index bd4fa797522a9..bf2f96e5b64d5 100644 --- a/generated/api/v1/process_baseline_service.pb.gw.go +++ b/generated/api/v1/process_baseline_service.pb.gw.go @@ -42,15 +42,15 @@ func request_ProcessBaselineService_GetProcessBaseline_0(ctx context.Context, ma protoReq GetProcessBaselineRequest metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ProcessBaselineService_GetProcessBaseline_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetProcessBaseline(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -185,15 +185,15 @@ func request_ProcessBaselineService_DeleteProcessBaselines_0(ctx context.Context protoReq DeleteProcessBaselinesRequest metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ProcessBaselineService_DeleteProcessBaselines_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.DeleteProcessBaselines(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } diff --git a/generated/api/v1/process_baseline_service.swagger.json b/generated/api/v1/process_baseline_service.swagger.json index 8ab759940ec00..75115c2d0e385 100644 --- a/generated/api/v1/process_baseline_service.swagger.json +++ b/generated/api/v1/process_baseline_service.swagger.json @@ -6,7 +6,8 @@ }, "tags": [ { - "name": "ProcessBaselineService" + "name": "ProcessBaselineService", + "description": "`ProcessBaselineService` APIs can be used to manage process baselines." } ], "consumes": [ @@ -262,7 +263,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" }, "storageBaselineElement": { diff --git a/generated/api/v1/process_listening_on_port_service.pb.go b/generated/api/v1/process_listening_on_port_service.pb.go index b028c17d133b8..b7773df360138 100644 --- a/generated/api/v1/process_listening_on_port_service.pb.go +++ b/generated/api/v1/process_listening_on_port_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/process_listening_on_port_service.proto diff --git a/generated/api/v1/process_listening_on_port_service.pb.gw.go b/generated/api/v1/process_listening_on_port_service.pb.gw.go index ad3a52474e845..abf8f51636f0c 100644 --- a/generated/api/v1/process_listening_on_port_service.pb.gw.go +++ b/generated/api/v1/process_listening_on_port_service.pb.gw.go @@ -43,9 +43,6 @@ func request_ListeningEndpointsService_GetListeningEndpoints_0(ctx context.Conte metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["deployment_id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "deployment_id") @@ -60,6 +57,9 @@ func request_ListeningEndpointsService_GetListeningEndpoints_0(ctx context.Conte if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ListeningEndpointsService_GetListeningEndpoints_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetListeningEndpoints(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } diff --git a/generated/api/v1/process_listening_on_port_service.swagger.json b/generated/api/v1/process_listening_on_port_service.swagger.json index 7953707c2f48a..d219f1585f7d0 100644 --- a/generated/api/v1/process_listening_on_port_service.swagger.json +++ b/generated/api/v1/process_listening_on_port_service.swagger.json @@ -6,7 +6,8 @@ }, "tags": [ { - "name": "ListeningEndpointsService" + "name": "ListeningEndpointsService", + "description": "ListeningEndpointsService API can be used to list listening endpoints and the processes that opened them." } ], "consumes": [ @@ -145,7 +146,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" }, "storageL4Protocol": { diff --git a/generated/api/v1/process_service.pb.go b/generated/api/v1/process_service.pb.go index 031690f9996fd..7dbd8e40ae252 100644 --- a/generated/api/v1/process_service.pb.go +++ b/generated/api/v1/process_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/process_service.proto diff --git a/generated/api/v1/process_service.pb.gw.go b/generated/api/v1/process_service.pb.gw.go index f25925019271f..82447c5165500 100644 --- a/generated/api/v1/process_service.pb.gw.go +++ b/generated/api/v1/process_service.pb.gw.go @@ -42,15 +42,15 @@ func request_ProcessService_CountProcesses_0(ctx context.Context, marshaler runt protoReq RawQuery metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ProcessService_CountProcesses_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.CountProcesses(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -76,9 +76,6 @@ func request_ProcessService_GetProcessesByDeployment_0(ctx context.Context, mars metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["deployment_id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "deployment_id") @@ -87,6 +84,9 @@ func request_ProcessService_GetProcessesByDeployment_0(ctx context.Context, mars if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "deployment_id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetProcessesByDeployment(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -115,9 +115,6 @@ func request_ProcessService_GetGroupedProcessByDeployment_0(ctx context.Context, metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["deployment_id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "deployment_id") @@ -126,6 +123,9 @@ func request_ProcessService_GetGroupedProcessByDeployment_0(ctx context.Context, if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "deployment_id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetGroupedProcessByDeployment(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -154,9 +154,6 @@ func request_ProcessService_GetGroupedProcessByDeploymentAndContainer_0(ctx cont metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["deployment_id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "deployment_id") @@ -165,6 +162,9 @@ func request_ProcessService_GetGroupedProcessByDeploymentAndContainer_0(ctx cont if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "deployment_id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetGroupedProcessByDeploymentAndContainer(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } diff --git a/generated/api/v1/process_service.swagger.json b/generated/api/v1/process_service.swagger.json index c517bfb0d3de2..fbeab6240543f 100644 --- a/generated/api/v1/process_service.swagger.json +++ b/generated/api/v1/process_service.swagger.json @@ -6,7 +6,8 @@ }, "tags": [ { - "name": "ProcessService" + "name": "ProcessService", + "description": "ProcessService APIs can be used to list processes executed in deployments." } ], "consumes": [ @@ -226,7 +227,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" }, "storageProcessIndicator": { diff --git a/generated/api/v1/rbac_service.pb.go b/generated/api/v1/rbac_service.pb.go index 742ade005a9fe..09bc326a11fe2 100644 --- a/generated/api/v1/rbac_service.pb.go +++ b/generated/api/v1/rbac_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/rbac_service.proto diff --git a/generated/api/v1/rbac_service.pb.gw.go b/generated/api/v1/rbac_service.pb.gw.go index 83e52643eb37b..e762978e6b3be 100644 --- a/generated/api/v1/rbac_service.pb.gw.go +++ b/generated/api/v1/rbac_service.pb.gw.go @@ -41,9 +41,6 @@ func request_RbacService_GetRole_0(ctx context.Context, marshaler runtime.Marsha metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -52,6 +49,9 @@ func request_RbacService_GetRole_0(ctx context.Context, marshaler runtime.Marsha if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetRole(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -81,15 +81,15 @@ func request_RbacService_ListRoles_0(ctx context.Context, marshaler runtime.Mars protoReq RawQuery metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_RbacService_ListRoles_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.ListRoles(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -115,9 +115,6 @@ func request_RbacService_GetRoleBinding_0(ctx context.Context, marshaler runtime metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -126,6 +123,9 @@ func request_RbacService_GetRoleBinding_0(ctx context.Context, marshaler runtime if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetRoleBinding(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -155,15 +155,15 @@ func request_RbacService_ListRoleBindings_0(ctx context.Context, marshaler runti protoReq RawQuery metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_RbacService_ListRoleBindings_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.ListRoleBindings(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -189,9 +189,6 @@ func request_RbacService_GetSubject_0(ctx context.Context, marshaler runtime.Mar metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -200,6 +197,9 @@ func request_RbacService_GetSubject_0(ctx context.Context, marshaler runtime.Mar if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetSubject(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -229,15 +229,15 @@ func request_RbacService_ListSubjects_0(ctx context.Context, marshaler runtime.M protoReq RawQuery metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_RbacService_ListSubjects_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.ListSubjects(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } diff --git a/generated/api/v1/rbac_service.swagger.json b/generated/api/v1/rbac_service.swagger.json index 7135cbec87026..547e342cdab73 100644 --- a/generated/api/v1/rbac_service.swagger.json +++ b/generated/api/v1/rbac_service.swagger.json @@ -361,7 +361,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" }, "storageK8sRole": { diff --git a/generated/api/v1/resource_collection_service.pb.go b/generated/api/v1/resource_collection_service.pb.go index 0b71cbc3194f2..eb6720e5d5234 100644 --- a/generated/api/v1/resource_collection_service.pb.go +++ b/generated/api/v1/resource_collection_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/resource_collection_service.proto diff --git a/generated/api/v1/resource_collection_service.pb.gw.go b/generated/api/v1/resource_collection_service.pb.gw.go index 6de4f6646b426..17989bc5527ed 100644 --- a/generated/api/v1/resource_collection_service.pb.gw.go +++ b/generated/api/v1/resource_collection_service.pb.gw.go @@ -64,9 +64,6 @@ func request_CollectionService_GetCollection_0(ctx context.Context, marshaler ru metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -81,6 +78,9 @@ func request_CollectionService_GetCollection_0(ctx context.Context, marshaler ru if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_CollectionService_GetCollection_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetCollection(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -116,15 +116,15 @@ func request_CollectionService_GetCollectionCount_0(ctx context.Context, marshal protoReq GetCollectionCountRequest metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_CollectionService_GetCollectionCount_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetCollectionCount(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -180,9 +180,6 @@ func request_CollectionService_UpdateCollection_0(ctx context.Context, marshaler if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -191,6 +188,9 @@ func request_CollectionService_UpdateCollection_0(ctx context.Context, marshaler if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.UpdateCollection(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -223,15 +223,15 @@ func request_CollectionService_ListCollections_0(ctx context.Context, marshaler protoReq ListCollectionsRequest metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_CollectionService_ListCollections_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.ListCollections(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -257,9 +257,6 @@ func request_CollectionService_DeleteCollection_0(ctx context.Context, marshaler metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -268,6 +265,9 @@ func request_CollectionService_DeleteCollection_0(ctx context.Context, marshaler if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.DeleteCollection(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } diff --git a/generated/api/v1/resource_collection_service.swagger.json b/generated/api/v1/resource_collection_service.swagger.json index dfa43cc273c41..6f87d4deb121f 100644 --- a/generated/api/v1/resource_collection_service.swagger.json +++ b/generated/api/v1/resource_collection_service.swagger.json @@ -463,7 +463,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" }, "storageBooleanOperator": { diff --git a/generated/api/v1/role_service.pb.go b/generated/api/v1/role_service.pb.go index cfe89975452c7..236017eb36dd0 100644 --- a/generated/api/v1/role_service.pb.go +++ b/generated/api/v1/role_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/role_service.proto diff --git a/generated/api/v1/role_service.pb.gw.go b/generated/api/v1/role_service.pb.gw.go index 69f19e28bf71c..ffd6c83912a0d 100644 --- a/generated/api/v1/role_service.pb.gw.go +++ b/generated/api/v1/role_service.pb.gw.go @@ -63,9 +63,6 @@ func request_RoleService_GetRole_0(ctx context.Context, marshaler runtime.Marsha metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -74,6 +71,9 @@ func request_RoleService_GetRole_0(ctx context.Context, marshaler runtime.Marsha if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetRole(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -126,9 +126,6 @@ func request_RoleService_CreateRole_0(ctx context.Context, marshaler runtime.Mar if err := marshaler.NewDecoder(req.Body).Decode(&protoReq.Role); err != nil && !errors.Is(err, io.EOF) { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["name"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "name") @@ -137,6 +134,9 @@ func request_RoleService_CreateRole_0(ctx context.Context, marshaler runtime.Mar if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "name", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.CreateRole(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -171,9 +171,6 @@ func request_RoleService_UpdateRole_0(ctx context.Context, marshaler runtime.Mar if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["name"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "name") @@ -182,6 +179,9 @@ func request_RoleService_UpdateRole_0(ctx context.Context, marshaler runtime.Mar if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "name", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.UpdateRole(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -213,9 +213,6 @@ func request_RoleService_DeleteRole_0(ctx context.Context, marshaler runtime.Mar metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -224,6 +221,9 @@ func request_RoleService_DeleteRole_0(ctx context.Context, marshaler runtime.Mar if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.DeleteRole(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -273,9 +273,6 @@ func request_RoleService_GetPermissionSet_0(ctx context.Context, marshaler runti metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -284,6 +281,9 @@ func request_RoleService_GetPermissionSet_0(ctx context.Context, marshaler runti if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetPermissionSet(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -363,9 +363,6 @@ func request_RoleService_PutPermissionSet_0(ctx context.Context, marshaler runti if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -374,6 +371,9 @@ func request_RoleService_PutPermissionSet_0(ctx context.Context, marshaler runti if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.PutPermissionSet(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -405,9 +405,6 @@ func request_RoleService_DeletePermissionSet_0(ctx context.Context, marshaler ru metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -416,6 +413,9 @@ func request_RoleService_DeletePermissionSet_0(ctx context.Context, marshaler ru if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.DeletePermissionSet(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -444,9 +444,6 @@ func request_RoleService_GetSimpleAccessScope_0(ctx context.Context, marshaler r metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -455,6 +452,9 @@ func request_RoleService_GetSimpleAccessScope_0(ctx context.Context, marshaler r if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetSimpleAccessScope(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -534,9 +534,6 @@ func request_RoleService_PutSimpleAccessScope_0(ctx context.Context, marshaler r if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -545,6 +542,9 @@ func request_RoleService_PutSimpleAccessScope_0(ctx context.Context, marshaler r if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.PutSimpleAccessScope(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -576,9 +576,6 @@ func request_RoleService_DeleteSimpleAccessScope_0(ctx context.Context, marshale metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -587,6 +584,9 @@ func request_RoleService_DeleteSimpleAccessScope_0(ctx context.Context, marshale if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.DeleteSimpleAccessScope(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -619,15 +619,15 @@ func request_RoleService_ComputeEffectiveAccessScope_0(ctx context.Context, mars if err := marshaler.NewDecoder(req.Body).Decode(&protoReq.AccessScope); err != nil && !errors.Is(err, io.EOF) { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_RoleService_ComputeEffectiveAccessScope_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.ComputeEffectiveAccessScope(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -657,15 +657,15 @@ func request_RoleService_GetClustersForPermissions_0(ctx context.Context, marsha protoReq GetClustersForPermissionsRequest metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_RoleService_GetClustersForPermissions_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetClustersForPermissions(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -693,9 +693,6 @@ func request_RoleService_GetNamespacesForClusterAndPermissions_0(ctx context.Con metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["cluster_id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "cluster_id") @@ -710,6 +707,9 @@ func request_RoleService_GetNamespacesForClusterAndPermissions_0(ctx context.Con if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_RoleService_GetNamespacesForClusterAndPermissions_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetNamespacesForClusterAndPermissions(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } diff --git a/generated/api/v1/role_service.swagger.json b/generated/api/v1/role_service.swagger.json index c1b228a80ca65..314d35ae1ebb5 100644 --- a/generated/api/v1/role_service.swagger.json +++ b/generated/api/v1/role_service.swagger.json @@ -913,7 +913,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" }, "storageAccess": { diff --git a/generated/api/v1/sbom.pb.go b/generated/api/v1/sbom.pb.go index 5857f099a3d19..e5a28eab3710e 100644 --- a/generated/api/v1/sbom.pb.go +++ b/generated/api/v1/sbom.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/sbom.proto diff --git a/generated/api/v1/sbom.swagger.json b/generated/api/v1/sbom.swagger.json index 7354252383621..65490e98998f6 100644 --- a/generated/api/v1/sbom.swagger.json +++ b/generated/api/v1/sbom.swagger.json @@ -39,7 +39,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" } } diff --git a/generated/api/v1/search_service.pb.go b/generated/api/v1/search_service.pb.go index 1a7e19fa32741..9b50e8b779b00 100644 --- a/generated/api/v1/search_service.pb.go +++ b/generated/api/v1/search_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/search_service.proto diff --git a/generated/api/v1/search_service.pb.gw.go b/generated/api/v1/search_service.pb.gw.go index d3552e35e4529..d378f935e30c5 100644 --- a/generated/api/v1/search_service.pb.gw.go +++ b/generated/api/v1/search_service.pb.gw.go @@ -42,15 +42,15 @@ func request_SearchService_Search_0(ctx context.Context, marshaler runtime.Marsh protoReq RawSearchRequest metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_SearchService_Search_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.Search(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -77,15 +77,15 @@ func request_SearchService_Options_0(ctx context.Context, marshaler runtime.Mars protoReq SearchOptionsRequest metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_SearchService_Options_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.Options(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -112,15 +112,15 @@ func request_SearchService_Autocomplete_0(ctx context.Context, marshaler runtime protoReq RawSearchRequest metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_SearchService_Autocomplete_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.Autocomplete(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } diff --git a/generated/api/v1/search_service.swagger.json b/generated/api/v1/search_service.swagger.json index f5a8a5301592d..e5025d1ed9ed2 100644 --- a/generated/api/v1/search_service.swagger.json +++ b/generated/api/v1/search_service.swagger.json @@ -431,7 +431,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" }, "v1AutocompleteResponse": { @@ -531,7 +531,7 @@ "IMAGE_CVE_INFOS" ], "default": "SEARCH_UNSET", - "title": "Next available tag: 85" + "description": "Next available tag: 85" }, "v1SearchOptionsResponse": { "type": "object", diff --git a/generated/api/v1/secret_service.pb.go b/generated/api/v1/secret_service.pb.go index c88e62cb63f80..9c480651181a1 100644 --- a/generated/api/v1/secret_service.pb.go +++ b/generated/api/v1/secret_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/secret_service.proto diff --git a/generated/api/v1/secret_service.pb.gw.go b/generated/api/v1/secret_service.pb.gw.go index 5cc80c64bf04c..d48c3cd9aaf6a 100644 --- a/generated/api/v1/secret_service.pb.gw.go +++ b/generated/api/v1/secret_service.pb.gw.go @@ -41,9 +41,6 @@ func request_SecretService_GetSecret_0(ctx context.Context, marshaler runtime.Ma metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -52,6 +49,9 @@ func request_SecretService_GetSecret_0(ctx context.Context, marshaler runtime.Ma if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetSecret(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -81,15 +81,15 @@ func request_SecretService_CountSecrets_0(ctx context.Context, marshaler runtime protoReq RawQuery metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_SecretService_CountSecrets_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.CountSecrets(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -116,15 +116,15 @@ func request_SecretService_ListSecrets_0(ctx context.Context, marshaler runtime. protoReq RawQuery metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_SecretService_ListSecrets_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.ListSecrets(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -151,15 +151,15 @@ func request_SecretService_ListSecretsExtended_0(ctx context.Context, marshaler protoReq ListSecretsExtendedRequest metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_SecretService_ListSecretsExtended_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.ListSecretsExtended(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } diff --git a/generated/api/v1/secret_service.swagger.json b/generated/api/v1/secret_service.swagger.json index 734fe1f9fbe1f..9bdbd252d5646 100644 --- a/generated/api/v1/secret_service.swagger.json +++ b/generated/api/v1/secret_service.swagger.json @@ -321,7 +321,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" }, "storageCert": { diff --git a/generated/api/v1/sensor_upgrade_service.pb.go b/generated/api/v1/sensor_upgrade_service.pb.go index 15d26cfdf661f..690ee71561cf4 100644 --- a/generated/api/v1/sensor_upgrade_service.pb.go +++ b/generated/api/v1/sensor_upgrade_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/sensor_upgrade_service.proto diff --git a/generated/api/v1/sensor_upgrade_service.pb.gw.go b/generated/api/v1/sensor_upgrade_service.pb.gw.go index 77e2081bf85f1..8ae39c741f536 100644 --- a/generated/api/v1/sensor_upgrade_service.pb.gw.go +++ b/generated/api/v1/sensor_upgrade_service.pb.gw.go @@ -89,9 +89,6 @@ func request_SensorUpgradeService_TriggerSensorUpgrade_0(ctx context.Context, ma metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -100,6 +97,9 @@ func request_SensorUpgradeService_TriggerSensorUpgrade_0(ctx context.Context, ma if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.TriggerSensorUpgrade(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -128,9 +128,6 @@ func request_SensorUpgradeService_TriggerSensorCertRotation_0(ctx context.Contex metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -139,6 +136,9 @@ func request_SensorUpgradeService_TriggerSensorCertRotation_0(ctx context.Contex if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.TriggerSensorCertRotation(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } diff --git a/generated/api/v1/sensor_upgrade_service.swagger.json b/generated/api/v1/sensor_upgrade_service.swagger.json index a324e351aea17..9c7f8fed0c668 100644 --- a/generated/api/v1/sensor_upgrade_service.swagger.json +++ b/generated/api/v1/sensor_upgrade_service.swagger.json @@ -6,7 +6,8 @@ }, "tags": [ { - "name": "SensorUpgradeService" + "name": "SensorUpgradeService", + "description": "SensorUpgradeService is deprecated. Use operator-based installation instead;\nthe operator handles sensor upgrades and certificate rotation." } ], "consumes": [ @@ -176,7 +177,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" }, "storageSensorUpgradeConfig": { diff --git a/generated/api/v1/service_account_service.pb.go b/generated/api/v1/service_account_service.pb.go index b76622395e63a..5e1c0556f42e8 100644 --- a/generated/api/v1/service_account_service.pb.go +++ b/generated/api/v1/service_account_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/service_account_service.proto diff --git a/generated/api/v1/service_account_service.pb.gw.go b/generated/api/v1/service_account_service.pb.gw.go index 8958f848a264f..8bddc40cc38c8 100644 --- a/generated/api/v1/service_account_service.pb.gw.go +++ b/generated/api/v1/service_account_service.pb.gw.go @@ -41,9 +41,6 @@ func request_ServiceAccountService_GetServiceAccount_0(ctx context.Context, mars metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -52,6 +49,9 @@ func request_ServiceAccountService_GetServiceAccount_0(ctx context.Context, mars if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetServiceAccount(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -81,15 +81,15 @@ func request_ServiceAccountService_ListServiceAccounts_0(ctx context.Context, ma protoReq RawQuery metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ServiceAccountService_ListServiceAccounts_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.ListServiceAccounts(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } diff --git a/generated/api/v1/service_account_service.swagger.json b/generated/api/v1/service_account_service.swagger.json index 3ef7af6e0bb10..f5ba0357ba13d 100644 --- a/generated/api/v1/service_account_service.swagger.json +++ b/generated/api/v1/service_account_service.swagger.json @@ -150,7 +150,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" }, "storageK8sRole": { diff --git a/generated/api/v1/service_identity_service.pb.go b/generated/api/v1/service_identity_service.pb.go index abb0f106b4b7f..a7a8d1a0af870 100644 --- a/generated/api/v1/service_identity_service.pb.go +++ b/generated/api/v1/service_identity_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/service_identity_service.proto diff --git a/generated/api/v1/service_identity_service.swagger.json b/generated/api/v1/service_identity_service.swagger.json index 2ff99c15cd7c3..779586dfe6703 100644 --- a/generated/api/v1/service_identity_service.swagger.json +++ b/generated/api/v1/service_identity_service.swagger.json @@ -121,7 +121,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" }, "storageServiceIdentity": { diff --git a/generated/api/v1/signal.pb.go b/generated/api/v1/signal.pb.go index c54ddaf697f5a..059076c5abc56 100644 --- a/generated/api/v1/signal.pb.go +++ b/generated/api/v1/signal.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/signal.proto diff --git a/generated/api/v1/signal.swagger.json b/generated/api/v1/signal.swagger.json index 20d4dc83d6133..72cc78ae29417 100644 --- a/generated/api/v1/signal.swagger.json +++ b/generated/api/v1/signal.swagger.json @@ -39,7 +39,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" } } diff --git a/generated/api/v1/signature_integration_service.pb.go b/generated/api/v1/signature_integration_service.pb.go index fbed8847a24d2..ccff377da6b66 100644 --- a/generated/api/v1/signature_integration_service.pb.go +++ b/generated/api/v1/signature_integration_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/signature_integration_service.proto diff --git a/generated/api/v1/signature_integration_service.pb.gw.go b/generated/api/v1/signature_integration_service.pb.gw.go index 9159179d308eb..3e0726fa787d4 100644 --- a/generated/api/v1/signature_integration_service.pb.gw.go +++ b/generated/api/v1/signature_integration_service.pb.gw.go @@ -63,9 +63,6 @@ func request_SignatureIntegrationService_GetSignatureIntegration_0(ctx context.C metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -74,6 +71,9 @@ func request_SignatureIntegrationService_GetSignatureIntegration_0(ctx context.C if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetSignatureIntegration(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -132,9 +132,6 @@ func request_SignatureIntegrationService_PutSignatureIntegration_0(ctx context.C if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -143,6 +140,9 @@ func request_SignatureIntegrationService_PutSignatureIntegration_0(ctx context.C if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.PutSignatureIntegration(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -174,9 +174,6 @@ func request_SignatureIntegrationService_DeleteSignatureIntegration_0(ctx contex metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -185,6 +182,9 @@ func request_SignatureIntegrationService_DeleteSignatureIntegration_0(ctx contex if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.DeleteSignatureIntegration(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } diff --git a/generated/api/v1/signature_integration_service.swagger.json b/generated/api/v1/signature_integration_service.swagger.json index 5a0e5be383376..ed07744b2c858 100644 --- a/generated/api/v1/signature_integration_service.swagger.json +++ b/generated/api/v1/signature_integration_service.swagger.json @@ -227,7 +227,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" }, "storageCertificateTransparencyLogVerification": { diff --git a/generated/api/v1/telemetry_service.pb.go b/generated/api/v1/telemetry_service.pb.go index 4923cccc45643..b7961504d70ce 100644 --- a/generated/api/v1/telemetry_service.pb.go +++ b/generated/api/v1/telemetry_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/telemetry_service.proto diff --git a/generated/api/v1/telemetry_service.swagger.json b/generated/api/v1/telemetry_service.swagger.json index 57e18860196cb..db5ba13ee404b 100644 --- a/generated/api/v1/telemetry_service.swagger.json +++ b/generated/api/v1/telemetry_service.swagger.json @@ -158,7 +158,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" }, "storageTelemetryConfiguration": { diff --git a/generated/api/v1/traits.pb.go b/generated/api/v1/traits.pb.go index 413295858e8b4..2fbf9683cedbf 100644 --- a/generated/api/v1/traits.pb.go +++ b/generated/api/v1/traits.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/traits.proto diff --git a/generated/api/v1/traits.swagger.json b/generated/api/v1/traits.swagger.json index e039a2b7b6272..f37135e368c3b 100644 --- a/generated/api/v1/traits.swagger.json +++ b/generated/api/v1/traits.swagger.json @@ -39,7 +39,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" } } diff --git a/generated/api/v1/user_service.pb.go b/generated/api/v1/user_service.pb.go index 5db9fbf6de584..2ab345487c4d1 100644 --- a/generated/api/v1/user_service.pb.go +++ b/generated/api/v1/user_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/user_service.proto diff --git a/generated/api/v1/user_service.pb.gw.go b/generated/api/v1/user_service.pb.gw.go index 231759af351f3..842f59fccefe4 100644 --- a/generated/api/v1/user_service.pb.gw.go +++ b/generated/api/v1/user_service.pb.gw.go @@ -62,9 +62,6 @@ func request_UserService_GetUser_0(ctx context.Context, marshaler runtime.Marsha metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -73,6 +70,9 @@ func request_UserService_GetUser_0(ctx context.Context, marshaler runtime.Marsha if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetUser(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } diff --git a/generated/api/v1/user_service.swagger.json b/generated/api/v1/user_service.swagger.json index 77a011bb1f480..925be291296d8 100644 --- a/generated/api/v1/user_service.swagger.json +++ b/generated/api/v1/user_service.swagger.json @@ -119,7 +119,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" }, "storageUser": { diff --git a/generated/api/v1/vuln_mgmt_service.pb.go b/generated/api/v1/vuln_mgmt_service.pb.go index 09a84733debfc..7b48309d83bc4 100644 --- a/generated/api/v1/vuln_mgmt_service.pb.go +++ b/generated/api/v1/vuln_mgmt_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v1/vuln_mgmt_service.proto diff --git a/generated/api/v1/vuln_mgmt_service.pb.gw.go b/generated/api/v1/vuln_mgmt_service.pb.gw.go index 211534deb1394..77e79d7c43d65 100644 --- a/generated/api/v1/vuln_mgmt_service.pb.gw.go +++ b/generated/api/v1/vuln_mgmt_service.pb.gw.go @@ -42,15 +42,15 @@ func request_VulnMgmtService_VulnMgmtExportWorkloads_0(ctx context.Context, mars protoReq VulnMgmtExportWorkloadsRequest metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_VulnMgmtService_VulnMgmtExportWorkloads_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } stream, err := client.VulnMgmtExportWorkloads(ctx, &protoReq) if err != nil { return nil, metadata, err diff --git a/generated/api/v1/vuln_mgmt_service.swagger.json b/generated/api/v1/vuln_mgmt_service.swagger.json index f35a4d8d751fa..36744e8d6c897 100644 --- a/generated/api/v1/vuln_mgmt_service.swagger.json +++ b/generated/api/v1/vuln_mgmt_service.swagger.json @@ -6,7 +6,8 @@ }, "tags": [ { - "name": "VulnMgmtService" + "name": "VulnMgmtService", + "description": "VulnMgmtService APIs are used to manage workload vulnerabilities." } ], "consumes": [ @@ -183,7 +184,7 @@ "UNKNOWN" ], "default": "UNSET", - "title": "For any update to EnvVarSource, please also update 'ui/src/messages/common.js'" + "description": "For any update to EnvVarSource, please also update 'ui/src/messages/common.js'" }, "LabelSelectorRequirement": { "type": "object", @@ -329,7 +330,7 @@ "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, - "additionalProperties": {}, + "additionalProperties": true, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(&foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := &pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := &pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": ,\n \"lastName\": \n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" }, "storageAdvisory": { @@ -1399,7 +1400,7 @@ "CLUSTER_ADMIN" ], "default": "UNSET", - "title": "For any update to PermissionLevel, also update:\n- pkg/searchbasedpolicies/builders/k8s_rbac.go\n- ui/src/messages/common.js" + "description": "For any update to PermissionLevel, also update:\n- pkg/searchbasedpolicies/builders/k8s_rbac.go\n- ui/src/messages/common.js" }, "storagePortConfig": { "type": "object", diff --git a/generated/api/v2/base_image_service.pb.go b/generated/api/v2/base_image_service.pb.go index e14ce1c99dfb9..0ee3a84f97fe0 100644 --- a/generated/api/v2/base_image_service.pb.go +++ b/generated/api/v2/base_image_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v2/base_image_service.proto diff --git a/generated/api/v2/base_image_service.pb.gw.go b/generated/api/v2/base_image_service.pb.gw.go index 4f16f63e08867..c3a0d7cf29f6f 100644 --- a/generated/api/v2/base_image_service.pb.gw.go +++ b/generated/api/v2/base_image_service.pb.gw.go @@ -92,9 +92,6 @@ func request_BaseImageServiceV2_UpdateBaseImageTagPattern_0(ctx context.Context, if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -103,6 +100,9 @@ func request_BaseImageServiceV2_UpdateBaseImageTagPattern_0(ctx context.Context, if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.UpdateBaseImageTagPattern(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -134,9 +134,6 @@ func request_BaseImageServiceV2_DeleteBaseImageReference_0(ctx context.Context, metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -145,6 +142,9 @@ func request_BaseImageServiceV2_DeleteBaseImageReference_0(ctx context.Context, if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.DeleteBaseImageReference(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } diff --git a/generated/api/v2/base_image_service.swagger.json b/generated/api/v2/base_image_service.swagger.json index 60d0dd4bb7c61..2ea26acc96b72 100644 --- a/generated/api/v2/base_image_service.swagger.json +++ b/generated/api/v2/base_image_service.swagger.json @@ -6,7 +6,8 @@ }, "tags": [ { - "name": "BaseImageServiceV2" + "name": "BaseImageServiceV2", + "description": "BaseImageServiceV2 APIs manages base image references." } ], "consumes": [ @@ -155,7 +156,7 @@ "type": "string" } }, - "additionalProperties": {} + "additionalProperties": true }, "rpcStatus": { "type": "object", diff --git a/generated/api/v2/common.pb.go b/generated/api/v2/common.pb.go index 46c6af89b3828..05518776c4403 100644 --- a/generated/api/v2/common.pb.go +++ b/generated/api/v2/common.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v2/common.proto diff --git a/generated/api/v2/common.swagger.json b/generated/api/v2/common.swagger.json index ee9c2b8f36384..8466b4ab4340d 100644 --- a/generated/api/v2/common.swagger.json +++ b/generated/api/v2/common.swagger.json @@ -19,7 +19,7 @@ "type": "string" } }, - "additionalProperties": {} + "additionalProperties": true }, "rpcStatus": { "type": "object", diff --git a/generated/api/v2/compliance_common.pb.go b/generated/api/v2/compliance_common.pb.go index ba7c41a32adee..d92f5c5cbc5d6 100644 --- a/generated/api/v2/compliance_common.pb.go +++ b/generated/api/v2/compliance_common.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v2/compliance_common.proto diff --git a/generated/api/v2/compliance_common.swagger.json b/generated/api/v2/compliance_common.swagger.json index cf27ee859202e..27eda455dd005 100644 --- a/generated/api/v2/compliance_common.swagger.json +++ b/generated/api/v2/compliance_common.swagger.json @@ -19,7 +19,7 @@ "type": "string" } }, - "additionalProperties": {} + "additionalProperties": true }, "rpcStatus": { "type": "object", diff --git a/generated/api/v2/compliance_integration_service.pb.go b/generated/api/v2/compliance_integration_service.pb.go index 769817cd4bcae..7a9ea6cae2642 100644 --- a/generated/api/v2/compliance_integration_service.pb.go +++ b/generated/api/v2/compliance_integration_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v2/compliance_integration_service.proto diff --git a/generated/api/v2/compliance_integration_service.pb.gw.go b/generated/api/v2/compliance_integration_service.pb.gw.go index b3ae5fb8f858a..1fedb13211987 100644 --- a/generated/api/v2/compliance_integration_service.pb.gw.go +++ b/generated/api/v2/compliance_integration_service.pb.gw.go @@ -42,15 +42,15 @@ func request_ComplianceIntegrationService_ListComplianceIntegrations_0(ctx conte protoReq RawQuery metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ComplianceIntegrationService_ListComplianceIntegrations_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.ListComplianceIntegrations(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } diff --git a/generated/api/v2/compliance_integration_service.swagger.json b/generated/api/v2/compliance_integration_service.swagger.json index 8457fc910e24f..5e4fec9e87707 100644 --- a/generated/api/v2/compliance_integration_service.swagger.json +++ b/generated/api/v2/compliance_integration_service.swagger.json @@ -101,7 +101,7 @@ "type": "string" } }, - "additionalProperties": {} + "additionalProperties": true }, "rpcStatus": { "type": "object", @@ -150,7 +150,7 @@ "UNHEALTHY" ], "default": "HEALTHY", - "title": "Represents the status of compliance operator" + "description": "Represents the status of compliance operator" }, "v2ClusterPlatformType": { "type": "string", diff --git a/generated/api/v2/compliance_profile_service.pb.go b/generated/api/v2/compliance_profile_service.pb.go index f16414001848c..7336af6368561 100644 --- a/generated/api/v2/compliance_profile_service.pb.go +++ b/generated/api/v2/compliance_profile_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v2/compliance_profile_service.proto diff --git a/generated/api/v2/compliance_profile_service.pb.gw.go b/generated/api/v2/compliance_profile_service.pb.gw.go index 76840ac44f315..54b5a20c7959b 100644 --- a/generated/api/v2/compliance_profile_service.pb.gw.go +++ b/generated/api/v2/compliance_profile_service.pb.gw.go @@ -41,9 +41,6 @@ func request_ComplianceProfileService_GetComplianceProfile_0(ctx context.Context metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -52,6 +49,9 @@ func request_ComplianceProfileService_GetComplianceProfile_0(ctx context.Context if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetComplianceProfile(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -81,15 +81,15 @@ func request_ComplianceProfileService_ListComplianceProfiles_0(ctx context.Conte protoReq ProfilesForClusterRequest metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ComplianceProfileService_ListComplianceProfiles_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.ListComplianceProfiles(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -116,15 +116,15 @@ func request_ComplianceProfileService_ListProfileSummaries_0(ctx context.Context protoReq ClustersProfileSummaryRequest metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ComplianceProfileService_ListProfileSummaries_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.ListProfileSummaries(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } diff --git a/generated/api/v2/compliance_profile_service.swagger.json b/generated/api/v2/compliance_profile_service.swagger.json index 04e5dec77b532..1def482f6536f 100644 --- a/generated/api/v2/compliance_profile_service.swagger.json +++ b/generated/api/v2/compliance_profile_service.swagger.json @@ -235,7 +235,7 @@ "type": "string" } }, - "additionalProperties": {} + "additionalProperties": true }, "rpcStatus": { "type": "object", diff --git a/generated/api/v2/compliance_results_service.pb.go b/generated/api/v2/compliance_results_service.pb.go index d3960013e7c7e..65cd85ab10ffe 100644 --- a/generated/api/v2/compliance_results_service.pb.go +++ b/generated/api/v2/compliance_results_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v2/compliance_results_service.proto diff --git a/generated/api/v2/compliance_results_service.pb.gw.go b/generated/api/v2/compliance_results_service.pb.gw.go index 1e74de8c07eb7..0b059ab384986 100644 --- a/generated/api/v2/compliance_results_service.pb.gw.go +++ b/generated/api/v2/compliance_results_service.pb.gw.go @@ -41,9 +41,6 @@ func request_ComplianceResultsService_GetComplianceScanCheckResult_0(ctx context metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -52,6 +49,9 @@ func request_ComplianceResultsService_GetComplianceScanCheckResult_0(ctx context if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetComplianceScanCheckResult(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -81,15 +81,15 @@ func request_ComplianceResultsService_GetComplianceScanResults_0(ctx context.Con protoReq RawQuery metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ComplianceResultsService_GetComplianceScanResults_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetComplianceScanResults(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -117,9 +117,6 @@ func request_ComplianceResultsService_GetComplianceScanConfigurationResults_0(ct metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["scan_config_name"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "scan_config_name") @@ -134,6 +131,9 @@ func request_ComplianceResultsService_GetComplianceScanConfigurationResults_0(ct if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ComplianceResultsService_GetComplianceScanConfigurationResults_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetComplianceScanConfigurationResults(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -170,9 +170,6 @@ func request_ComplianceResultsService_GetComplianceProfileResults_0(ctx context. metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["profile_name"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "profile_name") @@ -187,6 +184,9 @@ func request_ComplianceResultsService_GetComplianceProfileResults_0(ctx context. if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ComplianceResultsService_GetComplianceProfileResults_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetComplianceProfileResults(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -223,9 +223,6 @@ func request_ComplianceResultsService_GetComplianceProfileCheckResult_0(ctx cont metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["profile_name"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "profile_name") @@ -248,6 +245,9 @@ func request_ComplianceResultsService_GetComplianceProfileCheckResult_0(ctx cont if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ComplianceResultsService_GetComplianceProfileCheckResult_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetComplianceProfileCheckResult(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -292,9 +292,6 @@ func request_ComplianceResultsService_GetComplianceProfileClusterResults_0(ctx c metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["profile_name"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "profile_name") @@ -317,6 +314,9 @@ func request_ComplianceResultsService_GetComplianceProfileClusterResults_0(ctx c if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ComplianceResultsService_GetComplianceProfileClusterResults_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetComplianceProfileClusterResults(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -361,9 +361,6 @@ func request_ComplianceResultsService_GetComplianceProfileCheckDetails_0(ctx con metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["profile_name"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "profile_name") @@ -386,6 +383,9 @@ func request_ComplianceResultsService_GetComplianceProfileCheckDetails_0(ctx con if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ComplianceResultsService_GetComplianceProfileCheckDetails_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetComplianceProfileCheckDetails(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } diff --git a/generated/api/v2/compliance_results_service.swagger.json b/generated/api/v2/compliance_results_service.swagger.json index 13acb31de6379..01abcae4dde73 100644 --- a/generated/api/v2/compliance_results_service.swagger.json +++ b/generated/api/v2/compliance_results_service.swagger.json @@ -560,7 +560,7 @@ "type": "string" } }, - "additionalProperties": {} + "additionalProperties": true }, "rpcStatus": { "type": "object", diff --git a/generated/api/v2/compliance_results_stats_service.pb.go b/generated/api/v2/compliance_results_stats_service.pb.go index b2858c0c473c0..aad9bbc9b9a98 100644 --- a/generated/api/v2/compliance_results_stats_service.pb.go +++ b/generated/api/v2/compliance_results_stats_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v2/compliance_results_stats_service.proto diff --git a/generated/api/v2/compliance_results_stats_service.pb.gw.go b/generated/api/v2/compliance_results_stats_service.pb.gw.go index a5a101f60df19..ea656923fb95f 100644 --- a/generated/api/v2/compliance_results_stats_service.pb.gw.go +++ b/generated/api/v2/compliance_results_stats_service.pb.gw.go @@ -43,9 +43,6 @@ func request_ComplianceResultsStatsService_GetComplianceProfileStats_0(ctx conte metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["profile_name"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "profile_name") @@ -60,6 +57,9 @@ func request_ComplianceResultsStatsService_GetComplianceProfileStats_0(ctx conte if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ComplianceResultsStatsService_GetComplianceProfileStats_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetComplianceProfileStats(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -95,15 +95,15 @@ func request_ComplianceResultsStatsService_GetComplianceProfilesStats_0(ctx cont protoReq RawQuery metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ComplianceResultsStatsService_GetComplianceProfilesStats_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetComplianceProfilesStats(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -131,9 +131,6 @@ func request_ComplianceResultsStatsService_GetComplianceProfilesClusterStats_0(c metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["cluster_id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "cluster_id") @@ -148,6 +145,9 @@ func request_ComplianceResultsStatsService_GetComplianceProfilesClusterStats_0(c if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ComplianceResultsStatsService_GetComplianceProfilesClusterStats_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetComplianceProfilesClusterStats(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -184,9 +184,6 @@ func request_ComplianceResultsStatsService_GetComplianceProfileCheckStats_0(ctx metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["profile_name"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "profile_name") @@ -209,6 +206,9 @@ func request_ComplianceResultsStatsService_GetComplianceProfileCheckStats_0(ctx if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ComplianceResultsStatsService_GetComplianceProfileCheckStats_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetComplianceProfileCheckStats(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -253,9 +253,6 @@ func request_ComplianceResultsStatsService_GetComplianceClusterScanStats_0(ctx c metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["cluster_id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "cluster_id") @@ -270,6 +267,9 @@ func request_ComplianceResultsStatsService_GetComplianceClusterScanStats_0(ctx c if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ComplianceResultsStatsService_GetComplianceClusterScanStats_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetComplianceClusterScanStats(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -305,15 +305,15 @@ func request_ComplianceResultsStatsService_GetComplianceOverallClusterStats_0(ct protoReq RawQuery metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ComplianceResultsStatsService_GetComplianceOverallClusterStats_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetComplianceOverallClusterStats(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -341,9 +341,6 @@ func request_ComplianceResultsStatsService_GetComplianceClusterStats_0(ctx conte metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["profile_name"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "profile_name") @@ -358,6 +355,9 @@ func request_ComplianceResultsStatsService_GetComplianceClusterStats_0(ctx conte if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ComplianceResultsStatsService_GetComplianceClusterStats_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetComplianceClusterStats(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } diff --git a/generated/api/v2/compliance_results_stats_service.swagger.json b/generated/api/v2/compliance_results_stats_service.swagger.json index 168beee0f77e7..899401d31f5ff 100644 --- a/generated/api/v2/compliance_results_stats_service.swagger.json +++ b/generated/api/v2/compliance_results_stats_service.swagger.json @@ -592,7 +592,7 @@ "type": "string" } }, - "additionalProperties": {} + "additionalProperties": true }, "rpcStatus": { "type": "object", diff --git a/generated/api/v2/compliance_rule_service.pb.go b/generated/api/v2/compliance_rule_service.pb.go index 018f0515d91f3..f962e1500e898 100644 --- a/generated/api/v2/compliance_rule_service.pb.go +++ b/generated/api/v2/compliance_rule_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v2/compliance_rule_service.proto diff --git a/generated/api/v2/compliance_rule_service.pb.gw.go b/generated/api/v2/compliance_rule_service.pb.gw.go index 4a934175a8038..6584493a35518 100644 --- a/generated/api/v2/compliance_rule_service.pb.gw.go +++ b/generated/api/v2/compliance_rule_service.pb.gw.go @@ -43,9 +43,6 @@ func request_ComplianceRuleService_GetComplianceRule_0(ctx context.Context, mars metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["rule_name"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "rule_name") @@ -60,6 +57,9 @@ func request_ComplianceRuleService_GetComplianceRule_0(ctx context.Context, mars if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ComplianceRuleService_GetComplianceRule_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetComplianceRule(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } diff --git a/generated/api/v2/compliance_rule_service.swagger.json b/generated/api/v2/compliance_rule_service.swagger.json index 541bc3637ddc0..07a31d3e5e3a0 100644 --- a/generated/api/v2/compliance_rule_service.swagger.json +++ b/generated/api/v2/compliance_rule_service.swagger.json @@ -118,7 +118,7 @@ "type": "string" } }, - "additionalProperties": {} + "additionalProperties": true }, "rpcStatus": { "type": "object", diff --git a/generated/api/v2/compliance_scan_configuration_service.pb.go b/generated/api/v2/compliance_scan_configuration_service.pb.go index c5e288dec6d33..bdb65f6518c61 100644 --- a/generated/api/v2/compliance_scan_configuration_service.pb.go +++ b/generated/api/v2/compliance_scan_configuration_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v2/compliance_scan_configuration_service.proto diff --git a/generated/api/v2/compliance_scan_configuration_service.pb.gw.go b/generated/api/v2/compliance_scan_configuration_service.pb.gw.go index 67b0864a0e3f9..c500547c45890 100644 --- a/generated/api/v2/compliance_scan_configuration_service.pb.gw.go +++ b/generated/api/v2/compliance_scan_configuration_service.pb.gw.go @@ -42,15 +42,15 @@ func request_ComplianceScanConfigurationService_ListComplianceScanConfigurations protoReq RawQuery metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ComplianceScanConfigurationService_ListComplianceScanConfigurations_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.ListComplianceScanConfigurations(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -76,9 +76,6 @@ func request_ComplianceScanConfigurationService_GetComplianceScanConfiguration_0 metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -87,6 +84,9 @@ func request_ComplianceScanConfigurationService_GetComplianceScanConfiguration_0 if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetComplianceScanConfiguration(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -145,9 +145,6 @@ func request_ComplianceScanConfigurationService_UpdateComplianceScanConfiguratio if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -156,6 +153,9 @@ func request_ComplianceScanConfigurationService_UpdateComplianceScanConfiguratio if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.UpdateComplianceScanConfiguration(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -187,9 +187,6 @@ func request_ComplianceScanConfigurationService_DeleteComplianceScanConfiguratio metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -198,6 +195,9 @@ func request_ComplianceScanConfigurationService_DeleteComplianceScanConfiguratio if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.DeleteComplianceScanConfiguration(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -226,9 +226,6 @@ func request_ComplianceScanConfigurationService_RunComplianceScanConfiguration_0 metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -237,6 +234,9 @@ func request_ComplianceScanConfigurationService_RunComplianceScanConfiguration_0 if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.RunComplianceScanConfiguration(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -294,9 +294,6 @@ func request_ComplianceScanConfigurationService_GetReportHistory_0(ctx context.C metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -311,6 +308,9 @@ func request_ComplianceScanConfigurationService_GetReportHistory_0(ctx context.C if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ComplianceScanConfigurationService_GetReportHistory_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetReportHistory(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -347,9 +347,6 @@ func request_ComplianceScanConfigurationService_GetMyReportHistory_0(ctx context metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -364,6 +361,9 @@ func request_ComplianceScanConfigurationService_GetMyReportHistory_0(ctx context if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ComplianceScanConfigurationService_GetMyReportHistory_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetMyReportHistory(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -398,9 +398,6 @@ func request_ComplianceScanConfigurationService_DeleteReport_0(ctx context.Conte metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -409,6 +406,9 @@ func request_ComplianceScanConfigurationService_DeleteReport_0(ctx context.Conte if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.DeleteReport(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -438,15 +438,15 @@ func request_ComplianceScanConfigurationService_ListComplianceScanConfigProfiles protoReq RawQuery metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ComplianceScanConfigurationService_ListComplianceScanConfigProfiles_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.ListComplianceScanConfigProfiles(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -474,9 +474,6 @@ func request_ComplianceScanConfigurationService_ListComplianceScanConfigClusterP metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["cluster_id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "cluster_id") @@ -491,6 +488,9 @@ func request_ComplianceScanConfigurationService_ListComplianceScanConfigClusterP if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ComplianceScanConfigurationService_ListComplianceScanConfigClusterProfiles_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.ListComplianceScanConfigClusterProfiles(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } diff --git a/generated/api/v2/compliance_scan_configuration_service.swagger.json b/generated/api/v2/compliance_scan_configuration_service.swagger.json index 5e381aef66623..2866849a18d93 100644 --- a/generated/api/v2/compliance_scan_configuration_service.swagger.json +++ b/generated/api/v2/compliance_scan_configuration_service.swagger.json @@ -683,7 +683,7 @@ "type": "string" } }, - "additionalProperties": {} + "additionalProperties": true }, "rpcStatus": { "type": "object", diff --git a/generated/api/v2/node_report_service.pb.go b/generated/api/v2/node_report_service.pb.go index 47da5df35034e..2c30b83c3ad23 100644 --- a/generated/api/v2/node_report_service.pb.go +++ b/generated/api/v2/node_report_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v2/node_report_service.proto diff --git a/generated/api/v2/node_report_service.pb.gw.go b/generated/api/v2/node_report_service.pb.gw.go index c1bad98935a47..d9a561139487d 100644 --- a/generated/api/v2/node_report_service.pb.gw.go +++ b/generated/api/v2/node_report_service.pb.gw.go @@ -71,9 +71,6 @@ func request_NodeReportService_UpdateNodeReportConfiguration_0(ctx context.Conte if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -82,6 +79,9 @@ func request_NodeReportService_UpdateNodeReportConfiguration_0(ctx context.Conte if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.UpdateNodeReportConfiguration(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -114,15 +114,15 @@ func request_NodeReportService_ListNodeReportConfigurations_0(ctx context.Contex protoReq RawQuery metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_NodeReportService_ListNodeReportConfigurations_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.ListNodeReportConfigurations(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -149,15 +149,15 @@ func request_NodeReportService_CountNodeReportConfigurations_0(ctx context.Conte protoReq RawQuery metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_NodeReportService_CountNodeReportConfigurations_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.CountNodeReportConfigurations(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -183,9 +183,6 @@ func request_NodeReportService_GetNodeReportConfiguration_0(ctx context.Context, metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -194,6 +191,9 @@ func request_NodeReportService_GetNodeReportConfiguration_0(ctx context.Context, if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetNodeReportConfiguration(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -222,9 +222,6 @@ func request_NodeReportService_DeleteNodeReportConfiguration_0(ctx context.Conte metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -233,6 +230,9 @@ func request_NodeReportService_DeleteNodeReportConfiguration_0(ctx context.Conte if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.DeleteNodeReportConfiguration(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -290,9 +290,6 @@ func request_NodeReportService_GetNodeReportHistory_0(ctx context.Context, marsh metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -307,6 +304,9 @@ func request_NodeReportService_GetNodeReportHistory_0(ctx context.Context, marsh if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_NodeReportService_GetNodeReportHistory_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetNodeReportHistory(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -343,9 +343,6 @@ func request_NodeReportService_GetMyNodeReportHistory_0(ctx context.Context, mar metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -360,6 +357,9 @@ func request_NodeReportService_GetMyNodeReportHistory_0(ctx context.Context, mar if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_NodeReportService_GetMyNodeReportHistory_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetMyNodeReportHistory(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -394,9 +394,6 @@ func request_NodeReportService_GetNodeReportStatus_0(ctx context.Context, marsha metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -405,6 +402,9 @@ func request_NodeReportService_GetNodeReportStatus_0(ctx context.Context, marsha if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetNodeReportStatus(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -433,9 +433,6 @@ func request_NodeReportService_CancelNodeReport_0(ctx context.Context, marshaler metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -444,6 +441,9 @@ func request_NodeReportService_CancelNodeReport_0(ctx context.Context, marshaler if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.CancelNodeReport(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -472,9 +472,6 @@ func request_NodeReportService_DeleteNodeReport_0(ctx context.Context, marshaler metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -483,6 +480,9 @@ func request_NodeReportService_DeleteNodeReport_0(ctx context.Context, marshaler if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.DeleteNodeReport(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -539,15 +539,15 @@ func request_NodeReportService_GetViewBasedNodeReportHistory_0(ctx context.Conte protoReq GetViewBasedReportHistoryRequest metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_NodeReportService_GetViewBasedNodeReportHistory_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetViewBasedNodeReportHistory(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -574,15 +574,15 @@ func request_NodeReportService_GetViewBasedMyNodeReportHistory_0(ctx context.Con protoReq GetViewBasedReportHistoryRequest metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_NodeReportService_GetViewBasedMyNodeReportHistory_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetViewBasedMyNodeReportHistory(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } diff --git a/generated/api/v2/node_report_service.swagger.json b/generated/api/v2/node_report_service.swagger.json index 7af235e1fb798..7216ca887b473 100644 --- a/generated/api/v2/node_report_service.swagger.json +++ b/generated/api/v2/node_report_service.swagger.json @@ -815,7 +815,7 @@ "type": "string" } }, - "additionalProperties": {} + "additionalProperties": true }, "rpcStatus": { "type": "object", @@ -1070,7 +1070,7 @@ "NODE_VULNERABILITY" ], "default": "VULNERABILITY", - "title": "- VULNERABILITY: for historical reasons, this short form was used to mean \"Image Vulnerability\"" + "description": "- VULNERABILITY: for historical reasons, this short form was used to mean \"Image Vulnerability\"" }, "v2ReportHistoryResponse": { "type": "object", @@ -1108,7 +1108,7 @@ "NODE_VULNERABILITY" ], "default": "VULNERABILITY", - "title": "- VULNERABILITY: for historical reasons, this short form was used to mean \"Image Vulnerability\"" + "description": "- VULNERABILITY: for historical reasons, this short form was used to mean \"Image Vulnerability\"" }, "v2ReportSchedule": { "type": "object", @@ -1232,7 +1232,7 @@ "NODE_VULNERABILITY" ], "default": "VULNERABILITY", - "title": "- VULNERABILITY: for historical reasons, this short form was used to mean \"Image Vulnerability\"" + "description": "- VULNERABILITY: for historical reasons, this short form was used to mean \"Image Vulnerability\"" }, "v2ReportStatus": { "type": "object", diff --git a/generated/api/v2/pagination.pb.go b/generated/api/v2/pagination.pb.go index 872cc707cd73a..4caf365cac11a 100644 --- a/generated/api/v2/pagination.pb.go +++ b/generated/api/v2/pagination.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v2/pagination.proto diff --git a/generated/api/v2/pagination.swagger.json b/generated/api/v2/pagination.swagger.json index 40d73ca9e6c72..57fa8652da301 100644 --- a/generated/api/v2/pagination.swagger.json +++ b/generated/api/v2/pagination.swagger.json @@ -19,7 +19,7 @@ "type": "string" } }, - "additionalProperties": {} + "additionalProperties": true }, "rpcStatus": { "type": "object", diff --git a/generated/api/v2/report_service.pb.go b/generated/api/v2/report_service.pb.go index f33e6d1df9466..a0e3d59f5b211 100644 --- a/generated/api/v2/report_service.pb.go +++ b/generated/api/v2/report_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v2/report_service.proto diff --git a/generated/api/v2/report_service.pb.gw.go b/generated/api/v2/report_service.pb.gw.go index c950a85a074fa..360f14b3d2e54 100644 --- a/generated/api/v2/report_service.pb.gw.go +++ b/generated/api/v2/report_service.pb.gw.go @@ -71,9 +71,6 @@ func request_ReportService_UpdateReportConfiguration_0(ctx context.Context, mars if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -82,6 +79,9 @@ func request_ReportService_UpdateReportConfiguration_0(ctx context.Context, mars if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.UpdateReportConfiguration(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -114,15 +114,15 @@ func request_ReportService_ListReportConfigurations_0(ctx context.Context, marsh protoReq RawQuery metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ReportService_ListReportConfigurations_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.ListReportConfigurations(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -149,15 +149,15 @@ func request_ReportService_CountReportConfigurations_0(ctx context.Context, mars protoReq RawQuery metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ReportService_CountReportConfigurations_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.CountReportConfigurations(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -183,9 +183,6 @@ func request_ReportService_GetReportConfiguration_0(ctx context.Context, marshal metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -194,6 +191,9 @@ func request_ReportService_GetReportConfiguration_0(ctx context.Context, marshal if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetReportConfiguration(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -222,9 +222,6 @@ func request_ReportService_DeleteReportConfiguration_0(ctx context.Context, mars metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -233,6 +230,9 @@ func request_ReportService_DeleteReportConfiguration_0(ctx context.Context, mars if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.DeleteReportConfiguration(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -261,9 +261,6 @@ func request_ReportService_GetReportStatus_0(ctx context.Context, marshaler runt metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -272,6 +269,9 @@ func request_ReportService_GetReportStatus_0(ctx context.Context, marshaler runt if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetReportStatus(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -302,9 +302,6 @@ func request_ReportService_GetReportHistory_0(ctx context.Context, marshaler run metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -319,6 +316,9 @@ func request_ReportService_GetReportHistory_0(ctx context.Context, marshaler run if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ReportService_GetReportHistory_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetReportHistory(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -355,9 +355,6 @@ func request_ReportService_GetMyReportHistory_0(ctx context.Context, marshaler r metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -372,6 +369,9 @@ func request_ReportService_GetMyReportHistory_0(ctx context.Context, marshaler r if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ReportService_GetMyReportHistory_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetMyReportHistory(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -433,9 +433,6 @@ func request_ReportService_CancelReport_0(ctx context.Context, marshaler runtime metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -444,6 +441,9 @@ func request_ReportService_CancelReport_0(ctx context.Context, marshaler runtime if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.CancelReport(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -472,9 +472,6 @@ func request_ReportService_DeleteReport_0(ctx context.Context, marshaler runtime metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -483,6 +480,9 @@ func request_ReportService_DeleteReport_0(ctx context.Context, marshaler runtime if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.DeleteReport(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -539,15 +539,15 @@ func request_ReportService_GetViewBasedMyReportHistory_0(ctx context.Context, ma protoReq GetViewBasedReportHistoryRequest metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ReportService_GetViewBasedMyReportHistory_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetViewBasedMyReportHistory(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -574,15 +574,15 @@ func request_ReportService_GetViewBasedReportHistory_0(ctx context.Context, mars protoReq GetViewBasedReportHistoryRequest metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ReportService_GetViewBasedReportHistory_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetViewBasedReportHistory(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } diff --git a/generated/api/v2/report_service.swagger.json b/generated/api/v2/report_service.swagger.json index c1dc856396903..15979cc722461 100644 --- a/generated/api/v2/report_service.swagger.json +++ b/generated/api/v2/report_service.swagger.json @@ -827,7 +827,7 @@ "type": "string" } }, - "additionalProperties": {} + "additionalProperties": true }, "rpcStatus": { "type": "object", @@ -1082,7 +1082,7 @@ "NODE_VULNERABILITY" ], "default": "VULNERABILITY", - "title": "- VULNERABILITY: for historical reasons, this short form was used to mean \"Image Vulnerability\"" + "description": "- VULNERABILITY: for historical reasons, this short form was used to mean \"Image Vulnerability\"" }, "v2ReportHistoryResponse": { "type": "object", @@ -1120,7 +1120,7 @@ "NODE_VULNERABILITY" ], "default": "VULNERABILITY", - "title": "- VULNERABILITY: for historical reasons, this short form was used to mean \"Image Vulnerability\"" + "description": "- VULNERABILITY: for historical reasons, this short form was used to mean \"Image Vulnerability\"" }, "v2ReportSchedule": { "type": "object", @@ -1244,7 +1244,7 @@ "NODE_VULNERABILITY" ], "default": "VULNERABILITY", - "title": "- VULNERABILITY: for historical reasons, this short form was used to mean \"Image Vulnerability\"" + "description": "- VULNERABILITY: for historical reasons, this short form was used to mean \"Image Vulnerability\"" }, "v2ReportStatus": { "type": "object", diff --git a/generated/api/v2/scan_component.pb.go b/generated/api/v2/scan_component.pb.go index a28631c792fe7..1c34fc2650d30 100644 --- a/generated/api/v2/scan_component.pb.go +++ b/generated/api/v2/scan_component.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v2/scan_component.proto diff --git a/generated/api/v2/scan_component.swagger.json b/generated/api/v2/scan_component.swagger.json index 37e6f47de61df..e39db57c3cb71 100644 --- a/generated/api/v2/scan_component.swagger.json +++ b/generated/api/v2/scan_component.swagger.json @@ -19,7 +19,7 @@ "type": "string" } }, - "additionalProperties": {} + "additionalProperties": true }, "rpcStatus": { "type": "object", diff --git a/generated/api/v2/search_query.pb.go b/generated/api/v2/search_query.pb.go index bf921ff60f374..af455db782c5b 100644 --- a/generated/api/v2/search_query.pb.go +++ b/generated/api/v2/search_query.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v2/search_query.proto diff --git a/generated/api/v2/search_query.swagger.json b/generated/api/v2/search_query.swagger.json index a67b5c1be7275..7a0a5f48e1d7c 100644 --- a/generated/api/v2/search_query.swagger.json +++ b/generated/api/v2/search_query.swagger.json @@ -19,7 +19,7 @@ "type": "string" } }, - "additionalProperties": {} + "additionalProperties": true }, "rpcStatus": { "type": "object", diff --git a/generated/api/v2/user.pb.go b/generated/api/v2/user.pb.go index 00506829287a8..b594a8bec8d52 100644 --- a/generated/api/v2/user.pb.go +++ b/generated/api/v2/user.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v2/user.proto diff --git a/generated/api/v2/user.swagger.json b/generated/api/v2/user.swagger.json index 1ed06501f69c9..8b56c96e0747c 100644 --- a/generated/api/v2/user.swagger.json +++ b/generated/api/v2/user.swagger.json @@ -19,7 +19,7 @@ "type": "string" } }, - "additionalProperties": {} + "additionalProperties": true }, "rpcStatus": { "type": "object", diff --git a/generated/api/v2/virtual_machine_service.pb.go b/generated/api/v2/virtual_machine_service.pb.go index 3fb3ad8e65eac..2b63475d9a674 100644 --- a/generated/api/v2/virtual_machine_service.pb.go +++ b/generated/api/v2/virtual_machine_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v2/virtual_machine_service.proto diff --git a/generated/api/v2/virtual_machine_service.pb.gw.go b/generated/api/v2/virtual_machine_service.pb.gw.go index 7a0f59a3c2ec1..ab4bf0dc49f3f 100644 --- a/generated/api/v2/virtual_machine_service.pb.gw.go +++ b/generated/api/v2/virtual_machine_service.pb.gw.go @@ -43,9 +43,6 @@ func request_VirtualMachineService_GetVirtualMachine_0(ctx context.Context, mars metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -60,6 +57,9 @@ func request_VirtualMachineService_GetVirtualMachine_0(ctx context.Context, mars if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_VirtualMachineService_GetVirtualMachine_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetVirtualMachine(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -95,15 +95,15 @@ func request_VirtualMachineService_ListVirtualMachines_0(ctx context.Context, ma protoReq ListVirtualMachinesRequest metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_VirtualMachineService_ListVirtualMachines_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.ListVirtualMachines(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } diff --git a/generated/api/v2/virtual_machine_service.swagger.json b/generated/api/v2/virtual_machine_service.swagger.json index 56c1d376a8f96..f2ca8f52bee04 100644 --- a/generated/api/v2/virtual_machine_service.swagger.json +++ b/generated/api/v2/virtual_machine_service.swagger.json @@ -201,7 +201,7 @@ "type": "string" } }, - "additionalProperties": {} + "additionalProperties": true }, "rpcStatus": { "type": "object", diff --git a/generated/api/v2/virtual_machine_v2_service.pb.go b/generated/api/v2/virtual_machine_v2_service.pb.go index 61bd7b26f1f40..f57b4bf3b44e3 100644 --- a/generated/api/v2/virtual_machine_v2_service.pb.go +++ b/generated/api/v2/virtual_machine_v2_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v2/virtual_machine_v2_service.proto diff --git a/generated/api/v2/virtual_machine_v2_service.pb.gw.go b/generated/api/v2/virtual_machine_v2_service.pb.gw.go index 1ed2bd3562d05..aeafc249b1ffc 100644 --- a/generated/api/v2/virtual_machine_v2_service.pb.gw.go +++ b/generated/api/v2/virtual_machine_v2_service.pb.gw.go @@ -41,9 +41,6 @@ func request_VirtualMachineV2Service_GetVM_0(ctx context.Context, marshaler runt metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -52,6 +49,9 @@ func request_VirtualMachineV2Service_GetVM_0(ctx context.Context, marshaler runt if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetVM(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -82,9 +82,6 @@ func request_VirtualMachineV2Service_GetVMVulnSummary_0(ctx context.Context, mar metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -99,6 +96,9 @@ func request_VirtualMachineV2Service_GetVMVulnSummary_0(ctx context.Context, mar if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_VirtualMachineV2Service_GetVMVulnSummary_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetVMVulnSummary(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -135,9 +135,6 @@ func request_VirtualMachineV2Service_ListVMCVEsByVM_0(ctx context.Context, marsh metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["vm_id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "vm_id") @@ -152,6 +149,9 @@ func request_VirtualMachineV2Service_ListVMCVEsByVM_0(ctx context.Context, marsh if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_VirtualMachineV2Service_ListVMCVEsByVM_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.ListVMCVEsByVM(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -186,9 +186,6 @@ func request_VirtualMachineV2Service_GetVMCVEComponents_0(ctx context.Context, m metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["vm_id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "vm_id") @@ -205,6 +202,9 @@ func request_VirtualMachineV2Service_GetVMCVEComponents_0(ctx context.Context, m if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "cve_id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetVMCVEComponents(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -243,9 +243,6 @@ func request_VirtualMachineV2Service_ListVMComponents_0(ctx context.Context, mar metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["vm_id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "vm_id") @@ -260,6 +257,9 @@ func request_VirtualMachineV2Service_ListVMComponents_0(ctx context.Context, mar if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_VirtualMachineV2Service_ListVMComponents_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.ListVMComponents(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -295,15 +295,15 @@ func request_VirtualMachineV2Service_ListVMs_0(ctx context.Context, marshaler ru protoReq ListVMsRequest metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_VirtualMachineV2Service_ListVMs_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.ListVMs(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -330,15 +330,15 @@ func request_VirtualMachineV2Service_ListVMCVEs_0(ctx context.Context, marshaler protoReq ListVMCVEsRequest metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_VirtualMachineV2Service_ListVMCVEs_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.ListVMCVEs(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -365,15 +365,15 @@ func request_VirtualMachineV2Service_GetVMDashboardCounts_0(ctx context.Context, protoReq VMDashboardCountsRequest metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_VirtualMachineV2Service_GetVMDashboardCounts_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetVMDashboardCounts(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -401,9 +401,6 @@ func request_VirtualMachineV2Service_GetVMCVEDetail_0(ctx context.Context, marsh metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["cve_id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "cve_id") @@ -418,6 +415,9 @@ func request_VirtualMachineV2Service_GetVMCVEDetail_0(ctx context.Context, marsh if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_VirtualMachineV2Service_GetVMCVEDetail_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetVMCVEDetail(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -454,9 +454,6 @@ func request_VirtualMachineV2Service_ListVMCVEAffectedVMs_0(ctx context.Context, metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["cve_id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "cve_id") @@ -471,6 +468,9 @@ func request_VirtualMachineV2Service_ListVMCVEAffectedVMs_0(ctx context.Context, if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_VirtualMachineV2Service_ListVMCVEAffectedVMs_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.ListVMCVEAffectedVMs(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } diff --git a/generated/api/v2/virtual_machine_v2_service.swagger.json b/generated/api/v2/virtual_machine_v2_service.swagger.json index 39b003a344de8..61fb2417aa70e 100644 --- a/generated/api/v2/virtual_machine_v2_service.swagger.json +++ b/generated/api/v2/virtual_machine_v2_service.swagger.json @@ -6,7 +6,8 @@ }, "tags": [ { - "name": "VirtualMachineV2Service" + "name": "VirtualMachineV2Service", + "description": "NOTE: RPC ordering matters for grpc-gateway routing. The gateway prepends\neach handler (last registered = first matched), so wildcard routes like\n{id} must be defined FIRST to end up at the back of the matching list.\nLiteral routes defined after will match before the wildcard." } ], "consumes": [ @@ -731,7 +732,7 @@ "type": "string" } }, - "additionalProperties": {} + "additionalProperties": true }, "rpcStatus": { "type": "object", diff --git a/generated/api/v2/vuln_exception_service.pb.go b/generated/api/v2/vuln_exception_service.pb.go index 4fc43b0fba1fa..e7bc42d269992 100644 --- a/generated/api/v2/vuln_exception_service.pb.go +++ b/generated/api/v2/vuln_exception_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v2/vuln_exception_service.proto diff --git a/generated/api/v2/vuln_exception_service.pb.gw.go b/generated/api/v2/vuln_exception_service.pb.gw.go index c2cf3ff4bdc5c..f2132de0f7ad9 100644 --- a/generated/api/v2/vuln_exception_service.pb.gw.go +++ b/generated/api/v2/vuln_exception_service.pb.gw.go @@ -41,9 +41,6 @@ func request_VulnerabilityExceptionService_GetVulnerabilityException_0(ctx conte metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -52,6 +49,9 @@ func request_VulnerabilityExceptionService_GetVulnerabilityException_0(ctx conte if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetVulnerabilityException(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -81,15 +81,15 @@ func request_VulnerabilityExceptionService_ListVulnerabilityExceptions_0(ctx con protoReq RawQuery metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_VulnerabilityExceptionService_ListVulnerabilityExceptions_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.ListVulnerabilityExceptions(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -172,9 +172,6 @@ func request_VulnerabilityExceptionService_ApproveVulnerabilityException_0(ctx c if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -183,6 +180,9 @@ func request_VulnerabilityExceptionService_ApproveVulnerabilityException_0(ctx c if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.ApproveVulnerabilityException(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -217,9 +217,6 @@ func request_VulnerabilityExceptionService_DenyVulnerabilityException_0(ctx cont if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -228,6 +225,9 @@ func request_VulnerabilityExceptionService_DenyVulnerabilityException_0(ctx cont if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.DenyVulnerabilityException(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -262,9 +262,6 @@ func request_VulnerabilityExceptionService_UpdateVulnerabilityException_0(ctx co if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -273,6 +270,9 @@ func request_VulnerabilityExceptionService_UpdateVulnerabilityException_0(ctx co if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.UpdateVulnerabilityException(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -304,9 +304,6 @@ func request_VulnerabilityExceptionService_CancelVulnerabilityException_0(ctx co metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -315,6 +312,9 @@ func request_VulnerabilityExceptionService_CancelVulnerabilityException_0(ctx co if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.CancelVulnerabilityException(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -343,9 +343,6 @@ func request_VulnerabilityExceptionService_DeleteVulnerabilityException_0(ctx co metadata runtime.ServerMetadata err error ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } val, ok := pathParams["id"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") @@ -354,6 +351,9 @@ func request_VulnerabilityExceptionService_DeleteVulnerabilityException_0(ctx co if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.DeleteVulnerabilityException(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } diff --git a/generated/api/v2/vuln_exception_service.swagger.json b/generated/api/v2/vuln_exception_service.swagger.json index 6bb1cd47996dc..a3a594ed8a3aa 100644 --- a/generated/api/v2/vuln_exception_service.swagger.json +++ b/generated/api/v2/vuln_exception_service.swagger.json @@ -6,7 +6,8 @@ }, "tags": [ { - "name": "VulnerabilityExceptionService" + "name": "VulnerabilityExceptionService", + "description": "VulnerabilityExceptionService APIs can be used to manage create and manage vulnerability exceptions." } ], "consumes": [ @@ -434,7 +435,7 @@ "type": "string" } }, - "additionalProperties": {} + "additionalProperties": true }, "rpcStatus": { "type": "object", diff --git a/generated/api/v2/vuln_state.pb.go b/generated/api/v2/vuln_state.pb.go index c37d616e94f1b..6edbc792a07a8 100644 --- a/generated/api/v2/vuln_state.pb.go +++ b/generated/api/v2/vuln_state.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v2/vuln_state.proto diff --git a/generated/api/v2/vuln_state.swagger.json b/generated/api/v2/vuln_state.swagger.json index 0372de17c8984..0959fceaecdd8 100644 --- a/generated/api/v2/vuln_state.swagger.json +++ b/generated/api/v2/vuln_state.swagger.json @@ -19,7 +19,7 @@ "type": "string" } }, - "additionalProperties": {} + "additionalProperties": true }, "rpcStatus": { "type": "object", diff --git a/generated/api/v2/vulnerability.pb.go b/generated/api/v2/vulnerability.pb.go index 18099224a6193..0da91357ddea9 100644 --- a/generated/api/v2/vulnerability.pb.go +++ b/generated/api/v2/vulnerability.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: api/v2/vulnerability.proto diff --git a/generated/api/v2/vulnerability.swagger.json b/generated/api/v2/vulnerability.swagger.json index 70308da40b4aa..f81ff3d4cfdba 100644 --- a/generated/api/v2/vulnerability.swagger.json +++ b/generated/api/v2/vulnerability.swagger.json @@ -19,7 +19,7 @@ "type": "string" } }, - "additionalProperties": {} + "additionalProperties": true }, "rpcStatus": { "type": "object", diff --git a/generated/internalapi/central/auth.pb.go b/generated/internalapi/central/auth.pb.go index 98310971c11fa..0dbfada5ec090 100644 --- a/generated/internalapi/central/auth.pb.go +++ b/generated/internalapi/central/auth.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: internalapi/central/auth.proto diff --git a/generated/internalapi/central/baseline_sync.pb.go b/generated/internalapi/central/baseline_sync.pb.go index f4d7faf9c78a6..03f6b169863ae 100644 --- a/generated/internalapi/central/baseline_sync.pb.go +++ b/generated/internalapi/central/baseline_sync.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: internalapi/central/baseline_sync.proto diff --git a/generated/internalapi/central/cluster_config.pb.go b/generated/internalapi/central/cluster_config.pb.go index d9340b258415d..a0edcdf059287 100644 --- a/generated/internalapi/central/cluster_config.pb.go +++ b/generated/internalapi/central/cluster_config.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: internalapi/central/cluster_config.proto diff --git a/generated/internalapi/central/cluster_metrics.pb.go b/generated/internalapi/central/cluster_metrics.pb.go index db9f16eb351f9..cdf3289ee21d9 100644 --- a/generated/internalapi/central/cluster_metrics.pb.go +++ b/generated/internalapi/central/cluster_metrics.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: internalapi/central/cluster_metrics.proto diff --git a/generated/internalapi/central/cluster_status.pb.go b/generated/internalapi/central/cluster_status.pb.go index 469bf3766797d..b33a449c6d802 100644 --- a/generated/internalapi/central/cluster_status.pb.go +++ b/generated/internalapi/central/cluster_status.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: internalapi/central/cluster_status.proto diff --git a/generated/internalapi/central/compliance_operator.pb.go b/generated/internalapi/central/compliance_operator.pb.go index ded411391134d..49c13bbf8686c 100644 --- a/generated/internalapi/central/compliance_operator.pb.go +++ b/generated/internalapi/central/compliance_operator.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: internalapi/central/compliance_operator.proto diff --git a/generated/internalapi/central/delegated_registry_config.pb.go b/generated/internalapi/central/delegated_registry_config.pb.go index 2b52fcd7c6deb..6fcdf4cb2f17a 100644 --- a/generated/internalapi/central/delegated_registry_config.pb.go +++ b/generated/internalapi/central/delegated_registry_config.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: internalapi/central/delegated_registry_config.proto diff --git a/generated/internalapi/central/deployment_enhancement.pb.go b/generated/internalapi/central/deployment_enhancement.pb.go index e8efe5675e331..82700235ecd76 100644 --- a/generated/internalapi/central/deployment_enhancement.pb.go +++ b/generated/internalapi/central/deployment_enhancement.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: internalapi/central/deployment_enhancement.proto diff --git a/generated/internalapi/central/development_service.pb.go b/generated/internalapi/central/development_service.pb.go index d5beefb4c85e6..80058f8093a05 100644 --- a/generated/internalapi/central/development_service.pb.go +++ b/generated/internalapi/central/development_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: internalapi/central/development_service.proto diff --git a/generated/internalapi/central/development_service.pb.gw.go b/generated/internalapi/central/development_service.pb.gw.go index 1de6586c60742..21ba64121e2dd 100644 --- a/generated/internalapi/central/development_service.pb.gw.go +++ b/generated/internalapi/central/development_service.pb.gw.go @@ -69,15 +69,15 @@ func request_DevelopmentService_URLHasValidCert_0(ctx context.Context, marshaler protoReq URLHasValidCertRequest metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_DevelopmentService_URLHasValidCert_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.URLHasValidCert(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -104,15 +104,15 @@ func request_DevelopmentService_RandomData_0(ctx context.Context, marshaler runt protoReq RandomDataRequest metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_DevelopmentService_RandomData_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.RandomData(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } diff --git a/generated/internalapi/central/hello.pb.go b/generated/internalapi/central/hello.pb.go index 874368738bfee..5720311cf4bdd 100644 --- a/generated/internalapi/central/hello.pb.go +++ b/generated/internalapi/central/hello.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: internalapi/central/hello.proto diff --git a/generated/internalapi/central/image.pb.go b/generated/internalapi/central/image.pb.go index 25305a6e5585c..85e1a447b3475 100644 --- a/generated/internalapi/central/image.pb.go +++ b/generated/internalapi/central/image.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: internalapi/central/image.proto diff --git a/generated/internalapi/central/local_scanner.pb.go b/generated/internalapi/central/local_scanner.pb.go index 803964ec1fbbd..2209659e9768b 100644 --- a/generated/internalapi/central/local_scanner.pb.go +++ b/generated/internalapi/central/local_scanner.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: internalapi/central/local_scanner.proto diff --git a/generated/internalapi/central/network_baseline_sync.pb.go b/generated/internalapi/central/network_baseline_sync.pb.go index aec1571dd98d8..d2a1090fdcbc8 100644 --- a/generated/internalapi/central/network_baseline_sync.pb.go +++ b/generated/internalapi/central/network_baseline_sync.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: internalapi/central/network_baseline_sync.proto diff --git a/generated/internalapi/central/network_flow.pb.go b/generated/internalapi/central/network_flow.pb.go index fb9f918627c6f..ea6da89962369 100644 --- a/generated/internalapi/central/network_flow.pb.go +++ b/generated/internalapi/central/network_flow.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: internalapi/central/network_flow.proto diff --git a/generated/internalapi/central/policy_sync.pb.go b/generated/internalapi/central/policy_sync.pb.go index 532b9c8020cff..8477cde92b692 100644 --- a/generated/internalapi/central/policy_sync.pb.go +++ b/generated/internalapi/central/policy_sync.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: internalapi/central/policy_sync.proto diff --git a/generated/internalapi/central/process_listening_on_ports_update.pb.go b/generated/internalapi/central/process_listening_on_ports_update.pb.go index 87aabe9a70a6e..0adb573d5fc14 100644 --- a/generated/internalapi/central/process_listening_on_ports_update.pb.go +++ b/generated/internalapi/central/process_listening_on_ports_update.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: internalapi/central/process_listening_on_ports_update.proto diff --git a/generated/internalapi/central/secured_cluster_cert_refresh.pb.go b/generated/internalapi/central/secured_cluster_cert_refresh.pb.go index d29951663abb5..2a8aa24d86315 100644 --- a/generated/internalapi/central/secured_cluster_cert_refresh.pb.go +++ b/generated/internalapi/central/secured_cluster_cert_refresh.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: internalapi/central/secured_cluster_cert_refresh.proto diff --git a/generated/internalapi/central/sensor_events.pb.go b/generated/internalapi/central/sensor_events.pb.go index 3a567cb1fb43e..32c8efbcc3d04 100644 --- a/generated/internalapi/central/sensor_events.pb.go +++ b/generated/internalapi/central/sensor_events.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: internalapi/central/sensor_events.proto diff --git a/generated/internalapi/central/sensor_iservice.pb.go b/generated/internalapi/central/sensor_iservice.pb.go index 61ca5245e77b4..835caba41697b 100644 --- a/generated/internalapi/central/sensor_iservice.pb.go +++ b/generated/internalapi/central/sensor_iservice.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: internalapi/central/sensor_iservice.proto diff --git a/generated/internalapi/central/sensor_upgrade.pb.go b/generated/internalapi/central/sensor_upgrade.pb.go index 0217c7996b8ce..03e18f908e9c5 100644 --- a/generated/internalapi/central/sensor_upgrade.pb.go +++ b/generated/internalapi/central/sensor_upgrade.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: internalapi/central/sensor_upgrade.proto diff --git a/generated/internalapi/central/sensor_upgrade_ctrl_iservice.pb.go b/generated/internalapi/central/sensor_upgrade_ctrl_iservice.pb.go index 11ed075adf498..cf8e6b1027d39 100644 --- a/generated/internalapi/central/sensor_upgrade_ctrl_iservice.pb.go +++ b/generated/internalapi/central/sensor_upgrade_ctrl_iservice.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: internalapi/central/sensor_upgrade_ctrl_iservice.proto diff --git a/generated/internalapi/central/telemetry.pb.go b/generated/internalapi/central/telemetry.pb.go index fff1ae98a6a00..a21c999c5b8c1 100644 --- a/generated/internalapi/central/telemetry.pb.go +++ b/generated/internalapi/central/telemetry.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: internalapi/central/telemetry.proto diff --git a/generated/internalapi/central/v1/token_service.pb.go b/generated/internalapi/central/v1/token_service.pb.go index 44d13cacd94c5..e8045d252b33b 100644 --- a/generated/internalapi/central/v1/token_service.pb.go +++ b/generated/internalapi/central/v1/token_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: internalapi/central/v1/token_service.proto diff --git a/generated/internalapi/central/v1/token_service.pb.gw.go b/generated/internalapi/central/v1/token_service.pb.gw.go index 7d726f38314dd..ee94c3884fed2 100644 --- a/generated/internalapi/central/v1/token_service.pb.gw.go +++ b/generated/internalapi/central/v1/token_service.pb.gw.go @@ -42,15 +42,15 @@ func request_TokenService_GenerateTokenForPermissionsAndScope_0(ctx context.Cont protoReq GenerateTokenForPermissionsAndScopeRequest metadata runtime.ServerMetadata ) - if req.Body != nil { - _, _ = io.Copy(io.Discard, req.Body) - } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_TokenService_GenerateTokenForPermissionsAndScope_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GenerateTokenForPermissionsAndScope(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } diff --git a/generated/internalapi/compliance/compliance_data.pb.go b/generated/internalapi/compliance/compliance_data.pb.go index f83af5017b2c2..e9eef707766e8 100644 --- a/generated/internalapi/compliance/compliance_data.pb.go +++ b/generated/internalapi/compliance/compliance_data.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: internalapi/compliance/compliance_data.proto diff --git a/generated/internalapi/scanner/v4/common.pb.go b/generated/internalapi/scanner/v4/common.pb.go index 0e880bdfa519d..67299462678e8 100644 --- a/generated/internalapi/scanner/v4/common.pb.go +++ b/generated/internalapi/scanner/v4/common.pb.go @@ -4,7 +4,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: internalapi/scanner/v4/common.proto diff --git a/generated/internalapi/scanner/v4/index_report.pb.go b/generated/internalapi/scanner/v4/index_report.pb.go index 8ef70bab7f8ec..ef57844231a47 100644 --- a/generated/internalapi/scanner/v4/index_report.pb.go +++ b/generated/internalapi/scanner/v4/index_report.pb.go @@ -3,7 +3,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: internalapi/scanner/v4/index_report.proto diff --git a/generated/internalapi/scanner/v4/indexer_service.pb.go b/generated/internalapi/scanner/v4/indexer_service.pb.go index 5febdad9a7344..aea3b37eed023 100644 --- a/generated/internalapi/scanner/v4/indexer_service.pb.go +++ b/generated/internalapi/scanner/v4/indexer_service.pb.go @@ -4,7 +4,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: internalapi/scanner/v4/indexer_service.proto diff --git a/generated/internalapi/scanner/v4/matcher_service.pb.go b/generated/internalapi/scanner/v4/matcher_service.pb.go index 93368d7f63fa2..c3b614afc7077 100644 --- a/generated/internalapi/scanner/v4/matcher_service.pb.go +++ b/generated/internalapi/scanner/v4/matcher_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: internalapi/scanner/v4/matcher_service.proto diff --git a/generated/internalapi/scanner/v4/vulnerability_report.pb.go b/generated/internalapi/scanner/v4/vulnerability_report.pb.go index 3bd16abc49155..ffab5a0dbef8a 100644 --- a/generated/internalapi/scanner/v4/vulnerability_report.pb.go +++ b/generated/internalapi/scanner/v4/vulnerability_report.pb.go @@ -4,7 +4,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: internalapi/scanner/v4/vulnerability_report.proto diff --git a/generated/internalapi/sensor/admission_control.pb.go b/generated/internalapi/sensor/admission_control.pb.go index c43f3c244cb34..c1adff451079a 100644 --- a/generated/internalapi/sensor/admission_control.pb.go +++ b/generated/internalapi/sensor/admission_control.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: internalapi/sensor/admission_control.proto diff --git a/generated/internalapi/sensor/admission_control_iservice.pb.go b/generated/internalapi/sensor/admission_control_iservice.pb.go index e01e909a96d3e..e9cb91ee552f6 100644 --- a/generated/internalapi/sensor/admission_control_iservice.pb.go +++ b/generated/internalapi/sensor/admission_control_iservice.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: internalapi/sensor/admission_control_iservice.proto diff --git a/generated/internalapi/sensor/collector.pb.go b/generated/internalapi/sensor/collector.pb.go index 2a95c1d7facd3..f9ef7f7c936e3 100644 --- a/generated/internalapi/sensor/collector.pb.go +++ b/generated/internalapi/sensor/collector.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: internalapi/sensor/collector.proto diff --git a/generated/internalapi/sensor/collector_iservice.pb.go b/generated/internalapi/sensor/collector_iservice.pb.go index 96efa3e0321b9..9d48eda3a6234 100644 --- a/generated/internalapi/sensor/collector_iservice.pb.go +++ b/generated/internalapi/sensor/collector_iservice.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: internalapi/sensor/collector_iservice.proto diff --git a/generated/internalapi/sensor/compliance_iservice.pb.go b/generated/internalapi/sensor/compliance_iservice.pb.go index 041c11c982e9e..fb1533932bca2 100644 --- a/generated/internalapi/sensor/compliance_iservice.pb.go +++ b/generated/internalapi/sensor/compliance_iservice.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: internalapi/sensor/compliance_iservice.proto diff --git a/generated/internalapi/sensor/deployment_iservice.pb.go b/generated/internalapi/sensor/deployment_iservice.pb.go index 82e9efadd2409..23963030dfb0e 100644 --- a/generated/internalapi/sensor/deployment_iservice.pb.go +++ b/generated/internalapi/sensor/deployment_iservice.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: internalapi/sensor/deployment_iservice.proto diff --git a/generated/internalapi/sensor/fact.pb.go b/generated/internalapi/sensor/fact.pb.go index 1c5fac5e74654..11d3811fbace7 100644 --- a/generated/internalapi/sensor/fact.pb.go +++ b/generated/internalapi/sensor/fact.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: internalapi/sensor/fact.proto diff --git a/generated/internalapi/sensor/image_iservice.pb.go b/generated/internalapi/sensor/image_iservice.pb.go index 21c13768dfd81..1827aa49de2f9 100644 --- a/generated/internalapi/sensor/image_iservice.pb.go +++ b/generated/internalapi/sensor/image_iservice.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: internalapi/sensor/image_iservice.proto diff --git a/generated/internalapi/sensor/network_connection_info.pb.go b/generated/internalapi/sensor/network_connection_info.pb.go index 1e4dea02732ec..80cb31835ed4b 100644 --- a/generated/internalapi/sensor/network_connection_info.pb.go +++ b/generated/internalapi/sensor/network_connection_info.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: internalapi/sensor/network_connection_info.proto diff --git a/generated/internalapi/sensor/network_connection_iservice.pb.go b/generated/internalapi/sensor/network_connection_iservice.pb.go index 832a4e7718f1a..205af81b2f734 100644 --- a/generated/internalapi/sensor/network_connection_iservice.pb.go +++ b/generated/internalapi/sensor/network_connection_iservice.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: internalapi/sensor/network_connection_iservice.proto diff --git a/generated/internalapi/sensor/network_enums.pb.go b/generated/internalapi/sensor/network_enums.pb.go index 745fdb6eca418..3e5af29aa0212 100644 --- a/generated/internalapi/sensor/network_enums.pb.go +++ b/generated/internalapi/sensor/network_enums.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: internalapi/sensor/network_enums.proto diff --git a/generated/internalapi/sensor/sfa.pb.go b/generated/internalapi/sensor/sfa.pb.go index 7e484946ff09a..5b692eb8ede3a 100644 --- a/generated/internalapi/sensor/sfa.pb.go +++ b/generated/internalapi/sensor/sfa.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: internalapi/sensor/sfa.proto diff --git a/generated/internalapi/sensor/sfa_iservice.pb.go b/generated/internalapi/sensor/sfa_iservice.pb.go index acbc88d078122..a0fe9781bdf8d 100644 --- a/generated/internalapi/sensor/sfa_iservice.pb.go +++ b/generated/internalapi/sensor/sfa_iservice.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: internalapi/sensor/sfa_iservice.proto diff --git a/generated/internalapi/sensor/signal_iservice.pb.go b/generated/internalapi/sensor/signal_iservice.pb.go index f719986c05bdf..a60cecc1da7e1 100644 --- a/generated/internalapi/sensor/signal_iservice.pb.go +++ b/generated/internalapi/sensor/signal_iservice.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: internalapi/sensor/signal_iservice.proto diff --git a/generated/internalapi/virtualmachine/v1/index_report.pb.go b/generated/internalapi/virtualmachine/v1/index_report.pb.go index 61269d35286d4..f82fea0df92c2 100644 --- a/generated/internalapi/virtualmachine/v1/index_report.pb.go +++ b/generated/internalapi/virtualmachine/v1/index_report.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: internalapi/virtualmachine/v1/index_report.proto diff --git a/generated/internalapi/virtualmachine/v1/virtual_machine.pb.go b/generated/internalapi/virtualmachine/v1/virtual_machine.pb.go index 5921d62ac5a53..a68ca4d0d3d13 100644 --- a/generated/internalapi/virtualmachine/v1/virtual_machine.pb.go +++ b/generated/internalapi/virtualmachine/v1/virtual_machine.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: internalapi/virtualmachine/v1/virtual_machine.proto diff --git a/generated/internalapi/virtualmachine/v1/vm_service.pb.go b/generated/internalapi/virtualmachine/v1/vm_service.pb.go index 0944d64b27b20..e209febc395c0 100644 --- a/generated/internalapi/virtualmachine/v1/vm_service.pb.go +++ b/generated/internalapi/virtualmachine/v1/vm_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: internalapi/virtualmachine/v1/vm_service.proto diff --git a/generated/internalapi/wrapper/splunk_alert.pb.go b/generated/internalapi/wrapper/splunk_alert.pb.go index 5f337f671b73b..e9059584398c6 100644 --- a/generated/internalapi/wrapper/splunk_alert.pb.go +++ b/generated/internalapi/wrapper/splunk_alert.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: internalapi/wrapper/splunk_alert.proto diff --git a/generated/storage/administration_event.pb.go b/generated/storage/administration_event.pb.go index df9d45e84de39..e9be271076741 100644 --- a/generated/storage/administration_event.pb.go +++ b/generated/storage/administration_event.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/administration_event.proto diff --git a/generated/storage/administration_usage.pb.go b/generated/storage/administration_usage.pb.go index 6dd7fe42016e1..5a47c7315b122 100644 --- a/generated/storage/administration_usage.pb.go +++ b/generated/storage/administration_usage.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/administration_usage.proto diff --git a/generated/storage/alert.pb.go b/generated/storage/alert.pb.go index 5efdec723b73f..0cb19c88a4b7b 100644 --- a/generated/storage/alert.pb.go +++ b/generated/storage/alert.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/alert.proto diff --git a/generated/storage/api_token.pb.go b/generated/storage/api_token.pb.go index 553d80929e232..ccf6a95ad4ece 100644 --- a/generated/storage/api_token.pb.go +++ b/generated/storage/api_token.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/api_token.proto diff --git a/generated/storage/auth_machine_to_machine.pb.go b/generated/storage/auth_machine_to_machine.pb.go index 75595ab528119..8dee2c425a520 100644 --- a/generated/storage/auth_machine_to_machine.pb.go +++ b/generated/storage/auth_machine_to_machine.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/auth_machine_to_machine.proto diff --git a/generated/storage/auth_provider.pb.go b/generated/storage/auth_provider.pb.go index 116d32ff70de4..6894934e299ac 100644 --- a/generated/storage/auth_provider.pb.go +++ b/generated/storage/auth_provider.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/auth_provider.proto diff --git a/generated/storage/base_image.pb.go b/generated/storage/base_image.pb.go index 2302244fc1d57..91e6f9bdd80b6 100644 --- a/generated/storage/base_image.pb.go +++ b/generated/storage/base_image.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/base_image.proto diff --git a/generated/storage/base_image_repository.pb.go b/generated/storage/base_image_repository.pb.go index 98275adf0ee64..71c3665241dbe 100644 --- a/generated/storage/base_image_repository.pb.go +++ b/generated/storage/base_image_repository.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/base_image_repository.proto diff --git a/generated/storage/blob.pb.go b/generated/storage/blob.pb.go index de4cb680fa39d..71f5d355b89d2 100644 --- a/generated/storage/blob.pb.go +++ b/generated/storage/blob.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/blob.proto diff --git a/generated/storage/cloud_source.pb.go b/generated/storage/cloud_source.pb.go index 645bc74b61d5a..512ac32e377cb 100644 --- a/generated/storage/cloud_source.pb.go +++ b/generated/storage/cloud_source.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/cloud_source.proto diff --git a/generated/storage/cluster.pb.go b/generated/storage/cluster.pb.go index b032df461b173..6b327ad571102 100644 --- a/generated/storage/cluster.pb.go +++ b/generated/storage/cluster.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/cluster.proto diff --git a/generated/storage/cluster_init.pb.go b/generated/storage/cluster_init.pb.go index e145a4a0f8d52..76809c3446204 100644 --- a/generated/storage/cluster_init.pb.go +++ b/generated/storage/cluster_init.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/cluster_init.proto diff --git a/generated/storage/common.pb.go b/generated/storage/common.pb.go index 0019e4dfbfa26..5de76e47c3144 100644 --- a/generated/storage/common.pb.go +++ b/generated/storage/common.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/common.proto diff --git a/generated/storage/compliance.pb.go b/generated/storage/compliance.pb.go index a50a75801c3f2..c1747d82f5353 100644 --- a/generated/storage/compliance.pb.go +++ b/generated/storage/compliance.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/compliance.proto diff --git a/generated/storage/compliance_config.pb.go b/generated/storage/compliance_config.pb.go index 2c2541f8c00bb..39f7b1941bf93 100644 --- a/generated/storage/compliance_config.pb.go +++ b/generated/storage/compliance_config.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/compliance_config.proto diff --git a/generated/storage/compliance_integration.pb.go b/generated/storage/compliance_integration.pb.go index 43ba8b37010b3..2ea6bb1a2d1cb 100644 --- a/generated/storage/compliance_integration.pb.go +++ b/generated/storage/compliance_integration.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/compliance_integration.proto diff --git a/generated/storage/compliance_operator.pb.go b/generated/storage/compliance_operator.pb.go index 22e7bc33f22b9..09a4962f8d3c6 100644 --- a/generated/storage/compliance_operator.pb.go +++ b/generated/storage/compliance_operator.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/compliance_operator.proto diff --git a/generated/storage/compliance_operator_v2.pb.go b/generated/storage/compliance_operator_v2.pb.go index 5ad5bbeb070b2..a6d253464298f 100644 --- a/generated/storage/compliance_operator_v2.pb.go +++ b/generated/storage/compliance_operator_v2.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/compliance_operator_v2.proto diff --git a/generated/storage/config.pb.go b/generated/storage/config.pb.go index d0e5a336d1bec..96c75b18bff25 100644 --- a/generated/storage/config.pb.go +++ b/generated/storage/config.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/config.proto diff --git a/generated/storage/container_runtime.pb.go b/generated/storage/container_runtime.pb.go index 5b0cbfc4c857b..2aff805dfac12 100644 --- a/generated/storage/container_runtime.pb.go +++ b/generated/storage/container_runtime.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/container_runtime.proto diff --git a/generated/storage/cve.pb.go b/generated/storage/cve.pb.go index a3d5625cef0b2..62dd566ae5313 100644 --- a/generated/storage/cve.pb.go +++ b/generated/storage/cve.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/cve.proto diff --git a/generated/storage/declarative_config_health.pb.go b/generated/storage/declarative_config_health.pb.go index 2774a543154a8..ab8ae734357da 100644 --- a/generated/storage/declarative_config_health.pb.go +++ b/generated/storage/declarative_config_health.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/declarative_config_health.proto diff --git a/generated/storage/delegated_registry_config.pb.go b/generated/storage/delegated_registry_config.pb.go index e95aa9ab08de4..0c37b53103134 100644 --- a/generated/storage/delegated_registry_config.pb.go +++ b/generated/storage/delegated_registry_config.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/delegated_registry_config.proto diff --git a/generated/storage/deployment.pb.go b/generated/storage/deployment.pb.go index 652446d8996e5..e239a6b485255 100644 --- a/generated/storage/deployment.pb.go +++ b/generated/storage/deployment.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/deployment.proto diff --git a/generated/storage/discovered_cluster.pb.go b/generated/storage/discovered_cluster.pb.go index 305e3e5415b3d..44af51e85fd49 100644 --- a/generated/storage/discovered_cluster.pb.go +++ b/generated/storage/discovered_cluster.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/discovered_cluster.proto diff --git a/generated/storage/external_backup.pb.go b/generated/storage/external_backup.pb.go index 139ce582c3ace..a3abba232dbe3 100644 --- a/generated/storage/external_backup.pb.go +++ b/generated/storage/external_backup.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/external_backup.proto diff --git a/generated/storage/file_access.pb.go b/generated/storage/file_access.pb.go index 4c1a916c401b9..af066b531e822 100644 --- a/generated/storage/file_access.pb.go +++ b/generated/storage/file_access.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/file_access.proto diff --git a/generated/storage/group.pb.go b/generated/storage/group.pb.go index 0a7256ef0ca46..6e8dfd698d8d5 100644 --- a/generated/storage/group.pb.go +++ b/generated/storage/group.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/group.proto diff --git a/generated/storage/hash.pb.go b/generated/storage/hash.pb.go index fafb3d2e6e183..af6d811abd811 100644 --- a/generated/storage/hash.pb.go +++ b/generated/storage/hash.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/hash.proto diff --git a/generated/storage/helm_cluster.pb.go b/generated/storage/helm_cluster.pb.go index 6a4925aa0b167..7097f25b31a47 100644 --- a/generated/storage/helm_cluster.pb.go +++ b/generated/storage/helm_cluster.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/helm_cluster.proto diff --git a/generated/storage/http_endpoint.pb.go b/generated/storage/http_endpoint.pb.go index 40c5fe6f9220b..a67789f8acf25 100644 --- a/generated/storage/http_endpoint.pb.go +++ b/generated/storage/http_endpoint.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/http_endpoint.proto diff --git a/generated/storage/image.pb.go b/generated/storage/image.pb.go index 9e7c6399be2c8..514f86d078138 100644 --- a/generated/storage/image.pb.go +++ b/generated/storage/image.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/image.proto diff --git a/generated/storage/image_component.pb.go b/generated/storage/image_component.pb.go index 6f19b3ae98933..f3de77c18fa76 100644 --- a/generated/storage/image_component.pb.go +++ b/generated/storage/image_component.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/image_component.proto diff --git a/generated/storage/image_integration.pb.go b/generated/storage/image_integration.pb.go index a07822bbcd53f..5bd60d6f5a3de 100644 --- a/generated/storage/image_integration.pb.go +++ b/generated/storage/image_integration.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/image_integration.proto diff --git a/generated/storage/image_v2.pb.go b/generated/storage/image_v2.pb.go index 91c8fec274ec4..5ad060b592d96 100644 --- a/generated/storage/image_v2.pb.go +++ b/generated/storage/image_v2.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/image_v2.proto diff --git a/generated/storage/installation.pb.go b/generated/storage/installation.pb.go index 9116f619063db..d4377c57509ca 100644 --- a/generated/storage/installation.pb.go +++ b/generated/storage/installation.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/installation.proto diff --git a/generated/storage/integration_health.pb.go b/generated/storage/integration_health.pb.go index 1db17d2ebdc65..19730f4b31677 100644 --- a/generated/storage/integration_health.pb.go +++ b/generated/storage/integration_health.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/integration_health.proto diff --git a/generated/storage/kube_event.pb.go b/generated/storage/kube_event.pb.go index f16d6361dd25a..dfb2371d0fefb 100644 --- a/generated/storage/kube_event.pb.go +++ b/generated/storage/kube_event.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/kube_event.proto diff --git a/generated/storage/labels.pb.go b/generated/storage/labels.pb.go index efef57b7c92a3..564be4ea5bea5 100644 --- a/generated/storage/labels.pb.go +++ b/generated/storage/labels.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/labels.proto diff --git a/generated/storage/log.pb.go b/generated/storage/log.pb.go index 8d97ea23b666a..ccc10571fb333 100644 --- a/generated/storage/log.pb.go +++ b/generated/storage/log.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/log.proto diff --git a/generated/storage/mitre.pb.go b/generated/storage/mitre.pb.go index ce55aad910033..eae305559454e 100644 --- a/generated/storage/mitre.pb.go +++ b/generated/storage/mitre.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/mitre.proto diff --git a/generated/storage/namespace_metadata.pb.go b/generated/storage/namespace_metadata.pb.go index d1f325690d21a..416992ff47e30 100644 --- a/generated/storage/namespace_metadata.pb.go +++ b/generated/storage/namespace_metadata.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/namespace_metadata.proto diff --git a/generated/storage/network_baseline.pb.go b/generated/storage/network_baseline.pb.go index 5eb542d00dac6..9aeff948794ed 100644 --- a/generated/storage/network_baseline.pb.go +++ b/generated/storage/network_baseline.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/network_baseline.proto diff --git a/generated/storage/network_flow.pb.go b/generated/storage/network_flow.pb.go index f414d43499582..8c1037154ceca 100644 --- a/generated/storage/network_flow.pb.go +++ b/generated/storage/network_flow.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/network_flow.proto diff --git a/generated/storage/network_graph_config.pb.go b/generated/storage/network_graph_config.pb.go index d4d827735d388..f997b69b2bec9 100644 --- a/generated/storage/network_graph_config.pb.go +++ b/generated/storage/network_graph_config.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/network_graph_config.proto diff --git a/generated/storage/network_policy.pb.go b/generated/storage/network_policy.pb.go index 7c54d9d2c5c07..5a024cf1fbcfc 100644 --- a/generated/storage/network_policy.pb.go +++ b/generated/storage/network_policy.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/network_policy.proto diff --git a/generated/storage/node.pb.go b/generated/storage/node.pb.go index cc9988e90a4f6..26f5199b75a28 100644 --- a/generated/storage/node.pb.go +++ b/generated/storage/node.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/node.proto diff --git a/generated/storage/node_component.pb.go b/generated/storage/node_component.pb.go index 11103bf02cf2e..e64871d9945e0 100644 --- a/generated/storage/node_component.pb.go +++ b/generated/storage/node_component.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/node_component.proto diff --git a/generated/storage/node_integration.pb.go b/generated/storage/node_integration.pb.go index 62f2462fc3288..705aba38b1421 100644 --- a/generated/storage/node_integration.pb.go +++ b/generated/storage/node_integration.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/node_integration.proto diff --git a/generated/storage/notification_schedule.pb.go b/generated/storage/notification_schedule.pb.go index b2bbe7ce7762d..5fc49b03dcac7 100644 --- a/generated/storage/notification_schedule.pb.go +++ b/generated/storage/notification_schedule.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/notification_schedule.proto diff --git a/generated/storage/notifier.pb.go b/generated/storage/notifier.pb.go index 251d60ffc26b2..b18b3e0af803d 100644 --- a/generated/storage/notifier.pb.go +++ b/generated/storage/notifier.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/notifier.proto diff --git a/generated/storage/notifier_enc_config.pb.go b/generated/storage/notifier_enc_config.pb.go index 81a3a16a931f3..be1f06c80499c 100644 --- a/generated/storage/notifier_enc_config.pb.go +++ b/generated/storage/notifier_enc_config.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/notifier_enc_config.proto diff --git a/generated/storage/operation_status.pb.go b/generated/storage/operation_status.pb.go index 52d2abff8fa90..3fd6f13c5ba2a 100644 --- a/generated/storage/operation_status.pb.go +++ b/generated/storage/operation_status.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/operation_status.proto diff --git a/generated/storage/orchestrator_integration.pb.go b/generated/storage/orchestrator_integration.pb.go index 11e713af2a7df..76d6ce66b1d1d 100644 --- a/generated/storage/orchestrator_integration.pb.go +++ b/generated/storage/orchestrator_integration.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/orchestrator_integration.proto diff --git a/generated/storage/policy.pb.go b/generated/storage/policy.pb.go index c99de9332733b..bee936d9fb804 100644 --- a/generated/storage/policy.pb.go +++ b/generated/storage/policy.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/policy.proto @@ -392,6 +392,56 @@ func (Comparator) EnumDescriptor() ([]byte, []int) { return file_storage_policy_proto_rawDescGZIP(), []int{6} } +// WorkloadKind is a Kubernetes workload kind that can be excluded from a policy in bulk. +type Exclusion_WorkloadKind int32 + +const ( + Exclusion_WORKLOAD_KIND_UNSPECIFIED Exclusion_WorkloadKind = 0 + Exclusion_CRON_JOB Exclusion_WorkloadKind = 1 + Exclusion_JOB Exclusion_WorkloadKind = 2 +) + +// Enum value maps for Exclusion_WorkloadKind. +var ( + Exclusion_WorkloadKind_name = map[int32]string{ + 0: "WORKLOAD_KIND_UNSPECIFIED", + 1: "CRON_JOB", + 2: "JOB", + } + Exclusion_WorkloadKind_value = map[string]int32{ + "WORKLOAD_KIND_UNSPECIFIED": 0, + "CRON_JOB": 1, + "JOB": 2, + } +) + +func (x Exclusion_WorkloadKind) Enum() *Exclusion_WorkloadKind { + p := new(Exclusion_WorkloadKind) + *p = x + return p +} + +func (x Exclusion_WorkloadKind) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (Exclusion_WorkloadKind) Descriptor() protoreflect.EnumDescriptor { + return file_storage_policy_proto_enumTypes[7].Descriptor() +} + +func (Exclusion_WorkloadKind) Type() protoreflect.EnumType { + return &file_storage_policy_proto_enumTypes[7] +} + +func (x Exclusion_WorkloadKind) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use Exclusion_WorkloadKind.Descriptor instead. +func (Exclusion_WorkloadKind) EnumDescriptor() ([]byte, []int) { + return file_storage_policy_proto_rawDescGZIP(), []int{7, 0} +} + // Next tag: 29 type Policy struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -411,7 +461,7 @@ type Policy struct { LifecycleStages []LifecycleStage `protobuf:"varint,9,rep,packed,name=lifecycle_stages,json=lifecycleStages,proto3,enum=storage.LifecycleStage" json:"lifecycle_stages,omitempty" search:"Lifecycle Stage" crYaml:"lifecycleStages,stringer"` // @gotags: search:"Lifecycle Stage" crYaml:"lifecycleStages,stringer" // Describes which events should trigger execution of this policy EventSource EventSource `protobuf:"varint,22,opt,name=event_source,json=eventSource,proto3,enum=storage.EventSource" json:"event_source,omitempty" crYaml:"eventSource,stringer"` // @gotags: crYaml:"eventSource,stringer" - // Define deployments or images that should be excluded from this policy. + // Define deployments, images, or workload kinds that should be excluded from this policy. Exclusions []*Exclusion `protobuf:"bytes,21,rep,name=exclusions,proto3" json:"exclusions,omitempty" crYaml:",omitempty"` // @gotags: crYaml:",omitempty" // Defines clusters, namespaces, and deployments that should be included in this policy. No scopes defined includes everything. Scope []*Scope `protobuf:"bytes,11,rep,name=scope,proto3" json:"scope,omitempty" crYaml:",omitempty"` // @gotags: crYaml:",omitempty" @@ -1008,7 +1058,7 @@ func (x *ListPolicy) GetEvaluationFilter() *EvaluationFilter { // EvaluationFilter pre-filters which entities a policy evaluates. type EvaluationFilter struct { state protoimpl.MessageState `protogen:"open.v1"` - SkipContainerTypes []ContainerType `protobuf:"varint,1,rep,packed,name=skip_container_types,json=skipContainerTypes,proto3,enum=storage.ContainerType" json:"skip_container_types,omitempty"` + SkipContainerTypes []ContainerType `protobuf:"varint,1,rep,packed,name=skip_container_types,json=skipContainerTypes,proto3,enum=storage.ContainerType" json:"skip_container_types,omitempty" crYaml:"skipContainerTypes,omitempty,stringer"` // @gotags: crYaml:"skipContainerTypes,omitempty,stringer" unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -1051,11 +1101,18 @@ func (x *EvaluationFilter) GetSkipContainerTypes() []ContainerType { } type Exclusion struct { - state protoimpl.MessageState `protogen:"open.v1"` - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty" crYaml:",omitempty"` // @gotags: crYaml:",omitempty" - Deployment *Exclusion_Deployment `protobuf:"bytes,5,opt,name=deployment,proto3" json:"deployment,omitempty" crYaml:",omitempty"` // @gotags: crYaml:",omitempty" - Image *Exclusion_Image `protobuf:"bytes,7,opt,name=image,proto3" json:"image,omitempty" crYaml:",omitempty"` // @gotags: crYaml:",omitempty" - Expiration *timestamppb.Timestamp `protobuf:"bytes,6,opt,name=expiration,proto3" json:"expiration,omitempty" crYaml:",timestamp,omitempty"` // @gotags: crYaml:",timestamp,omitempty" + state protoimpl.MessageState `protogen:"open.v1"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty" crYaml:",omitempty"` // @gotags: crYaml:",omitempty" + Image *Exclusion_Image `protobuf:"bytes,7,opt,name=image,proto3" json:"image,omitempty" crYaml:",omitempty"` // @gotags: crYaml:",omitempty" + Expiration *timestamppb.Timestamp `protobuf:"bytes,6,opt,name=expiration,proto3" json:"expiration,omitempty" crYaml:",timestamp,omitempty"` // @gotags: crYaml:",timestamp,omitempty" + // matcher is either a name/scope exclusion or an exclusion by Kubernetes kind. + // Image stays outside the oneof because existing payloads may set both image and deployment. + // + // Types that are valid to be assigned to Matcher: + // + // *Exclusion_Deployment_ + // *Exclusion_ExcludeByKind_ + Matcher isExclusion_Matcher `protobuf_oneof:"matcher"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -1097,27 +1154,61 @@ func (x *Exclusion) GetName() string { return "" } -func (x *Exclusion) GetDeployment() *Exclusion_Deployment { +func (x *Exclusion) GetImage() *Exclusion_Image { if x != nil { - return x.Deployment + return x.Image } return nil } -func (x *Exclusion) GetImage() *Exclusion_Image { +func (x *Exclusion) GetExpiration() *timestamppb.Timestamp { if x != nil { - return x.Image + return x.Expiration } return nil } -func (x *Exclusion) GetExpiration() *timestamppb.Timestamp { +func (x *Exclusion) GetMatcher() isExclusion_Matcher { if x != nil { - return x.Expiration + return x.Matcher } return nil } +func (x *Exclusion) GetDeployment() *Exclusion_Deployment { + if x != nil { + if x, ok := x.Matcher.(*Exclusion_Deployment_); ok { + return x.Deployment + } + } + return nil +} + +func (x *Exclusion) GetExcludeByKind() *Exclusion_ExcludeByKind { + if x != nil { + if x, ok := x.Matcher.(*Exclusion_ExcludeByKind_); ok { + return x.ExcludeByKind + } + } + return nil +} + +type isExclusion_Matcher interface { + isExclusion_Matcher() +} + +type Exclusion_Deployment_ struct { + Deployment *Exclusion_Deployment `protobuf:"bytes,5,opt,name=deployment,proto3,oneof" crYaml:",omitempty"` // @gotags: crYaml:",omitempty" +} + +type Exclusion_ExcludeByKind_ struct { + ExcludeByKind *Exclusion_ExcludeByKind `protobuf:"bytes,8,opt,name=exclude_by_kind,json=excludeByKind,proto3,oneof" crYaml:"excludeByKind,omitempty"` // @gotags: crYaml:"excludeByKind,omitempty" +} + +func (*Exclusion_Deployment_) isExclusion_Matcher() {} + +func (*Exclusion_ExcludeByKind_) isExclusion_Matcher() {} + // ExportPoliciesResponse is used by the API but it is defined in storage because we expect customers to store them. // We do backwards-compatibility checks on objects in the storge folder and those checks should be applied to this object type ExportPoliciesResponse struct { @@ -1356,6 +1447,51 @@ func (x *Exclusion_Image) GetName() string { return "" } +// ExcludeByKind excludes all workloads of the selected Kubernetes kinds. +type Exclusion_ExcludeByKind struct { + state protoimpl.MessageState `protogen:"open.v1"` + Kinds []Exclusion_WorkloadKind `protobuf:"varint,1,rep,packed,name=kinds,proto3,enum=storage.Exclusion_WorkloadKind" json:"kinds,omitempty" crYaml:",omitempty,stringer"` // @gotags: crYaml:",omitempty,stringer" + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Exclusion_ExcludeByKind) Reset() { + *x = Exclusion_ExcludeByKind{} + mi := &file_storage_policy_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Exclusion_ExcludeByKind) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Exclusion_ExcludeByKind) ProtoMessage() {} + +func (x *Exclusion_ExcludeByKind) ProtoReflect() protoreflect.Message { + mi := &file_storage_policy_proto_msgTypes[13] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Exclusion_ExcludeByKind.ProtoReflect.Descriptor instead. +func (*Exclusion_ExcludeByKind) Descriptor() ([]byte, []int) { + return file_storage_policy_proto_rawDescGZIP(), []int{7, 3} +} + +func (x *Exclusion_ExcludeByKind) GetKinds() []Exclusion_WorkloadKind { + if x != nil { + return x.Kinds + } + return nil +} + var File_storage_policy_proto protoreflect.FileDescriptor const file_storage_policy_proto_rawDesc = "" + @@ -1430,16 +1566,17 @@ const file_storage_policy_proto_rawDesc = "" + "\x06source\x18\v \x01(\x0e2\x15.storage.PolicySourceR\x06source\x12F\n" + "\x11evaluation_filter\x18\f \x01(\v2\x19.storage.EvaluationFilterR\x10evaluationFilter\"\\\n" + "\x10EvaluationFilter\x12H\n" + - "\x14skip_container_types\x18\x01 \x03(\x0e2\x16.storage.ContainerTypeR\x12skipContainerTypes\"\xf5\x02\n" + + "\x14skip_container_types\x18\x01 \x03(\x0e2\x16.storage.ContainerTypeR\x12skipContainerTypes\"\xdc\x04\n" + "\tExclusion\x12\x12\n" + - "\x04name\x18\x01 \x01(\tR\x04name\x12=\n" + - "\n" + - "deployment\x18\x05 \x01(\v2\x1d.storage.Exclusion.DeploymentR\n" + - "deployment\x12.\n" + + "\x04name\x18\x01 \x01(\tR\x04name\x12.\n" + "\x05image\x18\a \x01(\v2\x18.storage.Exclusion.ImageR\x05image\x12:\n" + "\n" + "expiration\x18\x06 \x01(\v2\x1a.google.protobuf.TimestampR\n" + - "expiration\x1a>\n" + + "expiration\x12?\n" + + "\n" + + "deployment\x18\x05 \x01(\v2\x1d.storage.Exclusion.DeploymentH\x00R\n" + + "deployment\x12J\n" + + "\x0fexclude_by_kind\x18\b \x01(\v2 .storage.Exclusion.ExcludeByKindH\x00R\rexcludeByKind\x1a>\n" + "\tContainer\x121\n" + "\n" + "image_name\x18\x03 \x01(\v2\x12.storage.ImageNameR\timageName\x1aF\n" + @@ -1448,7 +1585,14 @@ const file_storage_policy_proto_rawDesc = "" + "\x04name\x18\x03 \x01(\tR\x04name\x12$\n" + "\x05scope\x18\x04 \x01(\v2\x0e.storage.ScopeR\x05scope\x1a\x1b\n" + "\x05Image\x12\x12\n" + - "\x04name\x18\x01 \x01(\tR\x04nameJ\x04\b\x02\x10\x03\"E\n" + + "\x04name\x18\x01 \x01(\tR\x04name\x1aF\n" + + "\rExcludeByKind\x125\n" + + "\x05kinds\x18\x01 \x03(\x0e2\x1f.storage.Exclusion.WorkloadKindR\x05kinds\"D\n" + + "\fWorkloadKind\x12\x1d\n" + + "\x19WORKLOAD_KIND_UNSPECIFIED\x10\x00\x12\f\n" + + "\bCRON_JOB\x10\x01\x12\a\n" + + "\x03JOB\x10\x02B\t\n" + + "\amatcherJ\x04\b\x02\x10\x03\"E\n" + "\x16ExportPoliciesResponse\x12+\n" + "\bpolicies\x18\x01 \x03(\v2\x0f.storage.PolicyR\bpolicies*/\n" + "\fPolicySource\x12\x0e\n" + @@ -1506,8 +1650,8 @@ func file_storage_policy_proto_rawDescGZIP() []byte { return file_storage_policy_proto_rawDescData } -var file_storage_policy_proto_enumTypes = make([]protoimpl.EnumInfo, 7) -var file_storage_policy_proto_msgTypes = make([]protoimpl.MessageInfo, 13) +var file_storage_policy_proto_enumTypes = make([]protoimpl.EnumInfo, 8) +var file_storage_policy_proto_msgTypes = make([]protoimpl.MessageInfo, 14) var file_storage_policy_proto_goTypes = []any{ (PolicySource)(0), // 0: storage.PolicySource (EventSource)(0), // 1: storage.EventSource @@ -1516,58 +1660,62 @@ var file_storage_policy_proto_goTypes = []any{ (Severity)(0), // 4: storage.Severity (LifecycleStage)(0), // 5: storage.LifecycleStage (Comparator)(0), // 6: storage.Comparator - (*Policy)(nil), // 7: storage.Policy - (*PolicySection)(nil), // 8: storage.PolicySection - (*PolicyGroup)(nil), // 9: storage.PolicyGroup - (*PolicyValue)(nil), // 10: storage.PolicyValue - (*PolicyList)(nil), // 11: storage.PolicyList - (*ListPolicy)(nil), // 12: storage.ListPolicy - (*EvaluationFilter)(nil), // 13: storage.EvaluationFilter - (*Exclusion)(nil), // 14: storage.Exclusion - (*ExportPoliciesResponse)(nil), // 15: storage.ExportPoliciesResponse - (*Policy_MitreAttackVectors)(nil), // 16: storage.Policy.MitreAttackVectors - (*Exclusion_Container)(nil), // 17: storage.Exclusion.Container - (*Exclusion_Deployment)(nil), // 18: storage.Exclusion.Deployment - (*Exclusion_Image)(nil), // 19: storage.Exclusion.Image - (*Scope)(nil), // 20: storage.Scope - (*timestamppb.Timestamp)(nil), // 21: google.protobuf.Timestamp - (ContainerType)(0), // 22: storage.ContainerType - (*ImageName)(nil), // 23: storage.ImageName + (Exclusion_WorkloadKind)(0), // 7: storage.Exclusion.WorkloadKind + (*Policy)(nil), // 8: storage.Policy + (*PolicySection)(nil), // 9: storage.PolicySection + (*PolicyGroup)(nil), // 10: storage.PolicyGroup + (*PolicyValue)(nil), // 11: storage.PolicyValue + (*PolicyList)(nil), // 12: storage.PolicyList + (*ListPolicy)(nil), // 13: storage.ListPolicy + (*EvaluationFilter)(nil), // 14: storage.EvaluationFilter + (*Exclusion)(nil), // 15: storage.Exclusion + (*ExportPoliciesResponse)(nil), // 16: storage.ExportPoliciesResponse + (*Policy_MitreAttackVectors)(nil), // 17: storage.Policy.MitreAttackVectors + (*Exclusion_Container)(nil), // 18: storage.Exclusion.Container + (*Exclusion_Deployment)(nil), // 19: storage.Exclusion.Deployment + (*Exclusion_Image)(nil), // 20: storage.Exclusion.Image + (*Exclusion_ExcludeByKind)(nil), // 21: storage.Exclusion.ExcludeByKind + (*Scope)(nil), // 22: storage.Scope + (*timestamppb.Timestamp)(nil), // 23: google.protobuf.Timestamp + (ContainerType)(0), // 24: storage.ContainerType + (*ImageName)(nil), // 25: storage.ImageName } var file_storage_policy_proto_depIdxs = []int32{ 5, // 0: storage.Policy.lifecycle_stages:type_name -> storage.LifecycleStage 1, // 1: storage.Policy.event_source:type_name -> storage.EventSource - 14, // 2: storage.Policy.exclusions:type_name -> storage.Exclusion - 20, // 3: storage.Policy.scope:type_name -> storage.Scope + 15, // 2: storage.Policy.exclusions:type_name -> storage.Exclusion + 22, // 3: storage.Policy.scope:type_name -> storage.Scope 4, // 4: storage.Policy.severity:type_name -> storage.Severity 3, // 5: storage.Policy.enforcement_actions:type_name -> storage.EnforcementAction - 21, // 6: storage.Policy.last_updated:type_name -> google.protobuf.Timestamp - 8, // 7: storage.Policy.policy_sections:type_name -> storage.PolicySection - 16, // 8: storage.Policy.mitre_attack_vectors:type_name -> storage.Policy.MitreAttackVectors + 23, // 6: storage.Policy.last_updated:type_name -> google.protobuf.Timestamp + 9, // 7: storage.Policy.policy_sections:type_name -> storage.PolicySection + 17, // 8: storage.Policy.mitre_attack_vectors:type_name -> storage.Policy.MitreAttackVectors 0, // 9: storage.Policy.source:type_name -> storage.PolicySource - 13, // 10: storage.Policy.evaluation_filter:type_name -> storage.EvaluationFilter - 9, // 11: storage.PolicySection.policy_groups:type_name -> storage.PolicyGroup + 14, // 10: storage.Policy.evaluation_filter:type_name -> storage.EvaluationFilter + 10, // 11: storage.PolicySection.policy_groups:type_name -> storage.PolicyGroup 2, // 12: storage.PolicyGroup.boolean_operator:type_name -> storage.BooleanOperator - 10, // 13: storage.PolicyGroup.values:type_name -> storage.PolicyValue - 7, // 14: storage.PolicyList.policies:type_name -> storage.Policy + 11, // 13: storage.PolicyGroup.values:type_name -> storage.PolicyValue + 8, // 14: storage.PolicyList.policies:type_name -> storage.Policy 4, // 15: storage.ListPolicy.severity:type_name -> storage.Severity 5, // 16: storage.ListPolicy.lifecycle_stages:type_name -> storage.LifecycleStage - 21, // 17: storage.ListPolicy.last_updated:type_name -> google.protobuf.Timestamp + 23, // 17: storage.ListPolicy.last_updated:type_name -> google.protobuf.Timestamp 1, // 18: storage.ListPolicy.event_source:type_name -> storage.EventSource 0, // 19: storage.ListPolicy.source:type_name -> storage.PolicySource - 13, // 20: storage.ListPolicy.evaluation_filter:type_name -> storage.EvaluationFilter - 22, // 21: storage.EvaluationFilter.skip_container_types:type_name -> storage.ContainerType - 18, // 22: storage.Exclusion.deployment:type_name -> storage.Exclusion.Deployment - 19, // 23: storage.Exclusion.image:type_name -> storage.Exclusion.Image - 21, // 24: storage.Exclusion.expiration:type_name -> google.protobuf.Timestamp - 7, // 25: storage.ExportPoliciesResponse.policies:type_name -> storage.Policy - 23, // 26: storage.Exclusion.Container.image_name:type_name -> storage.ImageName - 20, // 27: storage.Exclusion.Deployment.scope:type_name -> storage.Scope - 28, // [28:28] is the sub-list for method output_type - 28, // [28:28] is the sub-list for method input_type - 28, // [28:28] is the sub-list for extension type_name - 28, // [28:28] is the sub-list for extension extendee - 0, // [0:28] is the sub-list for field type_name + 14, // 20: storage.ListPolicy.evaluation_filter:type_name -> storage.EvaluationFilter + 24, // 21: storage.EvaluationFilter.skip_container_types:type_name -> storage.ContainerType + 20, // 22: storage.Exclusion.image:type_name -> storage.Exclusion.Image + 23, // 23: storage.Exclusion.expiration:type_name -> google.protobuf.Timestamp + 19, // 24: storage.Exclusion.deployment:type_name -> storage.Exclusion.Deployment + 21, // 25: storage.Exclusion.exclude_by_kind:type_name -> storage.Exclusion.ExcludeByKind + 8, // 26: storage.ExportPoliciesResponse.policies:type_name -> storage.Policy + 25, // 27: storage.Exclusion.Container.image_name:type_name -> storage.ImageName + 22, // 28: storage.Exclusion.Deployment.scope:type_name -> storage.Scope + 7, // 29: storage.Exclusion.ExcludeByKind.kinds:type_name -> storage.Exclusion.WorkloadKind + 30, // [30:30] is the sub-list for method output_type + 30, // [30:30] is the sub-list for method input_type + 30, // [30:30] is the sub-list for extension type_name + 30, // [30:30] is the sub-list for extension extendee + 0, // [0:30] is the sub-list for field type_name } func init() { file_storage_policy_proto_init() } @@ -1578,13 +1726,17 @@ func file_storage_policy_proto_init() { file_storage_deployment_proto_init() file_storage_image_proto_init() file_storage_scope_proto_init() + file_storage_policy_proto_msgTypes[7].OneofWrappers = []any{ + (*Exclusion_Deployment_)(nil), + (*Exclusion_ExcludeByKind_)(nil), + } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_storage_policy_proto_rawDesc), len(file_storage_policy_proto_rawDesc)), - NumEnums: 7, - NumMessages: 13, + NumEnums: 8, + NumMessages: 14, NumExtensions: 0, NumServices: 0, }, diff --git a/generated/storage/policy_category.pb.go b/generated/storage/policy_category.pb.go index 1d9f7c240caee..9f251b985de73 100644 --- a/generated/storage/policy_category.pb.go +++ b/generated/storage/policy_category.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/policy_category.proto diff --git a/generated/storage/policy_vtproto.pb.go b/generated/storage/policy_vtproto.pb.go index e24289130948a..4e4e98f768d0f 100644 --- a/generated/storage/policy_vtproto.pb.go +++ b/generated/storage/policy_vtproto.pb.go @@ -325,15 +325,38 @@ func (m *Exclusion_Image) CloneMessageVT() proto.Message { return m.CloneVT() } +func (m *Exclusion_ExcludeByKind) CloneVT() *Exclusion_ExcludeByKind { + if m == nil { + return (*Exclusion_ExcludeByKind)(nil) + } + r := new(Exclusion_ExcludeByKind) + if rhs := m.Kinds; rhs != nil { + tmpContainer := make([]Exclusion_WorkloadKind, len(rhs)) + copy(tmpContainer, rhs) + r.Kinds = tmpContainer + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *Exclusion_ExcludeByKind) CloneMessageVT() proto.Message { + return m.CloneVT() +} + func (m *Exclusion) CloneVT() *Exclusion { if m == nil { return (*Exclusion)(nil) } r := new(Exclusion) r.Name = m.Name - r.Deployment = m.Deployment.CloneVT() r.Image = m.Image.CloneVT() r.Expiration = (*timestamppb.Timestamp)((*timestamppb1.Timestamp)(m.Expiration).CloneVT()) + if m.Matcher != nil { + r.Matcher = m.Matcher.(interface{ CloneVT() isExclusion_Matcher }).CloneVT() + } if len(m.unknownFields) > 0 { r.unknownFields = make([]byte, len(m.unknownFields)) copy(r.unknownFields, m.unknownFields) @@ -345,6 +368,24 @@ func (m *Exclusion) CloneMessageVT() proto.Message { return m.CloneVT() } +func (m *Exclusion_Deployment_) CloneVT() isExclusion_Matcher { + if m == nil { + return (*Exclusion_Deployment_)(nil) + } + r := new(Exclusion_Deployment_) + r.Deployment = m.Deployment.CloneVT() + return r +} + +func (m *Exclusion_ExcludeByKind_) CloneVT() isExclusion_Matcher { + if m == nil { + return (*Exclusion_ExcludeByKind_)(nil) + } + r := new(Exclusion_ExcludeByKind_) + r.ExcludeByKind = m.ExcludeByKind.CloneVT() + return r +} + func (m *ExportPoliciesResponse) CloneVT() *ExportPoliciesResponse { if m == nil { return (*ExportPoliciesResponse)(nil) @@ -849,16 +890,50 @@ func (this *Exclusion_Image) EqualMessageVT(thatMsg proto.Message) bool { } return this.EqualVT(that) } +func (this *Exclusion_ExcludeByKind) EqualVT(that *Exclusion_ExcludeByKind) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if len(this.Kinds) != len(that.Kinds) { + return false + } + for i, vx := range this.Kinds { + vy := that.Kinds[i] + if vx != vy { + return false + } + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *Exclusion_ExcludeByKind) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*Exclusion_ExcludeByKind) + if !ok { + return false + } + return this.EqualVT(that) +} func (this *Exclusion) EqualVT(that *Exclusion) bool { if this == that { return true } else if this == nil || that == nil { return false } - if this.Name != that.Name { + if this.Matcher == nil && that.Matcher != nil { return false + } else if this.Matcher != nil { + if that.Matcher == nil { + return false + } + if !this.Matcher.(interface { + EqualVT(isExclusion_Matcher) bool + }).EqualVT(that.Matcher) { + return false + } } - if !this.Deployment.EqualVT(that.Deployment) { + if this.Name != that.Name { return false } if !(*timestamppb1.Timestamp)(this.Expiration).EqualVT((*timestamppb1.Timestamp)(that.Expiration)) { @@ -877,6 +952,56 @@ func (this *Exclusion) EqualMessageVT(thatMsg proto.Message) bool { } return this.EqualVT(that) } +func (this *Exclusion_Deployment_) EqualVT(thatIface isExclusion_Matcher) bool { + that, ok := thatIface.(*Exclusion_Deployment_) + if !ok { + return false + } + if this == that { + return true + } + if this == nil && that != nil || this != nil && that == nil { + return false + } + if p, q := this.Deployment, that.Deployment; p != q { + if p == nil { + p = &Exclusion_Deployment{} + } + if q == nil { + q = &Exclusion_Deployment{} + } + if !p.EqualVT(q) { + return false + } + } + return true +} + +func (this *Exclusion_ExcludeByKind_) EqualVT(thatIface isExclusion_Matcher) bool { + that, ok := thatIface.(*Exclusion_ExcludeByKind_) + if !ok { + return false + } + if this == that { + return true + } + if this == nil && that != nil || this != nil && that == nil { + return false + } + if p, q := this.ExcludeByKind, that.ExcludeByKind; p != q { + if p == nil { + p = &Exclusion_ExcludeByKind{} + } + if q == nil { + q = &Exclusion_ExcludeByKind{} + } + if !p.EqualVT(q) { + return false + } + } + return true +} + func (this *ExportPoliciesResponse) EqualVT(that *ExportPoliciesResponse) bool { if this == that { return true @@ -1797,6 +1922,60 @@ func (m *Exclusion_Image) MarshalToSizedBufferVT(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *Exclusion_ExcludeByKind) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Exclusion_ExcludeByKind) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *Exclusion_ExcludeByKind) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.Kinds) > 0 { + var pksize2 int + for _, num := range m.Kinds { + pksize2 += protohelpers.SizeOfVarint(uint64(num)) + } + i -= pksize2 + j1 := i + for _, num1 := range m.Kinds { + num := uint64(num1) + for num >= 1<<7 { + dAtA[j1] = uint8(uint64(num)&0x7f | 0x80) + num >>= 7 + j1++ + } + dAtA[j1] = uint8(num) + j1++ + } + i = protohelpers.EncodeVarint(dAtA, i, uint64(pksize2)) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func (m *Exclusion) MarshalVT() (dAtA []byte, err error) { if m == nil { return nil, nil @@ -1827,6 +2006,15 @@ func (m *Exclusion) MarshalToSizedBufferVT(dAtA []byte) (int, error) { i -= len(m.unknownFields) copy(dAtA[i:], m.unknownFields) } + if vtmsg, ok := m.Matcher.(interface { + MarshalToSizedBufferVT([]byte) (int, error) + }); ok { + size, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + } if m.Image != nil { size, err := m.Image.MarshalToSizedBufferVT(dAtA[:i]) if err != nil { @@ -1847,6 +2035,23 @@ func (m *Exclusion) MarshalToSizedBufferVT(dAtA []byte) (int, error) { i-- dAtA[i] = 0x32 } + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *Exclusion_Deployment_) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *Exclusion_Deployment_) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + i := len(dAtA) if m.Deployment != nil { size, err := m.Deployment.MarshalToSizedBufferVT(dAtA[:i]) if err != nil { @@ -1856,17 +2061,36 @@ func (m *Exclusion) MarshalToSizedBufferVT(dAtA []byte) (int, error) { i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) i-- dAtA[i] = 0x2a - } - if len(m.Name) > 0 { - i -= len(m.Name) - copy(dAtA[i:], m.Name) - i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Name))) + } else { + i = protohelpers.EncodeVarint(dAtA, i, 0) i-- - dAtA[i] = 0xa + dAtA[i] = 0x2a } return len(dAtA) - i, nil } +func (m *Exclusion_ExcludeByKind_) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} +func (m *Exclusion_ExcludeByKind_) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + i := len(dAtA) + if m.ExcludeByKind != nil { + size, err := m.ExcludeByKind.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x42 + } else { + i = protohelpers.EncodeVarint(dAtA, i, 0) + i-- + dAtA[i] = 0x42 + } + return len(dAtA) - i, nil +} func (m *ExportPoliciesResponse) MarshalVT() (dAtA []byte, err error) { if m == nil { return nil, nil @@ -2253,6 +2477,23 @@ func (m *Exclusion_Image) SizeVT() (n int) { return n } +func (m *Exclusion_ExcludeByKind) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Kinds) > 0 { + l = 0 + for _, e := range m.Kinds { + l += protohelpers.SizeOfVarint(uint64(e)) + } + n += 1 + protohelpers.SizeOfVarint(uint64(l)) + l + } + n += len(m.unknownFields) + return n +} + func (m *Exclusion) SizeVT() (n int) { if m == nil { return 0 @@ -2263,9 +2504,8 @@ func (m *Exclusion) SizeVT() (n int) { if l > 0 { n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) } - if m.Deployment != nil { - l = m.Deployment.SizeVT() - n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + if vtmsg, ok := m.Matcher.(interface{ SizeVT() int }); ok { + n += vtmsg.SizeVT() } if m.Expiration != nil { l = (*timestamppb1.Timestamp)(m.Expiration).SizeVT() @@ -2279,6 +2519,34 @@ func (m *Exclusion) SizeVT() (n int) { return n } +func (m *Exclusion_Deployment_) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Deployment != nil { + l = m.Deployment.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } else { + n += 2 + } + return n +} +func (m *Exclusion_ExcludeByKind_) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.ExcludeByKind != nil { + l = m.ExcludeByKind.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } else { + n += 2 + } + return n +} func (m *ExportPoliciesResponse) SizeVT() (n int) { if m == nil { return 0 @@ -4551,6 +4819,126 @@ func (m *Exclusion_Image) UnmarshalVT(dAtA []byte) error { } return nil } +func (m *Exclusion_ExcludeByKind) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Exclusion_ExcludeByKind: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Exclusion_ExcludeByKind: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType == 0 { + var v Exclusion_WorkloadKind + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= Exclusion_WorkloadKind(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Kinds = append(m.Kinds, v) + } else if wireType == 2 { + var packedLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + packedLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if packedLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + packedLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var elementCount int + if elementCount != 0 && len(m.Kinds) == 0 { + m.Kinds = make([]Exclusion_WorkloadKind, 0, elementCount) + } + for iNdEx < postIndex { + var v Exclusion_WorkloadKind + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= Exclusion_WorkloadKind(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Kinds = append(m.Kinds, v) + } + } else { + return fmt.Errorf("proto: wrong wireType = %d for field Kinds", wireType) + } + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *Exclusion) UnmarshalVT(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -4641,11 +5029,16 @@ func (m *Exclusion) UnmarshalVT(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if m.Deployment == nil { - m.Deployment = &Exclusion_Deployment{} - } - if err := m.Deployment.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { - return err + if oneof, ok := m.Matcher.(*Exclusion_Deployment_); ok { + if err := oneof.Deployment.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + } else { + v := &Exclusion_Deployment{} + if err := v.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Matcher = &Exclusion_Deployment_{Deployment: v} } iNdEx = postIndex case 6: @@ -4720,6 +5113,47 @@ func (m *Exclusion) UnmarshalVT(dAtA []byte) error { return err } iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ExcludeByKind", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if oneof, ok := m.Matcher.(*Exclusion_ExcludeByKind_); ok { + if err := oneof.ExcludeByKind.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + } else { + v := &Exclusion_ExcludeByKind{} + if err := v.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Matcher = &Exclusion_ExcludeByKind_{ExcludeByKind: v} + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := protohelpers.Skip(dAtA[iNdEx:]) @@ -7167,6 +7601,126 @@ func (m *Exclusion_Image) UnmarshalVTUnsafe(dAtA []byte) error { } return nil } +func (m *Exclusion_ExcludeByKind) UnmarshalVTUnsafe(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Exclusion_ExcludeByKind: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Exclusion_ExcludeByKind: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType == 0 { + var v Exclusion_WorkloadKind + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= Exclusion_WorkloadKind(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Kinds = append(m.Kinds, v) + } else if wireType == 2 { + var packedLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + packedLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if packedLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + packedLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var elementCount int + if elementCount != 0 && len(m.Kinds) == 0 { + m.Kinds = make([]Exclusion_WorkloadKind, 0, elementCount) + } + for iNdEx < postIndex { + var v Exclusion_WorkloadKind + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= Exclusion_WorkloadKind(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Kinds = append(m.Kinds, v) + } + } else { + return fmt.Errorf("proto: wrong wireType = %d for field Kinds", wireType) + } + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *Exclusion) UnmarshalVTUnsafe(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -7261,11 +7815,16 @@ func (m *Exclusion) UnmarshalVTUnsafe(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if m.Deployment == nil { - m.Deployment = &Exclusion_Deployment{} - } - if err := m.Deployment.UnmarshalVTUnsafe(dAtA[iNdEx:postIndex]); err != nil { - return err + if oneof, ok := m.Matcher.(*Exclusion_Deployment_); ok { + if err := oneof.Deployment.UnmarshalVTUnsafe(dAtA[iNdEx:postIndex]); err != nil { + return err + } + } else { + v := &Exclusion_Deployment{} + if err := v.UnmarshalVTUnsafe(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Matcher = &Exclusion_Deployment_{Deployment: v} } iNdEx = postIndex case 6: @@ -7340,6 +7899,47 @@ func (m *Exclusion) UnmarshalVTUnsafe(dAtA []byte) error { return err } iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ExcludeByKind", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if oneof, ok := m.Matcher.(*Exclusion_ExcludeByKind_); ok { + if err := oneof.ExcludeByKind.UnmarshalVTUnsafe(dAtA[iNdEx:postIndex]); err != nil { + return err + } + } else { + v := &Exclusion_ExcludeByKind{} + if err := v.UnmarshalVTUnsafe(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Matcher = &Exclusion_ExcludeByKind_{ExcludeByKind: v} + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := protohelpers.Skip(dAtA[iNdEx:]) diff --git a/generated/storage/process_baseline.pb.go b/generated/storage/process_baseline.pb.go index 60b8012737c28..5514b838e8e50 100644 --- a/generated/storage/process_baseline.pb.go +++ b/generated/storage/process_baseline.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/process_baseline.proto diff --git a/generated/storage/process_indicator.pb.go b/generated/storage/process_indicator.pb.go index 8bb409310fb2b..42af97489fbef 100644 --- a/generated/storage/process_indicator.pb.go +++ b/generated/storage/process_indicator.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/process_indicator.proto diff --git a/generated/storage/process_listening_on_port.pb.go b/generated/storage/process_listening_on_port.pb.go index aed79161edf94..d6f7d2bf73396 100644 --- a/generated/storage/process_listening_on_port.pb.go +++ b/generated/storage/process_listening_on_port.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/process_listening_on_port.proto diff --git a/generated/storage/rbac.pb.go b/generated/storage/rbac.pb.go index c792bfb7cd9a2..dbde734a53ab8 100644 --- a/generated/storage/rbac.pb.go +++ b/generated/storage/rbac.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/rbac.proto diff --git a/generated/storage/relations.pb.go b/generated/storage/relations.pb.go index 9fa78603c26f5..1e51ad5cb2adc 100644 --- a/generated/storage/relations.pb.go +++ b/generated/storage/relations.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/relations.proto diff --git a/generated/storage/report_configuration.pb.go b/generated/storage/report_configuration.pb.go index 72ad19441b0a3..3f969710bdc18 100644 --- a/generated/storage/report_configuration.pb.go +++ b/generated/storage/report_configuration.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/report_configuration.proto diff --git a/generated/storage/report_notifier_configuration.pb.go b/generated/storage/report_notifier_configuration.pb.go index 19dfa872e83af..7f687465c3762 100644 --- a/generated/storage/report_notifier_configuration.pb.go +++ b/generated/storage/report_notifier_configuration.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/report_notifier_configuration.proto diff --git a/generated/storage/report_snapshot.pb.go b/generated/storage/report_snapshot.pb.go index 54acf8958dd53..5d0e879a64623 100644 --- a/generated/storage/report_snapshot.pb.go +++ b/generated/storage/report_snapshot.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/report_snapshot.proto diff --git a/generated/storage/resource_collection.pb.go b/generated/storage/resource_collection.pb.go index 70e708df4febe..9b42e2f8865ad 100644 --- a/generated/storage/resource_collection.pb.go +++ b/generated/storage/resource_collection.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/resource_collection.proto diff --git a/generated/storage/risk.pb.go b/generated/storage/risk.pb.go index 146a00fa04b64..27ad23016ba5a 100644 --- a/generated/storage/risk.pb.go +++ b/generated/storage/risk.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/risk.proto diff --git a/generated/storage/role.pb.go b/generated/storage/role.pb.go index 095b43889468b..b140ce12e3969 100644 --- a/generated/storage/role.pb.go +++ b/generated/storage/role.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/role.proto diff --git a/generated/storage/schedule.pb.go b/generated/storage/schedule.pb.go index c39adb9ca6945..696be25aea17e 100644 --- a/generated/storage/schedule.pb.go +++ b/generated/storage/schedule.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/schedule.proto diff --git a/generated/storage/scope.pb.go b/generated/storage/scope.pb.go index 1b16ac4a200e5..4c74ece92a4cb 100644 --- a/generated/storage/scope.pb.go +++ b/generated/storage/scope.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/scope.proto diff --git a/generated/storage/secret.pb.go b/generated/storage/secret.pb.go index 62340b587afc8..d793f8b30e3f9 100644 --- a/generated/storage/secret.pb.go +++ b/generated/storage/secret.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/secret.proto diff --git a/generated/storage/sensor_upgrade.pb.go b/generated/storage/sensor_upgrade.pb.go index ea91a650104d0..a755cd2a7b3da 100644 --- a/generated/storage/sensor_upgrade.pb.go +++ b/generated/storage/sensor_upgrade.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/sensor_upgrade.proto diff --git a/generated/storage/service_account.pb.go b/generated/storage/service_account.pb.go index 090ab6d6bc01c..9e1dffac42593 100644 --- a/generated/storage/service_account.pb.go +++ b/generated/storage/service_account.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/service_account.proto diff --git a/generated/storage/service_identity.pb.go b/generated/storage/service_identity.pb.go index 977969b3c14c1..c5b86d165673d 100644 --- a/generated/storage/service_identity.pb.go +++ b/generated/storage/service_identity.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/service_identity.proto diff --git a/generated/storage/signature_integration.pb.go b/generated/storage/signature_integration.pb.go index fb77716dd328c..ba5e6066215fc 100644 --- a/generated/storage/signature_integration.pb.go +++ b/generated/storage/signature_integration.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/signature_integration.proto diff --git a/generated/storage/system_info.pb.go b/generated/storage/system_info.pb.go index 7610f92952411..9a785ad00ca21 100644 --- a/generated/storage/system_info.pb.go +++ b/generated/storage/system_info.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/system_info.proto diff --git a/generated/storage/taints.pb.go b/generated/storage/taints.pb.go index 70442763e613b..0d65db63da121 100644 --- a/generated/storage/taints.pb.go +++ b/generated/storage/taints.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/taints.proto diff --git a/generated/storage/telemetry.pb.go b/generated/storage/telemetry.pb.go index 92ee31589a4c4..f668c57b255ae 100644 --- a/generated/storage/telemetry.pb.go +++ b/generated/storage/telemetry.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/telemetry.proto diff --git a/generated/storage/test.pb.go b/generated/storage/test.pb.go index f7a42207b4636..4eb02802084ca 100644 --- a/generated/storage/test.pb.go +++ b/generated/storage/test.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/test.proto diff --git a/generated/storage/traits.pb.go b/generated/storage/traits.pb.go index 2b52cd5e6ca8c..95d2420db81f3 100644 --- a/generated/storage/traits.pb.go +++ b/generated/storage/traits.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/traits.proto diff --git a/generated/storage/user.pb.go b/generated/storage/user.pb.go index 8cf1a7c6ffe81..f014ea07d7778 100644 --- a/generated/storage/user.pb.go +++ b/generated/storage/user.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/user.proto diff --git a/generated/storage/version.pb.go b/generated/storage/version.pb.go index 07cbb4044198f..010bae61d2933 100644 --- a/generated/storage/version.pb.go +++ b/generated/storage/version.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/version.proto diff --git a/generated/storage/virtual_machine.pb.go b/generated/storage/virtual_machine.pb.go index 3e6238c18d3cc..5b11e46a5573b 100644 --- a/generated/storage/virtual_machine.pb.go +++ b/generated/storage/virtual_machine.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/virtual_machine.proto diff --git a/generated/storage/virtual_machine_component_v2.pb.go b/generated/storage/virtual_machine_component_v2.pb.go index 5c49311e552dc..cbbccf82b8dec 100644 --- a/generated/storage/virtual_machine_component_v2.pb.go +++ b/generated/storage/virtual_machine_component_v2.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/virtual_machine_component_v2.proto diff --git a/generated/storage/virtual_machine_cve_v2.pb.go b/generated/storage/virtual_machine_cve_v2.pb.go index 97caffbf5325b..130097ac3e344 100644 --- a/generated/storage/virtual_machine_cve_v2.pb.go +++ b/generated/storage/virtual_machine_cve_v2.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/virtual_machine_cve_v2.proto diff --git a/generated/storage/virtual_machine_scan_v2.pb.go b/generated/storage/virtual_machine_scan_v2.pb.go index 3f0adad8f9afb..cf2317cc60247 100644 --- a/generated/storage/virtual_machine_scan_v2.pb.go +++ b/generated/storage/virtual_machine_scan_v2.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/virtual_machine_scan_v2.proto diff --git a/generated/storage/virtual_machine_v2.pb.go b/generated/storage/virtual_machine_v2.pb.go index c9e7e603482a2..c228772e3559d 100644 --- a/generated/storage/virtual_machine_v2.pb.go +++ b/generated/storage/virtual_machine_v2.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/virtual_machine_v2.proto diff --git a/generated/storage/vuln_requests.pb.go b/generated/storage/vuln_requests.pb.go index 4c9821d23dd56..b17ccd4bdb986 100644 --- a/generated/storage/vuln_requests.pb.go +++ b/generated/storage/vuln_requests.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/vuln_requests.proto diff --git a/generated/storage/vulnerability.pb.go b/generated/storage/vulnerability.pb.go index 4d5bcd07dc214..95e619dea61a9 100644 --- a/generated/storage/vulnerability.pb.go +++ b/generated/storage/vulnerability.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: storage/vulnerability.proto diff --git a/generated/test/test.pb.go b/generated/test/test.pb.go index 5bc6afe472a3d..f17e92627291e 100644 --- a/generated/test/test.pb.go +++ b/generated/test/test.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: test/test.proto diff --git a/generated/tools/local-sensor/message.pb.go b/generated/tools/local-sensor/message.pb.go index fdd50698a2b55..a0b724624c413 100644 --- a/generated/tools/local-sensor/message.pb.go +++ b/generated/tools/local-sensor/message.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v6.32.1 // source: tools/local-sensor/message.proto diff --git a/go.mod b/go.mod index 85d98692d25c6..a1f756c415c3a 100644 --- a/go.mod +++ b/go.mod @@ -3,15 +3,15 @@ module github.com/stackrox/rox go 1.26.7 require ( - cloud.google.com/go/artifactregistry v1.26.0 - cloud.google.com/go/compute/metadata v0.9.0 - cloud.google.com/go/containeranalysis v0.19.0 - cloud.google.com/go/securitycenter v1.46.0 - cloud.google.com/go/storage v1.64.0 + cloud.google.com/go/artifactregistry v1.27.0 + cloud.google.com/go/compute/metadata v0.10.0 + cloud.google.com/go/containeranalysis v0.20.0 + cloud.google.com/go/securitycenter v1.47.0 + cloud.google.com/go/storage v1.69.0 dario.cat/mergo v1.0.2 github.com/Azure/azure-sdk-for-go-extensions v0.7.0 - github.com/Azure/azure-sdk-for-go/sdk/azcore v1.23.0 - github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.14.0 + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.23.3 + github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.15.0 github.com/Azure/azure-sdk-for-go/sdk/containers/azcontainerregistry v0.2.3 github.com/Azure/azure-sdk-for-go/sdk/monitor/ingestion/azlogs v1.1.0 github.com/BurntSushi/toml v1.6.0 @@ -20,28 +20,28 @@ require ( github.com/Masterminds/sprig/v3 v3.3.0 github.com/NYTimes/gziphandler v1.1.1 github.com/PagerDuty/go-pagerduty v1.8.0 - github.com/RoaringBitmap/roaring/v2 v2.26.0 + github.com/RoaringBitmap/roaring/v2 v2.29.0 github.com/Shopify/toxiproxy/v2 v2.12.0 github.com/VividCortex/ewma v1.2.0 - github.com/adhocore/gronx v1.20.3 + github.com/adhocore/gronx v1.20.5 github.com/andygrunwald/go-jira v1.17.0 - github.com/aws/aws-sdk-go-v2 v1.43.4 - github.com/aws/aws-sdk-go-v2/config v1.32.35 - github.com/aws/aws-sdk-go-v2/credentials v1.19.34 - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.35 - github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.22.41 - github.com/aws/aws-sdk-go-v2/service/ecr v1.60.4 - github.com/aws/aws-sdk-go-v2/service/s3 v1.107.0 - github.com/aws/aws-sdk-go-v2/service/securityhub v1.76.0 - github.com/aws/aws-sdk-go-v2/service/sts v1.45.4 - github.com/aws/smithy-go v1.27.8 - github.com/bmatcuk/doublestar/v4 v4.10.0 + github.com/aws/aws-sdk-go-v2 v1.47.3 + github.com/aws/aws-sdk-go-v2/config v1.33.9 + github.com/aws/aws-sdk-go-v2/credentials v1.20.9 + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.20.3 + github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.23.14 + github.com/aws/aws-sdk-go-v2/service/ecr v1.66.4 + github.com/aws/aws-sdk-go-v2/service/s3 v1.114.3 + github.com/aws/aws-sdk-go-v2/service/securityhub v1.85.0 + github.com/aws/aws-sdk-go-v2/service/sts v1.51.4 + github.com/aws/smithy-go v1.28.5 + github.com/bmatcuk/doublestar/v4 v4.10.3 github.com/cenkalti/backoff/v4 v4.3.0 github.com/cespare/xxhash/v2 v2.3.0 github.com/cloudflare/cfssl v1.6.5 - github.com/cockroachdb/pebble/v2 v2.1.6 + github.com/cockroachdb/pebble/v2 v2.1.7 github.com/containers/image/v5 v5.36.2 - github.com/coreos/go-oidc/v3 v3.20.0 + github.com/coreos/go-oidc/v3 v3.21.0 github.com/coreos/go-systemd/v22 v22.7.0 github.com/dave/jennifer v1.7.1 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc @@ -50,27 +50,27 @@ require ( github.com/facebookincubator/nvdtools v0.1.5 github.com/fatih/color v1.19.0 github.com/georgysavva/scany/v2 v2.1.4 - github.com/go-jose/go-jose/v4 v4.1.4 + github.com/go-jose/go-jose/v4 v4.1.5 github.com/go-logr/logr v1.4.4 github.com/go-logr/zapr v1.3.0 github.com/go-viper/mapstructure/v2 v2.5.0 - github.com/gobwas/glob v0.2.3 - github.com/godbus/dbus/v5 v5.2.2 + github.com/gobwas/glob v1.0.0 + github.com/godbus/dbus/v5 v5.2.3 github.com/golang-jwt/jwt/v5 v5.3.1 github.com/google/certificate-transparency-go v1.3.3 github.com/google/gnostic-models v0.7.1 github.com/google/go-cmp v0.7.0 - github.com/google/go-containerregistry v0.21.9 + github.com/google/go-containerregistry v0.22.1 github.com/google/go-github/v91 v91.0.0 github.com/google/uuid v1.6.0 - github.com/googleapis/gax-go/v2 v2.23.0 + github.com/googleapis/gax-go/v2 v2.26.2 github.com/gorilla/schema v1.4.1 github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 - github.com/grafana/pyroscope-go v1.4.2 - github.com/graph-gophers/graphql-go v1.10.3-0.20260702060009-60399cce0c05 - github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.3 + github.com/grafana/pyroscope-go v1.4.3 + github.com/graph-gophers/graphql-go v1.10.3 + github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.4 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20210315223345-82c243799c99 - github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 + github.com/grpc-ecosystem/grpc-gateway/v2 v2.32.0 github.com/hashicorp/go-multierror v1.1.1 github.com/hashicorp/go-retryablehttp v0.7.8 github.com/hashicorp/go-version v1.9.0 @@ -78,10 +78,10 @@ require ( github.com/heimdalr/dag v1.5.1 github.com/helm/helm-mapkubeapis v0.6.1 github.com/heroku/docker-registry-client v0.0.0 - github.com/jackc/pgx/v5 v5.10.0 + github.com/jackc/pgx/v5 v5.11.0 github.com/jeremywohl/flatten v1.0.1 github.com/joshdk/go-junit v1.0.0 - github.com/klauspost/compress v1.19.2 + github.com/klauspost/compress v1.20.3 github.com/lib/pq v1.12.3 github.com/machinebox/graphql v0.2.2 github.com/mailru/easyjson v0.9.2 @@ -90,39 +90,39 @@ require ( github.com/np-guard/cluster-topology-analyzer/v2 v2.3.0 github.com/np-guard/netpol-analyzer v1.4.4 github.com/nxadm/tail v1.4.11 - github.com/olekukonko/tablewriter v1.1.4 - github.com/onsi/ginkgo/v2 v2.32.1 - github.com/onsi/gomega v1.42.1 + github.com/olekukonko/tablewriter v1.1.5 + github.com/onsi/ginkgo/v2 v2.33.1 + github.com/onsi/gomega v1.44.0 github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec v1.1.1 - github.com/openshift-online/ocm-sdk-go v0.1.509 + github.com/openshift-online/ocm-sdk-go v0.1.517 github.com/openshift/api v0.0.0-20260317165824-54a3998d81eb github.com/openshift/client-go v0.0.0-20260317180604-743f664b82d1 github.com/openshift/controller-runtime-common v0.0.0-20260318085703-1812aed6dbd2 github.com/openshift/library-go v0.0.0-20260318142011-72bf34f474bc github.com/openshift/runtime-utils v0.0.0-20230921210328-7bdb5b9c177b github.com/operator-framework/helm-operator-plugins v0.0.0-00010101000000-000000000000 - github.com/owenrumney/go-sarif/v2 v2.3.3 - github.com/package-url/packageurl-go v0.1.6 + github.com/owenrumney/go-sarif/v3 v3.3.1 + github.com/package-url/packageurl-go v0.1.7 github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c github.com/pkg/errors v0.9.1 github.com/planetscale/vtprotobuf v0.6.1-0.20240409071808-615f978279ca github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 - github.com/prometheus/client_golang v1.24.1 - github.com/prometheus/client_model v0.6.2 - github.com/prometheus/common v0.70.1 - github.com/quay/claircore v1.5.55-0.20260720230557-3f07716d8b96 - github.com/quay/claircore/toolkit v1.6.1 + github.com/prometheus/client_golang v1.25.0 + github.com/prometheus/client_model v0.6.3 + github.com/prometheus/common v0.72.1 + github.com/quay/claircore v1.6.1-0.20260916195820-3902930ff815 + github.com/quay/claircore/toolkit v1.7.0 github.com/quay/zlog/v2 v2.1.1 github.com/remind101/migrate v0.0.0-20170729031349-52c1edff7319 github.com/russellhaering/gosaml2 v0.12.0 github.com/russellhaering/goxmldsig v1.6.1 - github.com/segmentio/analytics-go/v3 v3.3.0 + github.com/segmentio/analytics-go/v3 v3.4.0 github.com/sergi/go-diff v1.4.0 github.com/sigstore/cosign/v3 v3.1.3 github.com/sigstore/rekor v1.5.4 github.com/sigstore/sigstore v1.10.9 - github.com/sigstore/sigstore-go v1.2.2 + github.com/sigstore/sigstore-go v1.3.0 github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 github.com/spf13/cobra v1.10.2 github.com/spf13/pflag v1.0.10 @@ -134,53 +134,53 @@ require ( github.com/stackrox/pkcs7 v0.0.0-20240314170115-841ca6b5f88d github.com/stackrox/scanner v0.0.0-20240830165150-d133ba942d59 github.com/stolostron/cluster-lifecycle-api v0.0.0-20260330032750-43755d6ceb09 - github.com/stretchr/testify v1.11.1 - github.com/tidwall/gjson v1.19.0 + github.com/stretchr/testify v1.12.1 + github.com/tidwall/gjson v1.20.0 github.com/tkuchiki/go-timezone v0.2.3 github.com/travelaudience/go-promhttp v1.0.1 github.com/vbauerster/mpb/v4 v4.12.2 - go.uber.org/atomic v1.11.0 + go.uber.org/atomic v1.12.0 go.uber.org/goleak v1.3.0 go.uber.org/mock v0.6.0 go.uber.org/zap v1.28.0 go.yaml.in/yaml/v3 v3.0.5 - golang.org/x/crypto v0.56.0 - golang.org/x/mod v0.41.0 - golang.org/x/net v0.58.0 - golang.org/x/oauth2 v0.36.0 - golang.org/x/sync v0.23.0 - golang.org/x/sys v0.48.0 - golang.org/x/term v0.45.0 - golang.org/x/text v0.41.0 + golang.org/x/crypto v0.58.0 + golang.org/x/mod v0.42.0 + golang.org/x/net v0.61.0 + golang.org/x/oauth2 v0.37.0 + golang.org/x/sync v0.24.0 + golang.org/x/sys v0.49.0 + golang.org/x/term v0.47.0 + golang.org/x/text v0.43.0 golang.org/x/time v0.16.0 - golang.org/x/tools v0.49.0 + golang.org/x/tools v0.52.0 golang.stackrox.io/grpc-http1 v0.5.1 - google.golang.org/api v0.292.0 - google.golang.org/genproto v0.0.0-20260622175928-b703f567277d - google.golang.org/genproto/googleapis/api v0.0.0-20260727163830-6c54dddc4772 - google.golang.org/grpc v1.83.0 + google.golang.org/api v0.304.0 + google.golang.org/genproto v0.0.0-20260715232425-e75dac1f907d + google.golang.org/genproto/googleapis/api v0.0.0-20261012220534-4341edf3f941 + google.golang.org/grpc v1.84.0 google.golang.org/grpc/examples v0.0.0-20250407062114-b368379ef8f6 google.golang.org/protobuf v1.36.12 gopkg.in/mcuadros/go-syslog.v2 v2.3.0 gopkg.in/natefinch/lumberjack.v2 v2.2.1 gopkg.in/robfig/cron.v2 v2.0.0-20150107220207-be2e0b0deed5 gopkg.in/yaml.v3 v3.0.1 - gorm.io/driver/postgres v1.6.2 + gorm.io/driver/postgres v1.6.3 gorm.io/gorm v1.31.2 - helm.sh/helm/v3 v3.21.3 - k8s.io/api v0.36.4 - k8s.io/apiextensions-apiserver v0.36.4 - k8s.io/apimachinery v0.36.4 - k8s.io/apiserver v0.36.4 - k8s.io/cli-runtime v0.36.4 - k8s.io/client-go v0.36.4 - k8s.io/kubectl v0.36.4 + helm.sh/helm/v3 v3.22.1 + k8s.io/api v0.37.1 + k8s.io/apiextensions-apiserver v0.37.1 + k8s.io/apimachinery v0.37.1 + k8s.io/apiserver v0.37.1 + k8s.io/cli-runtime v0.37.1 + k8s.io/client-go v0.37.1 + k8s.io/kubectl v0.37.1 k8s.io/kubelet v0.32.13 - k8s.io/utils v0.0.0-20260319190234-28399d86e0b5 - kubevirt.io/api v1.9.0 - kubevirt.io/client-go v1.10.0-alpha.0 - sigs.k8s.io/controller-runtime v0.24.1 - sigs.k8s.io/controller-tools v0.21.0 + k8s.io/utils v0.0.0-20260626114624-be93311217bd + kubevirt.io/api v1.9.1 + kubevirt.io/client-go v1.10.0-beta.0 + sigs.k8s.io/controller-runtime v0.25.2 + sigs.k8s.io/controller-tools v0.22.0 sigs.k8s.io/e2e-framework v0.7.0 sigs.k8s.io/yaml v1.6.0 ) @@ -189,18 +189,18 @@ require ( al.essio.dev/pkg/shellescape v1.6.0 // indirect cel.dev/expr v0.25.2 // indirect cloud.google.com/go v0.123.0 // indirect - cloud.google.com/go/auth v0.22.0 // indirect - cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect + cloud.google.com/go/auth v0.24.1-0.20261001053825-dbc26066f70a // indirect + cloud.google.com/go/auth/oauth2adapt v0.3.0 // indirect cloud.google.com/go/iam v1.13.0 // indirect cloud.google.com/go/longrunning v1.2.0 // indirect - cloud.google.com/go/monitoring v1.29.0 // indirect - github.com/Azure/azure-sdk-for-go/sdk/internal v1.12.0 // indirect + cloud.google.com/go/monitoring v1.30.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/internal v1.13.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerservice/armcontainerservice/v9 v9.0.0 // indirect github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect - github.com/AzureAD/microsoft-authentication-library-for-go v1.7.2 // indirect + github.com/AzureAD/microsoft-authentication-library-for-go v1.10.1 // indirect github.com/ComplianceAsCode/compliance-sdk v0.0.0-20250925092238-0b432985772e // indirect github.com/DataDog/zstd v1.5.7 // indirect - github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.33.0 // indirect + github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.35.0 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.57.0 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.57.0 // indirect github.com/MakeNowJust/heredoc v1.0.0 // indirect @@ -216,23 +216,22 @@ require ( github.com/andybalholm/brotli v1.1.0 // indirect github.com/antlr4-go/antlr/v4 v4.13.1 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect - github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.16 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.35 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.35 // indirect - github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.36 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.15 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.28 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.35 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.36 // indirect - github.com/aws/aws-sdk-go-v2/service/signin v1.5.4 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.33.4 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.38.4 // indirect + github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.22 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.5.6 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.8.6 // indirect + github.com/aws/aws-sdk-go-v2/internal/v4a v1.5.6 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.21 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.11.7 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.14.6 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.20.6 // indirect + github.com/aws/aws-sdk-go-v2/service/signin v1.10.4 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.38.4 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.43.4 // indirect github.com/aymerick/douceur v0.2.0 // indirect github.com/beevik/etree v1.7.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bits-and-blooms/bitset v1.24.4 // indirect github.com/blang/semver/v4 v4.0.0 // indirect - github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect github.com/cenkalti/backoff/v5 v5.0.3 // indirect github.com/chai2010/gettext-go v1.0.2 // indirect github.com/clipperhouse/displaywidth v0.10.0 // indirect @@ -243,7 +242,7 @@ require ( github.com/cockroachdb/errors v1.12.0 // indirect github.com/cockroachdb/logtags v0.0.0-20241215232642-bb51bb14a506 // indirect github.com/cockroachdb/redact v1.1.6 // indirect - github.com/cockroachdb/swiss v0.0.0-20251224182025-b0f6560f979b // indirect + github.com/cockroachdb/swiss v0.0.0-20260820225851-333444432258 // indirect github.com/cockroachdb/tokenbucket v0.0.0-20250429170803-42689b6311bb // indirect github.com/coder/websocket v1.8.14 // indirect github.com/containers/storage v1.59.1 // indirect @@ -252,7 +251,7 @@ require ( github.com/cyphar/filepath-securejoin v0.7.0 // indirect github.com/digitorus/pkcs7 v0.0.0-20230818184609-3a137a874352 // indirect github.com/digitorus/timestamp v0.0.0-20231217203849-220c5c2851b7 // indirect - github.com/docker/cli v29.6.2+incompatible // indirect + github.com/docker/cli v29.7.2+incompatible // indirect github.com/docker/docker-credential-helpers v0.9.5 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 // indirect @@ -269,7 +268,7 @@ require ( github.com/facebookincubator/flog v0.0.0-20190930132826-d2511d0ce33c // indirect github.com/fatih/camelcase v1.0.0 // indirect github.com/fatih/structs v1.1.0 // indirect - github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/felixge/httpsnoop v1.1.0 // indirect github.com/fsnotify/fsnotify v1.10.1 // indirect github.com/fxamacker/cbor/v2 v2.9.1 // indirect github.com/getsentry/sentry-go v0.34.0 // indirect @@ -283,29 +282,28 @@ require ( github.com/go-kit/log v0.2.1 // indirect github.com/go-logfmt/logfmt v0.6.0 // indirect github.com/go-logr/stdr v1.2.2 // indirect - github.com/go-openapi/analysis v0.26.0 // indirect - github.com/go-openapi/errors v0.22.8 // indirect - github.com/go-openapi/jsonpointer v1.0.0 // indirect - github.com/go-openapi/jsonreference v1.0.0 // indirect - github.com/go-openapi/loads v0.25.1 // indirect - github.com/go-openapi/runtime v0.32.5 // indirect - github.com/go-openapi/runtime/server-middleware v0.30.0 // indirect - github.com/go-openapi/spec v0.22.9 // indirect - github.com/go-openapi/strfmt v0.27.0 // indirect - github.com/go-openapi/swag v0.26.1 // indirect - github.com/go-openapi/swag/cmdutils v0.26.1 // indirect - github.com/go-openapi/swag/conv v0.28.0 // indirect - github.com/go-openapi/swag/fileutils v0.28.0 // indirect - github.com/go-openapi/swag/jsonname v0.26.1 // indirect - github.com/go-openapi/swag/jsonutils v0.28.0 // indirect - github.com/go-openapi/swag/loading v0.28.0 // indirect - github.com/go-openapi/swag/mangling v0.28.0 // indirect - github.com/go-openapi/swag/netutils v0.26.1 // indirect - github.com/go-openapi/swag/pools v0.28.0 // indirect - github.com/go-openapi/swag/stringutils v0.28.0 // indirect - github.com/go-openapi/swag/typeutils v0.28.0 // indirect - github.com/go-openapi/swag/yamlutils v0.28.0 // indirect - github.com/go-openapi/validate v0.26.3 // indirect + github.com/go-openapi/analysis v1.0.0 // indirect + github.com/go-openapi/errors v0.22.9 // indirect + github.com/go-openapi/jsonpointer v1.0.1 // indirect + github.com/go-openapi/jsonreference v1.0.2 // indirect + github.com/go-openapi/loads v0.25.3 // indirect + github.com/go-openapi/runtime v0.33.3 // indirect + github.com/go-openapi/runtime/server-middleware v0.33.3 // indirect + github.com/go-openapi/spec v1.0.1 // indirect + github.com/go-openapi/strfmt v0.27.3 // indirect + github.com/go-openapi/swag v0.29.2 // indirect + github.com/go-openapi/swag/cmdutils v0.29.2 // indirect + github.com/go-openapi/swag/conv v0.29.2 // indirect + github.com/go-openapi/swag/fileutils v0.29.2 // indirect + github.com/go-openapi/swag/jsonutils v0.29.2 // indirect + github.com/go-openapi/swag/loading v0.29.2 // indirect + github.com/go-openapi/swag/mangling v0.29.2 // indirect + github.com/go-openapi/swag/netutils v0.29.2 // indirect + github.com/go-openapi/swag/pools v0.29.2 // indirect + github.com/go-openapi/swag/stringutils v0.29.2 // indirect + github.com/go-openapi/swag/typeutils v0.29.2 // indirect + github.com/go-openapi/swag/yamlutils v0.29.2 // indirect + github.com/go-openapi/validate v1.0.0 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/gobuffalo/flect v1.0.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect @@ -314,11 +312,11 @@ require ( github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect github.com/golang/snappy v1.0.0 // indirect github.com/google/btree v1.1.3 // indirect - github.com/google/cel-go v0.29.0 // indirect + github.com/google/cel-go v0.31.0 // indirect github.com/google/go-querystring v1.2.0 // indirect - github.com/google/pprof v0.0.0-20260402051712-545e8a4df936 // indirect - github.com/google/s2a-go v0.1.9 // indirect - github.com/googleapis/enterprise-certificate-proxy v0.3.19 // indirect + github.com/google/pprof v0.0.0-20260802141513-ef3492d7dac3 // indirect + github.com/google/s2a-go v0.1.11 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.23 // indirect github.com/gorilla/css v1.0.0 // indirect github.com/gosuri/uitable v0.0.4 // indirect github.com/grafana/pyroscope-go/godeltaprof v0.1.11 // indirect @@ -356,7 +354,7 @@ require ( github.com/matryer/is v1.4.1 // indirect github.com/mattermost/xml-roundtrip-validator v0.1.0 // indirect github.com/mattn/go-colorable v0.1.14 // indirect - github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-isatty v0.0.24 // indirect github.com/mattn/go-runewidth v0.0.19 // indirect github.com/mdlayher/socket v0.6.0 // indirect github.com/mholt/archiver/v3 v3.5.1 // indirect @@ -368,7 +366,7 @@ require ( github.com/moby/spdystream v0.5.1 // indirect github.com/moby/sys/capability v0.4.0 // indirect github.com/moby/sys/mountinfo v0.7.2 // indirect - github.com/moby/sys/user v0.4.0 // indirect + github.com/moby/sys/user v0.4.1 // indirect github.com/moby/term v0.5.2 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect @@ -379,13 +377,13 @@ require ( github.com/nozzle/throttler v0.0.0-20180817012639-2ea982251481 // indirect github.com/np-guard/models v0.5.7 // indirect github.com/nwaples/rardecode v1.1.3 // indirect - github.com/oklog/ulid/v2 v2.1.1 // indirect + github.com/oklog/ulid/v2 v2.1.2 // indirect github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6 // indirect github.com/olekukonko/errors v1.2.0 // indirect github.com/olekukonko/ll v0.1.6 // indirect github.com/opencontainers/runtime-spec v1.2.1 // indirect - github.com/openshift-online/ocm-api-model/clientapi v0.0.464 // indirect - github.com/openshift-online/ocm-api-model/model v0.0.464 // indirect + github.com/openshift-online/ocm-api-model/clientapi v0.0.470 // indirect + github.com/openshift-online/ocm-api-model/model v0.0.470 // indirect github.com/openshift/custom-resource-status v1.1.2 // indirect github.com/operator-framework/operator-lib v0.17.0 // indirect github.com/pelletier/go-toml v1.9.5 // indirect @@ -393,7 +391,7 @@ require ( github.com/peterbourgon/diskv v2.0.1+incompatible // indirect github.com/pierrec/lz4/v4 v4.1.21 // indirect github.com/pjbgf/sha1cd v0.6.0 // indirect - github.com/prometheus/procfs v0.21.1 // indirect + github.com/prometheus/procfs v0.22.0 // indirect github.com/quay/claircore/updater/driver v1.0.0 // indirect github.com/quay/goval-parser v0.8.8 // indirect github.com/redis/go-redis/extra/redisotel/v9 v9.5.3 // indirect @@ -402,22 +400,21 @@ require ( github.com/rubenv/sql-migrate v1.8.1 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/sagikazarmark/locafero v0.11.0 // indirect - github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 // indirect + github.com/santhosh-tekuri/jsonschema/v6 v6.0.3 // indirect github.com/sassoftware/relic/v8 v8.2.0 // indirect github.com/secure-systems-lab/go-securesystemslib v0.11.0 // indirect - github.com/segmentio/backo-go v1.0.1 // indirect github.com/shibumi/go-pathspec v1.3.0 // indirect github.com/shopspring/decimal v1.4.0 // indirect github.com/sigstore/protobuf-specs v0.5.1 // indirect github.com/sigstore/rekor-tiles/v2 v2.3.0 // indirect - github.com/sigstore/timestamp-authority/v2 v2.1.2 // indirect - github.com/sirupsen/logrus v1.9.4 // indirect + github.com/sigstore/timestamp-authority/v2 v2.1.3 // indirect + github.com/sirupsen/logrus v1.10.2 // indirect github.com/skeema/knownhosts v1.3.1 // indirect github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 // indirect github.com/spdx/tools-golang v0.5.7 // indirect github.com/spf13/afero v1.15.0 // indirect github.com/spf13/cast v1.10.0 // indirect - github.com/spiffe/go-spiffe/v2 v2.7.0 // indirect + github.com/spiffe/go-spiffe/v2 v2.8.1 // indirect github.com/stackrox/dotnet-scraper v0.0.0-20201023051640-72ef543323dd // indirect github.com/stackrox/istio-cves v0.0.0-20221007013142-0bde9b541ec8 // indirect github.com/stackrox/k8s-cves v0.0.0-20220818200547-7d0d1420c58d // indirect @@ -436,55 +433,59 @@ require ( github.com/weppos/publicsuffix-go v0.50.2 // indirect github.com/x448/float16 v0.8.4 // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect + github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect + github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect + github.com/xeipuuv/gojsonschema v1.2.0 // indirect github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect github.com/xlab/treeprint v1.2.0 // indirect github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect github.com/zmap/zcrypto v0.0.0-20250129210703-03c45d0bae98 // indirect github.com/zmap/zlint/v3 v3.6.6 // indirect - go.etcd.io/bbolt v1.4.3 // indirect + go.etcd.io/bbolt v1.5.0 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect - go.opentelemetry.io/contrib/detectors/gcp v1.44.0 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.68.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.68.0 // indirect - go.opentelemetry.io/otel v1.44.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.43.0 // indirect - go.opentelemetry.io/otel/metric v1.44.0 // indirect - go.opentelemetry.io/otel/sdk v1.44.0 // indirect - go.opentelemetry.io/otel/sdk/metric v1.44.0 // indirect - go.opentelemetry.io/otel/trace v1.44.0 // indirect - go.opentelemetry.io/proto/otlp v1.10.0 // indirect + go.opentelemetry.io/contrib/detectors/gcp v1.45.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.72.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.72.0 // indirect + go.opentelemetry.io/otel v1.47.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.45.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.45.0 // indirect + go.opentelemetry.io/otel/log v1.47.0 // indirect + go.opentelemetry.io/otel/metric v1.47.0 // indirect + go.opentelemetry.io/otel/sdk v1.47.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.47.0 // indirect + go.opentelemetry.io/otel/trace v1.47.0 // indirect + go.opentelemetry.io/proto/otlp v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.yaml.in/yaml/v2 v2.4.4 // indirect - golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f // indirect + golang.org/x/exp v0.0.0-20261014143641-f0251eb4aa3e // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20260803160001-6ac0973c030d // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20261005182115-fad411399dd8 // indirect gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - k8s.io/code-generator v0.36.4 // indirect - k8s.io/component-base v0.36.4 // indirect - k8s.io/component-helpers v0.36.4 // indirect - k8s.io/gengo/v2 v2.0.0-20250922181213-ec3ebc5fd46b // indirect + k8s.io/code-generator v0.37.1 // indirect + k8s.io/component-base v0.37.1 // indirect + k8s.io/component-helpers v0.37.1 // indirect + k8s.io/gengo/v2 v2.0.0-20260408192533-25e2208e0dc3 // indirect k8s.io/klog/v2 v2.140.0 // indirect k8s.io/kube-openapi v0.31.0 // indirect - k8s.io/streaming v0.36.4 // indirect + k8s.io/streaming v0.37.1 // indirect kubevirt.io/containerized-data-importer-api v1.64.0 // indirect kubevirt.io/controller-lifecycle-operator-sdk/api v0.2.4 // indirect - modernc.org/libc v1.73.4 // indirect + modernc.org/libc v1.75.6 // indirect modernc.org/mathutil v1.7.1 // indirect - modernc.org/memory v1.11.0 // indirect - modernc.org/sqlite v1.53.0 // indirect - oras.land/oras-go/v2 v2.6.1 // indirect - sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.34.0 // indirect + modernc.org/memory v1.12.1 // indirect + modernc.org/sqlite v1.58.0 // indirect + oras.land/oras-go/v2 v2.6.2 // indirect + sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.36.0 // indirect sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/kustomize/api v0.21.1 // indirect sigs.k8s.io/kustomize/kyaml v0.21.1 // indirect sigs.k8s.io/network-policy-api v0.1.5 // indirect sigs.k8s.io/randfill v1.0.0 // indirect - sigs.k8s.io/structured-merge-diff/v6 v6.4.0 // indirect + sigs.k8s.io/structured-merge-diff/v6 v6.4.2 // indirect ) // HOW TO BUMP diff --git a/go.sum b/go.sum index 1692220505635..570d2a5d8730f 100644 --- a/go.sum +++ b/go.sum @@ -32,12 +32,12 @@ cloud.google.com/go v0.98.0/go.mod h1:ua6Ush4NALrHk5QXDWnjvZHN93OuF0HfuEPq9I1X0c cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= cloud.google.com/go v0.123.0 h1:2NAUJwPR47q+E35uaJeYoNhuNEM9kM8SjgRgdeOJUSE= cloud.google.com/go v0.123.0/go.mod h1:xBoMV08QcqUGuPW65Qfm1o9Y4zKZBpGS+7bImXLTAZU= -cloud.google.com/go/artifactregistry v1.26.0 h1:iq5kkdY2FJY8RkkNghUelb3EOcqyy7dVhfDGVk/Xw9g= -cloud.google.com/go/artifactregistry v1.26.0/go.mod h1:c5FPi5GtDBP+OAr5kKhCBNQDT9ZgAyobXQjekx93VWs= -cloud.google.com/go/auth v0.22.0 h1:Xp9wAKkLoeaYb5pYZZoQGz4E9sdPxIbzS3gywZE3ciQ= -cloud.google.com/go/auth v0.22.0/go.mod h1:M9o2Oz+YI2jAfxewJgb1vyI3vceHF+eohmxyzmrl+9s= -cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc= -cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c= +cloud.google.com/go/artifactregistry v1.27.0 h1:EBgdk9sXNAVyWJ3hnTmWRdlmKhGDKCjkJbLoF3EsyWE= +cloud.google.com/go/artifactregistry v1.27.0/go.mod h1:r0rZgbNmn5ppdqwUMF182yc7EFH6vabJMbXM+PlfW9A= +cloud.google.com/go/auth v0.24.1-0.20261001053825-dbc26066f70a h1:jW1ZLFy9oa5ai8LOI40z6s+DL1cO/L1KSm9hVGnibn8= +cloud.google.com/go/auth v0.24.1-0.20261001053825-dbc26066f70a/go.mod h1:1dmBXa9xfBvBr39ZnDUDkaaA91ccq9CcqENDgJA4d7c= +cloud.google.com/go/auth/oauth2adapt v0.3.0 h1:FY8oSZpCYoUNv6QxVODuMjQz4IlSOVeiQtZ08vLPz88= +cloud.google.com/go/auth/oauth2adapt v0.3.0/go.mod h1:7+2uCm7++XFO+/lN06c2HXpDXb/NMNn2/UwyBPbTnkk= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= @@ -45,10 +45,10 @@ cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUM cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= -cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs= -cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10= -cloud.google.com/go/containeranalysis v0.19.0 h1:89ZhFvJHWzX9/jUJy/IEVbtSa2hv4+NtsvwWMEsUYnY= -cloud.google.com/go/containeranalysis v0.19.0/go.mod h1:Zq0XHzUIa0oTa7H6aSR8HWqeJnoRI9syUcYJzfozjZQ= +cloud.google.com/go/compute/metadata v0.10.0 h1:pyKMUQSwchgkIBBJGdILqQbs/BNJXqwSA7Ej6LAvvtY= +cloud.google.com/go/compute/metadata v0.10.0/go.mod h1:rGFHRrIif570kSibjFTMbt6/4/tzgJWFGI/HVol4GIk= +cloud.google.com/go/containeranalysis v0.20.0 h1:5tko84zYirVH+FEU6JPuT/xGBvSagsllYxH7m8ytjyI= +cloud.google.com/go/containeranalysis v0.20.0/go.mod h1:cJzgbuNqFTWswsVcT0eemqdqtOEq4dJEFvAH3cgzkyc= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/firestore v1.6.1/go.mod h1:asNXNOzBdyVQmEU+ggO8UPodTkEVFW5Qx+rwHnAz+EY= @@ -56,25 +56,25 @@ cloud.google.com/go/iam v1.13.0 h1:ufT3FPT5rFFXu6UtLkNoxaOaV5EuA1dsSkmemCSTo6U= cloud.google.com/go/iam v1.13.0/go.mod h1:gHXdDEiPDvqd1q1KwBDGQlgZY/BwY760zU2LhOZS5w0= cloud.google.com/go/kms v1.33.0 h1:pG0X78m212b2pv9N4fdMoUO69LuZGQ9kSvn8sHBOFAo= cloud.google.com/go/kms v1.33.0/go.mod h1:CSGvW6GnMQbY+1nOHcIzhMtHSbExXlOmCKjWtYVjcpA= -cloud.google.com/go/logging v1.18.0 h1:KhzZq+1cSkPH9YUaKLLhLtQxIHitVayBmk0sGfoM9+k= -cloud.google.com/go/logging v1.18.0/go.mod h1:ZGKnpBaURITh+g/uom2VhbiFoFWvejcrHPDhxFtU/gI= +cloud.google.com/go/logging v1.19.0 h1:NCqhdVUg3wQ8Cobdf16FDSuTGi3+6+hdSBHrY5TsR6Q= +cloud.google.com/go/logging v1.19.0/go.mod h1:i40NZCHC9Gqvod4yE+yQfDWwlgwW/SrshkkGibCHxcA= cloud.google.com/go/longrunning v1.2.0 h1:WjYH3YHBGCxGJP9M4dWGHBfXr/cFIjMkNgWcJj7/iMM= cloud.google.com/go/longrunning v1.2.0/go.mod h1:5KMQALFGOCtFoi2xSOA1u3H7WKlhmckgiyFw7+LGQp0= -cloud.google.com/go/monitoring v1.29.0 h1:AHhDsFaSax1/4k+qlIDX/SDGe6hggnfXJ9dkgD9qBPY= -cloud.google.com/go/monitoring v1.29.0/go.mod h1:72NOVjJXHY/HBfoLT0+qlCZBT059+9VXLeAnL2PeeVM= +cloud.google.com/go/monitoring v1.30.0 h1:r/d+JUbyKmJ8b07iznuKfzVzrIXTWxHQ3lBRm3x2LlY= +cloud.google.com/go/monitoring v1.30.0/go.mod h1:htlUR0QWVMrjFzZmN4LGnMAve9xB/eduwjmINxVZ8RM= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/securitycenter v1.46.0 h1:MfzR4Bj5W51MAIyJlA4molK/vj0xO64te4yCGAbwXL0= -cloud.google.com/go/securitycenter v1.46.0/go.mod h1:7mAlzsCsKlEVmciAFORl431laDGpoKGFkSQndAzFs30= +cloud.google.com/go/securitycenter v1.47.0 h1:cKjSLURYE5tewWgH6VW6Jo6YaZWG+FUUFh/SmrqrcHU= +cloud.google.com/go/securitycenter v1.47.0/go.mod h1:OWKAGzP36rJ4pFSjU441g+vi7WTRdMFRVw1rykvMwPE= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -cloud.google.com/go/storage v1.64.0 h1:KLpxI/oX9LxeRsNqn877d2WyeT3ryiEwnGt8pwcSPZg= -cloud.google.com/go/storage v1.64.0/go.mod h1:lWyAtwvDZHdL3k68WVKbESP6bmWaV23ZJJ/JEVw/ZaQ= +cloud.google.com/go/storage v1.69.0 h1:jAAMC1411HEh78nKsU0Zns+eFj3TnhjAWIhg5Ud/XBM= +cloud.google.com/go/storage v1.69.0/go.mod h1:PELYsxTYm2peE4mwLEC1+mS1dA/kUSRUxNv56rOy44g= cloud.google.com/go/trace v1.16.0 h1:GmQovzFc5F0CNfl0VLgL64aoTtu7xsM0YajW2GlG9+E= cloud.google.com/go/trace v1.16.0/go.mod h1:r+bdAn16dKLSV1G2D5v3e58IlQlizfxWrUfjx7kM7X0= dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8= @@ -92,16 +92,16 @@ github.com/AdamKorcz/go-fuzz-headers-1 v0.0.0-20230919221257-8b5d3ce2d11d/go.mod github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU= github.com/Azure/azure-sdk-for-go-extensions v0.7.0 h1:ko7jxarxFmfm3OAtIkKcnC2yK1H7a7wB7As38huaa4Y= github.com/Azure/azure-sdk-for-go-extensions v0.7.0/go.mod h1:f/wRrqvvh197V5r4jGADV7528UdO/zfL+/Ud92BMSag= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.23.0 h1:4gRPBpN1f6xt88yi4WR26m7XaD9OlWtVT6bWPdGUIok= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.23.0/go.mod h1:G7QVLxw1j1JVyrO1MA95S8m8HStaaleDZYTcfGgjB2o= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.14.0 h1:CU4+EJeJi3TKYWEcYuSdWsjzw0nVsK/H0MSQOiPcymU= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.14.0/go.mod h1:q0+UTSRvShwUCrR/s5HtyInYphN7Wvxb7snFM3u+SLA= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.23.3 h1:qgnWTiWs1G7AqcKZegFvkJD1bmXJcaDU3uC0ELSgZ5U= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.23.3/go.mod h1:XtxD48QPInqoj+GMlcRlXHEYsoOxFnP6w2JgIZ9rDS4= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.15.0 h1:w3gDUJlJ0BfBsHH02DCBDwbkmMSXJqBj6nBOCo9iocY= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.15.0/go.mod h1:7scl8mG/IFLVjJ9ef/ltdND2T1z0CkgVSaQoUxLvmeU= github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.4.0 h1:xFaZZ+IubdftrDHnGGwZ6QvQ3KHTtWl2MCK+GMt2vxs= github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.4.0/go.mod h1:mCBhUhlMjLLJKr5aqw2TNS/VqJOie8MzWq3DAMJeKso= github.com/Azure/azure-sdk-for-go/sdk/containers/azcontainerregistry v0.2.3 h1:ldKsKtEIblsgsr6mPwrd9yRntoX6uLz/K89wsldwx/k= github.com/Azure/azure-sdk-for-go/sdk/containers/azcontainerregistry v0.2.3/go.mod h1:MAm7bk0oDLmD8yIkvfbxPW04fxzphPyL+7GzwHxOp6Y= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.12.0 h1:fhqpLE3UEXi9lPaBRpQ6XuRW0nU7hgg4zlmZZa+a9q4= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.12.0/go.mod h1:7dCRMLwisfRH3dBupKeNCioWYUZ4SS09Z14H+7i8ZoY= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.13.0 h1:Terj1CMW4+NY5CpWjSRkqLoxh2DkYDdv/FH2z0897Uc= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.13.0/go.mod h1:7Ut2Qw9vcwpLW5Q4MBy43uSxXS7tK2yjs94OJ6j5thE= github.com/Azure/azure-sdk-for-go/sdk/monitor/ingestion/azlogs v1.1.0 h1:Q+tp/BW0x11uAm5i9f2xEu3RZ3wy89KNYfDVCWFHUJQ= github.com/Azure/azure-sdk-for-go/sdk/monitor/ingestion/azlogs v1.1.0/go.mod h1:et3yi6OrdxM8YK0pfOwpHSLf4gWypxQVWh4T9wRzg3k= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerservice/armcontainerservice/v9 v9.0.0 h1:z5qKE92WxOYrrU2yWL7fL0XW7vVBjMKyaXOITK+Z3bI= @@ -118,8 +118,8 @@ github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEK github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJTmL004Abzc5wDB5VtZG2PJk5ndYDgVacGqfirKxjM= github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE= -github.com/AzureAD/microsoft-authentication-library-for-go v1.7.2 h1:RHK7bS+HQMslb1sZpAokUt+zTVmue0hKSs2C791hhzU= -github.com/AzureAD/microsoft-authentication-library-for-go v1.7.2/go.mod h1:HKpQxkWaGLJ+D/5H8QRpyQXA1eKjxkFlOMwck5+33Jk= +github.com/AzureAD/microsoft-authentication-library-for-go v1.10.1 h1:0O6j18nQDoIff6/mtosT5LNU2WehEwp+LqfX6699oqY= +github.com/AzureAD/microsoft-authentication-library-for-go v1.10.1/go.mod h1:xdYAf5bjkOpsd3auA8riiJW4vneBubt9caavL7626jQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk= @@ -135,8 +135,8 @@ github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/zstd v1.5.7 h1:ybO8RBeh29qrxIhCA9E8gKY6xfONU9T6G6aP9DTKfLE= github.com/DataDog/zstd v1.5.7/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.33.0 h1:l7+6kwRMJNwdCvYdDl7Eax+wzEYHSnNY7zrrfbhDdTA= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.33.0/go.mod h1:pJTkW8hEUIIi3Pf65lPZOnn4Y81yCllX6IWk2jNXdkM= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.35.0 h1:bN1gA3of5bXtbnLsRPrwfmbbe7A5UWFlcTHseujLnpc= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.35.0/go.mod h1:Yj5vHEz/aAepZGliRJsA6uvHAVAQyEwajq9ORCHPxzM= github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.57.0 h1:jLdiS1vO+XJFyDSWRHBx56r4s/NNtcl5J6KyCcWUX/w= github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.57.0/go.mod h1:8lmpHY+1VRoteiOwyrQMDt1YGXOrFKCz+1wJW7n3ODY= github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.57.0 h1:cSjUzZ7KU8hicTgzaSv9NmSyM9fTVK3y5lsBUl3wOis= @@ -171,8 +171,8 @@ github.com/RaduBerinde/axisds v0.1.0 h1:YItk/RmU5nvlsv/awo2Fjx97Mfpt4JfgtEVAGPrL github.com/RaduBerinde/axisds v0.1.0/go.mod h1:UHGJonU9z4YYGKJxSaC6/TNcLOBptpmM5m2Cksbnw0Y= github.com/RaduBerinde/btreemap v0.0.0-20250419174037-3d62b7205d54 h1:bsU8Tzxr/PNz75ayvCnxKZWEYdLMPDkUgticP4a4Bvk= github.com/RaduBerinde/btreemap v0.0.0-20250419174037-3d62b7205d54/go.mod h1:0tr7FllbE9gJkHq7CVeeDDFAFKQVy5RnCSSNBOvdqbc= -github.com/RoaringBitmap/roaring/v2 v2.26.0 h1:K30ZxF4vZcIKvJsbmgfiep2K64f+dILJqkYGoj4xnwU= -github.com/RoaringBitmap/roaring/v2 v2.26.0/go.mod h1:BZufmFbox589n3j5eOmyTaLSGXbRLc2LmQvjKjzSEGU= +github.com/RoaringBitmap/roaring/v2 v2.29.0 h1:jSjxqZEqiF9W5dHUFsemupb9bnLaQJwZVe5yMetbsZg= +github.com/RoaringBitmap/roaring/v2 v2.29.0/go.mod h1:BZufmFbox589n3j5eOmyTaLSGXbRLc2LmQvjKjzSEGU= github.com/Shopify/toxiproxy/v2 v2.12.0 h1:d1x++lYZg/zijXPPcv7PH0MvHMzEI5aX/YuUi/Sw+yg= github.com/Shopify/toxiproxy/v2 v2.12.0/go.mod h1:R9Z38Pw6k2cGZWXHe7tbxjGW9azmY1KbDQJ1kd+h7Tk= github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA= @@ -182,8 +182,8 @@ github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpH github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo= github.com/aclements/go-perfevent v0.0.0-20240301234650-f7843625020f h1:JjxwchlOepwsUWcQwD2mLUAGE9aCp0/ehy6yCHFBOvo= github.com/aclements/go-perfevent v0.0.0-20240301234650-f7843625020f/go.mod h1:tMDTce/yLLN/SK8gMOxQfnyeMeCg8KGzp0D1cbECEeo= -github.com/adhocore/gronx v1.20.3 h1:DjvHxCqyz9WDzpodceOU814Z4GNpTvSpZs7oeX4ToKU= -github.com/adhocore/gronx v1.20.3/go.mod h1:7oUY1WAU8rEJWmAxXR2DN0JaO4gi9khSgKjiRypqteg= +github.com/adhocore/gronx v1.20.5 h1:UgXvkD97Hovm7yA1TTRTd309o9F1h7C8gX04rktaxnE= +github.com/adhocore/gronx v1.20.5/go.mod h1:7oUY1WAU8rEJWmAxXR2DN0JaO4gi9khSgKjiRypqteg= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= @@ -203,7 +203,6 @@ github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuW github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ= github.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw= -github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= @@ -213,50 +212,50 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPd github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= -github.com/aws/aws-sdk-go-v2 v1.43.4 h1:b9FTvbRwy+JCsfp2Wp6wV/KbOx3Aj7nkoFb2cRX0IhE= -github.com/aws/aws-sdk-go-v2 v1.43.4/go.mod h1:70vwSy16txshwG+g55WkpgPKDIByzHI8ccBsOteo3bQ= -github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.16 h1:aiuaKlDweRC5qExJondpWjOgyzMHpofpwspGXUtwn4c= -github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.16/go.mod h1:nG/LOlmox9BDe9HvQnXWzgcK8uKbgBMZ/Hp5pVt/21I= -github.com/aws/aws-sdk-go-v2/config v1.32.35 h1:UEzXuET8E42lxBPijuACu/tEK7v5lFPlk0Q+GT5WD9E= -github.com/aws/aws-sdk-go-v2/config v1.32.35/go.mod h1:KaMtJpFa2JlL2BStjjHQVwQpzZEmw+ND/EgVrfFoo2g= -github.com/aws/aws-sdk-go-v2/credentials v1.19.34 h1:y6GkSmcv5myd1ngrYbGmiLlwQqB6TQhOuN/tbSSuWDY= -github.com/aws/aws-sdk-go-v2/credentials v1.19.34/go.mod h1:w3dTcnDVoQIewjo7JG45hduAToikiIFLC4FIO7fndvw= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.35 h1:+S7kbJoLDDQ5tE+lHrUBgMkzC8NLgsaioS2F3dVoFAE= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.35/go.mod h1:Ak7xXviIARfFdNUJ9Etb0bdVDt/KAvKjMGJVLWXDzik= -github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.22.41 h1:RgRlA38QGJPnsG6TNEnMTQq8COa6Ye7AGwdnFlzd3Ys= -github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.22.41/go.mod h1:14QhagNwgiQqYUcAAJjQwgBXCcpxUau+8S/0YRLt5Uo= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.35 h1:kzVuGlatQtYinwBJEEyLAbggepCoavosiaHHX9+fD+c= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.35/go.mod h1:0yLx0yEI+SfqeJMPvOtIEFoZbiQYXMGszBueiutQyaI= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.35 h1:WK6CjihTuLisCjSKKbildJ79sGZZgbBz3iNa7VsKIhU= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.35/go.mod h1:KYleN57luLoe97R7vTnx8PMcVrr9gAcRECtOjl91DNg= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.36 h1:jbGY4CXLzZElOXgGsexlC3Hi+3YM0rSmk4opFXKqg/k= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.36/go.mod h1:uBu/9aKsS/UQGc72RAt3y54kjgYQxmhut8ZD2dXCDNE= -github.com/aws/aws-sdk-go-v2/service/ecr v1.60.4 h1:qIgueZwgw+rANqXuL1Cjk2Lm/Pihbw2nx3C1D7eQD+k= -github.com/aws/aws-sdk-go-v2/service/ecr v1.60.4/go.mod h1:Jr9Mh7l72YtNr8nmEwcJiU4xwCerZB8/krBWW4RckmY= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.15 h1:JJLBQxwY+AFwuPAi5ivGc1ChnTdUt4cXMv7e76m2c/Y= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.15/go.mod h1:lQknBIe78MVL0cQOQDlag8KGflMbMEVFx9mB6O8ENvk= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.28 h1:Q1TF1J9jVD+vFo0LzNnmNdQ9EAt52TS+MQlq9Ir+Yxo= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.28/go.mod h1:4KqXXC/p1hrotmouDFbrRoWaLy962b9PMUReCG6+uWo= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.35 h1:BBEElKh4a+rKshvjrfpajTe9CbpZvrbb4Jkg2PB7RzA= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.35/go.mod h1:zaZk983w//8beSruBVec/mr4CmDwgZitW/qzGhAAX0g= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.36 h1:EUIwBoN+q7UmhAejxgD27APiRjh1vwCFo53gSqdT0BM= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.36/go.mod h1:6u00gmlTGR6W0b2k9NBrld7MnOEmf1Spqx0VVt6AqyE= +github.com/aws/aws-sdk-go-v2 v1.47.3 h1:HRoT/MkNi3bjO5xF4dCzLzvVmkvRGHj3/cLINDnJejk= +github.com/aws/aws-sdk-go-v2 v1.47.3/go.mod h1:xSl+OSI5ZUw6bSMupWc218zE5Pl+65MCCu3ySWFY99A= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.22 h1:oiEmPz/YMMeh/JvAE8xSxNCIsvWE6lpFe4ZPlyFykQI= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.22/go.mod h1:QWUDuRi9PFjBHIU2iH1Pkldbe7zqLfXJC4wWLbF8nuQ= +github.com/aws/aws-sdk-go-v2/config v1.33.9 h1:Hv6bcQUJVnmuWaKjqD6Ot8sE75NrWsWV20oGT5aWle0= +github.com/aws/aws-sdk-go-v2/config v1.33.9/go.mod h1:ivowmrZNfBQLcg4QkaItgi5wae4Bzot9RzIdbY1hfTg= +github.com/aws/aws-sdk-go-v2/credentials v1.20.9 h1:SNO55PnWhaDafsOcv16lCA0kdoFMl/YlegWoVsU02s0= +github.com/aws/aws-sdk-go-v2/credentials v1.20.9/go.mod h1:+2reOTRtdD3VSBqpRDNwrZIYy8yMCYa7oK3WKTJ/I1I= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.20.3 h1:gr3b87OLB29jymWPzp/CAyXwQRJVE+sC4Wm0qBIKHsk= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.20.3/go.mod h1:BRjf4L/Yx2hY54o+ZibPbLJyMMeSwqYQXwcJfqW66a8= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.23.14 h1:nX4dV32e7e2GSg60GojffG61w4tvYxVpvEGWfSlcImo= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.23.14/go.mod h1:dNw78YbA0ylhEVJ1h84fPdtIiWkVTaszT7oHkE/cq5E= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.5.6 h1:CqL8NN3p4I0JTwwV5MEoatIl4Y2amZ2X9dRD+0hbRL0= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.5.6/go.mod h1:exdJ32hMqXl0Wyo6NwqEC5yIhtua3+PDaKE8P29m4qE= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.8.6 h1:FpBq24TG6WVSObTNhQOv7Q0088rounUUlwn3zlNItkM= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.8.6/go.mod h1:ONzdPVYC95oBOu0VWNEsKEntcoemP3xVKjT+qWml1s4= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.5.6 h1:Qmn60RWuk9+bd2ddvJJqwf3Cpac3VvGMOdbGemtUhX4= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.5.6/go.mod h1:h/YJhe4AVyQxEUMluph10iqV7mjajH7A9L+BHF5ppis= +github.com/aws/aws-sdk-go-v2/service/ecr v1.66.4 h1:qnnwXADWCoti36pKognFfw3L4bPYW1wIlsm4JqYmjDY= +github.com/aws/aws-sdk-go-v2/service/ecr v1.66.4/go.mod h1:uDza1Eipo/Olii3CCgLglHmAni24PScSAhpfIKbUl0c= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.21 h1:e6YW5uME30TkrElR+4/xcY7NB6CCj2dcv7vtmGXhfhQ= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.21/go.mod h1:obpHAMP693+f3/A8PkLhIqfK1C+NWWn8zXzqD3OH520= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.11.7 h1:CwvFlKw0uUScfgOMflXSRZa+ayXgOf6wk7lhyMemQYU= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.11.7/go.mod h1:4SbD8BB+p+QEnG0aX6DoWwrtk9SufyYXRsUv0nve8LE= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.14.6 h1:LHHdobjo5le1sjJdolitV7uVvYg3wkaeM1Ju2fDgeZQ= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.14.6/go.mod h1:CBGB0evAiaMD3Lk4wPO7LQCcCZLuhzL5Qf/wfEUHQ5w= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.20.6 h1:mYViDr2azcgxOpRrObZOl631bvavqILoE/L+Kxgbwys= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.20.6/go.mod h1:OXVdAo9jNhggB+hJRGOyy7WolGTKB6Rg7IIulDeSzPM= github.com/aws/aws-sdk-go-v2/service/kms v1.55.0 h1:uB8ymkVosyourmGXCZHyWhJ4wuKA4xq3ii2dVMPtBZY= github.com/aws/aws-sdk-go-v2/service/kms v1.55.0/go.mod h1:rK4RITSY/qJw3qVJ7p19fceOWuvrisqqOChFkX05n5I= -github.com/aws/aws-sdk-go-v2/service/s3 v1.107.0 h1:OkYV+1171za+ab9otU1tGxMXhx6uZvwVEtVddjLuYTg= -github.com/aws/aws-sdk-go-v2/service/s3 v1.107.0/go.mod h1:5FTZoQxhmLEiCAtYVk6V+t0iS/B5yGZVLZ3Wq5FDJZI= -github.com/aws/aws-sdk-go-v2/service/securityhub v1.76.0 h1:J/olEWGa5NIIZiejnuG4u+ahM5liNIKa07sEP5OPbqs= -github.com/aws/aws-sdk-go-v2/service/securityhub v1.76.0/go.mod h1:zHr00dDys+8JbwQALvat8WGyudYfzc2W3dw79e+bSWs= -github.com/aws/aws-sdk-go-v2/service/signin v1.5.4 h1:cOJELVNrq5Q3Udry2GLuHUM7MhwpeaQRdYaoa6GI/yI= -github.com/aws/aws-sdk-go-v2/service/signin v1.5.4/go.mod h1:f4LxzKBtaTxD7xh3PiVg3CE1tchQemfmghaJr+NbK2c= -github.com/aws/aws-sdk-go-v2/service/sso v1.33.4 h1:AMW7a7S8iQaHjBYZdU3PCq4GKRPijTPRAc7e6XtEThY= -github.com/aws/aws-sdk-go-v2/service/sso v1.33.4/go.mod h1:QQNsFV1DVXoXcZt18FS8lI8rtUrlDyAuWZLQ5shunv4= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.38.4 h1:AsbZcJAQPRmHDJG8K1N0pof/1zPWjVT8TFlTWuGLSvo= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.38.4/go.mod h1:6imqztH0//t0mKbl6yWl7swSEl7F/w32oAmqB3vP1ag= -github.com/aws/aws-sdk-go-v2/service/sts v1.45.4 h1:w/AryDYMjSUANSQ2uoZxJovUsMTwWJNTv3IMex30Y+4= -github.com/aws/aws-sdk-go-v2/service/sts v1.45.4/go.mod h1:WeBiAa67azG7Su9Vf+ChGDBLiAozJCXzdjXiPBUwtbc= -github.com/aws/smithy-go v1.27.8 h1:FR0dxZfIlV7Z8eh2iHfIofdunw382XsDV3Mxt9nUvRY= -github.com/aws/smithy-go v1.27.8/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc= +github.com/aws/aws-sdk-go-v2/service/s3 v1.114.3 h1:NyeuyXkZL476uoAowNActm4XJO1QPKf7aassgXHpiqA= +github.com/aws/aws-sdk-go-v2/service/s3 v1.114.3/go.mod h1:GfoBeKMDJecgRUsGf/0RGdx0NJAh81ObTd922h8pQys= +github.com/aws/aws-sdk-go-v2/service/securityhub v1.85.0 h1:nU2sJfyfpTPItClgNXzh4ILgQLceB7R3zc/Pt5ssuAI= +github.com/aws/aws-sdk-go-v2/service/securityhub v1.85.0/go.mod h1:/had+BOeuoD/E3LQR4PxHLZase9U7VOdXkC/+4425FA= +github.com/aws/aws-sdk-go-v2/service/signin v1.10.4 h1:tvpDjuUvgKURf3Yk4hOaGbZ4QdY+070OWcA5d6LUv2A= +github.com/aws/aws-sdk-go-v2/service/signin v1.10.4/go.mod h1:3ibVKg5Ng82Zby8++jELTD2nHxiPk2DJRLEeW/LKp8M= +github.com/aws/aws-sdk-go-v2/service/sso v1.38.4 h1:ChCtagixSFOxltv0o6E3NT8F7ksvZtZGPwUBynO5Nmk= +github.com/aws/aws-sdk-go-v2/service/sso v1.38.4/go.mod h1:+FEO9jrVMpc9oN3CdAxJbtlQEu3z8UddDPSedpeM3PY= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.43.4 h1:j6c+HA4AoS0EBEjArPjavFEBrucJEryfrQU0TffmACk= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.43.4/go.mod h1:RhghaXUk9q66VtOQUX1FdPddQuHnqQZzbB0fEYXmPRA= +github.com/aws/aws-sdk-go-v2/service/sts v1.51.4 h1:OKEfbf2tcfsF2pBk/S9QqNpo6alaAtiBs4hysCsBjPw= +github.com/aws/aws-sdk-go-v2/service/sts v1.51.4/go.mod h1:mCd6qGo9b8hTtfjgsmNkFlzwjyce4owd7HDVFnCLXhM= +github.com/aws/smithy-go v1.28.5 h1:OqbqKtzY9NUnr2yAe9+hiTdFb20tNaK/lI0PMOGXX9k= +github.com/aws/smithy-go v1.28.5/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc= github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= github.com/beevik/etree v1.7.0 h1:xjBk9O4p4x7D1YajePjfLzdaFC4/uYUENA7P0pv6gXA= @@ -273,12 +272,8 @@ github.com/bits-and-blooms/bitset v1.24.4 h1:95H15Og1clikBrKr/DuzMXkQzECs1M6hhoG github.com/bits-and-blooms/bitset v1.24.4/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= -github.com/bmatcuk/doublestar/v4 v4.10.0 h1:zU9WiOla1YA122oLM6i4EXvGW62DvKZVxIe6TYWexEs= -github.com/bmatcuk/doublestar/v4 v4.10.0/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= -github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY= -github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= -github.com/bshuster-repo/logrus-logstash-hook v1.1.0 h1:o2FzZifLg+z/DN1OFmzTWzZZx/roaqt8IPZCIVco8r4= -github.com/bshuster-repo/logrus-logstash-hook v1.1.0/go.mod h1:Q2aXOe7rNuPgbBtPCOzYyWDvKX7+FpxE5sRdvcPoui0= +github.com/bmatcuk/doublestar/v4 v4.10.3 h1:1UIv1+fqH3++ViVkpnaPTB+Pi1UHycnPFAq14zgK+gI= +github.com/bmatcuk/doublestar/v4 v4.10.3/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= @@ -330,12 +325,12 @@ github.com/cockroachdb/logtags v0.0.0-20241215232642-bb51bb14a506 h1:ASDL+UJcILM github.com/cockroachdb/logtags v0.0.0-20241215232642-bb51bb14a506/go.mod h1:Mw7HqKr2kdtu6aYGn3tPmAftiP3QPX63LdK/zcariIo= github.com/cockroachdb/metamorphic v0.0.0-20231108215700-4ba948b56895 h1:XANOgPYtvELQ/h4IrmPAohXqe2pWA8Bwhejr3VQoZsA= github.com/cockroachdb/metamorphic v0.0.0-20231108215700-4ba948b56895/go.mod h1:aPd7gM9ov9M8v32Yy5NJrDyOcD8z642dqs+F0CeNXfA= -github.com/cockroachdb/pebble/v2 v2.1.6 h1:GDo7Z2+LgFZ7LJLdLmBXhDeTVIwgSPGxIT15hE7vGqM= -github.com/cockroachdb/pebble/v2 v2.1.6/go.mod h1:Reo1RTniv1UjVTAu/Fv74y5i3kJ5gmVrPhO9UtFiKn8= +github.com/cockroachdb/pebble/v2 v2.1.7 h1:hFQnbsniSWg9BVcNKMuaUufYPiVXY6uJvaY9grbQ9+U= +github.com/cockroachdb/pebble/v2 v2.1.7/go.mod h1:JhU5cqqYkr2BdsBHbZhRZOryAtfhcV3eNI/oBcbrxWc= github.com/cockroachdb/redact v1.1.6 h1:zXJBwDZ84xJNlHl1rMyCojqyIxv+7YUpQiJLQ7n4314= github.com/cockroachdb/redact v1.1.6/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= -github.com/cockroachdb/swiss v0.0.0-20251224182025-b0f6560f979b h1:VXvSNzmr8hMj8XTuY0PT9Ane9qZGul/p67vGYwl9BFI= -github.com/cockroachdb/swiss v0.0.0-20251224182025-b0f6560f979b/go.mod h1:yBRu/cnL4ks9bgy4vAASdjIW+/xMlFwuHKqtmh3GZQg= +github.com/cockroachdb/swiss v0.0.0-20260820225851-333444432258 h1:IJ+uNItEm0qx9FE2AgIc1PMsCUtk8nbSIzhQE1t5GWw= +github.com/cockroachdb/swiss v0.0.0-20260820225851-333444432258/go.mod h1:yBRu/cnL4ks9bgy4vAASdjIW+/xMlFwuHKqtmh3GZQg= github.com/cockroachdb/tokenbucket v0.0.0-20250429170803-42689b6311bb h1:3bCgBvB8PbJVMX1ouCcSIxvsqKPYM7gs72o0zC76n9g= github.com/cockroachdb/tokenbucket v0.0.0-20250429170803-42689b6311bb/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ= github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb h1:EDmT6Q9Zs+SbUoc7Ik9EfrFqcylYqgPZ9ANSbTAntnE= @@ -346,8 +341,8 @@ github.com/containers/image/v5 v5.36.2 h1:GcxYQyAHRF/pLqR4p4RpvKllnNL8mOBn0eZnqJ github.com/containers/image/v5 v5.36.2/go.mod h1:b4GMKH2z/5t6/09utbse2ZiLK/c72GuGLFdp7K69eA4= github.com/containers/storage v1.59.1 h1:11Zu68MXsEQGBBd+GadPrHPpWeqjKS8hJDGiAHgIqDs= github.com/containers/storage v1.59.1/go.mod h1:KoAYHnAjP3/cTsRS+mmWZGkufSY2GACiKQ4V3ZLQnR0= -github.com/coreos/go-oidc/v3 v3.20.0 h1:EtE0WIBHk03N+DqGkY4+UONzzZHk7amKt6IyNd7OsZE= -github.com/coreos/go-oidc/v3 v3.20.0/go.mod h1:DYCf24+ncYi+XkIH97GY1+dqoRlbaSI26KVTCI9SrY4= +github.com/coreos/go-oidc/v3 v3.21.0 h1:wZo4Q9Pum8dYEj0eMUPrqR+kvuGkeUplbLpNCkBqoWM= +github.com/coreos/go-oidc/v3 v3.21.0/go.mod h1:DYCf24+ncYi+XkIH97GY1+dqoRlbaSI26KVTCI9SrY4= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/go-systemd/v22 v22.7.0 h1:LAEzFkke61DFROc7zNLX/WA2i5J8gYqe0rSj9KI28KA= @@ -377,22 +372,22 @@ github.com/digitorus/pkcs7 v0.0.0-20230818184609-3a137a874352 h1:ge14PCmCvPjpMQM github.com/digitorus/pkcs7 v0.0.0-20230818184609-3a137a874352/go.mod h1:SKVExuS+vpu2l9IoOc0RwqE7NYnb0JlcFHFnEJkVDzc= github.com/digitorus/timestamp v0.0.0-20231217203849-220c5c2851b7 h1:lxmTCgmHE1GUYL7P0MlNa00M67axePTq+9nBSGddR8I= github.com/digitorus/timestamp v0.0.0-20231217203849-220c5c2851b7/go.mod h1:GvWntX9qiTlOud0WkQ6ewFm0LPy5JUR1Xo0Ngbd1w6Y= -github.com/distribution/distribution/v3 v3.1.1 h1:KUbk7C8CfaLXy8kbf/hGq9cad/wCoLB6dbWH6DMbmX0= -github.com/distribution/distribution/v3 v3.1.1/go.mod h1:d7lXwZpph0bVcOj4Aqn0nMrWHIwRQGdiV5TLeI+/w6Y= +github.com/distribution/distribution/v3 v3.1.2 h1:/Bv2YIqqSR00HiO49FT93hovy6r9IlrzwUDsJjCN5qg= +github.com/distribution/distribution/v3 v3.1.2/go.mod h1:Oz0Drs2Tx3iTXzK3DhUD4otfTfqlCxlWVC7QJeXWBP0= github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI= github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= -github.com/docker/cli v29.6.2+incompatible h1:/bjePvcbbFTnRrMfWJBY7AjfICdsiLVgHn6LwTVOcqw= -github.com/docker/cli v29.6.2+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli v29.7.2+incompatible h1:dlkwallR8XqfeVnA2ELEhdwvb4lsSwuB4IgsG8Q9cLY= +github.com/docker/cli v29.7.2+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk= github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker-credential-helpers v0.9.5 h1:EFNN8DHvaiK8zVqFA2DT6BjXE0GzfLOZ38ggPTKePkY= github.com/docker/docker-credential-helpers v0.9.5/go.mod h1:v1S+hepowrQXITkEfw6o4+BMbGot02wiKpzWhGUZK6c= github.com/docker/go-events v0.0.0-20250808211157-605354379745 h1:yOn6Ze6IbYI/KAw2lw/83ELYvZh6hvsygTVkD0dzMC4= github.com/docker/go-events v0.0.0-20250808211157-605354379745/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= -github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8= -github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= +github.com/docker/go-metrics v0.1.0 h1:r76KPNpstz+IvQKSWpYegSkkyzex0V3A1ZGVx6bhGlY= +github.com/docker/go-metrics v0.1.0/go.mod h1:PciI3sONtB051kXALN1JoIlpcu54E1FuPh+4DuqEzyw= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 h1:UhxFibDNY/bfvqU5CAUmr9zpesgbU6SWc8/B4mflAE4= @@ -452,8 +447,8 @@ github.com/fatih/color v1.19.0 h1:Zp3PiM21/9Ld6FzSKyL5c/BULoe/ONr9KlbYVOfG8+w= github.com/fatih/color v1.19.0/go.mod h1:zNk67I0ZUT1bEGsSGyCZYZNrHuTkJJB+r6Q9VuMi0LE= github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= -github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= -github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/felixge/httpsnoop v1.1.0 h1:3YtUj32ZZkqZtt3sZZsClsymw/QDuVfpNhoA31zeORc= +github.com/felixge/httpsnoop v1.1.0/go.mod h1:Zqxgdd+1Rkcz8euOqdr7lqgCRJztwr5hp9vDSi5UZCE= github.com/foxcpp/go-mockdns v1.2.0 h1:omK3OrHRD1IWJz1FuFBCFquhXslXoF17OvBS6JPzZF0= github.com/foxcpp/go-mockdns v1.2.0/go.mod h1:IhLeSFGed3mJIAXPH2aiRQB+kqz7oqu8ld2qVbOu7Wk= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= @@ -501,8 +496,8 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gorp/gorp/v3 v3.1.0 h1:ItKF/Vbuj31dmV4jxA1qblpSwkl9g1typ24xoe70IGs= github.com/go-gorp/gorp/v3 v3.1.0/go.mod h1:dLEjIyyRNiXvNZ8PSmzpt1GsWAUK8kjVhEpjH8TixEw= -github.com/go-jose/go-jose/v4 v4.1.4 h1:moDMcTHmvE6Groj34emNPLs/qtYXRVcd6S7NHbHz3kA= -github.com/go-jose/go-jose/v4 v4.1.4/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= +github.com/go-jose/go-jose/v4 v4.1.5 h1:RjgjO2LOtWOJKUC5wpwY9LR3B3vwVAz6JS2YHfYU6eA= +github.com/go-jose/go-jose/v4 v4.1.5/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= @@ -523,69 +518,67 @@ github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= -github.com/go-openapi/analysis v0.26.0 h1:1xECln1iMMmQnTjgcknC1vi1hA4KISt6IHpSwnqcuwI= -github.com/go-openapi/analysis v0.26.0/go.mod h1:40gERFi/2dyXA1FaqRRLxkv1IlC6X+GPDNd1xrYAjZE= -github.com/go-openapi/errors v0.22.8 h1:oP7sW7TWc3wFFjrzzj0nI83H2qMBkNjNfSd+XRejk/I= -github.com/go-openapi/errors v0.22.8/go.mod h1:BuUoHcYrU6E7V9gfj1I5wLQqgtIHnup/alXZ8KdgQ0w= +github.com/go-openapi/analysis v1.0.0 h1:sNvbAGCJqUTqIAodr9IVqJMmuZas3YS9ms1dGK9yiJ4= +github.com/go-openapi/analysis v1.0.0/go.mod h1:NhYjJ57fnE+bcE7UwrJyMkhWA3Dfz7TdiBfTVAnos4Y= +github.com/go-openapi/errors v0.22.9 h1:HI9+SyVYiRzyeBQGv0CbWbQa+u2S0nny7G7AhY+UMiM= +github.com/go-openapi/errors v0.22.9/go.mod h1:R73q66sXP2smzAGgFOI4nqtusRK2xN5pYCjsij+KX58= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= -github.com/go-openapi/jsonpointer v1.0.0 h1:kR9tHqY0CtZaOPVFm622dPVNhrvYpwr4uCxgL3h1H8s= -github.com/go-openapi/jsonpointer v1.0.0/go.mod h1:Z3rw7dWu1p9IgitXCFamSlA5lmDiklEB6vkaxcNZW5Y= +github.com/go-openapi/jsonpointer v1.0.1 h1:2KxywRmNwJkT/FMBa3iRNHEaAxSJvjqoufQZy3au1Mg= +github.com/go-openapi/jsonpointer v1.0.1/go.mod h1:wI7ZYsFmbIi9nBXOZqgDaS/bqOchRGZjqxFli7FBYxY= github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns= github.com/go-openapi/jsonreference v0.20.1/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= -github.com/go-openapi/jsonreference v1.0.0 h1:jlmTr6torcd1YgDQvSfNmRtKzYDO4FGBkrAdlAVWnpY= -github.com/go-openapi/jsonreference v1.0.0/go.mod h1:jtwdyGbJk0Xhe5Y+rwtglQP6Sb1WZST4rT32LWB+sv0= -github.com/go-openapi/loads v0.25.1 h1:toKQdIDLxlqfKLLGUUmUsiTd5/X0Chzvde9EGYQP/Ac= -github.com/go-openapi/loads v0.25.1/go.mod h1:33Hen4tsKXHL45TyYojvfD5fZUFN4O1y4r/XhsRW2zc= -github.com/go-openapi/runtime v0.32.5 h1:+aDmMj6xB4P8isUwEOERtgHW3JNI/i93KvTWNa4LRik= -github.com/go-openapi/runtime v0.32.5/go.mod h1:eNPUCk8LAYV803GHJP3xDSNllJQfv+pBlXpFfWqpPO8= -github.com/go-openapi/runtime/server-middleware v0.30.0 h1:8rPoJ/xv7JL8BsovaqboKETlpWBArVh8n+0L/GyePog= -github.com/go-openapi/runtime/server-middleware v0.30.0/go.mod h1:OYNT/TxNvB/VK5oe4htM2jDTwlEXuejVJmu0DVZfAMs= -github.com/go-openapi/spec v0.22.9 h1:/vKIFDcGKp0ktZWGbym/tJEWbk6/XOEmAVU0kqKMH+w= -github.com/go-openapi/spec v0.22.9/go.mod h1:b/mNUYIOQOyIiUzUzXEE8xzyZqf93KvM9hQGP91yfl0= -github.com/go-openapi/strfmt v0.27.0 h1:kbcTeaD9TXuXD0hhMXzuYa1sdTo6+dWGvwjW93E80IM= -github.com/go-openapi/strfmt v0.27.0/go.mod h1:s/qhDqfY72irigXUGJmtgid2Rm+3tnz3k8hZaRmvWYc= +github.com/go-openapi/jsonreference v1.0.2 h1:oS4et8FOf3p3UQxEo4Xt0esijmBUM+F259Xl72OSZsc= +github.com/go-openapi/jsonreference v1.0.2/go.mod h1:TbUNSOo+fcorZjFaNoiSDSoaNnnZtqJtLGR1PuvE/Cs= +github.com/go-openapi/loads v0.25.3 h1:V+jKy/thXWdLJUuYC8sZX2dICyAa8M3DokF70jj34P0= +github.com/go-openapi/loads v0.25.3/go.mod h1:LgLyCSOLBL2Qnj0Ps1oo2YH8jZoEKsMeVZCc+ALIxFo= +github.com/go-openapi/runtime v0.33.3 h1:qVgTDaFH+pzO8UqlwYNVmx2DD+nwVK3rB65V29ednD0= +github.com/go-openapi/runtime v0.33.3/go.mod h1:57crQFXXnCtT68LuAd+NOELX5tSF4ZE1GFW3Z+r/KCk= +github.com/go-openapi/runtime/server-middleware v0.33.3 h1:Td5UBla/J/KCjlsD0tmZYWQWxnT4gHpfXbueLQv9Umw= +github.com/go-openapi/runtime/server-middleware v0.33.3/go.mod h1:dopwrwqIqXe4xWtovDZkkXJzYqKw+Ybmy7G/hIDUWKY= +github.com/go-openapi/spec v1.0.1 h1:lj2vdGpNDcVgwRc6qXdw6qt/KQpCtSa9tnUH6vpDPDk= +github.com/go-openapi/spec v1.0.1/go.mod h1:M//GWQGtDUAjnP37gE6fInLgaczB+FatoipV3H1fYw8= +github.com/go-openapi/strfmt v0.27.3 h1:cyf4J5Wjpd6bFpAs44MF8PsbWF/mWXhn82Ck/hgQZgw= +github.com/go-openapi/strfmt v0.27.3/go.mod h1:Bl+xadPLa3nhBiaCAxNND1vrQfzyEjF0vBrLx96n/4E= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= -github.com/go-openapi/swag v0.26.1 h1:l5sVEyVpwj+DDYeZyo7wQI/Ebn/mKYIyGB/pFwAfGoQ= -github.com/go-openapi/swag v0.26.1/go.mod h1:yNY38BbIVthxbkDtq1UHBCGasBqjakW3lCR6ANzdBEw= -github.com/go-openapi/swag/cmdutils v0.26.1 h1:f2iE1ijYaJ3nuu5PaEMx3zpEhzhZFgivCJObWEObLIQ= -github.com/go-openapi/swag/cmdutils v0.26.1/go.mod h1:Sm1MVFMkF6guJJ+pQqHnQA3N0j9qALV3NxzDSv6bETM= -github.com/go-openapi/swag/conv v0.28.0 h1:GtqqbyFe7vR5Y7ehxG9W6/OvrSFdf1OLeTGp40TqxH8= -github.com/go-openapi/swag/conv v0.28.0/go.mod h1:mbUE+mzctnhxi864m0Q07SpN8OowD9JhxmxuYvZZD/k= -github.com/go-openapi/swag/fileutils v0.28.0 h1:Z04XWQD7R8Eq+7GnOrjovBxPPmZzsS4gt2H2GPGIViU= -github.com/go-openapi/swag/fileutils v0.28.0/go.mod h1:VvJFZLTZS0AI854gEQz5tk7dBESdLjiNUMSZ/th2ry8= -github.com/go-openapi/swag/jsonname v0.26.1 h1:VReupaV6WxlAsCn0e4DUfgV6bPmINnPpyJDLqSfNPcE= -github.com/go-openapi/swag/jsonname v0.26.1/go.mod h1:OvdW6BoWoj33pTfi7x9vFrgmT+fk7aw0BRwvCE0YOuc= -github.com/go-openapi/swag/jsonutils v0.28.0 h1:YIch6FwO7RXzeAnbO8Tu7dWBZeUEH+4nA0HXltVTnv4= -github.com/go-openapi/swag/jsonutils v0.28.0/go.mod h1:CYM3WlTUcagR2ZoHdz54di/cbBqt82tuxuXgAjxw+mg= -github.com/go-openapi/swag/jsonutils/fixtures_test v0.28.0 h1:qV+VVUAx5Oro8WjVWpZeql7YReTKhT4smR4zhcOQZr0= -github.com/go-openapi/swag/jsonutils/fixtures_test v0.28.0/go.mod h1:mofwUWx70wvskwESqRJ//k/9kURmCgyJl5m5Ppoh5kY= -github.com/go-openapi/swag/loading v0.28.0 h1:td8QZdZC9MIYGGSnSPKShKiK22I2tU5UQvuUhIBPRLU= -github.com/go-openapi/swag/loading v0.28.0/go.mod h1:rXB0QiQX5mMveXEA7ouM4KiiM9jVJe4K6BVbwhD1M4k= -github.com/go-openapi/swag/mangling v0.28.0 h1:pH8eyeNO9SLYsTMWJrurnNfKmDa28XrlA+HePVD53VM= -github.com/go-openapi/swag/mangling v0.28.0/go.mod h1:jtBE2+V+3pILxOR7Vgce+Cwp6A2PgZbvVqfNntbVs0w= -github.com/go-openapi/swag/netutils v0.26.1 h1:BNctoc39WTAUMxyAs355fExOPzMZtPbZ0ZZ1Am2FR5M= -github.com/go-openapi/swag/netutils v0.26.1/go.mod h1:y02vByhZhQPAVwOX+0KipXFZ/hUbk6G/Enhf5rGaOkQ= -github.com/go-openapi/swag/pools v0.28.0 h1:HPMZWSAfce3rdVTFcjFiCIBtDg9h4x2QlRrHipwhxeU= -github.com/go-openapi/swag/pools v0.28.0/go.mod h1:kVQefhSK5RWuRe7BXsL8htgBPAMpN7HDGpGEknqugeE= -github.com/go-openapi/swag/stringutils v0.28.0 h1:ixsc9iYgDPubHL/8nSkbnryEHpD2VRlBMLKpQyPXcDU= -github.com/go-openapi/swag/stringutils v0.28.0/go.mod h1:lzRN95CxXmA03XcDWHLOb6nOMcxCqR5rGY0lOgsfRoM= -github.com/go-openapi/swag/typeutils v0.28.0 h1:nRBKSBXjDgf01VDPB3fWeD9nQuhCOVeIYAkUx2tbkyY= -github.com/go-openapi/swag/typeutils v0.28.0/go.mod h1:Srm0xFNRZ1Y+vCxJclo5qzx8aj+1pAKda/YfFPrG0dQ= -github.com/go-openapi/swag/yamlutils v0.28.0 h1:TV3JXH6DS46KUroDtMLAYHGkdWf5VDq3wVWFirmzROY= -github.com/go-openapi/swag/yamlutils v0.28.0/go.mod h1:x0q/yndZHEgk9Rx3DyDqzFUmHy55KTvIZldvF2dTJXs= -github.com/go-openapi/testify/enable/yaml/v2 v2.6.0 h1:gGHwAJ0R/5jU8BEGDbfRNR3hL68dAVi84WuOApp29B0= -github.com/go-openapi/testify/enable/yaml/v2 v2.6.0/go.mod h1:tY+St1SGq4NFl0QIqdTY4aEdbChAHxhyB77XQi9iJCo= -github.com/go-openapi/testify/v2 v2.6.0 h1:5PKH2HE7YJ/LuRPQGvSxBRlFXNQhSetBLlGAgUEu3ug= -github.com/go-openapi/testify/v2 v2.6.0/go.mod h1:SgsVHtfooshd0tublTtJ50FPKhujf47YRqauXXOUxfw= -github.com/go-openapi/validate v0.26.3 h1:OkfZgLvLDnGP2hrRGD+42WBiPWWkoHomTJ+IVI+KaDc= -github.com/go-openapi/validate v0.26.3/go.mod h1:7DOOa4raU6NRe7A8VQSKbm3VcuUIioREYHFt+er9Sk8= +github.com/go-openapi/swag v0.29.2 h1:9n8frkcsuQRA0INU31VbxNxt1zBaHxrHYGEf5BUjFi4= +github.com/go-openapi/swag v0.29.2/go.mod h1:RkCiX1gCVXWgLOavDXE3ALJrQ/VO2ziiIzOUs3z10xo= +github.com/go-openapi/swag/cmdutils v0.29.2 h1:cXEzX/nWCODon251f+1HgL75/R4XXML5IZxgLCWMoro= +github.com/go-openapi/swag/cmdutils v0.29.2/go.mod h1:XziaSVzYqkDvpWXzASfWajw2YvJrLscq610O2XiyqJw= +github.com/go-openapi/swag/conv v0.29.2 h1:8c9shoB8l0QRSR6ymq1llHdBWDqpIgJfjTGHx3Vuhm0= +github.com/go-openapi/swag/conv v0.29.2/go.mod h1:AZS0YigTNf8qNtD6WqJz/N4RUNmpr76SyjFGkq4+p6Q= +github.com/go-openapi/swag/fileutils v0.29.2 h1:mdUL+Vw5ah1fO1AvFCoHeIyv7YZsCz2MN3KNqd/lLVI= +github.com/go-openapi/swag/fileutils v0.29.2/go.mod h1:7QKmmodjAebaq61lGVJa8ldLdGeMF4DSgYv8tXOGGo0= +github.com/go-openapi/swag/jsonutils v0.29.2 h1:uZNSD2/rJDYAfvsLYkykTzXuyxM3QpDKV9jhRHrMu6k= +github.com/go-openapi/swag/jsonutils v0.29.2/go.mod h1:ONTdNvj3Y+IXRzfa17E+Rgt2ns/qiSOYjIo2K7v2yDs= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.29.2 h1:w+Fd6EBOMGlC74GYGHqCLGyb3Bpams8TtNrgM/SG4jo= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.29.2/go.mod h1:HC2egPORFzbj/gf05Zrfgz8Mgplx3oW7hgGi7pjZVhM= +github.com/go-openapi/swag/loading v0.29.2 h1:QU1ry24e6r6Shoxe380Nx0X5iKkpRO+hJffsyJ2dVlY= +github.com/go-openapi/swag/loading v0.29.2/go.mod h1:DqilDjuiJKETecsS4TRopWG1acUDsfqN39ZmQhPu6uI= +github.com/go-openapi/swag/mangling v0.29.2 h1:ltdo3K0tTP4P6zWhVVWDU9D37/YYBuMJRdZxiS2Dtog= +github.com/go-openapi/swag/mangling v0.29.2/go.mod h1:RjDi4TnItAenS3cgCXSpIl1kKbjG7il6pnmQVl/8bp8= +github.com/go-openapi/swag/netutils v0.29.2 h1:dBli6jyUa93sDS/XYWShJzf4+nnVfFKfvY9SLUaUzB8= +github.com/go-openapi/swag/netutils v0.29.2/go.mod h1:1pM6Xg/Um8E1eps3umWl8Hme3ByWXOtHsvFC0CULHUE= +github.com/go-openapi/swag/pools v0.29.2 h1:PlGoDRF8WtSyXkedZZkpW3f9wDhFf3u8KtaBcmgmh8c= +github.com/go-openapi/swag/pools v0.29.2/go.mod h1:V3lhxVT4qDYRqc2MRSSbLsTYIYV/2HlHafhyEkmzLIc= +github.com/go-openapi/swag/stringutils v0.29.2 h1:lcnBxwAaysT3bMUVBfn9V/PkfVqkurpqufKU6rTUMGk= +github.com/go-openapi/swag/stringutils v0.29.2/go.mod h1:i9cdh7sGaa0nm3CqIvH5IM5h2QClk1wns2ktKeILvRI= +github.com/go-openapi/swag/typeutils v0.29.2 h1:O7aVvkTs3pXwikgtrPLenigEMdQFgONKRooQA9pgf2I= +github.com/go-openapi/swag/typeutils v0.29.2/go.mod h1:7+GDG+uz9Ke+eVt4rClZg7wklSDp8hT/mKNh/pC26TE= +github.com/go-openapi/swag/yamlutils v0.29.2 h1:IFKFFeDnuIwzfsuWRQU+rI8iL3g4XyAYjV/RlnlxPLM= +github.com/go-openapi/swag/yamlutils v0.29.2/go.mod h1:7MGqtcrK73sxQ4ceiyIf8qiXS/s09JLMdR5esK5euYQ= +github.com/go-openapi/testify/enable/yaml/v2 v2.8.0 h1:dvOQNZ2ovOdogn902NYq7i6jUI9Dma4qyjTXABY5YTY= +github.com/go-openapi/testify/enable/yaml/v2 v2.8.0/go.mod h1:3VwZZUT6nWcAjhIr2RypXxlsxd3mPPtXh3T8z65aRlQ= +github.com/go-openapi/testify/v2 v2.8.0 h1:19QDx5b57p8KjO2E4sgs/woL4Akp+FGLRlVm2xn0Rho= +github.com/go-openapi/testify/v2 v2.8.0/go.mod h1:4gUN8jC+RqOE2qjW/vDmfyTvl5BCht4qL7oca0odrak= +github.com/go-openapi/validate v1.0.0 h1:dFsYCLVUQUL6Vi2lQSexgwmCXDuHe7eWRDhQxkE+xYA= +github.com/go-openapi/validate v1.0.0/go.mod h1:wwXGRqMQzOZ7PCqBcgNk+DD9+Cacnxv7we5T0M/eA3Y= github.com/go-rod/rod v0.116.2 h1:A5t2Ky2A+5eD/ZJQr1EfsQSe5rms5Xof/qj296e+ZqA= github.com/go-rod/rod v0.116.2/go.mod h1:H+CMO9SCNc2TJ2WfrG+pKhITz57uGNYU43qYHh438Mg= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= @@ -604,13 +597,13 @@ github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPE github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/gobuffalo/flect v1.0.3 h1:xeWBM2nui+qnVvNM4S3foBhCAL2XgPU+a7FdpelbTq4= github.com/gobuffalo/flect v1.0.3/go.mod h1:A5msMlrHtLqh9umBSnvabjsMrCcCpAyzglnDvkbYKHs= -github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= -github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/gobwas/glob v1.0.0 h1:p+FKbLEIsK1yZ39/OINwFvqNb5oyPY4H8xcy6uYu8dg= +github.com/gobwas/glob v1.0.0/go.mod h1:oWCdo522i2P1n/hMXGNWs7yoV4wy/ciZuUIbvKj5rkc= github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw= github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/godbus/dbus/v5 v5.2.2 h1:TUR3TgtSVDmjiXOgAAyaZbYmIeP3DPkld3jgKGV8mXQ= -github.com/godbus/dbus/v5 v5.2.2/go.mod h1:3AAv2+hPq5rdnr5txxxRwiGjPXamgoIHgz9FPBfOp3c= +github.com/godbus/dbus/v5 v5.2.3 h1:IQNSXULh6Nc4ZH8ETJ5Mdsj8loUFCWSBnsjmJkyjUB8= +github.com/godbus/dbus/v5 v5.2.3/go.mod h1:3AAv2+hPq5rdnr5txxxRwiGjPXamgoIHgz9FPBfOp3c= github.com/gofrs/flock v0.13.0 h1:95JolYOvGMqeH31+FC7D2+uULf6mG61mEZ/A8dRYMzw= github.com/gofrs/flock v0.13.0/go.mod h1:jxeyy9R1auM5S6JYDBhDt+E2TCo7DkratH4Pgi8P+Z0= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -666,8 +659,8 @@ github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Z github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= -github.com/google/cel-go v0.29.0 h1:fEG+Ja3YRwNOqnQxTyJwoByAUAvTuxUGiro/jhrm4F4= -github.com/google/cel-go v0.29.0/go.mod h1:X0bD6iVNR8pkROSOoHVdgTkzmRcosof7WQqCD6wcMc8= +github.com/google/cel-go v0.31.0 h1:H0bhpFTqOvmHrBGrWKp7ZlhBm5Hh8PYUEXnwxT1LL7A= +github.com/google/cel-go v0.31.0/go.mod h1:X0bD6iVNR8pkROSOoHVdgTkzmRcosof7WQqCD6wcMc8= github.com/google/certificate-transparency-go v1.3.3 h1:hq/rSxztSkXN2tx/3jQqF6Xc0O565UQPdHrOWvZwybo= github.com/google/certificate-transparency-go v1.3.3/go.mod h1:iR17ZgSaXRzSa5qvjFl8TnVD5h8ky2JMVio+dzoKMgA= github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ= @@ -690,8 +683,8 @@ github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 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/go-containerregistry v0.21.9 h1:F+D4uZ3iA3DLMJLfhaqMdHJbzeqm/216WGQq2dokuLs= -github.com/google/go-containerregistry v0.21.9/go.mod h1:dP5XNKcL7kMFF/TB3LfvWmVhAcv7iqkHb3oDK8aauTo= +github.com/google/go-containerregistry v0.22.1 h1:RZuuSYhTvlDvtsK+NkutoCZ//C0X2ebLK8X8l3ULs84= +github.com/google/go-containerregistry v0.22.1/go.mod h1:bJR35SK8XgisYmhg/FMQ/5RK0S/XrOAqLBV5/LR2XE0= github.com/google/go-github/v32 v32.1.0/go.mod h1:rIEpZD9CTDQwDK9GDrtMTycQNA4JU3qBsCizh3q2WCI= github.com/google/go-github/v91 v91.0.0 h1:fpulREh37uBvOj4kF0vLuzjwJ1HHmFcAfquNjJfmpYs= github.com/google/go-github/v91 v91.0.0/go.mod h1:rHtn7haKvmkTLhUK/aCQypiIj/suWSB3rnS+a1FdH6M= @@ -724,25 +717,25 @@ github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20260402051712-545e8a4df936 h1:EwtI+Al+DeppwYX2oXJCETMO23COyaKGP6fHVpkpWpg= -github.com/google/pprof v0.0.0-20260402051712-545e8a4df936/go.mod h1:MxpfABSjhmINe3F1It9d+8exIHFvUqtLIRCdOGNXqiI= +github.com/google/pprof v0.0.0-20260802141513-ef3492d7dac3 h1:LMLX+LgTNWpfvCBdFebv6EsYotImrt/Ppc5cXIriCSo= +github.com/google/pprof v0.0.0-20260802141513-ef3492d7dac3/go.mod h1:jl5iWTm0/hd5PjEYEOuwAJ57L/CibdZfrqZ5XA5GrCk= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0= -github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM= +github.com/google/s2a-go v0.1.11 h1:7v1V1TraNGP63WptsAkNqr2w8jgm4vM6A6qx6Lsw9iM= +github.com/google/s2a-go v0.1.11/go.mod h1:pz4tyvwXvJLLbyrkh6FW1eS2zPUXMaTmyNhYtyP2tNw= github.com/google/trillian v1.7.3 h1:hziW+vo4czis48tzx2GK5xRBl/ZxBA9B0/UR5avXOro= github.com/google/trillian v1.7.3/go.mod h1:qh8iy4x/GvnVXUBd5pK4oncuT1Y9vVYfibQVsR/WpKg= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 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= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/enterprise-certificate-proxy v0.3.19 h1:mMOE7DN2+p76/EdIrmAy9B9bH+yC4563vmnJ34QR8i4= -github.com/googleapis/enterprise-certificate-proxy v0.3.19/go.mod h1:rSEsBUemEBZEexP2y6jPp16LUmUbjmSbcPMQizR0o4k= +github.com/googleapis/enterprise-certificate-proxy v0.3.23 h1:J+VGF1wjAM2dU2kKUXZxJdDppRLReWP7KWcclfngQhc= +github.com/googleapis/enterprise-certificate-proxy v0.3.23/go.mod h1:Y8NO/15GNLkrXI3OR5xOFmeU3XLX1sLSdtlXgJ0zmIw= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= -github.com/googleapis/gax-go/v2 v2.23.0 h1:Tchl7qkvE7Ip3y+ztvNufYFvkfqTe7NfLTYGIdJRLuE= -github.com/googleapis/gax-go/v2 v2.23.0/go.mod h1:rBQKOVJCdb8IFEzg+FCwlt1LP/xMDGuqUXhUG+XMXEg= +github.com/googleapis/gax-go/v2 v2.26.2 h1:ydkmNXxj7bEmmeK5AihkKnWxyOyBR9TDebvp5L5izk8= +github.com/googleapis/gax-go/v2 v2.26.2/go.mod h1:sMKqnMesnKH+3wiRJROcttA+cJoZoGbZl1vDQ8XYtGk= github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY= github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= @@ -757,19 +750,19 @@ github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5T github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA= github.com/gosuri/uitable v0.0.4 h1:IG2xLKRvErL3uhY6e1BylFzG+aJiwQviDDTfOKeKTpY= github.com/gosuri/uitable v0.0.4/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16vt0PJo= -github.com/grafana/pyroscope-go v1.4.2 h1:0LW5HrUJXgGr9zF5gITP/HaFXN9/LsMiwlgVJAK75l0= -github.com/grafana/pyroscope-go v1.4.2/go.mod h1:Ej13Jr05rRJrjWvrrFhfh6gGYXtfibuukOs3Tl3Y7QQ= +github.com/grafana/pyroscope-go v1.4.3 h1:XAfYZe5ie8eRTsKAMHQG60ESJjHBV5XUijk8vDvqalw= +github.com/grafana/pyroscope-go v1.4.3/go.mod h1:enNhwzbML7+hMzJHTvKAIqTGqIaOOF1rgF+2au+NOwg= github.com/grafana/pyroscope-go/godeltaprof v0.1.11 h1:el5LYpXissAiCKZ5/6yjlr6mhYVV6Cp5lahTocxraXM= github.com/grafana/pyroscope-go/godeltaprof v0.1.11/go.mod h1:jl1V8M4cWsXciROCPIDDG7CtjSjT/ECbp6eLVuMxYRI= -github.com/graph-gophers/graphql-go v1.10.3-0.20260702060009-60399cce0c05 h1:nz9OX9q1iUJZwrPA2Ge8xNlB3inmq+pafyf6qmBLBew= -github.com/graph-gophers/graphql-go v1.10.3-0.20260702060009-60399cce0c05/go.mod h1:AsADheC4CCFwd8n1/QbkduTlHgYYMsRgtPihYVAlEsk= -github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.3 h1:B+8ClL/kCQkRiU82d9xajRPKYMrB7E0MbtzWVi1K4ns= -github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.3/go.mod h1:NbCUVmiS4foBGBHOYlCT25+YmGpJ32dZPi75pGEUpj4= +github.com/graph-gophers/graphql-go v1.10.3 h1:H6bqOfbuyolAQsbLapHnkIFdJ59vrXuAvDmc4uFvjbY= +github.com/graph-gophers/graphql-go v1.10.3/go.mod h1:AsADheC4CCFwd8n1/QbkduTlHgYYMsRgtPihYVAlEsk= +github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.4 h1:9ZJYjPEJpcleIKcqysXOo14NLQYwu23fzmKRFpIjPjc= +github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.4/go.mod h1:0xydIeg2omQ9DH6zYMP24Kk57793rnLUvP8fwdbFvz8= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20210315223345-82c243799c99 h1:JYghRBlGCZyCF2wNUJ8W0cwaQdtpcssJ4CgC406g+WU= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20210315223345-82c243799c99/go.mod h1:3bDW6wMZJB7tiONtC/1Xpicra6Wp5GgbTbQWCbI5fkc= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 h1:5VipnvEpbqr2gA2VbM+nYVbkIF28c5ZQfqCBQ5g2xfk= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0/go.mod h1:Hyl3n6Twe1hvtd9XUXDec4pTvgMSEixRuQKPTMH2bNs= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.32.0 h1:QMILzF8BA7xftE4zVORkRrlv08m12St3csK4RsyRgRs= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.32.0/go.mod h1:+ZQ6iUL8+ATyxGDQNuRKpNwJFdGDUi0e7E1QL9MvI7U= github.com/hashicorp/consul/api v1.11.0/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -854,8 +847,8 @@ github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsI github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= -github.com/jackc/pgx/v5 v5.10.0 h1:VhSvgU2jSli8o3AqIEOTJr7rZwAEUVo4E4XhR94Zfr0= -github.com/jackc/pgx/v5 v5.10.0/go.mod h1:mal1tBGAFfLHvZzaYh77YS/eC6IX9OWbRV1QIIM0Jn4= +github.com/jackc/pgx/v5 v5.11.0 h1:IzBBtyK9AHqf98cctWFifYSci2hgQR/cd56wB4p+ogg= +github.com/jackc/pgx/v5 v5.11.0/go.mod h1:mal1tBGAFfLHvZzaYh77YS/eC6IX9OWbRV1QIIM0Jn4= github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= @@ -896,8 +889,8 @@ github.com/kisielk/sqlstruct v0.0.0-20201105191214-5f3e10d3ab46 h1:veS9QfglfvqAw github.com/kisielk/sqlstruct v0.0.0-20201105191214-5f3e10d3ab46/go.mod h1:yyMNCyc/Ib3bDTKd379tNMpB/7/H5TjM2Y9QJ5THLbE= github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= -github.com/klauspost/compress v1.19.2 h1:hMRETovs/pu/dVWN7zIT1PGG8t509MwT6bO7XSi26R8= -github.com/klauspost/compress v1.19.2/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ= +github.com/klauspost/compress v1.20.3 h1:zWNoFqq/lSuYQRim3dUXlXeA0IqwuZGicdG5ZTfY5j4= +github.com/klauspost/compress v1.20.3/go.mod h1:LUdAzn7YLVvxLpc7y3V1m40wESHTgc1422pwwBSKYuI= github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= @@ -965,8 +958,8 @@ github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcME github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= -github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-isatty v0.0.24 h1:tGZZoVgT/KiqK1c8ocVLeDS8BSWMRd47J3Lbz7vsReI= +github.com/mattn/go-isatty v0.0.24/go.mod h1:nMCL3Zebbrt45jsMDgnfIwz6ydEQApk5oEI3HqDio6A= github.com/mattn/go-runewidth v0.0.19 h1:v++JhqYnZuu5jSKrk9RbgF5v4CGUjqRfBm05byFGLdw= github.com/mattn/go-runewidth v0.0.19/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs= github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= @@ -1011,8 +1004,8 @@ github.com/moby/sys/capability v0.4.0 h1:4D4mI6KlNtWMCM1Z/K0i7RV1FkX+DBDHKVJpCnd github.com/moby/sys/capability v0.4.0/go.mod h1:4g9IK291rVkms3LKCDOoYlnV8xKwoDTpIrNEE35Wq0I= github.com/moby/sys/mountinfo v0.7.2 h1:1shs6aH5s4o5H2zQLn796ADW1wMrIwHsyJ2v9KouLrg= github.com/moby/sys/mountinfo v0.7.2/go.mod h1:1YOa8w8Ih7uW0wALDUgT1dTTSBrZ+HiBLGws92L2RU4= -github.com/moby/sys/user v0.4.0 h1:jhcMKit7SA80hivmFJcbB1vqmw//wU61Zdui2eQXuMs= -github.com/moby/sys/user v0.4.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs= +github.com/moby/sys/user v0.4.1 h1:RgjRlaDKi/Xmyrz4t8lyzXT6v2ooFeO/7xtchmhVWE0= +github.com/moby/sys/user v0.4.1/go.mod h1:E9QsW5WRe1kUAf7kW8hXKwu1uhsZEAdPLYHYSDudF4Y= github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ= github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -1049,16 +1042,16 @@ github.com/np-guard/netpol-analyzer v1.4.4/go.mod h1:T31vBeTIBl1ksQr9NTW5GJBMHpm github.com/nwaples/rardecode v1.1.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0= github.com/nwaples/rardecode v1.1.3 h1:cWCaZwfM5H7nAD6PyEdcVnczzV8i/JtotnyW/dD9lEc= github.com/nwaples/rardecode v1.1.3/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0= -github.com/oklog/ulid/v2 v2.1.1 h1:suPZ4ARWLOJLegGFiZZ1dFAkqzhMjL3J1TzI+5wHz8s= -github.com/oklog/ulid/v2 v2.1.1/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNsTT1QQ= +github.com/oklog/ulid/v2 v2.1.2 h1:IEclFb9JNvzYA6MW2SCxbLzcHTVsfqm3PrqGQJH5zec= +github.com/oklog/ulid/v2 v2.1.2/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNsTT1QQ= github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6 h1:zrbMGy9YXpIeTnGj4EljqMiZsIcE09mmF8XsD5AYOJc= github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6/go.mod h1:rEKTHC9roVVicUIfZK7DYrdIoM0EOr8mK1Hj5s3JjH0= github.com/olekukonko/errors v1.2.0 h1:10Zcn4GeV59t/EGqJc8fUjtFT/FuUh5bTMzZ1XwmCRo= github.com/olekukonko/errors v1.2.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y= github.com/olekukonko/ll v0.1.6 h1:lGVTHO+Qc4Qm+fce/2h2m5y9LvqaW+DCN7xW9hsU3uA= github.com/olekukonko/ll v0.1.6/go.mod h1:NVUmjBb/aCtUpjKk75BhWrOlARz3dqsM+OtszpY4o88= -github.com/olekukonko/tablewriter v1.1.4 h1:ORUMI3dXbMnRlRggJX3+q7OzQFDdvgbN9nVWj1drm6I= -github.com/olekukonko/tablewriter v1.1.4/go.mod h1:+kedxuyTtgoZLwif3P1Em4hARJs+mVnzKxmsCL/C5RY= +github.com/olekukonko/tablewriter v1.1.5 h1:4LoZSfMySpMQY3PT8RWJsJeuEuMIoo9xGRgvmqjg6IQ= +github.com/olekukonko/tablewriter v1.1.5/go.mod h1:+kedxuyTtgoZLwif3P1Em4hARJs+mVnzKxmsCL/C5RY= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= @@ -1067,15 +1060,15 @@ github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= -github.com/onsi/ginkgo/v2 v2.32.1 h1:6tlvcDm/3sE8lGJbZ4+d4mO3RLy24/tQWOFzVSQNIfw= -github.com/onsi/ginkgo/v2 v2.32.1/go.mod h1:+aXOY+vzZ5mu2iI2HpTZUPmM//oQfsNFX6gU9kNcA44= +github.com/onsi/ginkgo/v2 v2.33.1 h1:62XfWJbEIjPSCSDYrsCPP/SHcmH7O0M8ne8zfqQ2iz4= +github.com/onsi/ginkgo/v2 v2.33.1/go.mod h1:+aXOY+vzZ5mu2iI2HpTZUPmM//oQfsNFX6gU9kNcA44= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= -github.com/onsi/gomega v1.42.1 h1:iN1rCUX+44NZ1Dc97MPoeFYbFR0vh8zxoxMFwKdyZ6I= -github.com/onsi/gomega v1.42.1/go.mod h1:REff/hsDsodHoKlWsP2mAPhu1+5/6hVYNf9rIEBpeSg= +github.com/onsi/gomega v1.44.0 h1:eAiGl3Pw5jz5GQdDff0BcxYpAX1JxW8xD7mFUuwNfZQ= +github.com/onsi/gomega v1.44.0/go.mod h1:e/C2HwaZ1DhvjzXXuFhcR7hY7Sh9pl7MmoWKEjzwcdA= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= @@ -1083,12 +1076,12 @@ github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJw github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= github.com/opencontainers/runtime-spec v1.2.1 h1:S4k4ryNgEpxW1dzyqffOmhI1BHYcjzU8lpJfSlR0xww= github.com/opencontainers/runtime-spec v1.2.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= -github.com/openshift-online/ocm-api-model/clientapi v0.0.464 h1:MrAdeU7E0ElWu4Ztv7hMRqlzY6cdcQeqWiNaO00n2n4= -github.com/openshift-online/ocm-api-model/clientapi v0.0.464/go.mod h1:fZwy5HY2URG9nrExvQeXrDU/08TGqZ16f8oymVEN5lo= -github.com/openshift-online/ocm-api-model/model v0.0.464 h1:aZCIx0+EPZxVSbct4QQ9cSCaI1deoeAhfgwx5CfNl54= -github.com/openshift-online/ocm-api-model/model v0.0.464/go.mod h1:PQIoq6P8Vlb7goOdRMLK8nJY+B7HH0RTqYAa4kyidTE= -github.com/openshift-online/ocm-sdk-go v0.1.509 h1:JcmyaaJQslBqe4vIFugV0rQElGLojJSP/lO11moI/Ho= -github.com/openshift-online/ocm-sdk-go v0.1.509/go.mod h1:h1owsjOKlqLFRgzos5WWa0K0lSr8xRU6P1lF9EG94do= +github.com/openshift-online/ocm-api-model/clientapi v0.0.470 h1:9oXPeJPc6/L3OaulJySDXzkTEJs+YEndI+HIZvQRLO4= +github.com/openshift-online/ocm-api-model/clientapi v0.0.470/go.mod h1:fZwy5HY2URG9nrExvQeXrDU/08TGqZ16f8oymVEN5lo= +github.com/openshift-online/ocm-api-model/model v0.0.470 h1:gnubZARa3aSclaWpVdd4aisOVYN4G2V255SRpyExOf8= +github.com/openshift-online/ocm-api-model/model v0.0.470/go.mod h1:PQIoq6P8Vlb7goOdRMLK8nJY+B7HH0RTqYAa4kyidTE= +github.com/openshift-online/ocm-sdk-go v0.1.517 h1:79KiFTqWHds1FanFByIEqo/485VqXB7LHQiN8XOTdJw= +github.com/openshift-online/ocm-sdk-go v0.1.517/go.mod h1:3rNVzZ86jRbpFtdQUqbdlxmpR+MhKs87szY45bLg3EI= github.com/openshift/api v0.0.0-20260317165824-54a3998d81eb h1:iwBR3mzmyE3EMFx7R3CQ9lOccTS0dNht8TW82aGITg0= github.com/openshift/api v0.0.0-20260317165824-54a3998d81eb/go.mod h1:pyVjK0nZ4sRs4fuQVQ4rubsJdahI1PB94LnQ8sGdvxo= github.com/openshift/client-go v0.0.0-20260317180604-743f664b82d1 h1:Hr/R38eg5ZJXfbiaHumjJIN1buDZwhsm4ys4npVCXH0= @@ -1103,11 +1096,10 @@ github.com/openshift/runtime-utils v0.0.0-20230921210328-7bdb5b9c177b h1:oXzC1N6 github.com/openshift/runtime-utils v0.0.0-20230921210328-7bdb5b9c177b/go.mod h1:l9/qeKZuAmYUMl0yicJlbkPGDsIycGhwxOvOAWyaP0E= github.com/operator-framework/operator-lib v0.17.0 h1:cbz51wZ9+GpWR1ZYP4CSKSSBxDlWxmmnseaHVZZjZt4= github.com/operator-framework/operator-lib v0.17.0/go.mod h1:TGopBxIE8L6E/Cojzo26R3NFp1eNlqhQNmzqhOblaLw= -github.com/owenrumney/go-sarif v1.1.1/go.mod h1:dNDiPlF04ESR/6fHlPyq7gHKmrM0sHUvAGjsoh8ZH0U= -github.com/owenrumney/go-sarif/v2 v2.3.3 h1:ubWDJcF5i3L/EIOER+ZyQ03IfplbSU1BLOE26uKQIIU= -github.com/owenrumney/go-sarif/v2 v2.3.3/go.mod h1:MSqMMx9WqlBSY7pXoOZWgEsVB4FDNfhcaXDA1j6Sr+w= -github.com/package-url/packageurl-go v0.1.6 h1:YO3p6u1XmCUliivUg/qWphaY8vI6hxSnnPv7Bfg3m5M= -github.com/package-url/packageurl-go v0.1.6/go.mod h1:nKAWB8E6uk1MHqiS/lQb9pYBGH2+mdJ2PJc2s50dQY0= +github.com/owenrumney/go-sarif/v3 v3.3.1 h1:bKY8YnWcY8zYTiGVObC5wZLlfEvMkCxK9XMGXBbzEtQ= +github.com/owenrumney/go-sarif/v3 v3.3.1/go.mod h1:72MaugkExDexbSauRuPq6BvUAAqAX0TwoNYMIQyZCMw= +github.com/package-url/packageurl-go v0.1.7 h1:iFWg6tzAjLA6F/qX3M5nZaiMHJgc+p2zxVyr/fY+sZY= +github.com/package-url/packageurl-go v0.1.7/go.mod h1:nKAWB8E6uk1MHqiS/lQb9pYBGH2+mdJ2PJc2s50dQY0= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o= @@ -1118,8 +1110,6 @@ github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0 github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= -github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= -github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= github.com/pierrec/lz4/v4 v4.1.2/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ= github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= @@ -1148,20 +1138,20 @@ github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXP github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= -github.com/prometheus/client_golang v1.24.1 h1:JnJkREXzWxUdCuPFpIWZiPispT9xVV59uiuyR2bPlnU= -github.com/prometheus/client_golang v1.24.1/go.mod h1:F+oSRECHg4sse5ucfYpYDeIv/hu68Zo0uoHKetWnzcE= +github.com/prometheus/client_golang v1.25.0 h1:cDtW1TcFsMi1RJc8khwCKB4VhzwV04aKqbYtNOXuiK0= +github.com/prometheus/client_golang v1.25.0/go.mod h1:j2X/4/kaQHLPnmyEU8zjmkndo1T317VpCIQEml8LTKk= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= -github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= +github.com/prometheus/client_model v0.6.3 h1:O0jaTVAYNxTHYInEPFJt5I3+sN8zqBtVMPTB1qyxiEo= +github.com/prometheus/client_model v0.6.3/go.mod h1:gpN5P9S7Rr6Yr92PiQ+Ixvhf6JZEkF1dnxsYL2aPBEM= github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= -github.com/prometheus/common v0.70.1 h1:1HvjP4D5oL3t8RsPlwxA9onvvStjtIHYE5XuuwOi/PY= -github.com/prometheus/common v0.70.1/go.mod h1:VdFUQDMZK3VLkurFUVhia6uys/0suUp86TJz5qbJRhc= +github.com/prometheus/common v0.72.1 h1:ZAiQed/nk8IIcsdzb2TlJu23NEUDyDLQ9TXTN2WRK6Y= +github.com/prometheus/common v0.72.1/go.mod h1:1IoBY4IRaJnhs2ESjNzjilP1cJ/P8pimGoomq7zRXrA= github.com/prometheus/otlptranslator v1.0.0 h1:s0LJW/iN9dkIH+EnhiD3BlkkP5QVIUVEoIwkU+A6qos= github.com/prometheus/otlptranslator v1.0.0/go.mod h1:vRYWnXvI6aWGpsdY/mOT/cbeVRBlPWtBNDb7kGR3uKM= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= @@ -1169,13 +1159,13 @@ github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= -github.com/prometheus/procfs v0.21.1 h1:GljZCt+zSTS+NZq88cyQ1LjZ+RCHp3uVuabBWA5+OJI= -github.com/prometheus/procfs v0.21.1/go.mod h1:aB55Cww9pdSJVHk0hUf0inxWyyjPogFIjmHKYgMKmtY= -github.com/quay/claircore v1.5.55-0.20260720230557-3f07716d8b96 h1:bpYvJiQTRbsyTPmdXX/a+05Hy5nHtCcjoswOPR/LgjM= -github.com/quay/claircore v1.5.55-0.20260720230557-3f07716d8b96/go.mod h1:hOp0JqY8vOZPdBakFRt3JwG8q4K+gnRkG9RGzt1DoB4= +github.com/prometheus/procfs v0.22.0 h1:6q9+/JL9IKAPbCmBrv9n5O5Ty3NKnciV5X7YGw0oics= +github.com/prometheus/procfs v0.22.0/go.mod h1:CvmFr/GVhIjIvWJZW3tgkODBQMRIf0EyWMQLHCHab58= +github.com/quay/claircore v1.6.1-0.20260916195820-3902930ff815 h1:jCU2qfY0HKDxhgnsn5tuZ3qaAE/C3r2neX+TYhcJwEo= +github.com/quay/claircore v1.6.1-0.20260916195820-3902930ff815/go.mod h1:fdao6wPVC6bYZk3DOuUQDGjxhYVL9codeSnmx/nqlo0= github.com/quay/claircore/toolkit v1.0.0/go.mod h1:3ELtgf92x7o1JCTSKVOAqhcnCTXc4s5qiGaEDx62i20= -github.com/quay/claircore/toolkit v1.6.1 h1:a3X1v28n5bo05T94cBlaoPU8xYCErRGPM3l6AlmYWj4= -github.com/quay/claircore/toolkit v1.6.1/go.mod h1:dTzlp1pgNchc+CN73HJiG9+e0ygU54QPt397eXnGGo4= +github.com/quay/claircore/toolkit v1.7.0 h1:flobJ7hTofiArNSBs1SKq8vDZ9h57dW02RxLyYn+bMw= +github.com/quay/claircore/toolkit v1.7.0/go.mod h1:1AzB56krwmcpGUak0hAOVbSrtzGywDQu5OTooDlKcb0= github.com/quay/claircore/updater/driver v1.0.0 h1:w7dAUjO3GBK6RjNyTZ2Kwz0l/Wuic3ykKJWPB80uA94= github.com/quay/claircore/updater/driver v1.0.0/go.mod h1:My5aY1wBpgxcWaHQZ0VoPmmj/EzuH7fq4ntzJbos4OI= github.com/quay/goval-parser v0.8.8 h1:Uf+f9iF2GIR5GPUY2pGoa9il2+4cdES44ZlM0mWm4cA= @@ -1212,17 +1202,15 @@ github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIH github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig= github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc= github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik= -github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ= -github.com/santhosh-tekuri/jsonschema/v6 v6.0.2/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU= +github.com/santhosh-tekuri/jsonschema/v6 v6.0.3 h1:1EYB5IzjZawrrnELUi78f9fPu57HuXjmddZPjrls/28= +github.com/santhosh-tekuri/jsonschema/v6 v6.0.3/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU= github.com/sassoftware/relic/v8 v8.2.0 h1:9/L4S4I6an/JsPNhmcTpqfiOIsLb/iJaePZD1xR+ulE= github.com/sassoftware/relic/v8 v8.2.0/go.mod h1:pZy7hLT9WCOKPonV8G/fplvtBLOZd6/kWtKqeHR6nKc= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/secure-systems-lab/go-securesystemslib v0.11.0 h1:iuCR9kcMFD4QurdKrGvPLoKZLv9YvwPYVr0473BdtFs= github.com/secure-systems-lab/go-securesystemslib v0.11.0/go.mod h1:+PMOTjUGwHj2vcZ+TFKlb1tXRbrdWE1LYDT5i9JC80Q= -github.com/segmentio/analytics-go/v3 v3.3.0 h1:8VOMaVGBW03pdBrj1CMFfY9o/rnjJC+1wyQHlVxjw5o= -github.com/segmentio/analytics-go/v3 v3.3.0/go.mod h1:p8owAF8X+5o27jmvUognuXxdtqvSGtD0ZrfY2kcS9bE= -github.com/segmentio/backo-go v1.0.1 h1:68RQccglxZeyURy93ASB/2kc9QudzgIDexJ927N++y4= -github.com/segmentio/backo-go v1.0.1/go.mod h1:9/Rh6yILuLysoQnZ2oNooD2g7aBnvM7r/fNVxRNWfBc= +github.com/segmentio/analytics-go/v3 v3.4.0 h1:8ACTF5ggK3W70b+kHId5SyxyWGYZ1sdgd/e8tb8jMRM= +github.com/segmentio/analytics-go/v3 v3.4.0/go.mod h1:l0qTADX69i/7AuXvN3tg0QMfcW4Oe6YN5VgsgqGaAPI= github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sergi/go-diff v1.4.0 h1:n/SP9D5ad1fORl+llWyN+D6qoUETXNZARKjyY2/KVCw= github.com/sergi/go-diff v1.4.0/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= @@ -1240,8 +1228,8 @@ github.com/sigstore/rekor-tiles/v2 v2.3.0 h1:HhMgH61UP0t899V8Fjt7pz1YdgOBptbaQdn github.com/sigstore/rekor-tiles/v2 v2.3.0/go.mod h1:DEFiKSyQ4nF75QRVNdOPaIH3cmvMkO2B6xDZjNYngPc= github.com/sigstore/sigstore v1.10.9 h1:7Dcpt+ibnltHQZ8XhaU0dFmhHaf/T491eJfA9WDex4Y= github.com/sigstore/sigstore v1.10.9/go.mod h1:LYW9+qH7bK8wZmLm6lPxIC5lkHtkJDCgkqjChzTAIBs= -github.com/sigstore/sigstore-go v1.2.2 h1:xAJ8hxaoecC0HKBYVbrwUjkeAI+GJYu6vLqbxDlD2Q0= -github.com/sigstore/sigstore-go v1.2.2/go.mod h1:MIFwBxAHJD+/lKgZzt9n/4Zhq/3T2+EuGX8iGrIsZgU= +github.com/sigstore/sigstore-go v1.3.0 h1:hnIMHREyCNTYFtOE1o7ae3Axa9B5W5EjUSBJICP2NBE= +github.com/sigstore/sigstore-go v1.3.0/go.mod h1:AyRQXfpH89py1twjE3kEZxlRersng90GSYqQV9zGJE8= github.com/sigstore/sigstore/pkg/signature/kms/aws v1.10.9 h1:2NWAU/utJRwzy1OrQurlY3wlDSynyH1rNJS5GgFchrg= github.com/sigstore/sigstore/pkg/signature/kms/aws v1.10.9/go.mod h1:2shgYiPHTzeb5NNEu6okco+LOojMS5n9p/5Wdp0jhGI= github.com/sigstore/sigstore/pkg/signature/kms/azure v1.10.9 h1:zcg/EG6JW/8RSx9T2g5j6zqxplaE4dymmhiFflDE6ks= @@ -1250,15 +1238,15 @@ github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.10.9 h1:DG8R4orWDs3l9trp70 github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.10.9/go.mod h1:d6oIwQ0YiYHMcFO4xqFcAx5njXwIf0dm5KfdytOar8A= github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.10.9 h1:V+spyeSHypvLHSOvPMT+V72dxDlS0LDkDd6lwCsUOXM= github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.10.9/go.mod h1:o7u5bQNLqpDQFaST29dpo6P6ihMV+wicwqfMmMW6H3c= -github.com/sigstore/timestamp-authority/v2 v2.1.2 h1:7DDhnknLL4w8VwomyvW2W8qblOS9LDR8oihna+jc7Ls= -github.com/sigstore/timestamp-authority/v2 v2.1.2/go.mod h1:o6rAVZceFyejClIj/uStRNIemP16bVMZtbMmhk6pr0U= +github.com/sigstore/timestamp-authority/v2 v2.1.3 h1:Fc+LjCTfik1lh3YLkaosENfkXa3R2Y1nswiUKutBdFA= +github.com/sigstore/timestamp-authority/v2 v2.1.3/go.mod h1:myoFOKJB/u5vNTFwvBBJVkG3NnOBeIJevbfjNeasLjo= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w= -github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g= +github.com/sirupsen/logrus v1.10.2 h1:G2SED73/qrAu6YwbdxOD6peLkCBI3z7L+ykJFTXJBBo= +github.com/sirupsen/logrus v1.10.2/go.mod h1:SLEg8TqYulVKKfIGHldVp2K2aYz2DKSVBq4g/H5bR7Q= github.com/skeema/knownhosts v1.3.1 h1:X2osQ+RAjK76shCbvhHHHVl3ZlgDm8apHEHFqRjnBY8= github.com/skeema/knownhosts v1.3.1/go.mod h1:r7KTdC8l4uxWRyK2TpQZ/1o5HaSzh06ePQNxPwTcfiY= github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA= @@ -1287,8 +1275,8 @@ github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3A github.com/spf13/viper v1.10.0/go.mod h1:SoyBPwAtKDzypXNDFKN5kzH7ppppbGZtls1UpIy5AsM= github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU= github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY= -github.com/spiffe/go-spiffe/v2 v2.7.0 h1:uXe1MflJoHw58wAUvxVlcM7WpKtijWG7I1UidcGh6g4= -github.com/spiffe/go-spiffe/v2 v2.7.0/go.mod h1:47Q0Q9/AqGha8QLHp+kxpH4Wca7X7EnOtlIJy3mxZ3U= +github.com/spiffe/go-spiffe/v2 v2.8.1 h1:eXZMLsu+3MLEPJyGJkolqtVrteZfQdUpOWj6LTiDl/E= +github.com/spiffe/go-spiffe/v2 v2.8.1/go.mod h1:47Q0Q9/AqGha8QLHp+kxpH4Wca7X7EnOtlIJy3mxZ3U= github.com/stackrox/docker-registry-client v0.2.0 h1:91TLimNkFgdwO9QF8rUC57DoLGiTAgDKm2KhLI2xkLU= github.com/stackrox/docker-registry-client v0.2.0/go.mod h1:4TU+pA11iczIvhtL0own2OJcJXc1o26tBHDivaXhlZU= github.com/stackrox/dotnet-scraper v0.0.0-20201023051640-72ef543323dd h1:vEjp7Q66zd4W72//Uk3uyVN50Mh/nFLbN9pb7CVK7mE= @@ -1346,8 +1334,8 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= -github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/stretchr/testify v1.12.1 h1:EuwCh5fleGS7H32xRwO3wRGT7DxrDhLAT6FF8MpWDWE= +github.com/stretchr/testify v1.12.1/go.mod h1:MDEgiDPPsNp5cuIrHPPCyornHKgEVbtFUmoNlxoYthg= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= @@ -1357,8 +1345,8 @@ github.com/theupdateframework/go-tuf v0.7.0 h1:CqbQFrWo1ae3/I0UCblSbczevCCbS31Qv github.com/theupdateframework/go-tuf v0.7.0/go.mod h1:uEB7WSY+7ZIugK6R1hiBMBjQftaFzn7ZCDJcp1tCUug= github.com/theupdateframework/go-tuf/v2 v2.4.2 h1:w7976/W8uTwlsegP5nRymlpjPgrwSh+AXUf85is6nJk= github.com/theupdateframework/go-tuf/v2 v2.4.2/go.mod h1:JqBrIUnNLAaNq/8GmBcEMFWfAFBbqp/MkJEJseXKbks= -github.com/tidwall/gjson v1.19.0 h1:xwxm7n691Uf3u5OFjzngavjGTh55KX5q/9w9xHW88JU= -github.com/tidwall/gjson v1.19.0/go.mod h1:V37/opeE/JbLUOfH0QTXiNez2l0RUjYUhpT4szFQAfc= +github.com/tidwall/gjson v1.20.0 h1:+agJ3rEzKcCXKDKo0ml26UROcpcAlnZyjq+TjbY5Fto= +github.com/tidwall/gjson v1.20.0/go.mod h1:V37/opeE/JbLUOfH0QTXiNez2l0RUjYUhpT4szFQAfc= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= @@ -1392,8 +1380,6 @@ github.com/vbauerster/mpb/v4 v4.12.2 h1:TsBs1nWRYF0m8cUH13pxNhOUqY6yKcOr2PeSYxp2 github.com/vbauerster/mpb/v4 v4.12.2/go.mod h1:LVRGvMch8T4HQO3eg2pFPsACH9kO/O6fT/7vhGje3QE= github.com/vladimirvivien/gexe v0.5.0 h1:AWBVaYnrTsGYBktXvcO0DfWPeSiZxn6mnQ5nvL+A1/A= github.com/vladimirvivien/gexe v0.5.0/go.mod h1:3gjgTqE2c0VyHnU5UOIwk7gyNzZDGulPb/DJPgcw64E= -github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4= -github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI= github.com/weppos/publicsuffix-go v0.13.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k= github.com/weppos/publicsuffix-go v0.40.3-0.20250127173806-e489a31678ca/go.mod h1:43Dfyxu2dpmLg56at26Q4k9gwf3yWSUiwk8kGnwzULk= github.com/weppos/publicsuffix-go v0.50.2 h1:KsJFc8IEKTJovM46SRCnGNsM+rFShxcs6VEHjOJcXzE= @@ -1402,6 +1388,13 @@ github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo= github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos= github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ= @@ -1428,7 +1421,6 @@ github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1 github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/zalando/go-keyring v0.2.6 h1:r7Yc3+H+Ux0+M72zacZoItR3UDxeWfKTcabvkI8ua9s= github.com/zalando/go-keyring v0.2.6/go.mod h1:2TCrxYrbUNYfNS/Kgy/LSrkSQzZ5UPVH85RwfczwvcI= -github.com/zclconf/go-cty v1.10.0/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk= github.com/zmap/rc2 v0.0.0-20131011165748-24b9757f5521/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE= github.com/zmap/rc2 v0.0.0-20190804163417-abaa70531248/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE= github.com/zmap/zcertificate v0.0.0-20180516150559-0e3d58b1bac4/go.mod h1:5iU54tB79AMBcySS0R2XIyZBAVmeHranShAFELYx7is= @@ -1440,8 +1432,8 @@ github.com/zmap/zcrypto v0.0.0-20250129210703-03c45d0bae98/go.mod h1:YTUyN/U1oJ7 github.com/zmap/zlint/v3 v3.0.0/go.mod h1:paGwFySdHIBEMJ61YjoqT4h7Ge+fdYG4sUQhnTb1lJ8= github.com/zmap/zlint/v3 v3.6.6 h1:tH7RJM9bDmh7IonlLEkFIkIn8XDYDYjehhUPgpLVqYA= github.com/zmap/zlint/v3 v3.6.6/go.mod h1:6yXG+CBOQBRpMCOnpIVPUUL296m5HYksZC9bj5LZkwE= -go.etcd.io/bbolt v1.4.3 h1:dEadXpI6G79deX5prL3QRNP6JB8UxVkqo4UPnHaNXJo= -go.etcd.io/bbolt v1.4.3/go.mod h1:tKQlpPaYCVFctUIgFKFnAlvbmB3tpy1vkTnDWohtc0E= +go.etcd.io/bbolt v1.5.0 h1:S7GAl7Fxv12yohbwFfIbQCGDWbQbtDGPET4P/bD4lxU= +go.etcd.io/bbolt v1.5.0/go.mod h1:mkltfYE5aUHQxUct9N9V+Kp7aSjFqjgrhcXIS70Lrdk= go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/v2 v2.305.1/go.mod h1:pMEacxZW7o8pg4CrFE7pquyCJJzZvkvdD2RibOCCCGs= @@ -1456,60 +1448,60 @@ go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/contrib/bridges/prometheus v0.67.0 h1:dkBzNEAIKADEaFnuESzcXvpd09vxvDZsOjx11gjUqLk= go.opentelemetry.io/contrib/bridges/prometheus v0.67.0/go.mod h1:Z5RIwRkZgauOIfnG5IpidvLpERjhTninpP1dTG2jTl4= -go.opentelemetry.io/contrib/detectors/gcp v1.44.0 h1:NmLfL734pJhM0JKaYd2Y28+nY9dPRWYAAbxhRCrKXPw= -go.opentelemetry.io/contrib/detectors/gcp v1.44.0/go.mod h1:tNAsgd8avTGke1+MndXlU5Cru4PQ9Ai/cCNWQv/ZJ/s= +go.opentelemetry.io/contrib/detectors/gcp v1.45.0 h1:9jR0ZPRok9ryaOQ2Wx8rg5F7Aon59mxrqbVI60/vlBk= +go.opentelemetry.io/contrib/detectors/gcp v1.45.0/go.mod h1:VSme3o2fvSg5bVg0dRzyHaj4Z5EVhG+g2Fde6LKzmQA= go.opentelemetry.io/contrib/exporters/autoexport v0.67.0 h1:4fnRcNpc6YFtG3zsFw9achKn3XgmxPxuMuqIL5rE8e8= go.opentelemetry.io/contrib/exporters/autoexport v0.67.0/go.mod h1:qTvIHMFKoxW7HXg02gm6/Wofhq5p3Ib/A/NNt1EoBSQ= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.68.0 h1:0Qx7VGBacMm9ZENQ7TnNObTYI4ShC+lHI16seduaxZo= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.68.0/go.mod h1:Sje3i3MjSPKTSPvVWCaL8ugBzJwik3u4smCjUeuupqg= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.68.0 h1:CqXxU8VOmDefoh0+ztfGaymYbhdB/tT3zs79QaZTNGY= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.68.0/go.mod h1:BuhAPThV8PBHBvg8ZzZ/Ok3idOdhWIodywz2xEcRbJo= -go.opentelemetry.io/otel v1.44.0 h1:JjwHmHpA4iZ3wBxluu2fbbE7j4kqlE8jXyAyPXH7HqU= -go.opentelemetry.io/otel v1.44.0/go.mod h1:BMgjTHL9WPRlRjL2oZCBTL4whCGtXch2H4BhOPIAyYc= -go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.19.0 h1:Dn8rkudDzY6KV9dr/D/bTUuWgqDf9xe0rr4G2elrn0Y= -go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.19.0/go.mod h1:gMk9F0xDgyN9M/3Ed5Y1wKcx/9mlU91NXY2SNq7RQuU= -go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.19.0 h1:HIBTQ3VO5aupLKjC90JgMqpezVXwFuq6Ryjn0/izoag= -go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.19.0/go.mod h1:ji9vId85hMxqfvICA0Jt8JqEdrXaAkcpkI9HPXya0ro= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.72.0 h1:Tq+E65HaNbZTeqcLw6QUhsV+/EIWdkfUH2CQzcrlE5M= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.72.0/go.mod h1:A+EVhDakAj1waJBPhmTszZaSr08ww8MRRKy1nB1rqck= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.72.0 h1:LxwW/9ctSCv+QkE/cLR7M91ZIkXNMqJtEMi1vCw9U8s= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.72.0/go.mod h1:tOsftB4SslBwwErVEPaenU2RpThXWPIU8DoJHEC4dyw= +go.opentelemetry.io/otel v1.47.0 h1:j7ALJ/zgkS7Z6aeJW09p8VC9804bC+PpeTfCD4XPnOM= +go.opentelemetry.io/otel v1.47.0/go.mod h1:8wS9O2qfXrYrzp6hIF/HOYJJf/wIhFPhR2xLuP+iXQU= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.21.0 h1:WseeVYf5dJZTsyPiyW5L14k5qsSibqXAMTSiFEDiWr0= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.21.0/go.mod h1:SiLZnQS6Qk2eCpvr2CH/XMAOa64TWGXxEZJZCpD2Lmc= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.21.0 h1:fvNHGyo3CdRv/DQveXqhqBxnKTDyRaC5sMSQxilX/A0= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.21.0/go.mod h1:zyGrjRKL2B/6+Jc/m4/otPoZqV2MY9ZjC/aBraRO7zc= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.43.0 h1:8UQVDcZxOJLtX6gxtDt3vY2WTgvZqMQRzjsqiIHQdkc= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.43.0/go.mod h1:2lmweYCiHYpEjQ/lSJBYhj9jP1zvCvQW4BqL9dnT7FQ= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.43.0 h1:w1K+pCJoPpQifuVpsKamUdn9U0zM3xUziVOqsGksUrY= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.43.0/go.mod h1:HBy4BjzgVE8139ieRI75oXm3EcDN+6GhD88JT1Kjvxg= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0 h1:88Y4s2C8oTui1LGM6bTWkw0ICGcOLCAI5l6zsD1j20k= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0/go.mod h1:Vl1/iaggsuRlrHf/hfPJPvVag77kKyvrLeD10kpMl+A= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.43.0 h1:RAE+JPfvEmvy+0LzyUA25/SGawPwIUbZ6u0Wug54sLc= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.43.0/go.mod h1:AGmbycVGEsRx9mXMZ75CsOyhSP6MFIcj/6dnG+vhVjk= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0 h1:3iZJKlCZufyRzPzlQhUIWVmfltrXuGyfjREgGP3UUjc= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0/go.mod h1:/G+nUPfhq2e+qiXMGxMwumDrP5jtzU+mWN7/sjT2rak= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.45.0 h1:QRefszxJmfPdjXUUm3j6iDzY03mTPXMjqErFqQ67vUg= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.45.0/go.mod h1:Tiz03lTBVBrm7eWZBOidzEaYaJa8tjwGUGv6d8mlTyk= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.45.0 h1:fG5MCxGz8+2VtrN/WgqSpJFctVz24gpxj8CxkKmc8Ww= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.45.0/go.mod h1:BmAYTn+3ysbRe+IU2msxmf5Rx3g6DHvex+tWI3LdhYI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.45.0 h1:QBajQ2SrwQijzHyZbQlPsuIzpl/ll8DY6wPWsajeGcI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.45.0/go.mod h1:08ZQLjrPLQ6R4kAXvuOvODEer5Yh4CoFvll5qB2BCI8= go.opentelemetry.io/otel/exporters/prometheus v0.66.0 h1:vkrK8PAznv2NKt2r+kdu252ccGzkEqLc2aSXbQIALYQ= go.opentelemetry.io/otel/exporters/prometheus v0.66.0/go.mod h1:V/UB6D3vMF/UBOL5igAsAYnk1nG/bzYYTzvsB16cy7o= -go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.19.0 h1:GJkybS+crDMdExT/BUNCEgfrmfboztcS6PhvSo88HKM= -go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.19.0/go.mod h1:NuAyxRYIG2lKX3YQkB+83StTxM7s52PUUkRRiC0wnYI= -go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.44.0 h1:hqxVTu/GtBF+vJ8d1fzW7fRxZFvgoDjWcxwwCaFDYpU= -go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.44.0/go.mod h1:z5fVEF4X5v0ESvlJqBrrFlBVoj5EQuefZpzsu7R+x5Q= -go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.43.0 h1:mS47AX77OtFfKG4vtp+84kuGSFZHTyxtXIN269vChY0= -go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.43.0/go.mod h1:PJnsC41lAGncJlPUniSwM81gc80GkgWJWr3cu2nKEtU= -go.opentelemetry.io/otel/log v0.19.0 h1:KUZs/GOsw79TBBMfDWsXS+KZ4g2Ckzksd1ymzsIEbo4= -go.opentelemetry.io/otel/log v0.19.0/go.mod h1:5DQYeGmxVIr4n0/BcJvF4upsraHjg6vudJJpnkL6Ipk= -go.opentelemetry.io/otel/metric v1.44.0 h1:1w0gILTcHdr3YI+ixLyjemwrVnsMURbTZFrSYCdDdmc= -go.opentelemetry.io/otel/metric v1.44.0/go.mod h1:8O7hanEPBNgEMmybD3s2VBKcgWOCsA6tzHBPODAiquo= -go.opentelemetry.io/otel/metric/x v0.66.0 h1:YkCrx1zLOChi9ZcZ6euupOcsgzbVlec7D/xoEU1+cTA= -go.opentelemetry.io/otel/metric/x v0.66.0/go.mod h1:d1+BDj9t96do0/1LoU1ayfCv79ZgNE41qbhBvnMOBZk= -go.opentelemetry.io/otel/sdk v1.44.0 h1:nHYwb9lK+fJPU/dnT6s7W7Z8itMWyqrnVfbheVYrZ58= -go.opentelemetry.io/otel/sdk v1.44.0/go.mod h1:Osuydd3Se74nqjAKxid74N5eC+jfEqfTegHRnq58oK0= -go.opentelemetry.io/otel/sdk/log v0.19.0 h1:scYVLqT22D2gqXItnWiocLUKGH9yvkkeql5dBDiXyko= -go.opentelemetry.io/otel/sdk/log v0.19.0/go.mod h1:vFBowwXGLlW9AvpuF7bMgnNI95LiW10szrOdvzBHlAg= -go.opentelemetry.io/otel/sdk/metric v1.44.0 h1:3LlKgI+VjbVsjNRFZJZAJ30WjXC5VkNRks6si09iEfI= -go.opentelemetry.io/otel/sdk/metric v1.44.0/go.mod h1:5B5pMARnXxKhltooO4xUuCBorl65a4EpnTalObqOigA= -go.opentelemetry.io/otel/trace v1.44.0 h1:jxF5CsGYCe74MCRx2X4g7WsY/VBKRqqpNvXlX/6gtIk= -go.opentelemetry.io/otel/trace v1.44.0/go.mod h1:oLl1jrMQAVo6v3GAggN+1VH9VIz9iUSvW53sW1Q8PIE= +go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.21.0 h1:2lpf4hnrasYIsUyEXwnTZq5lsxrMm4T2Bwb06IctAZQ= +go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.21.0/go.mod h1:YWOW6h7jwApz9Pl76ie/izUsSPj0s2MdIlpqbPqaf3U= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.45.0 h1:dm9iyzn6tioYZtwqaiBSU0TSI8Yu/8dTIbfG0+B49DY= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.45.0/go.mod h1:xAvxYjYK28qvt+yu4BYZ/zMmAjwMXINXD6JiMyeB8iI= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.47.0 h1:N3YQCxjxQ/bMjyc3heladfRm9t9RTksGQH8z4w6yU/0= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.47.0/go.mod h1:Mp8HOFqcaUyypCuGv9IhDdTHnJ56lSudSHMd+pVSCEA= +go.opentelemetry.io/otel/log v1.47.0 h1:cOTS1CcLbSQeZKanGJ+0JpF/+t4PELi3O3bbl2lqCcI= +go.opentelemetry.io/otel/log v1.47.0/go.mod h1:9byitSQ5pLC6PpqwGXjqdMKya6ZTswHRZh2vvXT33nw= +go.opentelemetry.io/otel/metric v1.47.0 h1:4PptaldXx3Eat1XjMZ68pPJEs5wrhlemctZE9a3UdWY= +go.opentelemetry.io/otel/metric v1.47.0/go.mod h1:ADGSXxRrXM6bjbvLo535EstVFlPpPYZm4LBKixjDHwU= +go.opentelemetry.io/otel/metric/x v0.69.0 h1:DjRLr15H83v+hCW7JA9NoJvOkYTtmq5YoDRbe9deYpM= +go.opentelemetry.io/otel/metric/x v0.69.0/go.mod h1:uVvsMPMFFyj/HUQfrUnH3JjnOQ1dwFDorgFLRBasM0k= +go.opentelemetry.io/otel/sdk v1.47.0 h1:zWXEr4j2lFefG87TU6Yg8a7ngfohIKFZHKp0Hf5hC6I= +go.opentelemetry.io/otel/sdk v1.47.0/go.mod h1:VUc24kiOeoGsxG8G9ULx3fWKvB7jMhnGE8Oi607lgR0= +go.opentelemetry.io/otel/sdk/log v0.21.0 h1:QsE7XSR0ktQdKmRKGnR+f1ObGF32WG+7MER/P9KgmYc= +go.opentelemetry.io/otel/sdk/log v0.21.0/go.mod h1:m9mApjCoD2/1QuKCAptjv+BrG9WKOvQLVdNx+iBldTo= +go.opentelemetry.io/otel/sdk/metric v1.47.0 h1:lfISg2j93VT6yqdk9OfUaZmw/GfcZqCCV3jdXtsPnKw= +go.opentelemetry.io/otel/sdk/metric v1.47.0/go.mod h1:ypLp+mW1Nt2x+Szt3b5/i1syodyts49lMOwxpDI3VGw= +go.opentelemetry.io/otel/trace v1.47.0 h1:JOjX/Oci8K94QHddo+bbfya/Ai/nf6/dt9ZfrFNWSrM= +go.opentelemetry.io/otel/trace v1.47.0/go.mod h1:jNaSLa2PZEYFG6fRjJABAu+bw4FS08uDmPg28lTghu0= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.opentelemetry.io/proto/otlp v1.10.0 h1:IQRWgT5srOCYfiWnpqUYz9CVmbO8bFmKcwYxpuCSL2g= -go.opentelemetry.io/proto/otlp v1.10.0/go.mod h1:/CV4QoCR/S9yaPj8utp3lvQPoqMtxXdzn7ozvvozVqk= +go.opentelemetry.io/proto/otlp v1.11.0 h1:5rrYs0Ykyj50sdU/JU0x8etU+LubXWb+gED6TbEdMIk= +go.opentelemetry.io/proto/otlp v1.11.0/go.mod h1:SmVizdCOAm3XBtG1g1NnOdhW6jtddT72hLMhv8VwA8E= go.step.sm/crypto v0.87.0 h1:+u0pDz1OV9M/SswA6KtcQ3GSrYMMelbL//0W/ceJVYI= go.step.sm/crypto v0.87.0/go.mod h1:gBr1mpMiKs5804/Yt03uAoOBiw3DFxARZnGUKEUO82M= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= -go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +go.uber.org/atomic v1.12.0 h1:BvcXdFKuviU4fTL/f+SxdQ5qJX/Jix8pAkgdUcb3XOE= +go.uber.org/atomic v1.12.0/go.mod h1:I6c4cg+6HCxRjfjSsYtApoFILnpc0CGUdGkXVqbYVNk= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= @@ -1550,8 +1542,8 @@ golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqj golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY= golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc= -golang.org/x/crypto v0.56.0 h1:GUh5Ii4J5jtcseSMiRqr1jXCNHoxjeV9Fmekc2oLy6Y= -golang.org/x/crypto v0.56.0/go.mod h1:OMW5y6CY9l38uPLmxU6l6pwcXp1obtLo3e6gT7gQR2I= +golang.org/x/crypto v0.58.0 h1:COkYLr4k7nDI4r6QtMML2AfzeIswWHAJthLS6K/M/54= +golang.org/x/crypto v0.58.0/go.mod h1:Xh+kl5A+M0gMiWDytH2Hhr5Z7WbNCpv/eB/EFgfSk+w= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1562,8 +1554,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f h1:W3F4c+6OLc6H2lb//N1q4WpJkhzJCK5J6kUi1NTVXfM= -golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f/go.mod h1:J1xhfL/vlindoeF/aINzNzt2Bket5bjo9sdOYzOsU80= +golang.org/x/exp v0.0.0-20261014143641-f0251eb4aa3e h1:HgI6W1OolKK6tcV74is+rl9SMT0njsHlp0TbQiGXI/A= +golang.org/x/exp v0.0.0-20261014143641-f0251eb4aa3e/go.mod h1:DBoxwWhjaW8DJJw/YeM4zpeOKMC1FMXSblsYy+1mFSw= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -1602,8 +1594,8 @@ golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ= golang.org/x/mod v0.27.0/go.mod h1:rWI627Fq0DEoudcK+MBkNkCe0EetEaDSwJJkCcjpazc= -golang.org/x/mod v0.41.0 h1:qJmnOUb4YB+FsEuM3HcWucdZASCPGhsX6uljO6pog0c= -golang.org/x/mod v0.41.0/go.mod h1:Ek9pY8RKWXwsWvd3rQiHYtMqkjSUV+s1Rj7j4H5Ur6o= +golang.org/x/mod v0.42.0 h1:ICeL3t2L30ljSPHHxDnR4fqVcBt/zR2zJAb9juavmQg= +golang.org/x/mod v0.42.0/go.mod h1:u5fzIrRInkL8MaO1cbRkUHT64v303YIT5KEqpNr7jRs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1670,8 +1662,8 @@ golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg= -golang.org/x/net v0.58.0 h1:ynWG7rqYi4ccpTEuPZ2QGWHktVEM9DMCj9yzDE0Q7To= -golang.org/x/net v0.58.0/go.mod h1:YwCddHnFlT7eLQqVprV19OnhLGtc5xOKgE0RyqgfWAU= +golang.org/x/net v0.61.0 h1:RR+6j/BTBCrggOLugxa+66R8FvoN6MHlzDlZIbN9YFw= +golang.org/x/net v0.61.0/go.mod h1:WgDCOTH8iwtB66T4/GfI94AHo/hhdb7Hah9NDseQfiI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1693,8 +1685,8 @@ golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= -golang.org/x/sync v0.23.0 h1:KameEIfc1IkluZyXWLn39Wd4tURc6GbCiISGiZm2bQk= -golang.org/x/sync v0.23.0/go.mod h1:sUUOizhqBxiL6pEWpqNLUiaJn1ShEbZ6BBqskPbjZm0= +golang.org/x/sync v0.24.0 h1:iqiDrGoDgyuvAKrhLQthUEzU/R378N78gXbBjxed7oA= +golang.org/x/sync v0.24.0/go.mod h1:sUUOizhqBxiL6pEWpqNLUiaJn1ShEbZ6BBqskPbjZm0= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1782,7 +1774,6 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= @@ -1793,8 +1784,8 @@ golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/sys v0.48.0 h1:bbX/i/6MgT9BVLM9RT1thmxL04yeTAhbEz4SyadbXoo= -golang.org/x/sys v0.48.0/go.mod h1:hNLxWAXmnKAxqDtdwIYC4bM9oQPEecfsnNMuSxOs3og= +golang.org/x/sys v0.49.0 h1:XbzkgYJHdqh/8m2Uu0W/dQv8nktxx4BFHp1M0gROTXA= +golang.org/x/sys v0.49.0/go.mod h1:hNLxWAXmnKAxqDtdwIYC4bM9oQPEecfsnNMuSxOs3og= golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= golang.org/x/telemetry v0.0.0-20240521205824-bda55230c457/go.mod h1:pRgIJT+bRLFKnoM1ldnzKoxTIn14Yxz928LQRYYgIN0= golang.org/x/telemetry v0.0.0-20250710130107-8d8967aff50b/go.mod h1:4ZwOYna0/zsOKwuR5X/m0QFOJpSZvAxFfkQT+Erd9D4= @@ -1813,8 +1804,8 @@ golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek= golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0= golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw= -golang.org/x/term v0.45.0 h1:NwWyBmoJCbfTHpxrWoZ9C6/VxOf7ic219I8xZZFdrf0= -golang.org/x/term v0.45.0/go.mod h1:9aqxs0blBcrm/n0L9QW0aRVD+ktan8ssZromtqJC43w= +golang.org/x/term v0.47.0 h1:cpyOwQkr2Nzxe2p6KnrTG7Ei2wtzjsuSjhpXXepZ/BM= +golang.org/x/term v0.47.0/go.mod h1:efAfAuG6RKABvg1ArGebRkvX6LXul14SM67o2e4mUCY= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1834,8 +1825,8 @@ golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= -golang.org/x/text v0.41.0 h1:vz/seA0lnX87Othu2f/0L24RcgrXD9/YFTSuGjj3rH8= -golang.org/x/text v0.41.0/go.mod h1:jvf1O8ajNzZqhSrQBPbutR/EB83Cc0CFrezNQIwbb5M= +golang.org/x/text v0.43.0 h1:1QivrlhwAsnMOcqgOdl9my7s9OyZl8O5/UGUTJVXoWc= +golang.org/x/text v0.43.0/go.mod h1:hbSIYA/amXcRXTFSZqh8tWHEoqRvvbKPJ2uz/KU+a+s= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1912,8 +1903,8 @@ golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg golang.org/x/tools v0.34.1-0.20250613162507-3f93fece84c7/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg= golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw= golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s= -golang.org/x/tools v0.49.0 h1:3NI7VXzL9+1WZD52Dx2ttoPwD5DWrFGpl9mFZDlmisI= -golang.org/x/tools v0.49.0/go.mod h1:SJNXV9DBKT0UbdttsQjbfJlAE/q+y36++zo3uL3N0Oo= +golang.org/x/tools v0.52.0 h1:ryxg4U63oaUYk7uOLTF37n43f4qgtGvqV4Ioit1BaEs= +golang.org/x/tools v0.52.0/go.mod h1:ItcP5UNaVGG+Yc4eIYmaFLNJ4soEopkx5Y2d4lcEurs= golang.org/x/tools/go/expect v0.1.0-deprecated/go.mod h1:eihoPOH+FgIqa3FpoTwguz/bVUSGBlGQU67vpBeOrBY= golang.org/x/tools/go/expect v0.1.1-deprecated h1:jpBZDwmgPhXsKZC6WhL20P4b/wmnpsEAGHaNy0n/rJM= golang.org/x/tools/go/expect v0.1.1-deprecated/go.mod h1:eihoPOH+FgIqa3FpoTwguz/bVUSGBlGQU67vpBeOrBY= @@ -1962,8 +1953,8 @@ google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdr google.golang.org/api v0.59.0/go.mod h1:sT2boj7M9YJxZzgeZqXogmhfmRWDtPzT31xkieUbuZU= google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= google.golang.org/api v0.62.0/go.mod h1:dKmwPCydfsad4qCH08MSdgWjfHOyfpd4VtDGgRFdavw= -google.golang.org/api v0.292.0 h1:Ewiwo/GTtiaPZSNAZQUcWLh8AYDEoPmIXyJfeoTSMHU= -google.golang.org/api v0.292.0/go.mod h1:07kjmMnFGm2RQuCza2EZM/5N68G/fVvFb1xKjWqoFA0= +google.golang.org/api v0.304.0 h1:2R1dYSiIVQRGcKN901u9yPFEdJu5h90oGY5X4TcgbmA= +google.golang.org/api v0.304.0/go.mod h1:dcjRWAy1QdjGb3Z67Qu0gdBWH2gL8Qoy/RI2ZVuvdeE= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -2035,12 +2026,12 @@ google.golang.org/genproto v0.0.0-20211129164237-f09f9a12af12/go.mod h1:5CzLGKJ6 google.golang.org/genproto v0.0.0-20211203200212-54befc351ae9/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20260622175928-b703f567277d h1:CP5omUq8AJTiWMrPKM1WRLJ7zZeXd9OPcQD3TbBNAyY= -google.golang.org/genproto v0.0.0-20260622175928-b703f567277d/go.mod h1:DrwuGJgFSEVNpv3S5Q5VxhRTvdnjauw9GtvwVOEARfA= -google.golang.org/genproto/googleapis/api v0.0.0-20260727163830-6c54dddc4772 h1:4namukbyF7JY83aWHQwi9J5ugNTnDReLJ9ZcpqOpRB4= -google.golang.org/genproto/googleapis/api v0.0.0-20260727163830-6c54dddc4772/go.mod h1:1brfde68Npq6+WA75c1EHWPijZEG1kMus61ygPZfn4A= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260803160001-6ac0973c030d h1:IL4hdHzcUv2l/gcg98/Rj3FbtE6axwqslOW8SW0C+S0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260803160001-6ac0973c030d/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= +google.golang.org/genproto v0.0.0-20260715232425-e75dac1f907d h1:C9v1o0/4quuhOAfmRXA2j+we0PqZIp8traLdeogF3Ms= +google.golang.org/genproto v0.0.0-20260715232425-e75dac1f907d/go.mod h1:Wz2wFJntZFmLGo7pLDXZ3wYk5hyc0Mb+SkHhDDXT+lU= +google.golang.org/genproto/googleapis/api v0.0.0-20261012220534-4341edf3f941 h1:DS/w3N8rsfrwxwgGSj6WhMsPo7aNQGmDx74J81zd0NQ= +google.golang.org/genproto/googleapis/api v0.0.0-20261012220534-4341edf3f941/go.mod h1:AuGAdi9KnXss7xbLxIKhCvk+Ro/SxpET/iS45DNYN+M= +google.golang.org/genproto/googleapis/rpc v0.0.0-20261005182115-fad411399dd8 h1:0SXBqli5dnuCKMjI/X3FM226zEaEa0GUcSCJtN1vL2o= +google.golang.org/genproto/googleapis/rpc v0.0.0-20261005182115-fad411399dd8/go.mod h1:OaIUM3+LpYcK2GXM4FTmhWoIq371Owdr+Cc7/BsYHHc= google.golang.org/grpc v1.18.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= @@ -2069,8 +2060,8 @@ google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnD google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.83.0 h1:JeNZEKJFbQxArAMl+hiytHauacDNqJUllNfmIMmpqnQ= -google.golang.org/grpc v1.83.0/go.mod h1:kDyl6SKsiHKt0uylY5gtn5cEjkrIOhQOGDgIc4JGwzQ= +google.golang.org/grpc v1.84.0 h1:soMyaPJ8pAak5PIQ0DGBUir0XRo2fRoMqhNWMLlLxO0= +google.golang.org/grpc v1.84.0/go.mod h1:ljCht0DrxQrXBDRTZp52Qxh3Ffk8CdYm2sj4O2QN2C0= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/grpc/examples v0.0.0-20250407062114-b368379ef8f6 h1:ExN12ndbJ608cboPYflpTny6mXSzPrDLh0iTaVrRrds= google.golang.org/grpc/examples v0.0.0-20250407062114-b368379ef8f6/go.mod h1:6ytKWczdvnpnO+m+JiG9NjEDzR1FJfsnmJdG7B8QVZ8= @@ -2114,16 +2105,16 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkep gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= -gorm.io/driver/postgres v1.6.2 h1:BvXQ/cNUg63q5TFNg672DmDcowZSFrNLkkA3Xe6GXq4= -gorm.io/driver/postgres v1.6.2/go.mod h1:0c4fQA44XhOklXDkgtuKqysHCycTa5i9e3EIpDGCwXk= +gorm.io/driver/postgres v1.6.3 h1:bAn6O2pUa8LtpWEvL5NFU4+52Tfx8Ut7IVaIacCLcI0= +gorm.io/driver/postgres v1.6.3/go.mod h1:0c4fQA44XhOklXDkgtuKqysHCycTa5i9e3EIpDGCwXk= gorm.io/driver/sqlite v1.6.0 h1:WHRRrIiulaPiPFmDcod6prc4l2VGVWHz80KspNsxSfQ= gorm.io/driver/sqlite v1.6.0/go.mod h1:AO9V1qIQddBESngQUKWL9yoH93HIeA1X6V633rBwyT8= gorm.io/gorm v1.31.2 h1:3o8FXNo9v9S858gil+3LlZA1LkCOzgb4g5BL64FgaCo= gorm.io/gorm v1.31.2/go.mod h1:XyQVbO2k6YkOis7C2437jSit3SsDK72s7n7rsSHd+Gs= gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q= gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA= -helm.sh/helm/v3 v3.21.3 h1:wkamdwI3liEkW6wI1l9aGqQZGxcTKyt8kx0qJLPcmCg= -helm.sh/helm/v3 v3.21.3/go.mod h1:iaJ0iNsPoTZl++7h6vzQFyT0VEVtLYJiyRBDkPOOBTs= +helm.sh/helm/v3 v3.22.1 h1:uo2SouzAxMkKZTNzZ1lLP/c/Bu7xfUJKYDaYMxMHvk8= +helm.sh/helm/v3 v3.22.1/go.mod h1:FNQoawxnIIReGrTytJc55tKakylfpaC3pGf64BGo1rI= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -2133,31 +2124,31 @@ honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= k8s.io/api v0.23.3/go.mod h1:w258XdGyvCmnBj/vGzQMj6kzdufJZVUwEM1U2fRJwSQ= -k8s.io/api v0.36.4 h1:RxrvqCL6vgH5/+UnTeu1IIFqYmGfy0hnyrod1rn35Oo= -k8s.io/api v0.36.4/go.mod h1:S2B3orCFBDhrgyWbLeuKcT2QdHIpQesBkCYSlWtwUOw= -k8s.io/apiextensions-apiserver v0.36.4 h1:SfvCVt+4CqKWvzuVytYDT5g9hyb9MztoiYELIkPVrFc= -k8s.io/apiextensions-apiserver v0.36.4/go.mod h1:JT9V2Ju7ys1FY4zbSpmX9XOvKB3/BwsODc4hFQEa+Xo= +k8s.io/api v0.37.1 h1:l6N77U7tjwB5L056bgrBTJIEdevac/naBZ3iSvDNfpM= +k8s.io/api v0.37.1/go.mod h1:zSlbB1YpJ1YQlFVQy20UYll81UJSJJUMLhkhvg6Z78M= +k8s.io/apiextensions-apiserver v0.37.1 h1:7fIQG8eThDSTVYBWg/DOpI8v5wYfKCo0N8/TDMjj+zY= +k8s.io/apiextensions-apiserver v0.37.1/go.mod h1:1Q3ujWwHgnhBoGsdmGORflwK1sDFmuaqH1OsMDWk2Gs= k8s.io/apimachinery v0.23.3/go.mod h1:BEuFMMBaIbcOqVIJqNZJXGFTP4W6AycEpb5+m/97hrM= -k8s.io/apimachinery v0.36.4 h1:PT2UzkupGuAx/+xT5XjiMJ1WGpY3fn9/hdAvjweRet4= -k8s.io/apimachinery v0.36.4/go.mod h1:p2I2dipt7JHG+quVwQ1d02d28O4GdDi77RByQ13MTpk= -k8s.io/apiserver v0.36.4 h1:AtKjaf2eUiX5G6TfF2IOlhuUuvMsHh49Ivr1+4fZ2gA= -k8s.io/apiserver v0.36.4/go.mod h1:RyiGghXP67hb0Ll+7iLJ6GGv2JpEzCn7ljbiA+L3cJ0= -k8s.io/cli-runtime v0.36.4 h1:OHvManCwP1k9GiC5tXRFxHhzZIQQFCsrHlt7OspKo3w= -k8s.io/cli-runtime v0.36.4/go.mod h1:qQSj2FJgQos6GHpS/ge7wTdQMZm9XFWlesWgV6h7qZY= -k8s.io/client-go v0.36.4 h1:MDvfDNvMSt0Br94SK8neviVlwL9qifw9B26hJCpD1K0= -k8s.io/client-go v0.36.4/go.mod h1:pNK4WKELbwlEDvtbE8l22lEZL5THYF61H5EealokZmA= +k8s.io/apimachinery v0.37.1 h1:hGCYyvKHCwtwMitj2vU4vYx0Z16N9GyZk9BBnz0wDAE= +k8s.io/apimachinery v0.37.1/go.mod h1:jF84AyUi/IRIXRot5f+lm6MpxoWI+F1XgjaMmwCdTFw= +k8s.io/apiserver v0.37.1 h1:dUsNwjsvItyVKNpC1N0AhQ0OBSiUJKfWz004vPifOe0= +k8s.io/apiserver v0.37.1/go.mod h1:EWXW6PntGfOC2uD9GGVobnOExgFoX1z0hZo7f7Rs7Ng= +k8s.io/cli-runtime v0.37.1 h1:3mir5bM4XjMJHW3SMRk++3Ylf4YQne0XFFsW+IGT85U= +k8s.io/cli-runtime v0.37.1/go.mod h1:g3VQOm71f//aNbp79g0az9jBRTrvPjAHz7WxVysbZ4M= +k8s.io/client-go v0.37.1 h1:QTv/5ha4jAHtW9qxxVBkQVFBRDb4jHfFopQqqMdc+wM= +k8s.io/client-go v0.37.1/go.mod h1:dnAPtTnCNY38Ho04D2KdY1F4IKausa9UbqaAZKl60SY= k8s.io/code-generator v0.23.3/go.mod h1:S0Q1JVA+kSzTI1oUvbKAxZY/DYbA/ZUb4Uknog12ETk= -k8s.io/code-generator v0.36.4 h1:KNW2Alv5LVoGiooEYh1GY982CGyg53u1inHu6Zi4bIA= -k8s.io/code-generator v0.36.4/go.mod h1:JmRrlYwTOn2glEuGOfNnlXTGbz3FfMg7t7Dq/8lHcc4= -k8s.io/component-base v0.36.4 h1:tz75yC2xgq3kd7vPdBtR8do5iMx0OHf6Zd1kuaxDB84= -k8s.io/component-base v0.36.4/go.mod h1:DCwb306U8ou89NNAp45Csuy8ok+1rp1ELDVPhzN5AWc= -k8s.io/component-helpers v0.36.4 h1:B5+SnptAlwTVJO0MW1JLsZVp4KevlADRg0CX5YFzjbU= -k8s.io/component-helpers v0.36.4/go.mod h1:RECUDkRdVuxcNOAl9/EK7lmy1TIjoWkBHs6f0uOyoCs= +k8s.io/code-generator v0.37.1 h1:tvxxAiGc2kMxoGx8HtUacs4cBdl0X5R+auBD2He974U= +k8s.io/code-generator v0.37.1/go.mod h1:RJepz1uW2WnHEwPDoCGzI3p4V23C7WuUdtqjueDl1uU= +k8s.io/component-base v0.37.1 h1:93DMmlENnK7gNLkL4pMqLO5M/HVf3p3sM4q/GasLveY= +k8s.io/component-base v0.37.1/go.mod h1:bBrdziT4dreQG5lzTaPVxBwsZe1oxphG+ZVdD56dQWQ= +k8s.io/component-helpers v0.37.1 h1:V6ueiH2SBqpZil1X9+uMK8GAwsGYPVfoRN9eA5vY2G8= +k8s.io/component-helpers v0.37.1/go.mod h1:Ib5+txJA7lG9/xCdRrPshX8GnRRTXPElxtxo+bFQ0Y8= k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/gengo v0.0.0-20211129171323-c02415ce4185/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/gengo/v2 v2.0.0-20250604051438-85fd79dbfd9f/go.mod h1:EJykeLsmFC60UQbYJezXkEsG2FLrt0GPNkU5iK5GWxU= -k8s.io/gengo/v2 v2.0.0-20250922181213-ec3ebc5fd46b h1:gMplByicHV/TJBizHd9aVEsTYoJBnnUAT5MHlTkbjhQ= -k8s.io/gengo/v2 v2.0.0-20250922181213-ec3ebc5fd46b/go.mod h1:CgujABENc3KuTrcsdpGmrrASjtQsWCT7R99mEV4U/fM= +k8s.io/gengo/v2 v2.0.0-20260408192533-25e2208e0dc3 h1:3L6PNkMLXkU/pz3jWzaaIUz0Rs2V9h+5O51AeRC7poc= +k8s.io/gengo/v2 v2.0.0-20260408192533-25e2208e0dc3/go.mod h1:yvyl3l9E+UxlqOMUULdKTAYB0rEhsmjr7+2Vb/1pCSo= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/klog/v2 v2.30.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= @@ -2168,63 +2159,63 @@ k8s.io/klog/v2 v2.140.0 h1:Tf+J3AH7xnUzZyVVXhTgGhEKnFqye14aadWv7bzXdzc= k8s.io/klog/v2 v2.140.0/go.mod h1:o+/RWfJ6PwpnFn7OyAG3QnO47BFsymfEfrz6XyYSSp0= k8s.io/kube-openapi v0.0.0-20260427204847-8949caaa1199 h1:sWu4Td5mgJlwunsUydnhKEAfNUHM7hm1wfKEQmD7G5c= k8s.io/kube-openapi v0.0.0-20260427204847-8949caaa1199/go.mod h1:uGBT7iTA6c6MvqUvSXIaYZo9ukscABYi2btjhvgKGZ0= -k8s.io/kubectl v0.36.4 h1:xZd9g1bFBd7hpb1oKjK8lT9jRL18dtgr4DAPQG1Oksk= -k8s.io/kubectl v0.36.4/go.mod h1:STWlr78cdEa1hHpr55wpcboaqchvfDueKRNDa1zOd1w= +k8s.io/kubectl v0.37.1 h1:n1VCIntOJiX943uByXCThSZQmE+4v9jGS8S9u94/aHU= +k8s.io/kubectl v0.37.1/go.mod h1:66cc4Bz8PxBTxlrHzBuzXEzGIytAnNasKQPeEcpuaV8= k8s.io/kubelet v0.32.13 h1:pGSrLTytcmuIlq4yvuRFnF4RdQjQh1FfsmPeRZXDKTo= k8s.io/kubelet v0.32.13/go.mod h1:XrwKgyKhVUE8TO/w9Lqq93UTM5W6t7ePItIgjvSmV/4= -k8s.io/streaming v0.36.4 h1:RS5YlhrdBN2pKGVjgygGntdu6SNdsduyjGWGe3cX0vo= -k8s.io/streaming v0.36.4/go.mod h1:tJ6S2bZa2HxIBauguBbCWSCYyd93Grfz1+z3tcOvlDE= +k8s.io/streaming v0.37.1 h1:TpzVfQeFuVndn2g9mFqxy1UcUYPwDzqjUmwR/IzJCWc= +k8s.io/streaming v0.37.1/go.mod h1:APlJR26ZWRcVy5bIEj0QRrKUXROtBHPcxl2NT7EAzPU= k8s.io/utils v0.0.0-20211116205334-6203023598ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -k8s.io/utils v0.0.0-20260319190234-28399d86e0b5 h1:kBawHLSnx/mYHmRnNUf9d4CpjREbeZuxoSGOX/J+aYM= -k8s.io/utils v0.0.0-20260319190234-28399d86e0b5/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk= -kubevirt.io/api v1.9.0 h1:FWqx9yGk/GHUP5o4IthGXZ8FeAlgVNv2It48wD86UUo= -kubevirt.io/api v1.9.0/go.mod h1:tFKAVaJMm7bXCMLxOoUdAqBprKAXoCa0sp0gBmnfBgY= -kubevirt.io/client-go v1.10.0-alpha.0 h1:4fEp/8Aa6OUDRo5RZT5Uehw3K6Bp/tQPA2hIJhFCQfw= -kubevirt.io/client-go v1.10.0-alpha.0/go.mod h1:bXmbwFVCJsUnFGg1lgVSB2Jc180N7IzlQRHXJxlrG6U= +k8s.io/utils v0.0.0-20260626114624-be93311217bd h1:Ea7fgQ5we8Y9T0OX5o0dAHzQOBRI07D/dEYRaB9ZZEs= +k8s.io/utils v0.0.0-20260626114624-be93311217bd/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk= +kubevirt.io/api v1.9.1 h1:kV+n8NPBS0SJ8b6Xm+tPxPgFn3JeQUHmvSQ2SNtu1IU= +kubevirt.io/api v1.9.1/go.mod h1:tFKAVaJMm7bXCMLxOoUdAqBprKAXoCa0sp0gBmnfBgY= +kubevirt.io/client-go v1.10.0-beta.0 h1:W0b7BBY4uKCbi+QP22Wpv/MRAmTch9R+3FumXtSlCUA= +kubevirt.io/client-go v1.10.0-beta.0/go.mod h1:lxFei8lrDf6zbLTzv2jE+O7lQxx32E8LHGmD8Tw4XbE= kubevirt.io/containerized-data-importer-api v1.64.0 h1:yBLY6qEogUp8F+XSJvabIkx9uEEDeToYDfRr0mbUxJc= kubevirt.io/containerized-data-importer-api v1.64.0/go.mod h1:VGp35wxpLXU18b7cnEpmcThI3AjcZUSfg/Zfql44U4o= kubevirt.io/controller-lifecycle-operator-sdk/api v0.2.4 h1:fZYvD3/Vnitfkx6IJxjLAk8ugnZQ7CXVYcRfkSKmuZY= kubevirt.io/controller-lifecycle-operator-sdk/api v0.2.4/go.mod h1:018lASpFYBsYN6XwmA2TIrPCx6e0gviTd/ZNtSitKgc= -modernc.org/cc/v4 v4.28.4 h1:Hd/4Es+MBj+/7hSdZaisNyu6bv3V0Dp2MdllyfqaH+c= -modernc.org/cc/v4 v4.28.4/go.mod h1:OnovgIhbbMXMu1aISnJ0wvVD1KnW+cAUJkIrAWh+kVI= -modernc.org/ccgo/v4 v4.34.4 h1:OVnSOWQjVKOYkFxoHYB+qQmSHK5gqMqARM+K9DpR/Ws= -modernc.org/ccgo/v4 v4.34.4/go.mod h1:qdKqE8FNIYyysougB1RX9MxCzp5oJOcQXSobANJ4TuE= +modernc.org/cc/v4 v4.29.2 h1:h6+9ciCnPKutf4I03CvheAvDLX7+IHlqR6Iy6J+cgd8= +modernc.org/cc/v4 v4.29.2/go.mod h1:OnovgIhbbMXMu1aISnJ0wvVD1KnW+cAUJkIrAWh+kVI= +modernc.org/ccgo/v4 v4.35.0 h1:F+TUsmw09QxLzmi3aeYYGxjAXarmZaKgj3mKQHNaA8w= +modernc.org/ccgo/v4 v4.35.0/go.mod h1:qrVGs9S3Sr2Ztcg9ve+kTAYMp5a3YvWjo+SoN06kJ5I= modernc.org/fileutil v1.4.0 h1:j6ZzNTftVS054gi281TyLjHPp6CPHr2KCxEXjEbD6SM= modernc.org/fileutil v1.4.0/go.mod h1:EqdKFDxiByqxLk8ozOxObDSfcVOv/54xDs/DUHdvCUU= modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI= modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito= -modernc.org/gc/v3 v3.1.3 h1:6QAplYyVO+KdPW3pGnqmJDUxtkec8ooEWvks/hhU3lc= -modernc.org/gc/v3 v3.1.3/go.mod h1:HFK/6AGESC7Ex+EZJhJ2Gni6cTaYpSMmU/cT9RmlfYY= +modernc.org/gc/v3 v3.1.5 h1:21ldfPfRYE31Tb7B3mwAK8gy1AxP4+dKjrOQPfqakoc= +modernc.org/gc/v3 v3.1.5/go.mod h1:HFK/6AGESC7Ex+EZJhJ2Gni6cTaYpSMmU/cT9RmlfYY= modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks= modernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI= -modernc.org/libc v1.73.4 h1:+ra4Ui8ngyt8HDcO1FTDPWlkAh6yOdaO2yAoh8MddQA= -modernc.org/libc v1.73.4/go.mod h1:DXZ3eO8qMCNn2SnmTNCiC71nJ9Rcq3PsnpU6Vc4rWK8= +modernc.org/libc v1.75.6 h1:yKk8qo+Di4gkmvRboK8ocCqH22FiUCR6jRy2OwtCRus= +modernc.org/libc v1.75.6/go.mod h1:bO5o2ztHxBb2rjz0PgdHN0sSMw57CgxGFLZ3Qd/QpVQ= modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU= modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg= -modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI= -modernc.org/memory v1.11.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw= +modernc.org/memory v1.12.1 h1:nFMiWrpStgZczNl6XI9GnIk/rWhYIyHGUaR04pGbp9g= +modernc.org/memory v1.12.1/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw= modernc.org/opt v0.2.0 h1:tGyef5ApycA7FSEOMraay9SaTk5zmbx7Tu+cJs4QKZg= modernc.org/opt v0.2.0/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns= modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w= modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE= -modernc.org/sqlite v1.53.0 h1:20WG8N9q4ji/dEqGk4uiI0c6OPjSeLTNYGFCc3+7c1M= -modernc.org/sqlite v1.53.0/go.mod h1:xoEpOIpGrgT48H5iiyt/YXPCZPEzlfmfFwtk8Lklw8s= +modernc.org/sqlite v1.58.0 h1:38u40/bwkfM7f0Myhosl+SEMltSDxnGdQf8o6Kjmys0= +modernc.org/sqlite v1.58.0/go.mod h1:rsD2CckafgObKC4DhBlGBf+RiHxkc3hINGt1Xw32tVY= modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0= modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A= modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= -oras.land/oras-go/v2 v2.6.1 h1:bonOEkjLfp8tt6qXWRRWP6p1F+9octchOf2EqnWB4Zs= -oras.land/oras-go/v2 v2.6.1/go.mod h1:dhtFrFOuZuDtAVeZ9FUnaa5zfzplG3ZnFX9/uH1J/Yk= +oras.land/oras-go/v2 v2.6.2 h1:N04RXngAp1LJKTG6ifz3xHPipasEkWr+hFmInja5YKo= +oras.land/oras-go/v2 v2.6.2/go.mod h1:PlTtg4JTDJkDe8yVHpM2wz7/YDc00GVas+i4jAW2TZ4= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.34.0 h1:hSfpvjjTQXQY2Fol2CS0QHMNs/WI1MOSGzCm1KhM5ec= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.34.0/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw= -sigs.k8s.io/controller-runtime v0.24.1 h1:miPEwrmirImAvgME1L9qebGHrOnGJoVmVdtOU9fRfo4= -sigs.k8s.io/controller-runtime v0.24.1/go.mod h1:vFkfY5fGt5xAC/sKb8IBFKgWPNKG9OUG29dR8Y2wImw= -sigs.k8s.io/controller-tools v0.21.0 h1:KXDQza3bgjlPY6xLR63tI/40gzjhyUAvkCrwzd2/6cs= -sigs.k8s.io/controller-tools v0.21.0/go.mod h1:DLIypi3Q2+azVAP8jr/mHXJgveYYHFjhnNOUuBJ10JE= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.36.0 h1:/YpDJ4vReG7ZmzSpBGxduXgywWkJU9zHubgJG03MT+Y= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.36.0/go.mod h1:tJo1aepTXyR+8Xs3sUsGBDk4Ub2AM5dPAPKJx0mpm5c= +sigs.k8s.io/controller-runtime v0.25.2 h1:bEkK3PVOIVK9X8QWLGVhJgmFc++47vfT6wakSzAOLsQ= +sigs.k8s.io/controller-runtime v0.25.2/go.mod h1:4QqLdT6z/L6Olj8JJCtvztid4/fnIiYsfaTFScegctc= +sigs.k8s.io/controller-tools v0.22.0 h1:eG3FAVja/KnlXKIWg95udIFz1cMyAtMjP11cqBh3t+k= +sigs.k8s.io/controller-tools v0.22.0/go.mod h1:VizwUStoZK7rReCj704czGGrB7mLxXTiJSJt7wN5ilI= sigs.k8s.io/e2e-framework v0.7.0 h1:AHkySTC6MvnnMbVSxaO4z1m2MhQKNFP+2Ihs5pRNLlM= sigs.k8s.io/e2e-framework v0.7.0/go.mod h1:1ZgXkUSjmnf18/JgHZNEATWjv48O5lJm9aI1QIsRdbw= sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs= @@ -2242,8 +2233,8 @@ sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= sigs.k8s.io/structured-merge-diff/v6 v6.2.0/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= -sigs.k8s.io/structured-merge-diff/v6 v6.4.0 h1:qmp2e3ZfFi1/jJbDGpD4mt3wyp6PE1NfKHCYLqgNQJo= -sigs.k8s.io/structured-merge-diff/v6 v6.4.0/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= +sigs.k8s.io/structured-merge-diff/v6 v6.4.2 h1:qdOxHwrl2Kaag1aQEarlYcOA9vSyGCp3CIki3aW8c4Q= +sigs.k8s.io/structured-merge-diff/v6 v6.4.2/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/govulncheck-allowlist.json b/govulncheck-allowlist.json index aa01576ec552e..1ed96ccb6020a 100644 --- a/govulncheck-allowlist.json +++ b/govulncheck-allowlist.json @@ -1,10 +1,4 @@ { "exceptions": { - "GO-2022-0635": { - "reason": "Unused portion of the SDK" - }, - "GO-2022-0646": { - "reason": "Unused portion of the SDK" - } } } diff --git a/image/postgres/Dockerfile b/image/postgres/Dockerfile index edb3503720933..f8391fe1b3480 100644 --- a/image/postgres/Dockerfile +++ b/image/postgres/Dockerfile @@ -1,4 +1,4 @@ -ARG PG_VERSION=15 +ARG PG_VERSION=16 FROM quay.io/sclorg/postgresql-${PG_VERSION}-c9s:latest AS final USER root @@ -39,7 +39,11 @@ RUN --mount=type=cache,target=/var/cache/dnf,sharing=locked \ rpm --verbose -e --nodeps $(rpm -qa curl '*rpm*' '*dnf*' '*libsolv*' '*hawkey*' 'yum*') && \ mkdir /docker-entrypoint-initdb.d -COPY --link scripts \ +COPY --link \ + scripts/backup-cleanup.sh \ + scripts/cert-watcher.sh \ + scripts/docker-entrypoint.sh \ + scripts/init-entrypoint.sh \ /usr/local/bin/ ENV LANG="en_US.utf8" diff --git a/image/postgres/README.md b/image/postgres/README.md new file mode 100644 index 0000000000000..8b4b43dcd434f --- /dev/null +++ b/image/postgres/README.md @@ -0,0 +1,50 @@ +# PostgreSQL upgrade backups + +`init-entrypoint.sh` creates a physical `backup.tar` before a supported PostgreSQL +major-version upgrade and verifies it by restoring and starting the old server. +Backups live in `-` directories on the optional backup PVC +(`/var/lib/postgresql/backup`) or the data PVC (`/var/lib/postgresql/data/backup`). + +## Automatic cleanup + +Cleanup runs only during a forward upgrade from `POSTGRESQL_PREV_VERSION`, after +checking the required binaries and starting and cleanly stopping the source DB. +It preserves older backups until the new backup has been verified. If neither +backup location has enough space for the new backup and its verification copy, +it first tries reclaiming obsolete backups and checks the space again. Cleanup +errors are logged; insufficient space still prevents the upgrade. + +A cleanup candidate must be a real directory with a canonical, increasing pair +of positive major versions (up to three digits) and a nonempty, regular, +non-symlink `backup.tar`. Its source version must precede the current source +version, and its destination must not exceed that version. For a `15-16` upgrade, +`13-15` qualifies; `15-16`, `16-17`, and `13-16` are preserved. Symlinked roots, +symlinked directories, unrelated names, and missing or ambiguous archives are +preserved. The layout identifies legacy backups; cleanup does not inspect their +archive contents. + +These older backups are outside the current image's supported rollback path. +They may still be useful with an older compatible image. When disk space is +insufficient, reclaiming them before the new backup is verified is a deliberate +tradeoff: the validated source database remains in place, but a later failure can +leave those older recovery points unavailable. + +There is no automatic age-based expiration. Ordinary startups and fresh +initialization preserve backups. `RESTORE_BACKUP` and `FORCE_NEW_BACKUP` suppress +automatic cleanup during recovery; their existing explicit actions still apply. +`FORCE_OLD_BINARIES` bypasses the upgrade and its cleanup entirely. In particular, +`FORCE_NEW_BACKUP` still explicitly removes the current upgrade backup. + +`FORCE_CLEANUP=true` removes `${PGDATA}-new`, the temporary database directory left +by a previous upgrade attempt, so the upgrade can retry. It does not suppress +automatic backup cleanup: obsolete backups remain eligible for removal under the +same validation and space checks as a normal upgrade. If `RESTORE_BACKUP` or +`FORCE_NEW_BACKUP` is also set to `true`, automatic backup cleanup stays disabled. + +## Tests + +Run `bats image/postgres/scripts`. Helper tests exercise real filesystem deletion +and preservation. Entrypoint tests use temporary paths and fake PostgreSQL and +space checks to cover cleanup timing, failures, retries, and recovery modes. +Real major-version upgrade and restore validation also requires a PostgreSQL +container with both supported server versions. diff --git a/image/postgres/download.sh b/image/postgres/download.sh index 624b992ee4867..977dfde78cf4f 100755 --- a/image/postgres/download.sh +++ b/image/postgres/download.sh @@ -2,7 +2,7 @@ set -euo pipefail -postgres_major=15 +postgres_major=16 pg_rhel_major=9 arch="$(uname -m)" @@ -16,6 +16,7 @@ output_dir="/rpms" mkdir $output_dir if [[ "$arch" == "s390x" ]]; then + dnf module enable -y postgresql:16 dnf install -y --downloadonly --downloaddir=/tmp postgresql postgresql-private-libs postgresql-server postgresql-contrib mv /tmp/postgresql-contrib-*.rpm "${output_dir}/postgres-contrib.rpm" mv /tmp/postgresql-server-*.rpm "${output_dir}/postgres-server.rpm" diff --git a/image/postgres/konflux.Dockerfile b/image/postgres/konflux.Dockerfile index 64fef48112d32..fb56cc8aa00de 100644 --- a/image/postgres/konflux.Dockerfile +++ b/image/postgres/konflux.Dockerfile @@ -1,5 +1,5 @@ -ARG PG_VERSION=15 -FROM registry.redhat.io/rhel9/postgresql-${PG_VERSION}:latest@sha256:26ca481f6fea9df09cb9e758188ad96382262d7487b104b1d6fd97b9b1ad15c9 AS final +ARG PG_VERSION=16 +FROM registry.redhat.io/rhel9/postgresql-${PG_VERSION}:latest@sha256:791a6f14563178d1bbcd3515bc7dc80c1ae0788a829ff26551cdedbf8f50f0d2 AS final USER root @@ -41,7 +41,11 @@ RUN localedef -f UTF-8 -i en_US en_US.UTF-8 && \ COPY LICENSE /licenses/LICENSE -COPY image/postgres/scripts \ +COPY \ + image/postgres/scripts/backup-cleanup.sh \ + image/postgres/scripts/cert-watcher.sh \ + image/postgres/scripts/docker-entrypoint.sh \ + image/postgres/scripts/init-entrypoint.sh \ /usr/local/bin/ ENV LANG="en_US.utf8" diff --git a/image/postgres/scripts/backup-cleanup.sh b/image/postgres/scripts/backup-cleanup.sh new file mode 100755 index 0000000000000..6db79fc7a801c --- /dev/null +++ b/image/postgres/scripts/backup-cleanup.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash + +# Remove recognized backups outside the current image's supported rollback path. +# Call only during a supported forward upgrade, after validating the source DB. +# Missing, ambiguous, or linked backups are preserved. Cleanup is best effort; +# callers must check available space again before attempting a new backup. +cleanup_stale_upgrade_backups() { + local current_upgrade_dir="$1" + shift + + # Accept canonical, bounded major versions so arithmetic cannot overflow. + local upgrade_pattern='^([1-9][0-9]{0,2})-([1-9][0-9]{0,2})$' + [[ "${current_upgrade_dir}" =~ ${upgrade_pattern} ]] || return 0 + local current_old_version="${BASH_REMATCH[1]}" + local current_new_version="${BASH_REMATCH[2]}" + (( current_old_version < current_new_version )) || return 0 + + local location old_backup backup_name backup_old_version backup_new_version + for location in "$@"; do + # Strip trailing slashes before testing for symlinks, including on roots. + while [[ "${location}" == */ ]]; do location="${location%/}"; done + [[ "${location}" == /* && -d "${location}" && ! -L "${location}" ]] || continue + + for old_backup in "${location}"/*; do + [[ -d "${old_backup}" && ! -L "${old_backup}" ]] || continue + backup_name="${old_backup##*/}" + [[ "${backup_name}" =~ ${upgrade_pattern} ]] || continue + backup_old_version="${BASH_REMATCH[1]}" + backup_new_version="${BASH_REMATCH[2]}" + # Preserve the current rollback version and any newer or ambiguous pair. + (( backup_old_version < backup_new_version && backup_old_version < current_old_version && + backup_new_version <= current_old_version )) || continue + [[ -f "${old_backup}/backup.tar" && -s "${old_backup}/backup.tar" && + ! -L "${old_backup}/backup.tar" ]] || continue + + echo "Removing obsolete upgrade backup ${old_backup}" + if ! rm -rf -- "${old_backup}"; then + echo "Warning: could not completely remove upgrade backup ${old_backup}" >&2 + fi + done + done + return 0 +} diff --git a/image/postgres/scripts/backup-cleanup_test.bats b/image/postgres/scripts/backup-cleanup_test.bats new file mode 100755 index 0000000000000..c17e5602e2f48 --- /dev/null +++ b/image/postgres/scripts/backup-cleanup_test.bats @@ -0,0 +1,142 @@ +#!/usr/bin/env bats + +setup() { + TEST_ROOT="${BATS_TEST_TMPDIR}/backup-cleanup" + BACKUP_VOLUME="${TEST_ROOT}/backup-volume" + DATA_VOLUME="${TEST_ROOT}/data-volume" + mkdir -p "${BACKUP_VOLUME}" "${DATA_VOLUME}" + + # shellcheck source=backup-cleanup.sh + source "${BATS_TEST_DIRNAME}/backup-cleanup.sh" +} + +make_backup() { + mkdir -p "$1" + echo "backup fixture" > "$1/backup.tar" +} + +@test "cleanup removes recognized backups from earlier upgrades in both locations" { + make_backup "${BACKUP_VOLUME}/13-15" + make_backup "${BACKUP_VOLUME}/14-15" + make_backup "${DATA_VOLUME}/13-14" + + cleanup_stale_upgrade_backups "15-16" "${BACKUP_VOLUME}" "${DATA_VOLUME}" + + [ ! -d "${BACKUP_VOLUME}/13-15" ] + [ ! -d "${BACKUP_VOLUME}/14-15" ] + [ ! -d "${DATA_VOLUME}/13-14" ] +} + +@test "cleanup preserves current, newer, and ambiguous upgrade pairs regardless of age" { + local pair + for pair in 15-16 16-17 15-17 13-16 15-15 15-13 0-15 013-15 13-015 999999999999999999999-15; do + make_backup "${BACKUP_VOLUME}/${pair}" + touch -t 202001010000 "${BACKUP_VOLUME}/${pair}" + done + + cleanup_stale_upgrade_backups "15-16" "${BACKUP_VOLUME}" + + for pair in 15-16 16-17 15-17 13-16 15-15 15-13 0-15 013-15 13-015 999999999999999999999-15; do + [ -f "${BACKUP_VOLUME}/${pair}/backup.tar" ] + done +} + +@test "cleanup preserves unrelated directories and files including numeric names without backups" { + local name + for name in lost+found unrelated 1foo-2 13-15-extra .13-15; do + make_backup "${BACKUP_VOLUME}/${name}" + done + mkdir -p "${BACKUP_VOLUME}/13-15" "${BACKUP_VOLUME}/14-15" + touch "${BACKUP_VOLUME}/14-15/backup.tar" "${BACKUP_VOLUME}/README" + + cleanup_stale_upgrade_backups "15-16" "${BACKUP_VOLUME}" + + for name in lost+found unrelated 1foo-2 13-15-extra .13-15 13-15 14-15; do + [ -d "${BACKUP_VOLUME}/${name}" ] + done + [ -f "${BACKUP_VOLUME}/README" ] +} + +@test "cleanup preserves symlinked directories and their targets" { + make_backup "${TEST_ROOT}/outside" + ln -s "${TEST_ROOT}/outside" "${BACKUP_VOLUME}/13-15" + ln -s "${TEST_ROOT}/missing" "${BACKUP_VOLUME}/14-15" + + cleanup_stale_upgrade_backups "15-16" "${BACKUP_VOLUME}" + + [ -L "${BACKUP_VOLUME}/13-15" ] + [ -L "${BACKUP_VOLUME}/14-15" ] + [ -f "${TEST_ROOT}/outside/backup.tar" ] +} + +@test "cleanup rejects symlinked backup roots with or without trailing slashes" { + make_backup "${TEST_ROOT}/outside/13-15" + ln -s "${TEST_ROOT}/outside" "${TEST_ROOT}/linked-root" + + cleanup_stale_upgrade_backups "15-16" "${TEST_ROOT}/linked-root" "${TEST_ROOT}/linked-root///" + + [ -f "${TEST_ROOT}/outside/13-15/backup.tar" ] +} + +@test "cleanup preserves directories with linked or nonregular backup archives" { + make_backup "${TEST_ROOT}/outside" + mkdir -p "${BACKUP_VOLUME}/13-15" "${BACKUP_VOLUME}/14-15/backup.tar" + ln -s "${TEST_ROOT}/outside/backup.tar" "${BACKUP_VOLUME}/13-15/backup.tar" + + cleanup_stale_upgrade_backups "15-16" "${BACKUP_VOLUME}" + + [ -L "${BACKUP_VOLUME}/13-15/backup.tar" ] + [ -d "${BACKUP_VOLUME}/14-15/backup.tar" ] + [ -f "${TEST_ROOT}/outside/backup.tar" ] +} + +@test "cleanup does not follow nested symlinks in recognized backups" { + make_backup "${BACKUP_VOLUME}/13-15" + make_backup "${TEST_ROOT}/outside" + ln -s "${TEST_ROOT}/outside" "${BACKUP_VOLUME}/13-15/nested" + + cleanup_stale_upgrade_backups "15-16" "${BACKUP_VOLUME}" + + [ ! -d "${BACKUP_VOLUME}/13-15" ] + [ -f "${TEST_ROOT}/outside/backup.tar" ] +} + +@test "cleanup is idempotent and accepts empty or missing locations" { + make_backup "${BACKUP_VOLUME}/13-15" + + cleanup_stale_upgrade_backups "15-16" "${BACKUP_VOLUME}/" + run cleanup_stale_upgrade_backups "15-16" "${BACKUP_VOLUME}" "${DATA_VOLUME}" "${TEST_ROOT}/missing" "" + + [ "${status}" -eq 0 ] + [ ! -d "${BACKUP_VOLUME}/13-15" ] +} + +@test "invalid or non-forward current upgrades never delete backups" { + make_backup "${BACKUP_VOLUME}/13-15" + local pair + for pair in "" invalid 16-15 15-15 015-16 0-16 15-999999999999999999999; do + cleanup_stale_upgrade_backups "${pair}" "${BACKUP_VOLUME}" + [ -f "${BACKUP_VOLUME}/13-15/backup.tar" ] + done +} + +@test "cleanup reports deletion failures and continues under errexit" { + make_backup "${BACKUP_VOLUME}/13-15" + make_backup "${BACKUP_VOLUME}/14-15" + rm() { + if [[ "${*: -1}" == */13-15 ]]; then + echo "Permission denied" >&2 + return 1 + fi + command rm "$@" + } + export -f rm cleanup_stale_upgrade_backups + + run bash -ec 'cleanup_stale_upgrade_backups 15-16 "$1"; echo continued' _ "${BACKUP_VOLUME}" + + [ "${status}" -eq 0 ] + [[ "${output}" == *"Warning: could not completely remove"* ]] + [[ "${output}" == *continued* ]] + [ -f "${BACKUP_VOLUME}/13-15/backup.tar" ] + [ ! -d "${BACKUP_VOLUME}/14-15" ] +} diff --git a/image/postgres/scripts/docker-entrypoint.sh b/image/postgres/scripts/docker-entrypoint.sh index 371b5dbd60021..6eafa1e5ac6bb 100755 --- a/image/postgres/scripts/docker-entrypoint.sh +++ b/image/postgres/scripts/docker-entrypoint.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# This file is from https://github.com/docker-library/postgres/tree/master/15/bookworm +# This file is from https://github.com/docker-library/postgres/tree/master/16/bookworm set -Eeo pipefail # TODO swap to -Eeuo pipefail above (after handling all potentially-unset variables) @@ -362,7 +362,7 @@ _main() { ### ROX_TLS_MIN_VERSION: passed to ssl_min_protocol_version (e.g. "TLSv1.2", "TLSv1.3"). ### ROX_TLS_OPENSSL_CIPHERS: colon-separated OpenSSL cipher names ### (e.g. "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384"). - ### Only affects TLS 1.2; TLS 1.3 ciphers are not configurable in PostgreSQL 15. + ### Only affects TLS 1.2; TLS 1.3 ciphers are not configurable in PostgreSQL 16. if [ -n "${ROX_TLS_MIN_VERSION:-}" ]; then set -- "$@" -c "ssl_min_protocol_version=${ROX_TLS_MIN_VERSION}" fi diff --git a/image/postgres/scripts/init-entrypoint.sh b/image/postgres/scripts/init-entrypoint.sh index cb4ce80fc7c12..e35c43c8e3fd1 100755 --- a/image/postgres/scripts/init-entrypoint.sh +++ b/image/postgres/scripts/init-entrypoint.sh @@ -2,6 +2,9 @@ set -Eeo pipefail +# shellcheck source=backup-cleanup.sh +source "$(dirname "${BASH_SOURCE[0]}")/backup-cleanup.sh" + # Return the list of possible backup locations based on the mounted volumes. # The result is either two locations, if the backup volume is mounted, or only # one otherwise. @@ -13,7 +16,7 @@ get_backup_locations () { local -n locations=$1 - if $(df | grep "${BACKUP_VOLUME_MOUNT}"); then + if df | grep -q "${BACKUP_VOLUME_MOUNT}"; then locations+=("${BACKUP_VOLUME_MOUNT}"); fi @@ -67,6 +70,7 @@ else PG_DATA_VERSION=$(cat "${PGDATA}/PG_VERSION") + backup_locations=() get_backup_locations backup_locations if [[ -v FORCE_CLEANUP && "${FORCE_CLEANUP}" == "true" ]]; then @@ -83,7 +87,7 @@ else # since we could be asked to restore a backup after an upgrade. # $POSTGRESQL_PREV_VERSION is an env variable set by the # postgresql-container image itself. - for location in ${backup_locations[*]} + for location in "${backup_locations[@]}" do echo "Removing ${location}/$POSTGRESQL_PREV_VERSION-$PG_BINARY_VERSION/" rm -rf "${location}/$POSTGRESQL_PREV_VERSION-$PG_BINARY_VERSION/" @@ -97,7 +101,7 @@ else # since we could be asked to restore a backup after an upgrade. # $POSTGRESQL_PREV_VERSION is an env variable set by the # postgresql-container image itself. - for location in ${backup_locations[*]} + for location in "${backup_locations[@]}" do BACKUP_DIR="${location}/$POSTGRESQL_PREV_VERSION-$PG_BINARY_VERSION/" @@ -141,17 +145,57 @@ else exit 1 fi + # Validate the supported source version and binaries before deleting backups. + if [ "${PG_DATA_VERSION}" != "${POSTGRESQL_PREV_VERSION:-}" ]; then + echo "Unsupported PostgreSQL upgrade from ${PG_DATA_VERSION} to ${PG_BINARY_VERSION}." + exit 1 + fi + OLD_BINARIES="/usr/lib64/pgsql/postgresql-${PG_DATA_VERSION}/bin" + NEW_BINARIES="/usr/bin" + for binary in "${OLD_BINARIES}/postgres" "${OLD_BINARIES}/pg_ctl" \ + "${OLD_BINARIES}/pg_isready" "${OLD_BINARIES}/pg_controldata" \ + "${NEW_BINARIES}/initdb" "${NEW_BINARIES}/pg_upgrade"; do + if [ ! -x "${binary}" ]; then + echo "Required PostgreSQL upgrade binary is missing: ${binary}" + exit 1 + fi + done + + # Recovery operations must not automatically discard other recovery backups. + ALLOW_BACKUP_CLEANUP=true + if [[ "${RESTORE_BACKUP:-}" == true || "${FORCE_NEW_BACKUP:-}" == true ]]; then + ALLOW_BACKUP_CLEANUP=false + fi + + # Upgrade requires restrictive permissions and a cleanly stopped source DB. + # Check its health before reclaiming space from any older backups. + chmod 0700 "${PGDATA}" + echo "Make sure PostgreSQL is shutdown clearly." + "${OLD_BINARIES}/pg_ctl" start -w --timeout 86400 -o "-h 127.0.0.1" + "${OLD_BINARIES}/pg_isready" -h 127.0.0.1 + "${OLD_BINARIES}/pg_ctl" stop -w + + STATUS=$("${OLD_BINARIES}/pg_controldata" -D "${PGDATA}" |\ + grep "Database cluster state" |\ + awk -F ':' '{print $2}' |\ + tr -d '[:space:]') + if [ "$STATUS" != "shutdown" ]; then + echo "Cluster was not shutdown cleanly." + exit 1 + fi + # This is the amount of disk space we currently consume. Normally we # could use df as well, since the data will be the only disk space # consumer, but in testing environment it might not be the case. PG_DATA_USED=$(du -s "${PGDATA}" | awk '{print $1}') + PG_BACKUP_VOLUME="" echo "Verifying backup locations ${backup_locations[*]}" - for location in ${backup_locations[*]} + for location in "${backup_locations[@]}" do - # The backup volume needs to accomodate two copies of data, one is the + # The backup volume needs to accommodate two copies of data, one is the # actual backup, and one is a restored copy, which will be deleted later. - echo "${location}: Checking avaibale disk space..." + echo "${location}: Checking available disk space..." if check_available_space "${location}" $((PG_DATA_USED * 2)); then echo "Location has enough space." PG_BACKUP_VOLUME="${location}" @@ -161,6 +205,19 @@ else fi done + # Reclaim space only if no location can hold the backup and verification copy. + # Otherwise preserve older backups until the new backup has been verified. + if [[ -z "${PG_BACKUP_VOLUME}" && "${ALLOW_BACKUP_CLEANUP}" == true ]]; then + for location in "${backup_locations[@]}"; do + cleanup_stale_upgrade_backups \ + "${PG_DATA_VERSION}-${PG_BINARY_VERSION}" "${location}" + if check_available_space "${location}" $((PG_DATA_USED * 2)); then + PG_BACKUP_VOLUME="${location}" + break + fi + done + fi + if [ -z "${PG_BACKUP_VOLUME}" ]; then echo "Not enough disk space, upgrade is cancelled." exit 1 @@ -168,30 +225,6 @@ else echo "Backup will be stored in ${PG_BACKUP_VOLUME}" fi - # After this point we know there is enough available disk space. - OLD_BINARIES="/usr/lib64/pgsql/postgresql-${PG_DATA_VERSION}/bin" - NEW_BINARIES="/usr/bin" - - # Not sure how it works now, but during the upgrade group permissions - # are rejected. - chmod 0700 "${PGDATA}" - - echo "Make sure PostgreSQL is shutdown clearly." - # Try to restart cluster temporary to make sure it was shutdown properly - "${OLD_BINARIES}/pg_ctl" start -w --timeout 86400 -o "-h 127.0.0.1" - "${OLD_BINARIES}/pg_isready" -h 127.0.0.1 - "${OLD_BINARIES}/pg_ctl" stop -w - - STATUS=$("${OLD_BINARIES}/pg_controldata" -D "${PGDATA}" |\ - grep "Database cluster state" |\ - awk -F ':' '{print $2}' |\ - tr -d '[:space:]') - - if [ "$STATUS" != "shutdown" ]; then - echo "Cluster was not shutdown cleanly." - exit 1 - fi - BACKUP_DIR="${PG_BACKUP_VOLUME}/$PG_DATA_VERSION-$PG_BINARY_VERSION/" # Do not care about symlinks yet if [ -d "${BACKUP_DIR}" ]; then @@ -221,6 +254,11 @@ else rm -rf "${BACKUP_VERIFY_PGDATA}" + if [ "${ALLOW_BACKUP_CLEANUP}" == true ]; then + cleanup_stale_upgrade_backups \ + "${PG_DATA_VERSION}-${PG_BINARY_VERSION}" "${backup_locations[@]}" + fi + echo "Upgrade..." # Good idea to --check first # shellcheck disable=SC2086 @@ -232,7 +270,7 @@ else --new-bindir="${NEW_BINARIES}" \ --old-datadir="${PGDATA}" \ --new-datadir="${PGDATA_NEW}" \ - --clone -j 4 -k --check + -j 4 -k --check RESULT=$? if [ $RESULT -ne 0 ]; then @@ -247,7 +285,7 @@ else --new-bindir="${NEW_BINARIES}" \ --old-datadir="${PGDATA}" \ --new-datadir="${PGDATA_NEW}" \ - --clone -j 4 -k + -j 4 -k RESULT=$? if [ $RESULT -ne 0 ]; then diff --git a/image/postgres/scripts/init-entrypoint_test.bats b/image/postgres/scripts/init-entrypoint_test.bats new file mode 100755 index 0000000000000..fa2f670a62dd9 --- /dev/null +++ b/image/postgres/scripts/init-entrypoint_test.bats @@ -0,0 +1,333 @@ +#!/usr/bin/env bats + +# Bats isolates each test in a subshell; exported fixture settings are per test. +# shellcheck disable=SC2030,SC2031 + +# Exercise the actual entrypoint's filesystem operations and control flow, using +# temporary paths and fake PostgreSQL/space checks. Real upgrades need a DB image. +setup() { + export TEST_ROOT="${BATS_TEST_TMPDIR}/init-entrypoint" + export PGDATA="${TEST_ROOT}/volumes/data/pgdata" + export BACKUP_VOLUME="${TEST_ROOT}/volumes/backup" + export DATA_VOLUME="${TEST_ROOT}/volumes/data/backup" + export POSTGRESQL_PREV_VERSION=15 + export TEST_EVENTS="${TEST_ROOT}/events" + export TEST_SPACE_MODE=available + export TEST_REAL_TAR + TEST_REAL_TAR=$(command -v tar) + unset RESTORE_BACKUP FORCE_OLD_BINARIES FORCE_NEW_BACKUP FORCE_CLEANUP + mkdir -p "${PGDATA}" "${BACKUP_VOLUME}" "${DATA_VOLUME}" \ + "${TEST_ROOT}/scripts" "${TEST_ROOT}/bin" "${TEST_ROOT}/old/postgresql-15/bin" + echo 15 > "${PGDATA}/PG_VERSION" + touch "${PGDATA}/postgresql.conf" "${TEST_EVENTS}" "${TEST_ROOT}/password" + + # Only replace fixed runtime paths; retain the production script's control flow. + sed -e "s|/var/lib/postgresql|${TEST_ROOT}/volumes|g" \ + -e "s|/usr/lib64/pgsql|${TEST_ROOT}/old|g" \ + -e "s|NEW_BINARIES=\"/usr/bin\"|NEW_BINARIES=\"${TEST_ROOT}/bin\"|g" \ + -e "s|/run/secrets/stackrox.io/secrets/password|${TEST_ROOT}/password|g" \ + "${BATS_TEST_DIRNAME}/init-entrypoint.sh" > "${TEST_ROOT}/scripts/init-entrypoint.sh" + cp "${BATS_TEST_DIRNAME}/backup-cleanup.sh" "${TEST_ROOT}/scripts/" + + cat > "${TEST_ROOT}/mock" <<'MOCK' +#!/usr/bin/env bash +set -euo pipefail +echo "${0##*/} $*" >> "${TEST_EVENTS}" +case "${0##*/}" in + postgres) echo 'postgres (PostgreSQL) 16.10' ;; + pg_ctl) + if [[ "$*" == *backup-restore-test* ]]; then + [[ "${TEST_FAIL_VERIFICATION:-}" != true ]] + else + [[ "${TEST_FAIL_SOURCE_START:-}" != true ]] + fi + ;; + pg_isready) exit 0 ;; + pg_controldata) echo "Database cluster state: ${TEST_CLUSTER_STATE:-shutdown}" ;; + pg_upgrade) [[ "${TEST_FAIL_UPGRADE:-}" != true ]] ;; + initdb) + target="${*: -1}" + [[ "${target}" == */pgdata-new ]] || target="${PGDATA}" + mkdir -p "${target}" + echo 16 > "${target}/PG_VERSION" + touch "${target}/postgresql.conf" + ;; + df) + if [[ $# == 0 ]]; then + echo "fixture 1000000 0 1000000 0% ${BACKUP_VOLUME}" + else + available=1000000 + case "${TEST_SPACE_MODE}" in + full) available=0 ;; + first-full) [[ "$1" != "${BACKUP_VOLUME}" ]] || available=0 ;; + reclaimable) [[ ! -f "$1/13-15/backup.tar" ]] || available=0 ;; + esac + echo "fixture 1000000 0 ${available} 0% $1" + fi + ;; + tar) + args=() + for arg in "$@"; do + [[ "${arg}" == --checkpoint=* ]] || args+=("${arg}") + done + exec "${TEST_REAL_TAR}" "${args[@]}" + ;; + sync) exit 0 ;; +esac +MOCK + chmod +x "${TEST_ROOT}/mock" + local binary + for binary in postgres pg_ctl pg_isready pg_controldata; do + cp "${TEST_ROOT}/mock" "${TEST_ROOT}/old/postgresql-15/bin/${binary}" + done + for binary in postgres initdb pg_upgrade df tar sync; do + cp "${TEST_ROOT}/mock" "${TEST_ROOT}/bin/${binary}" + done + export PATH="${TEST_ROOT}/bin:${PATH}" + make_upgrade_backup "${BACKUP_VOLUME}/13-15" + make_upgrade_backup "${DATA_VOLUME}/13-15" +} + +make_upgrade_backup() { + mkdir -p "$1" + "${TEST_REAL_TAR}" -cf "$1/backup.tar" -C "${PGDATA}" . +} + +run_init() { + run bash "${TEST_ROOT}/scripts/init-entrypoint.sh" +} + +assert_older_backups_preserved() { + [ -s "${BACKUP_VOLUME}/13-15/backup.tar" ] + [ -s "${DATA_VOLUME}/13-15/backup.tar" ] +} + +@test "ordinary startup preserves aged backups including the latest rollback backup" { + echo 16 > "${PGDATA}/PG_VERSION" + make_upgrade_backup "${BACKUP_VOLUME}/15-16" + touch -t 202001010000 "${BACKUP_VOLUME}/15-16" "${BACKUP_VOLUME}/13-15" + + run_init + + [ "${status}" -eq 0 ] + assert_older_backups_preserved + [ -s "${BACKUP_VOLUME}/15-16/backup.tar" ] +} + +@test "fresh initialization does not clean up existing backups" { + rm "${PGDATA}/PG_VERSION" + + run_init + + [ "${status}" -eq 0 ] + [ "$(cat "${PGDATA}/PG_VERSION")" = 16 ] + assert_older_backups_preserved +} + +@test "unsupported source versions fail before cleanup" { + echo 13 > "${PGDATA}/PG_VERSION" + + run_init + + [ "${status}" -ne 0 ] + [[ "${output}" == *"Unsupported PostgreSQL upgrade"* ]] + assert_older_backups_preserved +} + +@test "missing upgrade binaries fail before cleanup" { + rm "${TEST_ROOT}/old/postgresql-15/bin/pg_ctl" + + run_init + + [ "${status}" -ne 0 ] + [[ "${output}" == *"Required PostgreSQL upgrade binary is missing"* ]] + assert_older_backups_preserved +} + +@test "source startup failure prevents cleanup even when space is needed" { + export TEST_SPACE_MODE=reclaimable TEST_FAIL_SOURCE_START=true + + run_init + + [ "${status}" -ne 0 ] + assert_older_backups_preserved +} + +@test "unclean source database prevents cleanup" { + export TEST_CLUSTER_STATE='in production' + + run_init + + [ "${status}" -ne 0 ] + [[ "${output}" == *"Cluster was not shutdown cleanly"* ]] + assert_older_backups_preserved +} + +@test "an unfinished upgrade prevents automatic cleanup" { + mkdir -p "${PGDATA}-new" + + run_init + + [ "${status}" -ne 0 ] + [[ "${output}" == *"Upgraded data directory already exists"* ]] + assert_older_backups_preserved +} + +@test "FORCE_CLEANUP clears an unfinished upgrade and allows cleanup after verification" { + export FORCE_CLEANUP=true + mkdir -p "${PGDATA}-new" + touch "${PGDATA}-new/leftover" + + run_init + + [ "${status}" -eq 0 ] + [ "$(cat "${PGDATA}/PG_VERSION")" = 16 ] + [ ! -e "${PGDATA}/leftover" ] + [ ! -e "${PGDATA}-new" ] + [ ! -e "${BACKUP_VOLUME}/13-15" ] + [ ! -e "${DATA_VOLUME}/13-15" ] + [ -s "${BACKUP_VOLUME}/15-16/backup.tar" ] +} + +@test "FORCE_CLEANUP preserves older backups when verification fails with space available" { + export FORCE_CLEANUP=true TEST_FAIL_VERIFICATION=true + mkdir -p "${PGDATA}-new" + + run_init + + [ "${status}" -ne 0 ] + [ ! -e "${PGDATA}-new" ] + assert_older_backups_preserved + [ -s "${BACKUP_VOLUME}/15-16/backup.tar" ] +} + +@test "FORCE_CLEANUP allows reclaiming obsolete backups to retry an upgrade" { + export FORCE_CLEANUP=true TEST_SPACE_MODE=reclaimable + mkdir -p "${PGDATA}-new" + + run_init + + [ "${status}" -eq 0 ] + [ "$(cat "${PGDATA}/PG_VERSION")" = 16 ] + [ ! -e "${PGDATA}-new" ] + [ ! -e "${BACKUP_VOLUME}/13-15" ] + [ ! -e "${DATA_VOLUME}/13-15" ] + [ -s "${BACKUP_VOLUME}/15-16/backup.tar" ] +} + +@test "available space preserves older backups until verification succeeds" { + export TEST_FAIL_VERIFICATION=true + + run_init + + [ "${status}" -ne 0 ] + assert_older_backups_preserved + [ -s "${BACKUP_VOLUME}/15-16/backup.tar" ] +} + +@test "space in the second location avoids deleting backups before verification" { + export TEST_SPACE_MODE=first-full TEST_FAIL_VERIFICATION=true + + run_init + + [ "${status}" -ne 0 ] + assert_older_backups_preserved + [ -s "${DATA_VOLUME}/15-16/backup.tar" ] +} + +@test "verified upgrade prunes earlier backups and preserves the current backup on restart" { + run_init + + [ "${status}" -eq 0 ] + [ "$(cat "${PGDATA}/PG_VERSION")" = 16 ] + [ ! -e "${BACKUP_VOLUME}/13-15" ] + [ ! -e "${DATA_VOLUME}/13-15" ] + [ -s "${BACKUP_VOLUME}/15-16/backup.tar" ] + + run_init + + [ "${status}" -eq 0 ] + [ -s "${BACKUP_VOLUME}/15-16/backup.tar" ] +} + +@test "space shortage reclaims earlier backups while preserving the current and newer pairs" { + export TEST_SPACE_MODE=reclaimable + make_upgrade_backup "${BACKUP_VOLUME}/15-16" + make_upgrade_backup "${BACKUP_VOLUME}/16-17" + cp "${BACKUP_VOLUME}/15-16/backup.tar" "${TEST_ROOT}/original-backup.tar" + + run_init + + [ "${status}" -eq 0 ] + [ "$(cat "${PGDATA}/PG_VERSION")" = 16 ] + [ ! -e "${BACKUP_VOLUME}/13-15" ] + [ -s "${BACKUP_VOLUME}/16-17/backup.tar" ] + [ "$(cksum < "${TEST_ROOT}/original-backup.tar")" = "$(cksum < "${BACKUP_VOLUME}/15-16/backup.tar")" ] +} + +@test "insufficient space after cleanup fails without replacing the source database" { + export TEST_SPACE_MODE=full + + run_init + + [ "${status}" -ne 0 ] + [[ "${output}" == *"Not enough disk space, upgrade is cancelled"* ]] + [ "$(cat "${PGDATA}/PG_VERSION")" = 15 ] + [ ! -e "${BACKUP_VOLUME}/15-16" ] +} + +@test "recovery flags suppress automatic cleanup when the upgrade succeeds" { + local flag + for flag in FORCE_NEW_BACKUP RESTORE_BACKUP; do + echo 15 > "${PGDATA}/PG_VERSION" + make_upgrade_backup "${BACKUP_VOLUME}/15-16" + export "${flag}=true" + + run_init + + [ "${status}" -eq 0 ] + assert_older_backups_preserved + unset "${flag}" + done +} + +@test "recovery flags suppress reclamation even with FORCE_CLEANUP set" { + export FORCE_CLEANUP=true TEST_SPACE_MODE=reclaimable + local flag + for flag in FORCE_NEW_BACKUP RESTORE_BACKUP; do + mkdir -p "${PGDATA}-new" + make_upgrade_backup "${BACKUP_VOLUME}/15-16" + export "${flag}=true" + + run_init + + [ "${status}" -ne 0 ] + [[ "${output}" == *"Not enough disk space, upgrade is cancelled"* ]] + [ ! -e "${PGDATA}-new" ] + assert_older_backups_preserved + unset "${flag}" + done +} + +@test "restoring with old binaries preserves every backup" { + make_upgrade_backup "${BACKUP_VOLUME}/15-16" + echo 16 > "${PGDATA}/PG_VERSION" + export RESTORE_BACKUP=true FORCE_OLD_BINARIES=true + + run_init + + [ "${status}" -eq 0 ] + [ "$(cat "${PGDATA}/PG_VERSION")" = 15 ] + assert_older_backups_preserved + [ -s "${BACKUP_VOLUME}/15-16/backup.tar" ] +} + +@test "failed upgrade preserves the verified current backup for recovery" { + export TEST_FAIL_UPGRADE=true + + run_init + + [ "${status}" -ne 0 ] + [ "$(cat "${PGDATA}/PG_VERSION")" = 15 ] + [ -s "${BACKUP_VOLUME}/15-16/backup.tar" ] +} diff --git a/image/rhel/Dockerfile b/image/rhel/Dockerfile index ecd99837e048e..770bf1dc49ad4 100644 --- a/image/rhel/Dockerfile +++ b/image/rhel/Dockerfile @@ -1,12 +1,16 @@ +ARG PG_VERSION=16 + FROM registry.access.redhat.com/ubi9:latest AS ubi-base FROM registry.access.redhat.com/ubi9/ubi-micro:latest AS ubi-micro-base FROM ubi-base AS downloads ARG DEBUG_BUILD=no +ARG PG_VERSION WORKDIR / COPY download.sh /download.sh +COPY signatures/RPM-GPG-KEY-CentOS-Official /tmp/ RUN /download.sh FROM ubi-base AS stackrox_data @@ -39,7 +43,35 @@ RUN rpm --import /tmp/RPM-GPG-KEY-CentOS-Official && \ dnf clean all --installroot=/out/ && \ rm -rf /out/var/cache/dnf /out/var/cache/yum -FROM ubi-micro-base +FROM ubi-micro-base AS runtime-base + +ARG PG_VERSION + +COPY --from=package_installer /out/ / + +# Execute the clients in the final runtime to check their version and libraries. +RUN set -eu; \ + for client in pg_dump pg_restore; do \ + version="$("$client" --version)"; \ + echo "$version"; \ + case "$version" in \ + "$client (PostgreSQL) ${PG_VERSION}."*) ;; \ + *) echo "Expected PostgreSQL ${PG_VERSION} client: $client" >&2; exit 1 ;; \ + esac; \ + done + +FROM ubi-base AS cli-tarballs + +RUN dnf install -y pigz +COPY bin/roxctl* /tmp/roxctl/ +RUN cd /tmp/roxctl && \ + shopt -s nullglob && \ + for f in roxctl-*; do \ + [[ -f "$f" && -x "$f" ]] || continue; \ + tar -I pigz -cvf "${f%.exe}.tar.gz" "$f"; \ + done + +FROM runtime-base ARG LABEL_VERSION ARG LABEL_RELEASE @@ -62,8 +94,6 @@ ENV PATH="/stackrox:$PATH" \ ROX_IMAGE_FLAVOR=${ROX_IMAGE_FLAVOR} \ ROX_PRODUCT_BRANDING=${ROX_PRODUCT_BRANDING} -COPY --from=package_installer /out/ / - COPY static-bin /stackrox/ COPY --from=downloads /output/go/ /go/ @@ -94,9 +124,8 @@ COPY bin/admission-control /stackrox/bin/admission-control COPY bin/config-controller /stackrox/bin/config-controller COPY bin/central-worker /stackrox/bin/central-worker COPY bin/roxagent /stackrox/bin/roxagent -COPY bin/roxctl* /assets/downloads/cli/ - -RUN ln -s /assets/downloads/cli/roxctl-linux-${TARGET_ARCH} /stackrox/roxctl +COPY --from=cli-tarballs /tmp/roxctl/roxctl-*.tar.gz /assets/downloads/cli/ +COPY --from=cli-tarballs /tmp/roxctl/roxctl-linux-${TARGET_ARCH} /stackrox/roxctl EXPOSE 8443 diff --git a/image/rhel/README.md b/image/rhel/README.md index c3283e8a714f3..818126d99469d 100644 --- a/image/rhel/README.md +++ b/image/rhel/README.md @@ -3,3 +3,15 @@ The RedHat based main image is currently used for the RedHat marketplace as well as for DoD customers. This image is built in opinionated way based on the DoD Centralized Artifacts Repository (DCAR) requirements outlined [here](https://dccscr.dsop.io/dsop/dccscr/tree/master/contributor-onboarding) + +## PostgreSQL clients + +`Dockerfile` downloads PostgreSQL client RPMs from PGDG for amd64, arm64, and +ppc64le. For s390x, `download.sh` adds the CentOS Stream 9 AppStream repository +to its download commands because PGDG does not publish s390x packages and UBI's +repositories do not provide the PostgreSQL 16 module. The download and runtime +stages use UBI on every architecture. + +`PG_VERSION` selects the client major version. The `runtime-base` stage runs +`pg_dump` and `pg_restore` and checks their versions in the runtime filesystem, +so missing libraries or an older client fail the image build. diff --git a/image/rhel/download.sh b/image/rhel/download.sh index 82570540b1b49..cbddcdaabef82 100755 --- a/image/rhel/download.sh +++ b/image/rhel/download.sh @@ -3,6 +3,7 @@ set -euo pipefail arch=$(uname -m) +postgres_major="${PG_VERSION:-16}" goarch="$arch" dnf_list_args=() if [[ "$arch" == "x86_64" ]]; then @@ -35,15 +36,17 @@ fi mkdir -p "$output_dir/rpms" if [[ "$arch" == "s390x" ]]; then - dnf install -y --downloadonly --downloaddir=/tmp postgresql postgresql-private-libs + rpm --import /tmp/RPM-GPG-KEY-CentOS-Official + centos_repo="--repofrompath=centos-appstream,https://mirror.stream.centos.org/9-stream/AppStream/${arch}/os/" + dnf "$centos_repo" module enable -y "postgresql:${postgres_major}" + dnf "$centos_repo" install -y --downloadonly --downloaddir=/tmp postgresql postgresql-private-libs mv /tmp/postgresql-private-libs-*.rpm "${output_dir}/rpms/postgres-libs.rpm" mv /tmp/postgresql-*.rpm "${output_dir}/rpms/postgres.rpm" else - postgres_major=15 pg_rhel_major=9 postgres_repo_url="https://download.postgresql.org/pub/repos/yum/reporpms/EL-${pg_rhel_major}-${arch}/pgdg-redhat-repo-latest.noarch.rpm" dnf install --disablerepo='*' -y "${postgres_repo_url}" - postgres_minor=$(dnf list ${dnf_list_args[@]+"${dnf_list_args[@]}"} --disablerepo='*' ""--enablerepo=pgdg${postgres_major} -y postgresql${postgres_major}-server."$arch" | tail -n 1 | awk '{print $2}') + postgres_minor=$(dnf list ${dnf_list_args[@]+"${dnf_list_args[@]}"} --disablerepo='*' "--enablerepo=pgdg${postgres_major}" -y "postgresql${postgres_major}-server.${arch}" | tail -n 1 | awk '{print $2}') postgres_minor="$postgres_minor.$arch" postgres_url="https://download.postgresql.org/pub/repos/yum/${postgres_major}/redhat/rhel-${pg_rhel_major}-${arch}" diff --git a/image/rhel/konflux.Dockerfile b/image/rhel/konflux.Dockerfile index 50beb06e86deb..c06e1e6500b4d 100644 --- a/image/rhel/konflux.Dockerfile +++ b/image/rhel/konflux.Dockerfile @@ -1,4 +1,4 @@ -ARG PG_VERSION=15 +ARG PG_VERSION=16 FROM brew.registry.redhat.io/rh-osbs/openshift-golang-builder:rhel_9_golang_1.26@sha256:e74b03198cccc24c24a27071ad4d6c2edcfe0bb10c6de99c609ce6e3c06d6d04 AS go-builder @@ -43,8 +43,13 @@ RUN cd /go/src/github.com/stackrox/rox/app/image/rhel/bin && \ tar -I pigz -cvf "${f%.exe}.tar.gz" "$f"; \ done +RUN arch=$(uname -m) ; \ + case $arch in x86_64) arch=amd64 ;; aarch64) arch=arm64 ;; esac ; \ + cp /go/src/github.com/stackrox/rox/app/image/rhel/bin/roxctl-linux-${arch} \ + /go/src/github.com/stackrox/rox/app/image/rhel/bin/roxctl -FROM registry.access.redhat.com/ubi9/nodejs-22@sha256:a38a749f3a37a1c033932b4c13f3052f4958aa0eb7dbb0761cb3b5536ffe6878 as ui-builder + +FROM registry.access.redhat.com/ubi9/nodejs-22@sha256:ec6d5fae468462129f094c6c463207bd950c9e2b0023f6c0fd1ae1cbdc5abd3e as ui-builder WORKDIR /go/src/github.com/stackrox/rox/app @@ -66,9 +71,9 @@ ENV UI_PKG_INSTALL_EXTRA_ARGS="--ignore-scripts" RUN make -C ui build -FROM registry.access.redhat.com/ubi9/ubi-micro:latest@sha256:f332c99eb8f798a8486821c91937f10ad64ee83d7e739303be2df051040918f6 AS ubi-micro-base +FROM registry.access.redhat.com/ubi9/ubi-micro:latest@sha256:5be877a2a280ae36eb9ab80ca4efb28bbf77c57abbba38137cdc37a03b8465e6 AS ubi-micro-base -FROM registry.access.redhat.com/ubi9/ubi:latest@sha256:25a147defd01e19674714f55d17538c8dbe55d8c305fa157ecc3f9c8977b05b6 AS package_installer +FROM registry.access.redhat.com/ubi9/ubi:latest@sha256:16e9e43d99e181463513cc84a514859b1abb9460f1c4d9e208da4b4e51cd5cc3 AS package_installer ARG PG_VERSION @@ -104,16 +109,15 @@ COPY --from=ui-builder /go/src/github.com/stackrox/rox/app/ui/build /ui/ COPY --from=go-builder /go/src/github.com/stackrox/rox/app/image/rhel/bin/migrator /stackrox/bin/ COPY --from=go-builder /go/src/github.com/stackrox/rox/app/image/rhel/bin/central /stackrox/ COPY --from=go-builder /go/src/github.com/stackrox/rox/app/image/rhel/bin/compliance /stackrox/bin/ -COPY --from=go-builder /go/src/github.com/stackrox/rox/app/image/rhel/bin/roxctl* /assets/downloads/cli/ +COPY --from=go-builder /go/src/github.com/stackrox/rox/app/image/rhel/bin/roxctl-*.tar.gz /assets/downloads/cli/ +COPY --from=go-builder /go/src/github.com/stackrox/rox/app/image/rhel/bin/roxctl /stackrox/roxctl COPY --from=go-builder /go/src/github.com/stackrox/rox/app/image/rhel/bin/kubernetes-sensor /stackrox/bin/ COPY --from=go-builder /go/src/github.com/stackrox/rox/app/image/rhel/bin/sensor-upgrader /stackrox/bin/ COPY --from=go-builder /go/src/github.com/stackrox/rox/app/image/rhel/bin/admission-control /stackrox/bin/ COPY --from=go-builder /go/src/github.com/stackrox/rox/app/image/rhel/bin/config-controller /stackrox/bin/ COPY --from=go-builder /go/src/github.com/stackrox/rox/app/image/rhel/bin/roxagent /stackrox/bin/ +COPY --from=go-builder /go/src/github.com/stackrox/rox/app/image/rhel/bin/central-worker /stackrox/bin/ COPY --from=go-builder /go/src/github.com/stackrox/rox/app/image/rhel/static-bin/* /stackrox/ -RUN GOARCH=$(uname -m) ; \ - case $GOARCH in x86_64) GOARCH=amd64 ;; aarch64) GOARCH=arm64 ;; esac ; \ - ln -s /assets/downloads/cli/roxctl-linux-$GOARCH /stackrox/roxctl ARG BUILD_TAG diff --git a/image/roxctl/konflux.Dockerfile b/image/roxctl/konflux.Dockerfile index ddccfec721b47..c52eb5d654c53 100644 --- a/image/roxctl/konflux.Dockerfile +++ b/image/roxctl/konflux.Dockerfile @@ -25,9 +25,9 @@ ENV GOEXPERIMENT=strictfipsruntime RUN RACE=0 CGO_ENABLED=1 GOOS=linux GOARCH=$(go env GOARCH) scripts/go-build.sh ./roxctl && \ cp bin/linux_$(go env GOARCH)/roxctl image/bin/roxctl -FROM registry.access.redhat.com/ubi9/ubi-micro:latest@sha256:f332c99eb8f798a8486821c91937f10ad64ee83d7e739303be2df051040918f6 AS ubi-micro-base +FROM registry.access.redhat.com/ubi9/ubi-micro:latest@sha256:5be877a2a280ae36eb9ab80ca4efb28bbf77c57abbba38137cdc37a03b8465e6 AS ubi-micro-base -FROM registry.access.redhat.com/ubi9/ubi:latest@sha256:25a147defd01e19674714f55d17538c8dbe55d8c305fa157ecc3f9c8977b05b6 AS package_installer +FROM registry.access.redhat.com/ubi9/ubi:latest@sha256:16e9e43d99e181463513cc84a514859b1abb9460f1c4d9e208da4b4e51cd5cc3 AS package_installer # Copy ubi-micro base to /out/ to preserve its rpmdb COPY --from=ubi-micro-base / /out/ @@ -37,7 +37,7 @@ COPY --from=ubi-micro-base / /out/ # prefetched by Hermeto/Cachi2, instead of installroot's default UBI repos. RUN dnf install -y \ --installroot=/out/ \ - --releasever=8 \ + --releasever=9 \ --setopt=install_weak_deps=False \ --setopt=reposdir=/etc/yum.repos.d \ --nodocs \ diff --git a/image/templates/common/setup.sh b/image/templates/common/setup.sh index 4621967793d60..f0db17b406c7f 100644 --- a/image/templates/common/setup.sh +++ b/image/templates/common/setup.sh @@ -39,22 +39,3 @@ metadata: type: kubernetes.io/dockerconfigjson EOF fi - -{{ if ne .K8sConfig.ScannerSecretName "stackrox" }} -if ! ${KUBE_COMMAND} get secret/{{.K8sConfig.ScannerSecretName}} -n "$NAMESPACE" > /dev/null; then - registry_auth="$("${DIR}/docker-auth.sh" -m k8s "{{.K8sConfig.ScannerRegistry}}")" - [[ -n "$registry_auth" ]] || { echo >&2 "Unable to get registry auth info." ; exit 1 ; } - ${KUBE_COMMAND} create --namespace "$NAMESPACE" -f - < 0.8 + for: 1h + labels: + severity: warning + annotations: + summary: "Scanner V4 DB persistent volume is filling up" + description: "The Scanner V4 DB PVC {{ $scannerV4DBClaimName }} in namespace {{ ._rox._namespace }} is {{ "{{" }} $value | humanizePercentage {{ "}}" }} full (warning threshold 80%)." + - alert: ScannerV4DBPersistentVolumeFillingUp + expr: | + kubelet_volume_stats_used_bytes{namespace="{{ ._rox._namespace }}", persistentvolumeclaim="{{ $scannerV4DBClaimName }}"} + / kubelet_volume_stats_capacity_bytes{namespace="{{ ._rox._namespace }}", persistentvolumeclaim="{{ $scannerV4DBClaimName }}"} + > 0.9 + for: 5m + labels: + severity: critical + annotations: + summary: "Scanner V4 DB persistent volume is almost full" + description: "The Scanner V4 DB PVC {{ $scannerV4DBClaimName }} in namespace {{ ._rox._namespace }} is {{ "{{" }} $value | humanizePercentage {{ "}}" }} full (critical threshold 90%)." +{{- end }} +{{- end }} {{- end }} diff --git a/image/templates/helm/shared/templates/_metadata.tpl b/image/templates/helm/shared/templates/_metadata.tpl index dc74c28239993..f77112634b9a2 100644 --- a/image/templates/helm/shared/templates/_metadata.tpl +++ b/image/templates/helm/shared/templates/_metadata.tpl @@ -229,23 +229,66 @@ {{ end }} {{ end }} -{{/* Add namespace specific prefixes for global resources to avoid resource name clashes for multi-namespace deployments. */}} +{{/* + Add namespace specific prefixes for global resources to avoid resource name clashes for + multi-namespace deployments. + + The separator between the "stackrox" base and the resource-specific suffix is + inferred from $name ("-" for "stackrox-foo", ":" for "stackrox:foo"). A name that is + exactly "stackrox" (i.e. just the base name, no suffix) is completely replaced with globalPrefix. + */}} {{- define "srox.globalResourceName" -}} {{- $ := index . 0 -}} {{- $name := index . 1 -}} +{{- $separator := "" -}} {{- if eq $.Release.Namespace "stackrox" -}} {{- /* Standard namespace, use resource name as is. */ -}} {{- $name -}} {{- else -}} - {{- /* Add global prefix to resource name. */ -}} + {{- /* Infer the separator from $name. */ -}} {{- if hasPrefix "stackrox-" $name -}} - {{- printf "%s-%s" $._rox.globalPrefix (trimPrefix "stackrox-" $name) -}} + {{- $separator = "-" -}} {{- else if hasPrefix "stackrox:" $name -}} - {{- printf "%s:%s" $._rox.globalPrefix (trimPrefix "stackrox:" $name) -}} + {{- $separator = ":" -}} + {{- else if eq "stackrox" $name -}} + {{/* Keep $separator empty. */}} {{- else -}} {{- include "srox.fail" (printf "Unknown naming convention for global resource %q." $name) -}} {{- end -}} + {{- /* Add global prefix to resource name. */ -}} + {{- $suffix := trimPrefix (printf "stackrox%s" $separator) $name -}} + {{- if not $suffix -}} + {{- /* Bare "stackrox" base name: the global prefix already carries the namespace. */ -}} + {{- printf "%s" $._rox.globalPrefix -}} + {{- else -}} + {{- printf "%s%s%s" $._rox.globalPrefix $separator $suffix -}} + {{- end -}} +{{- end -}} +{{- end -}} + +{{/* + srox.optionalGlobalResourceName $ $name + + Opt-in wrapper around srox.globalResourceName: it applies namespace-prefixing to a + global (cluster-scoped) resource name only when ._rox.namespacePrefixGlobalResources + is set; otherwise the static base $name is returned verbatim. The arguments are + forwarded unchanged to srox.globalResourceName. + + This keeps namespace-prefixing of global resources opt-in: names default to stable, + static values (production safety) and prefixing can be enabled -- e.g. for tests that + deploy multiple secured clusters into different namespaces of the same cluster -- to + avoid cluster-scoped resource name clashes. Individual global resources opt in by + calling this helper instead of hard-coding a static name. This is deliberately generic + so further global resources can adopt it as the need arises. + */}} +{{- define "srox.optionalGlobalResourceName" -}} +{{- $ := index . 0 -}} +{{- $name := index . 1 -}} +{{- if $._rox.namespacePrefixGlobalResources -}} + {{- include "srox.globalResourceName" . -}} +{{- else -}} + {{- $name -}} {{- end -}} {{- end -}} diff --git a/image/templates/helm/stackrox-central/internal/config.stackrox.io_securitypolicies.yaml b/image/templates/helm/stackrox-central/internal/config.stackrox.io_securitypolicies.yaml index 6329c0e2b6373..d3a1254eabdb2 100644 --- a/image/templates/helm/stackrox-central/internal/config.stackrox.io_securitypolicies.yaml +++ b/image/templates/helm/stackrox-central/internal/config.stackrox.io_securitypolicies.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.21.0 + controller-gen.kubebuilder.io/version: v0.22.0 name: securitypolicies.config.stackrox.io spec: group: config.stackrox.io @@ -82,7 +82,11 @@ spec: evaluates. properties: skipContainerTypes: + description: SkipContainerTypes lists container kinds to skip + during evaluation. items: + description: ContainerType lists container kinds a policy may + skip during evaluation. enum: - REGULAR - INIT @@ -138,6 +142,23 @@ spec: type: object type: object type: object + excludeByKind: + description: ExcludeByKind excludes all workloads of the selected + Kubernetes kinds. + properties: + kinds: + description: Kinds is the list of Kubernetes workload kinds + to exclude. + items: + enum: + - CRON_JOB + - JOB + type: string + minItems: 1 + type: array + required: + - kinds + type: object expiration: format: date-time type: string @@ -149,6 +170,11 @@ spec: name: type: string type: object + x-kubernetes-validations: + - message: at most one of the fields in [deployment excludeByKind] + may be set + rule: (has(self.deployment)?1:0)+(has(self.excludeByKind)?1:0) + <= 1 type: array isDefault: description: IsDefault is unused diff --git a/image/templates/helm/stackrox-central/templates/00-stackrox-application.yaml b/image/templates/helm/stackrox-central/templates/00-stackrox-application.yaml deleted file mode 100644 index 3be046fa21d0c..0000000000000 --- a/image/templates/helm/stackrox-central/templates/00-stackrox-application.yaml +++ /dev/null @@ -1,122 +0,0 @@ -{{- include "srox.init" . -}} - -{{- if has "app.k8s.io/v1beta1/Application" ._rox._apiServer.apiResources -}} -apiVersion: app.k8s.io/v1beta1 -kind: Application -metadata: - name: stackrox - namespace: {{ .Release.Namespace }} - labels: - {{- include "srox.labels" (list . "application" "stackrox") | nindent 4 }} - annotations: - {{- include "srox.annotations" (list . "application" "stackrox") | nindent 4 }} - {{ if eq ._rox.image.registry "quay.io/stackrox-io" }} - kubernetes-engine.cloud.google.com/icon: "data:image/png;base64,{{ .Files.Get "assets/StackRox_icon.png" | b64enc }}" - {{ else }} - kubernetes-engine.cloud.google.com/icon: "data:image/png;base64,{{ .Files.Get "assets/Red_Hat-Hat_icon.png" | b64enc }}" - {{ end }} -spec: - descriptor: - type: StackRox - version: {{ .Chart.AppVersion | quote }} - description: |- - StackRox Kubernetes Security Platform - - Version {{ .Chart.AppVersion }} - - ## Thank you for installing StackRox! - -
- - #### Support - - [Email support@stackrox.com](mailto:support@stackrox.com?cc=sales@stackrox.com&Subject=StackRox%20Support%20Question&Body=Dear%20StackRox%20support,) - - ## Connecting to StackRox - -
- - #### Directly using a Load Balancer - - When deploying StackRox with the `Load Balancer` network configuration, the service can be accessed directly. - - $CONNECT - - #### Tunneling via Port Forward - - When deploying StackRox with the `Node Port` or `None` network configuration, the service must be accessed using a port forward tunnel. - - - Step 1 - Start the port forward tunnel to the StackRox Central service. - - ``` - $ kubectl -n stackrox port-forward svc/central 8443:443 - ``` - - - Step 2 - In a browser, [visit https://localhost:8443](https://localhost:8443) to access StackRox. - - keywords: - - "stackrox" - - "kube" - - "security" - maintainers: - - name: StackRox, Inc. - url: https://stackrox.com - owners: - - name: StackRox, Inc. - url: https://stackrox.com - links: - - description: StackRox Help Documentation - url: "https://help.stackrox.com" - - info: - - name: StackRox namespace - value: stackrox - - name: StackRox admin username - value: "admin" - - selector: - matchLabels: - app.kubernetes.io/name: stackrox - - componentKinds: - - group: '' - kind: ConfigMap - - group: '' - kind: Secret - - group: '' - kind: PersistentVolumeClaim - - group: '' - kind: PersistentVolume - - group: '' - kind: Service - - group: '' - kind: ServiceAccount - - group: rbac.authorization.k8s.io - kind: ClusterRole - - group: rbac.authorization.k8s.io - kind: ClusterRoleBinding - - group: apps - kind: Deployment -{{- if ._rox.network.enableNetworkPolicies }} - - group: networking.k8s.io - kind: NetworkPolicy -{{- end }} - - group: rbac.authorization.k8s.io - kind: Role - - group: rbac.authorization.k8s.io - kind: RoleBinding - - group: route.openshift.io - kind: Route - - group: security.openshift.io - kind: SecurityContextConstraints - - group: admissionregistration.k8s.io - kind: ValidatingWebhookConfiguration - - group: autoscaling - kind: HorizontalPodAutoscaler - - group: storage.k8s.io - kind: StorageClass -{{- if ._rox.system.enablePodSecurityPolicies }} - - group: policy - kind: PodSecurityPolicy -{{- end }} -{{- end }} diff --git a/image/templates/helm/stackrox-central/templates/99-openshift-monitoring.yaml b/image/templates/helm/stackrox-central/templates/99-openshift-monitoring.yaml index a2a6f28ff73aa..de5e7d80d88d8 100644 --- a/image/templates/helm/stackrox-central/templates/99-openshift-monitoring.yaml +++ b/image/templates/helm/stackrox-central/templates/99-openshift-monitoring.yaml @@ -77,6 +77,42 @@ spec: matchNames: - "{{ .Release.Namespace }}" +{{- if and ._rox.monitoring.openshift.custom ._rox.monitoring.openshift.custom.enabled (not ._rox.env.managedServices) }} +--- + +{{- /* +The ServiceMonitor is placed into the openshift-monitoring namespace to comply with the +OpenShift monitoring namespace label requirements. This is an exception to the rule +that leaking resources into system namespaces should be avoided. +*/}} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: "central-ocp-api-monitor-{{ .Release.Namespace }}" + namespace: openshift-monitoring + labels: + {{- include "srox.labels" (list . "servicemonitor" (print "central-ocp-api-monitor-" .Release.Namespace)) | nindent 4 }} + annotations: + {{- include "srox.annotations" (list . "servicemonitor" (print "central-ocp-api-monitor-" .Release.Namespace)) | nindent 4 }} +spec: + endpoints: + - interval: 30s + path: /metrics + port: https + scheme: https + tlsConfig: + caFile: /etc/prometheus/configmaps/serving-certs-ca-bundle/service-ca.crt + certFile: /etc/prometheus/secrets/metrics-client-certs/tls.crt + keyFile: /etc/prometheus/secrets/metrics-client-certs/tls.key + serverName: "central-ocp.{{ .Release.Namespace }}.svc" + selector: + matchLabels: + stackrox.io/ocp-api: "true" + namespaceSelector: + matchNames: + - "{{ .Release.Namespace }}" + +{{- end }} --- {{- /* @@ -145,5 +181,43 @@ spec: rox_central_secured_vcpus{branding="RHACS"} ) record: rhacs:telemetry:rox_central_secured_vcpus +{{- /* +Central DB PVC space alerting is evaluated by the platform Prometheus in +openshift-monitoring, which scrapes the relevant metrics in every namespace. +The rule is emitted only when central-db is PVC-backed (not for external, +hostPath, or emptyDir persistence). +*/}} +{{- $centralDBClaimName := "" -}} +{{- with ._rox.central.db.persistence._volumeCfg -}} +{{- with .persistentVolumeClaim -}} +{{- $centralDBClaimName = .claimName -}} +{{- end -}} +{{- end -}} +{{- if $centralDBClaimName }} + - name: rhacs.central-db + rules: + - alert: CentralDBPersistentVolumeFillingUp + expr: | + kubelet_volume_stats_used_bytes{namespace="{{ .Release.Namespace }}", persistentvolumeclaim="{{ $centralDBClaimName }}"} + / kubelet_volume_stats_capacity_bytes{namespace="{{ .Release.Namespace }}", persistentvolumeclaim="{{ $centralDBClaimName }}"} + > 0.8 + for: 1h + labels: + severity: warning + annotations: + summary: "Central DB persistent volume is filling up" + description: "The Central DB PVC {{ $centralDBClaimName }} in namespace {{ .Release.Namespace }} is {{ "{{" }} $value | humanizePercentage {{ "}}" }} full (warning threshold 80%)." + - alert: CentralDBPersistentVolumeFillingUp + expr: | + kubelet_volume_stats_used_bytes{namespace="{{ .Release.Namespace }}", persistentvolumeclaim="{{ $centralDBClaimName }}"} + / kubelet_volume_stats_capacity_bytes{namespace="{{ .Release.Namespace }}", persistentvolumeclaim="{{ $centralDBClaimName }}"} + > 0.9 + for: 5m + labels: + severity: critical + annotations: + summary: "Central DB persistent volume is almost full" + description: "The Central DB PVC {{ $centralDBClaimName }} in namespace {{ .Release.Namespace }} is {{ "{{" }} $value | humanizePercentage {{ "}}" }} full (critical threshold 90%)." +{{- end }} {{- end -}} diff --git a/image/templates/helm/stackrox-central/values-public.yaml.example.htpl b/image/templates/helm/stackrox-central/values-public.yaml.example.htpl index c4be9e07fe0f4..2fe94b736f17c 100644 --- a/image/templates/helm/stackrox-central/values-public.yaml.example.htpl +++ b/image/templates/helm/stackrox-central/values-public.yaml.example.htpl @@ -614,3 +614,6 @@ # # Enables integration with OpenShift platform monitoring. # openshift: # enabled: true +# # Enables custom metrics integration. +# custom: +# enabled: false diff --git a/image/templates/helm/stackrox-central/values.yaml.htpl b/image/templates/helm/stackrox-central/values.yaml.htpl index 10325b1af358a..5e67c78b7f884 100644 --- a/image/templates/helm/stackrox-central/values.yaml.htpl +++ b/image/templates/helm/stackrox-central/values.yaml.htpl @@ -495,3 +495,6 @@ central: # # Enables integration with OpenShift platform monitoring. # openshift: # enabled: true +# # Enables custom metrics integration. +# custom: +# enabled: false diff --git a/image/templates/helm/stackrox-secured-cluster/internal/config-shape.yaml b/image/templates/helm/stackrox-secured-cluster/internal/config-shape.yaml index c0c84066a2003..c19237777a1ce 100644 --- a/image/templates/helm/stackrox-secured-cluster/internal/config-shape.yaml +++ b/image/templates/helm/stackrox-secured-cluster/internal/config-shape.yaml @@ -182,6 +182,11 @@ customize: other: {} # dict allowNonstandardNamespace: null # bool allowNonstandardReleaseName: null # bool +# Undocumented, test-only: when true, global (cluster-scoped) resources that opt in via +# srox.optionalGlobalResourceName get namespace-prefixed names to avoid clashes when +# multiple secured clusters are deployed into different namespaces of one cluster. +# Defaults to false so production keeps stable, static names. +namespacePrefixGlobalResources: null # bool enableOpenShiftMonitoring: null # bool monitoring: openshift: diff --git a/image/templates/helm/stackrox-secured-cluster/internal/defaults/30-base-config.yaml.htpl b/image/templates/helm/stackrox-secured-cluster/internal/defaults/30-base-config.yaml.htpl index 02280536c4b4f..81335de9dd8cf 100644 --- a/image/templates/helm/stackrox-secured-cluster/internal/defaults/30-base-config.yaml.htpl +++ b/image/templates/helm/stackrox-secured-cluster/internal/defaults/30-base-config.yaml.htpl @@ -9,6 +9,10 @@ createSecrets: true exposeMonitoring: false +# Undocumented, test-only. Keep global resource names static by default for production +# safety; see config-shape.yaml and srox.optionalGlobalResourceName. +namespacePrefixGlobalResources: false + helmManaged: [< not .KubectlOutput >] [< if .Operator >] diff --git a/image/templates/helm/stackrox-secured-cluster/templates/admission-controller.yaml b/image/templates/helm/stackrox-secured-cluster/templates/admission-controller.yaml index 0f9fba8ea14ad..5863e9403d24f 100644 --- a/image/templates/helm/stackrox-secured-cluster/templates/admission-controller.yaml +++ b/image/templates/helm/stackrox-secured-cluster/templates/admission-controller.yaml @@ -218,7 +218,7 @@ spec: apiVersion: admissionregistration.k8s.io/v1 kind: ValidatingWebhookConfiguration metadata: - name: stackrox + name: {{ include "srox.optionalGlobalResourceName" (list . "stackrox") }} labels: {{- include "srox.labels" (list . "validatingwebhookconfiguration" "stackrox") | nindent 4 }} annotations: diff --git a/migrator/migrations/m_211_to_m_212_admission_control_config/migration_test.go b/migrator/migrations/m_211_to_m_212_admission_control_config/migration_test.go index 1f3d1e59d47de..7bfbd94cdfe51 100644 --- a/migrator/migrations/m_211_to_m_212_admission_control_config/migration_test.go +++ b/migrator/migrations/m_211_to_m_212_admission_control_config/migration_test.go @@ -63,17 +63,17 @@ func (s *migrationTestSuite) TestMigration() { search.NewQueryBuilder().AddExactMatches(search.Cluster, clusters[0].GetName()).ProtoQuery()) assert.NoError(s.T(), err) - assert.EqualValues(s.T(), result[0].HelmConfig.GetDynamicConfig().GetAdmissionControllerConfig().GetScanInline(), false) - assert.EqualValues(s.T(), result[0].HelmConfig.GetDynamicConfig().GetAdmissionControllerConfig().GetEnabled(), true) - assert.EqualValues(s.T(), result[0].HelmConfig.GetDynamicConfig().GetAdmissionControllerConfig().GetEnforceOnUpdates(), false) + assert.EqualValues(s.T(), result[0].GetHelmConfig().GetDynamicConfig().GetAdmissionControllerConfig().GetScanInline(), false) + assert.EqualValues(s.T(), result[0].GetHelmConfig().GetDynamicConfig().GetAdmissionControllerConfig().GetEnabled(), true) + assert.EqualValues(s.T(), result[0].GetHelmConfig().GetDynamicConfig().GetAdmissionControllerConfig().GetEnforceOnUpdates(), false) result, err = store.GetByQuery(s.ctx, search.NewQueryBuilder().AddExactMatches(search.Cluster, clusters[1].GetName()).ProtoQuery()) assert.NoError(s.T(), err) - assert.EqualValues(s.T(), result[0].DynamicConfig.GetAdmissionControllerConfig().GetScanInline(), true) - assert.EqualValues(s.T(), result[0].DynamicConfig.GetAdmissionControllerConfig().GetEnabled(), true) - assert.EqualValues(s.T(), result[0].DynamicConfig.GetAdmissionControllerConfig().GetEnforceOnUpdates(), true) + assert.EqualValues(s.T(), result[0].GetDynamicConfig().GetAdmissionControllerConfig().GetScanInline(), true) + assert.EqualValues(s.T(), result[0].GetDynamicConfig().GetAdmissionControllerConfig().GetEnabled(), true) + assert.EqualValues(s.T(), result[0].GetDynamicConfig().GetAdmissionControllerConfig().GetEnforceOnUpdates(), true) } diff --git a/migrator/migrations/policymigrationhelper/postgres_policy_migrator_test.go b/migrator/migrations/policymigrationhelper/postgres_policy_migrator_test.go index c6b0cf1c6bd6f..32f545dfaf0e7 100644 --- a/migrator/migrations/policymigrationhelper/postgres_policy_migrator_test.go +++ b/migrator/migrations/policymigrationhelper/postgres_policy_migrator_test.go @@ -177,12 +177,12 @@ func (s *postgresPolicyMigratorTestSuite) TestExclusionAreAddedAndRemovedAsNeces // Add a bunch of exclusions into the DB policy.Exclusions = []*storage.Exclusion{ - {Name: "exclusion0", Deployment: &storage.Exclusion_Deployment{Scope: &storage.Scope{Namespace: "namespace-0"}}}, - {Name: "exclusion1", Deployment: &storage.Exclusion_Deployment{Scope: &storage.Scope{Namespace: "namespace 1"}}}, - {Name: "exclusion0", Deployment: &storage.Exclusion_Deployment{Scope: &storage.Scope{Namespace: "namespace-0"}}}, - {Name: "exclusion2", Deployment: &storage.Exclusion_Deployment{Scope: &storage.Scope{Namespace: "namespace-2"}}}, - {Name: "exclusion3", Deployment: &storage.Exclusion_Deployment{Scope: &storage.Scope{Namespace: "namespace-3"}}}, - {Name: "exclusion4", Deployment: &storage.Exclusion_Deployment{Scope: &storage.Scope{Namespace: "namespace-4"}}}, + {Name: "exclusion0", Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{Scope: &storage.Scope{Namespace: "namespace-0"}}}}, + {Name: "exclusion1", Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{Scope: &storage.Scope{Namespace: "namespace 1"}}}}, + {Name: "exclusion0", Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{Scope: &storage.Scope{Namespace: "namespace-0"}}}}, + {Name: "exclusion2", Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{Scope: &storage.Scope{Namespace: "namespace-2"}}}}, + {Name: "exclusion3", Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{Scope: &storage.Scope{Namespace: "namespace-3"}}}}, + {Name: "exclusion4", Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{Scope: &storage.Scope{Namespace: "namespace-4"}}}}, } s.NoError(s.store.Upsert(s.ctx, policy)) @@ -196,14 +196,14 @@ func (s *postgresPolicyMigratorTestSuite) TestExclusionAreAddedAndRemovedAsNeces FieldsToCompare: []FieldComparator{ExclusionComparator}, ToChange: PolicyUpdates{ ExclusionsToAdd: []*storage.Exclusion{ - {Name: "exclusion1-changed", Deployment: &storage.Exclusion_Deployment{Scope: &storage.Scope{Namespace: "namespace-1"}}}, - {Name: "NEW exclusion", Deployment: &storage.Exclusion_Deployment{Scope: &storage.Scope{Namespace: "namespace-NEW"}}}, - {Name: "NEW exclusion2", Deployment: &storage.Exclusion_Deployment{Scope: &storage.Scope{Namespace: "namespace-NEW2"}}}, + {Name: "exclusion1-changed", Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{Scope: &storage.Scope{Namespace: "namespace-1"}}}}, + {Name: "NEW exclusion", Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{Scope: &storage.Scope{Namespace: "namespace-NEW"}}}}, + {Name: "NEW exclusion2", Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{Scope: &storage.Scope{Namespace: "namespace-NEW2"}}}}, }, ExclusionsToRemove: []*storage.Exclusion{ - {Name: "exclusion1", Deployment: &storage.Exclusion_Deployment{Scope: &storage.Scope{Namespace: "namespace 1"}}}, - {Name: "exclusion4", Deployment: &storage.Exclusion_Deployment{Scope: &storage.Scope{Namespace: "namespace-4"}}}, - {Name: "exclusion-NaN", Deployment: &storage.Exclusion_Deployment{Scope: &storage.Scope{Namespace: "namespace-NaN"}}}, // this exclusion doesn't exist so it shouldn't get removed + {Name: "exclusion1", Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{Scope: &storage.Scope{Namespace: "namespace 1"}}}}, + {Name: "exclusion4", Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{Scope: &storage.Scope{Namespace: "namespace-4"}}}}, + {Name: "exclusion-NaN", Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{Scope: &storage.Scope{Namespace: "namespace-NaN"}}}}, // this exclusion doesn't exist so it shouldn't get removed }, }, }, @@ -221,13 +221,13 @@ func (s *postgresPolicyMigratorTestSuite) TestExclusionAreAddedAndRemovedAsNeces // Policy exclusions should be updated policy.Exclusions = []*storage.Exclusion{ - {Name: "exclusion0", Deployment: &storage.Exclusion_Deployment{Scope: &storage.Scope{Namespace: "namespace-0"}}}, - {Name: "exclusion0", Deployment: &storage.Exclusion_Deployment{Scope: &storage.Scope{Namespace: "namespace-0"}}}, - {Name: "exclusion2", Deployment: &storage.Exclusion_Deployment{Scope: &storage.Scope{Namespace: "namespace-2"}}}, - {Name: "exclusion3", Deployment: &storage.Exclusion_Deployment{Scope: &storage.Scope{Namespace: "namespace-3"}}}, - {Name: "exclusion1-changed", Deployment: &storage.Exclusion_Deployment{Scope: &storage.Scope{Namespace: "namespace-1"}}}, - {Name: "NEW exclusion", Deployment: &storage.Exclusion_Deployment{Scope: &storage.Scope{Namespace: "namespace-NEW"}}}, - {Name: "NEW exclusion2", Deployment: &storage.Exclusion_Deployment{Scope: &storage.Scope{Namespace: "namespace-NEW2"}}}, + {Name: "exclusion0", Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{Scope: &storage.Scope{Namespace: "namespace-0"}}}}, + {Name: "exclusion0", Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{Scope: &storage.Scope{Namespace: "namespace-0"}}}}, + {Name: "exclusion2", Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{Scope: &storage.Scope{Namespace: "namespace-2"}}}}, + {Name: "exclusion3", Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{Scope: &storage.Scope{Namespace: "namespace-3"}}}}, + {Name: "exclusion1-changed", Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{Scope: &storage.Scope{Namespace: "namespace-1"}}}}, + {Name: "NEW exclusion", Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{Scope: &storage.Scope{Namespace: "namespace-NEW"}}}}, + {Name: "NEW exclusion2", Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{Scope: &storage.Scope{Namespace: "namespace-NEW2"}}}}, } s.comparePolicyWithDB(policyID, policy) @@ -248,7 +248,7 @@ func testPolicy(id string) *storage.Policy { }, }, Exclusions: []*storage.Exclusion{ - {Name: "exclusion name", Deployment: &storage.Exclusion_Deployment{Scope: &storage.Scope{Namespace: "namespace name"}}}, + {Name: "exclusion name", Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{Scope: &storage.Scope{Namespace: "namespace name"}}}}, }, } } diff --git a/operator/Makefile b/operator/Makefile index 8cfb88a07f6a3..1e13f7b7cc243 100755 --- a/operator/Makefile +++ b/operator/Makefile @@ -237,15 +237,21 @@ parent-proto-generate: ## Make sure ../generated directory has up-to-date conten [[ $${ROX_OPERATOR_SKIP_PROTO_GENERATED_SRCS:-false} = true ]] || $(MAKE) -C .. proto-generated-srcs .PHONY: manifests -manifests: parent-proto-generate controller-gen ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects. +manifests: parent-proto-generate controller-gen go-mod-download ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects. $(CONTROLLER_GEN) rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases .PHONY: generate -generate: parent-proto-generate controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations. +generate: parent-proto-generate controller-gen go-mod-download ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations. $(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./..." # The generated source files might not comply with the current go formatting, so format them explicitly. go fmt ./api/... +.PHONY: go-mod-download +go-mod-download: ## Download modules we depend on, with retries. +# Warm up go module cache so that transient network failures do not abort controller-gen. +# Once downloaded, this command is very quick (~200 ms). + go mod download || go mod download || go mod download + .PHONY: fmt fmt: ## Run go fmt against code. go fmt ./... @@ -297,7 +303,7 @@ stackrox-image-pull-secret: ## Create default image pull secret for StackRox ima # Create stackrox namespace if not exists. echo '{ "apiVersion": "v1", "kind": "Namespace", "metadata": { "name": "$(NAMESPACE)" } }' | $(PROJECT_DIR)/hack/retry-kubectl.sh apply -f - # Create stackrox image pull secret in stackrox namespace. - $(PROJECT_DIR)/../deploy/common/pull-secret.sh stackrox quay.io | $(PROJECT_DIR)/hack/retry-kubectl.sh -n "$(NAMESPACE)" apply -f - + $(PROJECT_DIR)/../scripts/pull-secret.sh stackrox quay.io | $(PROJECT_DIR)/hack/retry-kubectl.sh -n "$(NAMESPACE)" apply -f - .PHONY: check-ci-setup check-ci-setup: ## Make sure this target is not started in CI environment. diff --git a/operator/api/v1alpha1/central_types.go b/operator/api/v1alpha1/central_types.go index e5e6443bb9707..610b453f0bb94 100644 --- a/operator/api/v1alpha1/central_types.go +++ b/operator/api/v1alpha1/central_types.go @@ -38,7 +38,7 @@ type CentralSpec struct { //+operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors={"urn:alm:descriptor:com.tectonic.ui:hidden"} Scanner *ScannerComponentSpec `json:"scanner,omitempty"` - // Settings for the Scanner V4 component, which can run in addition to the previously existing Scanner components + // Settings for the Scanner V4 component // TODO(ROX-36705): renumber order annotations after legacy Scanner field removal //+operator-sdk:csv:customresourcedefinitions:type=spec,order=3,displayName="Scanner V4 Component Settings" ScannerV4 *ScannerV4Spec `json:"scannerV4,omitempty"` diff --git a/operator/api/v1alpha1/securedcluster_types.go b/operator/api/v1alpha1/securedcluster_types.go index 922d58f0dadda..4d792a3044e32 100644 --- a/operator/api/v1alpha1/securedcluster_types.go +++ b/operator/api/v1alpha1/securedcluster_types.go @@ -74,7 +74,7 @@ type SecuredClusterSpec struct { //+operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors={"urn:alm:descriptor:com.tectonic.ui:hidden"} Scanner *LocalScannerComponentSpec `json:"scanner,omitempty"` - // Settings for the Scanner V4 components, which can run in addition to the previously existing Scanner components + // Settings for the Scanner V4 components // TODO(ROX-36705): renumber order annotations after legacy Scanner field removal //+operator-sdk:csv:customresourcedefinitions:type=spec,order=9,displayName="Scanner V4 Component Settings" ScannerV4 *LocalScannerV4ComponentSpec `json:"scannerV4,omitempty"` @@ -607,7 +607,7 @@ type SecuredClusterStatus struct { // responsible for the connection to Central, and Collector, which performs host-level collection of process and // network events.

// **Important:** Please see the _Installation Prerequisites_ on the main RHACS operator page before deploying, or -// consult the RHACS documentation on creating cluster init bundles. +// consult the RHACS documentation on creating cluster registration secrets (CRS). type SecuredCluster struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` diff --git a/operator/bundle/manifests/config.stackrox.io_securitypolicies.yaml b/operator/bundle/manifests/config.stackrox.io_securitypolicies.yaml index 51c227281ddf2..dadcf9abe6338 100644 --- a/operator/bundle/manifests/config.stackrox.io_securitypolicies.yaml +++ b/operator/bundle/manifests/config.stackrox.io_securitypolicies.yaml @@ -2,7 +2,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.21.0 + controller-gen.kubebuilder.io/version: v0.22.0 labels: app: rhacs-operator name: securitypolicies.config.stackrox.io @@ -83,7 +83,11 @@ spec: evaluates. properties: skipContainerTypes: + description: SkipContainerTypes lists container kinds to skip + during evaluation. items: + description: ContainerType lists container kinds a policy may + skip during evaluation. enum: - REGULAR - INIT @@ -139,6 +143,23 @@ spec: type: object type: object type: object + excludeByKind: + description: ExcludeByKind excludes all workloads of the selected + Kubernetes kinds. + properties: + kinds: + description: Kinds is the list of Kubernetes workload kinds + to exclude. + items: + enum: + - CRON_JOB + - JOB + type: string + minItems: 1 + type: array + required: + - kinds + type: object expiration: format: date-time type: string @@ -150,6 +171,11 @@ spec: name: type: string type: object + x-kubernetes-validations: + - message: at most one of the fields in [deployment excludeByKind] + may be set + rule: (has(self.deployment)?1:0)+(has(self.excludeByKind)?1:0) + <= 1 type: array isDefault: description: IsDefault is unused diff --git a/operator/bundle/manifests/platform.stackrox.io_centrals.yaml b/operator/bundle/manifests/platform.stackrox.io_centrals.yaml index 554c25569a3f1..3474ec526ae09 100644 --- a/operator/bundle/manifests/platform.stackrox.io_centrals.yaml +++ b/operator/bundle/manifests/platform.stackrox.io_centrals.yaml @@ -2,7 +2,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.21.0 + controller-gen.kubebuilder.io/version: v0.22.0 labels: app: rhacs-operator name: centrals.platform.stackrox.io @@ -1998,7 +1998,9 @@ spec: description: Selects a key of a ConfigMap. properties: key: - description: The key to select. + description: |- + The key to select from the ConfigMap's Data field. + Keys in the BinaryData field are not currently propagated to container env vars. type: string name: default: "" @@ -2602,8 +2604,7 @@ spec: type: string type: object scannerV4: - description: Settings for the Scanner V4 component, which can run - in addition to the previously existing Scanner components + description: Settings for the Scanner V4 component properties: db: description: Settings pertaining to the DB deployment. diff --git a/operator/bundle/manifests/platform.stackrox.io_securedclusters.yaml b/operator/bundle/manifests/platform.stackrox.io_securedclusters.yaml index 42d024df618ec..82ccb863a715b 100644 --- a/operator/bundle/manifests/platform.stackrox.io_securedclusters.yaml +++ b/operator/bundle/manifests/platform.stackrox.io_securedclusters.yaml @@ -2,7 +2,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.21.0 + controller-gen.kubebuilder.io/version: v0.22.0 labels: app: rhacs-operator name: securedclusters.platform.stackrox.io @@ -36,7 +36,7 @@ spec: responsible for the connection to Central, and Collector, which performs host-level collection of process and network events.

**Important:** Please see the _Installation Prerequisites_ on the main RHACS operator page before deploying, or - consult the RHACS documentation on creating cluster init bundles. + consult the RHACS documentation on creating cluster registration secrets (CRS). properties: apiVersion: description: |- @@ -401,7 +401,9 @@ spec: description: Selects a key of a ConfigMap. properties: key: - description: The key to select. + description: |- + The key to select from the ConfigMap's Data field. + Keys in the BinaryData field are not currently propagated to container env vars. type: string name: default: "" @@ -1347,8 +1349,7 @@ spec: type: string type: object scannerV4: - description: Settings for the Scanner V4 components, which can run - in addition to the previously existing Scanner components + description: Settings for the Scanner V4 components properties: db: description: Settings pertaining to the DB deployment. diff --git a/operator/bundle/manifests/rhacs-operator.clusterserviceversion.yaml b/operator/bundle/manifests/rhacs-operator.clusterserviceversion.yaml index f91fb9857fa0a..17a9bd0fba155 100644 --- a/operator/bundle/manifests/rhacs-operator.clusterserviceversion.yaml +++ b/operator/bundle/manifests/rhacs-operator.clusterserviceversion.yaml @@ -84,7 +84,7 @@ spec: - description: Settings for the Central component, which is responsible for all user interaction. displayName: Central Component Settings path: central - - description: Settings for the Scanner V4 component, which can run in addition to the previously existing Scanner components + - description: Settings for the Scanner V4 component displayName: Scanner V4 Component Settings path: scannerV4 - description: Settings related to outgoing network traffic. @@ -989,7 +989,7 @@ spec: responsible for the connection to Central, and Collector, which performs host-level collection of process and network events.

**Important:** Please see the _Installation Prerequisites_ on the main RHACS operator page before deploying, or - consult the RHACS documentation on creating cluster init bundles. + consult the RHACS documentation on creating cluster registration secrets (CRS). displayName: Secured Cluster kind: SecuredCluster name: securedclusters.platform.stackrox.io @@ -1034,7 +1034,7 @@ spec: - description: Settings relating to process baselines. displayName: Process Baselines Settings path: processBaselines - - description: Settings for the Scanner V4 components, which can run in addition to the previously existing Scanner components + - description: Settings for the Scanner V4 components displayName: Scanner V4 Component Settings path: scannerV4 - description: Settings related to Transport Layer Security, such as Certificate Authorities. @@ -1692,7 +1692,7 @@ spec: 2. **Secured Cluster Services** - Secured cluster services are placed on each cluster you manage and report back to Central. These services allow users to enforce policies and monitor your OpenShift and Kubernetes clusters. Secured Cluster Services come as two Deployments (Sensor and Admission Controller) and one DaemonSet (Collector). - **Console Plugin (Tech Preview):** RHACS provides a dynamic plugin that displays vulnerability management information in the OpenShift web console. Install a SecuredCluster to deploy the plugin. Enable the plugin by selecting *Operators* > *Installed Operators* or by modifying the console Operator configuration. + **Console Plugin:** RHACS provides a dynamic plugin that displays vulnerability management information in the OpenShift web console. Install a SecuredCluster to deploy the plugin. Enable the plugin by selecting *Operators* > *Installed Operators* or by modifying the console Operator configuration. **Important:** The Console Plugin requires OpenShift 4.19 or later. ### Central Services Explained @@ -1701,8 +1701,10 @@ spec: | :------------------------------- | :-------------- | :-------------- | | Central | Deployment | Users interact with Red Hat Advanced Cluster Security through the user interface or APIs on Central. Central also sends notifications for violations and interacts with integrations. | | Central DB | Deployment | Central DB is a PostgreSQL-based persistent storage for the data collected and managed by Central. | - | Scanner | Deployment | Scanner is a Red Hat developed and certified image scanner. Scanner analyzes and reports vulnerabilities for images. Scanner uses HPA to scale the number of replicas based on workload. | - | Scanner DB | Deployment | Scanner DB is a cache for vulnerability definitions to serve vulnerability scanning use cases throughout the software development life cycle. | + | Scanner V4 Indexer | Deployment | Scanner V4 Indexer analyzes container image layers and creates an index of packages and files. Scanner V4 Indexer uses Horizontal Pod Autoscaler (HPA) to scale the number of replicas based on workload. | + | Scanner V4 Matcher | Deployment | Scanner V4 Matcher matches indexed image content in vulnerability databases to identify security issues. Scanner V4 Matcher uses HPA to scale the number of replicas based on workload. | + | Scanner V4 DB | Deployment | Scanner V4 DB is a PostgreSQL-based persistent storage for indexed image data and vulnerability definitions. | + | Config Controller | Deployment | Config Controller watches SecurityPolicy custom resources and reconciles them with Central to manage security policies declaratively. | ### Secured Cluster Services Explained @@ -1711,6 +1713,8 @@ spec: | Sensor | Deployment | Sensor analyzes and monitors Kubernetes in secured clusters. | | Collector | DaemonSet | Analyzes and monitors container activity on Kubernetes nodes.| | Admission Controller | Deployment | ValidatingWebhookConfiguration for enforcing policies in the deploy lifecycle. | + | Scanner V4 Indexer | Deployment | Scanner V4 Indexer analyzes container image layers and creates an index of packages and files. Scanner V4 Indexer uses HPA to scale the number of replicas based on workload. | + | Scanner V4 DB | Deployment | Scanner V4 DB is a PostgreSQL-based persistent storage for indexed image data. | ### Central Custom Resource @@ -1722,13 +1726,13 @@ spec: #### Installation Prerequisites - Before deploying a SecuredCluster resource, you need to create a cluster init bundle secret. + Before deploying a SecuredCluster resource, you need to create a cluster registration secret (CRS). - - **Through the RHACS UI:** To create a cluster init bundle secret through the RHACS UI, navigate to `Platform Configuration > Clusters`, and then click `Manage Tokens` in the top-right corner. Select `Cluster Init Bundle`, and click `Generate Bundle`. Select `Download Kubernetes secrets file`, and store the file under a name of your choice (for example, `cluster-init-secrets.yaml`). - - **Through the `roxctl` CLI:** To create a cluster init bundle secret through the `roxctl` command-line interface, run `roxctl central init-bundles generate --output-secrets `. Choose any `name` and `file name` that you like. + - **Through the RHACS UI:** To create a cluster registration secret (CRS) through the RHACS UI, navigate to `Platform Configuration > Clusters`, and then click `Cluster Registration Secrets`. Click `Create cluster registration secret` in the top-right corner, enter a name, and click `Download` to download the Kubernetes secret file. Store the file under a name of your choice (for example, `cluster-registration-secret.yaml`). + - **Through the `roxctl` CLI:** To create a cluster registration secret (CRS) through the `roxctl` command-line interface, run `roxctl central crs generate --output `. Choose any `name` and `file name` that you like. Run `oc project` and check that it reports the correct namespace where you intend to deploy SecuredCluster. In case you want to install SecuredCluster to a different namespace, select it by running `oc project `. - Then, run `oc create -f init-bundle.yaml`. If you have chosen a name other than `init-bundle.yaml`, specify that file name instead. + Then, run `oc create -f cluster-registration-secret.yaml`. If you have chosen a name other than `cluster-registration-secret.yaml`, specify that file name instead. #### Required Fields @@ -1927,7 +1931,7 @@ spec: - risk links: - name: Red Hat Advanced Cluster Security Documentation - url: https://docs.openshift.com/acs/welcome/ + url: https://docs.redhat.com/en/documentation/red_hat_advanced_cluster_security_for_kubernetes - name: DataSheet url: https://www.redhat.com/en/resources/advanced-cluster-security-for-kubernetes-datasheet - name: Support Policy diff --git a/operator/cmd/main.go b/operator/cmd/main.go index 55537fdbeb212..fdcb412405a44 100644 --- a/operator/cmd/main.go +++ b/operator/cmd/main.go @@ -20,10 +20,12 @@ import ( "context" "crypto/tls" "flag" + "fmt" "os" "strconv" "time" + "github.com/go-logr/logr" "github.com/go-logr/zapr" configv1 "github.com/openshift/api/config/v1" consolev1 "github.com/openshift/api/console/v1" @@ -73,7 +75,6 @@ const ( ) var ( - setupLog = ctrl.Log.WithName("setup") scheme = runtime.NewScheme() enableProfiling = env.RegisterBooleanSetting("ENABLE_PROFILING", false) profilingThresholdFraction = env.RegisterSetting("PROFILING_THRESHOLD_FRACTION", env.WithDefault("0.8")) @@ -113,25 +114,27 @@ func init() { func main() { if err := run(); err != nil { - setupLog.Error(err, "fatal error") + fmt.Fprintf(os.Stderr, "Error: %v\n", err) os.Exit(1) } } -func run() error { - setupLog.Info("Starting RHACS Operator", "version", version.GetMainVersion()) +type runtimeConfig struct { + metricsAddr string + enableLeaderElection bool + probeAddr string + enableHTTP2 bool +} - var metricsAddr string - var enableLeaderElection bool - var probeAddr string - var enableHTTP2 bool +func run() error { + var config runtimeConfig - flag.StringVar(&metricsAddr, "metrics-bind-address", "0.0.0.0:8443", "The address the metric endpoint binds to.") - flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.") - flag.BoolVar(&enableLeaderElection, "leader-elect", false, + flag.StringVar(&config.metricsAddr, "metrics-bind-address", "0.0.0.0:8443", "The address the metric endpoint binds to.") + flag.StringVar(&config.probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.") + flag.BoolVar(&config.enableLeaderElection, "leader-elect", false, "Enable leader election for controller manager. "+ "Enabling this will ensure there is only one active controller manager.") - flag.BoolVar(&enableHTTP2, "enable-http2", enableHTTP2, "If HTTP/2 should be enabled for the metrics server.") + flag.BoolVar(&config.enableHTTP2, "enable-http2", false, "If HTTP/2 should be enabled for the metrics server.") opts := zap.Options{ Development: !buildinfo.ReleaseBuild, @@ -141,13 +144,20 @@ func run() error { zapLogger := zap.NewRaw(zap.UseFlagOptions(&opts)) ctrl.SetLogger(zapr.NewLogger(zapLogger)) + setupLog := ctrl.Log.WithName("setup") restore, err := rawZap.RedirectStdLogAt(zapLogger, zapcore.DebugLevel) if err != nil { return errors.Wrap(err, "unable to redirect std log") } defer restore() - clusterTLSProfile, tlsOpts, err := buildMetricsServerTLSOpts(enableHTTP2) + return runWithLogger(setupLog, config) +} + +func runWithLogger(setupLog logr.Logger, config runtimeConfig) error { + setupLog.Info("Starting RHACS Operator", "version", version.GetMainVersion()) + + clusterTLSProfile, tlsOpts, err := buildMetricsServerTLSOpts(setupLog, config.enableHTTP2) if err != nil { return err } @@ -165,7 +175,7 @@ func run() error { mgr, err := ctrl.NewManager(utils.GetRHACSConfigOrDie(), ctrl.Options{ Scheme: scheme, Metrics: server.Options{ - BindAddress: metricsAddr, + BindAddress: config.metricsAddr, SecureServing: true, FilterProvider: filters.WithAuthenticationAndAuthorization, TLSOpts: tlsOpts, @@ -183,8 +193,8 @@ func run() error { }, }, }, - HealthProbeBindAddress: probeAddr, - LeaderElection: enableLeaderElection, + HealthProbeBindAddress: config.probeAddr, + LeaderElection: config.enableLeaderElection, LeaderElectionID: "bf7ea6a2.stackrox.io", }) if err != nil { @@ -280,7 +290,7 @@ func run() error { // buildMetricsServerTLSOpts reads the cluster TLS profile and returns the // TLS options for the Operator's metrics server along with the cluster profile // for later use by the watcher and operand enricher. -func buildMetricsServerTLSOpts(enableHTTP2 bool) (*tlsprofile.ClusterTLSProfile, []func(c *tls.Config), error) { +func buildMetricsServerTLSOpts(setupLog logr.Logger, enableHTTP2 bool) (*tlsprofile.ClusterTLSProfile, []func(c *tls.Config), error) { bootstrapClient, err := ctrlClient.New(utils.GetRHACSConfigOrDie(), ctrlClient.Options{Scheme: scheme}) if err != nil { return nil, nil, errors.Wrap(err, "unable to create bootstrap client for TLS profile") diff --git a/operator/config/crd/bases/platform.stackrox.io_centrals.yaml b/operator/config/crd/bases/platform.stackrox.io_centrals.yaml index 4bade613ee669..57482b2ae2c29 100644 --- a/operator/config/crd/bases/platform.stackrox.io_centrals.yaml +++ b/operator/config/crd/bases/platform.stackrox.io_centrals.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.21.0 + controller-gen.kubebuilder.io/version: v0.22.0 name: centrals.platform.stackrox.io spec: group: platform.stackrox.io @@ -1997,7 +1997,9 @@ spec: description: Selects a key of a ConfigMap. properties: key: - description: The key to select. + description: |- + The key to select from the ConfigMap's Data field. + Keys in the BinaryData field are not currently propagated to container env vars. type: string name: default: "" @@ -2601,8 +2603,7 @@ spec: type: string type: object scannerV4: - description: Settings for the Scanner V4 component, which can run - in addition to the previously existing Scanner components + description: Settings for the Scanner V4 component properties: db: description: Settings pertaining to the DB deployment. diff --git a/operator/config/crd/bases/platform.stackrox.io_securedclusters.yaml b/operator/config/crd/bases/platform.stackrox.io_securedclusters.yaml index e3f7245601a5e..ca3be78ed8da5 100644 --- a/operator/config/crd/bases/platform.stackrox.io_securedclusters.yaml +++ b/operator/config/crd/bases/platform.stackrox.io_securedclusters.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.21.0 + controller-gen.kubebuilder.io/version: v0.22.0 name: securedclusters.platform.stackrox.io spec: group: platform.stackrox.io @@ -35,7 +35,7 @@ spec: responsible for the connection to Central, and Collector, which performs host-level collection of process and network events.

**Important:** Please see the _Installation Prerequisites_ on the main RHACS operator page before deploying, or - consult the RHACS documentation on creating cluster init bundles. + consult the RHACS documentation on creating cluster registration secrets (CRS). properties: apiVersion: description: |- @@ -400,7 +400,9 @@ spec: description: Selects a key of a ConfigMap. properties: key: - description: The key to select. + description: |- + The key to select from the ConfigMap's Data field. + Keys in the BinaryData field are not currently propagated to container env vars. type: string name: default: "" @@ -1346,8 +1348,7 @@ spec: type: string type: object scannerV4: - description: Settings for the Scanner V4 components, which can run - in addition to the previously existing Scanner components + description: Settings for the Scanner V4 components properties: db: description: Settings pertaining to the DB deployment. diff --git a/operator/config/manifests/bases/rhacs-operator.clusterserviceversion.yaml b/operator/config/manifests/bases/rhacs-operator.clusterserviceversion.yaml index f234bc4a9cf4c..01dceb6a80742 100644 --- a/operator/config/manifests/bases/rhacs-operator.clusterserviceversion.yaml +++ b/operator/config/manifests/bases/rhacs-operator.clusterserviceversion.yaml @@ -438,8 +438,7 @@ spec: path: scanner.db x-descriptors: - urn:alm:descriptor:com.tectonic.ui:fieldDependency:.scannerComponent:Enabled - - description: Settings for the Scanner V4 component, which can run in addition - to the previously existing Scanner components + - description: Settings for the Scanner V4 component displayName: Scanner V4 Component Settings path: scannerV4 - description: |- @@ -979,7 +978,7 @@ spec: responsible for the connection to Central, and Collector, which performs host-level collection of process and network events.

**Important:** Please see the _Installation Prerequisites_ on the main RHACS operator page before deploying, or - consult the RHACS documentation on creating cluster init bundles. + consult the RHACS documentation on creating cluster registration secrets (CRS). displayName: Secured Cluster kind: SecuredCluster name: securedclusters.platform.stackrox.io @@ -1377,8 +1376,7 @@ spec: - description: Settings relating to process baselines. displayName: Process Baselines Settings path: processBaselines - - description: Settings for the Scanner V4 components, which can run in addition - to the previously existing Scanner components + - description: Settings for the Scanner V4 components displayName: Scanner V4 Component Settings path: scannerV4 - description: Settings related to Transport Layer Security, such as Certificate @@ -1698,7 +1696,7 @@ spec: 2. **Secured Cluster Services** - Secured cluster services are placed on each cluster you manage and report back to Central. These services allow users to enforce policies and monitor your OpenShift and Kubernetes clusters. Secured Cluster Services come as two Deployments (Sensor and Admission Controller) and one DaemonSet (Collector). - **Console Plugin (Tech Preview):** RHACS provides a dynamic plugin that displays vulnerability management information in the OpenShift web console. Install a SecuredCluster to deploy the plugin. Enable the plugin by selecting *Operators* > *Installed Operators* or by modifying the console Operator configuration. + **Console Plugin:** RHACS provides a dynamic plugin that displays vulnerability management information in the OpenShift web console. Install a SecuredCluster to deploy the plugin. Enable the plugin by selecting *Operators* > *Installed Operators* or by modifying the console Operator configuration. **Important:** The Console Plugin requires OpenShift 4.19 or later. ### Central Services Explained @@ -1707,8 +1705,10 @@ spec: | :------------------------------- | :-------------- | :-------------- | | Central | Deployment | Users interact with Red Hat Advanced Cluster Security through the user interface or APIs on Central. Central also sends notifications for violations and interacts with integrations. | | Central DB | Deployment | Central DB is a PostgreSQL-based persistent storage for the data collected and managed by Central. | - | Scanner | Deployment | Scanner is a Red Hat developed and certified image scanner. Scanner analyzes and reports vulnerabilities for images. Scanner uses HPA to scale the number of replicas based on workload. | - | Scanner DB | Deployment | Scanner DB is a cache for vulnerability definitions to serve vulnerability scanning use cases throughout the software development life cycle. | + | Scanner V4 Indexer | Deployment | Scanner V4 Indexer analyzes container image layers and creates an index of packages and files. Scanner V4 Indexer uses Horizontal Pod Autoscaler (HPA) to scale the number of replicas based on workload. | + | Scanner V4 Matcher | Deployment | Scanner V4 Matcher matches indexed image content in vulnerability databases to identify security issues. Scanner V4 Matcher uses HPA to scale the number of replicas based on workload. | + | Scanner V4 DB | Deployment | Scanner V4 DB is a PostgreSQL-based persistent storage for indexed image data and vulnerability definitions. | + | Config Controller | Deployment | Config Controller watches SecurityPolicy custom resources and reconciles them with Central to manage security policies declaratively. | ### Secured Cluster Services Explained @@ -1717,6 +1717,8 @@ spec: | Sensor | Deployment | Sensor analyzes and monitors Kubernetes in secured clusters. | | Collector | DaemonSet | Analyzes and monitors container activity on Kubernetes nodes.| | Admission Controller | Deployment | ValidatingWebhookConfiguration for enforcing policies in the deploy lifecycle. | + | Scanner V4 Indexer | Deployment | Scanner V4 Indexer analyzes container image layers and creates an index of packages and files. Scanner V4 Indexer uses HPA to scale the number of replicas based on workload. | + | Scanner V4 DB | Deployment | Scanner V4 DB is a PostgreSQL-based persistent storage for indexed image data. | ### Central Custom Resource @@ -1728,13 +1730,13 @@ spec: #### Installation Prerequisites - Before deploying a SecuredCluster resource, you need to create a cluster init bundle secret. + Before deploying a SecuredCluster resource, you need to create a cluster registration secret (CRS). - - **Through the RHACS UI:** To create a cluster init bundle secret through the RHACS UI, navigate to `Platform Configuration > Clusters`, and then click `Manage Tokens` in the top-right corner. Select `Cluster Init Bundle`, and click `Generate Bundle`. Select `Download Kubernetes secrets file`, and store the file under a name of your choice (for example, `cluster-init-secrets.yaml`). - - **Through the `roxctl` CLI:** To create a cluster init bundle secret through the `roxctl` command-line interface, run `roxctl central init-bundles generate --output-secrets `. Choose any `name` and `file name` that you like. + - **Through the RHACS UI:** To create a cluster registration secret (CRS) through the RHACS UI, navigate to `Platform Configuration > Clusters`, and then click `Cluster Registration Secrets`. Click `Create cluster registration secret` in the top-right corner, enter a name, and click `Download` to download the Kubernetes secret file. Store the file under a name of your choice (for example, `cluster-registration-secret.yaml`). + - **Through the `roxctl` CLI:** To create a cluster registration secret (CRS) through the `roxctl` command-line interface, run `roxctl central crs generate --output `. Choose any `name` and `file name` that you like. Run `oc project` and check that it reports the correct namespace where you intend to deploy SecuredCluster. In case you want to install SecuredCluster to a different namespace, select it by running `oc project `. - Then, run `oc create -f init-bundle.yaml`. If you have chosen a name other than `init-bundle.yaml`, specify that file name instead. + Then, run `oc create -f cluster-registration-secret.yaml`. If you have chosen a name other than `cluster-registration-secret.yaml`, specify that file name instead. #### Required Fields @@ -1776,7 +1778,7 @@ spec: - risk links: - name: Red Hat Advanced Cluster Security Documentation - url: https://docs.openshift.com/acs/welcome/ + url: https://docs.redhat.com/en/documentation/red_hat_advanced_cluster_security_for_kubernetes - name: DataSheet url: https://www.redhat.com/en/resources/advanced-cluster-security-for-kubernetes-datasheet - name: Support Policy diff --git a/operator/config/ui-metadata/bases/rhacs-operator.clusterserviceversion.yaml b/operator/config/ui-metadata/bases/rhacs-operator.clusterserviceversion.yaml index e14968528e1ee..3be0b24c6fbc2 100644 --- a/operator/config/ui-metadata/bases/rhacs-operator.clusterserviceversion.yaml +++ b/operator/config/ui-metadata/bases/rhacs-operator.clusterserviceversion.yaml @@ -65,7 +65,7 @@ spec: 2. **Secured Cluster Services** - Secured cluster services are placed on each cluster you manage and report back to Central. These services allow users to enforce policies and monitor your OpenShift and Kubernetes clusters. Secured Cluster Services come as two Deployments (Sensor and Admission Controller) and one DaemonSet (Collector). - **Console Plugin (Tech Preview):** RHACS provides a dynamic plugin that displays vulnerability management information in the OpenShift web console. Install a SecuredCluster to deploy the plugin. Enable the plugin by selecting *Operators* > *Installed Operators* or by modifying the console Operator configuration. + **Console Plugin:** RHACS provides a dynamic plugin that displays vulnerability management information in the OpenShift web console. Install a SecuredCluster to deploy the plugin. Enable the plugin by selecting *Operators* > *Installed Operators* or by modifying the console Operator configuration. **Important:** The Console Plugin requires OpenShift 4.19 or later. ### Central Services Explained @@ -74,8 +74,10 @@ spec: | :------------------------------- | :-------------- | :-------------- | | Central | Deployment | Users interact with Red Hat Advanced Cluster Security through the user interface or APIs on Central. Central also sends notifications for violations and interacts with integrations. | | Central DB | Deployment | Central DB is a PostgreSQL-based persistent storage for the data collected and managed by Central. | - | Scanner | Deployment | Scanner is a Red Hat developed and certified image scanner. Scanner analyzes and reports vulnerabilities for images. Scanner uses HPA to scale the number of replicas based on workload. | - | Scanner DB | Deployment | Scanner DB is a cache for vulnerability definitions to serve vulnerability scanning use cases throughout the software development life cycle. | + | Scanner V4 Indexer | Deployment | Scanner V4 Indexer analyzes container image layers and creates an index of packages and files. Scanner V4 Indexer uses Horizontal Pod Autoscaler (HPA) to scale the number of replicas based on workload. | + | Scanner V4 Matcher | Deployment | Scanner V4 Matcher matches indexed image content in vulnerability databases to identify security issues. Scanner V4 Matcher uses HPA to scale the number of replicas based on workload. | + | Scanner V4 DB | Deployment | Scanner V4 DB is a PostgreSQL-based persistent storage for indexed image data and vulnerability definitions. | + | Config Controller | Deployment | Config Controller watches SecurityPolicy custom resources and reconciles them with Central to manage security policies declaratively. | ### Secured Cluster Services Explained @@ -84,6 +86,8 @@ spec: | Sensor | Deployment | Sensor analyzes and monitors Kubernetes in secured clusters. | | Collector | DaemonSet | Analyzes and monitors container activity on Kubernetes nodes.| | Admission Controller | Deployment | ValidatingWebhookConfiguration for enforcing policies in the deploy lifecycle. | + | Scanner V4 Indexer | Deployment | Scanner V4 Indexer analyzes container image layers and creates an index of packages and files. Scanner V4 Indexer uses HPA to scale the number of replicas based on workload. | + | Scanner V4 DB | Deployment | Scanner V4 DB is a PostgreSQL-based persistent storage for indexed image data. | ### Central Custom Resource @@ -95,13 +99,13 @@ spec: #### Installation Prerequisites - Before deploying a SecuredCluster resource, you need to create a cluster init bundle secret. + Before deploying a SecuredCluster resource, you need to create a cluster registration secret (CRS). - - **Through the RHACS UI:** To create a cluster init bundle secret through the RHACS UI, navigate to `Platform Configuration > Clusters`, and then click `Manage Tokens` in the top-right corner. Select `Cluster Init Bundle`, and click `Generate Bundle`. Select `Download Kubernetes secrets file`, and store the file under a name of your choice (for example, `cluster-init-secrets.yaml`). - - **Through the `roxctl` CLI:** To create a cluster init bundle secret through the `roxctl` command-line interface, run `roxctl central init-bundles generate --output-secrets `. Choose any `name` and `file name` that you like. + - **Through the RHACS UI:** To create a cluster registration secret (CRS) through the RHACS UI, navigate to `Platform Configuration > Clusters`, and then click `Cluster Registration Secrets`. Click `Create cluster registration secret` in the top-right corner, enter a name, and click `Download` to download the Kubernetes secret file. Store the file under a name of your choice (for example, `cluster-registration-secret.yaml`). + - **Through the `roxctl` CLI:** To create a cluster registration secret (CRS) through the `roxctl` command-line interface, run `roxctl central crs generate --output `. Choose any `name` and `file name` that you like. Run `oc project` and check that it reports the correct namespace where you intend to deploy SecuredCluster. In case you want to install SecuredCluster to a different namespace, select it by running `oc project `. - Then, run `oc create -f init-bundle.yaml`. If you have chosen a name other than `init-bundle.yaml`, specify that file name instead. + Then, run `oc create -f cluster-registration-secret.yaml`. If you have chosen a name other than `cluster-registration-secret.yaml`, specify that file name instead. #### Required Fields @@ -139,7 +143,7 @@ spec: - risk links: - name: Red Hat Advanced Cluster Security Documentation - url: https://docs.openshift.com/acs/welcome/ + url: https://docs.redhat.com/en/documentation/red_hat_advanced_cluster_security_for_kubernetes - name: DataSheet url: https://www.redhat.com/en/resources/advanced-cluster-security-for-kubernetes-datasheet - name: Support Policy diff --git a/operator/hack/generate-and-install-chart.sh b/operator/hack/generate-and-install-chart.sh index f2fca504e9180..0399249b1be1b 100755 --- a/operator/hack/generate-and-install-chart.sh +++ b/operator/hack/generate-and-install-chart.sh @@ -19,4 +19,7 @@ echo >&2 "Deploying operator version ${version} from a temporary checkout at ${d git worktree add "${dir}" "${version}" trap 'git worktree remove --force "${dir}"' EXIT +# Warm up go module cache so that transient network failures do not abort controller-gen. +# TODO: this command can be removed once the version we upgrade from runs go-mod-download internally. +(cd "${dir}"; go mod download || go mod download || go mod download) make -C "${dir}/operator" chart deploy-via-chart VERSION="${version}" diff --git a/operator/internal/securedcluster/reconciler/reconciler.go b/operator/internal/securedcluster/reconciler/reconciler.go index e1a47c60a7dc4..c41a3185cd645 100644 --- a/operator/internal/securedcluster/reconciler/reconciler.go +++ b/operator/internal/securedcluster/reconciler/reconciler.go @@ -1,6 +1,10 @@ package reconciler import ( + "context" + "fmt" + "time" + pkgReconciler "github.com/operator-framework/helm-operator-plugins/pkg/reconciler" "github.com/stackrox/rox/image" platform "github.com/stackrox/rox/operator/api/v1alpha1" @@ -20,9 +24,28 @@ import ( "github.com/stackrox/rox/pkg/version" corev1 "k8s.io/api/core/v1" ctrl "sigs.k8s.io/controller-runtime" + ctrlClient "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/handler" + "sigs.k8s.io/controller-runtime/pkg/reconcile" "sigs.k8s.io/controller-runtime/pkg/source" ) +// A Central in any namespace changes the derived cluster label for every SecuredCluster. +func securedClusterRequests(ctx context.Context, client ctrlClient.Client) []reconcile.Request { + ctx, cancel := context.WithTimeout(ctx, 10*time.Minute) + defer cancel() + list := &platform.SecuredClusterList{} + if err := client.List(ctx, list); err != nil { + // Match HandleSiblings: a failed list must not silently leave resources stale. + panic(fmt.Errorf("cannot retrieve SecuredClusters when processing Central event: %w", err)) + } + requests := make([]reconcile.Request, 0, len(list.Items)) + for i := range list.Items { + requests = append(requests, utils.RequestFor(&list.Items[i])) + } + return requests +} + // RegisterNewReconciler registers a new helm reconciler in the given k8s controller manager func RegisterNewReconciler(mgr ctrl.Manager, selector string, tlsProfile *tlsprofile.TLSProfile) error { renderCache := rendercache.NewRenderCache() @@ -31,9 +54,11 @@ func RegisterNewReconciler(mgr ctrl.Manager, selector string, tlsProfile *tlspro source.Kind[*platform.Central]( mgr.GetCache(), &platform.Central{}, - reconciler.HandleSiblings[*platform.Central](platform.SecuredClusterGVK, mgr), - // Only appearance and disappearance of a Central resource can influence whether - // a local scanner should be deployed by the SecuredCluster controller. + handler.TypedEnqueueRequestsFromMapFunc(func(ctx context.Context, _ *platform.Central) []reconcile.Request { + return securedClusterRequests(ctx, mgr.GetClient()) + }), + // Central creation and deletion affect the cluster-wide derived label; a + // Central in the same namespace also affects local scanner detection. utils.CreateAndDeleteOnlyPredicate[*platform.Central]{})) // IMPORTANT: The FeatureDefaultingExtension preExtensions implements feature-defaulting logic // and therefore must be executed and registered first. diff --git a/operator/internal/securedcluster/reconciler/reconciler_test.go b/operator/internal/securedcluster/reconciler/reconciler_test.go new file mode 100644 index 0000000000000..9aead64724025 --- /dev/null +++ b/operator/internal/securedcluster/reconciler/reconciler_test.go @@ -0,0 +1,29 @@ +package reconciler + +import ( + "context" + "testing" + + platform "github.com/stackrox/rox/operator/api/v1alpha1" + "github.com/stackrox/rox/operator/internal/utils/testutils" + "github.com/stretchr/testify/assert" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/reconcile" +) + +func TestCentralEventEnqueuesSecuredClustersAcrossNamespaces(t *testing.T) { + securedClusters := []*platform.SecuredCluster{ + {ObjectMeta: metav1.ObjectMeta{Name: "local", Namespace: "central-namespace"}}, + {ObjectMeta: metav1.ObjectMeta{Name: "remote", Namespace: "secured-namespace"}}, + } + client := testutils.NewFakeClientBuilder(t, securedClusters[0], securedClusters[1]).Build() + want := []reconcile.Request{ + {NamespacedName: types.NamespacedName{Name: "local", Namespace: "central-namespace"}}, + {NamespacedName: types.NamespacedName{Name: "remote", Namespace: "secured-namespace"}}, + } + + // The mapping does not depend on whether a Central still exists, so it + // enqueues both SecuredClusters on both creation and deletion. + assert.ElementsMatch(t, want, securedClusterRequests(context.Background(), client)) +} diff --git a/operator/internal/securedcluster/values/translation/translation.go b/operator/internal/securedcluster/values/translation/translation.go index 75a9cd11b3c53..f9f52888700a6 100644 --- a/operator/internal/securedcluster/values/translation/translation.go +++ b/operator/internal/securedcluster/values/translation/translation.go @@ -4,6 +4,7 @@ import ( "context" "crypto/sha256" "fmt" + "maps" "strconv" // Required for the usage of go:embed below. @@ -40,6 +41,16 @@ const ( legacyCollectionKernelModule = "KernelModule" legacyCollectionEBPF = "EBPF" + + // namespacePrefixGlobalResourcesAnnotation is an undocumented, test-only annotation. + // When set to "true" it enables namespace-prefixing of global (cluster-scoped) + // resource names in the secured-cluster chart (see srox.optionalGlobalResourceName), + // so that multiple secured clusters can be deployed into different namespaces of the + // same cluster without cluster-scoped resource name clashes. It defaults to off, so + // production keeps stable, static names. Deliberately kept out of the CRD schema. + namespacePrefixGlobalResourcesAnnotation = "platform.stackrox.io/namespace-prefix-global-resources" + + centralColocatedLabelKey = "stackrox.io/central-colocated" ) var ( @@ -105,7 +116,18 @@ func (t Translator) translate(ctx context.Context, sc platform.SecuredCluster) ( if sc.Spec.ClusterName != nil { v.SetStringValue("clusterName", *sc.Spec.ClusterName) } - v.SetStringMap("clusterLabels", sc.Spec.ClusterLabels) + v.SetStringMap("clusterLabels", t.clusterLabels(ctx, sc)) + + if annotationValue, ok := sc.GetAnnotations()[namespacePrefixGlobalResourcesAnnotation]; ok { + namespacePrefix, err := strconv.ParseBool(annotationValue) + if err != nil { + return nil, fmt.Errorf("invalid annotation value %q for annotation %s", + annotationValue, namespacePrefixGlobalResourcesAnnotation) + } + if namespacePrefix { + v.SetBoolValue("namespacePrefixGlobalResources", true) + } + } if sc.Spec.CentralEndpoint != nil && *sc.Spec.CentralEndpoint != "" { v.SetStringValue("centralEndpoint", *sc.Spec.CentralEndpoint) @@ -614,3 +636,27 @@ func getVirtualMachinesValues(vm *platform.VirtualMachinesSpec) *translation.Val } return &cv } + +// clusterLabels returns the user-specified cluster labels (excluding the +// reserved central-colocated label) merged with auto-detected labels. When a +// Central CR exists anywhere in the cluster, the label +// stackrox.io/central-colocated=true is added so that access scopes can +// dynamically match the cluster where Central runs. The Central CR may live +// in a different namespace than the SecuredCluster CR, so the whole cluster +// is searched rather than just the SecuredCluster's own namespace. +func (t Translator) clusterLabels(ctx context.Context, sc platform.SecuredCluster) map[string]string { + labels := maps.Clone(sc.Spec.ClusterLabels) + delete(labels, centralColocatedLabelKey) + + centralList := &platform.CentralList{} + if err := t.client.List(ctx, centralList); err != nil { + return labels + } + if len(centralList.Items) > 0 { + if labels == nil { + labels = make(map[string]string, 1) + } + labels[centralColocatedLabelKey] = "true" + } + return labels +} diff --git a/operator/internal/securedcluster/values/translation/translation_cluster_labels_test.go b/operator/internal/securedcluster/values/translation/translation_cluster_labels_test.go new file mode 100644 index 0000000000000..259d3f8a7ea1d --- /dev/null +++ b/operator/internal/securedcluster/values/translation/translation_cluster_labels_test.go @@ -0,0 +1,100 @@ +package translation + +import ( + "context" + "errors" + "testing" + + platform "github.com/stackrox/rox/operator/api/v1alpha1" + "github.com/stackrox/rox/operator/internal/utils/testutils" + "github.com/stretchr/testify/assert" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + ctrlClient "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/interceptor" +) + +func TestClusterLabels(t *testing.T) { + newCentral := func(namespace string) *platform.Central { + return &platform.Central{ + ObjectMeta: metav1.ObjectMeta{Name: "central", Namespace: namespace}, + } + } + + tests := map[string]struct { + scNamespace string + userLabels map[string]string + centralObject *platform.Central + listError error + want map[string]string + }{ + "no Central CR anywhere: user labels are returned unchanged": { + scNamespace: "stackrox", + userLabels: map[string]string{"user-label": "value"}, + want: map[string]string{"user-label": "value"}, + }, + "no Central CR: reserved label is removed": { + userLabels: map[string]string{ + "user-label": "value", + centralColocatedLabelKey: "false", + }, + want: map[string]string{"user-label": "value"}, + }, + "Central lookup fails: reserved label is removed": { + userLabels: map[string]string{ + "user-label": "value", + centralColocatedLabelKey: "true", + }, + listError: errors.New("Central list failed"), + want: map[string]string{"user-label": "value"}, + }, + "Central CR in the same namespace: label is added": { + scNamespace: "stackrox", + userLabels: map[string]string{ + "user-label": "value", + centralColocatedLabelKey: "false", + }, + centralObject: newCentral("stackrox"), + want: map[string]string{ + "user-label": "value", + centralColocatedLabelKey: "true", + }, + }, + "Central CR in a different namespace on the same cluster: label is still added": { + // SecuredCluster and Central can be installed into different namespaces + // even when they run on the same physical cluster. + scNamespace: "stackrox-secured-cluster", + centralObject: newCentral("stackrox"), + want: map[string]string{ + centralColocatedLabelKey: "true", + }, + }, + } + + for name, tt := range tests { + t.Run(name, func(t *testing.T) { + var objects []ctrlClient.Object + if tt.centralObject != nil { + objects = append(objects, tt.centralObject) + } + builder := testutils.NewFakeClientBuilder(t, objects...) + if tt.listError != nil { + builder = builder.WithInterceptorFuncs(interceptor.Funcs{ + List: func(ctx context.Context, client ctrlClient.WithWatch, list ctrlClient.ObjectList, opts ...ctrlClient.ListOption) error { + return tt.listError + }, + }) + } + client := builder.Build() + translator := New(client, client) + + sc := platform.SecuredCluster{ + ObjectMeta: metav1.ObjectMeta{Namespace: tt.scNamespace}, + Spec: platform.SecuredClusterSpec{ClusterLabels: tt.userLabels}, + } + + got := translator.clusterLabels(context.Background(), sc) + assert.Equal(t, tt.want, got) + assert.Equal(t, tt.userLabels, sc.Spec.ClusterLabels) + }) + } +} diff --git a/operator/internal/securedcluster/values/translation/translation_test.go b/operator/internal/securedcluster/values/translation/translation_test.go index f047f65085cbf..b314bf5dcecde 100644 --- a/operator/internal/securedcluster/values/translation/translation_test.go +++ b/operator/internal/securedcluster/values/translation/translation_test.go @@ -257,6 +257,31 @@ func (s *TranslationTestSuite) TestTranslate() { }, }, }, + "namespace-prefix-global-resources annotation enabled": { + args: args{ + client: newDefaultFakeClient(t), + sc: platform.SecuredCluster{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "stackrox", + Annotations: map[string]string{namespacePrefixGlobalResourcesAnnotation: "true"}, + }, + Spec: platform.SecuredClusterSpec{ + ClusterName: new("test-cluster"), + }, + }, + }, + want: chartutil.Values{ + "clusterName": "test-cluster", + "ca": map[string]string{"cert": "ca central content"}, + "createSecrets": false, + "namespacePrefixGlobalResources": true, + "monitoring": map[string]interface{}{ + "openshift": map[string]interface{}{ + "enabled": true, + }, + }, + }, + }, "local scanner autosense suppression": { args: args{ client: newDefaultFakeClientWithCentral(t), @@ -274,7 +299,10 @@ func (s *TranslationTestSuite) TestTranslate() { }, }, want: chartutil.Values{ - "clusterName": "test-cluster", + "clusterName": "test-cluster", + "clusterLabels": map[string]interface{}{ + centralColocatedLabelKey: "true", + }, "ca": map[string]string{"cert": "ca central content"}, "createSecrets": false, "monitoring": map[string]interface{}{ diff --git a/operator/konflux.Dockerfile b/operator/konflux.Dockerfile index 5f8cadaaca0fb..a0e2da48c3cb4 100644 --- a/operator/konflux.Dockerfile +++ b/operator/konflux.Dockerfile @@ -17,10 +17,10 @@ ENV CI=1 GOFLAGS="" CGO_ENABLED=1 RUN GOOS=linux GOARCH=$(go env GOARCH) scripts/go-build-file.sh operator/cmd/main.go image/bin/operator -FROM registry.access.redhat.com/ubi9/ubi-micro:latest@sha256:f332c99eb8f798a8486821c91937f10ad64ee83d7e739303be2df051040918f6 AS ubi-micro-base +FROM registry.access.redhat.com/ubi9/ubi-micro:latest@sha256:5be877a2a280ae36eb9ab80ca4efb28bbf77c57abbba38137cdc37a03b8465e6 AS ubi-micro-base -FROM registry.access.redhat.com/ubi9/ubi:latest@sha256:25a147defd01e19674714f55d17538c8dbe55d8c305fa157ecc3f9c8977b05b6 AS package_installer +FROM registry.access.redhat.com/ubi9/ubi:latest@sha256:16e9e43d99e181463513cc84a514859b1abb9460f1c4d9e208da4b4e51cd5cc3 AS package_installer # Copy ubi-micro base to /out/ to preserve its rpmdb COPY --from=ubi-micro-base / /out/ @@ -30,7 +30,7 @@ COPY --from=ubi-micro-base / /out/ # prefetched by Hermeto/Cachi2, instead of installroot's default UBI repos. RUN dnf install -y \ --installroot=/out/ \ - --releasever=8 \ + --releasever=9 \ --setopt=install_weak_deps=False \ --setopt=reposdir=/etc/yum.repos.d \ --nodocs \ diff --git a/operator/tests/central/central-misc/080-assert-non-openshift.yaml b/operator/tests/central/central-misc/080-assert-non-openshift.yaml index c14a8f2a726c9..2f0a7e5508697 100644 --- a/operator/tests/central/central-misc/080-assert-non-openshift.yaml +++ b/operator/tests/central/central-misc/080-assert-non-openshift.yaml @@ -51,6 +51,8 @@ spec: value: "true" - name: ROX_LEGACY_SCANNER value: "false" + - name: ROX_CENTRAL_WORKER_ENABLED + value: "true" - name: NO_PROXY valueFrom: secretKeyRef: diff --git a/operator/tests/central/central-misc/080-assert-openshift.yaml b/operator/tests/central/central-misc/080-assert-openshift.yaml index cb70e23734560..ae04ed59c1774 100644 --- a/operator/tests/central/central-misc/080-assert-openshift.yaml +++ b/operator/tests/central/central-misc/080-assert-openshift.yaml @@ -55,6 +55,8 @@ spec: value: "true" - name: ROX_LEGACY_SCANNER value: "false" + - name: ROX_CENTRAL_WORKER_ENABLED + value: "true" - name: NO_PROXY valueFrom: secretKeyRef: diff --git a/operator/tests/central/central-misc/081-assert-non-openshift.yaml b/operator/tests/central/central-misc/081-assert-non-openshift.yaml index 3e1dd62db2461..c65e401e52019 100644 --- a/operator/tests/central/central-misc/081-assert-non-openshift.yaml +++ b/operator/tests/central/central-misc/081-assert-non-openshift.yaml @@ -47,6 +47,8 @@ spec: value: "true" - name: ROX_LEGACY_SCANNER value: "false" + - name: ROX_CENTRAL_WORKER_ENABLED + value: "true" - name: NO_PROXY valueFrom: secretKeyRef: diff --git a/operator/tests/central/central-misc/081-assert-openshift.yaml b/operator/tests/central/central-misc/081-assert-openshift.yaml index 462ed4f144083..1e5773a8454ed 100644 --- a/operator/tests/central/central-misc/081-assert-openshift.yaml +++ b/operator/tests/central/central-misc/081-assert-openshift.yaml @@ -51,6 +51,8 @@ spec: value: "true" - name: ROX_LEGACY_SCANNER value: "false" + - name: ROX_CENTRAL_WORKER_ENABLED + value: "true" - name: NO_PROXY valueFrom: secretKeyRef: diff --git a/operator/tests/common/image-pull-secrets.yaml b/operator/tests/common/image-pull-secrets.yaml index 0a0a21fd5ebf4..98145fd926f3b 100644 --- a/operator/tests/common/image-pull-secrets.yaml +++ b/operator/tests/common/image-pull-secrets.yaml @@ -6,7 +6,7 @@ commands: set -eu # shell in CI does not grok -o pipefail secret=$(mktemp) registry_hostname=quay.io - ../../../../deploy/common/pull-secret.sh e2e-test-pull-secret ${registry_hostname} > $secret + ../../../../scripts/pull-secret.sh e2e-test-pull-secret ${registry_hostname} > $secret retry-kubectl.sh -n $NAMESPACE apply -f $secret echo "Created pull secret for ${registry_hostname} in $NAMESPACE" rm $secret diff --git a/operator/tools/controller-gen/go.mod b/operator/tools/controller-gen/go.mod index 5acc2fc959bab..1896df6710f05 100644 --- a/operator/tools/controller-gen/go.mod +++ b/operator/tools/controller-gen/go.mod @@ -2,31 +2,31 @@ module github.com/stackrox/rox/operator/tools/controller-gen go 1.26.3 -require sigs.k8s.io/controller-tools v0.21.0 +require sigs.k8s.io/controller-tools v0.22.0 require ( + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/fatih/color v1.19.0 // indirect github.com/fxamacker/cbor/v2 v2.9.1 // indirect github.com/go-logr/logr v1.4.3 // indirect - github.com/go-openapi/jsonpointer v0.23.1 // indirect - github.com/go-openapi/jsonreference v0.21.5 // indirect - github.com/go-openapi/swag v0.26.0 // indirect - github.com/go-openapi/swag/cmdutils v0.26.0 // indirect - github.com/go-openapi/swag/conv v0.26.0 // indirect - github.com/go-openapi/swag/fileutils v0.26.0 // indirect - github.com/go-openapi/swag/jsonname v0.26.0 // indirect - github.com/go-openapi/swag/jsonutils v0.26.0 // indirect - github.com/go-openapi/swag/loading v0.26.0 // indirect - github.com/go-openapi/swag/mangling v0.26.0 // indirect - github.com/go-openapi/swag/netutils v0.26.0 // indirect - github.com/go-openapi/swag/stringutils v0.26.0 // indirect - github.com/go-openapi/swag/typeutils v0.26.0 // indirect - github.com/go-openapi/swag/yamlutils v0.26.0 // indirect + github.com/go-openapi/jsonpointer v1.0.0 // indirect + github.com/go-openapi/jsonreference v1.0.0 // indirect + github.com/go-openapi/swag v0.27.1 // indirect + github.com/go-openapi/swag/cmdutils v0.27.1 // indirect + github.com/go-openapi/swag/conv v0.27.1 // indirect + github.com/go-openapi/swag/fileutils v0.27.1 // indirect + github.com/go-openapi/swag/jsonutils v0.27.1 // indirect + github.com/go-openapi/swag/loading v0.27.1 // indirect + github.com/go-openapi/swag/mangling v0.27.1 // indirect + github.com/go-openapi/swag/netutils v0.27.1 // indirect + github.com/go-openapi/swag/pools v0.27.1 // indirect + github.com/go-openapi/swag/stringutils v0.27.1 // indirect + github.com/go-openapi/swag/typeutils v0.27.1 // indirect + github.com/go-openapi/swag/yamlutils v0.27.1 // indirect github.com/gobuffalo/flect v1.0.3 // indirect github.com/google/gnostic-models v0.7.1 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/kr/text v0.2.0 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect @@ -35,27 +35,25 @@ require ( github.com/spf13/pflag v1.0.10 // indirect github.com/x448/float16 v0.8.4 // indirect go.yaml.in/yaml/v2 v2.4.4 // indirect - go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/mod v0.35.0 // indirect - golang.org/x/net v0.55.0 // indirect - golang.org/x/sync v0.20.0 // indirect - golang.org/x/sys v0.45.0 // indirect - golang.org/x/text v0.37.0 // indirect - golang.org/x/tools v0.44.0 // indirect + go.yaml.in/yaml/v3 v3.0.5 // indirect + golang.org/x/mod v0.39.0 // indirect + golang.org/x/net v0.58.0 // indirect + golang.org/x/sync v0.22.0 // indirect + golang.org/x/sys v0.47.0 // indirect + golang.org/x/text v0.41.0 // indirect + golang.org/x/tools v0.49.0 // indirect google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af // indirect gopkg.in/inf.v0 v0.9.1 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/api v0.36.0 // indirect - k8s.io/apiextensions-apiserver v0.36.0 // indirect - k8s.io/apimachinery v0.36.0 // indirect - k8s.io/code-generator v0.36.0 // indirect - k8s.io/gengo/v2 v2.0.0-20250922181213-ec3ebc5fd46b // indirect + k8s.io/api v0.37.0 // indirect + k8s.io/apiextensions-apiserver v0.37.0 // indirect + k8s.io/apimachinery v0.37.0 // indirect + k8s.io/code-generator v0.37.0 // indirect + k8s.io/gengo/v2 v2.0.0-20260408192533-25e2208e0dc3 // indirect k8s.io/klog/v2 v2.140.0 // indirect - k8s.io/kube-openapi v0.0.0-20260427204847-8949caaa1199 // indirect - k8s.io/utils v0.0.0-20260319190234-28399d86e0b5 // indirect + k8s.io/kube-openapi v0.0.0-20260721132016-d427ff9ee9ad // indirect + k8s.io/utils v0.0.0-20260626114624-be93311217bd // indirect sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/randfill v1.0.0 // indirect - sigs.k8s.io/structured-merge-diff/v6 v6.4.0 // indirect + sigs.k8s.io/structured-merge-diff/v6 v6.4.2 // indirect sigs.k8s.io/yaml v1.6.0 // indirect ) diff --git a/operator/tools/controller-gen/go.sum b/operator/tools/controller-gen/go.sum index 88ed54599b220..74c70924ce78c 100644 --- a/operator/tools/controller-gen/go.sum +++ b/operator/tools/controller-gen/go.sum @@ -1,7 +1,9 @@ cel.dev/expr v0.25.1 h1:1KrZg61W6TWSxuNZ37Xy49ps13NUovb66QLprthtwi4= cel.dev/expr v0.25.1/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4= -github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI= -github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g= +github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0= +github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= +github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ= +github.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= @@ -11,7 +13,6 @@ github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F9 github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= @@ -20,69 +21,67 @@ github.com/fatih/color v1.19.0 h1:Zp3PiM21/9Ld6FzSKyL5c/BULoe/ONr9KlbYVOfG8+w= github.com/fatih/color v1.19.0/go.mod h1:zNk67I0ZUT1bEGsSGyCZYZNrHuTkJJB+r6Q9VuMi0LE= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/fsnotify/fsnotify v1.10.0 h1:Xx/5Ydg9CeBDX/wi4VJqStNtohYjitZhhlHt4h3St1M= -github.com/fsnotify/fsnotify v1.10.0/go.mod h1:TLheqan6HD6GBK6PrDWyDPBaEV8LspOxvPSjC+bVfgo= github.com/fxamacker/cbor/v2 v2.9.1 h1:2rWm8B193Ll4VdjsJY28jxs70IdDsHRWgQYAI80+rMQ= github.com/fxamacker/cbor/v2 v2.9.1/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-openapi/jsonpointer v0.23.1 h1:1HBACs7XIwR2RcmItfdSFlALhGbe6S92p0ry4d1GWg4= -github.com/go-openapi/jsonpointer v0.23.1/go.mod h1:iWRmZTrGn7XwYhtPt/fvdSFj1OfNBngqRT2UG3BxSqY= -github.com/go-openapi/jsonreference v0.21.5 h1:6uCGVXU/aNF13AQNggxfysJ+5ZcU4nEAe+pJyVWRdiE= -github.com/go-openapi/jsonreference v0.21.5/go.mod h1:u25Bw85sX4E2jzFodh1FOKMTZLcfifd1Q+iKKOUxExw= -github.com/go-openapi/swag v0.26.0 h1:GVDXCmfvhfu1BxiHo8/FA+BbKmhecHnG3varjON5/RI= -github.com/go-openapi/swag v0.26.0/go.mod h1:82g3193sZJRbocs7bNCqGfIgq8pkuwVwCfhKIRlEQF0= -github.com/go-openapi/swag/cmdutils v0.26.0 h1:iowihOcvq7y4egO8cOq0dmfohz6wfeQ63U1EnuhO2TU= -github.com/go-openapi/swag/cmdutils v0.26.0/go.mod h1:Sm1MVFMkF6guJJ+pQqHnQA3N0j9qALV3NxzDSv6bETM= -github.com/go-openapi/swag/conv v0.26.0 h1:5yGGsPYI1ZCva93U0AoKi/iZrNhaJEjr324YVsiD89I= -github.com/go-openapi/swag/conv v0.26.0/go.mod h1:tpAmIL7X58VPnHHiSO4uE3jBeRamGsFsfdDeDtb5ECE= -github.com/go-openapi/swag/fileutils v0.26.0 h1:WJoPRvsA7QRiiWluowkLJa9jaYR7FCuxmDvnCgaRRxU= -github.com/go-openapi/swag/fileutils v0.26.0/go.mod h1:0WDJ7lp67eNjPMO50wAWYlKvhOb6CQ37rzR7wrgI8Tc= -github.com/go-openapi/swag/jsonname v0.26.0 h1:gV1NFX9M8avo0YSpmWogqfQISigCmpaiNci8cGECU5w= -github.com/go-openapi/swag/jsonname v0.26.0/go.mod h1:urBBR8bZNoDYGr653ynhIx+gTeIz0ARZxHkAPktJK2M= -github.com/go-openapi/swag/jsonutils v0.26.0 h1:FawFML2iAXsPqmERscuMPIHmFsoP1tOqWkxBaKNMsnA= -github.com/go-openapi/swag/jsonutils v0.26.0/go.mod h1:2VmA0CJlyFqgawOaPI9psnjFDqzyivIqLYN34t9p91E= -github.com/go-openapi/swag/jsonutils/fixtures_test v0.26.0 h1:apqeINu/ICHouqiRZbyFvuDge5jCmmLTqGQ9V95EaOM= -github.com/go-openapi/swag/jsonutils/fixtures_test v0.26.0/go.mod h1:AyM6QT8uz5IdKxk5akv0y6u4QvcL9GWERt0Jx/F/R8Y= -github.com/go-openapi/swag/loading v0.26.0 h1:Apg6zaKhCJurpJer0DCxq99qwmhFddBhaMX7kilDcko= -github.com/go-openapi/swag/loading v0.26.0/go.mod h1:dBxQ/6V2uBaAQdevN18VELE6xSpJWZxLX4txe12JwDg= -github.com/go-openapi/swag/mangling v0.26.0 h1:Du2YC4YLA/Y5m/YKQd7AnY5qq0wRKSFZTTt8ktFaXcQ= -github.com/go-openapi/swag/mangling v0.26.0/go.mod h1:jifS7W9vbg+pw63bT+GI53otluMQL3CeemuyCHKwVx0= -github.com/go-openapi/swag/netutils v0.26.0 h1:CmZp+ZT7HrmFwrC3GdGsXBq2+42T1bjKBapcqVpIs3c= -github.com/go-openapi/swag/netutils v0.26.0/go.mod h1:5iK+Ok3ZohWWex1C50BFTPexi03UaPwjW4Oj8kgrpwo= -github.com/go-openapi/swag/stringutils v0.26.0 h1:qZQngLxs5s7SLijc3N2ZO+fUq2o8LjuWAASSrJuh+xg= -github.com/go-openapi/swag/stringutils v0.26.0/go.mod h1:sWn5uY+QIIspwPhvgnqJsH8xqFT2ZbYcvbcFanRyhFE= -github.com/go-openapi/swag/typeutils v0.26.0 h1:2kdEwdiNWy+JJdOvu5MA2IIg2SylWAFuuyQIKYybfq4= -github.com/go-openapi/swag/typeutils v0.26.0/go.mod h1:oovDuIUvTrEHVMqWilQzKzV4YlSKgyZmFh7AlfABNVE= -github.com/go-openapi/swag/yamlutils v0.26.0 h1:H7O8l/8NJJQ/oiReEN+oMpnGMyt8G0hl460nRZxhLMQ= -github.com/go-openapi/swag/yamlutils v0.26.0/go.mod h1:1evKEGAtP37Pkwcc7EWMF0hedX0/x3Rkvei2wtG/TbU= -github.com/go-openapi/testify/enable/yaml/v2 v2.4.2 h1:5zRca5jw7lzVREKCZVNBpysDNBjj74rBh0N2BGQbSR0= -github.com/go-openapi/testify/enable/yaml/v2 v2.4.2/go.mod h1:XVevPw5hUXuV+5AkI1u1PeAm27EQVrhXTTCPAF85LmE= -github.com/go-openapi/testify/v2 v2.4.2 h1:tiByHpvE9uHrrKjOszax7ZvKB7QOgizBWGBLuq0ePx4= -github.com/go-openapi/testify/v2 v2.4.2/go.mod h1:SgsVHtfooshd0tublTtJ50FPKhujf47YRqauXXOUxfw= +github.com/go-openapi/jsonpointer v1.0.0 h1:kR9tHqY0CtZaOPVFm622dPVNhrvYpwr4uCxgL3h1H8s= +github.com/go-openapi/jsonpointer v1.0.0/go.mod h1:Z3rw7dWu1p9IgitXCFamSlA5lmDiklEB6vkaxcNZW5Y= +github.com/go-openapi/jsonreference v1.0.0 h1:jlmTr6torcd1YgDQvSfNmRtKzYDO4FGBkrAdlAVWnpY= +github.com/go-openapi/jsonreference v1.0.0/go.mod h1:jtwdyGbJk0Xhe5Y+rwtglQP6Sb1WZST4rT32LWB+sv0= +github.com/go-openapi/swag v0.27.1 h1:VotvOLWW8q/EAxB0YdsBBGC8XYyeL1YwBj2ungAGPNg= +github.com/go-openapi/swag v0.27.1/go.mod h1:GTkJPwHfhJp6MWr4/rCh64HVI3Ofu+tcsbfjfHmTxpE= +github.com/go-openapi/swag/cmdutils v0.27.1 h1:I7sYqaWVl5mq0NEmNQkAmFDyNin9ufvMX/p2zwtQaOE= +github.com/go-openapi/swag/cmdutils v0.27.1/go.mod h1:Sm1MVFMkF6guJJ+pQqHnQA3N0j9qALV3NxzDSv6bETM= +github.com/go-openapi/swag/conv v0.27.1 h1:8wi9ZG+olmY1wXphl93EWniPtbSPkXM/feH7FgjsvrU= +github.com/go-openapi/swag/conv v0.27.1/go.mod h1:QbqMivkpKhC3g1B1GGGOJ6ANewI3S62dbzYu3Duowqs= +github.com/go-openapi/swag/fileutils v0.27.1 h1:QQqBSoi5mW4XpU85nS0mLcA+zAE6vLzrb0QkmLKf9oM= +github.com/go-openapi/swag/fileutils v0.27.1/go.mod h1:VvJFZLTZS0AI854gEQz5tk7dBESdLjiNUMSZ/th2ry8= +github.com/go-openapi/swag/jsonutils v0.27.1 h1:SVgK3i4USzCU5mibOOS/l4ea2h9UQXy7J7RNLTjuXjU= +github.com/go-openapi/swag/jsonutils v0.27.1/go.mod h1:tdlEpZqdcQ17uj6J4YdK9vd8It5qWMwjWXOs0tjpRlk= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.27.1 h1:mJu3COL9WEaZVp/Kf2PRMi7tPszPEJfSr/OO75ynCs8= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.27.1/go.mod h1:mofwUWx70wvskwESqRJ//k/9kURmCgyJl5m5Ppoh5kY= +github.com/go-openapi/swag/loading v0.27.1 h1:/DxUgDXKbBX4bcn7r9uEXfJyzN5XpiJmZplzQTjrRCY= +github.com/go-openapi/swag/loading v0.27.1/go.mod h1:jvGh3iA2+zyUUycB5fgJWzeHnhrpvGnJJM0RVE9ZShE= +github.com/go-openapi/swag/mangling v0.27.1 h1:yC9D0HyUE8gbP+BfmGx9+AA89ikwZTMjESK3OnnoaqA= +github.com/go-openapi/swag/mangling v0.27.1/go.mod h1:jtBE2+V+3pILxOR7Vgce+Cwp6A2PgZbvVqfNntbVs0w= +github.com/go-openapi/swag/netutils v0.27.1 h1:mICMFoS82F5TZ4Zy3cqmcQk+BFeCp3Uyq3Np7GI0/qU= +github.com/go-openapi/swag/netutils v0.27.1/go.mod h1:J+WYyFMLtvtCGqa6jLv+YNUmIKI3ZRQRrvfNDMoQoEQ= +github.com/go-openapi/swag/pools v0.27.1 h1:9LeadcMyb2GJCbXX5hVQDbZ2Lq9TL4dCs/nx1j5DO0E= +github.com/go-openapi/swag/pools v0.27.1/go.mod h1:kVQefhSK5RWuRe7BXsL8htgBPAMpN7HDGpGEknqugeE= +github.com/go-openapi/swag/stringutils v0.27.1 h1:ZXePZ0r2p1qSjo8tD3Un4vFj8+FqlCkczxDrJIhYUp8= +github.com/go-openapi/swag/stringutils v0.27.1/go.mod h1:lzRN95CxXmA03XcDWHLOb6nOMcxCqR5rGY0lOgsfRoM= +github.com/go-openapi/swag/typeutils v0.27.1 h1:KSTdFlfnse4r6dP9IrEnwMldjE+zs71UeEB3//PtVXc= +github.com/go-openapi/swag/typeutils v0.27.1/go.mod h1:Srm0xFNRZ1Y+vCxJclo5qzx8aj+1pAKda/YfFPrG0dQ= +github.com/go-openapi/swag/yamlutils v0.27.1 h1:ftxv6xvXb1E3zohUc+okZ9nSqNb9StQX/FXnKZ98sQA= +github.com/go-openapi/swag/yamlutils v0.27.1/go.mod h1:bnxFIB1qewGRiZHypXGZ3fNgf13/0HfRgnS/iZBDrOo= +github.com/go-openapi/testify/enable/yaml/v2 v2.6.0 h1:gGHwAJ0R/5jU8BEGDbfRNR3hL68dAVi84WuOApp29B0= +github.com/go-openapi/testify/enable/yaml/v2 v2.6.0/go.mod h1:tY+St1SGq4NFl0QIqdTY4aEdbChAHxhyB77XQi9iJCo= +github.com/go-openapi/testify/v2 v2.6.0 h1:5PKH2HE7YJ/LuRPQGvSxBRlFXNQhSetBLlGAgUEu3ug= +github.com/go-openapi/testify/v2 v2.6.0/go.mod h1:SgsVHtfooshd0tublTtJ50FPKhujf47YRqauXXOUxfw= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/gobuffalo/flect v1.0.3 h1:xeWBM2nui+qnVvNM4S3foBhCAL2XgPU+a7FdpelbTq4= github.com/gobuffalo/flect v1.0.3/go.mod h1:A5msMlrHtLqh9umBSnvabjsMrCcCpAyzglnDvkbYKHs= -github.com/google/cel-go v0.26.0 h1:DPGjXackMpJWH680oGY4lZhYjIameYmR+/6RBdDGmaI= -github.com/google/cel-go v0.26.0/go.mod h1:A9O8OU9rdvrK5MQyrqfIxo1a0u4g3sF8KB6PUIaryMM= +github.com/google/cel-go v0.29.2 h1:ZtDxkeiMmz0mxbKDYiNkE5Lk7V5edMRcaaDf2jX002k= +github.com/google/cel-go v0.29.2/go.mod h1:X0bD6iVNR8pkROSOoHVdgTkzmRcosof7WQqCD6wcMc8= github.com/google/gnostic-models v0.7.1 h1:SisTfuFKJSKM5CPZkffwi6coztzzeYUhc3v4yxLWH8c= github.com/google/gnostic-models v0.7.1/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ= 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/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/pprof v0.0.0-20260402051712-545e8a4df936 h1:EwtI+Al+DeppwYX2oXJCETMO23COyaKGP6fHVpkpWpg= +github.com/google/pprof v0.0.0-20260402051712-545e8a4df936/go.mod h1:MxpfABSjhmINe3F1It9d+8exIHFvUqtLIRCdOGNXqiI= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.7 h1:X+2YciYSxvMQK0UZ7sg45ZVabVZBeBuvMkmuI2V3Fak= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.7/go.mod h1:lW34nIZuQ8UDPdkon5fmfp2l3+ZkQ2me/+oecHYLOII= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 h1:5VipnvEpbqr2gA2VbM+nYVbkIF28c5ZQfqCBQ5g2xfk= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0/go.mod h1:Hyl3n6Twe1hvtd9XUXDec4pTvgMSEixRuQKPTMH2bNs= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= @@ -95,33 +94,27 @@ github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFd github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= -github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= -github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= -github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= -github.com/onsi/gomega v1.40.0 h1:Vtol0e1MghCD2ZVIilPDIg44XSL9l2QAn8ZNaljWcJc= -github.com/onsi/gomega v1.40.0/go.mod h1:M/Uqpu/8qTjtzCLUA2zJHX9Iilrau25x1PdoSRbWh5A= +github.com/onsi/ginkgo/v2 v2.32.1 h1:6tlvcDm/3sE8lGJbZ4+d4mO3RLy24/tQWOFzVSQNIfw= +github.com/onsi/ginkgo/v2 v2.32.1/go.mod h1:+aXOY+vzZ5mu2iI2HpTZUPmM//oQfsNFX6gU9kNcA44= +github.com/onsi/gomega v1.43.0 h1:VlG/1FxqNxhSO+lq/OHBNaaqwiBK/mO8JbVkX9Y+FeU= +github.com/onsi/gomega v1.43.0/go.mod h1:REff/hsDsodHoKlWsP2mAPhu1+5/6hVYNf9rIEBpeSg= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o= -github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg= +github.com/prometheus/client_golang v1.24.0 h1:5XStIklKuAtJSNpdD3s8XJj/Yv78IQmE1kbNk87JrAI= +github.com/prometheus/client_golang v1.24.0/go.mod h1:QcsNdotprC2nS4BTM2ucbcqxd2CeXTEa9jW7zHO9iDE= github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= -github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4= -github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw= -github.com/prometheus/procfs v0.20.1 h1:XwbrGOIplXW/AU3YhIhLODXMJYyC1isLFfYCsTEycfc= -github.com/prometheus/procfs v0.20.1/go.mod h1:o9EMBZGRyvDrSPH1RqdxhojkuXstoe4UlK79eF5TGGo= -github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= -github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= +github.com/prometheus/common v0.70.0 h1:bcpru3tWPVnxGnETLgOV5jbp/JRXgYEyv65CuBLAMMI= +github.com/prometheus/common v0.70.0/go.mod h1:S/SFasQmgGiYH6C81LKCtYa8QACgthGg5zxL2udV7SY= +github.com/prometheus/procfs v0.21.1 h1:GljZCt+zSTS+NZq88cyQ1LjZ+RCHp3uVuabBWA5+OJI= +github.com/prometheus/procfs v0.21.1/go.mod h1:aB55Cww9pdSJVHk0hUf0inxWyyjPogFIjmHKYgMKmtY= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU= github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4= github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs= -github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= @@ -135,102 +128,97 @@ github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.65.0 h1:7iP2uCb7sGddAr30RRS6xjKy7AZ2JtTOPA3oolgVSw8= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.65.0/go.mod h1:c7hN3ddxs/z6q9xwvfLPk+UHlWRQyaeR1LdgfL/66l0= -go.opentelemetry.io/otel v1.41.0 h1:YlEwVsGAlCvczDILpUXpIpPSL/VPugt7zHThEMLce1c= -go.opentelemetry.io/otel v1.41.0/go.mod h1:Yt4UwgEKeT05QbLwbyHXEwhnjxNO6D8L5PQP51/46dE= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.40.0 h1:QKdN8ly8zEMrByybbQgv8cWBcdAarwmIPZ6FThrWXJs= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.40.0/go.mod h1:bTdK1nhqF76qiPoCCdyFIV+N/sRHYXYCTQc+3VCi3MI= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.40.0 h1:DvJDOPmSWQHWywQS6lKL+pb8s3gBLOZUtw4N+mavW1I= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.40.0/go.mod h1:EtekO9DEJb4/jRyN4v4Qjc2yA7AtfCBuz2FynRUWTXs= -go.opentelemetry.io/otel/metric v1.41.0 h1:rFnDcs4gRzBcsO9tS8LCpgR0dxg4aaxWlJxCno7JlTQ= -go.opentelemetry.io/otel/metric v1.41.0/go.mod h1:xPvCwd9pU0VN8tPZYzDZV/BMj9CM9vs00GuBjeKhJps= -go.opentelemetry.io/otel/sdk v1.40.0 h1:KHW/jUzgo6wsPh9At46+h4upjtccTmuZCFAc9OJ71f8= -go.opentelemetry.io/otel/sdk v1.40.0/go.mod h1:Ph7EFdYvxq72Y8Li9q8KebuYUr2KoeyHx0DRMKrYBUE= -go.opentelemetry.io/otel/trace v1.41.0 h1:Vbk2co6bhj8L59ZJ6/xFTskY+tGAbOnCtQGVVa9TIN0= -go.opentelemetry.io/otel/trace v1.41.0/go.mod h1:U1NU4ULCoxeDKc09yCWdWe+3QoyweJcISEVa1RBzOis= -go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A= -go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0 h1:8tvICD4vSTOOsNrsI4Ljf6C+6UKvpTEH5XY3JMoyPoo= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0/go.mod h1:z9+yiacE0IHRqM4qFfkbt/JYlmYXgss8GY/jXoNuPJI= +go.opentelemetry.io/otel v1.44.0 h1:JjwHmHpA4iZ3wBxluu2fbbE7j4kqlE8jXyAyPXH7HqU= +go.opentelemetry.io/otel v1.44.0/go.mod h1:BMgjTHL9WPRlRjL2oZCBTL4whCGtXch2H4BhOPIAyYc= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.44.0 h1:4YsVu3B8+3qtWYYrsUYgn0OG78pN0rnNPRGX4SbokQI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.44.0/go.mod h1:+wnlSn0mD1ADVMe3v9Z/WIaiz6q6gL2J/ejaAmdmv80= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.44.0 h1:qazEJlUOQzhCpzQpFETGby7EdqjI1wsd0W+6Gg1SCTU= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.44.0/go.mod h1:fOD2Yefuxixkx3ahVNf0O/PERb6r4OlbxfATVnYvzCo= +go.opentelemetry.io/otel/metric v1.44.0 h1:1w0gILTcHdr3YI+ixLyjemwrVnsMURbTZFrSYCdDdmc= +go.opentelemetry.io/otel/metric v1.44.0/go.mod h1:8O7hanEPBNgEMmybD3s2VBKcgWOCsA6tzHBPODAiquo= +go.opentelemetry.io/otel/sdk v1.44.0 h1:nHYwb9lK+fJPU/dnT6s7W7Z8itMWyqrnVfbheVYrZ58= +go.opentelemetry.io/otel/sdk v1.44.0/go.mod h1:Osuydd3Se74nqjAKxid74N5eC+jfEqfTegHRnq58oK0= +go.opentelemetry.io/otel/trace v1.44.0 h1:jxF5CsGYCe74MCRx2X4g7WsY/VBKRqqpNvXlX/6gtIk= +go.opentelemetry.io/otel/trace v1.44.0/go.mod h1:oLl1jrMQAVo6v3GAggN+1VH9VIz9iUSvW53sW1Q8PIE= +go.opentelemetry.io/proto/otlp v1.10.0 h1:IQRWgT5srOCYfiWnpqUYz9CVmbO8bFmKcwYxpuCSL2g= +go.opentelemetry.io/proto/otlp v1.10.0/go.mod h1:/CV4QoCR/S9yaPj8utp3lvQPoqMtxXdzn7ozvvozVqk= go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ= go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ= -go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= -golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 h1:fQsdNF2N+/YewlRZiricy4P1iimyPKZ/xwniHj8Q2a0= -golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93/go.mod h1:EPRbTFwzwjXj9NpYyyrvenVh9Y+GFeEvMNh7Xuz7xgU= -golang.org/x/mod v0.35.0 h1:Ww1D637e6Pg+Zb2KrWfHQUnH2dQRLBQyAtpr/haaJeM= -golang.org/x/mod v0.35.0/go.mod h1:+GwiRhIInF8wPm+4AoT6L0FA1QWAad3OMdTRx4tFYlU= -golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8= -golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww= +go.yaml.in/yaml/v3 v3.0.5 h1:N6y/pJk8buWs9NY5ERU2HSMfm+IuD/OtfdAnq6kESPw= +go.yaml.in/yaml/v3 v3.0.5/go.mod h1:HVTZu1O7/Vkt2N+BFy8Zza+lnLsABggaTM2ZpNIGuKg= +golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f h1:W3F4c+6OLc6H2lb//N1q4WpJkhzJCK5J6kUi1NTVXfM= +golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f/go.mod h1:J1xhfL/vlindoeF/aINzNzt2Bket5bjo9sdOYzOsU80= +golang.org/x/mod v0.39.0 h1:UF5zwQdCRRUpHfyPwr7d4UrGiVeldIsogtzWVnczL74= +golang.org/x/mod v0.39.0/go.mod h1:bvIbwjQ0HUFFf5AKukeeYQG4ZBUG9yxQbR9aEweIwYY= +golang.org/x/net v0.58.0 h1:ynWG7rqYi4ccpTEuPZ2QGWHktVEM9DMCj9yzDE0Q7To= +golang.org/x/net v0.58.0/go.mod h1:YwCddHnFlT7eLQqVprV19OnhLGtc5xOKgE0RyqgfWAU= golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs= golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q= -golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= -golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= +golang.org/x/sync v0.22.0 h1:SZjpbeLmrCk4xhRSZFNZW5gFUeCeFgjekvI/+gfScek= +golang.org/x/sync v0.22.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY= -golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= -golang.org/x/term v0.43.0 h1:S4RLU2sB31O/NCl+zFN9Aru9A/Cq2aqKpTZJ6B+DwT4= -golang.org/x/term v0.43.0/go.mod h1:lrhlHNdQJHO+1qVYiHfFKVuVioJIheAc3fBSMFYEIsk= -golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc= -golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38= +golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs= +golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/term v0.45.0 h1:NwWyBmoJCbfTHpxrWoZ9C6/VxOf7ic219I8xZZFdrf0= +golang.org/x/term v0.45.0/go.mod h1:9aqxs0blBcrm/n0L9QW0aRVD+ktan8ssZromtqJC43w= +golang.org/x/text v0.41.0 h1:vz/seA0lnX87Othu2f/0L24RcgrXD9/YFTSuGjj3rH8= +golang.org/x/text v0.41.0/go.mod h1:jvf1O8ajNzZqhSrQBPbutR/EB83Cc0CFrezNQIwbb5M= golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U= golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno= -golang.org/x/tools v0.44.0 h1:UP4ajHPIcuMjT1GqzDWRlalUEoY+uzoZKnhOjbIPD2c= -golang.org/x/tools v0.44.0/go.mod h1:KA0AfVErSdxRZIsOVipbv3rQhVXTnlU6UhKxHd1seDI= +golang.org/x/tools v0.49.0 h1:3NI7VXzL9+1WZD52Dx2ttoPwD5DWrFGpl9mFZDlmisI= +golang.org/x/tools v0.49.0/go.mod h1:SJNXV9DBKT0UbdttsQjbfJlAE/q+y36++zo3uL3N0Oo= golang.org/x/tools/go/expect v0.1.1-deprecated h1:jpBZDwmgPhXsKZC6WhL20P4b/wmnpsEAGHaNy0n/rJM= 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= -google.golang.org/genproto/googleapis/api v0.0.0-20260128011058-8636f8732409 h1:merA0rdPeUV3YIIfHHcH4qBkiQAc1nfCKSI7lB4cV2M= -google.golang.org/genproto/googleapis/api v0.0.0-20260128011058-8636f8732409/go.mod h1:fl8J1IvUjCilwZzQowmw2b7HQB2eAuYBabMXzWurF+I= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260128011058-8636f8732409 h1:H86B94AW+VfJWDqFeEbBPhEtHzJwJfTbgE2lZa54ZAQ= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260128011058-8636f8732409/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ= -google.golang.org/grpc v1.79.3 h1:sybAEdRIEtvcD68Gx7dmnwjZKlyfuc61Dyo9pGXXkKE= -google.golang.org/grpc v1.79.3/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ= +google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa h1:Kjn0N0tCrDgiAFW+lGO4JZ3ck44CehvJQMAwj9QF0G8= +google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:q4lMZS6kskjT5HvCPrnnypcDPVJqT/f4nfxmkE7gryY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa h1:mZHHdPZl0dbGHCflZgAq/Q468DWVFcU2whhB2KAo8fk= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= +google.golang.org/grpc v1.82.1 h1:NnAxzGRA0677vCa4BUkOAnO5+FfQqVl9iUXeD0IqcGE= +google.golang.org/grpc v1.82.1/go.mod h1:yzTZ1TB1Z3SG+LIYaI+WiE8D5+PZ3ArnrSp8zF3+/ZA= google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af h1:+5/Sw3GsDNlEmu7TfklWKPdQ0Ykja5VEmq2i817+jbI= google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -k8s.io/api v0.36.0 h1:SgqDhZzHdOtMk40xVSvCXkP9ME0H05hPM3p9AB1kL80= -k8s.io/api v0.36.0/go.mod h1:m1LVrGPNYax5NBHdO+QuAedXyuzTt4RryI/qnmNvs34= -k8s.io/apiextensions-apiserver v0.36.0 h1:Wt7E8J+VBCbj4FjiBfDTK/neXDDjyJVJc7xfuOHImZ0= -k8s.io/apiextensions-apiserver v0.36.0/go.mod h1:kGDjH0msuiIB3tgsYRV0kS9GqpMYMUsQ3GHv7TApyug= -k8s.io/apimachinery v0.36.0 h1:jZyPzhd5Z+3h9vJLt0z9XdzW9VzNzWAUw+P1xZ9PXtQ= -k8s.io/apimachinery v0.36.0/go.mod h1:FklypaRJt6n5wUIwWXIP6GJlIpUizTgfo1T/As+Tyxc= -k8s.io/apiserver v0.36.0 h1:Jg5OFAENUACByUCg15CmhZAYrr5ZyJ+jodyA1mHl3YE= -k8s.io/apiserver v0.36.0/go.mod h1:mHvwdHf+qKEm+1/hYm756SV+oREOKSPnsjagOpx6Vho= -k8s.io/client-go v0.36.0 h1:pOYi7C4RHChYjMiHpZSpSbIM6ZxVbRXBy7CuiIwqA3c= -k8s.io/client-go v0.36.0/go.mod h1:ZKKcpwF0aLYfkHFCjillCKaTK/yBkEDHTDXCFY6AS9Y= -k8s.io/code-generator v0.36.0 h1:XWAkrhnArm0VWMmSFO7kyB+wE2LROwep7hEH0GPGkqA= -k8s.io/code-generator v0.36.0/go.mod h1:Tr2UhfBRdlyRoadfob9aPCmmGe8PUs5XPK9MEJ2nx+w= -k8s.io/component-base v0.36.0 h1:hFjEktssxiJhrK1zfybkH4kJOi8iZuF+mIDCqS5+jRo= -k8s.io/component-base v0.36.0/go.mod h1:JZvIfcNHk+uck+8LhJzhSBtydWXaZNQwX2OdL+Mnwsk= -k8s.io/gengo/v2 v2.0.0-20250922181213-ec3ebc5fd46b h1:gMplByicHV/TJBizHd9aVEsTYoJBnnUAT5MHlTkbjhQ= -k8s.io/gengo/v2 v2.0.0-20250922181213-ec3ebc5fd46b/go.mod h1:CgujABENc3KuTrcsdpGmrrASjtQsWCT7R99mEV4U/fM= +k8s.io/api v0.37.0 h1:Z//Vj9N7RA/yS2sDmxyeo7h+RR4zbUrd2vrd3Z0TbB4= +k8s.io/api v0.37.0/go.mod h1:LKXgcJWMc+f4OLbP5SFR8rulEg07zZhpi/zMULiBImk= +k8s.io/apiextensions-apiserver v0.37.0 h1:zRMQ3+/LIE5oZ0tVvXwYHC+dIkSP5cjNWju7AZU1LOI= +k8s.io/apiextensions-apiserver v0.37.0/go.mod h1:HU0PfSBwchHL5iDau6jjt9zU6ryWkDDlaVUiq91NK80= +k8s.io/apimachinery v0.37.0 h1:Np2AbDtf8x6RDHiD8T9LbKJ9gaegeVNa8yNm5FuGKm0= +k8s.io/apimachinery v0.37.0/go.mod h1:RN3nhprFSCxOi5Selxd7oMTXOe/c+ZbcE7Im+TS2zkE= +k8s.io/apiserver v0.37.0 h1:TXg7OxsOWrAH8J4Zi/gBAZuMw1Dfdd+6cca2h4qjRqo= +k8s.io/apiserver v0.37.0/go.mod h1:OddHDF4gy9qyIb8o/3+qaeP6S0vEObWLgOygVqXksv0= +k8s.io/client-go v0.37.0 h1:nsN31fy8wBySuZ+QRnKmrjRSQLOG2rvoGN0tKd12zhQ= +k8s.io/client-go v0.37.0/go.mod h1:FcGqw+Ll/gNQiq+nPGY1Oyt9y7SgDh1d3MW3RFDEbn0= +k8s.io/code-generator v0.37.0 h1:AC915wukzlVHHODAQYxvQ25WKibPh95faJ2kxf8dzuo= +k8s.io/code-generator v0.37.0/go.mod h1:qg7E/uDlyvevVRL1V8+h2z9UWmi/8gxaRka/lVXUBdk= +k8s.io/component-base v0.37.0 h1:3SdSa4+itMdFTDFTeR8CxKGmSTSMXFlKL4ky8OqjguM= +k8s.io/component-base v0.37.0/go.mod h1:LjOebp4R9y6LODWZQv102ZQxGheLcDO2ZJLAw6bbh4I= +k8s.io/gengo/v2 v2.0.0-20260408192533-25e2208e0dc3 h1:3L6PNkMLXkU/pz3jWzaaIUz0Rs2V9h+5O51AeRC7poc= +k8s.io/gengo/v2 v2.0.0-20260408192533-25e2208e0dc3/go.mod h1:yvyl3l9E+UxlqOMUULdKTAYB0rEhsmjr7+2Vb/1pCSo= k8s.io/klog/v2 v2.140.0 h1:Tf+J3AH7xnUzZyVVXhTgGhEKnFqye14aadWv7bzXdzc= k8s.io/klog/v2 v2.140.0/go.mod h1:o+/RWfJ6PwpnFn7OyAG3QnO47BFsymfEfrz6XyYSSp0= -k8s.io/kube-openapi v0.0.0-20260427204847-8949caaa1199 h1:sWu4Td5mgJlwunsUydnhKEAfNUHM7hm1wfKEQmD7G5c= -k8s.io/kube-openapi v0.0.0-20260427204847-8949caaa1199/go.mod h1:uGBT7iTA6c6MvqUvSXIaYZo9ukscABYi2btjhvgKGZ0= -k8s.io/utils v0.0.0-20260319190234-28399d86e0b5 h1:kBawHLSnx/mYHmRnNUf9d4CpjREbeZuxoSGOX/J+aYM= -k8s.io/utils v0.0.0-20260319190234-28399d86e0b5/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.34.0 h1:hSfpvjjTQXQY2Fol2CS0QHMNs/WI1MOSGzCm1KhM5ec= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.34.0/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw= -sigs.k8s.io/controller-tools v0.21.0 h1:KXDQza3bgjlPY6xLR63tI/40gzjhyUAvkCrwzd2/6cs= -sigs.k8s.io/controller-tools v0.21.0/go.mod h1:DLIypi3Q2+azVAP8jr/mHXJgveYYHFjhnNOUuBJ10JE= +k8s.io/kube-openapi v0.0.0-20260721132016-d427ff9ee9ad h1:oXImqH8mQNk7PmvzKhmN3ddJoY6OnyM225MXwGHPm0A= +k8s.io/kube-openapi v0.0.0-20260721132016-d427ff9ee9ad/go.mod h1:0/mqHCVhlumdJ3BhCfnjSZQE037nAhNodh1/hK0T8/I= +k8s.io/utils v0.0.0-20260626114624-be93311217bd h1:Ea7fgQ5we8Y9T0OX5o0dAHzQOBRI07D/dEYRaB9ZZEs= +k8s.io/utils v0.0.0-20260626114624-be93311217bd/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.36.0 h1:/YpDJ4vReG7ZmzSpBGxduXgywWkJU9zHubgJG03MT+Y= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.36.0/go.mod h1:tJo1aepTXyR+8Xs3sUsGBDk4Ub2AM5dPAPKJx0mpm5c= +sigs.k8s.io/controller-tools v0.22.0 h1:eG3FAVja/KnlXKIWg95udIFz1cMyAtMjP11cqBh3t+k= +sigs.k8s.io/controller-tools v0.22.0/go.mod h1:VizwUStoZK7rReCj704czGGrB7mLxXTiJSJt7wN5ilI= sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg= sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v6 v6.4.0 h1:qmp2e3ZfFi1/jJbDGpD4mt3wyp6PE1NfKHCYLqgNQJo= -sigs.k8s.io/structured-merge-diff/v6 v6.4.0/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= +sigs.k8s.io/structured-merge-diff/v6 v6.4.2 h1:qdOxHwrl2Kaag1aQEarlYcOA9vSyGCp3CIki3aW8c4Q= +sigs.k8s.io/structured-merge-diff/v6 v6.4.2/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/operator/tools/envtest/go.mod b/operator/tools/envtest/go.mod index b09764af31e09..61430b14f0fbd 100644 --- a/operator/tools/envtest/go.mod +++ b/operator/tools/envtest/go.mod @@ -2,7 +2,7 @@ module github.com/stackrox/rox/operator/tools/envtest go 1.26.3 -require sigs.k8s.io/controller-runtime/tools/setup-envtest v0.24.1 +require sigs.k8s.io/controller-runtime/tools/setup-envtest v0.25.1 require ( github.com/go-logr/logr v1.4.3 // indirect @@ -11,7 +11,7 @@ require ( github.com/spf13/pflag v1.0.10 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.1 // indirect - go.yaml.in/yaml/v2 v2.4.3 // indirect - golang.org/x/text v0.34.0 // indirect + go.yaml.in/yaml/v2 v2.4.4 // indirect + golang.org/x/text v0.40.0 // indirect sigs.k8s.io/yaml v1.6.0 // indirect ) diff --git a/operator/tools/envtest/go.sum b/operator/tools/envtest/go.sum index 2c1eb021c9a07..83ff5ea829f9d 100644 --- a/operator/tools/envtest/go.sum +++ b/operator/tools/envtest/go.sum @@ -30,31 +30,29 @@ go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= -go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= -go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= +go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ= +go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= -golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c= -golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU= -golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o= -golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8= -golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= -golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= -golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= -golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= -golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= -golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc= -golang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg= +golang.org/x/mod v0.37.0 h1:vF1DjpVEshcIqoEaauuHebaLk1O1forxjxBaVn884JQ= +golang.org/x/mod v0.37.0/go.mod h1:m8S8VeM9r4dzDwjrKO0a1sZP3YjeMamRRlD+fmR2Q/0= +golang.org/x/net v0.57.0 h1:K5+3DljvIuDG9/Jv9rvyMywYNFCQ9RSUY6OOTTkT+tE= +golang.org/x/net v0.57.0/go.mod h1:KpXc8iv+r3XplLAG/f7Jsf9RPszJzdR0f58q9vGOuEU= +golang.org/x/sync v0.22.0 h1:SZjpbeLmrCk4xhRSZFNZW5gFUeCeFgjekvI/+gfScek= +golang.org/x/sync v0.22.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= +golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs= +golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/text v0.40.0 h1:Ub2Z6/xjgF1WrYQz2nuITOEegKFtiIy+rieRJ5lHZKs= +golang.org/x/text v0.40.0/go.mod h1:hpnzDAfGV753zIKo+wk3u1bVKCGPbrnF7+7LBF/UHVY= +golang.org/x/tools v0.47.0 h1:7Kn5x/d1svx/PzryTsqeoZN4TZwqeH5pGWjefhLi/1Q= +golang.org/x/tools v0.47.0/go.mod h1:dFHnyTvFWY212G+h7ZY4Vsp/K3U4/7W9TyVaAul8uCA= google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af h1:+5/Sw3GsDNlEmu7TfklWKPdQ0Ykja5VEmq2i817+jbI= google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -k8s.io/apimachinery v0.36.0 h1:jZyPzhd5Z+3h9vJLt0z9XdzW9VzNzWAUw+P1xZ9PXtQ= -k8s.io/apimachinery v0.36.0/go.mod h1:FklypaRJt6n5wUIwWXIP6GJlIpUizTgfo1T/As+Tyxc= -sigs.k8s.io/controller-runtime/tools/setup-envtest v0.24.1 h1:l2AjyGE/PWub6EB165ij4/bpCK0TlY5NlhzIHfmGvmg= -sigs.k8s.io/controller-runtime/tools/setup-envtest v0.24.1/go.mod h1:wpkYufRHTSw9ABET21/PkEL7kdGnmiZJ6o72t9p/1I8= +k8s.io/apimachinery v0.37.0 h1:Np2AbDtf8x6RDHiD8T9LbKJ9gaegeVNa8yNm5FuGKm0= +k8s.io/apimachinery v0.37.0/go.mod h1:RN3nhprFSCxOi5Selxd7oMTXOe/c+ZbcE7Im+TS2zkE= +sigs.k8s.io/controller-runtime/tools/setup-envtest v0.25.1 h1:OYp0AfSZ1zr338OwcQC4PsyBuaHjkgHEfPuNFTFqw2Y= +sigs.k8s.io/controller-runtime/tools/setup-envtest v0.25.1/go.mod h1:q4i4kLTq6J6o29RUAQieHH8LS5knNkpgalnBhvrLp/8= sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/operator/tools/kubebuilder/go.mod b/operator/tools/kubebuilder/go.mod index 0225addfc86f7..adba09128eb2b 100644 --- a/operator/tools/kubebuilder/go.mod +++ b/operator/tools/kubebuilder/go.mod @@ -2,7 +2,7 @@ module github.com/stackrox/rox/operator/tools/kubebuilder go 1.26.3 -require sigs.k8s.io/kubebuilder/v4 v4.15.0 +require sigs.k8s.io/kubebuilder/v4 v4.16.0 require ( github.com/fxamacker/cbor/v2 v2.9.1 // indirect @@ -10,7 +10,6 @@ require ( github.com/gobuffalo/flect v1.0.3 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/kr/pretty v0.3.1 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect github.com/spf13/afero v1.15.0 // indirect @@ -18,19 +17,19 @@ require ( github.com/spf13/pflag v1.0.10 // indirect github.com/x448/float16 v0.8.4 // indirect go.yaml.in/yaml/v2 v2.4.4 // indirect - go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/mod v0.37.0 // indirect - golang.org/x/net v0.56.0 // indirect - golang.org/x/sync v0.21.0 // indirect - golang.org/x/text v0.38.0 // indirect - golang.org/x/tools v0.46.0 // indirect + go.yaml.in/yaml/v3 v3.0.5 // indirect + golang.org/x/mod v0.41.0 // indirect + golang.org/x/net v0.58.0 // indirect + golang.org/x/sync v0.22.0 // indirect + golang.org/x/text v0.41.0 // indirect + golang.org/x/tools v0.49.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect - k8s.io/apimachinery v0.36.2 // indirect + k8s.io/apimachinery v0.37.0 // indirect k8s.io/klog/v2 v2.140.0 // indirect - k8s.io/kube-openapi v0.0.0-20260414162039-ec9c827d403f // indirect - k8s.io/utils v0.0.0-20260319190234-28399d86e0b5 // indirect + k8s.io/kube-openapi v0.0.0-20260721132016-d427ff9ee9ad // indirect + k8s.io/utils v0.0.0-20260626114624-be93311217bd // indirect sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/randfill v1.0.0 // indirect - sigs.k8s.io/structured-merge-diff/v6 v6.4.0 // indirect + sigs.k8s.io/structured-merge-diff/v6 v6.4.2 // indirect sigs.k8s.io/yaml v1.6.0 // indirect ) diff --git a/operator/tools/kubebuilder/go.sum b/operator/tools/kubebuilder/go.sum index 7577d7cafe457..c18e6f79e30c3 100644 --- a/operator/tools/kubebuilder/go.sum +++ b/operator/tools/kubebuilder/go.sum @@ -1,7 +1,6 @@ github.com/Masterminds/semver/v3 v3.5.0 h1:kQceYJfbupGfZOKZQg0kou0DgAKhzDg2NZPAwZ/2OOE= github.com/Masterminds/semver/v3 v3.5.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= @@ -27,27 +26,19 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/onsi/ginkgo/v2 v2.30.0 h1:zxM/9XneXFIy64j6/wAmBIX4zRC7Hu6U8XFNZvDnCQc= -github.com/onsi/ginkgo/v2 v2.30.0/go.mod h1:+aXOY+vzZ5mu2iI2HpTZUPmM//oQfsNFX6gU9kNcA44= -github.com/onsi/gomega v1.41.0 h1:OwKp4pXNgVxf6sCplzYo794OFNuoL2q2SBMU5NSWOjA= -github.com/onsi/gomega v1.41.0/go.mod h1:M/Uqpu/8qTjtzCLUA2zJHX9Iilrau25x1PdoSRbWh5A= -github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/onsi/ginkgo/v2 v2.32.1 h1:6tlvcDm/3sE8lGJbZ4+d4mO3RLy24/tQWOFzVSQNIfw= +github.com/onsi/ginkgo/v2 v2.32.1/go.mod h1:+aXOY+vzZ5mu2iI2HpTZUPmM//oQfsNFX6gU9kNcA44= +github.com/onsi/gomega v1.43.0 h1:VlG/1FxqNxhSO+lq/OHBNaaqwiBK/mO8JbVkX9Y+FeU= +github.com/onsi/gomega v1.43.0/go.mod h1:REff/hsDsodHoKlWsP2mAPhu1+5/6hVYNf9rIEBpeSg= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= -github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg= @@ -69,43 +60,42 @@ github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ= go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ= -go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= -golang.org/x/mod v0.37.0 h1:vF1DjpVEshcIqoEaauuHebaLk1O1forxjxBaVn884JQ= -golang.org/x/mod v0.37.0/go.mod h1:m8S8VeM9r4dzDwjrKO0a1sZP3YjeMamRRlD+fmR2Q/0= -golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o= -golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec= -golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM= -golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= -golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw= -golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= -golang.org/x/text v0.38.0 h1:sXmwo9DwP3OK9EZ7PqAdaooSGozfl/3a6/xJcbzPRhE= -golang.org/x/text v0.38.0/go.mod h1:YXZt3QhHUKYT53r2lLKFIVi6Ao1jdzrTR/KQ09qyxF4= -golang.org/x/tools v0.46.0 h1:7jTurBkPZu4moS/Uy4OQT1M+QBlsj3wejyZwsT8Z7rk= -golang.org/x/tools v0.46.0/go.mod h1:FrD85F8l+NWL+9XWBSyVSHO6Ne4jutsfIFba7AWQ5Ys= +go.yaml.in/yaml/v3 v3.0.5 h1:N6y/pJk8buWs9NY5ERU2HSMfm+IuD/OtfdAnq6kESPw= +go.yaml.in/yaml/v3 v3.0.5/go.mod h1:HVTZu1O7/Vkt2N+BFy8Zza+lnLsABggaTM2ZpNIGuKg= +golang.org/x/mod v0.41.0 h1:qJmnOUb4YB+FsEuM3HcWucdZASCPGhsX6uljO6pog0c= +golang.org/x/mod v0.41.0/go.mod h1:Ek9pY8RKWXwsWvd3rQiHYtMqkjSUV+s1Rj7j4H5Ur6o= +golang.org/x/net v0.58.0 h1:ynWG7rqYi4ccpTEuPZ2QGWHktVEM9DMCj9yzDE0Q7To= +golang.org/x/net v0.58.0/go.mod h1:YwCddHnFlT7eLQqVprV19OnhLGtc5xOKgE0RyqgfWAU= +golang.org/x/sync v0.22.0 h1:SZjpbeLmrCk4xhRSZFNZW5gFUeCeFgjekvI/+gfScek= +golang.org/x/sync v0.22.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= +golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs= +golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/text v0.41.0 h1:vz/seA0lnX87Othu2f/0L24RcgrXD9/YFTSuGjj3rH8= +golang.org/x/text v0.41.0/go.mod h1:jvf1O8ajNzZqhSrQBPbutR/EB83Cc0CFrezNQIwbb5M= +golang.org/x/tools v0.49.0 h1:3NI7VXzL9+1WZD52Dx2ttoPwD5DWrFGpl9mFZDlmisI= +golang.org/x/tools v0.49.0/go.mod h1:SJNXV9DBKT0UbdttsQjbfJlAE/q+y36++zo3uL3N0Oo= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -k8s.io/apimachinery v0.36.2 h1:0PE/W/WNy1UX61NLbXY5TMbJ6UwLL6E6lAPkYrKFxbQ= -k8s.io/apimachinery v0.36.2/go.mod h1:fvf/HOLXq9RId0rnDIbN1OEBvHXdQbLMM8nu0LcBUf4= +k8s.io/apimachinery v0.37.0 h1:Np2AbDtf8x6RDHiD8T9LbKJ9gaegeVNa8yNm5FuGKm0= +k8s.io/apimachinery v0.37.0/go.mod h1:RN3nhprFSCxOi5Selxd7oMTXOe/c+ZbcE7Im+TS2zkE= k8s.io/klog/v2 v2.140.0 h1:Tf+J3AH7xnUzZyVVXhTgGhEKnFqye14aadWv7bzXdzc= k8s.io/klog/v2 v2.140.0/go.mod h1:o+/RWfJ6PwpnFn7OyAG3QnO47BFsymfEfrz6XyYSSp0= -k8s.io/kube-openapi v0.0.0-20260414162039-ec9c827d403f h1:4Qiq0YAoQATdgmHALJWz9rJ4fj20pB3xebpB4CFNhYM= -k8s.io/kube-openapi v0.0.0-20260414162039-ec9c827d403f/go.mod h1:uGBT7iTA6c6MvqUvSXIaYZo9ukscABYi2btjhvgKGZ0= -k8s.io/utils v0.0.0-20260319190234-28399d86e0b5 h1:kBawHLSnx/mYHmRnNUf9d4CpjREbeZuxoSGOX/J+aYM= -k8s.io/utils v0.0.0-20260319190234-28399d86e0b5/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk= +k8s.io/kube-openapi v0.0.0-20260721132016-d427ff9ee9ad h1:oXImqH8mQNk7PmvzKhmN3ddJoY6OnyM225MXwGHPm0A= +k8s.io/kube-openapi v0.0.0-20260721132016-d427ff9ee9ad/go.mod h1:0/mqHCVhlumdJ3BhCfnjSZQE037nAhNodh1/hK0T8/I= +k8s.io/utils v0.0.0-20260626114624-be93311217bd h1:Ea7fgQ5we8Y9T0OX5o0dAHzQOBRI07D/dEYRaB9ZZEs= +k8s.io/utils v0.0.0-20260626114624-be93311217bd/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk= sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg= sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= -sigs.k8s.io/kubebuilder/v4 v4.15.0 h1:LiTS6XCCmhxS0P7OXwpVqcoywlvbF3yK8G+tZjZF62A= -sigs.k8s.io/kubebuilder/v4 v4.15.0/go.mod h1:3Q0bwaT7zJg9V1wSqYOCClA29iAYkR9CVe+iqMuBg1w= +sigs.k8s.io/kubebuilder/v4 v4.16.0 h1:ay3e//yOWy2Jmi3JZnF8esrtCi0+/6jiPXiRtmW0Wu8= +sigs.k8s.io/kubebuilder/v4 v4.16.0/go.mod h1:ghrV2jGJIxjPVnzALWGVZyfpzIMzpMnN/LcYg7pZuZc= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v6 v6.4.0 h1:qmp2e3ZfFi1/jJbDGpD4mt3wyp6PE1NfKHCYLqgNQJo= -sigs.k8s.io/structured-merge-diff/v6 v6.4.0/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= +sigs.k8s.io/structured-merge-diff/v6 v6.4.2 h1:qdOxHwrl2Kaag1aQEarlYcOA9vSyGCp3CIki3aW8c4Q= +sigs.k8s.io/structured-merge-diff/v6 v6.4.2/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/operator/tools/kustomize/go.mod b/operator/tools/kustomize/go.mod index d3f33a6e89ea5..2ab7c7f278b5c 100644 --- a/operator/tools/kustomize/go.mod +++ b/operator/tools/kustomize/go.mod @@ -1,36 +1,31 @@ module github.com/stackrox/rox/operator/tools/kustomize -go 1.26.3 +go 1.27.0 -require sigs.k8s.io/kustomize/kustomize/v5 v5.8.1 +require sigs.k8s.io/kustomize/kustomize/v5 v5.8.3 require ( github.com/blang/semver/v4 v4.0.0 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/go-errors/errors v1.4.2 // indirect - github.com/go-openapi/jsonpointer v0.21.0 // indirect - github.com/go-openapi/jsonreference v0.20.2 // indirect - github.com/go-openapi/swag v0.23.0 // indirect - github.com/google/gnostic-models v0.6.9 // indirect + github.com/go-errors/errors v1.5.1 // indirect + github.com/go-openapi/jsonpointer v1.0.0 // indirect + github.com/go-openapi/jsonreference v1.0.0 // indirect + github.com/google/gnostic-models v0.7.1 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/josharian/intern v1.0.0 // indirect - github.com/mailru/easyjson v0.7.7 // indirect github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect github.com/sergi/go-diff v1.4.0 // indirect - github.com/spf13/cobra v1.9.1 // indirect - github.com/spf13/pflag v1.0.6 // indirect + github.com/spf13/cobra v1.10.2 // indirect + github.com/spf13/pflag v1.0.10 // indirect github.com/xlab/treeprint v1.2.0 // indirect - go.yaml.in/yaml/v2 v2.4.2 // indirect - go.yaml.in/yaml/v3 v3.0.3 // indirect - golang.org/x/sys v0.35.0 // indirect - golang.org/x/text v0.28.0 // indirect - google.golang.org/protobuf v1.36.5 // indirect + go.yaml.in/yaml/v2 v2.4.4 // indirect + go.yaml.in/yaml/v3 v3.0.5 // indirect + golang.org/x/sys v0.48.0 // indirect + golang.org/x/text v0.42.0 // indirect + google.golang.org/protobuf v1.36.12 // indirect gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/kube-openapi v0.0.0-20241212222426-2c72e554b1e7 // indirect - sigs.k8s.io/kustomize/api v0.21.1 // indirect - sigs.k8s.io/kustomize/cmd/config v0.21.1 // indirect - sigs.k8s.io/kustomize/kyaml v0.21.1 // indirect - sigs.k8s.io/yaml v1.5.0 // indirect + k8s.io/kube-openapi v0.0.0-20261001230523-97fa35140926 // indirect + sigs.k8s.io/kustomize/api v0.21.3 // indirect + sigs.k8s.io/kustomize/cmd/config v0.21.3 // indirect + sigs.k8s.io/kustomize/kyaml v0.21.3 // indirect + sigs.k8s.io/yaml v1.6.0 // indirect ) diff --git a/operator/tools/kustomize/go.sum b/operator/tools/kustomize/go.sum index ce3be4ca9c359..12247c596d1ac 100644 --- a/operator/tools/kustomize/go.sum +++ b/operator/tools/kustomize/go.sum @@ -1,83 +1,60 @@ github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= -github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= -github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= -github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= -github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= -github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= -github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= -github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= -github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= -github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= -github.com/google/gnostic-models v0.6.9 h1:MU/8wDLif2qCXZmzncUQ/BOfxWfthHi63KqpoNbWqVw= -github.com/google/gnostic-models v0.6.9/go.mod h1:CiWsm0s6BSQd1hRn8/QmxqB6BesYcbSZxsz9b0KuDBw= +github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8bk= +github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= +github.com/go-openapi/jsonpointer v1.0.0 h1:kR9tHqY0CtZaOPVFm622dPVNhrvYpwr4uCxgL3h1H8s= +github.com/go-openapi/jsonpointer v1.0.0/go.mod h1:Z3rw7dWu1p9IgitXCFamSlA5lmDiklEB6vkaxcNZW5Y= +github.com/go-openapi/jsonreference v1.0.0 h1:jlmTr6torcd1YgDQvSfNmRtKzYDO4FGBkrAdlAVWnpY= +github.com/go-openapi/jsonreference v1.0.0/go.mod h1:jtwdyGbJk0Xhe5Y+rwtglQP6Sb1WZST4rT32LWB+sv0= +github.com/go-openapi/testify/v2 v2.6.0 h1:5PKH2HE7YJ/LuRPQGvSxBRlFXNQhSetBLlGAgUEu3ug= +github.com/go-openapi/testify/v2 v2.6.0/go.mod h1:SgsVHtfooshd0tublTtJ50FPKhujf47YRqauXXOUxfw= +github.com/google/gnostic-models v0.7.1 h1:SisTfuFKJSKM5CPZkffwi6coztzzeYUhc3v4yxLWH8c= +github.com/google/gnostic-models v0.7.1/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ= 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/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= -github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= -github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= 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/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0= github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= -github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sergi/go-diff v1.4.0 h1:n/SP9D5ad1fORl+llWyN+D6qoUETXNZARKjyY2/KVCw= github.com/sergi/go-diff v1.4.0/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= -github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= -github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= -github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= -github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU= +github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4= +github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= +github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/objx v0.5.3 h1:jmXUvGomnU1o3W/V5h2VEradbpJDwGrzugQQvL0POH4= +github.com/stretchr/objx v0.5.3/go.mod h1:rDQraq+vQZU7Fde9LOZLr8Tax6zZvy4kuNKF+QYS+U0= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -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.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.12.1 h1:EuwCh5fleGS7H32xRwO3wRGT7DxrDhLAT6FF8MpWDWE= +github.com/stretchr/testify v1.12.1/go.mod h1:MDEgiDPPsNp5cuIrHPPCyornHKgEVbtFUmoNlxoYthg= github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ= github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= -go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI= -go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU= -go.yaml.in/yaml/v3 v3.0.3 h1:bXOww4E/J3f66rav3pX3m8w6jDE4knZjGOw8b5Y6iNE= -go.yaml.in/yaml/v3 v3.0.3/go.mod h1:tBHosrYAkRZjRAOREWbDnBXUf08JOwYq++0QNwQiWzI= -golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= -golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= -golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= -google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= -google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ= +go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ= +go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= +go.yaml.in/yaml/v3 v3.0.5 h1:N6y/pJk8buWs9NY5ERU2HSMfm+IuD/OtfdAnq6kESPw= +go.yaml.in/yaml/v3 v3.0.5/go.mod h1:HVTZu1O7/Vkt2N+BFy8Zza+lnLsABggaTM2ZpNIGuKg= +golang.org/x/sys v0.48.0 h1:bbX/i/6MgT9BVLM9RT1thmxL04yeTAhbEz4SyadbXoo= +golang.org/x/sys v0.48.0/go.mod h1:hNLxWAXmnKAxqDtdwIYC4bM9oQPEecfsnNMuSxOs3og= +golang.org/x/text v0.42.0 h1:JbOZXgfeCPU9gacVtYliJqOhD+zhrEqK4LfdpmlUZqI= +golang.org/x/text v0.42.0/go.mod h1:ojzP1Z+2QtioaF8DTtO8K5q7JWVVYwZKenzujK0Zd0E= +google.golang.org/protobuf v1.36.12 h1:pJOKDDOyeXErUroCihFAd5LQuwXBSpVnKGrj5o/fwxc= +google.golang.org/protobuf v1.36.12/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/evanphx/json-patch.v4 v4.13.0 h1:czT3CmqEaQ1aanPc5SdlgQrrEIb8w/wwCvWWnfEbYzo= gopkg.in/evanphx/json-patch.v4 v4.13.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= @@ -85,19 +62,19 @@ gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -k8s.io/kube-openapi v0.0.0-20241212222426-2c72e554b1e7 h1:hcha5B1kVACrLujCKLbr8XWMxCxzQx42DY8QKYJrDLg= -k8s.io/kube-openapi v0.0.0-20241212222426-2c72e554b1e7/go.mod h1:GewRfANuJ70iYzvn+i4lezLDAFzvjxZYK1gn1lWcfas= -sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= -sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= -sigs.k8s.io/kustomize/api v0.21.1 h1:lzqbzvz2CSvsjIUZUBNFKtIMsEw7hVLJp0JeSIVmuJs= -sigs.k8s.io/kustomize/api v0.21.1/go.mod h1:f3wkKByTrgpgltLgySCntrYoq5d3q7aaxveSagwTlwI= -sigs.k8s.io/kustomize/cmd/config v0.21.1 h1:/gxf3J1rQD9nfuL8fHlrTLeUL+JHWbK44eOnXJDYx0M= -sigs.k8s.io/kustomize/cmd/config v0.21.1/go.mod h1:7yEFYBJyBJlpZQ50VaRGQRtFMn3Vzn9Fb2wts4TCok4= -sigs.k8s.io/kustomize/kustomize/v5 v5.8.1 h1:Pgsg5psubpVEy7Nf6S89PARg5VmmWUC1l9dC6Dl4PG0= -sigs.k8s.io/kustomize/kustomize/v5 v5.8.1/go.mod h1:0vFa5pQ/elNEQMyiAJuGku9rhAMzz7u9+61hRqFKiwY= -sigs.k8s.io/kustomize/kyaml v0.21.1 h1:IVlbmhC076nf6foyL6Taw4BkrLuEsXUXNpsE+ScX7fI= -sigs.k8s.io/kustomize/kyaml v0.21.1/go.mod h1:hmxADesM3yUN2vbA5z1/YTBnzLJ1dajdqpQonwBL1FQ= -sigs.k8s.io/yaml v1.5.0 h1:M10b2U7aEUY6hRtU870n2VTPgR5RZiL/I6Lcc2F4NUQ= -sigs.k8s.io/yaml v1.5.0/go.mod h1:wZs27Rbxoai4C0f8/9urLZtZtF3avA3gKvGyPdDqTO4= +k8s.io/kube-openapi v0.0.0-20261001230523-97fa35140926 h1:Fe0G8t8FaMDn2lpat0IHu3X9lHrVyGzDxhhCwKXKp28= +k8s.io/kube-openapi v0.0.0-20261001230523-97fa35140926/go.mod h1:3e2VxsK2svhjvkNik92kYU1a5kgau5tZeAuEWwoN4q0= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= +sigs.k8s.io/kustomize/api v0.21.3 h1:DXGrbifGrAd+7AQ75Kx/tVhr+RLMCZFfAYl61HOR3T0= +sigs.k8s.io/kustomize/api v0.21.3/go.mod h1:JKlHjHXGh54cdoWVdKNqDscFzPb9z+sBk9upy9PBh6k= +sigs.k8s.io/kustomize/cmd/config v0.21.3 h1:/G7n3/SM3o5IxVxHY3+3/qPBliMtE5UcMAzbabkBuM4= +sigs.k8s.io/kustomize/cmd/config v0.21.3/go.mod h1:BFUnlKdjh9rfFkgb5HWi6xmhsW6ybqW/JsV6Y1cZmK0= +sigs.k8s.io/kustomize/kustomize/v5 v5.8.3 h1:SJXKgCEb4Ru+8PrhwQ+ORAASc2rPWBneHjh4fKTXPWY= +sigs.k8s.io/kustomize/kustomize/v5 v5.8.3/go.mod h1:goZZjpeux35r4u4E3BPtetYBYcj6Vi5xQtpABCPF9Nk= +sigs.k8s.io/kustomize/kyaml v0.21.3 h1:4ygzLsc8B1ep9dFuEivrJ2lFIAglL19dhPrWp1ioceY= +sigs.k8s.io/kustomize/kyaml v0.21.3/go.mod h1:HrAVNlYyEphOlRCcaSIQziGR+0ehwx6Xp1ucUrpC6hs= +sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= +sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= +sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= +sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/operator/tools/kuttl/go.mod b/operator/tools/kuttl/go.mod index 78782800d13cc..efd998592d696 100644 --- a/operator/tools/kuttl/go.mod +++ b/operator/tools/kuttl/go.mod @@ -2,7 +2,7 @@ module github.com/stackrox/rox/operator/tools/kuttl go 1.26.3 -require github.com/kudobuilder/kuttl v0.26.0 +require github.com/kudobuilder/kuttl v0.27.0 require ( al.essio.dev/pkg/shellescape v1.5.1 // indirect @@ -22,31 +22,31 @@ require ( github.com/distribution/reference v0.6.0 // indirect github.com/docker/go-connections v0.7.0 // indirect github.com/docker/go-units v0.5.0 // indirect - github.com/dustin/go-humanize v1.0.1 // indirect + github.com/dustin/go-humanize v1.1.0 // indirect github.com/dustinkirkland/golang-petname v0.0.0-20191129215211-8e5a1ed0cff0 // indirect github.com/emicklei/go-restful/v3 v3.13.0 // indirect github.com/evanphx/json-patch/v5 v5.9.11 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.10.0 // indirect github.com/fxamacker/cbor/v2 v2.9.1 // indirect - github.com/go-logr/logr v1.4.3 // indirect + github.com/go-logr/logr v1.4.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-logr/zapr v1.3.0 // indirect - github.com/go-openapi/jsonpointer v0.23.1 // indirect - github.com/go-openapi/jsonreference v0.21.5 // indirect - github.com/go-openapi/swag v0.26.0 // indirect - github.com/go-openapi/swag/cmdutils v0.26.0 // indirect - github.com/go-openapi/swag/conv v0.26.0 // indirect - github.com/go-openapi/swag/fileutils v0.26.0 // indirect - github.com/go-openapi/swag/jsonname v0.26.0 // indirect - github.com/go-openapi/swag/jsonutils v0.26.0 // indirect - github.com/go-openapi/swag/loading v0.26.0 // indirect - github.com/go-openapi/swag/mangling v0.26.0 // indirect - github.com/go-openapi/swag/netutils v0.26.0 // indirect - github.com/go-openapi/swag/stringutils v0.26.0 // indirect - github.com/go-openapi/swag/typeutils v0.26.0 // indirect - github.com/go-openapi/swag/yamlutils v0.26.0 // indirect - github.com/google/cel-go v0.29.0 // indirect + github.com/go-openapi/jsonpointer v1.0.0 // indirect + github.com/go-openapi/jsonreference v1.0.0 // indirect + github.com/go-openapi/swag v0.27.1 // indirect + github.com/go-openapi/swag/cmdutils v0.27.1 // indirect + github.com/go-openapi/swag/conv v0.27.1 // indirect + github.com/go-openapi/swag/fileutils v0.27.1 // indirect + github.com/go-openapi/swag/jsonutils v0.27.1 // indirect + github.com/go-openapi/swag/loading v0.27.1 // indirect + github.com/go-openapi/swag/mangling v0.27.1 // indirect + github.com/go-openapi/swag/netutils v0.27.1 // indirect + github.com/go-openapi/swag/pools v0.27.1 // indirect + github.com/go-openapi/swag/stringutils v0.27.1 // indirect + github.com/go-openapi/swag/typeutils v0.27.1 // indirect + github.com/go-openapi/swag/yamlutils v0.27.1 // indirect + github.com/google/cel-go v0.31.0 // indirect github.com/google/gnostic-models v0.7.1 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/google/uuid v1.6.0 // indirect @@ -57,21 +57,22 @@ require ( github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect - github.com/moby/moby/api v1.54.2 // indirect - github.com/moby/moby/client v0.4.1 // indirect + github.com/moby/moby/api v1.56.0 // indirect + github.com/moby/moby/client v0.6.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/onsi/gomega v1.40.0 // indirect + github.com/onsi/ginkgo/v2 v2.32.1 // indirect + github.com/onsi/gomega v1.43.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.1 // indirect github.com/pelletier/go-toml v1.9.5 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/prometheus/client_golang v1.23.2 // indirect + github.com/prometheus/client_golang v1.24.0 // indirect github.com/prometheus/client_model v0.6.2 // indirect - github.com/prometheus/common v0.67.5 // indirect - github.com/prometheus/procfs v0.20.1 // indirect + github.com/prometheus/common v0.70.0 // indirect + github.com/prometheus/procfs v0.21.1 // indirect github.com/shopspring/decimal v1.4.0 // indirect github.com/spf13/cast v1.7.0 // indirect github.com/spf13/cobra v1.10.2 // indirect @@ -79,42 +80,42 @@ require ( github.com/thoas/go-funk v0.9.3 // indirect github.com/x448/float16 v0.8.4 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.65.0 // indirect - go.opentelemetry.io/otel v1.43.0 // indirect - go.opentelemetry.io/otel/metric v1.43.0 // indirect - go.opentelemetry.io/otel/trace v1.43.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0 // indirect + go.opentelemetry.io/otel v1.44.0 // indirect + go.opentelemetry.io/otel/metric v1.44.0 // indirect + go.opentelemetry.io/otel/trace v1.44.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.1 // indirect go.yaml.in/yaml/v2 v2.4.4 // indirect - go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/crypto v0.53.0 // indirect - golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 // indirect - golang.org/x/net v0.55.0 // indirect + go.yaml.in/yaml/v3 v3.0.5 // indirect + golang.org/x/crypto v0.55.0 // indirect + golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f // indirect + golang.org/x/net v0.58.0 // indirect golang.org/x/oauth2 v0.36.0 // indirect - golang.org/x/sync v0.21.0 // indirect - golang.org/x/sys v0.46.0 // indirect - golang.org/x/term v0.44.0 // indirect - golang.org/x/text v0.38.0 // indirect + golang.org/x/sync v0.22.0 // indirect + golang.org/x/sys v0.47.0 // indirect + golang.org/x/term v0.45.0 // indirect + golang.org/x/text v0.41.0 // indirect golang.org/x/time v0.15.0 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa // indirect google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af // indirect gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/api v0.36.0 // indirect - k8s.io/apiextensions-apiserver v0.36.0 // indirect - k8s.io/apimachinery v0.36.0 // indirect - k8s.io/client-go v0.36.0 // indirect + k8s.io/api v0.37.0 // indirect + k8s.io/apiextensions-apiserver v0.37.0 // indirect + k8s.io/apimachinery v0.37.0 // indirect + k8s.io/client-go v0.37.0 // indirect k8s.io/klog/v2 v2.140.0 // indirect - k8s.io/kube-openapi v0.0.0-20260427204847-8949caaa1199 // indirect - k8s.io/utils v0.0.0-20260319190234-28399d86e0b5 // indirect - sigs.k8s.io/controller-runtime v0.24.0 // indirect + k8s.io/kube-openapi v0.0.0-20260721132016-d427ff9ee9ad // indirect + k8s.io/utils v0.0.0-20260626114624-be93311217bd // indirect + sigs.k8s.io/controller-runtime v0.25.1 // indirect sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect - sigs.k8s.io/kind v0.31.0 // indirect + sigs.k8s.io/kind v0.33.0 // indirect sigs.k8s.io/randfill v1.0.0 // indirect - sigs.k8s.io/structured-merge-diff/v6 v6.4.0 // indirect + sigs.k8s.io/structured-merge-diff/v6 v6.4.2 // indirect sigs.k8s.io/yaml v1.6.0 // indirect ) diff --git a/operator/tools/kuttl/go.sum b/operator/tools/kuttl/go.sum index 57a9d9a3222f9..6d90ca396d9c2 100644 --- a/operator/tools/kuttl/go.sum +++ b/operator/tools/kuttl/go.sum @@ -35,8 +35,8 @@ github.com/docker/go-connections v0.7.0 h1:6SsRfJddP22WMrCkj19x9WKjEDTB+ahsdiGYf github.com/docker/go-connections v0.7.0/go.mod h1:no1qkHdjq7kLMGUXYAduOhYPSJxxvgWBh7ogVvptn3Q= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= -github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/dustin/go-humanize v1.1.0 h1:dbKTrvD0klcbBV/h4AWJdMuZogJACoMlvWIWZ5b2xWg= +github.com/dustin/go-humanize v1.1.0/go.mod h1:hc1CvRkJMsgxqjmjMQF3QNRAZBwY8AXBAzKYoSX9sFI= github.com/dustinkirkland/golang-petname v0.0.0-20191129215211-8e5a1ed0cff0 h1:90Ly+6UfUypEF6vvvW5rQIv9opIL8CbmW9FT20LDQoY= github.com/dustinkirkland/golang-petname v0.0.0-20191129215211-8e5a1ed0cff0/go.mod h1:V+Qd57rJe8gd4eiGzZyg4h54VLHmYVVw54iMnlAMrF8= github.com/emicklei/go-restful/v3 v3.13.0 h1:C4Bl2xDndpU6nJ4bc1jXd+uTmYPVUwkD6bFY/oTyCes= @@ -54,50 +54,50 @@ github.com/fsnotify/fsnotify v1.10.0/go.mod h1:TLheqan6HD6GBK6PrDWyDPBaEV8LspOxv github.com/fxamacker/cbor/v2 v2.9.1 h1:2rWm8B193Ll4VdjsJY28jxs70IdDsHRWgQYAI80+rMQ= github.com/fxamacker/cbor/v2 v2.9.1/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= -github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.4 h1:tG4xh9yMsRCAiodLVTxyrkzSZ9+o0L1Kg/+cPVcbP/8= +github.com/go-logr/logr v1.4.4/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= -github.com/go-openapi/jsonpointer v0.23.1 h1:1HBACs7XIwR2RcmItfdSFlALhGbe6S92p0ry4d1GWg4= -github.com/go-openapi/jsonpointer v0.23.1/go.mod h1:iWRmZTrGn7XwYhtPt/fvdSFj1OfNBngqRT2UG3BxSqY= -github.com/go-openapi/jsonreference v0.21.5 h1:6uCGVXU/aNF13AQNggxfysJ+5ZcU4nEAe+pJyVWRdiE= -github.com/go-openapi/jsonreference v0.21.5/go.mod h1:u25Bw85sX4E2jzFodh1FOKMTZLcfifd1Q+iKKOUxExw= -github.com/go-openapi/swag v0.26.0 h1:GVDXCmfvhfu1BxiHo8/FA+BbKmhecHnG3varjON5/RI= -github.com/go-openapi/swag v0.26.0/go.mod h1:82g3193sZJRbocs7bNCqGfIgq8pkuwVwCfhKIRlEQF0= -github.com/go-openapi/swag/cmdutils v0.26.0 h1:iowihOcvq7y4egO8cOq0dmfohz6wfeQ63U1EnuhO2TU= -github.com/go-openapi/swag/cmdutils v0.26.0/go.mod h1:Sm1MVFMkF6guJJ+pQqHnQA3N0j9qALV3NxzDSv6bETM= -github.com/go-openapi/swag/conv v0.26.0 h1:5yGGsPYI1ZCva93U0AoKi/iZrNhaJEjr324YVsiD89I= -github.com/go-openapi/swag/conv v0.26.0/go.mod h1:tpAmIL7X58VPnHHiSO4uE3jBeRamGsFsfdDeDtb5ECE= -github.com/go-openapi/swag/fileutils v0.26.0 h1:WJoPRvsA7QRiiWluowkLJa9jaYR7FCuxmDvnCgaRRxU= -github.com/go-openapi/swag/fileutils v0.26.0/go.mod h1:0WDJ7lp67eNjPMO50wAWYlKvhOb6CQ37rzR7wrgI8Tc= -github.com/go-openapi/swag/jsonname v0.26.0 h1:gV1NFX9M8avo0YSpmWogqfQISigCmpaiNci8cGECU5w= -github.com/go-openapi/swag/jsonname v0.26.0/go.mod h1:urBBR8bZNoDYGr653ynhIx+gTeIz0ARZxHkAPktJK2M= -github.com/go-openapi/swag/jsonutils v0.26.0 h1:FawFML2iAXsPqmERscuMPIHmFsoP1tOqWkxBaKNMsnA= -github.com/go-openapi/swag/jsonutils v0.26.0/go.mod h1:2VmA0CJlyFqgawOaPI9psnjFDqzyivIqLYN34t9p91E= -github.com/go-openapi/swag/jsonutils/fixtures_test v0.26.0 h1:apqeINu/ICHouqiRZbyFvuDge5jCmmLTqGQ9V95EaOM= -github.com/go-openapi/swag/jsonutils/fixtures_test v0.26.0/go.mod h1:AyM6QT8uz5IdKxk5akv0y6u4QvcL9GWERt0Jx/F/R8Y= -github.com/go-openapi/swag/loading v0.26.0 h1:Apg6zaKhCJurpJer0DCxq99qwmhFddBhaMX7kilDcko= -github.com/go-openapi/swag/loading v0.26.0/go.mod h1:dBxQ/6V2uBaAQdevN18VELE6xSpJWZxLX4txe12JwDg= -github.com/go-openapi/swag/mangling v0.26.0 h1:Du2YC4YLA/Y5m/YKQd7AnY5qq0wRKSFZTTt8ktFaXcQ= -github.com/go-openapi/swag/mangling v0.26.0/go.mod h1:jifS7W9vbg+pw63bT+GI53otluMQL3CeemuyCHKwVx0= -github.com/go-openapi/swag/netutils v0.26.0 h1:CmZp+ZT7HrmFwrC3GdGsXBq2+42T1bjKBapcqVpIs3c= -github.com/go-openapi/swag/netutils v0.26.0/go.mod h1:5iK+Ok3ZohWWex1C50BFTPexi03UaPwjW4Oj8kgrpwo= -github.com/go-openapi/swag/stringutils v0.26.0 h1:qZQngLxs5s7SLijc3N2ZO+fUq2o8LjuWAASSrJuh+xg= -github.com/go-openapi/swag/stringutils v0.26.0/go.mod h1:sWn5uY+QIIspwPhvgnqJsH8xqFT2ZbYcvbcFanRyhFE= -github.com/go-openapi/swag/typeutils v0.26.0 h1:2kdEwdiNWy+JJdOvu5MA2IIg2SylWAFuuyQIKYybfq4= -github.com/go-openapi/swag/typeutils v0.26.0/go.mod h1:oovDuIUvTrEHVMqWilQzKzV4YlSKgyZmFh7AlfABNVE= -github.com/go-openapi/swag/yamlutils v0.26.0 h1:H7O8l/8NJJQ/oiReEN+oMpnGMyt8G0hl460nRZxhLMQ= -github.com/go-openapi/swag/yamlutils v0.26.0/go.mod h1:1evKEGAtP37Pkwcc7EWMF0hedX0/x3Rkvei2wtG/TbU= -github.com/go-openapi/testify/enable/yaml/v2 v2.4.2 h1:5zRca5jw7lzVREKCZVNBpysDNBjj74rBh0N2BGQbSR0= -github.com/go-openapi/testify/enable/yaml/v2 v2.4.2/go.mod h1:XVevPw5hUXuV+5AkI1u1PeAm27EQVrhXTTCPAF85LmE= -github.com/go-openapi/testify/v2 v2.4.2 h1:tiByHpvE9uHrrKjOszax7ZvKB7QOgizBWGBLuq0ePx4= -github.com/go-openapi/testify/v2 v2.4.2/go.mod h1:SgsVHtfooshd0tublTtJ50FPKhujf47YRqauXXOUxfw= +github.com/go-openapi/jsonpointer v1.0.0 h1:kR9tHqY0CtZaOPVFm622dPVNhrvYpwr4uCxgL3h1H8s= +github.com/go-openapi/jsonpointer v1.0.0/go.mod h1:Z3rw7dWu1p9IgitXCFamSlA5lmDiklEB6vkaxcNZW5Y= +github.com/go-openapi/jsonreference v1.0.0 h1:jlmTr6torcd1YgDQvSfNmRtKzYDO4FGBkrAdlAVWnpY= +github.com/go-openapi/jsonreference v1.0.0/go.mod h1:jtwdyGbJk0Xhe5Y+rwtglQP6Sb1WZST4rT32LWB+sv0= +github.com/go-openapi/swag v0.27.1 h1:VotvOLWW8q/EAxB0YdsBBGC8XYyeL1YwBj2ungAGPNg= +github.com/go-openapi/swag v0.27.1/go.mod h1:GTkJPwHfhJp6MWr4/rCh64HVI3Ofu+tcsbfjfHmTxpE= +github.com/go-openapi/swag/cmdutils v0.27.1 h1:I7sYqaWVl5mq0NEmNQkAmFDyNin9ufvMX/p2zwtQaOE= +github.com/go-openapi/swag/cmdutils v0.27.1/go.mod h1:Sm1MVFMkF6guJJ+pQqHnQA3N0j9qALV3NxzDSv6bETM= +github.com/go-openapi/swag/conv v0.27.1 h1:8wi9ZG+olmY1wXphl93EWniPtbSPkXM/feH7FgjsvrU= +github.com/go-openapi/swag/conv v0.27.1/go.mod h1:QbqMivkpKhC3g1B1GGGOJ6ANewI3S62dbzYu3Duowqs= +github.com/go-openapi/swag/fileutils v0.27.1 h1:QQqBSoi5mW4XpU85nS0mLcA+zAE6vLzrb0QkmLKf9oM= +github.com/go-openapi/swag/fileutils v0.27.1/go.mod h1:VvJFZLTZS0AI854gEQz5tk7dBESdLjiNUMSZ/th2ry8= +github.com/go-openapi/swag/jsonutils v0.27.1 h1:SVgK3i4USzCU5mibOOS/l4ea2h9UQXy7J7RNLTjuXjU= +github.com/go-openapi/swag/jsonutils v0.27.1/go.mod h1:tdlEpZqdcQ17uj6J4YdK9vd8It5qWMwjWXOs0tjpRlk= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.27.1 h1:mJu3COL9WEaZVp/Kf2PRMi7tPszPEJfSr/OO75ynCs8= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.27.1/go.mod h1:mofwUWx70wvskwESqRJ//k/9kURmCgyJl5m5Ppoh5kY= +github.com/go-openapi/swag/loading v0.27.1 h1:/DxUgDXKbBX4bcn7r9uEXfJyzN5XpiJmZplzQTjrRCY= +github.com/go-openapi/swag/loading v0.27.1/go.mod h1:jvGh3iA2+zyUUycB5fgJWzeHnhrpvGnJJM0RVE9ZShE= +github.com/go-openapi/swag/mangling v0.27.1 h1:yC9D0HyUE8gbP+BfmGx9+AA89ikwZTMjESK3OnnoaqA= +github.com/go-openapi/swag/mangling v0.27.1/go.mod h1:jtBE2+V+3pILxOR7Vgce+Cwp6A2PgZbvVqfNntbVs0w= +github.com/go-openapi/swag/netutils v0.27.1 h1:mICMFoS82F5TZ4Zy3cqmcQk+BFeCp3Uyq3Np7GI0/qU= +github.com/go-openapi/swag/netutils v0.27.1/go.mod h1:J+WYyFMLtvtCGqa6jLv+YNUmIKI3ZRQRrvfNDMoQoEQ= +github.com/go-openapi/swag/pools v0.27.1 h1:9LeadcMyb2GJCbXX5hVQDbZ2Lq9TL4dCs/nx1j5DO0E= +github.com/go-openapi/swag/pools v0.27.1/go.mod h1:kVQefhSK5RWuRe7BXsL8htgBPAMpN7HDGpGEknqugeE= +github.com/go-openapi/swag/stringutils v0.27.1 h1:ZXePZ0r2p1qSjo8tD3Un4vFj8+FqlCkczxDrJIhYUp8= +github.com/go-openapi/swag/stringutils v0.27.1/go.mod h1:lzRN95CxXmA03XcDWHLOb6nOMcxCqR5rGY0lOgsfRoM= +github.com/go-openapi/swag/typeutils v0.27.1 h1:KSTdFlfnse4r6dP9IrEnwMldjE+zs71UeEB3//PtVXc= +github.com/go-openapi/swag/typeutils v0.27.1/go.mod h1:Srm0xFNRZ1Y+vCxJclo5qzx8aj+1pAKda/YfFPrG0dQ= +github.com/go-openapi/swag/yamlutils v0.27.1 h1:ftxv6xvXb1E3zohUc+okZ9nSqNb9StQX/FXnKZ98sQA= +github.com/go-openapi/swag/yamlutils v0.27.1/go.mod h1:bnxFIB1qewGRiZHypXGZ3fNgf13/0HfRgnS/iZBDrOo= +github.com/go-openapi/testify/enable/yaml/v2 v2.6.0 h1:gGHwAJ0R/5jU8BEGDbfRNR3hL68dAVi84WuOApp29B0= +github.com/go-openapi/testify/enable/yaml/v2 v2.6.0/go.mod h1:tY+St1SGq4NFl0QIqdTY4aEdbChAHxhyB77XQi9iJCo= +github.com/go-openapi/testify/v2 v2.6.0 h1:5PKH2HE7YJ/LuRPQGvSxBRlFXNQhSetBLlGAgUEu3ug= +github.com/go-openapi/testify/v2 v2.6.0/go.mod h1:SgsVHtfooshd0tublTtJ50FPKhujf47YRqauXXOUxfw= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= -github.com/google/cel-go v0.29.0 h1:fEG+Ja3YRwNOqnQxTyJwoByAUAvTuxUGiro/jhrm4F4= -github.com/google/cel-go v0.29.0/go.mod h1:X0bD6iVNR8pkROSOoHVdgTkzmRcosof7WQqCD6wcMc8= +github.com/google/cel-go v0.31.0 h1:H0bhpFTqOvmHrBGrWKp7ZlhBm5Hh8PYUEXnwxT1LL7A= +github.com/google/cel-go v0.31.0/go.mod h1:X0bD6iVNR8pkROSOoHVdgTkzmRcosof7WQqCD6wcMc8= github.com/google/gnostic-models v0.7.1 h1:SisTfuFKJSKM5CPZkffwi6coztzzeYUhc3v4yxLWH8c= github.com/google/gnostic-models v0.7.1/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= @@ -105,8 +105,8 @@ github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J0b1vyeLSOYI8bm5wbJM/8yDe8= -github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= +github.com/google/pprof v0.0.0-20260402051712-545e8a4df936 h1:EwtI+Al+DeppwYX2oXJCETMO23COyaKGP6fHVpkpWpg= +github.com/google/pprof v0.0.0-20260402051712-545e8a4df936/go.mod h1:MxpfABSjhmINe3F1It9d+8exIHFvUqtLIRCdOGNXqiI= 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/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= @@ -117,14 +117,14 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= -github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= +github.com/klauspost/compress v1.19.0 h1:sXLILfc9jV2QYWkzFOPWStmcUVH2RHEB1JCdY2oVvCQ= +github.com/klauspost/compress v1.19.0/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/kudobuilder/kuttl v0.26.0 h1:8PXqnuismPqmxk5yslqfCezXLfkCbR+PIqz8KDzuo7M= -github.com/kudobuilder/kuttl v0.26.0/go.mod h1:jsTOHjoskFIcrkIWnLjAztV5n86o+YqUOjgTK/5lKsc= +github.com/kudobuilder/kuttl v0.27.0 h1:Dc+h0OaoLSaNdSt0caMtHFr0mvdhz7flDuZzq1k1wuU= +github.com/kudobuilder/kuttl v0.27.0/go.mod h1:mpoA6IwOP7pe3hxGO5ojVcpbE6KphWTn7QNN9qpZaWw= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= @@ -135,10 +135,10 @@ github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zx github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= -github.com/moby/moby/api v1.54.2 h1:wiat9QAhnDQjA7wk1kh/TqHz2I1uUA7M7t9SAl/JNXg= -github.com/moby/moby/api v1.54.2/go.mod h1:+RQ6wluLwtYaTd1WnPLykIDPekkuyD/ROWQClE83pzs= -github.com/moby/moby/client v0.4.1 h1:DMQgisVoMkmMs7fp3ROSdiBnoAu8+vo3GggFl06M/wY= -github.com/moby/moby/client v0.4.1/go.mod h1:z52C9O2POPOsnxZAy//WtKcQ32P+jT/NGeXu/7nfjGQ= +github.com/moby/moby/api v1.56.0 h1:GQzua3NA599ASSIICx0iFgiJeO9YkdDARvQsm23ZZuQ= +github.com/moby/moby/api v1.56.0/go.mod h1:sZ+THbVWkjOmBPPfbnzdD/G1LuIexWhqlSHHPTDQ1Uk= +github.com/moby/moby/client v0.6.0 h1:AJjEB21QPbXSXjDsZorFBoDZPhMrfbpaPLgSMAW9Bgs= +github.com/moby/moby/client v0.6.0/go.mod h1:OCo00wNRyA3m4lmJ228W3JbyCN4ZNNYjpOXiJydBdcQ= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -147,10 +147,10 @@ github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFd github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/onsi/ginkgo/v2 v2.27.4 h1:fcEcQW/A++6aZAZQNUmNjvA9PSOzefMJBerHJ4t8v8Y= -github.com/onsi/ginkgo/v2 v2.27.4/go.mod h1:ArE1D/XhNXBXCBkKOLkbsb2c81dQHCRcF5zwn/ykDRo= -github.com/onsi/gomega v1.40.0 h1:Vtol0e1MghCD2ZVIilPDIg44XSL9l2QAn8ZNaljWcJc= -github.com/onsi/gomega v1.40.0/go.mod h1:M/Uqpu/8qTjtzCLUA2zJHX9Iilrau25x1PdoSRbWh5A= +github.com/onsi/ginkgo/v2 v2.32.1 h1:6tlvcDm/3sE8lGJbZ4+d4mO3RLy24/tQWOFzVSQNIfw= +github.com/onsi/ginkgo/v2 v2.32.1/go.mod h1:+aXOY+vzZ5mu2iI2HpTZUPmM//oQfsNFX6gU9kNcA44= +github.com/onsi/gomega v1.43.0 h1:VlG/1FxqNxhSO+lq/OHBNaaqwiBK/mO8JbVkX9Y+FeU= +github.com/onsi/gomega v1.43.0/go.mod h1:REff/hsDsodHoKlWsP2mAPhu1+5/6hVYNf9rIEBpeSg= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= @@ -162,14 +162,14 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o= -github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg= +github.com/prometheus/client_golang v1.24.0 h1:5XStIklKuAtJSNpdD3s8XJj/Yv78IQmE1kbNk87JrAI= +github.com/prometheus/client_golang v1.24.0/go.mod h1:QcsNdotprC2nS4BTM2ucbcqxd2CeXTEa9jW7zHO9iDE= github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= -github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4= -github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw= -github.com/prometheus/procfs v0.20.1 h1:XwbrGOIplXW/AU3YhIhLODXMJYyC1isLFfYCsTEycfc= -github.com/prometheus/procfs v0.20.1/go.mod h1:o9EMBZGRyvDrSPH1RqdxhojkuXstoe4UlK79eF5TGGo= +github.com/prometheus/common v0.70.0 h1:bcpru3tWPVnxGnETLgOV5jbp/JRXgYEyv65CuBLAMMI= +github.com/prometheus/common v0.70.0/go.mod h1:S/SFasQmgGiYH6C81LKCtYa8QACgthGg5zxL2udV7SY= +github.com/prometheus/procfs v0.21.1 h1:GljZCt+zSTS+NZq88cyQ1LjZ+RCHp3uVuabBWA5+OJI= +github.com/prometheus/procfs v0.21.1/go.mod h1:aB55Cww9pdSJVHk0hUf0inxWyyjPogFIjmHKYgMKmtY= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -183,30 +183,30 @@ github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/objx v0.5.3 h1:jmXUvGomnU1o3W/V5h2VEradbpJDwGrzugQQvL0POH4= +github.com/stretchr/objx v0.5.3/go.mod h1:rDQraq+vQZU7Fde9LOZLr8Tax6zZvy4kuNKF+QYS+U0= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= -github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/stretchr/testify v1.12.1 h1:EuwCh5fleGS7H32xRwO3wRGT7DxrDhLAT6FF8MpWDWE= +github.com/stretchr/testify v1.12.1/go.mod h1:MDEgiDPPsNp5cuIrHPPCyornHKgEVbtFUmoNlxoYthg= github.com/thoas/go-funk v0.9.3 h1:7+nAEx3kn5ZJcnDm2Bh23N2yOtweO14bi//dvRtgLpw= github.com/thoas/go-funk v0.9.3/go.mod h1:+IWnUfUmFO1+WVYQWQtIJHeRRdaIyyYglZN7xzUPe4Q= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.65.0 h1:7iP2uCb7sGddAr30RRS6xjKy7AZ2JtTOPA3oolgVSw8= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.65.0/go.mod h1:c7hN3ddxs/z6q9xwvfLPk+UHlWRQyaeR1LdgfL/66l0= -go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I= -go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0= -go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM= -go.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY= -go.opentelemetry.io/otel/sdk v1.43.0 h1:pi5mE86i5rTeLXqoF/hhiBtUNcrAGHLKQdhg4h4V9Dg= -go.opentelemetry.io/otel/sdk v1.43.0/go.mod h1:P+IkVU3iWukmiit/Yf9AWvpyRDlUeBaRg6Y+C58QHzg= -go.opentelemetry.io/otel/sdk/metric v1.43.0 h1:S88dyqXjJkuBNLeMcVPRFXpRw2fuwdvfCGLEo89fDkw= -go.opentelemetry.io/otel/sdk/metric v1.43.0/go.mod h1:C/RJtwSEJ5hzTiUz5pXF1kILHStzb9zFlIEe85bhj6A= -go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A= -go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0 h1:8tvICD4vSTOOsNrsI4Ljf6C+6UKvpTEH5XY3JMoyPoo= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0/go.mod h1:z9+yiacE0IHRqM4qFfkbt/JYlmYXgss8GY/jXoNuPJI= +go.opentelemetry.io/otel v1.44.0 h1:JjwHmHpA4iZ3wBxluu2fbbE7j4kqlE8jXyAyPXH7HqU= +go.opentelemetry.io/otel v1.44.0/go.mod h1:BMgjTHL9WPRlRjL2oZCBTL4whCGtXch2H4BhOPIAyYc= +go.opentelemetry.io/otel/metric v1.44.0 h1:1w0gILTcHdr3YI+ixLyjemwrVnsMURbTZFrSYCdDdmc= +go.opentelemetry.io/otel/metric v1.44.0/go.mod h1:8O7hanEPBNgEMmybD3s2VBKcgWOCsA6tzHBPODAiquo= +go.opentelemetry.io/otel/sdk v1.44.0 h1:nHYwb9lK+fJPU/dnT6s7W7Z8itMWyqrnVfbheVYrZ58= +go.opentelemetry.io/otel/sdk v1.44.0/go.mod h1:Osuydd3Se74nqjAKxid74N5eC+jfEqfTegHRnq58oK0= +go.opentelemetry.io/otel/sdk/metric v1.44.0 h1:3LlKgI+VjbVsjNRFZJZAJ30WjXC5VkNRks6si09iEfI= +go.opentelemetry.io/otel/sdk/metric v1.44.0/go.mod h1:5B5pMARnXxKhltooO4xUuCBorl65a4EpnTalObqOigA= +go.opentelemetry.io/otel/trace v1.44.0 h1:jxF5CsGYCe74MCRx2X4g7WsY/VBKRqqpNvXlX/6gtIk= +go.opentelemetry.io/otel/trace v1.44.0/go.mod h1:oLl1jrMQAVo6v3GAggN+1VH9VIz9iUSvW53sW1Q8PIE= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= @@ -215,37 +215,38 @@ go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ= go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ= -go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= -golang.org/x/crypto v0.53.0 h1:QZ4Muo8THX6CizN2vPPd5fBGHyogrdK9fG4wLPFUsto= -golang.org/x/crypto v0.53.0/go.mod h1:DNLU434OwVakk9PzuwV8w62mAJpRJL3vsgcfp4Qnsio= -golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 h1:fQsdNF2N+/YewlRZiricy4P1iimyPKZ/xwniHj8Q2a0= -golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93/go.mod h1:EPRbTFwzwjXj9NpYyyrvenVh9Y+GFeEvMNh7Xuz7xgU= -golang.org/x/mod v0.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4= -golang.org/x/mod v0.36.0/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ= -golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8= -golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww= +go.yaml.in/yaml/v3 v3.0.5 h1:N6y/pJk8buWs9NY5ERU2HSMfm+IuD/OtfdAnq6kESPw= +go.yaml.in/yaml/v3 v3.0.5/go.mod h1:HVTZu1O7/Vkt2N+BFy8Zza+lnLsABggaTM2ZpNIGuKg= +golang.org/x/crypto v0.55.0 h1:+KWHjbgOaAQ66dh/YlkZKHlz9ZUlq61AFirAR9ntP8M= +golang.org/x/crypto v0.55.0/go.mod h1:uq0V9dE/fzQuJtbnL+2EhWOE63vo164FY8xqEnV9xis= +golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f h1:W3F4c+6OLc6H2lb//N1q4WpJkhzJCK5J6kUi1NTVXfM= +golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f/go.mod h1:J1xhfL/vlindoeF/aINzNzt2Bket5bjo9sdOYzOsU80= +golang.org/x/mod v0.39.0 h1:UF5zwQdCRRUpHfyPwr7d4UrGiVeldIsogtzWVnczL74= +golang.org/x/mod v0.39.0/go.mod h1:bvIbwjQ0HUFFf5AKukeeYQG4ZBUG9yxQbR9aEweIwYY= +golang.org/x/net v0.58.0 h1:ynWG7rqYi4ccpTEuPZ2QGWHktVEM9DMCj9yzDE0Q7To= +golang.org/x/net v0.58.0/go.mod h1:YwCddHnFlT7eLQqVprV19OnhLGtc5xOKgE0RyqgfWAU= golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs= golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q= -golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM= -golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= +golang.org/x/sync v0.22.0 h1:SZjpbeLmrCk4xhRSZFNZW5gFUeCeFgjekvI/+gfScek= +golang.org/x/sync v0.22.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw= -golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= -golang.org/x/term v0.44.0 h1:0rLvDRCtNj0gZkyIXhCyOb2OAzEhLVqc4B+hrsBhrmc= -golang.org/x/term v0.44.0/go.mod h1:7ze4MdzUzLXpSAoFP1H0bOI9aXDqveSvatT5vKcFh2Y= -golang.org/x/text v0.38.0 h1:sXmwo9DwP3OK9EZ7PqAdaooSGozfl/3a6/xJcbzPRhE= -golang.org/x/text v0.38.0/go.mod h1:YXZt3QhHUKYT53r2lLKFIVi6Ao1jdzrTR/KQ09qyxF4= +golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs= +golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/term v0.45.0 h1:NwWyBmoJCbfTHpxrWoZ9C6/VxOf7ic219I8xZZFdrf0= +golang.org/x/term v0.45.0/go.mod h1:9aqxs0blBcrm/n0L9QW0aRVD+ktan8ssZromtqJC43w= +golang.org/x/text v0.41.0 h1:vz/seA0lnX87Othu2f/0L24RcgrXD9/YFTSuGjj3rH8= +golang.org/x/text v0.41.0/go.mod h1:jvf1O8ajNzZqhSrQBPbutR/EB83Cc0CFrezNQIwbb5M= golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U= golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno= -golang.org/x/tools v0.45.0 h1:18qN3FAooORvApf5XjCXgsuayZOEtXf6JK18I3+ONa8= -golang.org/x/tools v0.45.0/go.mod h1:LuUGqqaXcXMEFEruIVJVm5mgDD8vww/z/SR1gQ4uE/0= +golang.org/x/tools v0.49.0 h1:3NI7VXzL9+1WZD52Dx2ttoPwD5DWrFGpl9mFZDlmisI= +golang.org/x/tools v0.49.0/go.mod h1:SJNXV9DBKT0UbdttsQjbfJlAE/q+y36++zo3uL3N0Oo= gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= -google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9 h1:VPWxll4HlMw1Vs/qXtN7BvhZqsS9cdAittCNvVENElA= -google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9/go.mod h1:7QBABkRtR8z+TEnmXTqIqwJLlzrZKVfAUm7tY3yGv0M= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9 h1:m8qni9SQFH0tJc1X0vmnpw/0t+AImlSvp30sEupozUg= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= +google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa h1:Kjn0N0tCrDgiAFW+lGO4JZ3ck44CehvJQMAwj9QF0G8= +google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:q4lMZS6kskjT5HvCPrnnypcDPVJqT/f4nfxmkE7gryY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa h1:mZHHdPZl0dbGHCflZgAq/Q468DWVFcU2whhB2KAo8fk= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af h1:+5/Sw3GsDNlEmu7TfklWKPdQ0Ykja5VEmq2i817+jbI= google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -262,31 +263,31 @@ 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.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q= gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA= -k8s.io/api v0.36.0 h1:SgqDhZzHdOtMk40xVSvCXkP9ME0H05hPM3p9AB1kL80= -k8s.io/api v0.36.0/go.mod h1:m1LVrGPNYax5NBHdO+QuAedXyuzTt4RryI/qnmNvs34= -k8s.io/apiextensions-apiserver v0.36.0 h1:Wt7E8J+VBCbj4FjiBfDTK/neXDDjyJVJc7xfuOHImZ0= -k8s.io/apiextensions-apiserver v0.36.0/go.mod h1:kGDjH0msuiIB3tgsYRV0kS9GqpMYMUsQ3GHv7TApyug= -k8s.io/apimachinery v0.36.0 h1:jZyPzhd5Z+3h9vJLt0z9XdzW9VzNzWAUw+P1xZ9PXtQ= -k8s.io/apimachinery v0.36.0/go.mod h1:FklypaRJt6n5wUIwWXIP6GJlIpUizTgfo1T/As+Tyxc= -k8s.io/client-go v0.36.0 h1:pOYi7C4RHChYjMiHpZSpSbIM6ZxVbRXBy7CuiIwqA3c= -k8s.io/client-go v0.36.0/go.mod h1:ZKKcpwF0aLYfkHFCjillCKaTK/yBkEDHTDXCFY6AS9Y= +k8s.io/api v0.37.0 h1:Z//Vj9N7RA/yS2sDmxyeo7h+RR4zbUrd2vrd3Z0TbB4= +k8s.io/api v0.37.0/go.mod h1:LKXgcJWMc+f4OLbP5SFR8rulEg07zZhpi/zMULiBImk= +k8s.io/apiextensions-apiserver v0.37.0 h1:zRMQ3+/LIE5oZ0tVvXwYHC+dIkSP5cjNWju7AZU1LOI= +k8s.io/apiextensions-apiserver v0.37.0/go.mod h1:HU0PfSBwchHL5iDau6jjt9zU6ryWkDDlaVUiq91NK80= +k8s.io/apimachinery v0.37.0 h1:Np2AbDtf8x6RDHiD8T9LbKJ9gaegeVNa8yNm5FuGKm0= +k8s.io/apimachinery v0.37.0/go.mod h1:RN3nhprFSCxOi5Selxd7oMTXOe/c+ZbcE7Im+TS2zkE= +k8s.io/client-go v0.37.0 h1:nsN31fy8wBySuZ+QRnKmrjRSQLOG2rvoGN0tKd12zhQ= +k8s.io/client-go v0.37.0/go.mod h1:FcGqw+Ll/gNQiq+nPGY1Oyt9y7SgDh1d3MW3RFDEbn0= k8s.io/klog/v2 v2.140.0 h1:Tf+J3AH7xnUzZyVVXhTgGhEKnFqye14aadWv7bzXdzc= k8s.io/klog/v2 v2.140.0/go.mod h1:o+/RWfJ6PwpnFn7OyAG3QnO47BFsymfEfrz6XyYSSp0= -k8s.io/kube-openapi v0.0.0-20260427204847-8949caaa1199 h1:sWu4Td5mgJlwunsUydnhKEAfNUHM7hm1wfKEQmD7G5c= -k8s.io/kube-openapi v0.0.0-20260427204847-8949caaa1199/go.mod h1:uGBT7iTA6c6MvqUvSXIaYZo9ukscABYi2btjhvgKGZ0= -k8s.io/utils v0.0.0-20260319190234-28399d86e0b5 h1:kBawHLSnx/mYHmRnNUf9d4CpjREbeZuxoSGOX/J+aYM= -k8s.io/utils v0.0.0-20260319190234-28399d86e0b5/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk= +k8s.io/kube-openapi v0.0.0-20260721132016-d427ff9ee9ad h1:oXImqH8mQNk7PmvzKhmN3ddJoY6OnyM225MXwGHPm0A= +k8s.io/kube-openapi v0.0.0-20260721132016-d427ff9ee9ad/go.mod h1:0/mqHCVhlumdJ3BhCfnjSZQE037nAhNodh1/hK0T8/I= +k8s.io/utils v0.0.0-20260626114624-be93311217bd h1:Ea7fgQ5we8Y9T0OX5o0dAHzQOBRI07D/dEYRaB9ZZEs= +k8s.io/utils v0.0.0-20260626114624-be93311217bd/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk= pgregory.net/rapid v1.2.0 h1:keKAYRcjm+e1F0oAuU5F5+YPAWcyxNNRK2wud503Gnk= pgregory.net/rapid v1.2.0/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04= -sigs.k8s.io/controller-runtime v0.24.0 h1:Ck6N2LdS8Lovy1o25BB4r1xjvLEKUl1s2o9kU+KWDE4= -sigs.k8s.io/controller-runtime v0.24.0/go.mod h1:vFkfY5fGt5xAC/sKb8IBFKgWPNKG9OUG29dR8Y2wImw= +sigs.k8s.io/controller-runtime v0.25.1 h1:BKgU9OeE8xv8EbbM8cY0NVzTQs35rokkdq1jh12fMb4= +sigs.k8s.io/controller-runtime v0.25.1/go.mod h1:4QqLdT6z/L6Olj8JJCtvztid4/fnIiYsfaTFScegctc= sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg= sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= -sigs.k8s.io/kind v0.31.0 h1:UcT4nzm+YM7YEbqiAKECk+b6dsvc/HRZZu9U0FolL1g= -sigs.k8s.io/kind v0.31.0/go.mod h1:FSqriGaoTPruiXWfRnUXNykF8r2t+fHtK0P0m1AbGF8= +sigs.k8s.io/kind v0.33.0 h1:AjvDv3vOygb/VKLVQW87lfktIBzkxR8Ump9DjxC8+Lk= +sigs.k8s.io/kind v0.33.0/go.mod h1:FSqriGaoTPruiXWfRnUXNykF8r2t+fHtK0P0m1AbGF8= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v6 v6.4.0 h1:qmp2e3ZfFi1/jJbDGpD4mt3wyp6PE1NfKHCYLqgNQJo= -sigs.k8s.io/structured-merge-diff/v6 v6.4.0/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= +sigs.k8s.io/structured-merge-diff/v6 v6.4.2 h1:qdOxHwrl2Kaag1aQEarlYcOA9vSyGCp3CIki3aW8c4Q= +sigs.k8s.io/structured-merge-diff/v6 v6.4.2/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/operator/tools/operator-sdk/go.mod b/operator/tools/operator-sdk/go.mod index b414d606b1a0c..6c414de8ca28a 100644 --- a/operator/tools/operator-sdk/go.mod +++ b/operator/tools/operator-sdk/go.mod @@ -5,7 +5,7 @@ go 1.26.3 require github.com/operator-framework/operator-sdk v1.42.3 require ( - cel.dev/expr v0.25.1 // indirect + cel.dev/expr v0.25.2 // indirect dario.cat/mergo v1.0.2 // indirect github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 // indirect github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect @@ -28,7 +28,7 @@ require ( github.com/chai2010/gettext-go v1.0.2 // indirect github.com/clipperhouse/uax29/v2 v2.6.0 // indirect github.com/containerd/cgroups/v3 v3.1.2 // indirect - github.com/containerd/containerd v1.7.33 // indirect + github.com/containerd/containerd v1.7.36 // indirect github.com/containerd/containerd/api v1.10.0 // indirect github.com/containerd/continuity v0.4.5 // indirect github.com/containerd/errdefs v1.0.0 // indirect @@ -62,10 +62,10 @@ require ( github.com/go-errors/errors v1.4.2 // indirect github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect github.com/go-git/go-billy/v5 v5.9.0 // indirect - github.com/go-git/go-git/v5 v5.19.1 // indirect + github.com/go-git/go-git/v5 v5.19.2 // indirect github.com/go-gorp/gorp/v3 v3.1.0 // indirect github.com/go-jose/go-jose/v4 v4.1.4 // indirect - github.com/go-logr/logr v1.4.3 // indirect + github.com/go-logr/logr v1.4.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/jsonpointer v0.22.4 // indirect github.com/go-openapi/jsonreference v0.21.4 // indirect @@ -91,7 +91,7 @@ require ( github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/google/btree v1.1.3 // indirect - github.com/google/cel-go v0.29.0 // indirect + github.com/google/cel-go v0.31.0 // indirect github.com/google/gnostic-models v0.7.1 // indirect github.com/google/go-cmp v0.7.0 // indirect github.com/google/go-containerregistry v0.21.5 // indirect @@ -135,7 +135,7 @@ require ( github.com/moby/sys/capability v0.4.0 // indirect github.com/moby/sys/mountinfo v0.7.2 // indirect github.com/moby/sys/sequential v0.6.0 // indirect - github.com/moby/sys/user v0.4.0 // indirect + github.com/moby/sys/user v0.4.1 // indirect github.com/moby/sys/userns v0.1.0 // indirect github.com/moby/term v0.5.2 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect @@ -194,33 +194,33 @@ require ( go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0 // indirect - go.opentelemetry.io/otel v1.43.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.42.0 // indirect - go.opentelemetry.io/otel/metric v1.43.0 // indirect - go.opentelemetry.io/otel/sdk v1.43.0 // indirect - go.opentelemetry.io/otel/trace v1.43.0 // indirect - go.opentelemetry.io/proto/otlp v1.10.0 // indirect + go.opentelemetry.io/otel v1.45.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.45.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.45.0 // indirect + go.opentelemetry.io/otel/metric v1.45.0 // indirect + go.opentelemetry.io/otel/sdk v1.45.0 // indirect + go.opentelemetry.io/otel/trace v1.45.0 // indirect + go.opentelemetry.io/proto/otlp v1.11.0 // indirect go.podman.io/common v0.66.1 // indirect go.podman.io/image/v5 v5.38.0 // indirect go.podman.io/storage v1.61.0 // indirect go.yaml.in/yaml/v2 v2.4.4 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/crypto v0.53.0 // indirect + golang.org/x/crypto v0.55.0 // indirect golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f // indirect - golang.org/x/mod v0.37.0 // indirect - golang.org/x/net v0.56.0 // indirect + golang.org/x/mod v0.38.0 // indirect + golang.org/x/net v0.58.0 // indirect golang.org/x/oauth2 v0.36.0 // indirect - golang.org/x/sync v0.21.0 // indirect - golang.org/x/sys v0.46.0 // indirect - golang.org/x/term v0.44.0 // indirect - golang.org/x/text v0.38.0 // indirect + golang.org/x/sync v0.22.0 // indirect + golang.org/x/sys v0.47.0 // indirect + golang.org/x/term v0.45.0 // indirect + golang.org/x/text v0.41.0 // indirect golang.org/x/time v0.15.0 // indirect - golang.org/x/tools v0.47.0 // indirect + golang.org/x/tools v0.48.0 // indirect google.golang.org/genproto v0.0.0-20260319201613-d00831a3d3e7 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20260414002931-afd174a4e478 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20260511170946-3700d4141b60 // indirect - google.golang.org/grpc v1.82.1 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20260803160001-6ac0973c030d // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260803160001-6ac0973c030d // indirect + google.golang.org/grpc v1.83.2 // indirect google.golang.org/protobuf v1.36.11 // indirect gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect @@ -239,7 +239,7 @@ require ( k8s.io/kube-openapi v0.0.0-20260127142750-a19766b6e2d4 // indirect k8s.io/kubectl v0.35.1 // indirect k8s.io/utils v0.0.0-20260108192941-914a6e750570 // indirect - oras.land/oras-go/v2 v2.6.0 // indirect + oras.land/oras-go/v2 v2.6.2 // indirect sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.34.0 // indirect sigs.k8s.io/controller-runtime v0.23.1 // indirect sigs.k8s.io/controller-tools v0.20.0 // indirect diff --git a/operator/tools/operator-sdk/go.sum b/operator/tools/operator-sdk/go.sum index b435790cea172..790d026981d54 100644 --- a/operator/tools/operator-sdk/go.sum +++ b/operator/tools/operator-sdk/go.sum @@ -1,5 +1,5 @@ -cel.dev/expr v0.25.1 h1:1KrZg61W6TWSxuNZ37Xy49ps13NUovb66QLprthtwi4= -cel.dev/expr v0.25.1/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4= +cel.dev/expr v0.25.2 h1:K6j46C81hXtZQfuX60cVWQFBJahKSE2gfRbNuvr5bFs= +cel.dev/expr v0.25.2/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8= dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA= @@ -58,8 +58,8 @@ github.com/clipperhouse/uax29/v2 v2.6.0/go.mod h1:Wn1g7MK6OoeDT0vL+Q0SQLDz/KpfsV github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/containerd/cgroups/v3 v3.1.2 h1:OSosXMtkhI6Qove637tg1XgK4q+DhR0mX8Wi8EhrHa4= github.com/containerd/cgroups/v3 v3.1.2/go.mod h1:PKZ2AcWmSBsY/tJUVhtS/rluX0b1uq1GmPO1ElCmbOw= -github.com/containerd/containerd v1.7.33 h1:iAkYGC/ifR/V+0eR4iXWHNGYUF0DF2PmGV5iz4Irj5M= -github.com/containerd/containerd v1.7.33/go.mod h1:gSbSCVjPCdkfJCjyrzz7aRC+xFlqVbatNpfHfVCYGUM= +github.com/containerd/containerd v1.7.36 h1:HyMsOG5kmp1LQsGzqwI6Ts06T4VpYZbszfDZYB0bW5w= +github.com/containerd/containerd v1.7.36/go.mod h1:ozI//0TomTCLPhQREnx0IXDIQMg+Fk7yTtg9fNvU8EQ= github.com/containerd/containerd/api v1.10.0 h1:5n0oHYVBwN4VhoX9fFykCV9dF1/BvAXeg2F8W6UYq1o= github.com/containerd/containerd/api v1.10.0/go.mod h1:NBm1OAk8ZL+LG8R0ceObGxT5hbUYj7CzTmR3xh0DlMM= github.com/containerd/continuity v0.4.5 h1:ZRoN1sXq9u7V6QoHMcVWGhOwDFqZ4B9i5H6un1Wh0x4= @@ -154,15 +154,15 @@ github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66D github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= github.com/go-git/go-billy/v5 v5.9.0 h1:jItGXszUDRtR/AlferWPTMN4j38BQ88XnXKbilmmBPA= github.com/go-git/go-billy/v5 v5.9.0/go.mod h1:jCnQMLj9eUgGU7+ludSTYoZL/GGmii14RxKFj7ROgHw= -github.com/go-git/go-git/v5 v5.19.1 h1:nX27AnaU43/K5bKktKwgBmR9lawoYVe1Ckg0rgzzN00= -github.com/go-git/go-git/v5 v5.19.1/go.mod h1:Pb1v0c7/g8aGQJwx9Us09W85yGoyvSwuhEGMH7zjDKQ= +github.com/go-git/go-git/v5 v5.19.2 h1:wkfn7vOlUBu8ivAWKBWisTiwJK4jYHzTF8Ndv1LyGqY= +github.com/go-git/go-git/v5 v5.19.2/go.mod h1:QqCBE1EFN5ddFmrliLQ3/ntRCUjZU3EJuwuB/jWEHjk= github.com/go-gorp/gorp/v3 v3.1.0 h1:ItKF/Vbuj31dmV4jxA1qblpSwkl9g1typ24xoe70IGs= github.com/go-gorp/gorp/v3 v3.1.0/go.mod h1:dLEjIyyRNiXvNZ8PSmzpt1GsWAUK8kjVhEpjH8TixEw= github.com/go-jose/go-jose/v4 v4.1.4 h1:moDMcTHmvE6Groj34emNPLs/qtYXRVcd6S7NHbHz3kA= github.com/go-jose/go-jose/v4 v4.1.4/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= -github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.4 h1:tG4xh9yMsRCAiodLVTxyrkzSZ9+o0L1Kg/+cPVcbP/8= +github.com/go-logr/logr v1.4.4/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= @@ -239,8 +239,8 @@ github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= -github.com/google/cel-go v0.29.0 h1:fEG+Ja3YRwNOqnQxTyJwoByAUAvTuxUGiro/jhrm4F4= -github.com/google/cel-go v0.29.0/go.mod h1:X0bD6iVNR8pkROSOoHVdgTkzmRcosof7WQqCD6wcMc8= +github.com/google/cel-go v0.31.0 h1:H0bhpFTqOvmHrBGrWKp7ZlhBm5Hh8PYUEXnwxT1LL7A= +github.com/google/cel-go v0.31.0/go.mod h1:X0bD6iVNR8pkROSOoHVdgTkzmRcosof7WQqCD6wcMc8= github.com/google/gnostic-models v0.7.1 h1:SisTfuFKJSKM5CPZkffwi6coztzzeYUhc3v4yxLWH8c= github.com/google/gnostic-models v0.7.1/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -356,8 +356,8 @@ github.com/moby/sys/mountinfo v0.7.2 h1:1shs6aH5s4o5H2zQLn796ADW1wMrIwHsyJ2v9Kou github.com/moby/sys/mountinfo v0.7.2/go.mod h1:1YOa8w8Ih7uW0wALDUgT1dTTSBrZ+HiBLGws92L2RU4= github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU= github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko= -github.com/moby/sys/user v0.4.0 h1:jhcMKit7SA80hivmFJcbB1vqmw//wU61Zdui2eQXuMs= -github.com/moby/sys/user v0.4.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs= +github.com/moby/sys/user v0.4.1 h1:RgjRlaDKi/Xmyrz4t8lyzXT6v2ooFeO/7xtchmhVWE0= +github.com/moby/sys/user v0.4.1/go.mod h1:E9QsW5WRe1kUAf7kW8hXKwu1uhsZEAdPLYHYSDudF4Y= github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g= github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28= github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ= @@ -527,8 +527,8 @@ go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.6 go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.67.0/go.mod h1:NoUCKYWK+3ecatC4HjkRktREheMeEtrXoQxrqYFeHSc= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0 h1:OyrsyzuttWTSur2qN/Lm0m2a8yqyIjUVBZcxFPuXq2o= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0/go.mod h1:C2NGBr+kAB4bk3xtMXfZ94gqFDtg/GkI7e9zqGh5Beg= -go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I= -go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0= +go.opentelemetry.io/otel v1.45.0 h1:pdrWmLHofpubmArBv1LgFSv1Z0Ie/ppdZzu+kUN5EeU= +go.opentelemetry.io/otel v1.45.0/go.mod h1:XZxIqPapzEYnhNSScF5DIqXhm/rYi0FzCe2XddAwZfQ= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.18.0 h1:deI9UQMoGFgrg5iLPgzueqFPHevDl+28YKfSpPTI6rY= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.18.0/go.mod h1:PFx9NgpNUKXdf7J4Q3agRxMs3Y07QhTCVipKmLsMKnU= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.19.0 h1:HIBTQ3VO5aupLKjC90JgMqpezVXwFuq6Ryjn0/izoag= @@ -537,10 +537,10 @@ go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.42.0 h1:MdK go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.42.0/go.mod h1:RolT8tWtfHcjajEH5wFIZ4Dgh5jpPdFXYV9pTAk/qjc= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.43.0 h1:w1K+pCJoPpQifuVpsKamUdn9U0zM3xUziVOqsGksUrY= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.43.0/go.mod h1:HBy4BjzgVE8139ieRI75oXm3EcDN+6GhD88JT1Kjvxg= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0 h1:88Y4s2C8oTui1LGM6bTWkw0ICGcOLCAI5l6zsD1j20k= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0/go.mod h1:Vl1/iaggsuRlrHf/hfPJPvVag77kKyvrLeD10kpMl+A= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.42.0 h1:zWWrB1U6nqhS/k6zYB74CjRpuiitRtLLi68VcgmOEto= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.42.0/go.mod h1:2qXPNBX1OVRC0IwOnfo1ljoid+RD0QK3443EaqVlsOU= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.45.0 h1:QRefszxJmfPdjXUUm3j6iDzY03mTPXMjqErFqQ67vUg= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.45.0/go.mod h1:Tiz03lTBVBrm7eWZBOidzEaYaJa8tjwGUGv6d8mlTyk= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.45.0 h1:fG5MCxGz8+2VtrN/WgqSpJFctVz24gpxj8CxkKmc8Ww= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.45.0/go.mod h1:BmAYTn+3ysbRe+IU2msxmf5Rx3g6DHvex+tWI3LdhYI= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0 h1:3iZJKlCZufyRzPzlQhUIWVmfltrXuGyfjREgGP3UUjc= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0/go.mod h1:/G+nUPfhq2e+qiXMGxMwumDrP5jtzU+mWN7/sjT2rak= go.opentelemetry.io/otel/exporters/prometheus v0.64.0 h1:g0LRDXMX/G1SEZtK8zl8Chm4K6GBwRkjPKE36LxiTYs= @@ -553,18 +553,18 @@ go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.42.0 h1:s/1iRkCKDfhlh1J go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.42.0/go.mod h1:UI3wi0FXg1Pofb8ZBiBLhtMzgoTm1TYkMvn71fAqDzs= go.opentelemetry.io/otel/log v0.19.0 h1:KUZs/GOsw79TBBMfDWsXS+KZ4g2Ckzksd1ymzsIEbo4= go.opentelemetry.io/otel/log v0.19.0/go.mod h1:5DQYeGmxVIr4n0/BcJvF4upsraHjg6vudJJpnkL6Ipk= -go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM= -go.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY= -go.opentelemetry.io/otel/sdk v1.43.0 h1:pi5mE86i5rTeLXqoF/hhiBtUNcrAGHLKQdhg4h4V9Dg= -go.opentelemetry.io/otel/sdk v1.43.0/go.mod h1:P+IkVU3iWukmiit/Yf9AWvpyRDlUeBaRg6Y+C58QHzg= +go.opentelemetry.io/otel/metric v1.45.0 h1:7Eg1uH7CJ5cXv9is6tnBe1FI6rj1nwUdbFypRm3br/M= +go.opentelemetry.io/otel/metric v1.45.0/go.mod h1:HAPbm1nd3p1PmFH7v2dR+6BjXxw+Lq4a2+pndMAm08s= +go.opentelemetry.io/otel/sdk v1.45.0 h1:4VVSMgQ83dUgW2aoX5f6JgLvHwIvzcuLnF9lUdCSpCw= +go.opentelemetry.io/otel/sdk v1.45.0/go.mod h1:Sr40LgXV7DsKMMJMKOhUWOgMWTfAaqvm2kF0g7ilwuA= go.opentelemetry.io/otel/sdk/log v0.19.0 h1:scYVLqT22D2gqXItnWiocLUKGH9yvkkeql5dBDiXyko= go.opentelemetry.io/otel/sdk/log v0.19.0/go.mod h1:vFBowwXGLlW9AvpuF7bMgnNI95LiW10szrOdvzBHlAg= -go.opentelemetry.io/otel/sdk/metric v1.43.0 h1:S88dyqXjJkuBNLeMcVPRFXpRw2fuwdvfCGLEo89fDkw= -go.opentelemetry.io/otel/sdk/metric v1.43.0/go.mod h1:C/RJtwSEJ5hzTiUz5pXF1kILHStzb9zFlIEe85bhj6A= -go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A= -go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0= -go.opentelemetry.io/proto/otlp v1.10.0 h1:IQRWgT5srOCYfiWnpqUYz9CVmbO8bFmKcwYxpuCSL2g= -go.opentelemetry.io/proto/otlp v1.10.0/go.mod h1:/CV4QoCR/S9yaPj8utp3lvQPoqMtxXdzn7ozvvozVqk= +go.opentelemetry.io/otel/sdk/metric v1.45.0 h1:oVFszMfyj1Am6s24Vtc7wBb8BKLcwepJjNEYILuiE3o= +go.opentelemetry.io/otel/sdk/metric v1.45.0/go.mod h1:vUWUxDZvu1WVRj8JA8S0AdhsPrZoDpA2DdZauIh4mDA= +go.opentelemetry.io/otel/trace v1.45.0 h1:l/mP6Uv7oNO7/TblbhpbgMidxhq1uO/rPsikOyVhxag= +go.opentelemetry.io/otel/trace v1.45.0/go.mod h1:qoJJA2xNMnxRrdISU/kLtfUH2wNeQbiv+jhs/CxI8bc= +go.opentelemetry.io/proto/otlp v1.11.0 h1:5rrYs0Ykyj50sdU/JU0x8etU+LubXWb+gED6TbEdMIk= +go.opentelemetry.io/proto/otlp v1.11.0/go.mod h1:SmVizdCOAm3XBtG1g1NnOdhW6jtddT72hLMhv8VwA8E= go.podman.io/common v0.66.1 h1:zDyd4HhVgQAN8LupBHCnhtM3FEOJ9DwmThjulXZq2qA= go.podman.io/common v0.66.1/go.mod h1:aNd2a0S7pY+fx1X5kpQYuF4hbwLU8ZOccuVrhu7h1Xc= go.podman.io/image/v5 v5.38.0 h1:aUKrCANkPvze1bnhLJsaubcfz0d9v/bSDLnwsXJm6G4= @@ -589,8 +589,8 @@ golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliY golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= -golang.org/x/crypto v0.53.0 h1:QZ4Muo8THX6CizN2vPPd5fBGHyogrdK9fG4wLPFUsto= -golang.org/x/crypto v0.53.0/go.mod h1:DNLU434OwVakk9PzuwV8w62mAJpRJL3vsgcfp4Qnsio= +golang.org/x/crypto v0.55.0 h1:+KWHjbgOaAQ66dh/YlkZKHlz9ZUlq61AFirAR9ntP8M= +golang.org/x/crypto v0.55.0/go.mod h1:uq0V9dE/fzQuJtbnL+2EhWOE63vo164FY8xqEnV9xis= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f h1:W3F4c+6OLc6H2lb//N1q4WpJkhzJCK5J6kUi1NTVXfM= golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f/go.mod h1:J1xhfL/vlindoeF/aINzNzt2Bket5bjo9sdOYzOsU80= @@ -604,8 +604,8 @@ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.37.0 h1:vF1DjpVEshcIqoEaauuHebaLk1O1forxjxBaVn884JQ= -golang.org/x/mod v0.37.0/go.mod h1:m8S8VeM9r4dzDwjrKO0a1sZP3YjeMamRRlD+fmR2Q/0= +golang.org/x/mod v0.38.0 h1:MECBjubtXD7yj4HrhIUcywNaGeNVUdfVnxmPajOk4yk= +golang.org/x/mod v0.38.0/go.mod h1:V6Xz0pq8TQ3dGqVQ1FVHuelZpAL0uNhSkk9ogYP3c40= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -622,8 +622,8 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= -golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o= -golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec= +golang.org/x/net v0.58.0 h1:ynWG7rqYi4ccpTEuPZ2QGWHktVEM9DMCj9yzDE0Q7To= +golang.org/x/net v0.58.0/go.mod h1:YwCddHnFlT7eLQqVprV19OnhLGtc5xOKgE0RyqgfWAU= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs= golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q= @@ -638,8 +638,8 @@ golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM= -golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= +golang.org/x/sync v0.22.0 h1:SZjpbeLmrCk4xhRSZFNZW5gFUeCeFgjekvI/+gfScek= +golang.org/x/sync v0.22.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -656,8 +656,8 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw= -golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs= +golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= 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= @@ -667,8 +667,8 @@ golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s= -golang.org/x/term v0.44.0 h1:0rLvDRCtNj0gZkyIXhCyOb2OAzEhLVqc4B+hrsBhrmc= -golang.org/x/term v0.44.0/go.mod h1:7ze4MdzUzLXpSAoFP1H0bOI9aXDqveSvatT5vKcFh2Y= +golang.org/x/term v0.45.0 h1:NwWyBmoJCbfTHpxrWoZ9C6/VxOf7ic219I8xZZFdrf0= +golang.org/x/term v0.45.0/go.mod h1:9aqxs0blBcrm/n0L9QW0aRVD+ktan8ssZromtqJC43w= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= @@ -678,8 +678,8 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= -golang.org/x/text v0.38.0 h1:sXmwo9DwP3OK9EZ7PqAdaooSGozfl/3a6/xJcbzPRhE= -golang.org/x/text v0.38.0/go.mod h1:YXZt3QhHUKYT53r2lLKFIVi6Ao1jdzrTR/KQ09qyxF4= +golang.org/x/text v0.41.0 h1:vz/seA0lnX87Othu2f/0L24RcgrXD9/YFTSuGjj3rH8= +golang.org/x/text v0.41.0/go.mod h1:jvf1O8ajNzZqhSrQBPbutR/EB83Cc0CFrezNQIwbb5M= golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U= golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -694,8 +694,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= -golang.org/x/tools v0.47.0 h1:7Kn5x/d1svx/PzryTsqeoZN4TZwqeH5pGWjefhLi/1Q= -golang.org/x/tools v0.47.0/go.mod h1:dFHnyTvFWY212G+h7ZY4Vsp/K3U4/7W9TyVaAul8uCA= +golang.org/x/tools v0.48.0 h1:3+hClM1aLL5mjMKm5ovokw9epgRXPuu2tILgismM6RE= +golang.org/x/tools v0.48.0/go.mod h1:08xX0orndb/F7jJxGDicx061tyd5pcMto75YMAXr6lk= golang.org/x/tools/go/expect v0.1.1-deprecated h1:jpBZDwmgPhXsKZC6WhL20P4b/wmnpsEAGHaNy0n/rJM= 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= @@ -713,17 +713,17 @@ google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98 google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20260319201613-d00831a3d3e7 h1:XzmzkmB14QhVhgnawEVsOn6OFsnpyxNPRY9QV01dNB0= google.golang.org/genproto v0.0.0-20260319201613-d00831a3d3e7/go.mod h1:L43LFes82YgSonw6iTXTxXUX1OlULt4AQtkik4ULL/I= -google.golang.org/genproto/googleapis/api v0.0.0-20260414002931-afd174a4e478 h1:yQugLulqltosq0B/f8l4w9VryjV+N/5gcW0jQ3N8Qec= -google.golang.org/genproto/googleapis/api v0.0.0-20260414002931-afd174a4e478/go.mod h1:C6ADNqOxbgdUUeRTU+LCHDPB9ttAMCTff6auwCVa4uc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260511170946-3700d4141b60 h1:seT2EwLWM78plQ7wcDfuWBc/4FAEAXDDiaSol4ku4qo= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260511170946-3700d4141b60/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= +google.golang.org/genproto/googleapis/api v0.0.0-20260803160001-6ac0973c030d h1:FarXi840EJWSHYTN3ERkADbPWjl307+FGrA22KAVjjc= +google.golang.org/genproto/googleapis/api v0.0.0-20260803160001-6ac0973c030d/go.mod h1:K/+WGbmBY7aNW1HDw1fJnKYo10i0DkAX6pows00dLig= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260803160001-6ac0973c030d h1:IL4hdHzcUv2l/gcg98/Rj3FbtE6axwqslOW8SW0C+S0= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260803160001-6ac0973c030d/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.82.1 h1:NnAxzGRA0677vCa4BUkOAnO5+FfQqVl9iUXeD0IqcGE= -google.golang.org/grpc v1.82.1/go.mod h1:yzTZ1TB1Z3SG+LIYaI+WiE8D5+PZ3ArnrSp8zF3+/ZA= +google.golang.org/grpc v1.83.2 h1:EManeRomTObA0BU7I8vXgg/78uE5MJ9M8B39EX2WscU= +google.golang.org/grpc v1.83.2/go.mod h1:YPI1hK3kDked6iHvgX3tR0y+nX/qpMFKhPgFsokw1S8= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -780,8 +780,8 @@ k8s.io/kubectl v0.35.1 h1:zP3Er8C5i1dcAFUMh9Eva0kVvZHptXIn/+8NtRWMxwg= k8s.io/kubectl v0.35.1/go.mod h1:cQ2uAPs5IO/kx8R5s5J3Ihv3VCYwrx0obCXum0CvnXo= k8s.io/utils v0.0.0-20260108192941-914a6e750570 h1:JT4W8lsdrGENg9W+YwwdLJxklIuKWdRm+BC+xt33FOY= k8s.io/utils v0.0.0-20260108192941-914a6e750570/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk= -oras.land/oras-go/v2 v2.6.0 h1:X4ELRsiGkrbeox69+9tzTu492FMUu7zJQW6eJU+I2oc= -oras.land/oras-go/v2 v2.6.0/go.mod h1:magiQDfG6H1O9APp+rOsvCPcW1GD2MM7vgnKY0Y+u1o= +oras.land/oras-go/v2 v2.6.2 h1:N04RXngAp1LJKTG6ifz3xHPipasEkWr+hFmInja5YKo= +oras.land/oras-go/v2 v2.6.2/go.mod h1:PlTtg4JTDJkDe8yVHpM2wz7/YDc00GVas+i4jAW2TZ4= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.34.0 h1:hSfpvjjTQXQY2Fol2CS0QHMNs/WI1MOSGzCm1KhM5ec= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.34.0/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw= sigs.k8s.io/controller-runtime v0.23.1 h1:TjJSM80Nf43Mg21+RCy3J70aj/W6KyvDtOlpKf+PupE= diff --git a/operator/tools/yq/go.mod b/operator/tools/yq/go.mod index 2e37eb540e772..ae946785ad2b6 100644 --- a/operator/tools/yq/go.mod +++ b/operator/tools/yq/go.mod @@ -2,13 +2,14 @@ module github.com/stackrox/rox/operator/tools/yq go 1.26.3 -require github.com/mikefarah/yq/v4 v4.53.3 +require github.com/mikefarah/yq/v4 v4.54.1 require ( github.com/a8m/envsubst v1.4.3 // indirect github.com/agext/levenshtein v1.2.1 // indirect github.com/alecthomas/participle/v2 v2.1.4 // indirect github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect + github.com/apparentlymart/go-textseg/v17 v17.0.1 // indirect github.com/dimchansky/utfbom v1.1.1 // indirect github.com/elliotchance/orderedmap v1.8.0 // indirect github.com/fatih/color v1.19.0 // indirect @@ -16,23 +17,23 @@ require ( github.com/goccy/go-json v0.10.6 // indirect github.com/goccy/go-yaml v1.19.2 // indirect github.com/google/go-cmp v0.6.0 // indirect - github.com/hashicorp/hcl/v2 v2.24.0 // indirect + github.com/hashicorp/hcl/v2 v2.25.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jinzhu/copier v0.4.0 // indirect - github.com/magiconair/properties v1.8.10 // indirect + github.com/magiconair/properties v1.18.12 // indirect github.com/mattn/go-colorable v0.1.14 // indirect - github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-isatty v0.0.24 // indirect github.com/mitchellh/go-wordwrap v1.0.1 // indirect - github.com/pelletier/go-toml/v2 v2.3.1 // indirect + github.com/pelletier/go-toml/v2 v2.4.3 // indirect github.com/spf13/cobra v1.10.2 // indirect github.com/spf13/pflag v1.0.10 // indirect github.com/yuin/gopher-lua v1.1.2 // indirect - github.com/zclconf/go-cty v1.18.1 // indirect - go.yaml.in/yaml/v4 v4.0.0-rc.4 // indirect - golang.org/x/mod v0.36.0 // indirect - golang.org/x/net v0.55.0 // indirect - golang.org/x/sync v0.20.0 // indirect - golang.org/x/sys v0.45.0 // indirect - golang.org/x/text v0.37.0 // indirect - golang.org/x/tools v0.44.0 // indirect + github.com/zclconf/go-cty v1.19.0 // indirect + go.yaml.in/yaml/v4 v4.0.0-rc.6 // indirect + golang.org/x/mod v0.41.0 // indirect + golang.org/x/net v0.59.0 // indirect + golang.org/x/sync v0.23.0 // indirect + golang.org/x/sys v0.48.0 // indirect + golang.org/x/text v0.42.0 // indirect + golang.org/x/tools v0.49.0 // indirect ) diff --git a/operator/tools/yq/go.sum b/operator/tools/yq/go.sum index 1597a5ce1c948..81dbe3c8b66ed 100644 --- a/operator/tools/yq/go.sum +++ b/operator/tools/yq/go.sum @@ -6,10 +6,12 @@ github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8v github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= github.com/alecthomas/participle/v2 v2.1.4 h1:W/H79S8Sat/krZ3el6sQMvMaahJ+XcM9WSI2naI7w2U= github.com/alecthomas/participle/v2 v2.1.4/go.mod h1:8tqVbpTX20Ru4NfYQgZf4mP18eXPTBViyMWiArNEgGI= -github.com/alecthomas/repr v0.5.2 h1:SU73FTI9D1P5UNtvseffFSGmdNci/O6RsqzeXJtP0Qs= -github.com/alecthomas/repr v0.5.2/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= +github.com/alecthomas/repr v0.5.4 h1:OVP7JEcuzU9CCDsT6STCr3rg17oQfWILtPWd2EG0uN4= +github.com/alecthomas/repr v0.5.4/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY= github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4= +github.com/apparentlymart/go-textseg/v17 v17.0.1 h1:bpMXRgQ5cEoRNuQke1a80/Nl6w3G5eoIbWo9f3gXkAs= +github.com/apparentlymart/go-textseg/v17 v17.0.1/go.mod h1:fa8X4jgGeevslICIY6LcdjkSecWnXmYd9Lk34z/VxZs= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -30,26 +32,26 @@ github.com/goccy/go-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM= github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/hashicorp/hcl/v2 v2.24.0 h1:2QJdZ454DSsYGoaE6QheQZjtKZSUs9Nh2izTWiwQxvE= -github.com/hashicorp/hcl/v2 v2.24.0/go.mod h1:oGoO1FIQYfn/AgyOhlg9qLC6/nOJPX3qGbkZpYAcqfM= +github.com/hashicorp/hcl/v2 v2.25.0 h1:HmmQVYRny4MaBo4b20TjmL46wyuUxpnMWkPZ4+NTbWk= +github.com/hashicorp/hcl/v2 v2.25.0/go.mod h1:vR+FKETxoZAmRlHgFfKmuqivj+C4Izm/c66XkmZ3r7M= github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8= github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= -github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE= -github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/magiconair/properties v1.18.12 h1:sT9zQpvTB3B4gzrX0tmZNTEaGyg8Zw55MFYRE32Mr9I= +github.com/magiconair/properties v1.18.12/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= -github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= -github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mikefarah/yq/v4 v4.53.3 h1:S0kwPkINdOjgPskW5CfYTGo/Vt7c3gUnUkKSp7CNqD0= -github.com/mikefarah/yq/v4 v4.53.3/go.mod h1:4mvgujMtSAB3lA27+lwg8eIud/4QUQw2/1rLbxgiauw= +github.com/mattn/go-isatty v0.0.24 h1:tGZZoVgT/KiqK1c8ocVLeDS8BSWMRd47J3Lbz7vsReI= +github.com/mattn/go-isatty v0.0.24/go.mod h1:nMCL3Zebbrt45jsMDgnfIwz6ydEQApk5oEI3HqDio6A= +github.com/mikefarah/yq/v4 v4.54.1 h1:wFk+RhKFcx6fU6tkjC9z069vLTL4uDoXi9R4SytFB8s= +github.com/mikefarah/yq/v4 v4.54.1/go.mod h1:2s/axTs7Quuo86zZrkN/2QjflxEtFay8aynJsuNT6Mw= github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= -github.com/pelletier/go-toml/v2 v2.3.1 h1:MYEvvGnQjeNkRF1qUuGolNtNExTDwct51yp7olPtrEc= -github.com/pelletier/go-toml/v2 v2.3.1/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= +github.com/pelletier/go-toml/v2 v2.4.3 h1:GTRvJQutkOSftxIFD5xw9aepkYNuPWmVJpffdDPYVpY= +github.com/pelletier/go-toml/v2 v2.4.3/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e h1:aoZm08cpOy4WuID//EZDgcC4zIxODThtZNPirFr42+A= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -65,26 +67,25 @@ github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5Cc github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/yuin/gopher-lua v1.1.2 h1:yF/FjE3hD65tBbt0VXLE13HWS9h34fdzJmrWRXwobGA= github.com/yuin/gopher-lua v1.1.2/go.mod h1:7aRmXIWl37SqRf0koeyylBEzJ+aPt8A+mmkQ4f1ntR8= -github.com/zclconf/go-cty v1.18.1 h1:yEGE8M4iIZlyKQURZNb2SnEyZlZHUcBCnx6KF81KuwM= -github.com/zclconf/go-cty v1.18.1/go.mod h1:qpnV6EDNgC1sns/AleL1fvatHw72j+S+nS+MJ+T2CSg= +github.com/zclconf/go-cty v1.19.0 h1:IV8WdqYZc2c5rLX9bEoLNXKojBAp0MZPBHMIrCoa/s4= +github.com/zclconf/go-cty v1.19.0/go.mod h1:12W89jGn3JCOIQi7infWr9m80rOkb5RNYJqXMZcN4c8= github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940 h1:4r45xpDWB6ZMSMNJFMOjqrGHynW3DIBuR2H9j0ug+Mo= github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940/go.mod h1:CmBdvvj3nqzfzJ6nTCIwDTPZ56aVGvDrmztiO5g3qrM= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= -go.yaml.in/yaml/v4 v4.0.0-rc.4 h1:UP4+v6fFrBIb1l934bDl//mmnoIZEDK0idg1+AIvX5U= -go.yaml.in/yaml/v4 v4.0.0-rc.4/go.mod h1:aZqd9kCMsGL7AuUv/m/PvWLdg5sjJsZ4oHDEnfPPfY0= -golang.org/x/mod v0.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4= -golang.org/x/mod v0.36.0/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ= -golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8= -golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww= -golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= -golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY= -golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= -golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc= -golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38= -golang.org/x/tools v0.44.0 h1:UP4ajHPIcuMjT1GqzDWRlalUEoY+uzoZKnhOjbIPD2c= -golang.org/x/tools v0.44.0/go.mod h1:KA0AfVErSdxRZIsOVipbv3rQhVXTnlU6UhKxHd1seDI= +go.yaml.in/yaml/v4 v4.0.0-rc.6 h1:1h7H1ohdUh93/FyE4YaDa1Zh64K6VVbjF4K6WUxMtH4= +go.yaml.in/yaml/v4 v4.0.0-rc.6/go.mod h1:aZqd9kCMsGL7AuUv/m/PvWLdg5sjJsZ4oHDEnfPPfY0= +golang.org/x/mod v0.41.0 h1:qJmnOUb4YB+FsEuM3HcWucdZASCPGhsX6uljO6pog0c= +golang.org/x/mod v0.41.0/go.mod h1:Ek9pY8RKWXwsWvd3rQiHYtMqkjSUV+s1Rj7j4H5Ur6o= +golang.org/x/net v0.59.0 h1:5zfYln+w5XCxwrnMMJPufRgNoXEaGxl0wo5GqPXyues= +golang.org/x/net v0.59.0/go.mod h1:2DA/G1UfVbCpQPeWTmMPGY7Cs2PkBkwu743bVX5PIVg= +golang.org/x/sync v0.23.0 h1:KameEIfc1IkluZyXWLn39Wd4tURc6GbCiISGiZm2bQk= +golang.org/x/sync v0.23.0/go.mod h1:sUUOizhqBxiL6pEWpqNLUiaJn1ShEbZ6BBqskPbjZm0= +golang.org/x/sys v0.48.0 h1:bbX/i/6MgT9BVLM9RT1thmxL04yeTAhbEz4SyadbXoo= +golang.org/x/sys v0.48.0/go.mod h1:hNLxWAXmnKAxqDtdwIYC4bM9oQPEecfsnNMuSxOs3og= +golang.org/x/text v0.42.0 h1:JbOZXgfeCPU9gacVtYliJqOhD+zhrEqK4LfdpmlUZqI= +golang.org/x/text v0.42.0/go.mod h1:ojzP1Z+2QtioaF8DTtO8K5q7JWVVYwZKenzujK0Zd0E= +golang.org/x/tools v0.49.0 h1:3NI7VXzL9+1WZD52Dx2ttoPwD5DWrFGpl9mFZDlmisI= +golang.org/x/tools v0.49.0/go.mod h1:SJNXV9DBKT0UbdttsQjbfJlAE/q+y36++zo3uL3N0Oo= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/pkg/auth/authproviders/oidc/backend_factory_impl.go b/pkg/auth/authproviders/oidc/backend_factory_impl.go index e3f16b348f5d1..2e745e545063a 100644 --- a/pkg/auth/authproviders/oidc/backend_factory_impl.go +++ b/pkg/auth/authproviders/oidc/backend_factory_impl.go @@ -20,10 +20,6 @@ const ( // TypeName is the standard type name for OIDC auth providers. TypeName = "oidc" - // TypeNameWithACMAccessControlDelegation is the type name for OIDC auth providers - // with role resolution from ACM. - TypeNameWithACMAccessControlDelegation = authproviders.OIDCTypeNameWithACMRoles - callbackRelativePath = "callback" nonceTTL = 1 * time.Minute diff --git a/pkg/auth/authproviders/provider_options.go b/pkg/auth/authproviders/provider_options.go index e7896739add1b..5409952ada564 100644 --- a/pkg/auth/authproviders/provider_options.go +++ b/pkg/auth/authproviders/provider_options.go @@ -166,3 +166,18 @@ func WithVisibility(visibility storage.Traits_Visibility) ProviderOption { return nil } } + +// WithOrigin sets the origin for the auth provider. +func WithOrigin(origin storage.Traits_Origin) ProviderOption { + return func(pr *providerImpl) error { + if pr.storedInfo == nil { + return errox.InvariantViolation.CausedBy("no storage data for auth provider") + } + if pr.storedInfo.GetTraits() != nil { + pr.storedInfo.Traits.Origin = origin + } else { + pr.storedInfo.Traits = &storage.Traits{Origin: origin} + } + return nil + } +} diff --git a/pkg/auth/authproviders/registry_impl.go b/pkg/auth/authproviders/registry_impl.go index c09c10178af9d..2e01d81d1a329 100644 --- a/pkg/auth/authproviders/registry_impl.go +++ b/pkg/auth/authproviders/registry_impl.go @@ -24,7 +24,6 @@ import ( const ( OpenShiftTypeNameWithACMAccessControlDelegation = "openshift-with-acm-roles" - OIDCTypeNameWithACMRoles = "oidc-with-acm-roles" ) var ( @@ -382,12 +381,6 @@ func (r *registryImpl) issueTokenForResponse(ctx context.Context, provider Provi return nil, nil, err } roxClaims.InternalRoles = roles - case OIDCTypeNameWithACMRoles: - roles, err := getRolesForOIDCResponse(ctx, authResp, r.clusterResolver) - if err != nil { - return nil, nil, err - } - roxClaims.InternalRoles = roles default: roxClaims.ExternalUser = authResp.Claims } @@ -460,45 +453,13 @@ func getRolesForOpenshiftResponse( if err != nil { return nil, errox.InvalidArgs.CausedByf("failed to parse token: %v", err) } - acmClientObj, err := getACMClientForToken(tokenData.AccessToken) - if err != nil { - return nil, errors.Wrap(err, "failed to get ACM client") - } - roles, err := externalrolebroker.GetResolvedRolesFromACM(ctx, acmClientObj, clusterIDResolver) - if err != nil { - return nil, errors.Wrap(err, "failed to fetch role information") - } - return roles, nil -} - -func getRolesForOIDCResponse( - ctx context.Context, - authResp *AuthResponse, - clusterIDResolver tokens.ClusterResolver, -) ([]*tokens.InternalRole, error) { - if authResp == nil { - return nil, errox.InvalidArgs.CausedBy("auth response must not be nil") - } - acmClientObj, err := getACMClientForToken(authResp.IdpToken) - if err != nil { - return nil, errors.Wrap(err, "failed to get ACM client") - } - roles, err := externalrolebroker.GetResolvedRolesFromACM(ctx, acmClientObj, clusterIDResolver) - if err != nil { - return nil, errors.Wrap(err, "failed to fetch role information") - } - return roles, nil - -} - -func getACMClientForToken(token string) (*acm.Client, error) { // Retrieve OpenShift cluster config cfg, err := rest.InClusterConfig() if err != nil { return nil, errors.Wrap(err, "failed to get cluster config") } // Enrich the config with the OpenShift Auth Token - cfg.BearerToken = token + cfg.BearerToken = tokenData.AccessToken // Clear BearerTokenFile so that BearerToken takes precedence. // InClusterConfig() sets BearerTokenFile to the service account token, // which would override the user's OAuth token we just set. @@ -507,15 +468,17 @@ func getACMClientForToken(token string) (*acm.Client, error) { if err != nil { return nil, errors.Wrap(err, "failed to instantiate ACM client") } - return acmClientObj, nil + roles, err := externalrolebroker.GetResolvedRolesFromACM(ctx, acmClientObj, clusterIDResolver) + if err != nil { + return nil, errors.Wrap(err, "failed to fetch role information") + } + return roles, nil } func isACMRoleDelegationProvider(provider Provider) bool { switch provider.Type() { case OpenShiftTypeNameWithACMAccessControlDelegation: return true - case OIDCTypeNameWithACMRoles: - return true } return false } diff --git a/pkg/booleanpolicy/evaluator/base_evaluators.go b/pkg/booleanpolicy/evaluator/base_evaluators.go index 78fec49431158..d187c64eb5a64 100644 --- a/pkg/booleanpolicy/evaluator/base_evaluators.go +++ b/pkg/booleanpolicy/evaluator/base_evaluators.go @@ -252,7 +252,7 @@ func generateTimestampMatcher(value string, matchAll bool) (baseMatcherAndExtrac } } return func(instance reflect.Value) []valueMatchedPair { - ts, ok := instance.Interface().(*protocompat.Timestamp) + ts, ok := reflect.TypeAssert[*protocompat.Timestamp](instance) if !ok { return nil } @@ -335,7 +335,7 @@ func generateBoolMatcher(value string, _ reflect.Type, matchAll bool) (baseMatch } func generateIntMatcher(value string, fieldType reflect.Type, matchAll bool) (baseMatcherAndExtractor, error) { - if enum, ok := reflect.Zero(fieldType).Interface().(protoreflect.ProtoEnum); ok { + if enum, ok := reflect.TypeAssert[protoreflect.ProtoEnum](reflect.Zero(fieldType)); ok { return generateEnumMatcher(value, enum, matchAll) } if matchAll && value != "" { diff --git a/pkg/centralsensor/caps_list.go b/pkg/centralsensor/caps_list.go index 6a90ecbaa50b8..e594c6fd237bf 100644 --- a/pkg/centralsensor/caps_list.go +++ b/pkg/centralsensor/caps_list.go @@ -109,4 +109,9 @@ const ( // VirtualMachineTelemetryCap lets Central distinguish "VM scanning off on // a new Sensor" from "old Sensor that predates VM telemetry fields." VirtualMachineTelemetryCap SensorCapability = "VirtualMachineTelemetry" + + // WorkloadKindExclusionCap identifies the capability of Sensor to honor + // Exclusion.exclude_by_kind rules. Central strips those rules when syncing + // policies to Sensors that lack this capability. + WorkloadKindExclusionCap SensorCapability = "WorkloadKindExclusion" ) diff --git a/pkg/clientconn/roxctl_command_header.go b/pkg/clientconn/roxctl_command_header.go index 80dd0bddb54d5..16750449bc5dc 100644 --- a/pkg/clientconn/roxctl_command_header.go +++ b/pkg/clientconn/roxctl_command_header.go @@ -12,3 +12,8 @@ const RoxctlCommandIndexHeader = "Rh-Roxctl-Command-Index" // ExecutionEnvironment is the HTTP header name with the custom execution // environment string. Can be supplied by roxctl, or any other API client. const ExecutionEnvironment = "Rh-Execution-Environment" + +// CentralVersionHeader is the gRPC response metadata key carrying the +// Central version. Set by Central for authenticated requests so that +// clients (e.g. roxctl) can detect version skew without an extra RPC. +const CentralVersionHeader = "Rh-Central-Version" diff --git a/pkg/cluster/filtering.go b/pkg/cluster/filtering.go index b0ec02528ba8b..d10bdcbc6b86a 100644 --- a/pkg/cluster/filtering.go +++ b/pkg/cluster/filtering.go @@ -12,13 +12,7 @@ const ( ) func GetNamespaceFilter(cluster *storage.Cluster) *string { - var config *storage.DynamicClusterConfig_ProcessIndicatorsConfig - - if cluster.GetManagedBy() == storage.ManagerType_MANAGER_TYPE_MANUAL || cluster.GetManagedBy() == storage.ManagerType_MANAGER_TYPE_UNKNOWN { - config = cluster.GetDynamicConfig().GetProcessIndicators() - } else { - config = cluster.GetHelmConfig().GetDynamicConfig().GetProcessIndicators() - } + config := getProcessIndicatorsConfig(cluster) // No configuration for runtime data means no filter if config == nil { @@ -49,3 +43,15 @@ func GetNamespaceFilter(cluster *storage.Cluster) *string { return new(filter) } + +// IsNoPersistenceEnabled reports whether process indicators must not be persisted for the cluster. +func IsNoPersistenceEnabled(cluster *storage.Cluster) bool { + return getProcessIndicatorsConfig(cluster).GetNoPersistence() +} + +func getProcessIndicatorsConfig(cluster *storage.Cluster) *storage.DynamicClusterConfig_ProcessIndicatorsConfig { + if cluster.GetManagedBy() == storage.ManagerType_MANAGER_TYPE_MANUAL || cluster.GetManagedBy() == storage.ManagerType_MANAGER_TYPE_UNKNOWN { + return cluster.GetDynamicConfig().GetProcessIndicators() + } + return cluster.GetHelmConfig().GetDynamicConfig().GetProcessIndicators() +} diff --git a/pkg/cluster/validation.go b/pkg/cluster/validation.go index 0a64a034da58c..064e19b2a3977 100644 --- a/pkg/cluster/validation.go +++ b/pkg/cluster/validation.go @@ -2,6 +2,7 @@ package cluster import ( "fmt" + "regexp" "strings" "github.com/distribution/reference" @@ -29,6 +30,9 @@ func Validate(cluster *storage.Cluster) *errorhelpers.ErrorList { // Some fields are allowed to be left empty for the server to complete with default values. func ValidatePartial(cluster *storage.Cluster) *errorhelpers.ErrorList { errorList := errorhelpers.NewErrorList("Cluster Validation") + if err := ValidateConfiguredNamespaceFilter(cluster); err != nil { + errorList.AddError(err) + } if cluster.GetName() == "" { errorList.AddString("Cluster name is required") } @@ -79,6 +83,19 @@ func ValidatePartial(cluster *storage.Cluster) *errorhelpers.ErrorList { return errorList } +// ValidateConfiguredNamespaceFilter checks the stored filter even when NoPersistence masks it. +func ValidateConfiguredNamespaceFilter(cluster *storage.Cluster) error { + config := getProcessIndicatorsConfig(cluster) + if config == nil { + return nil + } + filter := config.GetExcludeNamespaceFilter() + if _, err := regexp.Compile(filter); err != nil { + return fmt.Errorf("invalid excluded namespaces filter %q: %w", filter, err) + } + return nil +} + // GetAutoLockProcessBaselinesEnabled returns whether the auto-lock process baselines feature is enabled // for the given cluster. For manually managed clusters, it reads from the cluster's dynamic config. // For helm/operator-managed clusters, it reads from the cluster's helm config. diff --git a/pkg/cluster/validation_test.go b/pkg/cluster/validation_test.go index 8c156e034aeb5..fc71eca11ec2d 100644 --- a/pkg/cluster/validation_test.go +++ b/pkg/cluster/validation_test.go @@ -99,6 +99,42 @@ func TestPartialValidation(t *testing.T) { cluster.Type = storage.ClusterType_OPENSHIFT4_CLUSTER }, }, + "Invalid manual namespace filter should fail": { + configureClusterFn: func(cluster *storage.Cluster) { + cluster.DynamicConfig = &storage.DynamicClusterConfig{ + ProcessIndicators: &storage.DynamicClusterConfig_ProcessIndicatorsConfig{ExcludeNamespaceFilter: "["}, + } + }, + expectedErrors: []string{"invalid excluded namespaces filter", "missing closing ]"}, + }, + "Invalid Helm namespace filter should fail": { + configureClusterFn: func(cluster *storage.Cluster) { + cluster.ManagedBy = storage.ManagerType_MANAGER_TYPE_HELM_CHART + cluster.HelmConfig = &storage.CompleteClusterConfig{DynamicConfig: &storage.DynamicClusterConfig{ + ProcessIndicators: &storage.DynamicClusterConfig_ProcessIndicatorsConfig{ExcludeNamespaceFilter: "["}, + }} + }, + expectedErrors: []string{"invalid excluded namespaces filter"}, + }, + "Invalid namespace filter should fail even with no persistence": { + configureClusterFn: func(cluster *storage.Cluster) { + cluster.DynamicConfig = &storage.DynamicClusterConfig{ + ProcessIndicators: &storage.DynamicClusterConfig_ProcessIndicatorsConfig{ + ExcludeNamespaceFilter: "[", NoPersistence: true, + }, + } + }, + expectedErrors: []string{"invalid excluded namespaces filter"}, + }, + "Valid combined namespace filter should pass": { + configureClusterFn: func(cluster *storage.Cluster) { + cluster.DynamicConfig = &storage.DynamicClusterConfig{ + ProcessIndicators: &storage.DynamicClusterConfig_ProcessIndicatorsConfig{ + ExcludeNamespaceFilter: "test-.*", ExcludeOpenshiftNs: true, + }, + } + }, + }, } for name, c := range cases { diff --git a/pkg/clusterhealth/status.go b/pkg/clusterhealth/status.go index 1d451ca4aaf36..a5fe930db215d 100644 --- a/pkg/clusterhealth/status.go +++ b/pkg/clusterhealth/status.go @@ -121,6 +121,16 @@ func PopulateLocalScannerStatus(localScannerHealthInfo *storage.ScannerHealthInf return storage.ClusterHealthStatus_UNINITIALIZED } + // A non-nil ScannerHealthInfo means local image scanning is enabled on the secured + // cluster. If Sensor could not gather scanner health it reports the reason(s) via + // StatusErrors and leaves the pod counts unset, e.g. a misconfiguration (local scanning + // enabled but Scanner V4 is not) or a missing scanner deployment. Reporting UNHEALTHY + // distinguishes this "enabled but broken" state from the "not installed" case above and + // surfaces the problem to the user. + if len(localScannerHealthInfo.GetStatusErrors()) > 0 { + return storage.ClusterHealthStatus_UNHEALTHY + } + desiredPods := localScannerHealthInfo.GetTotalDesiredAnalyzerPods() readyPods := localScannerHealthInfo.GetTotalReadyAnalyzerPods() diff --git a/pkg/clusterhealth/status_test.go b/pkg/clusterhealth/status_test.go index 440e0537497b9..4f6228e4cc3bb 100644 --- a/pkg/clusterhealth/status_test.go +++ b/pkg/clusterhealth/status_test.go @@ -270,3 +270,88 @@ func TestOverallHealth(t *testing.T) { }) } } + +func TestPopulateLocalScannerStatus(t *testing.T) { + cases := map[string]struct { + scannerHealthInfo *storage.ScannerHealthInfo + expected storage.ClusterHealthStatus_HealthStatusLabel + }{ + "nil: local scanning not enabled (optional component)": { + scannerHealthInfo: nil, + expected: storage.ClusterHealthStatus_UNINITIALIZED, + }, + "status errors: enabled but misconfigured (no scanner v4)": { + scannerHealthInfo: &storage.ScannerHealthInfo{ + StatusErrors: []string{"local image scanning is enabled but Scanner V4 is not enabled"}, + }, + expected: storage.ClusterHealthStatus_UNHEALTHY, + }, + "status errors take precedence over pod counts": { + scannerHealthInfo: &storage.ScannerHealthInfo{ + StatusErrors: []string{"unable to find scanner deployment"}, + TotalDesiredAnalyzerPodsOpt: analyzerPodsDesired(3), + TotalReadyAnalyzerPodsOpt: analyzerPodsReady(3), + TotalReadyDbPodsOpt: dbPodsReady(1), + }, + expected: storage.ClusterHealthStatus_UNHEALTHY, + }, + "no pod counts, no errors: uninitialized": { + scannerHealthInfo: &storage.ScannerHealthInfo{}, + expected: storage.ClusterHealthStatus_UNINITIALIZED, + }, + "desired analyzer pods zero: uninitialized": { + scannerHealthInfo: &storage.ScannerHealthInfo{ + TotalDesiredAnalyzerPodsOpt: analyzerPodsDesired(0), + TotalReadyAnalyzerPodsOpt: analyzerPodsReady(0), + }, + expected: storage.ClusterHealthStatus_UNINITIALIZED, + }, + "no ready db pods: unhealthy": { + scannerHealthInfo: &storage.ScannerHealthInfo{ + TotalDesiredAnalyzerPodsOpt: analyzerPodsDesired(3), + TotalReadyAnalyzerPodsOpt: analyzerPodsReady(3), + TotalReadyDbPodsOpt: dbPodsReady(0), + }, + expected: storage.ClusterHealthStatus_UNHEALTHY, + }, + "all analyzer and db pods ready: healthy": { + scannerHealthInfo: &storage.ScannerHealthInfo{ + TotalDesiredAnalyzerPodsOpt: analyzerPodsDesired(3), + TotalReadyAnalyzerPodsOpt: analyzerPodsReady(3), + TotalReadyDbPodsOpt: dbPodsReady(1), + }, + expected: storage.ClusterHealthStatus_HEALTHY, + }, + "some analyzer pods not ready: degraded": { + scannerHealthInfo: &storage.ScannerHealthInfo{ + TotalDesiredAnalyzerPodsOpt: analyzerPodsDesired(3), + TotalReadyAnalyzerPodsOpt: analyzerPodsReady(2), + TotalReadyDbPodsOpt: dbPodsReady(1), + }, + expected: storage.ClusterHealthStatus_DEGRADED, + }, + "most analyzer pods not ready: unhealthy": { + scannerHealthInfo: &storage.ScannerHealthInfo{ + TotalDesiredAnalyzerPodsOpt: analyzerPodsDesired(3), + TotalReadyAnalyzerPodsOpt: analyzerPodsReady(1), + TotalReadyDbPodsOpt: dbPodsReady(1), + }, + expected: storage.ClusterHealthStatus_UNHEALTHY, + }, + } + for name, c := range cases { + t.Run(name, func(t *testing.T) { + assert.Equal(t, c.expected, PopulateLocalScannerStatus(c.scannerHealthInfo)) + }) + } +} + +func analyzerPodsDesired(num int32) *storage.ScannerHealthInfo_TotalDesiredAnalyzerPods { + return &storage.ScannerHealthInfo_TotalDesiredAnalyzerPods{TotalDesiredAnalyzerPods: num} +} +func analyzerPodsReady(num int32) *storage.ScannerHealthInfo_TotalReadyAnalyzerPods { + return &storage.ScannerHealthInfo_TotalReadyAnalyzerPods{TotalReadyAnalyzerPods: num} +} +func dbPodsReady(num int32) *storage.ScannerHealthInfo_TotalReadyDbPods { + return &storage.ScannerHealthInfo_TotalReadyDbPods{TotalReadyDbPods: num} +} diff --git a/pkg/concurrency/value_stream.go b/pkg/concurrency/value_stream.go index 354be592cb9d3..c106a7d9faafb 100644 --- a/pkg/concurrency/value_stream.go +++ b/pkg/concurrency/value_stream.go @@ -101,7 +101,7 @@ func (i *valueStreamIterBase[T]) Done() <-chan struct{} { return i.nextC } -func (*valueStreamIterBase[T]) isValueStreamIter(T) {} //nolint:unused // This is required for generic magic +func (*valueStreamIterBase[T]) isValueStreamIter(T) {} type valueStreamStrictIter[T any] struct { valueStreamIterBase[T] diff --git a/pkg/declarativeconfig/context.go b/pkg/declarativeconfig/context.go index b507bbc34d561..658247c115a93 100644 --- a/pkg/declarativeconfig/context.go +++ b/pkg/declarativeconfig/context.go @@ -10,6 +10,7 @@ type originCheckerKey struct{} const allowOnlyDeclarativeOperations = 0 const allowModifyDeclarativeOrImperative = 1 +const allowDefaultOperations = 2 // WithModifyDeclarativeResource returns a context that is a child of the given context and allows to modify // proto messages with the traits origin == DECLARATIVE. @@ -23,6 +24,13 @@ func WithModifyDeclarativeOrImperative(ctx context.Context) context.Context { return context.WithValue(ctx, originCheckerKey{}, allowModifyDeclarativeOrImperative) } +// WithModifyDefaultResource returns a context that allows creating and modifying +// proto messages with the traits origin == DEFAULT. This is intended for internal +// seeding of system-managed objects that should not be user-modifiable. +func WithModifyDefaultResource(ctx context.Context) context.Context { + return context.WithValue(ctx, originCheckerKey{}, allowDefaultOperations) +} + // ResourceWithTraits is a common interface for proto messages containing storage.Traits. type ResourceWithTraits interface { GetTraits() *storage.Traits @@ -37,11 +45,14 @@ func HasModifyDeclarativeResourceKey(ctx context.Context) bool { // CanModifyResource returns whether context holder is allowed to modify resource. func CanModifyResource(ctx context.Context, resource ResourceWithTraits) bool { - if ctx.Value(originCheckerKey{}) == allowOnlyDeclarativeOperations { + switch ctx.Value(originCheckerKey{}) { + case allowOnlyDeclarativeOperations: return IsDeclarativeOrigin(resource) - } - if ctx.Value(originCheckerKey{}) == allowModifyDeclarativeOrImperative { + case allowModifyDeclarativeOrImperative: return IsDeclarativeOrigin(resource) || IsImperativeOrigin(resource) || IsEphemeralOrigin(resource) + case allowDefaultOperations: + return IsDefaultOrigin(resource) + default: + return IsImperativeOrigin(resource) || IsEphemeralOrigin(resource) } - return IsImperativeOrigin(resource) || IsEphemeralOrigin(resource) } diff --git a/pkg/declarativeconfig/context_test.go b/pkg/declarativeconfig/context_test.go index fd850da97f5b4..8444aedc0de60 100644 --- a/pkg/declarativeconfig/context_test.go +++ b/pkg/declarativeconfig/context_test.go @@ -24,6 +24,7 @@ func TestContext(t *testing.T) { ctx := context.Background() declarativeCtx := WithModifyDeclarativeResource(ctx) declarativeOrImperativeCtx := WithModifyDeclarativeOrImperative(ctx) + defaultCtx := WithModifyDefaultResource(ctx) // 1.1. empty context can modify imperative origin assert.True(t, CanModifyResource(ctx, imperativeResource)) // 1.2. empty context can modify ephemeral origin @@ -48,4 +49,10 @@ func TestContext(t *testing.T) { assert.True(t, CanModifyResource(declarativeOrImperativeCtx, ephemeralResource)) // 9. context.WithModifyDeclarativeOrImperative can't modify default origin assert.False(t, CanModifyResource(declarativeOrImperativeCtx, defaultResource)) + // 10. context.WithModifyDefaultResource can modify default origin + assert.True(t, CanModifyResource(defaultCtx, defaultResource)) + // 11.1. context.WithModifyDefaultResource can't modify imperative origin + assert.False(t, CanModifyResource(defaultCtx, imperativeResource)) + // 11.2. context.WithModifyDefaultResource can't modify declarative origin + assert.False(t, CanModifyResource(defaultCtx, declarativeResource)) } diff --git a/pkg/declarativeconfig/origin.go b/pkg/declarativeconfig/origin.go index f23b14a6a7cd0..7b406e0a7bd37 100644 --- a/pkg/declarativeconfig/origin.go +++ b/pkg/declarativeconfig/origin.go @@ -28,3 +28,8 @@ func IsEphemeralOrigin(resource ResourceWithTraits) bool { func IsImperativeOrigin(resource ResourceWithTraits) bool { return resource.GetTraits().GetOrigin() == storage.Traits_IMPERATIVE } + +// IsDefaultOrigin returns whether origin of resource is default or not. +func IsDefaultOrigin(resource ResourceWithTraits) bool { + return resource.GetTraits().GetOrigin() == storage.Traits_DEFAULT +} diff --git a/pkg/delegatedregistry/delegator.go b/pkg/delegatedregistry/delegator.go index a22466ebb3f50..0b22df893ad40 100644 --- a/pkg/delegatedregistry/delegator.go +++ b/pkg/delegatedregistry/delegator.go @@ -28,5 +28,5 @@ type Delegator interface { // ValidateCluster returns nil if a cluster is a valid target for delegation, returns an // error otherwise. - ValidateCluster(clusterID string) error + ValidateCluster(ctx context.Context, clusterID string) error } diff --git a/pkg/delegatedregistry/mocks/delegator.go b/pkg/delegatedregistry/mocks/delegator.go index b9e01fe6b7022..6caf1c8279489 100644 --- a/pkg/delegatedregistry/mocks/delegator.go +++ b/pkg/delegatedregistry/mocks/delegator.go @@ -88,15 +88,15 @@ func (mr *MockDelegatorMockRecorder) GetDelegateClusterID(ctx, imgName any) *gom } // ValidateCluster mocks base method. -func (m *MockDelegator) ValidateCluster(clusterID string) error { +func (m *MockDelegator) ValidateCluster(ctx context.Context, clusterID string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ValidateCluster", clusterID) + ret := m.ctrl.Call(m, "ValidateCluster", ctx, clusterID) ret0, _ := ret[0].(error) return ret0 } // ValidateCluster indicates an expected call of ValidateCluster. -func (mr *MockDelegatorMockRecorder) ValidateCluster(clusterID any) *gomock.Call { +func (mr *MockDelegatorMockRecorder) ValidateCluster(ctx, clusterID any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateCluster", reflect.TypeOf((*MockDelegator)(nil).ValidateCluster), clusterID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateCluster", reflect.TypeOf((*MockDelegator)(nil).ValidateCluster), ctx, clusterID) } diff --git a/pkg/detection/compiled_policy.go b/pkg/detection/compiled_policy.go index 9fedc810495f5..351f03c45caf6 100644 --- a/pkg/detection/compiled_policy.go +++ b/pkg/detection/compiled_policy.go @@ -9,9 +9,12 @@ import ( "github.com/stackrox/rox/pkg/booleanpolicy/augmentedobjs" "github.com/stackrox/rox/pkg/booleanpolicy/filter" "github.com/stackrox/rox/pkg/booleanpolicy/policyfields" + "github.com/stackrox/rox/pkg/features" + "github.com/stackrox/rox/pkg/kubernetes" "github.com/stackrox/rox/pkg/policies" "github.com/stackrox/rox/pkg/regexutils" "github.com/stackrox/rox/pkg/scopecomp" + "github.com/stackrox/rox/pkg/set" ) // CompiledPolicy is a compiled policy, which means it can match a policy, as well as check whether a policy is applicable. @@ -46,11 +49,14 @@ func newCompiledPolicy(policy *storage.Policy, clusterLabelProvider scopecomp.Cl exclusions := make([]*compiledExclusion, 0, len(policy.GetExclusions())) for _, w := range policy.GetExclusions() { - w, err := newCompiledExclusion(w) + if w.GetExcludeByKind() != nil && !features.PolicyWorkloadKindExclusion.Enabled() { + continue + } + cx, err := newCompiledExclusion(w) if err != nil { return nil, errors.Wrapf(err, "compiling exclusion list %+v for policy %s", w, policy.GetName()) } - exclusions = append(exclusions, w) + exclusions = append(exclusions, cx) } scopes := make([]*scopecomp.CompiledScope, 0, len(policy.GetScope())) @@ -477,6 +483,7 @@ type compiledExclusion struct { exclusion *storage.Exclusion deploymentNameMatcher regexutils.StringMatcher cs *scopecomp.CompiledScope + excludedKinds set.Set[string] } type alwaysFalseMatcher struct{} @@ -489,6 +496,18 @@ func newCompiledExclusion(exclusion *storage.Exclusion) (*compiledExclusion, err cx := &compiledExclusion{ exclusion: exclusion, } + if exclusion.GetExcludeByKind() != nil { + if features.PolicyWorkloadKindExclusion.Enabled() { + excludedKinds, err := kubernetesKindsForExcludeByKind(exclusion.GetExcludeByKind()) + if err != nil { + return nil, err + } + cx.excludedKinds = excludedKinds + } else { + cx.excludedKinds = set.NewSet[string]() + } + return cx, nil + } if name := exclusion.GetDeployment().GetName(); name != "" { deploymentNameMatcher, err := regexutils.CompileWholeStringMatcher(name, regexutils.Flags{CaseInsensitive: true}) if err != nil { @@ -514,11 +533,23 @@ func newCompiledExclusion(exclusion *storage.Exclusion) (*compiledExclusion, err return cx, nil } +// appliesToDeployments reports whether the exclusion can match a deployment. +// Image-only exclusions are applied to images, so they must not match deployments or audit events. +// Without this check, the nil deployment scope matches everything and the exclusion turns the policy off for every deployment. +// Kind exclusions have no deployment matcher, but they still apply to deployments of the selected kinds. +func (cw *compiledExclusion) appliesToDeployments() bool { + return cw.exclusion.GetDeployment() != nil || cw.excludedKinds != nil +} + func (cw *compiledExclusion) MatchesDeployment(ctx context.Context, deployment *storage.Deployment) bool { - if exclusionIsExpired(cw.exclusion) { + if !cw.appliesToDeployments() || exclusionIsExpired(cw.exclusion) { return false } + if cw.excludedKinds != nil { + return cw.excludedKinds.Contains(deployment.GetType()) + } + if cw.deploymentNameMatcher != nil && !cw.deploymentNameMatcher.MatchString(deployment.GetName()) { return false } @@ -527,7 +558,11 @@ func (cw *compiledExclusion) MatchesDeployment(ctx context.Context, deployment * } func (cw *compiledExclusion) MatchesAuditEvent(ctx context.Context, auditEvent *storage.KubernetesEvent) bool { - if exclusionIsExpired(cw.exclusion) { + if !cw.appliesToDeployments() || exclusionIsExpired(cw.exclusion) { + return false + } + // Kind exclusions apply to workload detections, not audit-log events. + if cw.excludedKinds != nil { return false } if !cw.cs.MatchesAuditEvent(ctx, auditEvent) { @@ -536,6 +571,25 @@ func (cw *compiledExclusion) MatchesAuditEvent(ctx context.Context, auditEvent * return true } +func kubernetesKindsForExcludeByKind(excludeByKind *storage.Exclusion_ExcludeByKind) (set.Set[string], error) { + kinds := excludeByKind.GetKinds() + if len(kinds) == 0 { + return nil, errors.New("exclude_by_kind must specify at least one workload kind") + } + kubernetesKinds := set.NewSet[string]() + for _, kind := range kinds { + switch kind { + case storage.Exclusion_CRON_JOB: + kubernetesKinds.Add(kubernetes.CronJob) + case storage.Exclusion_JOB: + kubernetesKinds.Add(kubernetes.Job) + default: + return nil, errors.Errorf("exclude_by_kind contains unknown workload kind %s", kind) + } + } + return kubernetesKinds, nil +} + // Predicate for deployments. type deploymentPredicate struct { exclusions []*compiledExclusion diff --git a/pkg/detection/compiled_policy_test.go b/pkg/detection/compiled_policy_test.go index f50720961ee0a..4ea21b0d5e949 100644 --- a/pkg/detection/compiled_policy_test.go +++ b/pkg/detection/compiled_policy_test.go @@ -6,10 +6,13 @@ import ( "testing" "github.com/stackrox/rox/generated/storage" + "github.com/stackrox/rox/pkg/booleanpolicy" "github.com/stackrox/rox/pkg/booleanpolicy/fieldnames" "github.com/stackrox/rox/pkg/booleanpolicy/policyversion" "github.com/stackrox/rox/pkg/features" "github.com/stackrox/rox/pkg/fixtures" + "github.com/stackrox/rox/pkg/kubernetes" + "github.com/stackrox/rox/pkg/testutils" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -64,9 +67,20 @@ func TestCompiledPolicyScopesAndExclusions(t *testing.T) { { desc: "only stackrox ns, but app=stackrox excluded", scopes: []*storage.Scope{stackRoxNSScope}, - exclusions: []*storage.Exclusion{{Deployment: &storage.Exclusion_Deployment{Scope: appStackRoxScope}}}, + exclusions: []*storage.Exclusion{{Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{Scope: appStackRoxScope}}}}, shouldApplyTo: []*storage.Deployment{stackRoxNSDep}, }, + { + desc: "image-only exclusion does not exclude any deployment", + exclusions: []*storage.Exclusion{{Image: &storage.Exclusion_Image{Name: "docker.io/library/unrelated"}}}, + shouldApplyTo: []*storage.Deployment{stackRoxNSDep, defaultNSDep, appStackRoxDep}, + }, + { + desc: "only stackrox ns, with an image-only exclusion", + scopes: []*storage.Scope{stackRoxNSScope}, + exclusions: []*storage.Exclusion{{Image: &storage.Exclusion_Image{Name: "docker.io/library/unrelated"}}}, + shouldApplyTo: []*storage.Deployment{stackRoxNSDep, appStackRoxDep}, + }, { desc: "only default ns", scopes: []*storage.Scope{defaultNSScope}, @@ -94,6 +108,60 @@ func TestCompiledPolicyScopesAndExclusions(t *testing.T) { } } +func TestCompiledPolicyWorkloadKindExclusion(t *testing.T) { + testutils.MustUpdateFeature(t, features.PolicyWorkloadKindExclusion, true) + + cronJob := newDeployment("CRONJOB") + cronJob.Name = "batch-cron" + cronJob.Type = kubernetes.CronJob + regular := newDeployment("DEPLOYMENT") + regular.Name = "web" + regular.Type = kubernetes.Deployment + + policy := constructPolicy(nil, []*storage.Exclusion{ + { + Matcher: &storage.Exclusion_ExcludeByKind_{ + ExcludeByKind: &storage.Exclusion_ExcludeByKind{ + Kinds: []storage.Exclusion_WorkloadKind{storage.Exclusion_CRON_JOB}, + }, + }, + }, + { + Matcher: &storage.Exclusion_Deployment_{ + Deployment: &storage.Exclusion_Deployment{Name: regular.GetName()}, + }, + }, + }) + compiled, err := CompilePolicy(policy, nil, nil) + require.NoError(t, err) + assert.False(t, compiled.AppliesTo(context.Background(), cronJob)) + assert.False(t, compiled.AppliesTo(context.Background(), regular)) + + other := newDeployment("OTHER") + other.Name = "other" + other.Type = kubernetes.DaemonSet + assert.True(t, compiled.AppliesTo(context.Background(), other)) +} + +func TestCompiledPolicyWorkloadKindExclusionFlagOff(t *testing.T) { + testutils.MustUpdateFeature(t, features.PolicyWorkloadKindExclusion, false) + + cronJob := newDeployment("CRONJOB") + cronJob.Type = kubernetes.CronJob + policy := constructPolicy(nil, []*storage.Exclusion{ + { + Matcher: &storage.Exclusion_ExcludeByKind_{ + ExcludeByKind: &storage.Exclusion_ExcludeByKind{ + Kinds: []storage.Exclusion_WorkloadKind{storage.Exclusion_CRON_JOB}, + }, + }, + }, + }) + compiled, err := CompilePolicy(policy, nil, nil) + require.NoError(t, err) + assert.True(t, compiled.AppliesTo(context.Background(), cronJob)) +} + // TestProcessAndFileAccessMatchers verifies that when a policy contains both Process and FileAccess fields, // only the file access matcher is created, not both matchers. func TestProcessAndFileAccessMatchers(t *testing.T) { @@ -276,3 +344,115 @@ func TestProcessAndFileAccessMatchers(t *testing.T) { }) } } + +func initAndRegularDeployment() (*storage.Deployment, []*storage.Image) { + dep := &storage.Deployment{ + Id: "dep", + Name: "dep", + Namespace: "ns", + Containers: []*storage.Container{ + { + Name: "init-setup", + Type: storage.ContainerType_INIT, + SecurityContext: &storage.SecurityContext{Privileged: true}, + Image: &storage.ContainerImage{Id: "init-img", Name: &storage.ImageName{FullName: "busybox:latest"}}, + }, + { + Name: "app", + Type: storage.ContainerType_REGULAR, + SecurityContext: &storage.SecurityContext{}, + Image: &storage.ContainerImage{Id: "app-img", Name: &storage.ImageName{FullName: "nginx:1.25"}}, + }, + }, + } + images := []*storage.Image{ + {Id: "init-img", Name: &storage.ImageName{FullName: "busybox:latest"}}, + {Id: "app-img", Name: &storage.ImageName{FullName: "nginx:1.25"}}, + } + return dep, images +} + +func TestEvaluationFilterSkipsContainers(t *testing.T) { + t.Setenv(features.EvaluationFilter.EnvVar(), "true") + + dep, images := initAndRegularDeployment() + ed := booleanpolicy.EnhancedDeployment{Deployment: dep, Images: images} + + skipInit := &storage.EvaluationFilter{ + SkipContainerTypes: []storage.ContainerType{storage.ContainerType_INIT}, + } + privilegedPolicy := &storage.Policy{ + PolicyVersion: policyversion.CurrentVersion().String(), + Name: "privileged", + LifecycleStages: []storage.LifecycleStage{storage.LifecycleStage_DEPLOY}, + PolicySections: []*storage.PolicySection{{ + PolicyGroups: []*storage.PolicyGroup{{ + FieldName: fieldnames.PrivilegedContainer, + Values: []*storage.PolicyValue{{Value: "true"}}, + }}, + }}, + EvaluationFilter: skipInit, + } + + compiled, err := CompilePolicy(privilegedPolicy, nil, nil) + require.NoError(t, err) + + violations, err := compiled.MatchAgainstDeployment(nil, ed) + require.NoError(t, err) + assert.Empty(t, violations.AlertViolations, "privileged init container is skipped") + + dep.Containers[0].SecurityContext.Privileged = false + dep.Containers[1].SecurityContext.Privileged = true + violations, err = compiled.MatchAgainstDeployment(nil, ed) + require.NoError(t, err) + require.Len(t, violations.AlertViolations, 1) + assert.Contains(t, violations.AlertViolations[0].GetMessage(), "app") + + skipRegular := privilegedPolicy.CloneVT() + skipRegular.EvaluationFilter.SkipContainerTypes = []storage.ContainerType{storage.ContainerType_REGULAR} + compiled, err = CompilePolicy(skipRegular, nil, nil) + require.NoError(t, err) + violations, err = compiled.MatchAgainstDeployment(nil, ed) + require.NoError(t, err) + assert.Empty(t, violations.AlertViolations, "privileged regular container is skipped") + + dep.Containers[0].SecurityContext.Privileged = true + dep.Containers[1].SecurityContext.Privileged = false + violations, err = compiled.MatchAgainstDeployment(nil, ed) + require.NoError(t, err) + require.Len(t, violations.AlertViolations, 1) + assert.Contains(t, violations.AlertViolations[0].GetMessage(), "init-setup") + + unfiltered := privilegedPolicy.CloneVT() + unfiltered.EvaluationFilter = nil + compiled, err = CompilePolicy(unfiltered, nil, nil) + require.NoError(t, err) + violations, err = compiled.MatchAgainstDeployment(nil, ed) + require.NoError(t, err) + require.NotEmpty(t, violations.AlertViolations) + assert.Contains(t, violations.AlertViolations[0].GetMessage(), "init-setup") + + processPolicy := &storage.Policy{ + PolicyVersion: policyversion.CurrentVersion().String(), + Name: "process", + LifecycleStages: []storage.LifecycleStage{storage.LifecycleStage_RUNTIME}, + EventSource: storage.EventSource_DEPLOYMENT_EVENT, + PolicySections: []*storage.PolicySection{{ + PolicyGroups: []*storage.PolicyGroup{{ + FieldName: fieldnames.ProcessName, + Values: []*storage.PolicyValue{{Value: "bash"}}, + }}, + }}, + EvaluationFilter: skipInit, + } + compiled, err = CompilePolicy(processPolicy, nil, nil) + require.NoError(t, err) + + appProcess := &storage.ProcessIndicator{ + ContainerName: "app", + Signal: &storage.ProcessSignal{Name: "bash", ExecFilePath: "/bin/bash"}, + } + violations, err = compiled.MatchAgainstDeploymentAndProcess(nil, ed, appProcess, true) + require.NoError(t, err) + assert.NotNil(t, violations.ProcessViolation) +} diff --git a/pkg/detection/deploytime/detector_impl_test.go b/pkg/detection/deploytime/detector_impl_test.go new file mode 100644 index 0000000000000..377ebbc6d353e --- /dev/null +++ b/pkg/detection/deploytime/detector_impl_test.go @@ -0,0 +1,138 @@ +package deploytime + +import ( + "context" + "testing" + "time" + + "github.com/stackrox/rox/generated/storage" + "github.com/stackrox/rox/pkg/booleanpolicy" + "github.com/stackrox/rox/pkg/booleanpolicy/fieldnames" + "github.com/stackrox/rox/pkg/booleanpolicy/policyversion" + "github.com/stackrox/rox/pkg/detection" + "github.com/stackrox/rox/pkg/protocompat" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +const ( + excludedImage = "registry.example.com/team/legacy-app:1.0" + vulnerableImage = "registry.example.com/team/payments:2.3" +) + +// oldCriticalCVEPolicy mirrors a "Block Critical CVE older than 180 days" policy that runs at +// both the build and deploy stages and excludes a single image. +func oldCriticalCVEPolicy(exclusions ...*storage.Exclusion) *storage.Policy { + return &storage.Policy{ + Id: "old-critical-cve", + Name: "Block Critical CVE older than 180 days", + PolicyVersion: policyversion.CurrentVersion().String(), + Severity: storage.Severity_CRITICAL_SEVERITY, + LifecycleStages: []storage.LifecycleStage{storage.LifecycleStage_BUILD, storage.LifecycleStage_DEPLOY}, + Exclusions: exclusions, + PolicySections: []*storage.PolicySection{{ + PolicyGroups: []*storage.PolicyGroup{ + {FieldName: fieldnames.Severity, Values: []*storage.PolicyValue{{Value: "CRITICAL"}}}, + {FieldName: fieldnames.DaysSinceImageFirstDiscovered, Values: []*storage.PolicyValue{{Value: "180"}}}, + }, + }}, + } +} + +func imageExclusion(fullName string) *storage.Exclusion { + return &storage.Exclusion{Image: &storage.Exclusion_Image{Name: fullName}} +} + +func imageWithOldCriticalCVE(t *testing.T, fullName string) *storage.Image { + firstSeen, err := protocompat.ConvertTimeToTimestampOrError(time.Now().AddDate(0, 0, -365)) + require.NoError(t, err) + return &storage.Image{ + Id: fullName + "-sha", + Name: &storage.ImageName{FullName: fullName}, + Scan: &storage.ImageScan{ + Components: []*storage.EmbeddedImageScanComponent{{ + Name: "openssl", + Version: "1.0.1", + Vulns: []*storage.EmbeddedVulnerability{{ + Cve: "CVE-2014-0160", + Severity: storage.VulnerabilitySeverity_CRITICAL_VULNERABILITY_SEVERITY, + FirstImageOccurrence: firstSeen, + }}, + }}, + }, + } +} + +func deploymentRunning(name string, image *storage.Image) booleanpolicy.EnhancedDeployment { + return booleanpolicy.EnhancedDeployment{ + Deployment: &storage.Deployment{ + Id: name + "-id", + Name: name, + Namespace: "shop", + ClusterId: "cluster-1", + Containers: []*storage.Container{{ + Name: name, + Image: &storage.ContainerImage{Id: image.GetId(), Name: image.GetName()}, + }}, + }, + Images: []*storage.Image{image}, + } +} + +func detectorFor(t *testing.T, policy *storage.Policy) Detector { + policySet := detection.NewPolicySet(nil, nil) + require.NoError(t, policySet.UpsertPolicy(policy)) + return NewDetector(policySet) +} + +// TestImageExclusionDoesNotDisableDeployTimeDetection reproduces the customer report: adding an +// image exclusion to a build and deploy policy stopped the policy from alerting on every deployment, +// including deployments that do not run the excluded image. +func TestImageExclusionDoesNotDisableDeployTimeDetection(t *testing.T) { + ctx := context.Background() + payments := deploymentRunning("payments", imageWithOldCriticalCVE(t, vulnerableImage)) + + t.Run("without an exclusion, the vulnerable deployment alerts", func(t *testing.T) { + alerts, err := detectorFor(t, oldCriticalCVEPolicy()).Detect(ctx, payments) + require.NoError(t, err) + assert.Len(t, alerts, 1) + }) + + t.Run("with an image exclusion, a deployment that does not run the excluded image still alerts", func(t *testing.T) { + policy := oldCriticalCVEPolicy(imageExclusion(excludedImage)) + alerts, err := detectorFor(t, policy).Detect(ctx, payments) + require.NoError(t, err) + require.Len(t, alerts, 1) + assert.Equal(t, "payments", alerts[0].GetDeployment().GetName()) + }) + + t.Run("with an image exclusion, a deployment running the excluded image still alerts", func(t *testing.T) { + // Image exclusions only apply at build time, so a deployment running the excluded image is + // still evaluated at deploy time. + legacy := deploymentRunning("legacy-app", imageWithOldCriticalCVE(t, excludedImage)) + policy := oldCriticalCVEPolicy(imageExclusion(excludedImage)) + alerts, err := detectorFor(t, policy).Detect(ctx, legacy) + require.NoError(t, err) + require.Len(t, alerts, 1) + assert.Equal(t, "legacy-app", alerts[0].GetDeployment().GetName()) + }) + + t.Run("a deployment exclusion still skips the named deployment", func(t *testing.T) { + policy := oldCriticalCVEPolicy(&storage.Exclusion{Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{Name: "payments"}}}) + alerts, err := detectorFor(t, policy).Detect(ctx, payments) + require.NoError(t, err) + assert.Empty(t, alerts) + }) +} + +// TestImageExclusionStillAppliesAtBuildTime checks that the fix does not change build-time +// behavior: the excluded image is skipped, other images are still checked. +func TestImageExclusionStillAppliesAtBuildTime(t *testing.T) { + ctx := context.Background() + policy := oldCriticalCVEPolicy(imageExclusion(excludedImage)) + compiled, err := detection.CompilePolicy(policy, nil, nil) + require.NoError(t, err) + + assert.False(t, compiled.AppliesTo(ctx, imageWithOldCriticalCVE(t, excludedImage))) + assert.True(t, compiled.AppliesTo(ctx, imageWithOldCriticalCVE(t, vulnerableImage))) +} diff --git a/pkg/detection/exclusion_test.go b/pkg/detection/exclusion_test.go index f075901acf537..c96474e6189bc 100644 --- a/pkg/detection/exclusion_test.go +++ b/pkg/detection/exclusion_test.go @@ -6,8 +6,11 @@ import ( "time" "github.com/stackrox/rox/generated/storage" + "github.com/stackrox/rox/pkg/features" "github.com/stackrox/rox/pkg/fixtures" + "github.com/stackrox/rox/pkg/kubernetes" "github.com/stackrox/rox/pkg/protoconv" + "github.com/stackrox/rox/pkg/testutils" "github.com/stackrox/rox/pkg/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -31,9 +34,7 @@ func TestMatchesDeploymentExclusion(t *testing.T) { deployment: fixtures.GetDeployment(), policy: &storage.Policy{ Exclusions: []*storage.Exclusion{ - { - Deployment: &storage.Exclusion_Deployment{Name: fixtures.GetDeployment().GetName()}, - }, + {Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{Name: fixtures.GetDeployment().GetName()}}}, }, }, shouldMatch: true, @@ -43,9 +44,7 @@ func TestMatchesDeploymentExclusion(t *testing.T) { deployment: fixtures.GetDeployment(), policy: &storage.Policy{ Exclusions: []*storage.Exclusion{ - { - Deployment: &storage.Exclusion_Deployment{Name: "nginx.*"}, - }, + {Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{Name: "nginx.*"}}}, }, }, shouldMatch: true, @@ -55,9 +54,7 @@ func TestMatchesDeploymentExclusion(t *testing.T) { deployment: fixtures.GetDeployment(), policy: &storage.Policy{ Exclusions: []*storage.Exclusion{ - { - Deployment: &storage.Exclusion_Deployment{Name: "nginy.*"}, - }, + {Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{Name: "nginy.*"}}}, }, }, shouldMatch: false, @@ -67,9 +64,7 @@ func TestMatchesDeploymentExclusion(t *testing.T) { deployment: fixtures.GetDeployment(), policy: &storage.Policy{ Exclusions: []*storage.Exclusion{ - { - Deployment: &storage.Exclusion_Deployment{Name: "ngin\\K"}, - }, + {Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{Name: "ngin\\K"}}}, }, }, shouldMatch: false, @@ -79,12 +74,8 @@ func TestMatchesDeploymentExclusion(t *testing.T) { deployment: fixtures.GetDeployment(), policy: &storage.Policy{ Exclusions: []*storage.Exclusion{ - { - Deployment: &storage.Exclusion_Deployment{Name: fixtures.GetDeployment().GetName()}, - }, - { - Deployment: &storage.Exclusion_Deployment{Name: uuid.NewV4().String()}, - }, + {Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{Name: fixtures.GetDeployment().GetName()}}}, + {Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{Name: uuid.NewV4().String()}}}, }, }, shouldMatch: true, @@ -94,9 +85,7 @@ func TestMatchesDeploymentExclusion(t *testing.T) { deployment: fixtures.GetDeployment(), policy: &storage.Policy{ Exclusions: []*storage.Exclusion{ - { - Deployment: &storage.Exclusion_Deployment{Name: uuid.NewV4().String()}, - }, + {Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{Name: uuid.NewV4().String()}}}, }, }, shouldMatch: false, @@ -106,9 +95,7 @@ func TestMatchesDeploymentExclusion(t *testing.T) { deployment: fixtures.GetDeployment(), policy: &storage.Policy{ Exclusions: []*storage.Exclusion{ - { - Deployment: &storage.Exclusion_Deployment{Scope: &storage.Scope{Namespace: fixtures.GetDeployment().GetNamespace()}}, - }, + {Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{Scope: &storage.Scope{Namespace: fixtures.GetDeployment().GetNamespace()}}}}, }, }, shouldMatch: true, @@ -116,10 +103,20 @@ func TestMatchesDeploymentExclusion(t *testing.T) { { name: "Scoped excluded scope with wrong name", deployment: fixtures.GetDeployment(), + policy: &storage.Policy{ + Exclusions: []*storage.Exclusion{ + {Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{Scope: &storage.Scope{Namespace: uuid.NewV4().String()}}}}, + }, + }, + shouldMatch: false, + }, + { + name: "Image-only exclusion does not match deployments", + deployment: fixtures.GetDeployment(), policy: &storage.Policy{ Exclusions: []*storage.Exclusion{ { - Deployment: &storage.Exclusion_Deployment{Scope: &storage.Scope{Namespace: uuid.NewV4().String()}}, + Image: &storage.Exclusion_Image{Name: "docker.io/library/nginx"}, }, }, }, @@ -130,9 +127,7 @@ func TestMatchesDeploymentExclusion(t *testing.T) { deployment: fixtures.GetDeployment(), policy: &storage.Policy{ Exclusions: []*storage.Exclusion{ - { - Deployment: &storage.Exclusion_Deployment{Name: uuid.NewV4().String(), Scope: &storage.Scope{Namespace: fixtures.GetDeployment().GetNamespace()}}, - }, + {Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{Name: uuid.NewV4().String(), Scope: &storage.Scope{Namespace: fixtures.GetDeployment().GetNamespace()}}}}, }, }, shouldMatch: false, @@ -168,6 +163,126 @@ func TestMatchesDeploymentExclusion(t *testing.T) { } } +func TestMatchesWorkloadKindExclusion(t *testing.T) { + cronJob := fixtures.GetDeployment() + cronJob.Type = kubernetes.CronJob + job := fixtures.GetDeployment() + job.Type = kubernetes.Job + deployment := fixtures.GetDeployment() + deployment.Type = kubernetes.Deployment + + kindExclusion := func(kinds ...storage.Exclusion_WorkloadKind) *storage.Exclusion { + return &storage.Exclusion{ + Matcher: &storage.Exclusion_ExcludeByKind_{ + ExcludeByKind: &storage.Exclusion_ExcludeByKind{Kinds: kinds}, + }, + } + } + nameExclusion := func(name string) *storage.Exclusion { + return &storage.Exclusion{ + Matcher: &storage.Exclusion_Deployment_{ + Deployment: &storage.Exclusion_Deployment{Name: name}, + }, + } + } + + compile := func(t *testing.T, exclusions ...*storage.Exclusion) []*compiledExclusion { + t.Helper() + compiled := make([]*compiledExclusion, 0, len(exclusions)) + for _, exclusion := range exclusions { + cw, err := newCompiledExclusion(exclusion) + require.NoError(t, err) + compiled = append(compiled, cw) + } + return compiled + } + + t.Run("flag off does not exclude by kind", func(t *testing.T) { + testutils.MustUpdateFeature(t, features.PolicyWorkloadKindExclusion, false) + compiled := compile(t, kindExclusion(storage.Exclusion_CRON_JOB, storage.Exclusion_JOB)) + assert.False(t, deploymentMatchesExclusions(context.Background(), cronJob, compiled)) + assert.False(t, deploymentMatchesExclusions(context.Background(), job, compiled)) + assert.False(t, deploymentMatchesExclusions(context.Background(), deployment, compiled)) + }) + + testutils.MustUpdateFeature(t, features.PolicyWorkloadKindExclusion, true) + + cases := map[string]struct { + exclusions []*storage.Exclusion + workload *storage.Deployment + shouldMatch bool + }{ + "cronjob matches cronjob kind": { + exclusions: []*storage.Exclusion{kindExclusion(storage.Exclusion_CRON_JOB)}, + workload: cronJob, + shouldMatch: true, + }, + "deployment does not match cronjob kind": { + exclusions: []*storage.Exclusion{kindExclusion(storage.Exclusion_CRON_JOB)}, + workload: deployment, + shouldMatch: false, + }, + "job matches job and cronjob kinds": { + exclusions: []*storage.Exclusion{kindExclusion(storage.Exclusion_CRON_JOB, storage.Exclusion_JOB)}, + workload: job, + shouldMatch: true, + }, + "OR with name/scope exclusion": { + exclusions: []*storage.Exclusion{ + kindExclusion(storage.Exclusion_JOB), + nameExclusion(deployment.GetName()), + }, + workload: deployment, + shouldMatch: true, + }, + "kind exclusion does not match unrelated name": { + exclusions: []*storage.Exclusion{kindExclusion(storage.Exclusion_JOB)}, + workload: deployment, + shouldMatch: false, + }, + } + + for name, c := range cases { + t.Run(name, func(t *testing.T) { + compiled := compile(t, c.exclusions...) + got := deploymentMatchesExclusions(context.Background(), c.workload, compiled) + assert.Equal(t, c.shouldMatch, got) + if c.shouldMatch { + for _, exclusion := range c.exclusions { + exclusion.Expiration = protoconv.MustConvertTimeToTimestamp(time.Now().Add(-1 * time.Hour)) + } + assert.False(t, deploymentMatchesExclusions(context.Background(), c.workload, compiled)) + } + }) + } + + for name, tc := range map[string]struct { + kinds []storage.Exclusion_WorkloadKind + errContains string + }{ + "empty kind list is rejected": { + errContains: "at least one workload kind", + }, + "unknown kind is rejected": { + kinds: []storage.Exclusion_WorkloadKind{storage.Exclusion_WorkloadKind(99)}, + errContains: "unknown workload kind", + }, + "mixed valid and unknown kinds are rejected": { + kinds: []storage.Exclusion_WorkloadKind{storage.Exclusion_JOB, storage.Exclusion_WorkloadKind(99)}, + errContains: "unknown workload kind", + }, + "UNSPECIFIED is rejected": { + kinds: []storage.Exclusion_WorkloadKind{storage.Exclusion_WORKLOAD_KIND_UNSPECIFIED}, + errContains: "unknown workload kind", + }, + } { + t.Run(name, func(t *testing.T) { + _, err := newCompiledExclusion(kindExclusion(tc.kinds...)) + require.ErrorContains(t, err, tc.errContains) + }) + } +} + func TestMatchesImageExclusion(t *testing.T) { cases := []struct { name string @@ -243,8 +358,18 @@ func TestMatchesImageExclusion(t *testing.T) { } assert.True(t, matchesImageExclusion(c.image, c.policy)) } - c.policy.Exclusions = append(c.policy.Exclusions, &storage.Exclusion{Deployment: &storage.Exclusion_Deployment{Name: "BLAH"}}) + c.policy.Exclusions = append(c.policy.Exclusions, &storage.Exclusion{Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{Name: "BLAH"}}}) assert.Equal(t, c.shouldMatch, got) }) } } + +func TestImageOnlyExclusionDoesNotMatchAuditEvent(t *testing.T) { + cx, err := newCompiledExclusion(&storage.Exclusion{Image: &storage.Exclusion_Image{Name: "docker.io/library/nginx"}}) + require.NoError(t, err) + + auditEvent := &storage.KubernetesEvent{ + Object: &storage.KubernetesEvent_Object{Name: "my-secret", Namespace: "default", ClusterId: "cluster-1"}, + } + assert.False(t, auditEventMatchesExclusions(context.Background(), auditEvent, []*compiledExclusion{cx})) +} diff --git a/pkg/features/list.go b/pkg/features/list.go index 3631aef643ceb..c2d19ebbf9269 100644 --- a/pkg/features/list.go +++ b/pkg/features/list.go @@ -15,9 +15,6 @@ var ( // ClusterAwareDeploymentCheck enables roxctl deployment check to check deployments on the cluster level. ClusterAwareDeploymentCheck = registerFeature("Enables cluster level check for the 'roxctl deployment check' command.", "ROX_CLUSTER_AWARE_DEPLOYMENT_CHECK", enabled) - // PolicyCriteriaModal enables a modal for selecting policy criteria when editing a policy - PolicyCriteriaModal = registerFeature("Enable modal to select policy criteria when editing a policy", "ROX_POLICY_CRITERIA_MODAL") - // SensorDeploymentBuildOptimization enables a performance improvement by skipping deployments processing when no dependency or spec changed SensorDeploymentBuildOptimization = registerFeature("Enables a performance improvement by skipping deployments processing when no dependency or spec changed", "ROX_DEPLOYMENT_BUILD_OPTIMIZATION", enabled) @@ -36,6 +33,12 @@ var ( // ComplianceRemediationV2 enables the remediation feature of the compliance v2 integration. ComplianceRemediationV2 = registerFeature("Enable Compliance Remediation feature", "ROX_COMPLIANCE_REMEDIATION", enabled) + // ComplianceSurfaceStaleData gates surfacing stale compliance data in Coverage views (ROX-35712). Default off. + ComplianceSurfaceStaleData = registerFeature("Surface stale compliance data in Coverage views", "ROX_COMPLIANCE_SURFACE_STALE_DATA") + + // ComplianceCustomNodeRoles gates configurable node roles in compliance scan configurations (ROX-34167). Default off. + ComplianceCustomNodeRoles = registerFeature("Enable configurable node roles in compliance scan configurations", "ROX_COMPLIANCE_CUSTOM_NODE_ROLES") + // SensorAggregateDeploymentReferenceOptimization enables a performance improvement by aggregating deployment references when the same reference is queued for processing SensorAggregateDeploymentReferenceOptimization = registerFeature("Enables a performance improvement by aggregating deployment references when the same reference is queued for processing", "ROX_AGGREGATE_DEPLOYMENT_REFERENCE_OPTIMIZATION", enabled) @@ -99,10 +102,7 @@ var ( // KnownExploitedVulnerabilities enables support for CISA Known Exploited Vulnerabilities (KEV) data. // // This must be enabled in Central and Scanner V4 Matcher to have any effect. - KnownExploitedVulnerabilities = registerFeature("Display CISA Known Exploited Vulnerabilities (KEV) data", "ROX_CISA_KEV") - - // Display Compliance Dashboard (Deprecated) in user interface (not displayed by default starting in 4.11 release). - DeprecatedComplianceDashboard = registerFeature("Display Compliance Dashboard (Deprecated) in user interface", "ROX_DEPRECATED_COMPLIANCE_DASHBOARD") + KnownExploitedVulnerabilities = registerFeature("Display CISA Known Exploited Vulnerabilities (KEV) data", "ROX_CISA_KEV", enabled) // SensitiveFileActivity enables monitoring of sensitive files. SensitiveFileActivity = registerFeature("Enable sensitive file monitoring", "ROX_SENSITIVE_FILE_ACTIVITY", enabled) @@ -146,6 +146,9 @@ var ( // EvaluationFilter enables evaluation filtering in policy evaluation. EvaluationFilter = registerFeature("Enable evaluation filtering in policy evaluation", "ROX_EVALUATION_FILTER", enabled) + // PolicyWorkloadKindExclusion enables excluding all workloads of selected Kubernetes kinds (Job, CronJob) from a policy. + PolicyWorkloadKindExclusion = registerFeature("Enable excluding all workloads of a given kind from a policy", "ROX_POLICY_WORKLOAD_KIND_EXCLUSION") + // UISecretsPageMigration enables the secrets list page under the Risk section UISecretsPageMigration = registerFeature("Display secrets list page under Risk section", "ROX_UI_SECRETS_PAGE_MIGRATION") diff --git a/pkg/glob/pattern.go b/pkg/glob/pattern.go index 3f4009ddd3134..a89e0eeb7fe0b 100644 --- a/pkg/glob/pattern.go +++ b/pkg/glob/pattern.go @@ -19,7 +19,7 @@ func (p *Pattern) Compile() error { return err } -func (p *Pattern) compile() (glob.Glob, error) { +func (p *Pattern) compile() (*glob.Pattern, error) { g, err := glob.Compile(string(*p)) if err != nil { return nil, errors.WithMessagef(err, "failed to compile %q", string(*p)) @@ -36,7 +36,7 @@ func (p *Pattern) Match(s string) bool { return false } } - return v.(glob.Glob).Match(s) + return v.(*glob.Pattern).Match(s) } func (p Pattern) Ptr() *Pattern { diff --git a/pkg/grpc/versionheader/interceptor.go b/pkg/grpc/versionheader/interceptor.go new file mode 100644 index 0000000000000..98bc6b08bed29 --- /dev/null +++ b/pkg/grpc/versionheader/interceptor.go @@ -0,0 +1,27 @@ +package versionheader + +import ( + "context" + + "github.com/stackrox/rox/pkg/clientconn" + "github.com/stackrox/rox/pkg/grpc/authn" + "github.com/stackrox/rox/pkg/version" + "google.golang.org/grpc" + "google.golang.org/grpc/metadata" +) + +// CentralVersionServerInterceptor returns a gRPC unary server interceptor that sets the +// Central version in the response header for authenticated requests. +func CentralVersionServerInterceptor() grpc.UnaryServerInterceptor { + return func(ctx context.Context, req any, _ *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) { + setVersionHeader(ctx) + return handler(ctx, req) + } +} + +func setVersionHeader(ctx context.Context) { + if authn.IdentityFromContextOrNil(ctx) == nil { + return + } + _ = grpc.SetHeader(ctx, metadata.Pairs(clientconn.CentralVersionHeader, version.GetMainVersion())) +} diff --git a/pkg/helm/charts/meta.go b/pkg/helm/charts/meta.go index 2d70deea56ceb..8e30e94cc98ab 100644 --- a/pkg/helm/charts/meta.go +++ b/pkg/helm/charts/meta.go @@ -20,11 +20,6 @@ type MetaValues struct { FactRegistry string FactImageRemote string FactImageTag string - ScannerImageRemote string - ScannerSlimImageRemote string - ScannerImageTag string - ScannerDBImageRemote string - ScannerDBSlimImageRemote string ScannerV4ImageRemote string ScannerV4DBImageRemote string ScannerV4ImageTag string @@ -69,33 +64,28 @@ type MetaValues struct { // GetMetaValuesForFlavor are the default meta values for rendering the StackRox charts in production. func GetMetaValuesForFlavor(imageFlavor defaults.ImageFlavor) *MetaValues { metaValues := MetaValues{ - Versions: imageFlavor.Versions, - MainRegistry: imageFlavor.MainRegistry, - ImageRemote: imageFlavor.MainImageName, - ImageTag: imageFlavor.MainImageTag, - CentralDBImageTag: imageFlavor.CentralDBImageTag, - CentralDBImageRemote: imageFlavor.CentralDBImageName, - CollectorRegistry: imageFlavor.CollectorRegistry, - CollectorImageRemote: imageFlavor.CollectorImageName, - CollectorImageTag: imageFlavor.CollectorImageTag, - FactRegistry: imageFlavor.FactRegistry, - FactImageRemote: imageFlavor.FactImageName, - FactImageTag: imageFlavor.FactImageTag, - ScannerImageRemote: imageFlavor.ScannerImageName, - ScannerSlimImageRemote: imageFlavor.ScannerSlimImageName, - ScannerImageTag: imageFlavor.ScannerImageTag, - ScannerDBImageRemote: imageFlavor.ScannerDBImageName, - ScannerDBSlimImageRemote: imageFlavor.ScannerDBSlimImageName, - ScannerV4ImageRemote: imageFlavor.ScannerV4ImageName, - ScannerV4DBImageRemote: imageFlavor.ScannerV4DBImageName, - ScannerV4ImageTag: imageFlavor.ScannerV4ImageTag, - RenderMode: "renderAll", - ChartRepo: imageFlavor.ChartRepo, - ImagePullSecrets: imageFlavor.ImagePullSecrets, - Operator: false, - ReleaseBuild: buildinfo.ReleaseBuild, - FeatureFlags: features.GetFeatureFlagsAsGenericMap(), - TelemetryEnabled: true, + Versions: imageFlavor.Versions, + MainRegistry: imageFlavor.MainRegistry, + ImageRemote: imageFlavor.MainImageName, + ImageTag: imageFlavor.MainImageTag, + CentralDBImageTag: imageFlavor.CentralDBImageTag, + CentralDBImageRemote: imageFlavor.CentralDBImageName, + CollectorRegistry: imageFlavor.CollectorRegistry, + CollectorImageRemote: imageFlavor.CollectorImageName, + CollectorImageTag: imageFlavor.CollectorImageTag, + FactRegistry: imageFlavor.FactRegistry, + FactImageRemote: imageFlavor.FactImageName, + FactImageTag: imageFlavor.FactImageTag, + ScannerV4ImageRemote: imageFlavor.ScannerV4ImageName, + ScannerV4DBImageRemote: imageFlavor.ScannerV4DBImageName, + ScannerV4ImageTag: imageFlavor.ScannerV4ImageTag, + RenderMode: "renderAll", + ChartRepo: imageFlavor.ChartRepo, + ImagePullSecrets: imageFlavor.ImagePullSecrets, + Operator: false, + ReleaseBuild: buildinfo.ReleaseBuild, + FeatureFlags: features.GetFeatureFlagsAsGenericMap(), + TelemetryEnabled: true, AutoSensePodSecurityPolicies: true, } diff --git a/pkg/helm/charts/meta_test.go b/pkg/helm/charts/meta_test.go index ed519d25bd3f6..6fc69592c3d3e 100644 --- a/pkg/helm/charts/meta_test.go +++ b/pkg/helm/charts/meta_test.go @@ -29,8 +29,6 @@ func TestRequiredMetaValuesArePresent(t *testing.T) { assert.NotEmpty(t, metaVals.CollectorRegistry) assert.NotEmpty(t, metaVals.CollectorImageRemote) assert.NotEmpty(t, metaVals.CollectorImageTag) - assert.NotEmpty(t, metaVals.ScannerImageRemote) - assert.NotEmpty(t, metaVals.ScannerImageTag) assert.NotEmpty(t, metaVals.ScannerV4ImageRemote) assert.NotEmpty(t, metaVals.ScannerV4DBImageRemote) assert.NotEmpty(t, metaVals.ScannerV4ImageTag) @@ -39,8 +37,6 @@ func TestRequiredMetaValuesArePresent(t *testing.T) { assert.NotEmpty(t, metaVals.Versions.ChartVersion) assert.NotEmpty(t, metaVals.Versions.MainVersion) - // TODO: replace this with the check of the scanner tag once we migrate to it instead of version. - assert.NotEmpty(t, metaVals.Versions.ScannerVersion) assert.Len(t, metaVals.FeatureFlags, len(features.Flags)) }) } diff --git a/pkg/helm/charts/tests/centralservices/base_suite_test.go b/pkg/helm/charts/tests/centralservices/base_suite_test.go index e1da27eab219c..91a163712ac25 100644 --- a/pkg/helm/charts/tests/centralservices/base_suite_test.go +++ b/pkg/helm/charts/tests/centralservices/base_suite_test.go @@ -26,7 +26,6 @@ var ( Revision: 1, IsInstall: true, }, - APIVersions: append(chartutil.DefaultVersionSet, "app.k8s.io/v1beta1/Application"), } // A values YAML that sets all generatable values explicitly, and causes all diff --git a/pkg/helm/charts/tests/centralservices/flavor/flavor_test.go b/pkg/helm/charts/tests/centralservices/flavor/flavor_test.go index 20835227cb42e..97dc8de19a6bf 100644 --- a/pkg/helm/charts/tests/centralservices/flavor/flavor_test.go +++ b/pkg/helm/charts/tests/centralservices/flavor/flavor_test.go @@ -17,19 +17,14 @@ const testDir = "testdata/helmtest" func customFlavor(t *testing.T) defaults.ImageFlavor { return defaults.ImageFlavor{ - MainRegistry: "example.io", - MainImageName: "custom-main", - MainImageTag: "1.2.3", - CentralDBImageName: "custom-central-db", - CentralDBImageTag: "1.2.4", - ScannerImageName: "custom-scanner", - ScannerSlimImageName: "scanner-slim", - ScannerImageTag: "3.2.1", - ScannerDBSlimImageName: "scanner-slim", - ScannerDBImageName: "custom-scanner-db", - ScannerV4ImageName: "custom-scanner-v4", - ScannerV4DBImageName: "custom-scanner-v4-db", - ScannerV4ImageTag: "4.2.1", + MainRegistry: "example.io", + MainImageName: "custom-main", + MainImageTag: "1.2.3", + CentralDBImageName: "custom-central-db", + CentralDBImageTag: "1.2.4", + ScannerV4ImageName: "custom-scanner-v4", + ScannerV4DBImageName: "custom-scanner-v4-db", + ScannerV4ImageTag: "4.2.1", ChartRepo: defaults.ChartRepo{ URL: "url", diff --git a/pkg/helm/charts/tests/centralservices/testdata/helmtest/openshift-monitoring.test.yaml b/pkg/helm/charts/tests/centralservices/testdata/helmtest/openshift-monitoring.test.yaml index a9b75d76642e6..fb1f3ab3d3756 100644 --- a/pkg/helm/charts/tests/centralservices/testdata/helmtest/openshift-monitoring.test.yaml +++ b/pkg/helm/charts/tests/centralservices/testdata/helmtest/openshift-monitoring.test.yaml @@ -54,6 +54,120 @@ tests: env.openshift: 4 tests: *enabled-test +- name: "Central DB PVC space alerts" + set: + monitoring.openshift.enabled: true + env.openshift: 4 + tests: + - name: "warning and critical alerts are created" + expect: | + .prometheusrules["central-telemeter-stackrox"].spec.groups | + assertThat(any(.[]; .name == "rhacs.central-db")) + .prometheusrules["central-telemeter-stackrox"].spec.groups[] | + select(.name == "rhacs.central-db") | .rules | [ + assertThat(length == 2), + assertThat(all(.[]; .alert == "CentralDBPersistentVolumeFillingUp")), + assertThat(any(.[]; .labels.severity == "warning")), + assertThat(any(.[]; .labels.severity == "critical")) + ] + .prometheusrules["central-telemeter-stackrox"].spec.groups[] | + select(.name == "rhacs.central-db") | .rules[] | + select(.labels.severity == "warning") | + assertThat(.expr | contains("persistentvolumeclaim=\"central-db\"") and contains("> 0.8")) + + - name: "custom claim name is honoured" + set: + central.db.persistence.persistentVolumeClaim.claimName: my-central-db + expect: | + .prometheusrules["central-telemeter-stackrox"].spec.groups[] | + select(.name == "rhacs.central-db") | .rules[0] | + assertThat(.expr | contains("persistentvolumeclaim=\"my-central-db\"")) + + - name: "omitted when central-db is not PVC-backed" + set: + central.db.persistence.hostPath: /var/lib/central-db-test + expect: | + .prometheusrules["central-telemeter-stackrox"].spec.groups | + assertThat(all(.[]; .name != "rhacs.central-db")) + +- name: "Scanner V4 DB PVC space alerts" + set: + monitoring.openshift.enabled: true + env.openshift: 4 + scannerV4: + disable: false + tests: + - name: "warning and critical alerts are created" + expect: | + .prometheusrules["scanner-v4-db-stackrox"].spec.groups | + assertThat(any(.[]; .name == "rhacs.scanner-v4-db")) + .prometheusrules["scanner-v4-db-stackrox"].spec.groups[] | + select(.name == "rhacs.scanner-v4-db") | .rules | [ + assertThat(length == 2), + assertThat(all(.[]; .alert == "ScannerV4DBPersistentVolumeFillingUp")), + assertThat(any(.[]; .labels.severity == "warning")), + assertThat(any(.[]; .labels.severity == "critical")) + ] + .prometheusrules["scanner-v4-db-stackrox"].spec.groups[] | + select(.name == "rhacs.scanner-v4-db") | .rules[] | + select(.labels.severity == "warning") | + assertThat(.expr | contains("persistentvolumeclaim=\"scanner-v4-db\"") and contains("> 0.8")) + + - name: "custom claim name is honoured" + set: + scannerV4.db.persistence.persistentVolumeClaim.claimName: my-scanner-v4-db + expect: | + .prometheusrules["scanner-v4-db-stackrox"].spec.groups[] | + select(.name == "rhacs.scanner-v4-db") | .rules[0] | + assertThat(.expr | contains("persistentvolumeclaim=\"my-scanner-v4-db\"")) + + - name: "omitted when scanner-v4-db is not PVC-backed" + set: + scannerV4.db.persistence.none: true + expect: | + .prometheusrules["scanner-v4-db-stackrox"] | assertThat(. == null) + + - name: "omitted when Scanner V4 is disabled" + set: + scannerV4.disable: true + expect: | + .prometheusrules["scanner-v4-db-stackrox"] | assertThat(. == null) + +- name: "Custom metrics" + set: + env.openshift: 4 + tests: + - name: "openshift metrics disabled" + expect: | + .servicemonitors["central-ocp-api-monitor-stackrox"] | assertThat(. == null) + + - name: "custom metrics disabled" + set: + monitoring.openshift.enabled: true + expect: | + .servicemonitors["central-ocp-api-monitor-stackrox"] | assertThat(. == null) + + - name: "custom metrics enabled" + set: + monitoring.openshift.enabled: true + monitoring.openshift.custom.enabled: true + expect: | + .servicemonitors["central-ocp-api-monitor-stackrox"] | [ + assertThat(.metadata.namespace == "openshift-monitoring"), + assertThat(.spec.endpoints[].port == "https"), + assertThat(.spec.endpoints[].path == "/metrics"), + assertThat(.spec.endpoints[].scheme == "https"), + assertThat(.spec.endpoints[].tlsConfig.caFile == "/etc/prometheus/configmaps/serving-certs-ca-bundle/service-ca.crt") + ] + + - name: "custom metrics disabled on managed services" + set: + monitoring.openshift.enabled: true + monitoring.openshift.custom.enabled: true + env.managedServices: true + expect: | + .servicemonitors["central-ocp-api-monitor-stackrox"] | assertThat(. == null) + - name: "When enabled with Scanner V4" set: monitoring.openshift.enabled: true @@ -146,6 +260,7 @@ tests: .rolebindings["central-prometheus-k8s"] | assertThat(. == null) .rolebindings["rhacs-central-auth-reader-stackrox"] | assertThat(. == null) .servicemonitors["central-monitor-stackrox"] | assertThat(. == null) + .servicemonitors["central-ocp-api-monitor-stackrox"] | assertThat(. == null) .services["central-ocp"] | assertThat(. == null) - name: "secure metrics endpoint is disabled" diff --git a/pkg/helm/charts/tests/securedclusterservices/base_suite_test.go b/pkg/helm/charts/tests/securedclusterservices/base_suite_test.go index c2ebfdb4461a5..98cb4bf010421 100644 --- a/pkg/helm/charts/tests/securedclusterservices/base_suite_test.go +++ b/pkg/helm/charts/tests/securedclusterservices/base_suite_test.go @@ -25,7 +25,6 @@ var ( Revision: 1, IsInstall: true, }, - APIVersions: append(chartutil.DefaultVersionSet, "app.k8s.io/v1beta1/Application"), } // A values YAML that sets all generatable values explicitly, and causes all diff --git a/pkg/helm/charts/tests/securedclusterservices/testdata/helmtest/openshift-monitoring.test.yaml b/pkg/helm/charts/tests/securedclusterservices/testdata/helmtest/openshift-monitoring.test.yaml index f10712e50aaf9..2cea2a231037f 100644 --- a/pkg/helm/charts/tests/securedclusterservices/testdata/helmtest/openshift-monitoring.test.yaml +++ b/pkg/helm/charts/tests/securedclusterservices/testdata/helmtest/openshift-monitoring.test.yaml @@ -124,6 +124,72 @@ tests: ] .networkpolicys["scanner-v4-indexer-monitoring-tls"] | assertThat(. != null) +- name: "Scanner V4 DB PVC space alerts" + set: + monitoring.openshift.enabled: true + env.openshift: 4 + scannerV4.disable: false + tests: + # Scanner V4 DB in the secured cluster only uses a PVC when a default + # StorageClass is present; otherwise it falls back to emptyDir and no PVC + # alert should be emitted. + - name: "warning and critical alerts are created when PVC-backed" + server: + objects: + - apiVersion: storage.k8s.io/v1 + kind: StorageClass + metadata: + name: def-sc + annotations: + storageclass.kubernetes.io/is-default-class: true + expect: | + .prometheusrules["scanner-v4-db-stackrox"].spec.groups | + assertThat(any(.[]; .name == "rhacs.scanner-v4-db")) + .prometheusrules["scanner-v4-db-stackrox"].spec.groups[] | + select(.name == "rhacs.scanner-v4-db") | .rules | [ + assertThat(length == 2), + assertThat(all(.[]; .alert == "ScannerV4DBPersistentVolumeFillingUp")), + assertThat(any(.[]; .labels.severity == "warning")), + assertThat(any(.[]; .labels.severity == "critical")) + ] + .prometheusrules["scanner-v4-db-stackrox"].spec.groups[] | + select(.name == "rhacs.scanner-v4-db") | .rules[] | + select(.labels.severity == "warning") | + assertThat(.expr | contains("persistentvolumeclaim=\"scanner-v4-db\"") and contains("> 0.8")) + + - name: "alerts target the PVC namespace when overridden" + release: + namespace: default + set: + meta.namespaceOverride: my-stackrox + allowNonstandardNamespace: true + server: + objects: + - apiVersion: storage.k8s.io/v1 + kind: StorageClass + metadata: + name: def-sc + annotations: + storageclass.kubernetes.io/is-default-class: true + expect: | + .persistentvolumeclaims["scanner-v4-db"].metadata.namespace | assertThat(. == "my-stackrox") + .prometheusrules["scanner-v4-db-default"].spec.groups[] | + select(.name == "rhacs.scanner-v4-db") | .rules[] | [ + assertThat(.expr | contains("kubelet_volume_stats_used_bytes{namespace=\"my-stackrox\"")), + assertThat(.expr | contains("kubelet_volume_stats_capacity_bytes{namespace=\"my-stackrox\"")), + assertThat(.annotations.description | contains("in namespace my-stackrox")) + ] + + - name: "omitted when scanner-v4-db falls back to emptyDir (no default StorageClass)" + expect: | + .prometheusrules["scanner-v4-db-stackrox"] | assertThat(. == null) + + - name: "omitted when Scanner V4 is disabled" + set: + scannerV4.disable: true + expect: | + .prometheusrules["scanner-v4-db-stackrox"] | assertThat(. == null) + - name: "When enabled via default value" set: env.openshift: 4 diff --git a/pkg/helm/charts/tests/securedclusterservices/testdata/helmtest/vwc-global-name.test.yaml b/pkg/helm/charts/tests/securedclusterservices/testdata/helmtest/vwc-global-name.test.yaml new file mode 100644 index 0000000000000..fa547c87e89ca --- /dev/null +++ b/pkg/helm/charts/tests/securedclusterservices/testdata/helmtest/vwc-global-name.test.yaml @@ -0,0 +1,42 @@ +name: "Test ValidatingWebhookConfiguration global resource naming" +values: + imagePullSecrets: + allowNone: true + +defs: | + def vwcNames: + (.validatingwebhookconfigurations // {}) | keys; + +tests: +# By default namespacePrefixGlobalResources is false, so the base name is kept static +# ("stackrox") regardless of namespace, for production safety. +- name: base name is static in the standard namespace + expect: | + vwcNames | assertThat(. == ["stackrox"]) + +- name: base name stays static in a non-standard namespace when prefixing is disabled + release: + namespace: custom-ns + set: + allowNonstandardNamespace: true + expect: | + vwcNames | assertThat(. == ["stackrox"]) + +# When namespacePrefixGlobalResources is enabled the name is namespace-prefixed to avoid +# clashes across multiple secured clusters in different namespaces of the same cluster. +- name: base name is used verbatim in the standard namespace even when prefixing is enabled + set: + namespacePrefixGlobalResources: true + expect: | + vwcNames | assertThat(. == ["stackrox"]) + +- name: base name is namespace-prefixed in a non-standard namespace when prefixing is enabled + release: + namespace: custom-ns + set: + allowNonstandardNamespace: true + namespacePrefixGlobalResources: true + expect: | + # A bare "stackrox" base name (no suffix) must not trigger the "Unknown naming + # convention" failure; the global prefix already carries the namespace. + vwcNames | assertThat(. == ["stackrox-custom-ns"]) diff --git a/pkg/helm/config/roundtrip_test.go b/pkg/helm/config/roundtrip_test.go index 03206e561c8b3..597e0114bd355 100644 --- a/pkg/helm/config/roundtrip_test.go +++ b/pkg/helm/config/roundtrip_test.go @@ -30,7 +30,6 @@ var ( Revision: 1, IsInstall: true, }, - APIVersions: chartutil.DefaultVersionSet, } ) diff --git a/pkg/helm/util/render.go b/pkg/helm/util/render.go index 78e9f953d88cf..a12ed1668ae82 100644 --- a/pkg/helm/util/render.go +++ b/pkg/helm/util/render.go @@ -17,8 +17,6 @@ type Options struct { ReleaseOptions chartutil.ReleaseOptions KubeVersion string HelmVersion string - - APIVersions chartutil.VersionSet } // Render renders a chart locally, like renderutil.Render, but its options struct allows specifying @@ -38,10 +36,6 @@ func Render(c *chart.Chart, values chartutil.Values, opts Options) (map[string]s HelmVersion: chartutil.DefaultCapabilities.HelmVersion, } - if opts.APIVersions != nil { - caps.APIVersions = opts.APIVersions - } - if opts.KubeVersion != "" { kv, verErr := semver.NewVersion(opts.KubeVersion) if verErr != nil { diff --git a/pkg/images/defaults/flavor.go b/pkg/images/defaults/flavor.go index ad47ec1793aaa..0978da9737412 100644 --- a/pkg/images/defaults/flavor.go +++ b/pkg/images/defaults/flavor.go @@ -83,13 +83,6 @@ type ImageFlavor struct { FactImageName string FactImageTag string - // ScannerImageTag is used for all scanner* images (scanner, scanner-db, scanner-slim and scanner-db-slim) - ScannerImageTag string - ScannerImageName string - ScannerSlimImageName string - ScannerDBImageName string - ScannerDBSlimImageName string - // ScannerV4ImageTag is used for all scanner-v4* images (scanner-v4, scanner-v4-db) ScannerV4ImageTag string ScannerV4ImageName string @@ -123,12 +116,6 @@ func DevelopmentBuildImageFlavor() ImageFlavor { FactImageName: "fact", FactImageTag: v.FactVersion, - ScannerImageName: "scanner", - ScannerSlimImageName: "scanner-slim", - ScannerImageTag: v.ScannerVersion, - ScannerDBImageName: "scanner-db", - ScannerDBSlimImageName: "scanner-db-slim", - ScannerV4ImageName: "scanner-v4", ScannerV4DBImageName: "scanner-v4-db", // Scanner v4 is released along with the main image, so the tags are expected to be the same. @@ -163,12 +150,6 @@ func RHACSReleaseImageFlavor() ImageFlavor { FactImageName: "rhacs-fact-rhel9", FactImageTag: v.FactVersion, - ScannerImageName: "rhacs-scanner-rhel9", - ScannerSlimImageName: "rhacs-scanner-slim-rhel9", - ScannerImageTag: v.ScannerVersion, - ScannerDBImageName: "rhacs-scanner-db-rhel9", - ScannerDBSlimImageName: "rhacs-scanner-db-slim-rhel9", - ScannerV4ImageName: "rhacs-scanner-v4-rhel9", ScannerV4DBImageName: "rhacs-scanner-v4-db-rhel9", // Scanner v4 is released along with the main image, so the tags are expected to be the same. @@ -212,12 +193,6 @@ func OpenSourceImageFlavor() ImageFlavor { FactImageName: "fact", FactImageTag: v.FactVersion, - ScannerImageName: "scanner", - ScannerSlimImageName: "scanner-slim", - ScannerImageTag: v.ScannerVersion, - ScannerDBImageName: "scanner-db", - ScannerDBSlimImageName: "scanner-db-slim", - ScannerV4ImageName: "scanner-v4", ScannerV4DBImageName: "scanner-v4-db", // Scanner v4 is released along with the main image, so the tags are expected to be the same. @@ -311,21 +286,6 @@ func (f *ImageFlavor) IsImageDefaultMain(img *storage.ImageName) bool { return f.MainImageNoTag() == overrideImageNoTag } -// ScannerImage is the container image reference (full name) for the scanner image. -func (f *ImageFlavor) ScannerImage() string { - return fmt.Sprintf("%s/%s:%s", f.MainRegistry, f.ScannerImageName, f.ScannerImageTag) -} - -// ScannerSlimImage is the container image reference (full name) for the scanner-slim image. -func (f *ImageFlavor) ScannerSlimImage() string { - return fmt.Sprintf("%s/%s:%s", f.MainRegistry, f.ScannerSlimImageName, f.ScannerImageTag) -} - -// ScannerDBImage is the container image reference (full name) for the scanner-db image. -func (f *ImageFlavor) ScannerDBImage() string { - return fmt.Sprintf("%s/%s:%s", f.MainRegistry, f.ScannerDBImageName, f.ScannerImageTag) -} - // ScannerV4Image is the container image reference (full name) for the scanner-v4 image. func (f *ImageFlavor) ScannerV4Image() string { return fmt.Sprintf("%s/%s:%s", f.MainRegistry, f.ScannerV4ImageName, f.ScannerV4ImageTag) diff --git a/pkg/images/defaults/flavor_test.go b/pkg/images/defaults/flavor_test.go index 4f87fbc812926..1411fbd00b4cd 100644 --- a/pkg/images/defaults/flavor_test.go +++ b/pkg/images/defaults/flavor_test.go @@ -117,15 +117,12 @@ func (s *imageFlavorTestSuite) TestOpenSourceImageFlavorDevReleaseTags() { s.Equal(f.MainImageTag, "3.0.99.0") s.Equal(f.CentralDBImageTag, "3.0.99.0") s.Equal(f.CollectorImageTag, "3.0.99.0") - s.Equal(f.ScannerImageTag, "3.0.99.0") } else { // Original tags are used s.Equal(f.MainImageTag, "3.0.99.0") s.Equal(f.CentralDBImageTag, "3.0.99.0") s.Equal(f.CollectorImageTag, "99.9.9") - s.Equal(f.ScannerImageTag, "99.9.9") - } } diff --git a/pkg/images/defaults/testutils/flavor.go b/pkg/images/defaults/testutils/flavor.go index 5d60121f7afed..0dddbc8eba2f2 100644 --- a/pkg/images/defaults/testutils/flavor.go +++ b/pkg/images/defaults/testutils/flavor.go @@ -13,25 +13,20 @@ import ( func MakeImageFlavorForTest(t *testing.T) defaults.ImageFlavor { testutils.MustBeInTest(t) return defaults.ImageFlavor{ - MainRegistry: "test.registry", - MainImageName: "main", - MainImageTag: "1.2.3", - CentralDBImageTag: "1.2.4", - CentralDBImageName: "central-db", - CollectorRegistry: "test.registry", - CollectorImageName: "collector", - CollectorImageTag: "3.2.1", - FactRegistry: "test.registry", - FactImageName: "fact", - FactImageTag: "0.1.0", - ScannerImageName: "scanner", - ScannerSlimImageName: "scanner-slim", - ScannerImageTag: "2.2.2", - ScannerDBImageName: "scanner-db", - ScannerDBSlimImageName: "scanner-db-slim", - ScannerV4ImageName: "scanner-v4", - ScannerV4DBImageName: "scanner-v4-db", - ScannerV4ImageTag: "1.2.3", // Match MainVersion + MainRegistry: "test.registry", + MainImageName: "main", + MainImageTag: "1.2.3", + CentralDBImageTag: "1.2.4", + CentralDBImageName: "central-db", + CollectorRegistry: "test.registry", + CollectorImageName: "collector", + CollectorImageTag: "3.2.1", + FactRegistry: "test.registry", + FactImageName: "fact", + FactImageTag: "0.1.0", + ScannerV4ImageName: "scanner-v4", + ScannerV4DBImageName: "scanner-v4-db", + ScannerV4ImageTag: "1.2.3", // Match MainVersion ChartRepo: defaults.ChartRepo{ URL: "some.url/path/to/chart", IconURL: "some.url/path/to/icon.png", @@ -42,7 +37,6 @@ func MakeImageFlavorForTest(t *testing.T) defaults.ImageFlavor { Versions: version.Versions{ CollectorVersion: "3.2.1", MainVersion: "1.2.3", - ScannerVersion: "2.2.2", ChartVersion: "1.23.4", FactVersion: "0.1.0", }, diff --git a/pkg/images/enricher/enricher_impl.go b/pkg/images/enricher/enricher_impl.go index 6f747496609c2..3e773a97b9992 100644 --- a/pkg/images/enricher/enricher_impl.go +++ b/pkg/images/enricher/enricher_impl.go @@ -158,7 +158,7 @@ func (e *enricherImpl) delegateEnrichImage(ctx context.Context, enrichCtx Enrich clusterID, shouldDelegate, err = e.scanDelegator.GetDelegateClusterID(ctx, image.GetName()) } else { // A cluster ID has been passed to the enricher, determine if it's valid for delegation. - err = e.scanDelegator.ValidateCluster(enrichCtx.ClusterID) + err = e.scanDelegator.ValidateCluster(ctx, enrichCtx.ClusterID) shouldDelegate = true } diff --git a/pkg/images/enricher/enricher_impl_test.go b/pkg/images/enricher/enricher_impl_test.go index 072e106e51fed..24658b4757270 100644 --- a/pkg/images/enricher/enricher_impl_test.go +++ b/pkg/images/enricher/enricher_impl_test.go @@ -1179,7 +1179,7 @@ func TestDelegateEnrichImage(t *testing.T) { t.Run("delegate enrich success with cluster id provided", func(t *testing.T) { setup(t) fakeImage := &storage.Image{} - dele.EXPECT().ValidateCluster("cluster-id").Return(nil) + dele.EXPECT().ValidateCluster(emptyCtx, "cluster-id").Return(nil) dele.EXPECT().DelegateScanImage(emptyCtx, gomock.Any(), "cluster-id", "", gomock.Any()).Return(fakeImage, nil) deleEnrichCtx := EnrichmentContext{Delegable: true, ClusterID: "cluster-id"} @@ -1192,7 +1192,7 @@ func TestDelegateEnrichImage(t *testing.T) { t.Run("delegate enrich error with cluster id provided", func(t *testing.T) { setup(t) fakeImage := &storage.Image{} - dele.EXPECT().ValidateCluster("cluster-id").Return(errBroken) + dele.EXPECT().ValidateCluster(emptyCtx, "cluster-id").Return(errBroken) deleEnrichCtx := EnrichmentContext{Delegable: true, ClusterID: "cluster-id"} should, err := e.delegateEnrichImage(emptyCtx, deleEnrichCtx, fakeImage) diff --git a/pkg/images/enricher/enricher_v2_impl.go b/pkg/images/enricher/enricher_v2_impl.go index 55f7034b45ccc..df8b3a70969bf 100644 --- a/pkg/images/enricher/enricher_v2_impl.go +++ b/pkg/images/enricher/enricher_v2_impl.go @@ -168,7 +168,7 @@ func (e *enricherV2Impl) delegateEnrichImage(ctx context.Context, enrichCtx Enri clusterID, shouldDelegate, err = e.scanDelegator.GetDelegateClusterID(ctx, imageV2.GetName()) } else { // A cluster ID has been passed to the enricher, determine if it's valid for delegation. - err = e.scanDelegator.ValidateCluster(enrichCtx.ClusterID) + err = e.scanDelegator.ValidateCluster(ctx, enrichCtx.ClusterID) shouldDelegate = true } diff --git a/pkg/images/enricher/enricher_v2_impl_test.go b/pkg/images/enricher/enricher_v2_impl_test.go index ec24990660c35..1976852d1bc3b 100644 --- a/pkg/images/enricher/enricher_v2_impl_test.go +++ b/pkg/images/enricher/enricher_v2_impl_test.go @@ -1209,7 +1209,7 @@ func TestDelegateEnrichImageV2(t *testing.T) { t.Run("delegate enrich success with cluster id provided", func(t *testing.T) { setup(t) fakeImage := &storage.ImageV2{} - dele.EXPECT().ValidateCluster("cluster-id").Return(nil) + dele.EXPECT().ValidateCluster(emptyCtx, "cluster-id").Return(nil) dele.EXPECT().DelegateScanImageV2(emptyCtx, gomock.Any(), "cluster-id", "", gomock.Any()).Return(fakeImage, nil) deleEnrichCtx := EnrichmentContext{Delegable: true, ClusterID: "cluster-id"} @@ -1222,7 +1222,7 @@ func TestDelegateEnrichImageV2(t *testing.T) { t.Run("delegate enrich error with cluster id provided", func(t *testing.T) { setup(t) fakeImage := &storage.ImageV2{} - dele.EXPECT().ValidateCluster("cluster-id").Return(errBroken) + dele.EXPECT().ValidateCluster(emptyCtx, "cluster-id").Return(errBroken) deleEnrichCtx := EnrichmentContext{Delegable: true, ClusterID: "cluster-id"} should, err := e.delegateEnrichImage(emptyCtx, deleEnrichCtx, fakeImage) diff --git a/pkg/migrations/release_version.go b/pkg/migrations/release_version.go new file mode 100644 index 0000000000000..31182bb6b3d40 --- /dev/null +++ b/pkg/migrations/release_version.go @@ -0,0 +1,9 @@ +package migrations + +//go:generate go run ../../tools/generate-helpers/release-versions + +// ReleaseVersion records a stream's initial-release database sequence (GA, or latest RC until GA). +type ReleaseVersion struct { + Version string + Sequence int +} diff --git a/pkg/migrations/release_versions.go b/pkg/migrations/release_versions.go new file mode 100644 index 0000000000000..f787dccd185fb --- /dev/null +++ b/pkg/migrations/release_versions.go @@ -0,0 +1,16 @@ +// Code generated by release-versions. DO NOT EDIT. + +package migrations + +var releaseVersions = []ReleaseVersion{ + {Version: "4.4", Sequence: 199}, + {Version: "4.5", Sequence: 205}, + {Version: "4.6", Sequence: 209}, + {Version: "4.7", Sequence: 209}, + {Version: "4.8", Sequence: 211}, + {Version: "4.9", Sequence: 213}, + {Version: "4.10", Sequence: 220}, + {Version: "4.11", Sequence: 225}, + {Version: "5.0", Sequence: 227}, + {Version: "5.1", Sequence: 227}, +} diff --git a/pkg/mocks/github.com/jackc/pgx/v5/mocks/rows.go b/pkg/mocks/github.com/jackc/pgx/v5/mocks/rows.go index 5deff357c4ee4..64eec106df3ec 100644 --- a/pkg/mocks/github.com/jackc/pgx/v5/mocks/rows.go +++ b/pkg/mocks/github.com/jackc/pgx/v5/mocks/rows.go @@ -8,6 +8,7 @@ import ( "github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5/pgconn" + "github.com/jackc/pgx/v5/pgtype" ) // This file was copied and fixed @@ -221,6 +222,10 @@ func (rs *rowSets) Conn() *pgx.Conn { return nil } +func (rs *rowSets) TypeMap() *pgtype.Map { + return nil +} + func convert(rows ...*Rows) pgx.Rows { defs := 0 sets := make([]*Rows, len(rows)) diff --git a/pkg/mtls/README.md b/pkg/mtls/README.md index f9045e81f8f0a..e601bbdedbf30 100644 --- a/pkg/mtls/README.md +++ b/pkg/mtls/README.md @@ -52,12 +52,12 @@ This document covers TLS certificate management in StackRox, primarily the inter - Sensor cert refresh (TLS challenge + CA bundle): `sensor/kubernetes/certrefresh/` - Postgres DB cert reload (Central DB, Scanner V4 DB): `image/postgres/scripts/cert-watcher.sh`, `image/templates/helm/shared/templates/_cert-watcher.tpl` -### Central has four independent cert-handling paths +### Central has three independent cert-handling paths 1. **TLS manager** (`TLSConfigHolder`) — incoming connections. Composes default cert (watched) + internal cert (watched) + OpenShift cert (watched, if configured) + sync.Once trust roots. + - **OpenShift service-serving TLS** (`central/tlsconfig/openshift_tls.go`) — on OpenShift, watches certs issued for the `central-ocp` Service. Loaded into the TLS manager and presented via SNI on the same `:8443` listener alongside the StackRox internal cert. 2. **Outbound client connections** (`clientconn.TLSConfig`) — reads leaf cert from disk on each TLS handshake, trust pool from `mtls.CACert()`. 3. **TLS challenge endpoint** (`central/metadata/service`) — reads primary leaf via certwatch, issues secondary leaf with short validity and auto-renewal, reads CA via `mtls.CACert()`. -4. **OpenShift service-serving TLS** (`central/tlsconfig/openshift_tls.go`) — on OpenShift, watches certs issued for the `central-ocp` Service. Presented via SNI on the same `:8443` listener alongside the StackRox internal cert. ## Certificate caching diff --git a/pkg/policyutils/exclusions_test.go b/pkg/policyutils/exclusions_test.go index c5af2b5742431..ff7c7a218f1dd 100644 --- a/pkg/policyutils/exclusions_test.go +++ b/pkg/policyutils/exclusions_test.go @@ -33,8 +33,7 @@ func TestDeploymentExclusionToQuery_NoDeploymentExclusions(t *testing.T) { func TestDeploymentExclusionToQuery_MalformedDeploymentExclusion(t *testing.T) { q := DeploymentExclusionToQuery([]*storage.Exclusion{ { - Name: "myExcludedScope", - Deployment: &storage.Exclusion_Deployment{}, + Name: "myExcludedScope", Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{}}, }, }) protoassert.Equal(t, q, search.MatchNoneQuery()) @@ -43,10 +42,9 @@ func TestDeploymentExclusionToQuery_MalformedDeploymentExclusion(t *testing.T) { func TestDeploymentExclusionToQuery_NamedDeploymentExclusion(t *testing.T) { q := DeploymentExclusionToQuery([]*storage.Exclusion{ { - Name: "myExcludedScope", - Deployment: &storage.Exclusion_Deployment{ + Name: "myExcludedScope", Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{ Name: "blessed-deployment", - }, + }}, }, }) protoassert.Equal(t, q, search.NewQueryBuilder().AddExactMatches(search.DeploymentName, "blessed-deployment").ProtoQuery()) @@ -55,12 +53,11 @@ func TestDeploymentExclusionToQuery_NamedDeploymentExclusion(t *testing.T) { func TestDeploymentExclusionToQuery_ScopedDeploymentExclusion(t *testing.T) { q := DeploymentExclusionToQuery([]*storage.Exclusion{ { - Name: "myExcludedScope", - Deployment: &storage.Exclusion_Deployment{ + Name: "myExcludedScope", Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{ Scope: &storage.Scope{ Cluster: "blessed-cluster-id", }, - }, + }}, }, }) protoassert.Equal(t, q, search.NewQueryBuilder().AddExactMatches(search.ClusterID, "blessed-cluster-id").ProtoQuery()) diff --git a/pkg/postgres/walker/walker.go b/pkg/postgres/walker/walker.go index fcfe5a6e82e1e..fb79783ca2119 100644 --- a/pkg/postgres/walker/walker.go +++ b/pkg/postgres/walker/walker.go @@ -357,7 +357,7 @@ func tableName(parent, child string) string { } func typeIsEnum(typ reflect.Type) bool { - enum, ok := reflect.Zero(typ).Interface().(protoreflect.ProtoEnum) + enum, ok := reflect.TypeAssert[protoreflect.ProtoEnum](reflect.Zero(typ)) if !ok { return false } diff --git a/pkg/printers/sarif.go b/pkg/printers/sarif.go index e1188b3dea0d2..d1de4b365a5a7 100644 --- a/pkg/printers/sarif.go +++ b/pkg/printers/sarif.go @@ -5,8 +5,8 @@ import ( "slices" "strings" - "github.com/owenrumney/go-sarif/v2/sarif" - "github.com/pkg/errors" + "github.com/owenrumney/go-sarif/v3/pkg/report" + "github.com/owenrumney/go-sarif/v3/pkg/report/v210/sarif" "github.com/stackrox/rox/generated/storage" "github.com/stackrox/rox/pkg/errox" "github.com/stackrox/rox/pkg/gjson" @@ -125,58 +125,54 @@ func (s *SarifPrinter) Print(object interface{}, out io.Writer) error { WithVersion(version.GetMainVersion()). WithFullName("roxctl command line utility") - report, err := sarif.New(sarif.Version210) - if err != nil { - return errors.Wrap(err, "creating sarif report") - } + sarifReport := report.NewV210Report() for _, entry := range sarifEntries { s.addEntry(run, entry) } - report.AddRun(run) - return report.PrettyWrite(out) + sarifReport.AddRun(run) + return sarifReport.PrettyWrite(out) } func (s *SarifPrinter) addEntry(run *sarif.Run, entry sarifEntry) { rule := run.AddRule(entry.ruleID) rule.WithName(s.reportType). // Setting the description is also setting the title displayed in GitHub. - WithShortDescription(sarif.NewMultiformatMessageString(entry.ruleID)). - WithFullDescription(sarif.NewMultiformatMessageString(entry.ruleID)). - WithHelp(sarif.NewMultiformatMessageString(entry.help)) + WithShortDescription(sarif.NewMultiformatMessageString().WithText(entry.ruleID)). + WithFullDescription(sarif.NewMultiformatMessageString().WithText(entry.ruleID)). + WithHelp(sarif.NewMultiformatMessageString().WithText(entry.help)) if entry.helpLink != "" { rule.WithHelpURI(entry.helpLink) } - properties := sarif.Properties{ + properties := sarif.NewPropertyBag(). // Precision very-high ensures this violation is shown first within GitHub. - "precision": "very-high", + Add("precision", "very-high"). // Tags allow filtering, which is desirable to have. - "tags": []string{ + WithTags([]string{ utils.IfThenElse(s.reportType == SarifVulnerabilityReport, "security", "policy-violation"), entry.severity, - }, - } + }) + // For vulnerability reports, generated the security severity based of the severity reported. if s.reportType == SarifVulnerabilityReport { - properties["security-severity"] = toSecuritySeverity(entry.severity) + properties.Add("security-severity", toSecuritySeverity(entry.severity)) } rule.WithProperties(properties) - run.AddResult(sarif.NewRuleResult(entry.ruleID). + run.CreateResultForRule(entry.ruleID). WithLevel(toSarifLevel(entry.severity)). // Reusing the help here, since the help includes remediation information. WithMessage(sarif.NewMessage().WithText(entry.help)). WithLocations([]*sarif.Location{ - { - PhysicalLocation: &sarif.PhysicalLocation{ - ArtifactLocation: sarif.NewArtifactLocation().WithUri(s.entity), - Region: sarif.NewSimpleRegion(1, 1), - }, - }, - })) + sarif.NewLocationWithPhysicalLocation( + sarif.NewPhysicalLocation(). + WithArtifactLocation(sarif.NewArtifactLocation().WithURI(s.entity)). + WithRegion(sarif.NewSimpleRegion(1, 1)), + ), + }) } func sarifEntriesFromJSONObject(jsonObject interface{}, pathExpressions map[string]string) ([]sarifEntry, error) { diff --git a/pkg/printers/sarif_test.go b/pkg/printers/sarif_test.go index 0fe19b6db5d3b..35d41a8e07802 100644 --- a/pkg/printers/sarif_test.go +++ b/pkg/printers/sarif_test.go @@ -8,6 +8,7 @@ import ( "strings" "testing" + "github.com/owenrumney/go-sarif/v3/pkg/report/v210/sarif" "github.com/stackrox/rox/pkg/errox" "github.com/stackrox/rox/pkg/version" "github.com/stretchr/testify/assert" @@ -75,11 +76,63 @@ func TestSarifPrinter_Print_Success(t *testing.T) { err = printer.Print(obj, &out) require.NoError(t, err) + // Strict parsing preserves null arrays so validation checks the emitted output. + report, err := sarif.FromString(out.String(), sarif.WithStrictValidation()) + require.NoError(t, err) + assert.NoError(t, report.Validate()) + // Since the report contains the version, replace it specifically here. exp, err := regexp.Compile(fmt.Sprintf(`"version": "%s"`, version.GetMainVersion())) require.NoError(t, err) output := exp.ReplaceAllString(out.String(), `"version": ""`) - assert.Equal(t, string(expectedOutput), output) + assert.JSONEq(t, string(expectedOutput), output) +} + +func TestSarifPrinter_Print_RuleIndexes(t *testing.T) { + for name, tc := range map[string]struct { + ruleIDs []string + indexes []int + }{ + "distinct rules": { + ruleIDs: []string{"A", "B", "C"}, + indexes: []int{0, 1, 2}, + }, + "repeated rule": { + ruleIDs: []string{"A", "B", "A", "C"}, + indexes: []int{0, 1, 0, 2}, + }, + } { + t.Run(name, func(t *testing.T) { + obj := &testObject{} + for _, ruleID := range tc.ruleIDs { + obj.Violations = append(obj.Violations, violation{ + ID: ruleID, + Reason: "remediation", + Severity: "IMPORTANT", + }) + } + printer := NewSarifPrinter(map[string]string{ + SarifRuleJSONPathExpressionKey: "violations.#.id", + SarifHelpJSONPathExpressionKey: "violations.#.reason", + SarifSeverityJSONPathExpressionKey: "violations.#.severity", + }, "docker.io/nginx:1.19", SarifPolicyReport) + var out strings.Builder + require.NoError(t, printer.Print(obj, &out)) + report, err := sarif.FromString(out.String(), sarif.WithStrictValidation()) + require.NoError(t, err) + assert.NoError(t, report.Validate()) + require.Len(t, report.Runs, 1) + run := report.Runs[0] + require.Len(t, run.Tool.Driver.Rules, 3) + require.Len(t, run.Results, len(tc.ruleIDs)) + for i, result := range run.Results { + assert.Equal(t, tc.indexes[i], result.RuleIndex) + require.GreaterOrEqual(t, result.RuleIndex, 0) + require.Less(t, result.RuleIndex, len(run.Tool.Driver.Rules)) + assert.Equal(t, result.RuleID, run.Tool.Driver.Rules[result.RuleIndex].ID) + } + }) + } } func TestSarifPrinter_Print_EmptyViolations(t *testing.T) { @@ -98,9 +151,14 @@ func TestSarifPrinter_Print_EmptyViolations(t *testing.T) { err = printer.Print(obj, &out) require.NoError(t, err) + // Strict parsing preserves null arrays so validation checks the emitted output. + report, err := sarif.FromString(out.String(), sarif.WithStrictValidation()) + require.NoError(t, err) + assert.NoError(t, report.Validate()) + // Since the report contains the version, replace it specifically here. exp, err := regexp.Compile(fmt.Sprintf(`"version": "%s"`, version.GetMainVersion())) require.NoError(t, err) output := exp.ReplaceAllString(out.String(), `"version": ""`) - assert.Equal(t, string(expectedOutput), output) + assert.JSONEq(t, string(expectedOutput), output) } diff --git a/pkg/printers/testdata/empty_sarif_report.json b/pkg/printers/testdata/empty_sarif_report.json index 12a809e7d2a13..3d7731ab0b0a6 100644 --- a/pkg/printers/testdata/empty_sarif_report.json +++ b/pkg/printers/testdata/empty_sarif_report.json @@ -1,10 +1,40 @@ { "version": "2.1.0", "$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/main/sarif-2.1/schema/sarif-schema-2.1.0.json", + "properties": {}, "runs": [ { + "addresses": [], + "graphs": [], + "invocations": [], + "language": "en-US", + "logicalLocations": [], + "newlineSequences": [ + "\r\n", + "\n" + ], + "policies": [], + "redactionTokens": [], + "runAggregates": [], + "taxonomies": [], + "threadFlowLocations": [], + "translations": [], + "versionControlProvenance": [], + "webRequests": [], + "webResponses": [], "tool": { + "extensions": [], "driver": { + "contents": [ + "localizedData", + "nonLocalizedData" + ], + "isComprehensive": false, + "language": "en-US", + "locations": [], + "notifications": [], + "supportedTaxonomies": [], + "taxa": [], "fullName": "roxctl command line utility", "informationUri": "https://github.com/stackrox/stackrox", "name": "roxctl", diff --git a/pkg/printers/testdata/sarif_report.json b/pkg/printers/testdata/sarif_report.json index f397ad866c0d6..3b6c3aad03213 100644 --- a/pkg/printers/testdata/sarif_report.json +++ b/pkg/printers/testdata/sarif_report.json @@ -1,15 +1,46 @@ { + "properties": {}, "version": "2.1.0", "$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/main/sarif-2.1/schema/sarif-schema-2.1.0.json", "runs": [ { + "addresses": [], + "graphs": [], + "invocations": [], + "language": "en-US", + "logicalLocations": [], + "newlineSequences": [ + "\r\n", + "\n" + ], + "policies": [], + "redactionTokens": [], + "runAggregates": [], + "taxonomies": [], + "threadFlowLocations": [], + "translations": [], + "versionControlProvenance": [], + "webRequests": [], + "webResponses": [], "tool": { + "extensions": [], "driver": { + "contents": [ + "localizedData", + "nonLocalizedData" + ], + "isComprehensive": false, + "language": "en-US", + "locations": [], + "notifications": [], + "supportedTaxonomies": [], + "taxa": [], "fullName": "roxctl command line utility", "informationUri": "https://github.com/stackrox/stackrox", "name": "roxctl", "rules": [ { + "relationships": [], "id": "first-violation", "name": "PolicyViolations", "shortDescription": { @@ -30,6 +61,7 @@ } }, { + "relationships": [], "id": "second-violation", "name": "PolicyViolations", "shortDescription": { @@ -50,6 +82,7 @@ } }, { + "relationships": [], "id": "third-violation", "name": "PolicyViolations", "shortDescription": { @@ -75,19 +108,37 @@ }, "results": [ { + "attachments": [], + "codeFlows": [], + "fixes": [], + "graphTraversals": [], + "graphs": [], + "kind": "fail", + "rank": -1, + "relatedLocations": [], + "stacks": [], + "taxa": [], "ruleId": "first-violation", "ruleIndex": 0, "level": "error", "message": { + "arguments": [], "text": "something about misconfiguration" }, "locations": [ { + "annotations": [], + "id": -1, + "logicalLocations": [], + "relationships": [], "physicalLocation": { "artifactLocation": { + "index": -1, "uri": "docker.io/nginx:1.19" }, "region": { + "byteOffset": -1, + "charOffset": -1, "startLine": 1, "endLine": 1 } @@ -96,19 +147,37 @@ ] }, { + "attachments": [], + "codeFlows": [], + "fixes": [], + "graphTraversals": [], + "graphs": [], + "kind": "fail", + "rank": -1, + "relatedLocations": [], + "stacks": [], + "taxa": [], "ruleId": "second-violation", "ruleIndex": 1, "level": "note", "message": { + "arguments": [], "text": "something about vulnerabilities" }, "locations": [ { + "annotations": [], + "id": -1, + "logicalLocations": [], + "relationships": [], "physicalLocation": { "artifactLocation": { + "index": -1, "uri": "docker.io/nginx:1.19" }, "region": { + "byteOffset": -1, + "charOffset": -1, "startLine": 1, "endLine": 1 } @@ -117,19 +186,37 @@ ] }, { + "attachments": [], + "codeFlows": [], + "fixes": [], + "graphTraversals": [], + "graphs": [], + "kind": "fail", + "rank": -1, + "relatedLocations": [], + "stacks": [], + "taxa": [], "ruleId": "third-violation", "ruleIndex": 2, "level": "error", "message": { + "arguments": [], "text": "something about secrets" }, "locations": [ { + "annotations": [], + "id": -1, + "logicalLocations": [], + "relationships": [], "physicalLocation": { "artifactLocation": { + "index": -1, "uri": "docker.io/nginx:1.19" }, "region": { + "byteOffset": -1, + "charOffset": -1, "startLine": 1, "endLine": 1 } diff --git a/pkg/protocompat/oneof.go b/pkg/protocompat/oneof.go index 96d043e7249c5..aa148cd07926d 100644 --- a/pkg/protocompat/oneof.go +++ b/pkg/protocompat/oneof.go @@ -25,7 +25,7 @@ func GetOneOfTypesByInterface(msgType reflect.Type, oneOfInterfaceType reflect.T oneOfFieldTypes := make([]reflect.Type, 0) // Get proto message from Go reflect type. - msg, ok := reflect.New(msgType).Interface().(proto.Message) + msg, ok := reflect.TypeAssert[proto.Message](reflect.New(msgType)) if !ok { return oneOfFieldTypes } diff --git a/pkg/protoconv/resources/resources.go b/pkg/protoconv/resources/resources.go index e95a3a12736b7..e03afc7e1a050 100644 --- a/pkg/protoconv/resources/resources.go +++ b/pkg/protoconv/resources/resources.go @@ -106,7 +106,7 @@ func SpecToPodTemplateSpec(spec reflect.Value) (v1.PodTemplateSpec, error) { if templateInterface.Type().Kind() == reflect.Pointer && !templateInterface.IsNil() { templateInterface = templateInterface.Elem() } - podTemplate, ok := templateInterface.Interface().(v1.PodTemplateSpec) + podTemplate, ok := reflect.TypeAssert[v1.PodTemplateSpec](templateInterface) if !ok { return v1.PodTemplateSpec{}, errors.New("not a valid PodTemplateSpec") } @@ -356,12 +356,12 @@ func (w *DeploymentWrap) populateReplicas(spec reflect.Value, obj interface{}) { return } - replicasPointer, ok := replicaField.Interface().(*int32) + replicasPointer, ok := reflect.TypeAssert[*int32](replicaField) if ok && replicasPointer != nil { w.Deployment.Replicas = int64(*replicasPointer) } - replicas, ok := replicaField.Interface().(int32) + replicas, ok := reflect.TypeAssert[int32](replicaField) if ok { w.Deployment.Replicas = int64(replicas) } diff --git a/pkg/protoreflect/field.go b/pkg/protoreflect/field.go index c7a97b95069f1..f06ae1d1ed51e 100644 --- a/pkg/protoreflect/field.go +++ b/pkg/protoreflect/field.go @@ -7,7 +7,7 @@ import ( ) func IsProtoMessage(msgType reflect.Type) bool { - _, ok := reflect.New(msgType).Interface().(protocompat.Message) + _, ok := reflect.TypeAssert[protocompat.Message](reflect.New(msgType)) return ok } diff --git a/pkg/registrymirror/store_test.go b/pkg/registrymirror/store_test.go index 1d31e682108ff..705603c959772 100644 --- a/pkg/registrymirror/store_test.go +++ b/pkg/registrymirror/store_test.go @@ -172,6 +172,14 @@ func TestDataRaceAtCleanup(t *testing.T) { s.Cleanup() doneSignal.Signal() wg.Wait() + + // The stopped writers may still have a delayed updateConfigNow scheduled. + // One more update cancels those pending writes and lets us wait for the pipeline to flush, + // so no background write recreates the file after Cleanup(). + source := icspA.Spec.RepositoryDigestMirrors[0].Source + require.NoError(t, s.UpsertImageContentSourcePolicy(icspA)) + require.Eventually(t, func() bool { return fileContains(path, source) }, 5*time.Second, 10*time.Millisecond) + s.Cleanup() } func TestCleanup(t *testing.T) { diff --git a/pkg/renderer/images.go b/pkg/renderer/images.go index aa80367c25dd6..22735a127cf12 100644 --- a/pkg/renderer/images.go +++ b/pkg/renderer/images.go @@ -88,10 +88,6 @@ func configureImageOverrides(c *Config, imageFlavor defaults.ImageFlavor) { imageOverrides["Main"] = mainOverrides imageOverrides["CentralDB"] = ComputeImageOverrides(c.K8sConfig.CentralDBImage, registry, imageFlavor.CentralDBImageName, imageFlavor.CentralDBImageTag) - imageOverrides["Scanner"] = ComputeImageOverrides(c.K8sConfig.ScannerImage, registry, imageFlavor.ScannerImageName, - imageFlavor.ScannerImageTag) - imageOverrides["ScannerDB"] = ComputeImageOverrides(c.K8sConfig.ScannerDBImage, registry, imageFlavor.ScannerDBImageName, - imageFlavor.ScannerImageTag) imageOverrides["ScannerV4"] = ComputeImageOverrides(c.K8sConfig.ScannerV4Image, registry, imageFlavor.ScannerV4ImageName, imageFlavor.ScannerV4ImageTag) imageOverrides["ScannerV4DB"] = ComputeImageOverrides(c.K8sConfig.ScannerV4DBImage, registry, imageFlavor.ScannerV4DBImageName, diff --git a/pkg/renderer/images_test.go b/pkg/renderer/images_test.go index 62bf68186da02..ae15153d017e7 100644 --- a/pkg/renderer/images_test.go +++ b/pkg/renderer/images_test.go @@ -167,16 +167,12 @@ func TestConfigureImageOverrides(t *testing.T) { configValues CommonConfig expectedMainRegistry string expectedMainOverrides map[string]string - expectedScannerOverrides map[string]string - expectedScannerDBOverrides map[string]string expectedScannerV4Overrides map[string]string expectedScannerV4DBOverrides map[string]string }{ "Override Main Registry": { configValues: CommonConfig{ MainImage: "quay.io/rhacs/main", - ScannerImage: testFlavor.ScannerImage(), - ScannerDBImage: testFlavor.ScannerDBImage(), ScannerV4Image: testFlavor.ScannerV4Image(), ScannerV4DBImage: testFlavor.ScannerV4DBImage(), }, @@ -184,12 +180,6 @@ func TestConfigureImageOverrides(t *testing.T) { expectedMainOverrides: map[string]string{ "Tag": "latest", }, - expectedScannerOverrides: map[string]string{ - "Registry": "test.registry", - }, - expectedScannerDBOverrides: map[string]string{ - "Registry": "test.registry", - }, expectedScannerV4Overrides: map[string]string{ "Registry": "test.registry", }, @@ -200,8 +190,6 @@ func TestConfigureImageOverrides(t *testing.T) { "Don't override main registry": { configValues: CommonConfig{ MainImage: testFlavor.MainImage(), - ScannerImage: testFlavor.ScannerImage(), - ScannerDBImage: testFlavor.ScannerDBImage(), ScannerV4Image: testFlavor.ScannerV4Image(), ScannerV4DBImage: testFlavor.ScannerV4DBImage(), }, @@ -209,8 +197,6 @@ func TestConfigureImageOverrides(t *testing.T) { "Override Main sub-repo": { configValues: CommonConfig{ MainImage: "test.registry/sub-repo/main", - ScannerImage: testFlavor.ScannerImage(), - ScannerDBImage: testFlavor.ScannerDBImage(), ScannerV4Image: testFlavor.ScannerV4Image(), ScannerV4DBImage: testFlavor.ScannerV4DBImage(), }, @@ -218,12 +204,6 @@ func TestConfigureImageOverrides(t *testing.T) { expectedMainOverrides: map[string]string{ "Tag": "latest", }, - expectedScannerOverrides: map[string]string{ - "Registry": "test.registry", - }, - expectedScannerDBOverrides: map[string]string{ - "Registry": "test.registry", - }, expectedScannerV4Overrides: map[string]string{ "Registry": "test.registry", }, @@ -234,8 +214,6 @@ func TestConfigureImageOverrides(t *testing.T) { "Override Main sub-repo and name": { configValues: CommonConfig{ MainImage: "test.registry/sub-repo/my-main", - ScannerImage: testFlavor.ScannerImage(), - ScannerDBImage: testFlavor.ScannerDBImage(), ScannerV4Image: testFlavor.ScannerV4Image(), ScannerV4DBImage: testFlavor.ScannerV4DBImage(), }, @@ -248,15 +226,9 @@ func TestConfigureImageOverrides(t *testing.T) { "Override Scanner registry": { configValues: CommonConfig{ MainImage: testFlavor.MainImage(), - ScannerImage: "quay.io/rhacs/scanner", - ScannerDBImage: testFlavor.ScannerDBImage(), ScannerV4Image: "quay.io/rhacs/scanner-v4", ScannerV4DBImage: testFlavor.ScannerV4DBImage(), }, - expectedScannerOverrides: map[string]string{ - "Registry": "quay.io/rhacs", - "Tag": "latest", - }, expectedScannerV4Overrides: map[string]string{ "Registry": "quay.io/rhacs", "Tag": "latest", @@ -266,15 +238,9 @@ func TestConfigureImageOverrides(t *testing.T) { "Override ScannerDB registry": { configValues: CommonConfig{ MainImage: testFlavor.MainImage(), - ScannerImage: testFlavor.ScannerImage(), - ScannerDBImage: "quay.io/rhacs/scanner-db", ScannerV4Image: testFlavor.ScannerV4Image(), ScannerV4DBImage: "quay.io/rhacs/scanner-v4-db", }, - expectedScannerDBOverrides: map[string]string{ - "Registry": "quay.io/rhacs", - "Tag": "latest", - }, expectedScannerV4DBOverrides: map[string]string{ "Registry": "quay.io/rhacs", "Tag": "latest", @@ -283,8 +249,6 @@ func TestConfigureImageOverrides(t *testing.T) { "Override Main and Scanner registries": { configValues: CommonConfig{ MainImage: "quay.io/rhacs/main", - ScannerImage: "stackrox.io/scanner", - ScannerDBImage: testFlavor.ScannerDBImage(), ScannerV4Image: "stackrox.io/scanner-v4", ScannerV4DBImage: testFlavor.ScannerV4DBImage(), }, @@ -292,13 +256,6 @@ func TestConfigureImageOverrides(t *testing.T) { expectedMainOverrides: map[string]string{ "Tag": "latest", }, - expectedScannerOverrides: map[string]string{ - "Registry": "stackrox.io", - "Tag": "latest", - }, - expectedScannerDBOverrides: map[string]string{ - "Registry": "test.registry", - }, expectedScannerV4Overrides: map[string]string{ "Registry": "stackrox.io", "Tag": "latest", @@ -310,8 +267,6 @@ func TestConfigureImageOverrides(t *testing.T) { "Override Main and ScannerDB registries": { configValues: CommonConfig{ MainImage: "quay.io/rhacs/main", - ScannerImage: testFlavor.ScannerImage(), - ScannerDBImage: "stackrox.io/scanner-db", ScannerV4Image: testFlavor.ScannerV4Image(), ScannerV4DBImage: "stackrox.io/scanner-v4-db", }, @@ -319,13 +274,6 @@ func TestConfigureImageOverrides(t *testing.T) { expectedMainOverrides: map[string]string{ "Tag": "latest", }, - expectedScannerOverrides: map[string]string{ - "Registry": "test.registry", - }, - expectedScannerDBOverrides: map[string]string{ - "Registry": "stackrox.io", - "Tag": "latest", - }, expectedScannerV4Overrides: map[string]string{ "Registry": "test.registry", }, @@ -337,8 +285,6 @@ func TestConfigureImageOverrides(t *testing.T) { "Override Main, Scanner and ScannerDB with the same registries": { configValues: CommonConfig{ MainImage: "quay.io/rhacs/main", - ScannerImage: "quay.io/rhacs/scanner", - ScannerDBImage: "quay.io/rhacs/scanner-db", ScannerV4Image: "quay.io/rhacs/scanner-v4", ScannerV4DBImage: "quay.io/rhacs/scanner-v4-db", }, @@ -346,12 +292,6 @@ func TestConfigureImageOverrides(t *testing.T) { expectedMainOverrides: map[string]string{ "Tag": "latest", }, - expectedScannerOverrides: map[string]string{ - "Tag": "latest", - }, - expectedScannerDBOverrides: map[string]string{ - "Tag": "latest", - }, expectedScannerV4Overrides: map[string]string{ "Tag": "latest", }, @@ -383,16 +323,6 @@ func TestConfigureImageOverrides(t *testing.T) { } else { assert.Len(t, config.K8sConfig.ImageOverrides["Main"], 0, "should have no keys in Main map") } - if c.expectedScannerOverrides != nil { - assert.Equal(t, c.expectedScannerOverrides, config.K8sConfig.ImageOverrides["Scanner"].(map[string]string)) - } else { - assert.Len(t, config.K8sConfig.ImageOverrides["Scanner"], 0, "should have no keys in Scanner map") - } - if c.expectedScannerDBOverrides != nil { - assert.Equal(t, c.expectedScannerDBOverrides, config.K8sConfig.ImageOverrides["ScannerDB"].(map[string]string)) - } else { - assert.Len(t, config.K8sConfig.ImageOverrides["ScannerDB"], 0, "should have no keys in ScannerDB map") - } if c.expectedScannerV4Overrides != nil { assert.Equal(t, c.expectedScannerV4Overrides, config.K8sConfig.ImageOverrides["ScannerV4"].(map[string]string)) } else { diff --git a/pkg/renderer/kubernetes.go b/pkg/renderer/kubernetes.go index 74badd5b0c6e5..0470cb8217c48 100644 --- a/pkg/renderer/kubernetes.go +++ b/pkg/renderer/kubernetes.go @@ -55,12 +55,6 @@ func postProcessConfig(c *Config, mode mode, imageFlavor defaults.ImageFlavor) e if c.K8sConfig.CentralDBImage == "" { c.K8sConfig.CentralDBImage = imageFlavor.CentralDBImage() } - if c.K8sConfig.ScannerImage == "" { - c.K8sConfig.ScannerImage = imageFlavor.ScannerImage() - } - if c.K8sConfig.ScannerDBImage == "" { - c.K8sConfig.ScannerDBImage = imageFlavor.ScannerDBImage() - } if c.K8sConfig.ScannerV4Image == "" { c.K8sConfig.ScannerV4Image = imageFlavor.ScannerV4Image() } @@ -101,16 +95,6 @@ func postProcessConfig(c *Config, mode mode, imageFlavor defaults.ImageFlavor) e } } - c.K8sConfig.ScannerRegistry, err = kubernetesPkg.GetResolvedRegistry(c.K8sConfig.ScannerImage) - if err != nil { - return err - } - if c.K8sConfig.Registry != c.K8sConfig.ScannerRegistry { - c.K8sConfig.ScannerSecretName = "stackrox-scanner" - } else { - c.K8sConfig.ScannerSecretName = "stackrox" - } - if mode == renderAll { if err := injectImageTags(c); err != nil { return err diff --git a/pkg/renderer/kubernetes_helm_test.go b/pkg/renderer/kubernetes_helm_test.go index 1b5d3a2b78d76..cfc45da401f39 100644 --- a/pkg/renderer/kubernetes_helm_test.go +++ b/pkg/renderer/kubernetes_helm_test.go @@ -54,9 +54,7 @@ func getDefaultMetaValues(t *testing.T) *charts.MetaValues { FactImageRemote: "fact", FactImageTag: "0.1.0", - ScannerSlimImageRemote: "scanner", - ScannerImageTag: "3.0.11-slim", - ScannerV4ImageTag: "4.4.0.x-92-g9e8a347ffe", + ScannerV4ImageTag: "4.4.0.x-92-g9e8a347ffe", CollectionMethod: "CORE_BPF", diff --git a/pkg/renderer/kubernetes_test.go b/pkg/renderer/kubernetes_test.go index 1cbbdf2da34f7..c3b6b6a13c6b8 100644 --- a/pkg/renderer/kubernetes_test.go +++ b/pkg/renderer/kubernetes_test.go @@ -21,7 +21,6 @@ func getBaseConfig() Config { K8sConfig: &K8sConfig{ CommonConfig: CommonConfig{ MainImage: "stackrox/main:2.2.11.0-57-g392c0f5bed-dirty", - ScannerImage: "stackrox.io/scanner:0.4.2", ScannerV4Image: "stackrox.io/scanner-v4:0.5.0", }, }, @@ -136,9 +135,9 @@ func (suite *renderSuite) TestRenderFailsForOpenShift3() { func (suite *renderSuite) TestRenderWithBadImage() { conf := getBaseConfig() - conf.K8sConfig.ScannerImage = "invalid-image#!@$" + conf.K8sConfig.MainImage = "invalid-image#!@$" _, err := Render(conf, suite.testFlavor) - suite.Error(err) + suite.ErrorContains(err, "error parsing image name") } func (suite *renderSuite) TestRenderWithBadV4Image() { diff --git a/pkg/renderer/render_test.go b/pkg/renderer/render_test.go index 3eb5304e04084..c23521ec0cfe7 100644 --- a/pkg/renderer/render_test.go +++ b/pkg/renderer/render_test.go @@ -1,10 +1,12 @@ package renderer import ( + "fmt" "strings" "testing" v1 "github.com/stackrox/rox/generated/api/v1" + "github.com/stackrox/rox/pkg/helm/charts" "github.com/stackrox/rox/pkg/images/defaults" "github.com/stackrox/rox/pkg/images/defaults/testutils" "github.com/stackrox/rox/pkg/k8sutil" @@ -16,6 +18,56 @@ import ( "k8s.io/apimachinery/pkg/runtime" ) +func TestRenderCentralWorkerEnv(t *testing.T) { + t.Setenv("TEST_VERSIONS", "true") + flavor := testutils.MakeImageFlavorForTest(t) + config := getBaseConfig() + config.Environment = map[string]string{ + "ROX_CENTRAL_WORKER_ENABLED": "true", + "CUSTOM_ENV": "preserved", + } + require.NoError(t, postProcessConfig(&config, renderAll, flavor)) + valuesFiles, err := renderNewHelmValues(config) + require.NoError(t, err) + chartTemplate, err := config.HelmImage.GetCentralServicesChartTemplate() + require.NoError(t, err) + metaValues := charts.GetMetaValuesForFlavor(flavor) + metaValues.KubectlOutput = true + chartFiles, err := chartTemplate.InstantiateRaw(metaValues) + require.NoError(t, err) + + cases := map[string]struct { + enabled bool + expectedEnv []corev1.EnvVar + }{ + "enabled": { + enabled: true, + expectedEnv: []corev1.EnvVar{{Name: "ROX_CENTRAL_WORKER_ENABLED", Value: "true"}}, + }, + "disabled": {}, + } + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + workerValues := zip.NewFile("worker-values.yaml", []byte(fmt.Sprintf("centralWorker:\n enabled: %t\n", tc.enabled)), 0) + files, err := renderHelmChart(chartFiles, renderAll, append(valuesFiles, workerValues)) + require.NoError(t, err) + centralFile := filterCentralFile(files) + require.NotNil(t, centralFile) + deployment := getCentralDeployment(t, centralFile) + require.Len(t, deployment.Spec.Template.Spec.Containers, 1) + envVars := deployment.Spec.Template.Spec.Containers[0].Env + var workerEnv []corev1.EnvVar + for _, envVar := range envVars { + if envVar.Name == "ROX_CENTRAL_WORKER_ENABLED" { + workerEnv = append(workerEnv, envVar) + } + } + assert.Equal(t, tc.expectedEnv, workerEnv) + assert.Contains(t, envVars, corev1.EnvVar{Name: "CUSTOM_ENV", Value: "preserved"}) + }) + } +} + func TestRenderTLSSecretsOnly(t *testing.T) { config := Config{ SecretsByteMap: map[string][]byte{ @@ -77,8 +129,6 @@ func TestRenderScannerOnly(t *testing.T) { K8sConfig: &K8sConfig{ CommonConfig: CommonConfig{ MainImage: flavor.MainImage(), - ScannerImage: flavor.ScannerImage(), - ScannerDBImage: flavor.ScannerDBImage(), ScannerV4Image: flavor.ScannerV4Image(), ScannerV4DBImage: flavor.ScannerV4DBImage(), }, @@ -119,8 +169,6 @@ func TestRenderWithDeclarativeConfig(t *testing.T) { K8sConfig: &K8sConfig{ CommonConfig: CommonConfig{ MainImage: flavor.MainImage(), - ScannerImage: flavor.ScannerImage(), - ScannerDBImage: flavor.ScannerDBImage(), ScannerV4Image: flavor.ScannerV4Image(), ScannerV4DBImage: flavor.ScannerV4DBImage(), }, @@ -197,8 +245,6 @@ func TestRenderDeclarativeConfigEmpty(t *testing.T) { K8sConfig: &K8sConfig{ CommonConfig: CommonConfig{ MainImage: flavor.MainImage(), - ScannerImage: flavor.ScannerImage(), - ScannerDBImage: flavor.ScannerDBImage(), ScannerV4Image: flavor.ScannerV4Image(), ScannerV4DBImage: flavor.ScannerV4DBImage(), }, @@ -228,8 +274,6 @@ func TestRenderDeclarativeConfigEmpty(t *testing.T) { K8sConfig: &K8sConfig{ CommonConfig: CommonConfig{ MainImage: flavor.MainImage(), - ScannerImage: flavor.ScannerImage(), - ScannerDBImage: flavor.ScannerDBImage(), ScannerV4Image: flavor.ScannerV4Image(), ScannerV4DBImage: flavor.ScannerV4DBImage(), }, @@ -259,8 +303,6 @@ func TestRenderDeclarativeConfigEmpty(t *testing.T) { K8sConfig: &K8sConfig{ CommonConfig: CommonConfig{ MainImage: flavor.MainImage(), - ScannerImage: flavor.ScannerImage(), - ScannerDBImage: flavor.ScannerDBImage(), ScannerV4Image: flavor.ScannerV4Image(), ScannerV4DBImage: flavor.ScannerV4DBImage(), }, @@ -328,8 +370,6 @@ func TestDeclarativeConfigDuplicateValues(t *testing.T) { K8sConfig: &K8sConfig{ CommonConfig: CommonConfig{ MainImage: flavor.MainImage(), - ScannerImage: flavor.ScannerImage(), - ScannerDBImage: flavor.ScannerDBImage(), ScannerV4Image: flavor.ScannerV4Image(), ScannerV4DBImage: flavor.ScannerV4DBImage(), }, diff --git a/pkg/renderer/templater.go b/pkg/renderer/templater.go index 75ff1a11b7763..bbc9531d7739b 100644 --- a/pkg/renderer/templater.go +++ b/pkg/renderer/templater.go @@ -59,8 +59,6 @@ func (h *HostPathPersistenceInstance) WithNodeSelector() bool { type CommonConfig struct { MainImage string CentralDBImage string - ScannerImage string - ScannerDBImage string ScannerV4Image string ScannerV4DBImage string } @@ -106,10 +104,6 @@ type K8sConfig struct { // k8s fields Registry string - ScannerRegistry string - // If the scanner registry is different from the central registry get a separate secret - ScannerSecretName string - // These variables are not prompted for by Cobra, but are set based on // provided inputs for use in templating. MainImageTag string diff --git a/pkg/renderer/templates/public_values.yaml.tpl b/pkg/renderer/templates/public_values.yaml.tpl index e30ddff852591..30a40e9942d31 100644 --- a/pkg/renderer/templates/public_values.yaml.tpl +++ b/pkg/renderer/templates/public_values.yaml.tpl @@ -17,9 +17,6 @@ env: imagePullSecrets: useExisting: - stackrox - {{- if and .K8sConfig.ScannerSecretName (ne .K8sConfig.ScannerSecretName "stackrox") }} - - {{ .K8sConfig.ScannerSecretName | quote }} - {{- end }} {{- if .K8sConfig.ImageOverrides.MainRegistry }} image: @@ -153,6 +150,7 @@ scannerV4: {{- $_ := unset $envVars "ROX_TELEMETRY_ENDPOINT" -}} {{- $_ := unset $envVars "ROX_TELEMETRY_STORAGE_KEY_V1" -}} {{- $_ := unset $envVars "ROX_SCANNER_V4" -}} +{{- $_ := unset $envVars "ROX_CENTRAL_WORKER_ENABLED" -}} {{- if $envVars }} customize: diff --git a/pkg/scanners/scannerv4/convert.go b/pkg/scanners/scannerv4/convert.go index e511b1a605c66..a4869148a29dd 100644 --- a/pkg/scanners/scannerv4/convert.go +++ b/pkg/scanners/scannerv4/convert.go @@ -8,6 +8,8 @@ import ( "strconv" "strings" + "github.com/quay/claircore/rhel/rhcc" + v4 "github.com/stackrox/rox/generated/internalapi/scanner/v4" "github.com/stackrox/rox/generated/storage" "github.com/stackrox/rox/pkg/clair" @@ -21,16 +23,23 @@ import ( "github.com/stackrox/rox/pkg/utils" ) -// vulnDataSourceDelimiter separates the parts of a vuln's datasource. -// IMPORTANT: This delimiter was chosen because it does not appear in any known -// Claircore or StackRox updater names. -const vulnDataSourceDelimiter = "::" +const ( + // vulnDataSourceDelimiter separates the parts of a vuln's datasource. + // IMPORTANT: This delimiter was chosen because it does not appear in any known + // Claircore or StackRox updater names. + vulnDataSourceDelimiter = "::" + // redHatVEXUpdaterName identifies vulnerabilities from Claircore's Red Hat VEX updater. + redHatVEXUpdaterName = "rhel-vex" +) // digitSegment matches contiguous runs of digits for numeric segment comparisons. var digitSegment = regexp.MustCompile(`\d+`) func imageScan(metadata *storage.ImageMetadata, report *v4.VulnerabilityReport, scannerVersion string) *storage.ImageScan { layerSHAToIndex := clair.BuildSHAToIndexMap(metadata) + if features.ScannerV4RedHatLayers.Enabled() { + filterRedHatLayerVulnerabilities(report, layerSHAToIndex) + } if features.ScannerV4RedHatVEXNotAffected.Enabled() { filterNotAffectedVulnerabilities(report, layerSHAToIndex) } @@ -50,14 +59,7 @@ func imageScan(metadata *storage.ImageMetadata, report *v4.VulnerabilityReport, } func componentsWithLayerMap(metadata *storage.ImageMetadata, report *v4.VulnerabilityReport, layerSHAToIndex map[string]int32) []*storage.EmbeddedImageScanComponent { - pkgs := report.GetContents().GetPackages() - if len(pkgs) == 0 { - pkgs = make(map[string]*v4.Package, len(report.GetContents().GetPackagesDEPRECATED())) - // Fallback to the deprecated slice, if needed. - for _, pkg := range report.GetContents().GetPackagesDEPRECATED() { - pkgs[pkg.GetId()] = pkg - } - } + pkgs := packagesByID(report.GetContents()) // Filter out packages that should not become user-facing components. // Unreferenced source packages are kept defensively. dedupe := features.ScannerV4Dedupe.Enabled() @@ -149,6 +151,21 @@ func envOS(env *v4.Environment, report *v4.VulnerabilityReport) string { return dist.GetDid() + ":" + dist.GetVersionId() } +// packagesByID returns the current package map, falling back to the deprecated +// package list when the map is empty. +func packagesByID(contents *v4.Contents) map[string]*v4.Package { + packages := contents.GetPackages() + if len(packages) > 0 { + return packages + } + + packages = make(map[string]*v4.Package, len(contents.GetPackagesDEPRECATED())) + for _, pkg := range contents.GetPackagesDEPRECATED() { + packages[pkg.GetId()] = pkg + } + return packages +} + // environmentList returns the *v4.Environment_List associated with the given // package ID, falling back to the deprecated environments map if the // current one is unset. @@ -577,6 +594,51 @@ func getPackageLayerIndex(report *v4.VulnerabilityReport, layerSHAToIndex map[st return layerIdx, ok } +// filterRedHatLayerVulnerabilities removes non-Red Hat VEX findings at or below the +// highest RHCC-marked ancestry layer. Findings above it are unchanged. +func filterRedHatLayerVulnerabilities(report *v4.VulnerabilityReport, layerSHAToIndex map[string]int32) { + contents := report.GetContents() + if len(layerSHAToIndex) == 0 || contents == nil { + return + } + + packages := packagesByID(contents) + maxLayerIdx := int32(-1) + for pkgID, pkg := range packages { + if pkg == nil || pkg.GetKind() != "ancestry" || !packageHasRepositoryKey(report, pkgID, rhcc.RepositoryKey) { + continue + } + layerIdx, ok := getPackageLayerIndex(report, layerSHAToIndex, pkgID) + if !ok { + continue + } + if layerIdx > maxLayerIdx { + maxLayerIdx = layerIdx + } + } + if maxLayerIdx < 0 { + return + } + + for pkgID, vulnIDs := range report.GetPackageVulnerabilities() { + pkgLayerIdx, ok := getPackageLayerIndex(report, layerSHAToIndex, pkgID) + if !ok || pkgLayerIdx > maxLayerIdx { + continue + } + filtered := make([]string, 0, len(vulnIDs.GetValues())) + for _, vulnID := range vulnIDs.GetValues() { + if report.GetVulnerabilities()[vulnID].GetUpdater() == redHatVEXUpdaterName { + filtered = append(filtered, vulnID) + } + } + if len(filtered) == 0 { + delete(report.PackageVulnerabilities, pkgID) //nolint:protogetter // mutation requires direct field access + } else { + report.PackageVulnerabilities[pkgID] = &v4.StringList{Values: filtered} + } + } +} + // filterNotAffectedVulnerabilities removes vulnerabilities from PackageVulnerabilities // when they are covered by VEX not-affected assertions via AncestryPackage entries. // A package is covered if it was introduced at or below the AncestryPackage's layer @@ -661,14 +723,7 @@ func filterNotAffectedVulnerabilities(report *v4.VulnerabilityReport, layerSHATo // PackageVulnerabilities when a rhel-vex updater vulnerability shares a // CVE alias at or above the OSV package's layer. func filterOSVSupersededByRedHatVEX(report *v4.VulnerabilityReport, layerSHAToIndex map[string]int32) { - const ( - osvUpdaterPrefix = "osv/" - redHatVEXUpdaterName = "rhel-vex" - // redHatContainerRepositoryKey matches - // github.com/quay/claircore/rhel/rhcc.RepositoryKey: it is set on - // every Repository indexed by claircore's RHCC (container) ecosystem. - redHatContainerRepositoryKey = "rhcc-container-repository" - ) + const osvUpdaterPrefix = "osv/" if len(report.GetPackageVulnerabilities()) == 0 { return @@ -679,7 +734,7 @@ func filterOSVSupersededByRedHatVEX(report *v4.VulnerabilityReport, layerSHAToIn aliasKeyToLayerIndex := make(map[string]int32) for pkgID, vulnIDs := range report.GetPackageVulnerabilities() { // Only consider OCI (RHCC) packages. - if !packageHasRepositoryKey(report, pkgID, redHatContainerRepositoryKey) { + if !packageHasRepositoryKey(report, pkgID, rhcc.RepositoryKey) { continue } diff --git a/pkg/scanners/scannerv4/convert_test.go b/pkg/scanners/scannerv4/convert_test.go index 9ad37ca82d9b2..98c6964be66b9 100644 --- a/pkg/scanners/scannerv4/convert_test.go +++ b/pkg/scanners/scannerv4/convert_test.go @@ -1847,6 +1847,177 @@ func TestNotes(t *testing.T) { } } +func TestFilterRedHatLayerVulnerabilities(t *testing.T) { + layers := map[string]int32{ + "base": 0, "rh-base": 1, "middle": 2, "rh-top": 3, "user": 4, + } + newReport := func() *v4.VulnerabilityReport { + packages := map[string]*v4.Package{} + environments := map[string]*v4.Environment_List{} + pkgVulns := map[string]*v4.StringList{} + for layer := range layers { + packages[layer] = &v4.Package{Id: layer, Kind: "binary"} + environments[layer] = &v4.Environment_List{Environments: []*v4.Environment{{IntroducedIn: layer}}} + pkgVulns[layer] = &v4.StringList{Values: []string{"osv", "redhat"}} + } + // These layers have only OSV findings. + pkgVulns["base"] = &v4.StringList{Values: []string{"osv"}} + pkgVulns["middle"] = &v4.StringList{Values: []string{"osv"}} + for _, layer := range []string{"rh-base", "rh-top"} { + id := layer + "-ancestry" + packages[id] = &v4.Package{Id: id, Kind: "ancestry"} + environments[id] = &v4.Environment_List{Environments: []*v4.Environment{{IntroducedIn: layer, RepositoryIds: []string{"rhcc"}}}} + } + return &v4.VulnerabilityReport{ + Contents: &v4.Contents{ + Packages: packages, + Repositories: map[string]*v4.Repository{"rhcc": {Key: "rhcc-container-repository"}}, + Environments: environments, + }, + Vulnerabilities: map[string]*v4.VulnerabilityReport_Vulnerability{ + "osv": {Updater: "osv/go"}, "redhat": {Updater: "rhel-vex"}, + }, + PackageVulnerabilities: pkgVulns, + } + } + + tests := map[string]struct { + prepare func(*v4.VulnerabilityReport) + indices map[string]int32 + filtered []string + }{ + "unmarked layer between Red Hat markers needs no VEX assertion": { + indices: layers, filtered: []string{"base", "rh-base", "middle", "rh-top"}, + }, + "single marker includes every lower layer": { + prepare: func(r *v4.VulnerabilityReport) { delete(r.GetContents().GetEnvironments(), "rh-top-ancestry") }, + indices: layers, filtered: []string{"base", "rh-base"}, + }, + "RHCC-marked binary above ancestry does not extend boundary": { + prepare: func(r *v4.VulnerabilityReport) { r.Contents.Packages["rh-top-ancestry"].Kind = "binary" }, + indices: layers, filtered: []string{"base", "rh-base"}, + }, + "RHCC-marked binaries without ancestry leave findings alone": { + prepare: func(r *v4.VulnerabilityReport) { + r.Contents.Packages["rh-base-ancestry"].Kind = "binary" + r.Contents.Packages["rh-top-ancestry"].Kind = "binary" + }, + indices: layers, + }, + "top marker includes unmarked lower layers": { + prepare: func(r *v4.VulnerabilityReport) { delete(r.GetContents().GetEnvironments(), "rh-base-ancestry") }, + indices: layers, filtered: []string{"base", "rh-base", "middle", "rh-top"}, + }, + "marker in layer zero": { + prepare: func(r *v4.VulnerabilityReport) { + delete(r.GetContents().GetEnvironments(), "rh-top-ancestry") + r.Contents.Environments["rh-base-ancestry"].Environments[0].IntroducedIn = "base" + }, + indices: layers, filtered: []string{"base"}, + }, + "legacy Gold Repository marker uses RHCC key": { + prepare: func(r *v4.VulnerabilityReport) { + r.Contents.Repositories["rhcc"] = &v4.Repository{ + Name: "Red Hat Container Catalog", + Uri: "https://catalog.redhat.com/software/containers/explore", + Key: "rhcc-container-repository", + } + }, + indices: layers, filtered: []string{"base", "rh-base", "middle", "rh-top"}, + }, + "no Red Hat marker leaves findings alone": { + prepare: func(r *v4.VulnerabilityReport) { + delete(r.GetContents().GetEnvironments(), "rh-base-ancestry") + delete(r.GetContents().GetEnvironments(), "rh-top-ancestry") + }, + indices: layers, + }, + "orphaned environments do not mark Red Hat layers": { + prepare: func(r *v4.VulnerabilityReport) { + delete(r.GetContents().GetPackages(), "rh-base-ancestry") + delete(r.GetContents().GetPackages(), "rh-top-ancestry") + }, + indices: layers, + }, + "deprecated environments retain the boundary": { + prepare: func(r *v4.VulnerabilityReport) { + for _, pkg := range r.GetContents().GetPackages() { + r.Contents.PackagesDEPRECATED = append(r.Contents.PackagesDEPRECATED, pkg) + } + r.Contents.Packages = nil + r.Contents.EnvironmentsDEPRECATED = r.GetContents().GetEnvironments() + r.Contents.Environments = nil + }, + indices: layers, filtered: []string{"base", "rh-base", "middle", "rh-top"}, + }, + "SBOM without image layer order leaves findings alone": { + indices: nil, + }, + } + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + report := newReport() + if tc.prepare != nil { + tc.prepare(report) + } + filterRedHatLayerVulnerabilities(report, tc.indices) + filtered := make(map[string]bool) + for _, layer := range tc.filtered { + filtered[layer] = true + } + for layer := range layers { + want := []string{"osv", "redhat"} + if layer == "base" || layer == "middle" { + want = []string{"osv"} + } + if filtered[layer] { + want = []string{"redhat"} + if layer == "base" || layer == "middle" { + want = nil + } + } + assert.Equal(t, want, report.GetPackageVulnerabilities()[layer].GetValues(), "layer %s", layer) + if want == nil { + assert.NotContains(t, report.GetPackageVulnerabilities(), layer) + } + } + }) + } +} + +func TestImageScanRedHatLayerFlag(t *testing.T) { + newReport := func() *v4.VulnerabilityReport { + return &v4.VulnerabilityReport{ + Contents: &v4.Contents{ + Packages: map[string]*v4.Package{ + "marker": {Kind: "ancestry"}, + "package": {Kind: "binary"}, + }, + Repositories: map[string]*v4.Repository{"rhcc": {Key: "rhcc-container-repository"}}, + Environments: map[string]*v4.Environment_List{ + "marker": {Environments: []*v4.Environment{{IntroducedIn: "layer", RepositoryIds: []string{"rhcc"}}}}, + "package": {Environments: []*v4.Environment{{IntroducedIn: "layer"}}}, + }, + }, + Vulnerabilities: map[string]*v4.VulnerabilityReport_Vulnerability{"osv": {Updater: "osv/go"}}, + PackageVulnerabilities: map[string]*v4.StringList{"package": {Values: []string{"osv"}}}, + } + } + metadata := &storage.ImageMetadata{ + V1: &storage.V1Metadata{Layers: []*storage.ImageLayer{{}}}, + LayerShas: []string{"layer"}, + } + + testutils.MustUpdateFeature(t, features.ScannerV4RedHatLayers, true) + imageReport := newReport() + imageScan(metadata, imageReport, scannerVersion) + assert.Empty(t, imageReport.GetPackageVulnerabilities()) + + sbomReport := newReport() + imageScan(nil, sbomReport, scannerVersion) + assert.Equal(t, []string{"osv"}, sbomReport.GetPackageVulnerabilities()["package"].GetValues()) +} + func TestFilterNotAffectedVulnerabilities(t *testing.T) { // Layer SHAs for test scenarios: // layer0 (index 0) - base layer diff --git a/pkg/scanners/scannerv4/nodescan_convert.go b/pkg/scanners/scannerv4/nodescan_convert.go index ade2eb0b28650..307e7f5ae4d41 100644 --- a/pkg/scanners/scannerv4/nodescan_convert.go +++ b/pkg/scanners/scannerv4/nodescan_convert.go @@ -13,7 +13,8 @@ import ( ) var ( - rhcosOSImageRegexp = regexp.MustCompile(`(Red Hat Enterprise Linux) (CoreOS) ([\d])([\d]+)`) + rhcosOSImageRegexp = regexp.MustCompile(`Red Hat Enterprise Linux CoreOS (4)(\d+)`) + rhcosDottedOSImageRegexp = regexp.MustCompile(`Red Hat Enterprise Linux CoreOS (\d+)\.(\d+)\b`) ) const ( @@ -40,21 +41,18 @@ func toNodeScan(r *v4.VulnerabilityReport, osImageRef string) *storage.NodeScan func toOperatingSystem(ref string) string { r := rhcosOSImageRegexp.FindStringSubmatch(ref) - if len(r) != 5 { - return "" + if len(r) == 3 { + return fmt.Sprintf("rhcos:%s.%s", r[1], r[2]) } - return fmt.Sprintf("rhcos:%s.%s", r[3], r[4]) + r = rhcosDottedOSImageRegexp.FindStringSubmatch(ref) + if len(r) == 3 { + return fmt.Sprintf("rhcos:%s.%s", r[1], r[2]) + } + return "" } func toStorageComponents(r *v4.VulnerabilityReport) []*storage.EmbeddedNodeScanComponent { - packages := r.GetContents().GetPackages() - if len(packages) == 0 { - packages = make(map[string]*v4.Package, len(r.GetContents().GetPackagesDEPRECATED())) - // Fallback to the deprecated slice, if needed. - for _, pkg := range r.GetContents().GetPackagesDEPRECATED() { - packages[pkg.GetId()] = pkg - } - } + packages := packagesByID(r.GetContents()) result := make([]*storage.EmbeddedNodeScanComponent, 0, len(packages)) for id, pkg := range packages { diff --git a/pkg/scanners/scannerv4/nodescan_convert_test.go b/pkg/scanners/scannerv4/nodescan_convert_test.go index f7d5417209736..220503b4efe7b 100644 --- a/pkg/scanners/scannerv4/nodescan_convert_test.go +++ b/pkg/scanners/scannerv4/nodescan_convert_test.go @@ -251,6 +251,26 @@ func (s *indexReportConvertSuite) TestToOperatingSystem() { in: "Red Hat Enterprise Linux CoreOS 41712345.94.2024", expected: "rhcos:4.1712345", }, + "legacy single-digit minor version": { + in: "Red Hat Enterprise Linux CoreOS 41.84.201907030753-0", + expected: "rhcos:4.1", + }, + "RHCOS 9.6 (OCP 4.19)": { + in: "Red Hat Enterprise Linux CoreOS 9.6.20250701-0 (Plow)", + expected: "rhcos:9.6", + }, + "RHCOS 9.8": { + in: "Red Hat Enterprise Linux CoreOS 9.8.20260908-0 (Plow)", + expected: "rhcos:9.8", + }, + "RHCOS 10.1": { + in: "Red Hat Enterprise Linux CoreOS 10.1.20260908-0 (Plow)", + expected: "rhcos:10.1", + }, + "RHCOS dotted version without build suffix": { + in: "Red Hat Enterprise Linux CoreOS 9.8 (Plow)", + expected: "rhcos:9.8", + }, "non-RHCOS": { in: "Oracle Linux Server release 6.8", expected: "", diff --git a/pkg/scanners/scannerv4/scannerv4.go b/pkg/scanners/scannerv4/scannerv4.go index cacecd18c1c7e..d34ed5f24e05d 100644 --- a/pkg/scanners/scannerv4/scannerv4.go +++ b/pkg/scanners/scannerv4/scannerv4.go @@ -1,6 +1,7 @@ package scannerv4 import ( + "cmp" "context" "fmt" "io" @@ -393,14 +394,15 @@ func (s *scannerv4) GetVirtualMachineScan( if indexReport == nil { return nil, errors.New("index report is required for VM scanning") } + vmLabel := cmp.Or(vm.GetName(), vm.GetId()) vmDigest, err := name.NewDigest(mockVirtualMachineDigest) if err != nil { - return nil, errors.Wrapf(err, "failed to parse digest for VM %q", vm.GetName()) + return nil, errors.Wrapf(err, "failed to parse digest for VM %q", vmLabel) } vr, err := s.getVulnerabilityReport(vmDigest, indexReport) if err != nil { - return nil, errors.Wrapf(err, "failed to get vulnerability report for VM %q", vm.GetName()) + return nil, errors.Wrapf(err, "failed to get vulnerability report for VM %q", vmLabel) } return ToVirtualMachineScan(vr), nil diff --git a/pkg/scanners/scannerv4/scannerv4_test.go b/pkg/scanners/scannerv4/scannerv4_test.go index e3c07abd56b03..c73b8bf5c026e 100644 --- a/pkg/scanners/scannerv4/scannerv4_test.go +++ b/pkg/scanners/scannerv4/scannerv4_test.go @@ -585,6 +585,21 @@ func TestGetVirtualMachineScan_Timeout(t *testing.T) { assert.Nil(t, scan) } +func TestGetVirtualMachineScan_EmptyNameUsesID(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockClient := s4ClientMocks.NewMockScanner(ctrl) + mockClient.EXPECT().GetVulnerabilities(gomock.Any(), gomock.Any(), gomock.Any()). + Return(nil, errors.New("scanner service unavailable")) + + scanner := &scannerv4{scannerClient: mockClient} + scan, err := scanner.GetVirtualMachineScan(&storage.VirtualMachine{Id: "vm-id"}, &v4.IndexReport{Contents: &v4.Contents{}}) + require.Error(t, err) + assert.Contains(t, err.Error(), `failed to get vulnerability report for VM "vm-id"`) + assert.Nil(t, scan) +} + func TestNewVirtualMachineScanner(t *testing.T) { t.Run("successful creation", func(it *testing.T) { ctrl := gomock.NewController(t) diff --git a/pkg/scanners/scannerv4/vm_convert.go b/pkg/scanners/scannerv4/vm_convert.go index 7c8a553bd72fc..93042ef3713b3 100644 --- a/pkg/scanners/scannerv4/vm_convert.go +++ b/pkg/scanners/scannerv4/vm_convert.go @@ -53,13 +53,7 @@ func hasValidCPE(repositories map[string]*v4.Repository, environments map[string func toVirtualMachineComponents(r *v4.VulnerabilityReport) []*storage.EmbeddedVirtualMachineScanComponent { repositories := r.GetContents().GetRepositories() environments := r.GetContents().GetEnvironments() - packages := r.GetContents().GetPackages() - if len(packages) == 0 { - packages = make(map[string]*v4.Package, len(r.GetContents().GetPackagesDEPRECATED())) - for _, pkg := range r.GetContents().GetPackagesDEPRECATED() { - packages[pkg.GetId()] = pkg - } - } + packages := packagesByID(r.GetContents()) result := make([]*storage.EmbeddedVirtualMachineScanComponent, 0, len(packages)) for id, pkg := range packages { vulnerabilityIDs := r.GetPackageVulnerabilities()[id].GetValues() diff --git a/pkg/scannerv4/mappers/mappers.go b/pkg/scannerv4/mappers/mappers.go index 2476267e13547..78df19c2148ca 100644 --- a/pkg/scannerv4/mappers/mappers.go +++ b/pkg/scannerv4/mappers/mappers.go @@ -19,7 +19,6 @@ import ( "github.com/quay/claircore" "github.com/quay/claircore/enricher/epss" "github.com/quay/claircore/enricher/kev" - "github.com/quay/claircore/rhel/rhcc" "github.com/quay/claircore/rhel/vex" "github.com/quay/claircore/toolkit/types" "github.com/quay/claircore/toolkit/types/cpe" @@ -45,6 +44,11 @@ const ( redhatErrataURLPrefix = "https://access.redhat.com/errata/" rhelRepositoryKey = "rhel-cpe-repository" + + // unsetCPE is the bound form of an unset CPE. Every released StackRox + // component emits and accepts this form, so keep it on the wire instead of + // the empty string ClairCore now produces for unset CPEs. + unsetCPE = "cpe:2.3:*:*:*:*:*:*:*:*:*:*:*" ) var ( @@ -86,13 +90,6 @@ var ( // Catchall regexp.MustCompile(`[A-Z]+-\d{4}[-:]\d+`), } - - // vexUpdater is the name of the Red Hat VEX updater used by Claircore. - vexUpdater = (*vex.Updater)(nil).Name() - // rhccRepoName is the name of the "Gold Repository". - rhccRepoName = rhcc.GoldRepo.Name - // rhccRepoURI is the URI of the "Gold Repository". - rhccRepoURI = rhcc.GoldRepo.URI ) // ToProtoV4IndexReport maps claircore.IndexReport to v4.IndexReport. @@ -118,7 +115,6 @@ func ToProtoV4VulnerabilityReport(ctx context.Context, r *claircore.Vulnerabilit return nil, nil } filterPackages(r) - filterVulnerabilities(r) nvdVulns, err := nvdVulnerabilities(r.Enrichments) if err != nil { return nil, fmt.Errorf("internal error: parsing nvd vulns: %w", err) @@ -257,6 +253,10 @@ func v4Package(p *claircore.Package) (*v4.Package, error) { if err != nil { return nil, err } + cpeStr, err := toCPEString(p.CPE) + if err != nil { + return nil, fmt.Errorf("package %q: %w", p.ID, err) + } return &v4.Package{ Id: p.ID, Name: p.Name, @@ -268,7 +268,7 @@ func v4Package(p *claircore.Package) (*v4.Package, error) { RepositoryHint: p.RepositoryHint, Module: p.Module, Arch: p.Arch, - Cpe: toCPEString(p.CPE), + Cpe: cpeStr, }, nil } @@ -322,6 +322,10 @@ func v4Distribution(d *claircore.Distribution) (*v4.Distribution, error) { if d == nil { return nil, nil } + cpeStr, err := toCPEString(d.CPE) + if err != nil { + return nil, fmt.Errorf("distribution %q: %w", d.ID, err) + } return &v4.Distribution{ Id: d.ID, Did: d.DID, @@ -330,7 +334,7 @@ func v4Distribution(d *claircore.Distribution) (*v4.Distribution, error) { VersionCodeName: d.VersionCodeName, VersionId: VersionID(d), Arch: d.Arch, - Cpe: toCPEString(d.CPE), + Cpe: cpeStr, PrettyName: d.PrettyName, }, nil } @@ -339,12 +343,16 @@ func v4Repository(r *claircore.Repository) (*v4.Repository, error) { if r == nil { return nil, nil } + cpeStr, err := toCPEString(r.CPE) + if err != nil { + return nil, fmt.Errorf("repository %q: %w", r.ID, err) + } return &v4.Repository{ Id: r.ID, Name: r.Name, Key: r.Key, Uri: r.URI, - Cpe: toCPEString(r.CPE), + Cpe: cpeStr, }, nil } @@ -825,8 +833,15 @@ func toPackageKind(s string) types.PackageKind { return k } -func toCPEString(c cpe.WFN) string { - return c.BindFS() +func toCPEString(c cpe.WFN) (string, error) { + if errors.Is(c.Valid(), cpe.ErrUnset) { + return unsetCPE, nil + } + b, err := c.AppendText(nil) + if err != nil { + return "", err + } + return string(b), nil } func toDigestString(digest claircore.Digest) string { @@ -834,6 +849,9 @@ func toDigestString(digest claircore.Digest) string { } func toClairCoreCPE(s string) (cpe.WFN, error) { + if s == "" { + return cpe.WFN{}, nil + } c, err := cpe.Unbind(s) if err != nil { return c, fmt.Errorf("%q: %s", s, strings.TrimPrefix(err.Error(), "cpe: ")) @@ -1150,106 +1168,6 @@ func filterPackages(report *claircore.VulnerabilityReport) { } } -// filterVulnerabilities filters out vulnerabilities from the given vulnerability report. -// Note: This function only modifies the report's PackageVulnerabilities map. -// It is non-trivial to remove all unreferenced vulnerabilities from the report's -// Vulnerabilities map, so we leave it untouched and accept we may send Scanner V4 clients -// extra vulnerabilities. It is up to the client to handle this. -func filterVulnerabilities(report *claircore.VulnerabilityReport) { - // We only filter out non-Red Hat vulnerabilities found in Red Hat layers (if configured to do so) at this time. - if !features.ScannerV4RedHatLayers.Enabled() { - return - } - - redhatLayers := rhccLayers(report) - if redhatLayers.IsEmpty() { - // This image is neither an official Red Hat image nor based on one, so nothing to do here. - return - } - for pkgID, pkg := range report.Packages { - // Sanity check. - if pkg == nil { - continue - } - - envs, found := report.Environments[pkgID] - if !found { - // Did not find a related environment, so we cannot determine the layer. - continue - } - - // Just use the first environment. - // It is possible there are multiple environments associated with this package; - // however, for our purposes, we only need the first one, - // as the layer index will always be the same between different environments. - // Quay does this, too: https://github.com/quay/quay/blob/v3.10.3/data/secscan_model/secscan_v4_model.py#L583. - // We also do this in our own client code. - env := envs[0] - // If this package was introduced in a non-Red Hat layer, skip it. - if !redhatLayers.Contains(env.IntroducedIn.String()) { - continue - } - - var n int - for _, vulnID := range report.PackageVulnerabilities[pkgID] { - vuln := report.Vulnerabilities[vulnID] - // Sanity check. - if vuln == nil { - continue - } - - // If the vulnerability did not come from Red Hat's VEX data, then skip it. - if vuln.Updater != vexUpdater { - continue - } - - report.PackageVulnerabilities[pkgID][n] = vulnID - n++ - } - - // Hint to the GC the filtered vulnerabilities are no longer needed. - clear(report.PackageVulnerabilities[pkgID][n:]) - report.PackageVulnerabilities[pkgID] = report.PackageVulnerabilities[pkgID][:n:n] - - // If there aren't any vulnerabilities from Red Hat's VEX data, - // then delete the whole entry. - if n == 0 { - delete(report.PackageVulnerabilities, pkgID) - } - } -} - -// rhccLayers returns a set of SHAs for the layers in official Red Hat images. -// TODO(ROX-29158): account for images built via Konflux, as they do not contain the same identifiers -// as the old build system. -func rhccLayers(report *claircore.VulnerabilityReport) set.FrozenStringSet { - layers := set.NewStringSet() - - var rhccID string - for id, repo := range report.Repositories { - if repo.Name == rhccRepoName && repo.URI == rhccRepoURI { - rhccID = id - break - } - } - if rhccID == "" { - // Not an official Red Hat image nor based on one. - return layers.Freeze() - } - - for _, envs := range report.Environments { - for _, env := range envs { - for _, repoID := range env.RepositoryIDs { - if repoID == rhccID { - layers.Add(env.IntroducedIn.String()) - } - } - } - } - - return layers.Freeze() -} - // pkgFixedBy unmarshals and returns the package-fixed-by enrichment, if it exists. func pkgFixedBy(enrichments map[string][]json.RawMessage) (map[string]string, error) { enrichmentsList := enrichments[fixedby.Type] diff --git a/pkg/scannerv4/mappers/mappers_test.go b/pkg/scannerv4/mappers/mappers_test.go index 23916fe6fd0c1..e46084b043fb4 100644 --- a/pkg/scannerv4/mappers/mappers_test.go +++ b/pkg/scannerv4/mappers/mappers_test.go @@ -2,8 +2,7 @@ package mappers import ( "encoding/json" - "slices" - "strings" + "strconv" "testing" "time" @@ -470,361 +469,6 @@ func Test_ToProtoV4VulnerabilityReport_FilterNodeJS(t *testing.T) { } } -func TestToProtoV4VulnerabilityReport_FilterRHCCLayers(t *testing.T) { - testutils.MustUpdateFeature(t, features.ScannerV4RedHatLayers, true) - - layerA := claircore.MustParseDigest("sha256:" + strings.Repeat("a", 64)) - layerB := claircore.MustParseDigest("sha256:" + strings.Repeat("b", 64)) - - tests := map[string]struct { - arg *claircore.VulnerabilityReport - want *v4.VulnerabilityReport - wantErr string - }{ - "filter non-RPM packages in Red Hat layers": { - arg: &claircore.VulnerabilityReport{ - Hash: claircore.MustParseDigest("sha256:9124cd5256c6d674f6b11a4d01fea8148259be1f66ca2cf9dfbaafc83c31874e"), - Vulnerabilities: map[string]*claircore.Vulnerability{ - "0": { - ID: "0", - Name: "0", - Updater: "rhel-vex", - }, - "1": { - ID: "1", - Name: "1", - Updater: "rhel-vex", - }, - "2": { - ID: "2", - Name: "2", - Updater: "something else", - }, - "3": { - ID: "3", - Name: "3", - Updater: "something different", - }, - }, - Packages: map[string]*claircore.Package{ - "0": { - ID: "0", - Name: "my go binary", - Version: "0", - }, - "1": { - ID: "1", - Name: "my java jar", - Version: "1", - }, - "2": { - ID: "2", - Name: "my python egg", - Version: "2", - }, - "3": { - ID: "3", - Name: "my ruby gem", - Version: "3", - }, - }, - Repositories: map[string]*claircore.Repository{ - "0": { - ID: "0", - Name: "Red Hat Container Catalog", - URI: `https://catalog.redhat.com/software/containers/explore`, - }, - "something else": { - ID: "1", - Name: "something else", - Key: "rhel-cpe-repository", - URI: "somethingelse.com", - }, - }, - Environments: map[string][]*claircore.Environment{ - "0": { - { - RepositoryIDs: []string{"0", "something else"}, - IntroducedIn: layerA, - }, - }, - "1": { - { - RepositoryIDs: []string{"something else"}, - IntroducedIn: layerB, - }, - }, - "2": { - { - RepositoryIDs: []string{"0"}, - IntroducedIn: layerA, - }, - }, - "3": { - { - RepositoryIDs: []string{"something else"}, - IntroducedIn: layerB, - }, - }, - }, - PackageVulnerabilities: map[string][]string{ - "0": {"2", "0", "3", "1"}, - "1": {"1", "2"}, - "2": {"2", "3"}, - "3": {"0", "1", "2", "3"}, - }, - }, - want: &v4.VulnerabilityReport{ - // Converter doesn't set HashId to empty. - HashId: "", - Vulnerabilities: map[string]*v4.VulnerabilityReport_Vulnerability{ - "0": { - Id: "0", - Name: "0", - Updater: "rhel-vex", - }, - "1": { - Id: "1", - Name: "1", - Updater: "rhel-vex", - }, - "2": { - Id: "2", - Name: "2", - Updater: "something else", - }, - "3": { - Id: "3", - Name: "3", - Updater: "something different", - }, - }, - PackageVulnerabilities: map[string]*v4.StringList{ - "0": { - Values: []string{"0", "1"}, - }, - "1": { - Values: []string{"1", "2"}, - }, - "3": { - Values: []string{"0", "1", "2", "3"}, - }, - }, - Contents: &v4.Contents{ - Packages: map[string]*v4.Package{ - "0": { - Id: "0", - Name: "my go binary", - Version: "0", - NormalizedVersion: &v4.NormalizedVersion{ - V: []int32{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - }, - Kind: "unknown", - Cpe: emptyCPE, - }, - "1": { - Id: "1", - Name: "my java jar", - Version: "1", - NormalizedVersion: &v4.NormalizedVersion{ - V: []int32{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - }, - Kind: "unknown", - Cpe: emptyCPE, - }, - "2": { - Id: "2", - Name: "my python egg", - Version: "2", - NormalizedVersion: &v4.NormalizedVersion{ - V: []int32{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - }, - Kind: "unknown", - Cpe: emptyCPE, - }, - "3": { - Id: "3", - Name: "my ruby gem", - Version: "3", - NormalizedVersion: &v4.NormalizedVersion{ - V: []int32{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - }, - Kind: "unknown", - Cpe: emptyCPE, - }, - }, - PackagesDEPRECATED: []*v4.Package{ - { - Id: "0", - Name: "my go binary", - Version: "0", - NormalizedVersion: &v4.NormalizedVersion{ - V: []int32{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - }, - Kind: "unknown", - Cpe: emptyCPE, - }, - { - Id: "1", - Name: "my java jar", - Version: "1", - NormalizedVersion: &v4.NormalizedVersion{ - V: []int32{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - }, - Kind: "unknown", - Cpe: emptyCPE, - }, - { - Id: "2", - Name: "my python egg", - Version: "2", - NormalizedVersion: &v4.NormalizedVersion{ - V: []int32{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - }, - Kind: "unknown", - Cpe: emptyCPE, - }, - { - Id: "3", - Name: "my ruby gem", - Version: "3", - NormalizedVersion: &v4.NormalizedVersion{ - V: []int32{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - }, - Kind: "unknown", - Cpe: emptyCPE, - }, - }, - Repositories: map[string]*v4.Repository{ - "0": { - Id: "0", - Name: "Red Hat Container Catalog", - Uri: `https://catalog.redhat.com/software/containers/explore`, - Cpe: emptyCPE, - }, - "something else": { - Id: "1", - Name: "something else", - Key: "rhel-cpe-repository", - Uri: "somethingelse.com", - Cpe: emptyCPE, - }, - }, - RepositoriesDEPRECATED: []*v4.Repository{ - { - Id: "0", - Name: "Red Hat Container Catalog", - Uri: `https://catalog.redhat.com/software/containers/explore`, - Cpe: emptyCPE, - }, - { - Id: "1", - Name: "something else", - Key: "rhel-cpe-repository", - Uri: "somethingelse.com", - Cpe: emptyCPE, - }, - }, - Environments: map[string]*v4.Environment_List{ - "0": { - Environments: []*v4.Environment{ - { - RepositoryIds: []string{"0", "something else"}, - IntroducedIn: layerA.String(), - }, - }, - }, - "1": { - Environments: []*v4.Environment{ - { - RepositoryIds: []string{"something else"}, - IntroducedIn: layerB.String(), - }, - }, - }, - "2": { - Environments: []*v4.Environment{ - { - RepositoryIds: []string{"0"}, - IntroducedIn: layerA.String(), - }, - }, - }, - "3": { - Environments: []*v4.Environment{ - { - RepositoryIds: []string{"something else"}, - IntroducedIn: layerB.String(), - }, - }, - }, - }, - EnvironmentsDEPRECATED: map[string]*v4.Environment_List{ - "0": { - Environments: []*v4.Environment{ - { - RepositoryIds: []string{"0", "1"}, - IntroducedIn: layerA.String(), - }, - }, - }, - "1": { - Environments: []*v4.Environment{ - { - RepositoryIds: []string{"1"}, - IntroducedIn: layerB.String(), - }, - }, - }, - "2": { - Environments: []*v4.Environment{ - { - RepositoryIds: []string{"0"}, - IntroducedIn: layerA.String(), - }, - }, - }, - "3": { - Environments: []*v4.Environment{ - { - RepositoryIds: []string{"1"}, - IntroducedIn: layerB.String(), - }, - }, - }, - }, - }, - }, - wantErr: "", - }, - } - for name, tt := range tests { - t.Run(name, func(t *testing.T) { - ctx := test.Logging(t) - got, err := ToProtoV4VulnerabilityReport(ctx, tt.arg) - if tt.wantErr != "" { - assert.ErrorContains(t, err, tt.wantErr) - return - } - assert.NoError(t, err) - - // The assert library cannot compare elements in slices like the ones below - // while ignoring order. So, sort each slice. - for _, pkgVulns := range got.GetPackageVulnerabilities() { - slices.Sort(pkgVulns.GetValues()) - } - slices.SortFunc(got.GetContents().GetPackagesDEPRECATED(), func(a, b *v4.Package) int { - return strings.Compare(a.GetId(), b.GetId()) - }) - slices.SortFunc(got.GetContents().GetRepositoriesDEPRECATED(), func(a, b *v4.Repository) int { - return strings.Compare(a.GetId(), b.GetId()) - }) - - protoassert.Equal(t, tt.want, got) - }) - } -} - func Test_ToClairCoreIndexReport(t *testing.T) { tests := map[string]struct { arg *v4.Contents @@ -1062,6 +706,28 @@ func Test_ToClairCoreIndexReport(t *testing.T) { } } +func TestDeprecatedIndexContentsBecomeCurrentVulnerabilityContents(t *testing.T) { + const layerSHA = "sha256:9124cd5256c6d674f6b11a4d01fea8148259be1f66ca2cf9dfbaafc83c31874e" + index, err := ToClairCoreIndexReport(&v4.Contents{ + PackagesDEPRECATED: []*v4.Package{{Id: "marker", Name: "image", Kind: "ancestry"}}, + RepositoriesDEPRECATED: []*v4.Repository{{Id: "rhcc", Key: "rhcc-container-repository"}}, + EnvironmentsDEPRECATED: map[string]*v4.Environment_List{ + "marker": {Environments: []*v4.Environment{{IntroducedIn: layerSHA, RepositoryIds: []string{"rhcc"}}}}, + }, + }) + require.NoError(t, err) + + report, err := ToProtoV4VulnerabilityReport(test.Logging(t), &claircore.VulnerabilityReport{ + Packages: index.Packages, + Repositories: index.Repositories, + Environments: index.Environments, + }) + require.NoError(t, err) + require.Contains(t, report.GetContents().GetPackages(), "marker") + require.Equal(t, "rhcc-container-repository", report.GetContents().GetRepositories()["rhcc"].GetKey()) + require.Equal(t, layerSHA, report.GetContents().GetEnvironments()["marker"].GetEnvironments()[0].GetIntroducedIn()) +} + func Test_toProtoV4Package(t *testing.T) { tests := []struct { name string @@ -3261,3 +2927,97 @@ func Test_PackageKindRoundTrip(t *testing.T) { }) } } + +func Test_toCPEString(t *testing.T) { + tests := []struct { + name string + arg cpe.WFN + want string + wantErr string + }{ + { + name: "when zero value then wildcard", + arg: cpe.WFN{}, + want: emptyCPE, + }, + { + name: "when wildcard then wildcard", + arg: cpe.MustUnbind(emptyCPE), + want: emptyCPE, + }, + { + name: "when set then bound", + arg: cpe.MustUnbind("cpe:/a:redhat:openshift:4.12::el8"), + want: "cpe:2.3:a:redhat:openshift:4.12:*:el8:*:*:*:*:*", + }, + { + name: "when invalid then error", + arg: cpe.WFN{Attr: [cpe.NumAttr]cpe.Value{cpe.Part: {Kind: cpe.ValueSet, V: "x"}}}, + wantErr: "disallowed value", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := toCPEString(tt.arg) + if tt.wantErr != "" { + assert.ErrorContains(t, err, tt.wantErr) + return + } + require.NoError(t, err) + assert.Equal(t, tt.want, got) + }) + } +} + +func Test_toClairCoreCPE(t *testing.T) { + tests := []struct { + name string + arg string + want cpe.WFN + wantErr string + }{ + { + name: "when empty then zero value", + arg: "", + want: cpe.WFN{}, + }, + { + name: "when wildcard then no error", + arg: emptyCPE, + want: cpe.MustUnbind(emptyCPE), + }, + { + name: "when set then unbound", + arg: "cpe:2.3:a:redhat:openshift:4.12:*:el8:*:*:*:*:*", + want: cpe.MustUnbind("cpe:2.3:a:redhat:openshift:4.12:*:el8:*:*:*:*:*"), + }, + { + name: "when invalid then error", + arg: "not a cpe", + wantErr: `"not a cpe": `, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := toClairCoreCPE(tt.arg) + if tt.wantErr != "" { + assert.ErrorContains(t, err, tt.wantErr) + return + } + require.NoError(t, err) + assert.Equal(t, tt.want, got) + }) + } +} + +func Test_CPERoundTrip(t *testing.T) { + for _, s := range []string{"", emptyCPE} { + t.Run("from "+strconv.Quote(s), func(t *testing.T) { + ccCPE, err := toClairCoreCPE(s) + require.NoError(t, err) + got, err := toCPEString(ccCPE) + require.NoError(t, err) + assert.Equal(t, emptyCPE, got) + }) + } +} diff --git a/pkg/search/predicate/base_predicates.go b/pkg/search/predicate/base_predicates.go index 1497c46ed3935..556695794f25e 100644 --- a/pkg/search/predicate/base_predicates.go +++ b/pkg/search/predicate/base_predicates.go @@ -38,7 +38,7 @@ func createBasePredicate(fullPath string, fieldType reflect.Type, value string) case reflect.Bool: return createBoolPredicate(fullPath, value) case reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8, reflect.Int: - if enum, ok := reflect.Zero(fieldType).Interface().(protoreflect.ProtoEnum); ok { + if enum, ok := reflect.TypeAssert[protoreflect.ProtoEnum](reflect.Zero(fieldType)); ok { return createEnumPredicate(fullPath, value, enum) } return createIntPredicate(fullPath, value) diff --git a/pkg/search/predicate/timestamp_predicate.go b/pkg/search/predicate/timestamp_predicate.go index 2dd98eb589f75..18aea5f5e070e 100644 --- a/pkg/search/predicate/timestamp_predicate.go +++ b/pkg/search/predicate/timestamp_predicate.go @@ -14,7 +14,7 @@ func createTimestampPredicate(fullPath, value string) (internalPredicate, error) return nil, err } return internalPredicateFunc(func(instance reflect.Value) (*search.Result, bool) { - instanceTS, ok := instance.Interface().(*protocompat.Timestamp) + instanceTS, ok := reflect.TypeAssert[*protocompat.Timestamp](instance) if ok && baseMatcher(instanceTS) { return &search.Result{ diff --git a/pkg/search/walker.go b/pkg/search/walker.go index 2a4a3df0e3571..0e6262a8617a5 100644 --- a/pkg/search/walker.go +++ b/pkg/search/walker.go @@ -137,7 +137,7 @@ func (s *searchWalker) walkRecursive(prefix string, original reflect.Type) v1.Se case reflect.Bool: return v1.SearchDataType_SEARCH_BOOL case reflect.Uint32, reflect.Uint64, reflect.Int32, reflect.Int64, reflect.Float32, reflect.Float64: - enum, ok := reflect.Zero(original).Interface().(protoreflect.ProtoEnum) + enum, ok := reflect.TypeAssert[protoreflect.ProtoEnum](reflect.Zero(original)) if !ok { return v1.SearchDataType_SEARCH_NUMERIC } diff --git a/pkg/signatures/cosign_sig_fetcher.go b/pkg/signatures/cosign_sig_fetcher.go index ae3ac21bffd84..468214b06e37b 100644 --- a/pkg/signatures/cosign_sig_fetcher.go +++ b/pkg/signatures/cosign_sig_fetcher.go @@ -121,12 +121,12 @@ func (c *cosignSignatureFetcher) FetchSignatures(ctx context.Context, image *sto if tagErr == nil { allPayloads = append(allPayloads, tagPayloads...) } else { - log.Warnf("Tag-based discovery failed for %q: %v", fullImageName, tagErr) + log.Debugf("Tag-based discovery failed for %q: %v", fullImageName, tagErr) } if referrerErr == nil { allPayloads = append(allPayloads, referrerPayloads...) } else { - log.Warnf("Referrer-based discovery failed for %q: %v", fullImageName, referrerErr) + log.Debugf("Referrer-based discovery failed for %q: %v", fullImageName, referrerErr) } // Return an error only when both discovery paths failed. diff --git a/pkg/telemetry/data/data_test.go b/pkg/telemetry/data/data_test.go index 1f9b94d47d909..2f8850001fe5b 100644 --- a/pkg/telemetry/data/data_test.go +++ b/pkg/telemetry/data/data_test.go @@ -26,7 +26,7 @@ func validateJSONFieldNames(t *testing.T, val reflect.Value) { validateJSONFieldNames(t, val.Index(i)) } case reflect.Map: - m, ok := val.Interface().(map[string]interface{}) + m, ok := reflect.TypeAssert[map[string]interface{}](val) assert.True(t, ok) for mKey, mVal := range m { validateFieldName(t, mKey) diff --git a/pkg/telemetry/phonehome/campaign_test.go b/pkg/telemetry/phonehome/campaign_test.go index a56b5b8ce9aa2..b9a440febf3d1 100644 --- a/pkg/telemetry/phonehome/campaign_test.go +++ b/pkg/telemetry/phonehome/campaign_test.go @@ -408,7 +408,7 @@ func TestCompile(t *testing.T) { }, { criterion: *PathPattern("[b-a]"), - errorMessage: `error parsing path pattern: failed to compile "[b-a]": hi character 'a' should be greater than lo 'b'`, + errorMessage: `error parsing path pattern: failed to compile "[b-a]": glob: syntax error at 5: range hi character is less than lo`, }, } diff --git a/pkg/testutils/centralgrpc/connect_to_central.go b/pkg/testutils/centralgrpc/connect_to_central.go index ff46258b72862..ce5dc1408d8ea 100644 --- a/pkg/testutils/centralgrpc/connect_to_central.go +++ b/pkg/testutils/centralgrpc/connect_to_central.go @@ -72,7 +72,7 @@ func RoxAPIEndpoint(t testutils.T) string { // UnauthenticatedGRPCConnectionToCentral is like GRPCConnectionToCentral, // but does not inject credentials into the request. func UnauthenticatedGRPCConnectionToCentral(t *testing.T) *grpc.ClientConn { - return grpcConnectionToCentral(t, nil) + return grpcConnectionToCentral(t) } // GRPCConnectionToCentral returns a GRPC connection to Central, which can be used in E2E tests. @@ -187,19 +187,31 @@ func grpcConnectionToCentral(t testutils.T, optsFuncs ...func(options *clientcon // HTTPClientForCentral returns an *http.Client for talking to central in tests. Basic auth credentials and // the hostname and scheme part of the URL may be omitted. func HTTPClientForCentral(t testutils.T) *http.Client { + user := RoxUsername(t) + pw := RoxPassword(t) + return newHTTPClientForCentral(t, user, pw) +} + +// UnauthenticatedHTTPClientForCentral is like HTTPClientForCentral but does not inject auth credentials. +// The hostname and scheme part of the URL may still be omitted. +func UnauthenticatedHTTPClientForCentral(t testutils.T) *http.Client { + return newHTTPClientForCentral(t, "", "") +} + +func newHTTPClientForCentral(t testutils.T, username, password string) *http.Client { baseTransport := &http.Transport{ TLSClientConfig: &tls.Config{ - InsecureSkipVerify: true, + InsecureSkipVerify: true, //#nosec G402 }, } endpoint := RoxAPIEndpoint(t) - user := RoxUsername(t) - pw := RoxPassword(t) transport := httputil.RoundTripperFunc(func(req *http.Request) (*http.Response, error) { modReq := req.Clone(req.Context()) - modReq.SetBasicAuth(user, pw) + if username != "" || password != "" { + modReq.SetBasicAuth(username, password) + } if modReq.URL.Host == "" { modReq.URL.Host = endpoint } @@ -214,10 +226,8 @@ func HTTPClientForCentral(t testutils.T) *http.Client { return resp, nil }) - client := &http.Client{ + return &http.Client{ Timeout: 10 * time.Second, Transport: transport, } - - return client } diff --git a/pkg/version/internal/version_data.go b/pkg/version/internal/version_data.go index 47b7af84355c7..c8ef4634e58b3 100644 --- a/pkg/version/internal/version_data.go +++ b/pkg/version/internal/version_data.go @@ -7,8 +7,6 @@ var ( CollectorVersion string //XDef:STABLE_COLLECTOR_VERSION // FactVersion is the fact version to be used by default. FactVersion string //XDef:STABLE_FACT_VERSION - // ScannerVersion is the scanner version to be used with this Rox version. - ScannerVersion string //XDef:STABLE_SCANNER_VERSION // GitShortSha is the (short) Git SHA that was built. GitShortSha string //XDef:STABLE_GIT_SHORT_SHA ) diff --git a/pkg/version/testutils/set_version.go b/pkg/version/testutils/set_version.go index c96d48d340927..d5fc6b65bd29a 100644 --- a/pkg/version/testutils/set_version.go +++ b/pkg/version/testutils/set_version.go @@ -31,7 +31,6 @@ func SetExampleVersion(t *testing.T) { func SetVersion(t *testing.T, version version.Versions) { testutils.MustBeInTest(t) internal.MainVersion = version.MainVersion - internal.ScannerVersion = version.ScannerVersion internal.CollectorVersion = version.CollectorVersion internal.GitShortSha = version.GitCommit internal.FactVersion = version.FactVersion @@ -46,7 +45,6 @@ func GetExampleVersion(t *testing.T) version.Versions { GoVersion: runtime.Version(), MainVersion: "3.0.99.0", Platform: runtime.GOOS + "/" + runtime.GOARCH, - ScannerVersion: "99.9.9", ChartVersion: "3.99.0", FactVersion: "0.1.0", } diff --git a/pkg/version/version.go b/pkg/version/version.go index 214224773b35b..01c284ceb722e 100644 --- a/pkg/version/version.go +++ b/pkg/version/version.go @@ -51,11 +51,7 @@ type Versions struct { GoVersion string `json:"GoVersion"` MainVersion string `json:"MainVersion"` Platform string `json:"Platform"` - // ScannerVersion is exported for compatibility with users that depend on `roxctl version --json` output. - // Please do not depend on it. Rely on internal.ScannerVersion if you need the value from the SCANNER_VERSION file, - // or rely on defaults.ImageFlavor if you need a default collector image tag. - ScannerVersion string `json:"ScannerVersion"` - ChartVersion string `json:"ChartVersion"` + ChartVersion string `json:"ChartVersion"` // The Database versioning needs to be added by the caller due to scoping issues of config availabilty Database string `json:"Database,omitempty"` DatabaseServerVersion string `json:"DatabaseServerVersion,omitempty"` @@ -69,7 +65,6 @@ func GetAllVersionsDevelopment() Versions { GoVersion: runtime.Version(), MainVersion: GetMainVersion(), Platform: runtime.GOOS + "/" + runtime.GOARCH, - ScannerVersion: internal.ScannerVersion, ChartVersion: GetChartVersion(), FactVersion: getFactVersion(), } @@ -82,7 +77,6 @@ func GetAllVersionsDevelopment() Versions { func GetAllVersionsUnified() Versions { v := GetAllVersionsDevelopment() v.CollectorVersion = GetMainVersion() - v.ScannerVersion = GetMainVersion() return v } diff --git a/proto/storage/policy.proto b/proto/storage/policy.proto index c07c52d6152e2..922f9fba17715 100644 --- a/proto/storage/policy.proto +++ b/proto/storage/policy.proto @@ -36,7 +36,7 @@ message Policy { EventSource event_source = 22; // @gotags: crYaml:"eventSource,stringer" reserved 10; //was repeated Exclusion whitelists - // Define deployments or images that should be excluded from this policy. + // Define deployments, images, or workload kinds that should be excluded from this policy. repeated Exclusion exclusions = 21; // @gotags: crYaml:",omitempty" // Defines clusters, namespaces, and deployments that should be included in this policy. No scopes defined includes everything. repeated Scope scope = 11; // @gotags: crYaml:",omitempty" @@ -180,7 +180,7 @@ enum Comparator { // EvaluationFilter pre-filters which entities a policy evaluates. message EvaluationFilter { - repeated ContainerType skip_container_types = 1; + repeated ContainerType skip_container_types = 1; // @gotags: crYaml:"skipContainerTypes,omitempty,stringer" } message Exclusion { @@ -195,7 +195,6 @@ message Exclusion { string name = 3; // @gotags: crYaml:",omitempty" Scope scope = 4; // @gotags: crYaml:",omitempty" } - Deployment deployment = 5; // @gotags: crYaml:",omitempty" message Image { string name = 1; @@ -203,6 +202,25 @@ message Exclusion { Image image = 7; // @gotags: crYaml:",omitempty" google.protobuf.Timestamp expiration = 6; // @gotags: crYaml:",timestamp,omitempty" + + // WorkloadKind is a Kubernetes workload kind that can be excluded from a policy in bulk. + enum WorkloadKind { + WORKLOAD_KIND_UNSPECIFIED = 0; + CRON_JOB = 1; + JOB = 2; + } + + // ExcludeByKind excludes all workloads of the selected Kubernetes kinds. + message ExcludeByKind { + repeated WorkloadKind kinds = 1; // @gotags: crYaml:",omitempty,stringer" + } + + // matcher is either a name/scope exclusion or an exclusion by Kubernetes kind. + // Image stays outside the oneof because existing payloads may set both image and deployment. + oneof matcher { + Deployment deployment = 5; // @gotags: crYaml:",omitempty" + ExcludeByKind exclude_by_kind = 8; // @gotags: crYaml:"excludeByKind,omitempty" + } } // ExportPoliciesResponse is used by the API but it is defined in storage because we expect customers to store them. diff --git a/proto/storage/proto.lock b/proto/storage/proto.lock index ada9094986dcf..d2c619b50b714 100644 --- a/proto/storage/proto.lock +++ b/proto/storage/proto.lock @@ -14054,6 +14054,22 @@ "integer": 4 } ] + }, + { + "name": "Exclusion.WorkloadKind", + "enum_fields": [ + { + "name": "WORKLOAD_KIND_UNSPECIFIED" + }, + { + "name": "CRON_JOB", + "integer": 1 + }, + { + "name": "JOB", + "integer": 2 + } + ] } ], "messages": [ @@ -14371,11 +14387,6 @@ "name": "name", "type": "string" }, - { - "id": 5, - "name": "deployment", - "type": "Deployment" - }, { "id": 7, "name": "image", @@ -14385,6 +14396,18 @@ "id": 6, "name": "expiration", "type": "google.protobuf.Timestamp" + }, + { + "id": 5, + "name": "deployment", + "type": "Deployment", + "oneof_parent": "matcher" + }, + { + "id": 8, + "name": "exclude_by_kind", + "type": "ExcludeByKind", + "oneof_parent": "matcher" } ], "reserved_ids": [ @@ -14425,6 +14448,17 @@ "type": "string" } ] + }, + { + "name": "ExcludeByKind", + "fields": [ + { + "id": 1, + "name": "kinds", + "type": "WorkloadKind", + "is_repeated": true + } + ] } ] }, diff --git a/qa-tests-backend/scripts/run-part-1.sh b/qa-tests-backend/scripts/run-part-1.sh index ef446d76f608a..819caaefda26f 100755 --- a/qa-tests-backend/scripts/run-part-1.sh +++ b/qa-tests-backend/scripts/run-part-1.sh @@ -45,6 +45,11 @@ config_part_1() { setup_gcp setup_deployment_env false false if [[ "$use_roxie_deploy" == "true" ]]; then + # On GHA we already installed roxie in a previous workflow step. On Prow we have roxie available as part of the apollo-ci image, + # but it might not be up to date, hence this invocation to make sure that we have a recent roxie version also on Prow. + if [[ "${GITHUB_ACTIONS:-}" != "true" ]]; then + ensure_roxie_on_path + fi info "Using roxie-based pre-test teardown" roxie teardown all --single-namespace else @@ -58,6 +63,8 @@ config_part_1() { if [[ "$use_roxie_deploy" == "true" ]]; then info "Using roxie-based config_part_1 for qa-tests-backend" + ensure_roxie_on_path + local config_file config_file="$(mktemp)" @@ -71,13 +78,6 @@ securedCluster: resourceProfile: ci EOF - if [[ "${USE_KONFLUX_IMAGES:-false}" == "true" ]]; then - info "Environment contains USE_KONFLUX_IMAGES=true, will be using Konflux-built images for deploying StackRox" - patch_yaml "$config_file" ".roxie.konfluxImages = true" - elif pr_has_label test-konflux-images; then - info "PR label 'test-konflux-images' detected, will be using Konflux-built images for deploying StackRox" - patch_yaml "$config_file" ".roxie.konfluxImages = true" - fi deploy_stackrox_with_roxie_compat "$config_file" setup_client_TLS_certs "$ROOT/$DEPLOY_DIR/client_TLS_certs" # Note: The traditional deployment path still references PodSecurityPolicies, diff --git a/qa-tests-backend/src/main/groovy/objects/Deployment.groovy b/qa-tests-backend/src/main/groovy/objects/Deployment.groovy index 7645193566c1a..151da20ae5735 100644 --- a/qa-tests-backend/src/main/groovy/objects/Deployment.groovy +++ b/qa-tests-backend/src/main/groovy/objects/Deployment.groovy @@ -14,6 +14,8 @@ class Deployment { String name String namespace = Constants.ORCHESTRATOR_NAMESPACE String image + // Optional policy for the main container; takes precedence over the CI Quay policy. + String imagePullPolicyOverride Map labels = [:] Map ports = [:] Integer targetport @@ -104,6 +106,11 @@ class Deployment { return this } + Deployment setImagePullPolicyOverride(String policy) { + this.imagePullPolicyOverride = policy + return this + } + Deployment addLabel(String k, String v) { this.labels[k] = v return this diff --git a/qa-tests-backend/src/main/groovy/orchestratormanager/Kubernetes.groovy b/qa-tests-backend/src/main/groovy/orchestratormanager/Kubernetes.groovy index 3ff93c2e6c171..7d44e2751784b 100644 --- a/qa-tests-backend/src/main/groovy/orchestratormanager/Kubernetes.groovy +++ b/qa-tests-backend/src/main/groovy/orchestratormanager/Kubernetes.groovy @@ -2450,7 +2450,9 @@ class Kubernetes { // Allow override of imagePullPolicy for quay.io images. Typically used // to set to Never to help keep the list of quay.io prebuilt images up // to date for image-prefetcher. Why not all images? See ROX-25258. - if (Env.IMAGE_PULL_POLICY_FOR_QUAY_IO && deployment.image =~ /^quay.io/) { + if (deployment.imagePullPolicyOverride) { + container.setImagePullPolicy(deployment.imagePullPolicyOverride) + } else if (Env.IMAGE_PULL_POLICY_FOR_QUAY_IO && deployment.image =~ /^quay.io/) { container.setImagePullPolicy(Env.IMAGE_PULL_POLICY_FOR_QUAY_IO) } if (deployment.livenessProbeDefined) { @@ -2678,8 +2680,91 @@ class Kubernetes { withRetry(2, 3) { client.namespaces().withName(ns).delete() } - if (waitForDeletion) { - waitForNamespaceDeletion(ns) + if (waitForDeletion && !waitForNamespaceDeletion(ns)) { + // A namespace that is still listed is a failed cleanup, not a soft warning. + throw new OrchestratorManagerException( + "Timed out waiting for namespace ${ns} to be deleted${namespaceDeletionDiagnostics(ns)}") + } + } + + // deleteManagedWorkloads removes deployments, replica sets, and pods so + // namespace deletion is not held by a pod's termination. A second delete + // with grace period 0 shortens a termination already in progress. + @CompileDynamic + void deleteManagedWorkloads(String ns) { + Timer t = new Timer(20, 1) + boolean sawNoPods = false + while (t.IsValid()) { + if (namespaceGone(ns)) { + return + } + deleteCollectionQuietly { client.apps().deployments().inNamespace(ns).delete() } + deleteCollectionQuietly { client.apps().replicaSets().inNamespace(ns).delete() } + deleteCollectionQuietly { client.pods().inNamespace(ns).withGracePeriod(0L).delete() } + if (listPodsQuietly(ns).isEmpty()) { + // A second empty read covers a replica set that creates one + // more pod after it is told to delete. + if (sawNoPods) { + return + } + sawNoPods = true + continue + } + sawNoPods = false + } + def stuck = listPodsQuietly(ns).collect { + "${it.metadata?.name} phase=${it.status?.phase} finalizers=${it.metadata?.finalizers}" + } + log.info "Workloads still present in ${ns} before namespace deletion: ${stuck}" + } + + @CompileDynamic + private boolean namespaceGone(String ns) { + try { + return client.namespaces().withName(ns).get() == null + } catch (KubernetesClientException e) { + return e.code == 404 + } + } + + @CompileDynamic + private void deleteCollectionQuietly(Closure deletion) { + try { + deletion.call() + } catch (KubernetesClientException e) { + if (e.code != 404) { + log.warn "Resource delete during namespace cleanup failed: ${e.message}" + } + } + } + + @CompileDynamic + private List listPodsQuietly(String ns) { + try { + return client.pods().inNamespace(ns).list()?.items ?: [] + } catch (KubernetesClientException e) { + if (e.code == 404) { + return [] + } + throw e + } + } + + @CompileDynamic + private String namespaceDeletionDiagnostics(String ns) { + try { + def remaining = client.namespaces().withName(ns).get() + if (remaining == null) { + return "" + } + def pods = listPodsQuietly(ns).collect { + "${it.metadata?.name}(phase=${it.status?.phase}, finalizers=${it.metadata?.finalizers})" + } + return " (phase=${remaining.status?.phase}," + + " deletionTimestamp=${remaining.metadata?.deletionTimestamp}," + + " finalizers=${remaining.metadata?.finalizers}, pods=${pods})" + } catch (Exception e) { + return " (failed to collect namespace diagnostics: ${e.message})" } } diff --git a/qa-tests-backend/src/test/groovy/AdmissionControllerTest.groovy b/qa-tests-backend/src/test/groovy/AdmissionControllerTest.groovy index 07a5f9c9f3308..5c674a7b3b03b 100644 --- a/qa-tests-backend/src/test/groovy/AdmissionControllerTest.groovy +++ b/qa-tests-backend/src/test/groovy/AdmissionControllerTest.groovy @@ -1,5 +1,7 @@ import static util.Helpers.withRetry +import io.grpc.Status +import io.grpc.StatusRuntimeException import io.stackrox.proto.storage.Cve.VulnerabilitySeverity import io.stackrox.proto.storage.ImageOuterClass import io.stackrox.proto.storage.PolicyOuterClass @@ -8,6 +10,7 @@ import io.stackrox.proto.storage.ScopeOuterClass import objects.Deployment import services.ClusterService import services.ImageService +import services.NamespaceService import services.PolicyService import util.Timer @@ -130,10 +133,17 @@ class AdmissionControllerTest extends BaseSpecification { } def cleanupSpec() { + // A pod can still be listed after its deployment object is gone, and + // that holds this shared namespace in Terminating. + orchestrator.deleteManagedWorkloads(TEST_NAMESPACE) orchestrator.deleteNamespace(TEST_NAMESPACE) - for (policyID in createdPolicyIds) { - PolicyService.deletePolicy(policyID) + try { + for (policyID in createdPolicyIds) { + PolicyService.deletePolicy(policyID) + } + } catch (Exception e) { + log.warn "Failed to delete one or more policies during cleanup: ${e.message}" } } @@ -238,6 +248,20 @@ class AdmissionControllerTest extends BaseSpecification { true | true } + // cleanupLabelTestNamespace removes workloads before the namespace. A pod + // from an allowed deployment keeps the namespace past the delete wait, and + // Central can still list it after the API object is gone (ROX-36941). + private void cleanupLabelTestNamespace(String testNs) { + if (!testNs) { + return + } + orchestrator.deleteManagedWorkloads(testNs) + orchestrator.deleteNamespace(testNs) + withRetry(30, 1) { + assert NamespaceService.getNamespaces().every { it.metadata.name != testNs } + } + } + def deleteDeploymentWithCaution(Deployment deployment) { orchestrator.deleteDeployment(deployment) def timer = new Timer(30, 1) @@ -249,6 +273,32 @@ class AdmissionControllerTest extends BaseSpecification { log.warn "Failed to confirm deletion of deployment ${deployment.name}. Subsequent tests may be affected ..." } + private Exception deletePolicyWithCaution(String policyId) { + try { + if (policyId) { + PolicyService.deletePolicy(policyId) + // Wait for policy deletion to propagate to admission controller + withRetry(10, 1) { + def policyExists = true + try { + Services.getPolicy(policyId) + } catch (StatusRuntimeException e) { + if (e.status.code == Status.Code.NOT_FOUND) { + policyExists = false + } else { + throw e + } + } + assert !policyExists : "Policy ${policyId} still exists after deletion" + } + } + } catch (Exception e) { + log.warn "Failed to delete policy ${policyId}: ${e.message}" + return e + } + return null + } + // Retry to allow time for the admission controller to fetch scan data from // Central. Policies that require image enrichment (e.g. severity) may not // evaluate on the first attempt if the AC pod handling this request hasn't @@ -313,12 +363,15 @@ class AdmissionControllerTest extends BaseSpecification { assert created == !blocked cleanup: - if (created) { - deleteDeploymentWithCaution(deployment) + def policyDeletionFailure = deletePolicyWithCaution(policyId) + try { + cleanupLabelTestNamespace(testNs) + } catch (Exception e) { + log.warn "Namespace ${testNs} deletion failed or timed out: ${e.message}" + throw e } - orchestrator.deleteNamespace(testNs, false) - if (policyId) { - PolicyService.deletePolicy(policyId) + if (policyDeletionFailure) { + throw policyDeletionFailure } where: @@ -410,12 +463,15 @@ class AdmissionControllerTest extends BaseSpecification { assert created2 cleanup: - if (created2) { - deleteDeploymentWithCaution(deployment2) + def policyDeletionFailure = deletePolicyWithCaution(policyId) + try { + cleanupLabelTestNamespace(testNs) + } catch (Exception e) { + log.warn "Namespace ${testNs} deletion failed or timed out: ${e.message}" + throw e } - orchestrator.deleteNamespace(testNs, false) - if (policyId) { - PolicyService.deletePolicy(policyId) + if (policyDeletionFailure) { + throw policyDeletionFailure } where: diff --git a/qa-tests-backend/src/test/groovy/DefaultPoliciesTest.groovy b/qa-tests-backend/src/test/groovy/DefaultPoliciesTest.groovy index 5998fb1b6c6a1..f2bb5227ac1b6 100644 --- a/qa-tests-backend/src/test/groovy/DefaultPoliciesTest.groovy +++ b/qa-tests-backend/src/test/groovy/DefaultPoliciesTest.groovy @@ -83,6 +83,10 @@ class DefaultPoliciesTest extends BaseSpecification { "tunnelfront - Secure Shell Server (sshd) Execution", "tunnelfront - Docker CIS 4.7: Alert on Update Instruction", "webhookserver - Kubernetes Actions: Port Forward to Pod", + // Newer EKS ebs-csi-node DaemonSets use bidirectional mount propagation. + "ebs-csi-node - Docker CIS 5.19: Ensure mount propagation mode is not enabled", + // GKE filestore-node DaemonSets use bidirectional mount propagation. + "filestore-node - Docker CIS 5.19: Ensure mount propagation mode is not enabled", ] static final private Deployment STRUTS_DEPLOYMENT = new Deployment() @@ -459,11 +463,10 @@ class DefaultPoliciesTest extends BaseSpecification { "Port 80 is exposed in the cluster" | null | [] "Image Vulnerabilities" | 4.0f | null | - // StackRox Scanner reports 100+ CVEs between Low and Critical. - // Scanner V4 reports fewer CVEs (~78) and a different minimum - // severity (Moderate in this case). Using \\d{2,} and \\w+ to accept both outcomes. + // Scanner versions report different counts of distinct CVEs and minimum + // severities. Use a regex to accept both outcomes. "Image \"" + STRUTS_IMAGE + "\\\"" + - " contains \\d{2,} CVEs with severities ranging between " + + " contains \\d{2,} distinct CVEs with severities ranging between " + "\\w+ and \\w+" | [] "Service Configuration" | 2.0f | diff --git a/qa-tests-backend/src/test/groovy/GlobalSearch.groovy b/qa-tests-backend/src/test/groovy/GlobalSearch.groovy index 04056f42a13f5..e4f563e85bf19 100644 --- a/qa-tests-backend/src/test/groovy/GlobalSearch.groovy +++ b/qa-tests-backend/src/test/groovy/GlobalSearch.groovy @@ -34,10 +34,6 @@ class GlobalSearch extends BaseSpecification { SearchServiceOuterClass.SearchCategory.NAMESPACES, SearchServiceOuterClass.SearchCategory.IMAGES, SearchServiceOuterClass.SearchCategory.DEPLOYMENTS) - if (flattenImageDataEnabled) { - EXPECTED_DEPLOYMENT_CATEGORIES.add(SearchServiceOuterClass.SearchCategory.IMAGES_V2) - EXPECTED_IMAGE_CATEGORIES.add(SearchServiceOuterClass.SearchCategory.IMAGES_V2) - } orchestrator.createDeployment(DEPLOYMENT) assert Services.waitForDeployment(DEPLOYMENT) diff --git a/qa-tests-backend/src/test/groovy/ImageScanningTest.groovy b/qa-tests-backend/src/test/groovy/ImageScanningTest.groovy index c709e80c1498b..a56d13e2c4e47 100644 --- a/qa-tests-backend/src/test/groovy/ImageScanningTest.groovy +++ b/qa-tests-backend/src/test/groovy/ImageScanningTest.groovy @@ -80,6 +80,8 @@ class ImageScanningTest extends BaseSpecification { // Alternatively can use quay.io/rhacs-eng/qa:struts-app but that doesn't have as many // dockerfile violations .setImage("quay.io/rhacs-eng/qa:registry-image-0-3") + // TODO(ROX-37155): Revert this override. + .setImagePullPolicyOverride("IfNotPresent") .addLabel("app", "quay-image-scanning-test") .addImagePullSecret("quay-image-scanning-test"), "gcr": new Deployment() diff --git a/qa-tests-backend/src/test/groovy/NodeIndexTest.groovy b/qa-tests-backend/src/test/groovy/NodeIndexTest.groovy index 6c101aa005ca7..68963fb8e9be0 100644 --- a/qa-tests-backend/src/test/groovy/NodeIndexTest.groovy +++ b/qa-tests-backend/src/test/groovy/NodeIndexTest.groovy @@ -31,8 +31,6 @@ class NodeIndexTest extends BaseSpecification { given: "Scanner V4 is enabled and the cluster has nodes" Assume.assumeTrue("Scanner V4 node indexing is required", scannerV4Enabled) - List nodes = NodeService.getNodes() - assert nodes.size() > 0 when: "scanner-v4-matcher is ready so index reports can be enriched" @@ -40,14 +38,10 @@ class NodeIndexTest extends BaseSpecification { waitForTrue(20, 6) { orchestrator.deploymentReady(Constants.STACKROX_NAMESPACE, "scanner-v4-matcher") } - // Matcher-not-ready drops the first index report as unretryable. CI deploy - // sets ROX_NODE_SCANNING_MAX_INITIAL_WAIT=1s and ROX_NODE_SCANNING_INTERVAL=30s - // so a later scan lands after matcher is up without restarting collector. - then: "each OpenShift node scan has RPM packages, not only kubelet/kernel/runtime" withRetry(12, 30) { - nodes = NodeService.getNodes() + List nodes = NodeService.getNodes() assert nodes.size() > 0, "Expected to find at least one node" nodes.each { node -> assert node.getScan(), "Expected to find a nodeScan on the node" diff --git a/qa-tests-backend/src/test/groovy/SACTest.groovy b/qa-tests-backend/src/test/groovy/SACTest.groovy index dd6a10fa6d83a..c9bd307501e2f 100644 --- a/qa-tests-backend/src/test/groovy/SACTest.groovy +++ b/qa-tests-backend/src/test/groovy/SACTest.groovy @@ -404,7 +404,7 @@ class SACTest extends BaseSpecification { tokenName | category | numResults NOACCESSTOKEN | "Cluster" | 0 "searchDeploymentsToken" | "Deployment" | 1 - "searchImagesToken" | "Image" | (flattenImageDataEnabled ? 2 : 1) + "searchImagesToken" | "Image" | 1 } @Unroll diff --git a/roxctl/central/generate/interactive.go b/roxctl/central/generate/interactive.go index fe544dca69b66..e5df581fb6f4a 100644 --- a/roxctl/central/generate/interactive.go +++ b/roxctl/central/generate/interactive.go @@ -352,11 +352,9 @@ func processFlagWraps(argSlice *argSlice, fws []flagWrap) { depUnmet := false for _, dep := range fw.Annotations[flags.DependenciesKey] { flag := flagsByName[dep] - //nolint:staticcheck // SA5011 flag is definitely not nil because utils.Must panics. if flag == nil { utils.CrashOnError(errors.Errorf("invalid flag dependency %q", dep)) } - //nolint:staticcheck // SA5011 flag is definitely not nil because utils.Must panics. if !argSlice.flagNameIsSetExplicitly(flag.Name) { depUnmet = true break diff --git a/roxctl/common/client.go b/roxctl/common/client.go index d1f8cb4ef4dcb..3cc94fb51002a 100644 --- a/roxctl/common/client.go +++ b/roxctl/common/client.go @@ -2,6 +2,7 @@ package common import ( "context" + "crypto/tls" "fmt" "io" "net/http" @@ -59,16 +60,16 @@ func getURL(path string) (string, error) { return fmt.Sprintf("%s://%s/%s", scheme, endpoint, strings.TrimLeft(path, "/")), nil } -// GetRoxctlHTTPClient returns a new instance of RoxctlHTTPClient with the given configuration -func GetRoxctlHTTPClient(config *HttpClientConfig) (RoxctlHTTPClient, error) { - tlsConf, err := tlsConfigForCentral() - if err != nil { - return nil, errors.Wrap(err, "instantiating TLS configuration for central") - } +// newHTTPTransport builds the HTTP transport used by roxctl to talk to Central. +// Proxy is set to http.ProxyFromEnvironment so that HTTP(S)_PROXY/NO_PROXY are honored; +// a hand-built http.Transport otherwise defaults to no proxy (unlike http.DefaultTransport), +// which made roxctl dial Central directly and time out behind egress proxies (ROX-37149). +func newHTTPTransport(tlsConf *tls.Config, forceHTTP1 bool) *http.Transport { transport := &http.Transport{ + Proxy: http.ProxyFromEnvironment, TLSClientConfig: tlsConf, } - if config.ForceHTTP1 { + if forceHTTP1 { transport.TLSClientConfig.NextProtos = http1NextProtos } else { // There's no reason to not use HTTP/2, but we don't go out of our way to do so. @@ -76,6 +77,16 @@ func GetRoxctlHTTPClient(config *HttpClientConfig) (RoxctlHTTPClient, error) { transport.TLSClientConfig.NextProtos = http1NextProtos } } + return transport +} + +// GetRoxctlHTTPClient returns a new instance of RoxctlHTTPClient with the given configuration +func GetRoxctlHTTPClient(config *HttpClientConfig) (RoxctlHTTPClient, error) { + tlsConf, err := tlsConfigForCentral() + if err != nil { + return nil, errors.Wrap(err, "instantiating TLS configuration for central") + } + transport := newHTTPTransport(tlsConf, config.ForceHTTP1) retryClient := retryablehttp.NewClient() retryClient.CheckRetry = func(ctx context.Context, resp *http.Response, err error) (bool, error) { diff --git a/roxctl/common/client_test.go b/roxctl/common/client_test.go index 9804d62c26050..be569f3b6e40a 100644 --- a/roxctl/common/client_test.go +++ b/roxctl/common/client_test.go @@ -1,13 +1,16 @@ package common import ( + "crypto/tls" "net/http" + "reflect" "testing" "github.com/stackrox/rox/pkg/clientconn" "github.com/stackrox/rox/pkg/env" "github.com/stackrox/rox/pkg/telemetry/phonehome" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestSanitizeHeaderValue(t *testing.T) { @@ -22,6 +25,25 @@ func TestSanitizeHeaderValue(t *testing.T) { } } +func Test_newHTTPTransport_honorsProxyEnv(t *testing.T) { + // Regression test for ROX-37149: roxctl ignored HTTP(S)_PROXY because the + // hand-built transport left Proxy unset. Verify the transport delegates to + // http.ProxyFromEnvironment for both HTTP/2 and forced HTTP/1 modes. + for name, forceHTTP1 := range map[string]bool{ + "http2": false, + "forceHTTP1": true, + } { + t.Run(name, func(t *testing.T) { + transport := newHTTPTransport(&tls.Config{}, forceHTTP1) + require.NotNil(t, transport.Proxy, "transport must resolve the proxy from the environment") + assert.Equal(t, + reflect.ValueOf(http.ProxyFromEnvironment).Pointer(), + reflect.ValueOf(transport.Proxy).Pointer(), + "transport.Proxy must be http.ProxyFromEnvironment") + }) + } +} + func Test_setCustomHeaders(t *testing.T) { headers := http.Header{} setCustomHeaders(phonehome.Headers(headers).Set) diff --git a/roxctl/common/connection.go b/roxctl/common/connection.go index 19246279db05e..a60d8a17b16e7 100644 --- a/roxctl/common/connection.go +++ b/roxctl/common/connection.go @@ -3,6 +3,7 @@ package common import ( "context" "crypto/tls" + "io" "net" "strings" "time" @@ -16,6 +17,7 @@ import ( "github.com/stackrox/rox/pkg/roxctl/common" "github.com/stackrox/rox/roxctl/common/auth" "github.com/stackrox/rox/roxctl/common/flags" + "github.com/stackrox/rox/roxctl/common/versioncheck" http1DowngradeClient "golang.stackrox.io/grpc-http1/client" "google.golang.org/grpc" "google.golang.org/grpc/codes" @@ -33,6 +35,15 @@ func WithRetryTimeout(timeout time.Duration) GRPCOption { } } +// WithVersionCheck enables version compatibility checking on gRPC responses. +// Warnings are written to w at most once when a version incompatibility is +// detected from the Central version response header. +func WithVersionCheck(w io.Writer) GRPCOption { + return func(config *grpcConfig) { + config.versionCheckWriter = w + } +} + // GetGRPCConnection gets a grpc connection to Central with the correct auth func GetGRPCConnection(am auth.Method, connectionOpts ...GRPCOption) (*grpc.ClientConn, error) { endpoint, serverName, usePlaintext, err := ConnectNames() @@ -67,14 +78,15 @@ func GetGRPCConnection(am auth.Method, connectionOpts ...GRPCOption) (*grpc.Clie } type grpcConfig struct { - usePlaintext bool - insecure bool - opts clientconn.Options - serverName string - useDirectGRPC bool - forceHTTP1 bool - endpoint string - retryTimeout time.Duration + usePlaintext bool + insecure bool + opts clientconn.Options + serverName string + useDirectGRPC bool + forceHTTP1 bool + endpoint string + retryTimeout time.Duration + versionCheckWriter io.Writer } func makeCtxWithCommandHeader(ctx context.Context) context.Context { @@ -122,13 +134,19 @@ func createGRPCConn(c grpcConfig) (*grpc.ClientConn, error) { grpc_retry.WithRetriable(shouldRetry), } + unaryInterceptors := []grpc.UnaryClientInterceptor{ + addCommandHeaderUnaryInterceptor, + grpc_retry.UnaryClientInterceptor(retryOpts...), + } + if c.versionCheckWriter != nil { + unaryInterceptors = append(unaryInterceptors, versioncheck.CentralVersionClientInterceptor(c.versionCheckWriter)) + } + grpcDialOpts := []grpc.DialOption{ grpc.WithChainStreamInterceptor( addCommandHeaderStreamInterceptor, grpc_retry.StreamClientInterceptor(retryOpts...)), - grpc.WithChainUnaryInterceptor( - addCommandHeaderUnaryInterceptor, - grpc_retry.UnaryClientInterceptor(retryOpts...)), + grpc.WithChainUnaryInterceptor(unaryInterceptors...), } if c.usePlaintext { diff --git a/roxctl/common/environment/environment-impl.go b/roxctl/common/environment/environment-impl.go index 1833f212aa496..63627eedffd89 100644 --- a/roxctl/common/environment/environment-impl.go +++ b/roxctl/common/environment/environment-impl.go @@ -94,6 +94,7 @@ func (c *cliEnvironmentImpl) GRPCConnection(connectionOpts ...common.GRPCOption) if err != nil { return nil, errors.Wrap(err, "determining auth method") } + connectionOpts = append(connectionOpts, common.WithVersionCheck(c.io.ErrOut())) connection, err := common.GetGRPCConnection(am, connectionOpts...) return connection, errors.WithStack(err) } diff --git a/roxctl/common/versioncheck/check.go b/roxctl/common/versioncheck/check.go new file mode 100644 index 0000000000000..58f979fb799fd --- /dev/null +++ b/roxctl/common/versioncheck/check.go @@ -0,0 +1,87 @@ +package versioncheck + +import ( + "context" + "fmt" + "io" + "strings" + "sync/atomic" + + "github.com/stackrox/rox/pkg/clientconn" + "github.com/stackrox/rox/pkg/version" + "github.com/stackrox/rox/pkg/version/productstreams" + "github.com/stackrox/rox/pkg/version/versioncompatibility" + "google.golang.org/grpc" + "google.golang.org/grpc/metadata" +) + +// CentralVersionClientInterceptor returns a gRPC unary client interceptor that reads +// the Central version from response header and emits a warning if the +// versions of Central and roxctl are incompatible. The warning is emitted at most once per +// interceptor instance. +func CentralVersionClientInterceptor(w io.Writer) grpc.UnaryClientInterceptor { + var checked atomic.Bool + return func(ctx context.Context, method string, req, reply any, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error { + var md metadata.MD + opts = append(opts, grpc.Header(&md)) + // Response headers are populated after the RPC completes. + err := invoker(ctx, method, req, reply, cc, opts...) + if vals := md.Get(clientconn.CentralVersionHeader); len(vals) > 0 { + if !checked.Swap(true) { + checkAndWarn(vals[0], w) + } + } + return err + } +} + +func checkAndWarn(centralVersion string, w io.Writer) bool { + remoteXY, err := productstreams.ParseXYFromVersionString(centralVersion) + if err != nil { + return false + } + roxctlVersion := version.GetMainVersion() + localXY, err := productstreams.ParseXYFromVersionString(roxctlVersion) + if err != nil { + return false + } + if localXY == remoteXY { + return false + } + + compat, err := versioncompatibility.ClassifyVersion(remoteXY) + if err != nil { + return false + } + if compat != versioncompatibility.IncompatibleAhead && compat != versioncompatibility.IncompatibleBehind { + return false + } + + versionRange, err := versioncompatibility.CompatibleVersions() + if err != nil { + return false + } + compatRange := formatVersionRange(versionRange) + + var direction string + if compat == versioncompatibility.IncompatibleAhead { + direction = "too old" + } else { + direction = "too new" + } + fmt.Fprintf(w, "Warning: Your roxctl %s is %s for this Central %s. "+ + "Correct functioning is not guaranteed. "+ + "Use roxctl version matching the Central version or at least such that the Central version is within the roxctl compatibility range.\n", + roxctlVersion, direction, centralVersion) + fmt.Fprintf(w, " roxctl: %s | Central: %s | Compatible Centrals: %s\n", + roxctlVersion, centralVersion, compatRange) + return true +} + +func formatVersionRange(versions []productstreams.XYVersion) string { + strs := make([]string, len(versions)) + for i, v := range versions { + strs[i] = v.String() + } + return strings.Join(strs, ", ") +} diff --git a/roxctl/common/versioncheck/check_test.go b/roxctl/common/versioncheck/check_test.go new file mode 100644 index 0000000000000..4551678f69001 --- /dev/null +++ b/roxctl/common/versioncheck/check_test.go @@ -0,0 +1,227 @@ +package versioncheck + +import ( + "bytes" + "context" + "net" + "testing" + + v1 "github.com/stackrox/rox/generated/api/v1" + "github.com/stackrox/rox/pkg/clientconn" + "github.com/stackrox/rox/pkg/grpc/authn" + "github.com/stackrox/rox/pkg/grpc/versionheader" + "github.com/stackrox/rox/pkg/version/testutils" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/test/bufconn" +) + +func TestCheckAndWarn(t *testing.T) { + cases := map[string]struct { + localVersion string + centralVersion string + expectWarning string + }{ + "same version": { + localVersion: "4.8.0", + centralVersion: "4.8.0", + }, + "same XY different patch": { + localVersion: "4.8.0", + centralVersion: "4.8.1", + }, + "compatible behind within range": { + localVersion: "4.8.0", + centralVersion: "4.6.0", + }, + "compatible ahead within range": { + localVersion: "4.8.0", + centralVersion: "4.10.0", + }, + "incompatible behind": { + localVersion: "4.8.0", + centralVersion: "4.3.0", + expectWarning: "too new", + }, + "incompatible ahead": { + localVersion: "4.8.0", + centralVersion: "4.15.0", + expectWarning: "too old", + }, + "invalid central version": { + localVersion: "4.8.0", + centralVersion: "invalid", + }, + "invalid local version": { + localVersion: "invalid", + centralVersion: "4.10.1", + }, + } + + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + testutils.SetMainVersion(t, tc.localVersion) + + var buf bytes.Buffer + result := checkAndWarn(tc.centralVersion, &buf) + + assert.Equal(t, tc.expectWarning != "", result, "return value mismatch") + if tc.expectWarning != "" { + assert.Contains(t, buf.String(), tc.expectWarning) + assert.Contains(t, buf.String(), "Compatible Centrals:") + } else { + assert.Empty(t, buf.String()) + } + }) + } +} + +func TestCentralVersionClientInterceptor(t *testing.T) { + cases := map[string]struct { + centralVersion string + expectWarning string + }{ + "incompatible version warns": { + centralVersion: "4.2.0", + expectWarning: "too new", + }, + "compatible version is silent": { + centralVersion: "4.10.6", + }, + } + + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + testutils.SetMainVersion(t, "4.8.0") + + var buf bytes.Buffer + conn := setupServerAndClient(t, + []grpc.UnaryServerInterceptor{injectVersionHeaderInterceptor(t, tc.centralVersion)}, + []grpc.UnaryClientInterceptor{CentralVersionClientInterceptor(&buf)}, + ) + + client := v1.NewMetadataServiceClient(conn) + _, err := client.GetMetadata(context.Background(), &v1.Empty{}) + require.NoError(t, err) + + if tc.expectWarning != "" { + assert.Contains(t, buf.String(), tc.expectWarning) + assert.Contains(t, buf.String(), "Compatible Centrals:") + } else { + assert.Empty(t, buf.String()) + } + }) + } +} + +func TestCentralVersionClientInterceptor_WithRealServerInterceptor(t *testing.T) { + // When the client is authenticated, CentralVersionServerInterceptor serves the same version so no warning is raised. + // When the client is not authenticated, CentralVersionServerInterceptor does not return the header and no warning is raised either. + cases := map[string]struct { + authenticated bool + }{ + "authenticated with matching versions is silent": {authenticated: true}, + "anonymous is silent": {authenticated: false}, + } + + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + testutils.SetMainVersion(t, "4.8.0") + + var serverInterceptors []grpc.UnaryServerInterceptor + if tc.authenticated { + serverInterceptors = append(serverInterceptors, injectIdentityInterceptor(t)) + } + serverInterceptors = append(serverInterceptors, versionheader.CentralVersionServerInterceptor()) + + var buf bytes.Buffer + conn := setupServerAndClient(t, + serverInterceptors, + []grpc.UnaryClientInterceptor{CentralVersionClientInterceptor(&buf)}, + ) + + client := v1.NewMetadataServiceClient(conn) + _, err := client.GetMetadata(context.Background(), &v1.Empty{}) + require.NoError(t, err) + + assert.Empty(t, buf.String()) + }) + } +} + +func TestCentralVersionClientInterceptor_WarnsOnlyOnce(t *testing.T) { + testutils.SetMainVersion(t, "4.8.0") + + var buf bytes.Buffer + conn := setupServerAndClient(t, + []grpc.UnaryServerInterceptor{ + injectIdentityInterceptor(t), + injectVersionHeaderInterceptor(t, "4.2.0"), + }, + []grpc.UnaryClientInterceptor{CentralVersionClientInterceptor(&buf)}, + ) + + client := v1.NewMetadataServiceClient(conn) + _, err := client.GetMetadata(context.Background(), &v1.Empty{}) + require.NoError(t, err) + assert.NotEmpty(t, buf.String()) + + buf.Reset() + + _, err = client.GetMetadata(context.Background(), &v1.Empty{}) + require.NoError(t, err) + assert.Empty(t, buf.String(), "warning should not be emitted a second time") +} + +// --- helpers and mocks --- + +type fakeIdentity struct { + authn.Identity +} + +type fakeMetadataServer struct { + v1.UnimplementedMetadataServiceServer +} + +func (f *fakeMetadataServer) GetMetadata(_ context.Context, _ *v1.Empty) (*v1.Metadata, error) { + return &v1.Metadata{Version: "test"}, nil +} + +func setupServerAndClient(t *testing.T, serverInterceptors []grpc.UnaryServerInterceptor, clientInterceptors []grpc.UnaryClientInterceptor) *grpc.ClientConn { + listener := bufconn.Listen(1024 * 1024) + server := grpc.NewServer(grpc.ChainUnaryInterceptor(serverInterceptors...)) + v1.RegisterMetadataServiceServer(server, &fakeMetadataServer{}) + + go func() { + assert.NoError(t, server.Serve(listener)) + }() + t.Cleanup(server.Stop) + + conn, err := grpc.NewClient("passthrough:///bufnet", + grpc.WithContextDialer(func(ctx context.Context, _ string) (net.Conn, error) { + return listener.DialContext(ctx) + }), + grpc.WithTransportCredentials(insecure.NewCredentials()), + grpc.WithChainUnaryInterceptor(clientInterceptors...), + ) + require.NoError(t, err) + t.Cleanup(func() { assert.NoError(t, conn.Close()) }) + return conn +} + +func injectIdentityInterceptor(t testing.TB) grpc.UnaryServerInterceptor { + return func(ctx context.Context, req any, _ *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) { + ctx = authn.ContextWithIdentity(ctx, fakeIdentity{}, t) + return handler(ctx, req) + } +} + +func injectVersionHeaderInterceptor(t testing.TB, centralVersion string) grpc.UnaryServerInterceptor { + return func(ctx context.Context, req any, _ *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) { + require.NoError(t, grpc.SetHeader(ctx, metadata.Pairs(clientconn.CentralVersionHeader, centralVersion))) + return handler(ctx, req) + } +} diff --git a/roxctl/maincommand/command.go b/roxctl/maincommand/command.go index e30cc43e1fc96..44fb99c00e3e2 100644 --- a/roxctl/maincommand/command.go +++ b/roxctl/maincommand/command.go @@ -9,6 +9,7 @@ import ( "github.com/stackrox/rox/pkg/buildinfo" "github.com/stackrox/rox/pkg/env" "github.com/stackrox/rox/pkg/version" + "github.com/stackrox/rox/pkg/version/versioncompatibility" "github.com/stackrox/rox/roxctl/central" "github.com/stackrox/rox/roxctl/cluster" "github.com/stackrox/rox/roxctl/collector" @@ -27,6 +28,11 @@ import ( "github.com/stackrox/rox/roxctl/sensor" ) +type roxctlVersionInfo struct { + version.Versions + CompatibleCentralVersions []string `json:"CompatibleCentralVersions,omitempty"` +} + func versionCommand(cliEnvironment environment.Environment) *cobra.Command { c := &cobra.Command{ Use: "version", @@ -36,11 +42,15 @@ func versionCommand(cliEnvironment environment.Environment) *cobra.Command { if useJSON, _ := c.Flags().GetBool("json"); useJSON { enc := json.NewEncoder(cliEnvironment.InputOutput().Out()) enc.SetIndent("", " ") - versions := version.GetAllVersionsDevelopment() + base := version.GetAllVersionsDevelopment() if buildinfo.ReleaseBuild { - versions = version.GetAllVersionsUnified() + base = version.GetAllVersionsUnified() + } + v := roxctlVersionInfo{ + Versions: base, + CompatibleCentralVersions: compatibleVersionStrings(), } - return errors.Wrap(enc.Encode(versions), "could not encode version") + return errors.Wrap(enc.Encode(v), "could not encode version") } cliEnvironment.Logger().PrintfLn(version.GetMainVersion()) return nil @@ -51,6 +61,16 @@ func versionCommand(cliEnvironment environment.Environment) *cobra.Command { return c } +func compatibleVersionStrings() []string { + // Ignoring error because it's handled inside the function. + versions, _ := versioncompatibility.CompatibleVersions() + result := make([]string, 0, len(versions)) + for _, v := range versions { + result = append(result, v.String()) + } + return result +} + // Command constructs and returns the roxctl command tree func Command() *cobra.Command { c := &cobra.Command{ diff --git a/roxctl/maincommand/command_test.go b/roxctl/maincommand/command_test.go index 2de6a4002b860..743f8258a49ba 100644 --- a/roxctl/maincommand/command_test.go +++ b/roxctl/maincommand/command_test.go @@ -1,12 +1,17 @@ package maincommand import ( + "encoding/json" "fmt" "strings" "testing" "github.com/spf13/cobra" "github.com/spf13/pflag" + versiontestutils "github.com/stackrox/rox/pkg/version/testutils" + "github.com/stackrox/rox/roxctl/common/environment" + cliIO "github.com/stackrox/rox/roxctl/common/io" + "github.com/stackrox/rox/roxctl/common/printer" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.yaml.in/yaml/v3" @@ -141,3 +146,32 @@ func Test_commandTree(t *testing.T) { assert.NotEmpty(t, commandTreeFilename, result) assert.Equal(t, commandTree, result) } + +// Deploy scripts and external tooling parse "roxctl version" output expecting +// a single line containing only the version string. Adding extra lines or +// content breaks version-match checks and causes deployment failures. +func TestVersionCommand_TextOutput_SingleVersionLine(t *testing.T) { + versiontestutils.SetMainVersion(t, "5.0.0") + + testIO, _, out, _ := cliIO.TestIO() + env := environment.NewTestCLIEnvironment(t, testIO, printer.DefaultColorPrinter()) + cmd := versionCommand(env) + require.NoError(t, cmd.Execute()) + + assert.Equal(t, "5.0.0\n", out.String()) +} + +func TestVersionCommand_JSONOutput_IncludesCompatibleVersions(t *testing.T) { + versiontestutils.SetMainVersion(t, "5.0.0") + + testIO, _, out, _ := cliIO.TestIO() + env := environment.NewTestCLIEnvironment(t, testIO, printer.DefaultColorPrinter()) + cmd := versionCommand(env) + cmd.SetArgs([]string{"--json"}) + require.NoError(t, cmd.Execute()) + + var result roxctlVersionInfo + require.NoError(t, json.Unmarshal(out.Bytes(), &result)) + assert.Equal(t, "5.0.0", result.MainVersion) + assert.NotEmpty(t, result.CompatibleCentralVersions) +} diff --git a/rpms.in.yaml b/rpms.in.yaml index 8df6cca8fdb6a..ee1616dcd4c38 100644 --- a/rpms.in.yaml +++ b/rpms.in.yaml @@ -19,7 +19,7 @@ packages: - tar moduleEnable: # final stage in image/rhel/konflux.Dockerfile -- postgresql:15 +- postgresql:16 contentOrigin: repofiles: [ "rpms.rhel.repo" ] context: diff --git a/rpms.lock.yaml b/rpms.lock.yaml index c282d700c4b1c..3263e010852b7 100644 --- a/rpms.lock.yaml +++ b/rpms.lock.yaml @@ -18,13 +18,13 @@ arches: name: delve evr: 1.26.1-1.el9_8 sourcerpm: delve-1.26.1-1.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/appstream/os/Packages/g/gawk-all-langpacks-5.1.0-6.el9.aarch64.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/appstream/os/Packages/g/gawk-all-langpacks-5.1.0-6.el9_8.1.aarch64.rpm repoid: rhel-9-for-aarch64-appstream-rpms - size: 216292 - checksum: sha256:3fd73bd271e9c04dc297eb08c3829d276faee372f77666aad29f4b676ea220f4 + size: 218086 + checksum: sha256:d38712f7aa4e5b3821ba899d6b4f62821407f6f239e17bf240ca488fb1d35376 name: gawk-all-langpacks - evr: 5.1.0-6.el9 - sourcerpm: gawk-5.1.0-6.el9.src.rpm + evr: 5.1.0-6.el9_8.1 + sourcerpm: gawk-5.1.0-6.el9_8.1.src.rpm - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/appstream/os/Packages/g/gcc-11.5.0-14.el9.aarch64.rpm repoid: rhel-9-for-aarch64-appstream-rpms size: 31291354 @@ -32,55 +32,55 @@ arches: name: gcc evr: 11.5.0-14.el9 sourcerpm: gcc-11.5.0-14.el9.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/appstream/os/Packages/g/glibc-devel-2.34-275.el9_8.aarch64.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/appstream/os/Packages/g/glibc-devel-2.34-283.el9_8.aarch64.rpm repoid: rhel-9-for-aarch64-appstream-rpms - size: 576947 - checksum: sha256:aef79b53955c2ec67efdc39cb91148b377f8719a8b68cf76c7ddcffbcb6b8bf0 + size: 577250 + checksum: sha256:b363f894683abf7076596ea8d67269eb878d2724d9447e6b3f4c6409650cefd2 name: glibc-devel - evr: 2.34-275.el9_8 - sourcerpm: glibc-2.34-275.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/appstream/os/Packages/g/go-toolset-1.26.7-1.el9_8.aarch64.rpm + evr: 2.34-283.el9_8 + sourcerpm: glibc-2.34-283.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/appstream/os/Packages/g/go-toolset-1.26.7-2.el9_8.aarch64.rpm repoid: rhel-9-for-aarch64-appstream-rpms - size: 12361 - checksum: sha256:7c4e8b7e0647a459b3b04e9deb17b6d5d02a43fa1bff0e8dc782f48e08fccd30 + size: 12453 + checksum: sha256:3d9ec6b63182ed0120fad760a8fc20a4bfa05e96134b4cc5c6fe42b9f85ec9c5 name: go-toolset - evr: 1.26.7-1.el9_8 - sourcerpm: golang-1.26.7-1.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/appstream/os/Packages/g/golang-1.26.7-1.el9_8.aarch64.rpm + evr: 1.26.7-2.el9_8 + sourcerpm: golang-1.26.7-2.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/appstream/os/Packages/g/golang-1.26.7-2.el9_8.aarch64.rpm repoid: rhel-9-for-aarch64-appstream-rpms - size: 1520214 - checksum: sha256:2f1b635e07c0f74ac53e9a79e28e287ae47742599deec1138aa7a27f94b4d5c9 + size: 1520141 + checksum: sha256:27c00a1943d2e5c5e3a19308f6b8650e3740d784e8dc7e4aa0036693c958b1c4 name: golang - evr: 1.26.7-1.el9_8 - sourcerpm: golang-1.26.7-1.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/appstream/os/Packages/g/golang-bin-1.26.7-1.el9_8.aarch64.rpm + evr: 1.26.7-2.el9_8 + sourcerpm: golang-1.26.7-2.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/appstream/os/Packages/g/golang-bin-1.26.7-2.el9_8.aarch64.rpm repoid: rhel-9-for-aarch64-appstream-rpms - size: 42741902 - checksum: sha256:aff04f0bea0253c15c37d1f008d2826884cfdc401714c0d884c3172f2affce01 + size: 42755650 + checksum: sha256:4a3e09bbf75a009a9e4ef2b0f2703b517353335f9113d22f3562886390c13eb4 name: golang-bin - evr: 1.26.7-1.el9_8 - sourcerpm: golang-1.26.7-1.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/appstream/os/Packages/g/golang-race-1.26.7-1.el9_8.aarch64.rpm + evr: 1.26.7-2.el9_8 + sourcerpm: golang-1.26.7-2.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/appstream/os/Packages/g/golang-race-1.26.7-2.el9_8.aarch64.rpm repoid: rhel-9-for-aarch64-appstream-rpms - size: 1743223 - checksum: sha256:cb3fed044deab06fcf00a3426b635f4562cdfd6f5937912d9e2a854b88498c72 + size: 1743339 + checksum: sha256:80c03d0c817e3f37bae189287bb6b42fc18dcadeb22c90e57f01d6ecbceec4a7 name: golang-race - evr: 1.26.7-1.el9_8 - sourcerpm: golang-1.26.7-1.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/appstream/os/Packages/g/golang-src-1.26.7-1.el9_8.noarch.rpm + evr: 1.26.7-2.el9_8 + sourcerpm: golang-1.26.7-2.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/appstream/os/Packages/g/golang-src-1.26.7-2.el9_8.noarch.rpm repoid: rhel-9-for-aarch64-appstream-rpms - size: 12881267 - checksum: sha256:b570b95df0bc6429486a71a10fb433f56bb3a694f5de8a777131b2a841e81181 + size: 12879471 + checksum: sha256:ff54c6f194fcf25d743af1af7893242085c798b7ce04056066fee993c2167166 name: golang-src - evr: 1.26.7-1.el9_8 - sourcerpm: golang-1.26.7-1.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/appstream/os/Packages/k/kernel-headers-5.14.0-687.46.1.el9_8.aarch64.rpm + evr: 1.26.7-2.el9_8 + sourcerpm: golang-1.26.7-2.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/appstream/os/Packages/k/kernel-headers-5.14.0-687.57.1.el9_8.aarch64.rpm repoid: rhel-9-for-aarch64-appstream-rpms - size: 2882381 - checksum: sha256:c99d6e379176e2617942bbb1b429f58377a74930af88ed24e9d85f3d53d75fb0 + size: 2939977 + checksum: sha256:31860419149438987e706dd2929fbc707552cd2e51dbc86547d294f9fed5f204 name: kernel-headers - evr: 5.14.0-687.46.1.el9_8 - sourcerpm: kernel-5.14.0-687.46.1.el9_8.src.rpm + evr: 5.14.0-687.57.1.el9_8 + sourcerpm: kernel-5.14.0-687.57.1.el9_8.src.rpm - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/appstream/os/Packages/l/libasan-11.5.0-14.el9.aarch64.rpm repoid: rhel-9-for-aarch64-appstream-rpms size: 409047 @@ -130,41 +130,41 @@ arches: name: mpdecimal evr: 2.5.1-3.el9 sourcerpm: mpdecimal-2.5.1-3.el9.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/appstream/os/Packages/o/openssl-devel-3.5.5-6.el9_8.aarch64.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/appstream/os/Packages/o/openssl-devel-3.5.8-2.el9_8.aarch64.rpm repoid: rhel-9-for-aarch64-appstream-rpms - size: 5028889 - checksum: sha256:c92e750163820a817ca5562935010872f8db5ca5712a517b01beafcb87221670 + size: 5049780 + checksum: sha256:7ae4c2948a7e30ad50c399558b1af9be4055de267eb8de1d1757e12b2776e3ef name: openssl-devel - evr: 1:3.5.5-6.el9_8 - sourcerpm: openssl-3.5.5-6.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/appstream/os/Packages/p/postgresql-15.18-1.module+el9.8.0+24358+32c5830e.aarch64.rpm + evr: 1:3.5.8-2.el9_8 + sourcerpm: openssl-3.5.8-2.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/appstream/os/Packages/p/postgresql-16.15-1.module+el9.8.0+24803+9dca000b.aarch64.rpm repoid: rhel-9-for-aarch64-appstream-rpms - size: 1819455 - checksum: sha256:9a533624ca7110176ccfedbd4ec54d339fadeeb985f7016eed7e4e738dd44ed2 + size: 2049624 + checksum: sha256:5295a9a347f24655946ca8870d76cc7acdaa96c1e631a6880193576e92061d27 name: postgresql - evr: 15.18-1.module+el9.8.0+24358+32c5830e - sourcerpm: postgresql-15.18-1.module+el9.8.0+24358+32c5830e.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/appstream/os/Packages/p/postgresql-private-libs-15.18-1.module+el9.8.0+24358+32c5830e.aarch64.rpm + evr: 16.15-1.module+el9.8.0+24803+9dca000b + sourcerpm: postgresql-16.15-1.module+el9.8.0+24803+9dca000b.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/appstream/os/Packages/p/postgresql-private-libs-16.15-1.module+el9.8.0+24803+9dca000b.aarch64.rpm repoid: rhel-9-for-aarch64-appstream-rpms - size: 149345 - checksum: sha256:7168e8dc1147af4fe2033ddaa86418321f850c746c1a92f7aa0e5416b2b37ced + size: 149710 + checksum: sha256:e4b9f9f73ee8986c64148b838c9a32492d75e4c6352810542952a8126eaa31ef name: postgresql-private-libs - evr: 15.18-1.module+el9.8.0+24358+32c5830e - sourcerpm: postgresql-15.18-1.module+el9.8.0+24358+32c5830e.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/appstream/os/Packages/p/python3.12-3.12.14-1.el9_8.aarch64.rpm + evr: 16.15-1.module+el9.8.0+24803+9dca000b + sourcerpm: postgresql-16.15-1.module+el9.8.0+24803+9dca000b.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/appstream/os/Packages/p/python3.12-3.12.15-1.el9_8.aarch64.rpm repoid: rhel-9-for-aarch64-appstream-rpms - size: 32440 - checksum: sha256:127b8467e15c3f233d87bdb85c57809332eefb2e7b483aca7a08790dd9b62b74 + size: 32621 + checksum: sha256:9097113ea007073e718b55da7ea5d33f5ee5ce0e5f7b0b04beb706872d5968a4 name: python3.12 - evr: 3.12.14-1.el9_8 - sourcerpm: python3.12-3.12.14-1.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/appstream/os/Packages/p/python3.12-libs-3.12.14-1.el9_8.aarch64.rpm + evr: 3.12.15-1.el9_8 + sourcerpm: python3.12-3.12.15-1.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/appstream/os/Packages/p/python3.12-libs-3.12.15-1.el9_8.aarch64.rpm repoid: rhel-9-for-aarch64-appstream-rpms - size: 10145691 - checksum: sha256:cca9ebdb4242036911ccc7271de7cb9e3d621c152b402f781ae22b700ab02231 + size: 10154341 + checksum: sha256:f0b73d057827f2380f50f3bc9459298cc103da8b333eefc5cacd3865087b4ee1 name: python3.12-libs - evr: 3.12.14-1.el9_8 - sourcerpm: python3.12-3.12.14-1.el9_8.src.rpm + evr: 3.12.15-1.el9_8 + sourcerpm: python3.12-3.12.15-1.el9_8.src.rpm - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/appstream/os/Packages/p/python3.12-pip-wheel-23.2.1-5.el9.noarch.rpm repoid: rhel-9-for-aarch64-appstream-rpms size: 1527128 @@ -340,13 +340,13 @@ arches: name: elfutils-libs evr: 0.194-1.el9 sourcerpm: elfutils-0.194-1.el9.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/os/Packages/e/expat-2.5.0-6.el9_8.3.aarch64.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/os/Packages/e/expat-2.5.0-6.el9_8.5.aarch64.rpm repoid: rhel-9-for-aarch64-baseos-rpms - size: 122400 - checksum: sha256:df004398da989f75bae9267cfb0ad402ada6e6db46ebef0932c869894c013c08 + size: 122957 + checksum: sha256:d13bd77f429835b303d388e24811fb935060be4788c8fe4cf87703640f2337e0 name: expat - evr: 2.5.0-6.el9_8.3 - sourcerpm: expat-2.5.0-6.el9_8.3.src.rpm + evr: 2.5.0-6.el9_8.5 + sourcerpm: expat-2.5.0-6.el9_8.5.src.rpm - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/os/Packages/f/filesystem-3.16-5.el9.aarch64.rpm repoid: rhel-9-for-aarch64-baseos-rpms size: 5003914 @@ -361,13 +361,13 @@ arches: name: findutils evr: 1:4.8.0-7.el9 sourcerpm: findutils-4.8.0-7.el9.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/os/Packages/g/gawk-5.1.0-6.el9.aarch64.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/os/Packages/g/gawk-5.1.0-6.el9_8.1.aarch64.rpm repoid: rhel-9-for-aarch64-baseos-rpms - size: 1024204 - checksum: sha256:a4b7202ac90653a7d3e072c2444bde6a9270d6a818eb6f2ffcfcaa50774f1fad + size: 1026105 + checksum: sha256:54365d2a6150079c2dc5003eeb94ada32fc15801b5db05422361f02ed58e6772 name: gawk - evr: 5.1.0-6.el9 - sourcerpm: gawk-5.1.0-6.el9.src.rpm + evr: 5.1.0-6.el9_8.1 + sourcerpm: gawk-5.1.0-6.el9_8.1.src.rpm - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/os/Packages/g/gdbm-libs-1.23-1.el9.aarch64.rpm repoid: rhel-9-for-aarch64-baseos-rpms size: 60311 @@ -375,34 +375,34 @@ arches: name: gdbm-libs evr: 1:1.23-1.el9 sourcerpm: gdbm-1.23-1.el9.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/os/Packages/g/glibc-2.34-275.el9_8.aarch64.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/os/Packages/g/glibc-2.34-283.el9_8.aarch64.rpm repoid: rhel-9-for-aarch64-baseos-rpms - size: 1813928 - checksum: sha256:e40a78100f731b5f5a1b235880a0aaad5b08bb32e6521e90535b7f4a94c6e9e9 + size: 1814330 + checksum: sha256:76611b8d5d56730d15142d62b85e83731f5c199523b40a31da5250f81ec66d3c name: glibc - evr: 2.34-275.el9_8 - sourcerpm: glibc-2.34-275.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/os/Packages/g/glibc-common-2.34-275.el9_8.aarch64.rpm + evr: 2.34-283.el9_8 + sourcerpm: glibc-2.34-283.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/os/Packages/g/glibc-common-2.34-283.el9_8.aarch64.rpm repoid: rhel-9-for-aarch64-baseos-rpms - size: 312665 - checksum: sha256:24e1c7189d101531c526dd3cc1a42ab62d89f874824b54fb6b518ec24f190554 + size: 312943 + checksum: sha256:a3cbba6c367d316bb1738bab6ac3e3e1c9423fa642faf8365b39a23a7b067768 name: glibc-common - evr: 2.34-275.el9_8 - sourcerpm: glibc-2.34-275.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/os/Packages/g/glibc-gconv-extra-2.34-275.el9_8.aarch64.rpm + evr: 2.34-283.el9_8 + sourcerpm: glibc-2.34-283.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/os/Packages/g/glibc-gconv-extra-2.34-283.el9_8.aarch64.rpm repoid: rhel-9-for-aarch64-baseos-rpms - size: 1829737 - checksum: sha256:7f2f23c07b84b3cd3bacb905dffaca4f4474298e936f3b10b93390d4127591da + size: 1831695 + checksum: sha256:15321958afc2a83349b084df59bdf272ee447ea98b384fdfec57e5c589fa143c name: glibc-gconv-extra - evr: 2.34-275.el9_8 - sourcerpm: glibc-2.34-275.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/os/Packages/g/glibc-minimal-langpack-2.34-275.el9_8.aarch64.rpm + evr: 2.34-283.el9_8 + sourcerpm: glibc-2.34-283.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/os/Packages/g/glibc-minimal-langpack-2.34-283.el9_8.aarch64.rpm repoid: rhel-9-for-aarch64-baseos-rpms - size: 30881 - checksum: sha256:b1348c4c4fe3da979f342b0c27ff0d33a11688274a0b6708292d7750bbc8d853 + size: 31033 + checksum: sha256:422d151f31a9fea5dd99aa7bb218c2932d64386f5daa3a8af0827183dc1beb39 name: glibc-minimal-langpack - evr: 2.34-275.el9_8 - sourcerpm: glibc-2.34-275.el9_8.src.rpm + evr: 2.34-283.el9_8 + sourcerpm: glibc-2.34-283.el9_8.src.rpm - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/os/Packages/g/gmp-6.2.0-13.el9.aarch64.rpm repoid: rhel-9-for-aarch64-baseos-rpms size: 275679 @@ -494,13 +494,13 @@ arches: name: libblkid evr: 2.37.4-25.el9 sourcerpm: util-linux-2.37.4-25.el9.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/os/Packages/l/libbrotli-1.0.9-9.el9_7.aarch64.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/os/Packages/l/libbrotli-1.0.9-10.el9_8.aarch64.rpm repoid: rhel-9-for-aarch64-baseos-rpms - size: 325179 - checksum: sha256:f5237abc90191238333c1214da97b5202c8a15c2be3ab401ee10d95343cfdf17 + size: 325419 + checksum: sha256:04d157b138153dcd27c04d81ae985e8190ddc542d63620f3d1ae0a690a1041b7 name: libbrotli - evr: 1.0.9-9.el9_7 - sourcerpm: brotli-1.0.9-9.el9_7.src.rpm + evr: 1.0.9-10.el9_8 + sourcerpm: brotli-1.0.9-10.el9_8.src.rpm - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/os/Packages/l/libcap-2.48-10.el9_8.1.aarch64.rpm repoid: rhel-9-for-aarch64-baseos-rpms size: 78021 @@ -522,13 +522,13 @@ arches: name: libcom_err evr: 1.46.5-8.el9 sourcerpm: e2fsprogs-1.46.5-8.el9.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/os/Packages/l/libcurl-7.76.1-40.el9_8.5.aarch64.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/os/Packages/l/libcurl-7.76.1-40.el9_8.8.aarch64.rpm repoid: rhel-9-for-aarch64-baseos-rpms - size: 292322 - checksum: sha256:ea6c3ade86939df7a985ae71e4c5100731962add54295fd40660a2f2c2f85f1d + size: 293076 + checksum: sha256:a7ec72530e41371da4984e19c93168de6a911067d2bb597dec1e3bbe48e179a8 name: libcurl - evr: 7.76.1-40.el9_8.5 - sourcerpm: curl-7.76.1-40.el9_8.5.src.rpm + evr: 7.76.1-40.el9_8.8 + sourcerpm: curl-7.76.1-40.el9_8.8.src.rpm - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/os/Packages/l/libdb-5.3.28-57.el9_6.aarch64.rpm repoid: rhel-9-for-aarch64-baseos-rpms size: 727417 @@ -543,13 +543,13 @@ arches: name: libeconf evr: 0.4.1-7.el9_8 sourcerpm: libeconf-0.4.1-7.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/os/Packages/l/libevent-2.1.12-8.el9_4.aarch64.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/os/Packages/l/libevent-2.1.13-1.el9_8.aarch64.rpm repoid: rhel-9-for-aarch64-baseos-rpms - size: 265763 - checksum: sha256:0858687ac9d55a0db78ecc4f669ad21ccba6815744457d135f5a313898dfcab7 + size: 268476 + checksum: sha256:27a85302d64c15bfd383929eedcdeabef9bfc8f0a1e085b0501d0de73cb2bf74 name: libevent - evr: 2.1.12-8.el9_4 - sourcerpm: libevent-2.1.12-8.el9_4.src.rpm + evr: 2.1.13-1.el9_8 + sourcerpm: libevent-2.1.13-1.el9_8.src.rpm - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/os/Packages/l/libfdisk-2.37.4-25.el9.aarch64.rpm repoid: rhel-9-for-aarch64-baseos-rpms size: 156711 @@ -809,13 +809,13 @@ arches: name: openldap evr: 2.6.8-4.el9 sourcerpm: openldap-2.6.8-4.el9.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/os/Packages/o/openssl-3.5.5-6.el9_8.aarch64.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/os/Packages/o/openssl-3.5.8-2.el9_8.aarch64.rpm repoid: rhel-9-for-aarch64-baseos-rpms - size: 1541002 - checksum: sha256:9f10be36d0d532c65a3f9a41f7d0cd3190b0b908f60850862cc24cab06cd1101 + size: 1546093 + checksum: sha256:f625d004eb04013ac83037d7b6b77a100d54706de8d9a9c8a6d39d907169bbf8 name: openssl - evr: 1:3.5.5-6.el9_8 - sourcerpm: openssl-3.5.5-6.el9_8.src.rpm + evr: 1:3.5.8-2.el9_8 + sourcerpm: openssl-3.5.8-2.el9_8.src.rpm - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/os/Packages/o/openssl-fips-provider-3.0.7-11.el9_8.aarch64.rpm repoid: rhel-9-for-aarch64-baseos-rpms size: 14220 @@ -830,13 +830,13 @@ arches: name: openssl-fips-provider-so evr: 3.0.7-11.el9_8 sourcerpm: openssl-fips-provider-3.0.7-11.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/os/Packages/o/openssl-libs-3.5.5-6.el9_8.aarch64.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/os/Packages/o/openssl-libs-3.5.8-2.el9_8.aarch64.rpm repoid: rhel-9-for-aarch64-baseos-rpms - size: 2290581 - checksum: sha256:9af799c6be853cb42999a1228a2768da20a21895b7dcac111dba3be13a397b67 + size: 2294447 + checksum: sha256:89aa84e734616240e7541b8095c2f2c2cd9c114e98b345042f5276d03781180b name: openssl-libs - evr: 1:3.5.5-6.el9_8 - sourcerpm: openssl-3.5.5-6.el9_8.src.rpm + evr: 1:3.5.8-2.el9_8 + sourcerpm: openssl-3.5.8-2.el9_8.src.rpm - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/os/Packages/p/p11-kit-0.26.4-1.el9_8.aarch64.rpm repoid: rhel-9-for-aarch64-baseos-rpms size: 589112 @@ -865,20 +865,20 @@ arches: name: pcre evr: 8.44-4.el9 sourcerpm: pcre-8.44-4.el9.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/os/Packages/p/pcre2-10.40-6.el9.aarch64.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/os/Packages/p/pcre2-10.40-7.el9_8.aarch64.rpm repoid: rhel-9-for-aarch64-baseos-rpms - size: 224938 - checksum: sha256:29285f81cef68f73b4f8ff81ee8fdf4ceaa007933302119ed1615e4aa1091613 + size: 227991 + checksum: sha256:40fd0cd92f4cf824fb5186128d360bdc0a8a9f70c9f820b8c0efda4afec75cc8 name: pcre2 - evr: 10.40-6.el9 - sourcerpm: pcre2-10.40-6.el9.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/os/Packages/p/pcre2-syntax-10.40-6.el9.noarch.rpm + evr: 10.40-7.el9_8 + sourcerpm: pcre2-10.40-7.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/os/Packages/p/pcre2-syntax-10.40-7.el9_8.noarch.rpm repoid: rhel-9-for-aarch64-baseos-rpms - size: 147926 - checksum: sha256:d386b5e9b3a4b077b2ba143882e605750855dd3354f13c55fa12ed26908cb442 + size: 150069 + checksum: sha256:e7466a43ef2bfda2b1dc07e855b0db743d48b11c0bdc1402e1d2ea6fb23d33a3 name: pcre2-syntax - evr: 10.40-6.el9 - sourcerpm: pcre2-10.40-6.el9.src.rpm + evr: 10.40-7.el9_8 + sourcerpm: pcre2-10.40-7.el9_8.src.rpm - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/os/Packages/p/pigz-2.8-1.el9.aarch64.rpm repoid: rhel-9-for-aarch64-baseos-rpms size: 93525 @@ -963,34 +963,34 @@ arches: name: sqlite-libs evr: 3.34.1-11.el9_8 sourcerpm: sqlite-3.34.1-11.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/os/Packages/s/systemd-252-67.el9_8.4.aarch64.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/os/Packages/s/systemd-252-67.el9_8.6.aarch64.rpm repoid: rhel-9-for-aarch64-baseos-rpms - size: 4156431 - checksum: sha256:f49001c208ea0ec7776b2353800f133d3383e72bda8486132dc6822a803aef9f + size: 4135917 + checksum: sha256:758ae3df6d76cace670ce7af7caa557a7cf8807a2160ccb30c49f7d8ec018749 name: systemd - evr: 252-67.el9_8.4 - sourcerpm: systemd-252-67.el9_8.4.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/os/Packages/s/systemd-libs-252-67.el9_8.4.aarch64.rpm + evr: 252-67.el9_8.6 + sourcerpm: systemd-252-67.el9_8.6.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/os/Packages/s/systemd-libs-252-67.el9_8.6.aarch64.rpm repoid: rhel-9-for-aarch64-baseos-rpms - size: 647617 - checksum: sha256:78f8f784050b920675ce5d37d659213226265dd72de14ec10df291afae59d8b7 + size: 629233 + checksum: sha256:55e58c413ee69f19a69ba25905f96343076e21abe54cdff51f0d80e48be06769 name: systemd-libs - evr: 252-67.el9_8.4 - sourcerpm: systemd-252-67.el9_8.4.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/os/Packages/s/systemd-pam-252-67.el9_8.4.aarch64.rpm + evr: 252-67.el9_8.6 + sourcerpm: systemd-252-67.el9_8.6.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/os/Packages/s/systemd-pam-252-67.el9_8.6.aarch64.rpm repoid: rhel-9-for-aarch64-baseos-rpms - size: 266579 - checksum: sha256:e85f1916e5fc35f483282c2de00cb4e1a9a40743e745c00bb66e30e383955d46 + size: 247880 + checksum: sha256:736a6bbb73b0ef682ddfe356bb49578c2a8f17c6685ca762fcc1636003a4f5f3 name: systemd-pam - evr: 252-67.el9_8.4 - sourcerpm: systemd-252-67.el9_8.4.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/os/Packages/s/systemd-rpm-macros-252-67.el9_8.4.noarch.rpm + evr: 252-67.el9_8.6 + sourcerpm: systemd-252-67.el9_8.6.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/os/Packages/s/systemd-rpm-macros-252-67.el9_8.6.noarch.rpm repoid: rhel-9-for-aarch64-baseos-rpms - size: 59475 - checksum: sha256:7d671ec39a7caeb7346be6d5fcb44212545844ced6f4974c4b409fef6a12a891 + size: 40844 + checksum: sha256:974a0352427799559a3e90dcdb38200d767631452cca7717c5b0fbe7760df313 name: systemd-rpm-macros - evr: 252-67.el9_8.4 - sourcerpm: systemd-252-67.el9_8.4.src.rpm + evr: 252-67.el9_8.6 + sourcerpm: systemd-252-67.el9_8.6.src.rpm - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/os/Packages/t/tar-1.34-13.el9_8.aarch64.rpm repoid: rhel-9-for-aarch64-baseos-rpms size: 909271 @@ -998,13 +998,13 @@ arches: name: tar evr: 2:1.34-13.el9_8 sourcerpm: tar-1.34-13.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/os/Packages/t/tzdata-2026c-1.el9_8.noarch.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/os/Packages/t/tzdata-2026e-1.el9_8.noarch.rpm repoid: rhel-9-for-aarch64-baseos-rpms - size: 933286 - checksum: sha256:8d6196e02853c0900c3c2e2367665beffb62cb2d0ff5f465ea2d00848a9a35dc + size: 936099 + checksum: sha256:c105d92f6cacb9bb8337b77041cedd9c9c906a72c4b5233909b9b69b78f4369f name: tzdata - evr: 2026c-1.el9_8 - sourcerpm: tzdata-2026c-1.el9_8.src.rpm + evr: 2026e-1.el9_8 + sourcerpm: tzdata-2026e-1.el9_8.src.rpm - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/os/Packages/u/util-linux-2.37.4-25.el9.aarch64.rpm repoid: rhel-9-for-aarch64-baseos-rpms size: 2390152 @@ -1040,12 +1040,12 @@ arches: checksum: sha256:5fa267daa0e7df3e072c17e81db41b809b256da8cfb0372669d9a1bea937a01a name: delve evr: 1.26.1-1.el9_8 - - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/appstream/source/SRPMS/Packages/g/golang-1.26.7-1.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/appstream/source/SRPMS/Packages/g/golang-1.26.7-2.el9_8.src.rpm repoid: rhel-9-for-aarch64-appstream-source-rpms - size: 36535123 - checksum: sha256:3e46d00b71773429b84079992fff32610eda8917d7319d09c3cee5e6e4bd5bf5 + size: 36539286 + checksum: sha256:7a9ea792be9d09b61bc321ce8b65a040430d06891d6372aeb929753c2f270770 name: golang - evr: 1.26.7-1.el9_8 + evr: 1.26.7-2.el9_8 - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/appstream/source/SRPMS/Packages/l/libmpc-1.2.1-4.el9.src.rpm repoid: rhel-9-for-aarch64-appstream-source-rpms size: 846236 @@ -1070,18 +1070,18 @@ arches: checksum: sha256:2f5ece89d6a8d892816f386462d8be291ad83f1500b4c4b3655dcc7ed5192c0d name: mpdecimal evr: 2.5.1-3.el9 - - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/appstream/source/SRPMS/Packages/p/postgresql-15.18-1.module+el9.8.0+24358+32c5830e.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/appstream/source/SRPMS/Packages/p/postgresql-16.15-1.module+el9.8.0+24803+9dca000b.src.rpm repoid: rhel-9-for-aarch64-appstream-source-rpms - size: 45775054 - checksum: sha256:5955f781730fe817b08b7ddc3d2117a7c0a0c95ed2fd2044cbc1ff7d1eba1b28 + size: 48516429 + checksum: sha256:fdb3a4e84c097bb87061fbf6b3f1f11a03b4aa6adf13b0b20cc1d439b5a2c7d7 name: postgresql - evr: 15.18-1.module+el9.8.0+24358+32c5830e - - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/appstream/source/SRPMS/Packages/p/python3.12-3.12.14-1.el9_8.src.rpm + evr: 16.15-1.module+el9.8.0+24803+9dca000b + - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/appstream/source/SRPMS/Packages/p/python3.12-3.12.15-1.el9_8.src.rpm repoid: rhel-9-for-aarch64-appstream-source-rpms - size: 20894742 - checksum: sha256:d855a90132b827b528e26c617484c250fd02dbe2cc8fdb8ef1f7d0d0a9f3f4f7 + size: 20904561 + checksum: sha256:8a3db1154cbfe206ac68b31268348da6039522d09be22520dd94207417146ebd name: python3.12 - evr: 3.12.14-1.el9_8 + evr: 3.12.15-1.el9_8 - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/appstream/source/SRPMS/Packages/p/python3.12-pip-23.2.1-5.el9.src.rpm repoid: rhel-9-for-aarch64-appstream-source-rpms size: 9384965 @@ -1130,12 +1130,12 @@ arches: checksum: sha256:82174416ee39df7795da7fab8d37ea5dbbe25f1dbc2df39f5fb3f8a168bf5120 name: binutils evr: 2.35.2-72.el9 - - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/source/SRPMS/Packages/b/brotli-1.0.9-9.el9_7.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/source/SRPMS/Packages/b/brotli-1.0.9-10.el9_8.src.rpm repoid: rhel-9-for-aarch64-baseos-source-rpms - size: 517498 - checksum: sha256:814868e0bec831c79d3e12ff76d31e06e5e62c462a1a4b6607b1f3cab7014438 + size: 519221 + checksum: sha256:c833ffbd6c6555543472ef4034a958cf4b8b8dee35b8661b2144ca6fc38908c7 name: brotli - evr: 1.0.9-9.el9_7 + evr: 1.0.9-10.el9_8 - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/source/SRPMS/Packages/b/bzip2-1.0.8-11.el9.src.rpm repoid: rhel-9-for-aarch64-baseos-source-rpms size: 828199 @@ -1172,12 +1172,12 @@ arches: checksum: sha256:775d926429179caeade6af8dc7dea15a0bea49102c2592d5b712f996a329ec38 name: crypto-policies evr: 20260224-1.gitea0f072.el9_8 - - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/source/SRPMS/Packages/c/curl-7.76.1-40.el9_8.5.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/source/SRPMS/Packages/c/curl-7.76.1-40.el9_8.8.src.rpm repoid: rhel-9-for-aarch64-baseos-source-rpms - size: 2576796 - checksum: sha256:5a455f6c35ae1069b8c54ade4c9d0d3d260134f76bee10f22efef9683c31b03f + size: 2581541 + checksum: sha256:303a97cbdfaaac1d709ef7621b2b349dc403da6a553ecfe5e3114f76d757d554 name: curl - evr: 7.76.1-40.el9_8.5 + evr: 7.76.1-40.el9_8.8 - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/source/SRPMS/Packages/c/cyrus-sasl-2.1.27-22.el9.src.rpm repoid: rhel-9-for-aarch64-baseos-source-rpms size: 4025677 @@ -1214,12 +1214,12 @@ arches: checksum: sha256:643279e796ded16c5be5cdc2a91839c787e62e59757008675eb0580a4a42af21 name: elfutils evr: 0.194-1.el9 - - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/source/SRPMS/Packages/e/expat-2.5.0-6.el9_8.3.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/source/SRPMS/Packages/e/expat-2.5.0-6.el9_8.5.src.rpm repoid: rhel-9-for-aarch64-baseos-source-rpms - size: 8403095 - checksum: sha256:0cff2a2213384dc43eb1874bf6e77b2b8230be848f50387d8057e0e6cde3d392 + size: 8411609 + checksum: sha256:38d7acfd1130c02c6a00010159a1350ca0f56cd7ed64f3d8394aa5b3d6512ddd name: expat - evr: 2.5.0-6.el9_8.3 + evr: 2.5.0-6.el9_8.5 - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/source/SRPMS/Packages/f/filesystem-3.16-5.el9.src.rpm repoid: rhel-9-for-aarch64-baseos-source-rpms size: 20486 @@ -1232,12 +1232,12 @@ arches: checksum: sha256:48bd4d4dd081120bcc6ab772b930a150f30b2fc89a4a14a24220383d24a30b3f name: findutils evr: 1:4.8.0-7.el9 - - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/source/SRPMS/Packages/g/gawk-5.1.0-6.el9.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/source/SRPMS/Packages/g/gawk-5.1.0-6.el9_8.1.src.rpm repoid: rhel-9-for-aarch64-baseos-source-rpms - size: 3190934 - checksum: sha256:37571947707e835d36ceb5641b187aba13ef8f5f605a6762ce72aeea3e745b8d + size: 3197459 + checksum: sha256:8f156f11c96b1720ba2e9e287f2ddf5e0588a9c9ad17753f779ebbdf0c4e99df name: gawk - evr: 5.1.0-6.el9 + evr: 5.1.0-6.el9_8.1 - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/source/SRPMS/Packages/g/gcc-11.5.0-14.el9.src.rpm repoid: rhel-9-for-aarch64-baseos-source-rpms size: 81978017 @@ -1250,12 +1250,12 @@ arches: checksum: sha256:ad42264274c2a792220395a4dbe736a1de6100c4e14611707ec1dd447583271f name: gdbm evr: 1:1.23-1.el9 - - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/source/SRPMS/Packages/g/glibc-2.34-275.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/source/SRPMS/Packages/g/glibc-2.34-283.el9_8.src.rpm repoid: rhel-9-for-aarch64-baseos-source-rpms - size: 20442764 - checksum: sha256:bd7a453f66e13da24d073f53070c2d209fcd88ca2aaa24ab3b2f81cae198b46c + size: 20462553 + checksum: sha256:9007b0a97151f43f812049a925cb418753f9fd643fe1283cc7eddc7e6785e2f3 name: glibc - evr: 2.34-275.el9_8 + evr: 2.34-283.el9_8 - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/source/SRPMS/Packages/g/gmp-6.2.0-13.el9.src.rpm repoid: rhel-9-for-aarch64-baseos-source-rpms size: 2503825 @@ -1286,12 +1286,12 @@ arches: checksum: sha256:c4c76ebfd66ba6d00edf672797d7f077b29d279b7866a04e05258a257a5bc306 name: json-c evr: 0.14-11.el9 - - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/source/SRPMS/Packages/k/kernel-5.14.0-687.46.1.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/source/SRPMS/Packages/k/kernel-5.14.0-687.57.1.el9_8.src.rpm repoid: rhel-9-for-aarch64-baseos-source-rpms - size: 152431117 - checksum: sha256:378c1016ec891505f10477bf4f32f695033e3d4a94e7366d457bc0b076c826fd + size: 152563149 + checksum: sha256:a2660af0b87ac6a4d161ccc76c7d8a8338a44b4fbaad6da9e5529e3027f25aa2 name: kernel - evr: 5.14.0-687.46.1.el9_8 + evr: 5.14.0-687.57.1.el9_8 - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/source/SRPMS/Packages/k/keyutils-1.6.3-1.el9.src.rpm repoid: rhel-9-for-aarch64-baseos-source-rpms size: 150790 @@ -1340,12 +1340,12 @@ arches: checksum: sha256:425009c96135f39ca7bdb8a6ea948187d052d339dd76235979439fbd169da331 name: libeconf evr: 0.4.1-7.el9_8 - - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/source/SRPMS/Packages/l/libevent-2.1.12-8.el9_4.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/source/SRPMS/Packages/l/libevent-2.1.13-1.el9_8.src.rpm repoid: rhel-9-for-aarch64-baseos-source-rpms - size: 1123179 - checksum: sha256:8c00dc837b8685fc660cc0bcdfd4f533888facaa8c83655c26d2fb068cb7b135 + size: 1152974 + checksum: sha256:39aef29e588e3815189ca7b54326a4e1247e8a1f5a44c908ca4325c8cae83acb name: libevent - evr: 2.1.12-8.el9_4 + evr: 2.1.13-1.el9_8 - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/source/SRPMS/Packages/l/libffi-3.4.2-8.el9.src.rpm repoid: rhel-9-for-aarch64-baseos-source-rpms size: 1367398 @@ -1502,12 +1502,12 @@ arches: checksum: sha256:0d21c12c55d40d1fc2f006c8ec187b5fcc799b794cfd31ed2d98434189c62800 name: openldap evr: 2.6.8-4.el9 - - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/source/SRPMS/Packages/o/openssl-3.5.5-6.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/source/SRPMS/Packages/o/openssl-3.5.8-2.el9_8.src.rpm repoid: rhel-9-for-aarch64-baseos-source-rpms - size: 53369050 - checksum: sha256:b79f08d2d04536fdb6801b6ba7da7174942d174dd2b7969316402c737689d735 + size: 53435636 + checksum: sha256:1e67b59efe228f804c0544a31ab3de0bb4a0c8250d3d5f5fc53a3c7794104795 name: openssl - evr: 1:3.5.5-6.el9_8 + evr: 1:3.5.8-2.el9_8 - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/source/SRPMS/Packages/o/openssl-fips-provider-3.0.7-11.el9_8.src.rpm repoid: rhel-9-for-aarch64-baseos-source-rpms size: 28686020 @@ -1532,12 +1532,12 @@ arches: checksum: sha256:7edbd87b866a3f6e3df1426d660b902e063193d6186027bf99f6d77626a43817 name: pcre evr: 8.44-4.el9 - - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/source/SRPMS/Packages/p/pcre2-10.40-6.el9.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/source/SRPMS/Packages/p/pcre2-10.40-7.el9_8.src.rpm repoid: rhel-9-for-aarch64-baseos-source-rpms - size: 1789790 - checksum: sha256:a570f7192be555222aa3704882b9199fb013a84ad4d7dcf40a93d8de2ecf6e0a + size: 1805958 + checksum: sha256:43c40093332890a77f7d7c573a1b540867319bbcaaec5a6dfd73101765dc6ea0 name: pcre2 - evr: 10.40-6.el9 + evr: 10.40-7.el9_8 - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/source/SRPMS/Packages/p/pigz-2.8-1.el9.src.rpm repoid: rhel-9-for-aarch64-baseos-source-rpms size: 131701 @@ -1592,24 +1592,24 @@ arches: checksum: sha256:4efcc956008f0468362b41bdba79111c41027b682bcdea3ecca3744cf50ebfd7 name: sqlite evr: 3.34.1-11.el9_8 - - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/source/SRPMS/Packages/s/systemd-252-67.el9_8.4.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/source/SRPMS/Packages/s/systemd-252-67.el9_8.6.src.rpm repoid: rhel-9-for-aarch64-baseos-source-rpms - size: 45009674 - checksum: sha256:e44181d1de2a135a5507b956d18a9eb11951a35aaa9c15dbc0f144ed8313f732 + size: 45003976 + checksum: sha256:f535f4c20ed82f56cc7f4c86202e3cd582815f702bb0c24005a07a496ec94c97 name: systemd - evr: 252-67.el9_8.4 + evr: 252-67.el9_8.6 - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/source/SRPMS/Packages/t/tar-1.34-13.el9_8.src.rpm repoid: rhel-9-for-aarch64-baseos-source-rpms size: 2312101 checksum: sha256:15eeffee75eaef17e056cef4d5207825782a755db6dfd509a759e672ffd03b6c name: tar evr: 2:1.34-13.el9_8 - - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/source/SRPMS/Packages/t/tzdata-2026c-1.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/source/SRPMS/Packages/t/tzdata-2026e-1.el9_8.src.rpm repoid: rhel-9-for-aarch64-baseos-source-rpms - size: 933774 - checksum: sha256:4cc10832b19807c03a30bd9317fb37dc811d2f13c11b1ed35af8d2efa481622f + size: 943814 + checksum: sha256:016ab67407e6f67418d8f36c5944396fe82c85896b9e945441f93d3cf1b823b4 name: tzdata - evr: 2026c-1.el9_8 + evr: 2026e-1.el9_8 - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/source/SRPMS/Packages/u/util-linux-2.37.4-25.el9.src.rpm repoid: rhel-9-for-aarch64-baseos-source-rpms size: 6291867 @@ -1635,10 +1635,10 @@ arches: name: zstd evr: 1.5.5-1.el9 module_metadata: - - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/appstream/os/repodata/4bc3c61db4611b362edc13ee5c445b4ca84c2bfcef77e623494428ab15132ae1-modules.yaml.gz + - url: https://cdn.redhat.com/content/dist/rhel9/9/aarch64/appstream/os/repodata/e4bd35a63d3720d47f8770f923c2f4f4a21dc06f0ff1cb37c98ba520477a2b5f-modules.yaml.gz repoid: rhel-9-for-aarch64-appstream-rpms - size: 65894 - checksum: sha256:4bc3c61db4611b362edc13ee5c445b4ca84c2bfcef77e623494428ab15132ae1 + size: 69384 + checksum: sha256:e4bd35a63d3720d47f8770f923c2f4f4a21dc06f0ff1cb37c98ba520477a2b5f - arch: ppc64le packages: - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/appstream/os/Packages/c/cpp-11.5.0-14.el9.ppc64le.rpm @@ -1655,13 +1655,13 @@ arches: name: delve evr: 1.26.1-1.el9_8 sourcerpm: delve-1.26.1-1.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/appstream/os/Packages/g/gawk-all-langpacks-5.1.0-6.el9.ppc64le.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/appstream/os/Packages/g/gawk-all-langpacks-5.1.0-6.el9_8.1.ppc64le.rpm repoid: rhel-9-for-ppc64le-appstream-rpms - size: 216324 - checksum: sha256:f44a17730803f53266874678031b8121541b5b1a8047a3205c2576630216f468 + size: 218118 + checksum: sha256:c12a101cc4a7fd08f4fa1a430629fe45fa7fd56e59d5f4094aaa159c9a0aabea name: gawk-all-langpacks - evr: 5.1.0-6.el9 - sourcerpm: gawk-5.1.0-6.el9.src.rpm + evr: 5.1.0-6.el9_8.1 + sourcerpm: gawk-5.1.0-6.el9_8.1.src.rpm - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/appstream/os/Packages/g/gcc-11.5.0-14.el9.ppc64le.rpm repoid: rhel-9-for-ppc64le-appstream-rpms size: 29072214 @@ -1669,55 +1669,55 @@ arches: name: gcc evr: 11.5.0-14.el9 sourcerpm: gcc-11.5.0-14.el9.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/appstream/os/Packages/g/glibc-devel-2.34-275.el9_8.ppc64le.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/appstream/os/Packages/g/glibc-devel-2.34-283.el9_8.ppc64le.rpm repoid: rhel-9-for-ppc64le-appstream-rpms - size: 587995 - checksum: sha256:8a7198be7897a154c0882d7302fe37ebead33e09d41ca2643b1677360dbb06ee + size: 588179 + checksum: sha256:bbf07477a92658eb7667624537b47fc925a61c8aa379b912a5d701ff22cd924b name: glibc-devel - evr: 2.34-275.el9_8 - sourcerpm: glibc-2.34-275.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/appstream/os/Packages/g/go-toolset-1.26.7-1.el9_8.ppc64le.rpm + evr: 2.34-283.el9_8 + sourcerpm: glibc-2.34-283.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/appstream/os/Packages/g/go-toolset-1.26.7-2.el9_8.ppc64le.rpm repoid: rhel-9-for-ppc64le-appstream-rpms - size: 12381 - checksum: sha256:ff9550d877b563eb05b3a49b4f352a1b578a42cd234704cbc43db08825b9d632 + size: 12469 + checksum: sha256:e41a8424c10bc94cd0bfcd5e047dde7bced6d7f5e8e56ceeec3845ea9c0a91ce name: go-toolset - evr: 1.26.7-1.el9_8 - sourcerpm: golang-1.26.7-1.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/appstream/os/Packages/g/golang-1.26.7-1.el9_8.ppc64le.rpm + evr: 1.26.7-2.el9_8 + sourcerpm: golang-1.26.7-2.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/appstream/os/Packages/g/golang-1.26.7-2.el9_8.ppc64le.rpm repoid: rhel-9-for-ppc64le-appstream-rpms - size: 1520537 - checksum: sha256:d09b9280e3d43c13454aadceb3c00e0997063fc7d621b7b8a2359b4c737f619f + size: 1520306 + checksum: sha256:0666a0e9d74aba917e5dd385629548b8d4e6f13e29441f3dec00e2a928c0173a name: golang - evr: 1.26.7-1.el9_8 - sourcerpm: golang-1.26.7-1.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/appstream/os/Packages/g/golang-bin-1.26.7-1.el9_8.ppc64le.rpm + evr: 1.26.7-2.el9_8 + sourcerpm: golang-1.26.7-2.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/appstream/os/Packages/g/golang-bin-1.26.7-2.el9_8.ppc64le.rpm repoid: rhel-9-for-ppc64le-appstream-rpms - size: 43924293 - checksum: sha256:db278a5a095d81a8100e884f5ffebcff5cca10b7c4f3fd3f9230b596c667026e + size: 43905181 + checksum: sha256:079e5c168a173ea7b7caa53a6b08c768fd9ce36c9dc746a45b2e47aec9ae8c62 name: golang-bin - evr: 1.26.7-1.el9_8 - sourcerpm: golang-1.26.7-1.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/appstream/os/Packages/g/golang-race-1.26.7-1.el9_8.ppc64le.rpm + evr: 1.26.7-2.el9_8 + sourcerpm: golang-1.26.7-2.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/appstream/os/Packages/g/golang-race-1.26.7-2.el9_8.ppc64le.rpm repoid: rhel-9-for-ppc64le-appstream-rpms - size: 1663611 - checksum: sha256:ed9e4c84393cf7875bf23a34489fa235610df93ebb97dc9d2c52bb9d3d0733f4 + size: 1663702 + checksum: sha256:06cbd04d297dd3d522deab3c3c4b4226358efb4616eb55988edcac4c373a6617 name: golang-race - evr: 1.26.7-1.el9_8 - sourcerpm: golang-1.26.7-1.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/appstream/os/Packages/g/golang-src-1.26.7-1.el9_8.noarch.rpm + evr: 1.26.7-2.el9_8 + sourcerpm: golang-1.26.7-2.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/appstream/os/Packages/g/golang-src-1.26.7-2.el9_8.noarch.rpm repoid: rhel-9-for-ppc64le-appstream-rpms - size: 12881267 - checksum: sha256:b570b95df0bc6429486a71a10fb433f56bb3a694f5de8a777131b2a841e81181 + size: 12879471 + checksum: sha256:ff54c6f194fcf25d743af1af7893242085c798b7ce04056066fee993c2167166 name: golang-src - evr: 1.26.7-1.el9_8 - sourcerpm: golang-1.26.7-1.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/appstream/os/Packages/k/kernel-headers-5.14.0-687.46.1.el9_8.ppc64le.rpm + evr: 1.26.7-2.el9_8 + sourcerpm: golang-1.26.7-2.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/appstream/os/Packages/k/kernel-headers-5.14.0-687.57.1.el9_8.ppc64le.rpm repoid: rhel-9-for-ppc64le-appstream-rpms - size: 2906129 - checksum: sha256:dd1c1221252a44f184e44ab4a4bbe82743e4970169cfc3405f44d4a7d0f54232 + size: 2963757 + checksum: sha256:92f45cbda331f1f1a398d83ef564d02085e9e8e5274127f949129446a1e62668 name: kernel-headers - evr: 5.14.0-687.46.1.el9_8 - sourcerpm: kernel-5.14.0-687.46.1.el9_8.src.rpm + evr: 5.14.0-687.57.1.el9_8 + sourcerpm: kernel-5.14.0-687.57.1.el9_8.src.rpm - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/appstream/os/Packages/l/libasan-11.5.0-14.el9.ppc64le.rpm repoid: rhel-9-for-ppc64le-appstream-rpms size: 440756 @@ -1767,41 +1767,41 @@ arches: name: mpdecimal evr: 2.5.1-3.el9 sourcerpm: mpdecimal-2.5.1-3.el9.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/appstream/os/Packages/o/openssl-devel-3.5.5-6.el9_8.ppc64le.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/appstream/os/Packages/o/openssl-devel-3.5.8-2.el9_8.ppc64le.rpm repoid: rhel-9-for-ppc64le-appstream-rpms - size: 5028706 - checksum: sha256:c3c05e886a636a5fc3c6ff52638cedcd11612913cf7547ccd9659ee017624939 + size: 5049303 + checksum: sha256:43e79a52675424d735be395869a49f30355257639571d46b7a15699364547463 name: openssl-devel - evr: 1:3.5.5-6.el9_8 - sourcerpm: openssl-3.5.5-6.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/appstream/os/Packages/p/postgresql-15.18-1.module+el9.8.0+24358+32c5830e.ppc64le.rpm + evr: 1:3.5.8-2.el9_8 + sourcerpm: openssl-3.5.8-2.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/appstream/os/Packages/p/postgresql-16.15-1.module+el9.8.0+24803+9dca000b.ppc64le.rpm repoid: rhel-9-for-ppc64le-appstream-rpms - size: 1881747 - checksum: sha256:6aee4d674c4b3b504a62e263386ebc1bf4f9daed2cd89b3a9578de4fc3e3dcce + size: 2115888 + checksum: sha256:a5f63dd209db8b709ebda515c4a71c746360e2438ed54a448920a84b431ab3d3 name: postgresql - evr: 15.18-1.module+el9.8.0+24358+32c5830e - sourcerpm: postgresql-15.18-1.module+el9.8.0+24358+32c5830e.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/appstream/os/Packages/p/postgresql-private-libs-15.18-1.module+el9.8.0+24358+32c5830e.ppc64le.rpm + evr: 16.15-1.module+el9.8.0+24803+9dca000b + sourcerpm: postgresql-16.15-1.module+el9.8.0+24803+9dca000b.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/appstream/os/Packages/p/postgresql-private-libs-16.15-1.module+el9.8.0+24803+9dca000b.ppc64le.rpm repoid: rhel-9-for-ppc64le-appstream-rpms - size: 170196 - checksum: sha256:388ed8fa7cddbdcf4c20bfd13986e2c1d25090daadcb585e442fe7ca99a76955 + size: 171976 + checksum: sha256:96366eb8e165d019f05d42c0b5fb801e658377f65b1d92bae29a8e9d73722725 name: postgresql-private-libs - evr: 15.18-1.module+el9.8.0+24358+32c5830e - sourcerpm: postgresql-15.18-1.module+el9.8.0+24358+32c5830e.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/appstream/os/Packages/p/python3.12-3.12.14-1.el9_8.ppc64le.rpm + evr: 16.15-1.module+el9.8.0+24803+9dca000b + sourcerpm: postgresql-16.15-1.module+el9.8.0+24803+9dca000b.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/appstream/os/Packages/p/python3.12-3.12.15-1.el9_8.ppc64le.rpm repoid: rhel-9-for-ppc64le-appstream-rpms - size: 32494 - checksum: sha256:8e3fcabf92bf5be325dbb114ab2921b92c3a3007c9bab8b24f93d3c2a5bb44c8 + size: 32671 + checksum: sha256:8487fe96fe76e5dce0a7725ac8d7f0567f7b6efd79bfa425994e5e58c11fc4e7 name: python3.12 - evr: 3.12.14-1.el9_8 - sourcerpm: python3.12-3.12.14-1.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/appstream/os/Packages/p/python3.12-libs-3.12.14-1.el9_8.ppc64le.rpm + evr: 3.12.15-1.el9_8 + sourcerpm: python3.12-3.12.15-1.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/appstream/os/Packages/p/python3.12-libs-3.12.15-1.el9_8.ppc64le.rpm repoid: rhel-9-for-ppc64le-appstream-rpms - size: 10093244 - checksum: sha256:32e4a045a4ce07f8db54811f223def1404fbabe4b7b521d48a56c7480f6b1057 + size: 10098201 + checksum: sha256:da7dceeaf521afad56701795db246750b261a5759053fe37c1ebbfe623034c21 name: python3.12-libs - evr: 3.12.14-1.el9_8 - sourcerpm: python3.12-3.12.14-1.el9_8.src.rpm + evr: 3.12.15-1.el9_8 + sourcerpm: python3.12-3.12.15-1.el9_8.src.rpm - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/appstream/os/Packages/p/python3.12-pip-wheel-23.2.1-5.el9.noarch.rpm repoid: rhel-9-for-ppc64le-appstream-rpms size: 1527128 @@ -1977,13 +1977,13 @@ arches: name: elfutils-libs evr: 0.194-1.el9 sourcerpm: elfutils-0.194-1.el9.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/os/Packages/e/expat-2.5.0-6.el9_8.3.ppc64le.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/os/Packages/e/expat-2.5.0-6.el9_8.5.ppc64le.rpm repoid: rhel-9-for-ppc64le-baseos-rpms - size: 133470 - checksum: sha256:731fb187d6550a4a5fc6227d43370464d67a68e9fb41481c2e86b95e4560345b + size: 133703 + checksum: sha256:f379b66b57d67569fabaa4cecc75d7ed26b1c46733b626f3550fc31e740761af name: expat - evr: 2.5.0-6.el9_8.3 - sourcerpm: expat-2.5.0-6.el9_8.3.src.rpm + evr: 2.5.0-6.el9_8.5 + sourcerpm: expat-2.5.0-6.el9_8.5.src.rpm - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/os/Packages/f/filesystem-3.16-5.el9.ppc64le.rpm repoid: rhel-9-for-ppc64le-baseos-rpms size: 5003944 @@ -1998,13 +1998,13 @@ arches: name: findutils evr: 1:4.8.0-7.el9 sourcerpm: findutils-4.8.0-7.el9.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/os/Packages/g/gawk-5.1.0-6.el9.ppc64le.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/os/Packages/g/gawk-5.1.0-6.el9_8.1.ppc64le.rpm repoid: rhel-9-for-ppc64le-baseos-rpms - size: 1064251 - checksum: sha256:b0cc389ad0855900c79f2cfa525df8cbc663093056b0b5d29ec3e36a189b325e + size: 1062624 + checksum: sha256:4c2d81c6874201646d5c5eee719ecdb95f610b277b3782bb1956a19f71d17d59 name: gawk - evr: 5.1.0-6.el9 - sourcerpm: gawk-5.1.0-6.el9.src.rpm + evr: 5.1.0-6.el9_8.1 + sourcerpm: gawk-5.1.0-6.el9_8.1.src.rpm - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/os/Packages/g/gdbm-libs-1.23-1.el9.ppc64le.rpm repoid: rhel-9-for-ppc64le-baseos-rpms size: 65838 @@ -2012,34 +2012,34 @@ arches: name: gdbm-libs evr: 1:1.23-1.el9 sourcerpm: gdbm-1.23-1.el9.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/os/Packages/g/glibc-2.34-275.el9_8.ppc64le.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/os/Packages/g/glibc-2.34-283.el9_8.ppc64le.rpm repoid: rhel-9-for-ppc64le-baseos-rpms - size: 2910729 - checksum: sha256:283894cf70b0f263673a2c312c221fdde95c57ee42919ca55f2a8ddffe9ac35b + size: 2912446 + checksum: sha256:58cb522948a569844774333002f3f46bef3605995a12ae1d604c6b9346d2c3e2 name: glibc - evr: 2.34-275.el9_8 - sourcerpm: glibc-2.34-275.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/os/Packages/g/glibc-common-2.34-275.el9_8.ppc64le.rpm + evr: 2.34-283.el9_8 + sourcerpm: glibc-2.34-283.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/os/Packages/g/glibc-common-2.34-283.el9_8.ppc64le.rpm repoid: rhel-9-for-ppc64le-baseos-rpms - size: 339553 - checksum: sha256:385baf7f6dff31df34fd649b90b3352f6435bc18aa1bb6b75b4cae1f706148d2 + size: 339738 + checksum: sha256:425ee42d476c84313217e727d19fa9e5621536de9154be01a3a1de2e24732445 name: glibc-common - evr: 2.34-275.el9_8 - sourcerpm: glibc-2.34-275.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/os/Packages/g/glibc-gconv-extra-2.34-275.el9_8.ppc64le.rpm + evr: 2.34-283.el9_8 + sourcerpm: glibc-2.34-283.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/os/Packages/g/glibc-gconv-extra-2.34-283.el9_8.ppc64le.rpm repoid: rhel-9-for-ppc64le-baseos-rpms - size: 1828793 - checksum: sha256:6c70cd8679823b0834ddc4e31d0d878a7b65b0a2299cfd860705e7fc51328ee1 + size: 1829644 + checksum: sha256:8818013abf534cecafd88c6c8f0e47229745a9aac310d322e4eef3cf31c5ceaf name: glibc-gconv-extra - evr: 2.34-275.el9_8 - sourcerpm: glibc-2.34-275.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/os/Packages/g/glibc-minimal-langpack-2.34-275.el9_8.ppc64le.rpm + evr: 2.34-283.el9_8 + sourcerpm: glibc-2.34-283.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/os/Packages/g/glibc-minimal-langpack-2.34-283.el9_8.ppc64le.rpm repoid: rhel-9-for-ppc64le-baseos-rpms - size: 30901 - checksum: sha256:207421071834e057ca6e25ee11c273be2b4f230cd9fd6f16760be5be3276b39f + size: 31057 + checksum: sha256:809935a22c981342d7ce446e8085753351a2cbc29db8baa2006a67091e7331d4 name: glibc-minimal-langpack - evr: 2.34-275.el9_8 - sourcerpm: glibc-2.34-275.el9_8.src.rpm + evr: 2.34-283.el9_8 + sourcerpm: glibc-2.34-283.el9_8.src.rpm - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/os/Packages/g/gmp-6.2.0-13.el9.ppc64le.rpm repoid: rhel-9-for-ppc64le-baseos-rpms size: 312805 @@ -2131,13 +2131,13 @@ arches: name: libblkid evr: 2.37.4-25.el9 sourcerpm: util-linux-2.37.4-25.el9.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/os/Packages/l/libbrotli-1.0.9-9.el9_7.ppc64le.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/os/Packages/l/libbrotli-1.0.9-10.el9_8.ppc64le.rpm repoid: rhel-9-for-ppc64le-baseos-rpms - size: 349508 - checksum: sha256:ff72df4a441c2f8ee8e1bcde8dcbd5bbd89250db9caf8792ff253b7af3e1c51c + size: 349850 + checksum: sha256:42e896518cf1eafcacb3de33fc0bd827d574413543166a218ee69b22653ccea9 name: libbrotli - evr: 1.0.9-9.el9_7 - sourcerpm: brotli-1.0.9-9.el9_7.src.rpm + evr: 1.0.9-10.el9_8 + sourcerpm: brotli-1.0.9-10.el9_8.src.rpm - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/os/Packages/l/libcap-2.48-10.el9_8.1.ppc64le.rpm repoid: rhel-9-for-ppc64le-baseos-rpms size: 82771 @@ -2159,13 +2159,13 @@ arches: name: libcom_err evr: 1.46.5-8.el9 sourcerpm: e2fsprogs-1.46.5-8.el9.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/os/Packages/l/libcurl-7.76.1-40.el9_8.5.ppc64le.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/os/Packages/l/libcurl-7.76.1-40.el9_8.8.ppc64le.rpm repoid: rhel-9-for-ppc64le-baseos-rpms - size: 329146 - checksum: sha256:1101e1698ca9b9d1b67332cf81c29ffbfbcd4342b053a3e3d4304d8d86e73bc2 + size: 329921 + checksum: sha256:3398c7352676781afaccc81aeb80925dc9b213c4fdbe6784e0662194931ad948 name: libcurl - evr: 7.76.1-40.el9_8.5 - sourcerpm: curl-7.76.1-40.el9_8.5.src.rpm + evr: 7.76.1-40.el9_8.8 + sourcerpm: curl-7.76.1-40.el9_8.8.src.rpm - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/os/Packages/l/libdb-5.3.28-57.el9_6.ppc64le.rpm repoid: rhel-9-for-ppc64le-baseos-rpms size: 837087 @@ -2180,13 +2180,13 @@ arches: name: libeconf evr: 0.4.1-7.el9_8 sourcerpm: libeconf-0.4.1-7.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/os/Packages/l/libevent-2.1.12-8.el9_4.ppc64le.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/os/Packages/l/libevent-2.1.13-1.el9_8.ppc64le.rpm repoid: rhel-9-for-ppc64le-baseos-rpms - size: 287857 - checksum: sha256:bc6eb253e6cf0e06fa7270c029502e14ee70cb22c2ed86b15f2a9952ba2f375f + size: 290670 + checksum: sha256:807d7fa3f3d44f61494a8e10513fba73a030202c44e4f740406a1aecb8af9094 name: libevent - evr: 2.1.12-8.el9_4 - sourcerpm: libevent-2.1.12-8.el9_4.src.rpm + evr: 2.1.13-1.el9_8 + sourcerpm: libevent-2.1.13-1.el9_8.src.rpm - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/os/Packages/l/libfdisk-2.37.4-25.el9.ppc64le.rpm repoid: rhel-9-for-ppc64le-baseos-rpms size: 176392 @@ -2453,13 +2453,13 @@ arches: name: openldap evr: 2.6.8-4.el9 sourcerpm: openldap-2.6.8-4.el9.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/os/Packages/o/openssl-3.5.5-6.el9_8.ppc64le.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/os/Packages/o/openssl-3.5.8-2.el9_8.ppc64le.rpm repoid: rhel-9-for-ppc64le-baseos-rpms - size: 1566179 - checksum: sha256:d207d19541eb62721034fbcf7f8ae046d3862541bc20221bd5cb12262eefe3a0 + size: 1571604 + checksum: sha256:1821093057fa1deba0217258135142da201100664028ce15b36471a36c4a20d9 name: openssl - evr: 1:3.5.5-6.el9_8 - sourcerpm: openssl-3.5.5-6.el9_8.src.rpm + evr: 1:3.5.8-2.el9_8 + sourcerpm: openssl-3.5.8-2.el9_8.src.rpm - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/os/Packages/o/openssl-fips-provider-3.0.7-11.el9_8.ppc64le.rpm repoid: rhel-9-for-ppc64le-baseos-rpms size: 14245 @@ -2474,13 +2474,13 @@ arches: name: openssl-fips-provider-so evr: 3.0.7-11.el9_8 sourcerpm: openssl-fips-provider-3.0.7-11.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/os/Packages/o/openssl-libs-3.5.5-6.el9_8.ppc64le.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/os/Packages/o/openssl-libs-3.5.8-2.el9_8.ppc64le.rpm repoid: rhel-9-for-ppc64le-baseos-rpms - size: 2553440 - checksum: sha256:736ae95ae35ebd344438f0871e471135e0ebb0ed61352b467e71040412f871de + size: 2558230 + checksum: sha256:a3cc786155a4fe2be6d16c15b12bdb628f3f5141f21851dfd061bc550dfe34d8 name: openssl-libs - evr: 1:3.5.5-6.el9_8 - sourcerpm: openssl-3.5.5-6.el9_8.src.rpm + evr: 1:3.5.8-2.el9_8 + sourcerpm: openssl-3.5.8-2.el9_8.src.rpm - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/os/Packages/p/p11-kit-0.26.4-1.el9_8.ppc64le.rpm repoid: rhel-9-for-ppc64le-baseos-rpms size: 621129 @@ -2509,20 +2509,20 @@ arches: name: pcre evr: 8.44-4.el9 sourcerpm: pcre-8.44-4.el9.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/os/Packages/p/pcre2-10.40-6.el9.ppc64le.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/os/Packages/p/pcre2-10.40-7.el9_8.ppc64le.rpm repoid: rhel-9-for-ppc64le-baseos-rpms - size: 243057 - checksum: sha256:fcccf3d6981333ac0ac747ee143dae975381e02025ad2bc53e6aa7e0dc5fafb7 + size: 245697 + checksum: sha256:58ff04ee8a1bca90fbabc3310043eac023d09440579f9140fa74306425dd3de4 name: pcre2 - evr: 10.40-6.el9 - sourcerpm: pcre2-10.40-6.el9.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/os/Packages/p/pcre2-syntax-10.40-6.el9.noarch.rpm + evr: 10.40-7.el9_8 + sourcerpm: pcre2-10.40-7.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/os/Packages/p/pcre2-syntax-10.40-7.el9_8.noarch.rpm repoid: rhel-9-for-ppc64le-baseos-rpms - size: 147926 - checksum: sha256:d386b5e9b3a4b077b2ba143882e605750855dd3354f13c55fa12ed26908cb442 + size: 150069 + checksum: sha256:e7466a43ef2bfda2b1dc07e855b0db743d48b11c0bdc1402e1d2ea6fb23d33a3 name: pcre2-syntax - evr: 10.40-6.el9 - sourcerpm: pcre2-10.40-6.el9.src.rpm + evr: 10.40-7.el9_8 + sourcerpm: pcre2-10.40-7.el9_8.src.rpm - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/os/Packages/p/pigz-2.8-1.el9.ppc64le.rpm repoid: rhel-9-for-ppc64le-baseos-rpms size: 101362 @@ -2607,34 +2607,34 @@ arches: name: sqlite-libs evr: 3.34.1-11.el9_8 sourcerpm: sqlite-3.34.1-11.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/os/Packages/s/systemd-252-67.el9_8.4.ppc64le.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/os/Packages/s/systemd-252-67.el9_8.6.ppc64le.rpm repoid: rhel-9-for-ppc64le-baseos-rpms - size: 4435450 - checksum: sha256:bff8fa0817533a53ff5f52d3510b15566af85678685d14d731154806ace4e1d7 + size: 4416503 + checksum: sha256:ce49b64e3fdba53c10a4127b91a9f80ceb9d18e6a1fe834a41e4d66cd1a20b90 name: systemd - evr: 252-67.el9_8.4 - sourcerpm: systemd-252-67.el9_8.4.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/os/Packages/s/systemd-libs-252-67.el9_8.4.ppc64le.rpm + evr: 252-67.el9_8.6 + sourcerpm: systemd-252-67.el9_8.6.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/os/Packages/s/systemd-libs-252-67.el9_8.6.ppc64le.rpm repoid: rhel-9-for-ppc64le-baseos-rpms - size: 713252 - checksum: sha256:334c026fbafebded08f9d42b0bdaba9dba60863179c95792c13af4cb1f8b6523 + size: 694605 + checksum: sha256:8779364a6687523779cc8f9cfa8a5e0fc809d390e5c6d9e399705a754531c79f name: systemd-libs - evr: 252-67.el9_8.4 - sourcerpm: systemd-252-67.el9_8.4.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/os/Packages/s/systemd-pam-252-67.el9_8.4.ppc64le.rpm + evr: 252-67.el9_8.6 + sourcerpm: systemd-252-67.el9_8.6.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/os/Packages/s/systemd-pam-252-67.el9_8.6.ppc64le.rpm repoid: rhel-9-for-ppc64le-baseos-rpms - size: 294891 - checksum: sha256:cb44a6b99e0deafaad55d75942b67fa6079a1cfbc0929fefeeeea8f8ada6eaf0 + size: 276291 + checksum: sha256:bdc687a7e14c8df0cc6d5f1f3c1fd0ffa911e391ac83102f33c5ececf08dde08 name: systemd-pam - evr: 252-67.el9_8.4 - sourcerpm: systemd-252-67.el9_8.4.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/os/Packages/s/systemd-rpm-macros-252-67.el9_8.4.noarch.rpm + evr: 252-67.el9_8.6 + sourcerpm: systemd-252-67.el9_8.6.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/os/Packages/s/systemd-rpm-macros-252-67.el9_8.6.noarch.rpm repoid: rhel-9-for-ppc64le-baseos-rpms - size: 59475 - checksum: sha256:7d671ec39a7caeb7346be6d5fcb44212545844ced6f4974c4b409fef6a12a891 + size: 40844 + checksum: sha256:974a0352427799559a3e90dcdb38200d767631452cca7717c5b0fbe7760df313 name: systemd-rpm-macros - evr: 252-67.el9_8.4 - sourcerpm: systemd-252-67.el9_8.4.src.rpm + evr: 252-67.el9_8.6 + sourcerpm: systemd-252-67.el9_8.6.src.rpm - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/os/Packages/t/tar-1.34-13.el9_8.ppc64le.rpm repoid: rhel-9-for-ppc64le-baseos-rpms size: 947907 @@ -2642,13 +2642,13 @@ arches: name: tar evr: 2:1.34-13.el9_8 sourcerpm: tar-1.34-13.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/os/Packages/t/tzdata-2026c-1.el9_8.noarch.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/os/Packages/t/tzdata-2026e-1.el9_8.noarch.rpm repoid: rhel-9-for-ppc64le-baseos-rpms - size: 933286 - checksum: sha256:8d6196e02853c0900c3c2e2367665beffb62cb2d0ff5f465ea2d00848a9a35dc + size: 936099 + checksum: sha256:c105d92f6cacb9bb8337b77041cedd9c9c906a72c4b5233909b9b69b78f4369f name: tzdata - evr: 2026c-1.el9_8 - sourcerpm: tzdata-2026c-1.el9_8.src.rpm + evr: 2026e-1.el9_8 + sourcerpm: tzdata-2026e-1.el9_8.src.rpm - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/os/Packages/u/util-linux-2.37.4-25.el9.ppc64le.rpm repoid: rhel-9-for-ppc64le-baseos-rpms size: 2426763 @@ -2684,12 +2684,12 @@ arches: checksum: sha256:5fa267daa0e7df3e072c17e81db41b809b256da8cfb0372669d9a1bea937a01a name: delve evr: 1.26.1-1.el9_8 - - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/appstream/source/SRPMS/Packages/g/golang-1.26.7-1.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/appstream/source/SRPMS/Packages/g/golang-1.26.7-2.el9_8.src.rpm repoid: rhel-9-for-ppc64le-appstream-source-rpms - size: 36535123 - checksum: sha256:3e46d00b71773429b84079992fff32610eda8917d7319d09c3cee5e6e4bd5bf5 + size: 36539286 + checksum: sha256:7a9ea792be9d09b61bc321ce8b65a040430d06891d6372aeb929753c2f270770 name: golang - evr: 1.26.7-1.el9_8 + evr: 1.26.7-2.el9_8 - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/appstream/source/SRPMS/Packages/l/libmpc-1.2.1-4.el9.src.rpm repoid: rhel-9-for-ppc64le-appstream-source-rpms size: 846236 @@ -2714,18 +2714,18 @@ arches: checksum: sha256:2f5ece89d6a8d892816f386462d8be291ad83f1500b4c4b3655dcc7ed5192c0d name: mpdecimal evr: 2.5.1-3.el9 - - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/appstream/source/SRPMS/Packages/p/postgresql-15.18-1.module+el9.8.0+24358+32c5830e.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/appstream/source/SRPMS/Packages/p/postgresql-16.15-1.module+el9.8.0+24803+9dca000b.src.rpm repoid: rhel-9-for-ppc64le-appstream-source-rpms - size: 45775054 - checksum: sha256:5955f781730fe817b08b7ddc3d2117a7c0a0c95ed2fd2044cbc1ff7d1eba1b28 + size: 48516429 + checksum: sha256:fdb3a4e84c097bb87061fbf6b3f1f11a03b4aa6adf13b0b20cc1d439b5a2c7d7 name: postgresql - evr: 15.18-1.module+el9.8.0+24358+32c5830e - - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/appstream/source/SRPMS/Packages/p/python3.12-3.12.14-1.el9_8.src.rpm + evr: 16.15-1.module+el9.8.0+24803+9dca000b + - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/appstream/source/SRPMS/Packages/p/python3.12-3.12.15-1.el9_8.src.rpm repoid: rhel-9-for-ppc64le-appstream-source-rpms - size: 20894742 - checksum: sha256:d855a90132b827b528e26c617484c250fd02dbe2cc8fdb8ef1f7d0d0a9f3f4f7 + size: 20904561 + checksum: sha256:8a3db1154cbfe206ac68b31268348da6039522d09be22520dd94207417146ebd name: python3.12 - evr: 3.12.14-1.el9_8 + evr: 3.12.15-1.el9_8 - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/appstream/source/SRPMS/Packages/p/python3.12-pip-23.2.1-5.el9.src.rpm repoid: rhel-9-for-ppc64le-appstream-source-rpms size: 9384965 @@ -2774,12 +2774,12 @@ arches: checksum: sha256:82174416ee39df7795da7fab8d37ea5dbbe25f1dbc2df39f5fb3f8a168bf5120 name: binutils evr: 2.35.2-72.el9 - - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/source/SRPMS/Packages/b/brotli-1.0.9-9.el9_7.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/source/SRPMS/Packages/b/brotli-1.0.9-10.el9_8.src.rpm repoid: rhel-9-for-ppc64le-baseos-source-rpms - size: 517498 - checksum: sha256:814868e0bec831c79d3e12ff76d31e06e5e62c462a1a4b6607b1f3cab7014438 + size: 519221 + checksum: sha256:c833ffbd6c6555543472ef4034a958cf4b8b8dee35b8661b2144ca6fc38908c7 name: brotli - evr: 1.0.9-9.el9_7 + evr: 1.0.9-10.el9_8 - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/source/SRPMS/Packages/b/bzip2-1.0.8-11.el9.src.rpm repoid: rhel-9-for-ppc64le-baseos-source-rpms size: 828199 @@ -2816,12 +2816,12 @@ arches: checksum: sha256:775d926429179caeade6af8dc7dea15a0bea49102c2592d5b712f996a329ec38 name: crypto-policies evr: 20260224-1.gitea0f072.el9_8 - - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/source/SRPMS/Packages/c/curl-7.76.1-40.el9_8.5.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/source/SRPMS/Packages/c/curl-7.76.1-40.el9_8.8.src.rpm repoid: rhel-9-for-ppc64le-baseos-source-rpms - size: 2576796 - checksum: sha256:5a455f6c35ae1069b8c54ade4c9d0d3d260134f76bee10f22efef9683c31b03f + size: 2581541 + checksum: sha256:303a97cbdfaaac1d709ef7621b2b349dc403da6a553ecfe5e3114f76d757d554 name: curl - evr: 7.76.1-40.el9_8.5 + evr: 7.76.1-40.el9_8.8 - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/source/SRPMS/Packages/c/cyrus-sasl-2.1.27-22.el9.src.rpm repoid: rhel-9-for-ppc64le-baseos-source-rpms size: 4025677 @@ -2858,12 +2858,12 @@ arches: checksum: sha256:643279e796ded16c5be5cdc2a91839c787e62e59757008675eb0580a4a42af21 name: elfutils evr: 0.194-1.el9 - - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/source/SRPMS/Packages/e/expat-2.5.0-6.el9_8.3.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/source/SRPMS/Packages/e/expat-2.5.0-6.el9_8.5.src.rpm repoid: rhel-9-for-ppc64le-baseos-source-rpms - size: 8403095 - checksum: sha256:0cff2a2213384dc43eb1874bf6e77b2b8230be848f50387d8057e0e6cde3d392 + size: 8411609 + checksum: sha256:38d7acfd1130c02c6a00010159a1350ca0f56cd7ed64f3d8394aa5b3d6512ddd name: expat - evr: 2.5.0-6.el9_8.3 + evr: 2.5.0-6.el9_8.5 - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/source/SRPMS/Packages/f/filesystem-3.16-5.el9.src.rpm repoid: rhel-9-for-ppc64le-baseos-source-rpms size: 20486 @@ -2876,12 +2876,12 @@ arches: checksum: sha256:48bd4d4dd081120bcc6ab772b930a150f30b2fc89a4a14a24220383d24a30b3f name: findutils evr: 1:4.8.0-7.el9 - - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/source/SRPMS/Packages/g/gawk-5.1.0-6.el9.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/source/SRPMS/Packages/g/gawk-5.1.0-6.el9_8.1.src.rpm repoid: rhel-9-for-ppc64le-baseos-source-rpms - size: 3190934 - checksum: sha256:37571947707e835d36ceb5641b187aba13ef8f5f605a6762ce72aeea3e745b8d + size: 3197459 + checksum: sha256:8f156f11c96b1720ba2e9e287f2ddf5e0588a9c9ad17753f779ebbdf0c4e99df name: gawk - evr: 5.1.0-6.el9 + evr: 5.1.0-6.el9_8.1 - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/source/SRPMS/Packages/g/gcc-11.5.0-14.el9.src.rpm repoid: rhel-9-for-ppc64le-baseos-source-rpms size: 81978017 @@ -2894,12 +2894,12 @@ arches: checksum: sha256:ad42264274c2a792220395a4dbe736a1de6100c4e14611707ec1dd447583271f name: gdbm evr: 1:1.23-1.el9 - - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/source/SRPMS/Packages/g/glibc-2.34-275.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/source/SRPMS/Packages/g/glibc-2.34-283.el9_8.src.rpm repoid: rhel-9-for-ppc64le-baseos-source-rpms - size: 20442764 - checksum: sha256:bd7a453f66e13da24d073f53070c2d209fcd88ca2aaa24ab3b2f81cae198b46c + size: 20462553 + checksum: sha256:9007b0a97151f43f812049a925cb418753f9fd643fe1283cc7eddc7e6785e2f3 name: glibc - evr: 2.34-275.el9_8 + evr: 2.34-283.el9_8 - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/source/SRPMS/Packages/g/gmp-6.2.0-13.el9.src.rpm repoid: rhel-9-for-ppc64le-baseos-source-rpms size: 2503825 @@ -2930,12 +2930,12 @@ arches: checksum: sha256:c4c76ebfd66ba6d00edf672797d7f077b29d279b7866a04e05258a257a5bc306 name: json-c evr: 0.14-11.el9 - - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/source/SRPMS/Packages/k/kernel-5.14.0-687.46.1.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/source/SRPMS/Packages/k/kernel-5.14.0-687.57.1.el9_8.src.rpm repoid: rhel-9-for-ppc64le-baseos-source-rpms - size: 152431117 - checksum: sha256:378c1016ec891505f10477bf4f32f695033e3d4a94e7366d457bc0b076c826fd + size: 152563149 + checksum: sha256:a2660af0b87ac6a4d161ccc76c7d8a8338a44b4fbaad6da9e5529e3027f25aa2 name: kernel - evr: 5.14.0-687.46.1.el9_8 + evr: 5.14.0-687.57.1.el9_8 - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/source/SRPMS/Packages/k/keyutils-1.6.3-1.el9.src.rpm repoid: rhel-9-for-ppc64le-baseos-source-rpms size: 150790 @@ -2984,12 +2984,12 @@ arches: checksum: sha256:425009c96135f39ca7bdb8a6ea948187d052d339dd76235979439fbd169da331 name: libeconf evr: 0.4.1-7.el9_8 - - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/source/SRPMS/Packages/l/libevent-2.1.12-8.el9_4.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/source/SRPMS/Packages/l/libevent-2.1.13-1.el9_8.src.rpm repoid: rhel-9-for-ppc64le-baseos-source-rpms - size: 1123179 - checksum: sha256:8c00dc837b8685fc660cc0bcdfd4f533888facaa8c83655c26d2fb068cb7b135 + size: 1152974 + checksum: sha256:39aef29e588e3815189ca7b54326a4e1247e8a1f5a44c908ca4325c8cae83acb name: libevent - evr: 2.1.12-8.el9_4 + evr: 2.1.13-1.el9_8 - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/source/SRPMS/Packages/l/libffi-3.4.2-8.el9.src.rpm repoid: rhel-9-for-ppc64le-baseos-source-rpms size: 1367398 @@ -3152,12 +3152,12 @@ arches: checksum: sha256:0d21c12c55d40d1fc2f006c8ec187b5fcc799b794cfd31ed2d98434189c62800 name: openldap evr: 2.6.8-4.el9 - - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/source/SRPMS/Packages/o/openssl-3.5.5-6.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/source/SRPMS/Packages/o/openssl-3.5.8-2.el9_8.src.rpm repoid: rhel-9-for-ppc64le-baseos-source-rpms - size: 53369050 - checksum: sha256:b79f08d2d04536fdb6801b6ba7da7174942d174dd2b7969316402c737689d735 + size: 53435636 + checksum: sha256:1e67b59efe228f804c0544a31ab3de0bb4a0c8250d3d5f5fc53a3c7794104795 name: openssl - evr: 1:3.5.5-6.el9_8 + evr: 1:3.5.8-2.el9_8 - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/source/SRPMS/Packages/o/openssl-fips-provider-3.0.7-11.el9_8.src.rpm repoid: rhel-9-for-ppc64le-baseos-source-rpms size: 28686020 @@ -3182,12 +3182,12 @@ arches: checksum: sha256:7edbd87b866a3f6e3df1426d660b902e063193d6186027bf99f6d77626a43817 name: pcre evr: 8.44-4.el9 - - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/source/SRPMS/Packages/p/pcre2-10.40-6.el9.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/source/SRPMS/Packages/p/pcre2-10.40-7.el9_8.src.rpm repoid: rhel-9-for-ppc64le-baseos-source-rpms - size: 1789790 - checksum: sha256:a570f7192be555222aa3704882b9199fb013a84ad4d7dcf40a93d8de2ecf6e0a + size: 1805958 + checksum: sha256:43c40093332890a77f7d7c573a1b540867319bbcaaec5a6dfd73101765dc6ea0 name: pcre2 - evr: 10.40-6.el9 + evr: 10.40-7.el9_8 - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/source/SRPMS/Packages/p/pigz-2.8-1.el9.src.rpm repoid: rhel-9-for-ppc64le-baseos-source-rpms size: 131701 @@ -3242,24 +3242,24 @@ arches: checksum: sha256:4efcc956008f0468362b41bdba79111c41027b682bcdea3ecca3744cf50ebfd7 name: sqlite evr: 3.34.1-11.el9_8 - - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/source/SRPMS/Packages/s/systemd-252-67.el9_8.4.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/source/SRPMS/Packages/s/systemd-252-67.el9_8.6.src.rpm repoid: rhel-9-for-ppc64le-baseos-source-rpms - size: 45009674 - checksum: sha256:e44181d1de2a135a5507b956d18a9eb11951a35aaa9c15dbc0f144ed8313f732 + size: 45003976 + checksum: sha256:f535f4c20ed82f56cc7f4c86202e3cd582815f702bb0c24005a07a496ec94c97 name: systemd - evr: 252-67.el9_8.4 + evr: 252-67.el9_8.6 - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/source/SRPMS/Packages/t/tar-1.34-13.el9_8.src.rpm repoid: rhel-9-for-ppc64le-baseos-source-rpms size: 2312101 checksum: sha256:15eeffee75eaef17e056cef4d5207825782a755db6dfd509a759e672ffd03b6c name: tar evr: 2:1.34-13.el9_8 - - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/source/SRPMS/Packages/t/tzdata-2026c-1.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/source/SRPMS/Packages/t/tzdata-2026e-1.el9_8.src.rpm repoid: rhel-9-for-ppc64le-baseos-source-rpms - size: 933774 - checksum: sha256:4cc10832b19807c03a30bd9317fb37dc811d2f13c11b1ed35af8d2efa481622f + size: 943814 + checksum: sha256:016ab67407e6f67418d8f36c5944396fe82c85896b9e945441f93d3cf1b823b4 name: tzdata - evr: 2026c-1.el9_8 + evr: 2026e-1.el9_8 - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/baseos/source/SRPMS/Packages/u/util-linux-2.37.4-25.el9.src.rpm repoid: rhel-9-for-ppc64le-baseos-source-rpms size: 6291867 @@ -3285,10 +3285,10 @@ arches: name: zstd evr: 1.5.5-1.el9 module_metadata: - - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/appstream/os/repodata/7be89893f89f1eeab3a3acde3a734175464076f4b4567c5b0f4747b88ed95c70-modules.yaml.gz + - url: https://cdn.redhat.com/content/dist/rhel9/9/ppc64le/appstream/os/repodata/2b46c0e65a7612308b8149db945f1a1710a6c4491c106262a500f9942b2fc429-modules.yaml.gz repoid: rhel-9-for-ppc64le-appstream-rpms - size: 65561 - checksum: sha256:7be89893f89f1eeab3a3acde3a734175464076f4b4567c5b0f4747b88ed95c70 + size: 70564 + checksum: sha256:2b46c0e65a7612308b8149db945f1a1710a6c4491c106262a500f9942b2fc429 - arch: s390x packages: - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/appstream/os/Packages/c/cpp-11.5.0-14.el9.s390x.rpm @@ -3298,13 +3298,13 @@ arches: name: cpp evr: 11.5.0-14.el9 sourcerpm: gcc-11.5.0-14.el9.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/appstream/os/Packages/g/gawk-all-langpacks-5.1.0-6.el9.s390x.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/appstream/os/Packages/g/gawk-all-langpacks-5.1.0-6.el9_8.1.s390x.rpm repoid: rhel-9-for-s390x-appstream-rpms - size: 216312 - checksum: sha256:fc71db041e9b749a3f8bcbc9f812509625cfaf5d4fa83d37324c4dbdeb00a36e + size: 218106 + checksum: sha256:4828be3b34d4f1e54ec4b0ff53c1291f18b01be78165e10ec4967b6b061e13d4 name: gawk-all-langpacks - evr: 5.1.0-6.el9 - sourcerpm: gawk-5.1.0-6.el9.src.rpm + evr: 5.1.0-6.el9_8.1 + sourcerpm: gawk-5.1.0-6.el9_8.1.src.rpm - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/appstream/os/Packages/g/gcc-11.5.0-14.el9.s390x.rpm repoid: rhel-9-for-s390x-appstream-rpms size: 26825105 @@ -3312,62 +3312,62 @@ arches: name: gcc evr: 11.5.0-14.el9 sourcerpm: gcc-11.5.0-14.el9.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/appstream/os/Packages/g/glibc-devel-2.34-275.el9_8.s390x.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/appstream/os/Packages/g/glibc-devel-2.34-283.el9_8.s390x.rpm repoid: rhel-9-for-s390x-appstream-rpms - size: 54280 - checksum: sha256:afc3171234ba01129468f8e08f175f17454f060961c364bc35a1242ea41b9111 + size: 54448 + checksum: sha256:5231ede78f3db9f2a58735cb755f8f930f00f0398c60b809c8d6ca0ed1b231c2 name: glibc-devel - evr: 2.34-275.el9_8 - sourcerpm: glibc-2.34-275.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/appstream/os/Packages/g/glibc-headers-2.34-275.el9_8.s390x.rpm + evr: 2.34-283.el9_8 + sourcerpm: glibc-2.34-283.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/appstream/os/Packages/g/glibc-headers-2.34-283.el9_8.s390x.rpm repoid: rhel-9-for-s390x-appstream-rpms - size: 557847 - checksum: sha256:4d87900e5abc5755b1bf57a4e127d6edddd8f59b1501b5005d0463c3ad3e457d + size: 558061 + checksum: sha256:72bb935c23190ee6b4162cff38de2e5289f55de71e454bcd198624424d3e3d8b name: glibc-headers - evr: 2.34-275.el9_8 - sourcerpm: glibc-2.34-275.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/appstream/os/Packages/g/go-toolset-1.26.7-1.el9_8.s390x.rpm + evr: 2.34-283.el9_8 + sourcerpm: glibc-2.34-283.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/appstream/os/Packages/g/go-toolset-1.26.7-2.el9_8.s390x.rpm repoid: rhel-9-for-s390x-appstream-rpms - size: 12353 - checksum: sha256:aba50425a0797a21ef3c7a5bc054ed4afb3c96a8802ea0758db89a4bf974a6f5 + size: 12445 + checksum: sha256:a0a8e830dc1a6cb78d888682650f74a03e99a3e06f0d9e944f083d58cf479d5e name: go-toolset - evr: 1.26.7-1.el9_8 - sourcerpm: golang-1.26.7-1.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/appstream/os/Packages/g/golang-1.26.7-1.el9_8.s390x.rpm + evr: 1.26.7-2.el9_8 + sourcerpm: golang-1.26.7-2.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/appstream/os/Packages/g/golang-1.26.7-2.el9_8.s390x.rpm repoid: rhel-9-for-s390x-appstream-rpms - size: 1520130 - checksum: sha256:e7bee02758864c0cb61bdd3e8a1318b5c32195df2ec07bb8e914639b381acbcb + size: 1520127 + checksum: sha256:1a996cac6c20254f109cc904e8e42866520dd686d85accea215e0e359d9c41d6 name: golang - evr: 1.26.7-1.el9_8 - sourcerpm: golang-1.26.7-1.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/appstream/os/Packages/g/golang-bin-1.26.7-1.el9_8.s390x.rpm + evr: 1.26.7-2.el9_8 + sourcerpm: golang-1.26.7-2.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/appstream/os/Packages/g/golang-bin-1.26.7-2.el9_8.s390x.rpm repoid: rhel-9-for-s390x-appstream-rpms - size: 46549574 - checksum: sha256:e03b18d614adf56123dc37c84535013b366e645e270ec105c2489e6a569703bd + size: 46533766 + checksum: sha256:948cdcf452abbbd590d9552a1eae7ef061c78bcd717c80d059def1c9db440089 name: golang-bin - evr: 1.26.7-1.el9_8 - sourcerpm: golang-1.26.7-1.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/appstream/os/Packages/g/golang-race-1.26.7-1.el9_8.s390x.rpm + evr: 1.26.7-2.el9_8 + sourcerpm: golang-1.26.7-2.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/appstream/os/Packages/g/golang-race-1.26.7-2.el9_8.s390x.rpm repoid: rhel-9-for-s390x-appstream-rpms - size: 1711630 - checksum: sha256:7e441ca5a2954e97ffb978489bec3b13378708fde3fe471f7aca78f3b6089094 + size: 1711787 + checksum: sha256:cdf8536fbba9d019882ad9e90b0b34d4997077eac595fef7adcb631768f4c492 name: golang-race - evr: 1.26.7-1.el9_8 - sourcerpm: golang-1.26.7-1.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/appstream/os/Packages/g/golang-src-1.26.7-1.el9_8.noarch.rpm + evr: 1.26.7-2.el9_8 + sourcerpm: golang-1.26.7-2.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/appstream/os/Packages/g/golang-src-1.26.7-2.el9_8.noarch.rpm repoid: rhel-9-for-s390x-appstream-rpms - size: 12881267 - checksum: sha256:b570b95df0bc6429486a71a10fb433f56bb3a694f5de8a777131b2a841e81181 + size: 12879471 + checksum: sha256:ff54c6f194fcf25d743af1af7893242085c798b7ce04056066fee993c2167166 name: golang-src - evr: 1.26.7-1.el9_8 - sourcerpm: golang-1.26.7-1.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/appstream/os/Packages/k/kernel-headers-5.14.0-687.46.1.el9_8.s390x.rpm + evr: 1.26.7-2.el9_8 + sourcerpm: golang-1.26.7-2.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/appstream/os/Packages/k/kernel-headers-5.14.0-687.57.1.el9_8.s390x.rpm repoid: rhel-9-for-s390x-appstream-rpms - size: 2912377 - checksum: sha256:0b7f6e5b57c4a4a459fd36b9e930959958bb5a18b2bdac21f46b53b5c2950b47 + size: 2969965 + checksum: sha256:33a6f1dfc82b4e4487e3a00df7f49d05a07644da11e9f3ccbf32aca3453837fa name: kernel-headers - evr: 5.14.0-687.46.1.el9_8 - sourcerpm: kernel-5.14.0-687.46.1.el9_8.src.rpm + evr: 5.14.0-687.57.1.el9_8 + sourcerpm: kernel-5.14.0-687.57.1.el9_8.src.rpm - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/appstream/os/Packages/l/libasan-11.5.0-14.el9.s390x.rpm repoid: rhel-9-for-s390x-appstream-rpms size: 412888 @@ -3417,41 +3417,41 @@ arches: name: mpdecimal evr: 2.5.1-3.el9 sourcerpm: mpdecimal-2.5.1-3.el9.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/appstream/os/Packages/o/openssl-devel-3.5.5-6.el9_8.s390x.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/appstream/os/Packages/o/openssl-devel-3.5.8-2.el9_8.s390x.rpm repoid: rhel-9-for-s390x-appstream-rpms - size: 5038202 - checksum: sha256:c8316fcfae1d02ba21f72428811811f832f0e85ab02d826c44cb79e26966e4fb + size: 5050289 + checksum: sha256:fcd9416c3dfecbd9144d886d183fb0b9633fb05e142fb5cade8ae01874a82396 name: openssl-devel - evr: 1:3.5.5-6.el9_8 - sourcerpm: openssl-3.5.5-6.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/appstream/os/Packages/p/postgresql-15.18-1.module+el9.8.0+24358+32c5830e.s390x.rpm + evr: 1:3.5.8-2.el9_8 + sourcerpm: openssl-3.5.8-2.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/appstream/os/Packages/p/postgresql-16.15-1.module+el9.8.0+24803+9dca000b.s390x.rpm repoid: rhel-9-for-s390x-appstream-rpms - size: 1851802 - checksum: sha256:dec726e071d7a3d2fd601eaa3d0dc88797022ebf3145c5d3facfdc5ff6827602 + size: 2085027 + checksum: sha256:7c047295d9ae473c18fbbeb9b0ce4a432ae6a75f1a8378d857809cbad2596214 name: postgresql - evr: 15.18-1.module+el9.8.0+24358+32c5830e - sourcerpm: postgresql-15.18-1.module+el9.8.0+24358+32c5830e.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/appstream/os/Packages/p/postgresql-private-libs-15.18-1.module+el9.8.0+24358+32c5830e.s390x.rpm + evr: 16.15-1.module+el9.8.0+24803+9dca000b + sourcerpm: postgresql-16.15-1.module+el9.8.0+24803+9dca000b.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/appstream/os/Packages/p/postgresql-private-libs-16.15-1.module+el9.8.0+24803+9dca000b.s390x.rpm repoid: rhel-9-for-s390x-appstream-rpms - size: 147697 - checksum: sha256:504ab6379c9051e1b745d0ab259f6957e0a2c0eee3042c9989302229af7dd3cd + size: 150732 + checksum: sha256:fa72693328f1f6fa5958912ca1d048aec07563e4bc7f013ccb1f4050805a8703 name: postgresql-private-libs - evr: 15.18-1.module+el9.8.0+24358+32c5830e - sourcerpm: postgresql-15.18-1.module+el9.8.0+24358+32c5830e.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/appstream/os/Packages/p/python3.12-3.12.14-1.el9_8.s390x.rpm + evr: 16.15-1.module+el9.8.0+24803+9dca000b + sourcerpm: postgresql-16.15-1.module+el9.8.0+24803+9dca000b.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/appstream/os/Packages/p/python3.12-3.12.15-1.el9_8.s390x.rpm repoid: rhel-9-for-s390x-appstream-rpms - size: 32298 - checksum: sha256:1d9c6400225666643a98052596e6a10a3e0f84c81daf0fef28867331749bf2f9 + size: 32494 + checksum: sha256:5056455a54f6c67bab0c0758930535a8364a18b71075ab6e34e37076111c87b5 name: python3.12 - evr: 3.12.14-1.el9_8 - sourcerpm: python3.12-3.12.14-1.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/appstream/os/Packages/p/python3.12-libs-3.12.14-1.el9_8.s390x.rpm + evr: 3.12.15-1.el9_8 + sourcerpm: python3.12-3.12.15-1.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/appstream/os/Packages/p/python3.12-libs-3.12.15-1.el9_8.s390x.rpm repoid: rhel-9-for-s390x-appstream-rpms - size: 9974169 - checksum: sha256:000bf9abc0a7627f453b50e1a94181a2f6729927d8d3324aa27ab8b251fb1ed1 + size: 9982480 + checksum: sha256:d83ff7b955bd7bc2aadbdd44a6f80bbf6004b0c08371db0c7b90945a587e5b78 name: python3.12-libs - evr: 3.12.14-1.el9_8 - sourcerpm: python3.12-3.12.14-1.el9_8.src.rpm + evr: 3.12.15-1.el9_8 + sourcerpm: python3.12-3.12.15-1.el9_8.src.rpm - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/appstream/os/Packages/p/python3.12-pip-wheel-23.2.1-5.el9.noarch.rpm repoid: rhel-9-for-s390x-appstream-rpms size: 1527128 @@ -3627,13 +3627,13 @@ arches: name: elfutils-libs evr: 0.194-1.el9 sourcerpm: elfutils-0.194-1.el9.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/os/Packages/e/expat-2.5.0-6.el9_8.3.s390x.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/os/Packages/e/expat-2.5.0-6.el9_8.5.s390x.rpm repoid: rhel-9-for-s390x-baseos-rpms - size: 124579 - checksum: sha256:e6bd000496dc070c1e4cfd17162d512111341820f12c10442b8752c0767c68a0 + size: 125167 + checksum: sha256:f7480b168cba79b9f30bc54faf1c43b9eab1cd3d9701c31f601b40e472659981 name: expat - evr: 2.5.0-6.el9_8.3 - sourcerpm: expat-2.5.0-6.el9_8.3.src.rpm + evr: 2.5.0-6.el9_8.5 + sourcerpm: expat-2.5.0-6.el9_8.5.src.rpm - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/os/Packages/f/filesystem-3.16-5.el9.s390x.rpm repoid: rhel-9-for-s390x-baseos-rpms size: 5003897 @@ -3648,13 +3648,13 @@ arches: name: findutils evr: 1:4.8.0-7.el9 sourcerpm: findutils-4.8.0-7.el9.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/os/Packages/g/gawk-5.1.0-6.el9.s390x.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/os/Packages/g/gawk-5.1.0-6.el9_8.1.s390x.rpm repoid: rhel-9-for-s390x-baseos-rpms - size: 1029188 - checksum: sha256:d34fd3f586240f43f71bc74824ae513cba2e4a6812f0ebbd101122e7e99bafe8 + size: 1029963 + checksum: sha256:7382392d06b5e21161966cec0c187bba6afb9710047ab17d79e7b55ce43def40 name: gawk - evr: 5.1.0-6.el9 - sourcerpm: gawk-5.1.0-6.el9.src.rpm + evr: 5.1.0-6.el9_8.1 + sourcerpm: gawk-5.1.0-6.el9_8.1.src.rpm - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/os/Packages/g/gdbm-libs-1.23-1.el9.s390x.rpm repoid: rhel-9-for-s390x-baseos-rpms size: 60437 @@ -3662,34 +3662,34 @@ arches: name: gdbm-libs evr: 1:1.23-1.el9 sourcerpm: gdbm-1.23-1.el9.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/os/Packages/g/glibc-2.34-275.el9_8.s390x.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/os/Packages/g/glibc-2.34-283.el9_8.s390x.rpm repoid: rhel-9-for-s390x-baseos-rpms - size: 1790650 - checksum: sha256:f73a9a19f2139ac3aca555309f1f9d5909a549d1bda684eadbdc9ed95e536407 + size: 1790814 + checksum: sha256:7b757b36efa81a2a5ed6e3cd47d1c0df6c1a8b52e9c7975411d308e022bc09fd name: glibc - evr: 2.34-275.el9_8 - sourcerpm: glibc-2.34-275.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/os/Packages/g/glibc-common-2.34-275.el9_8.s390x.rpm + evr: 2.34-283.el9_8 + sourcerpm: glibc-2.34-283.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/os/Packages/g/glibc-common-2.34-283.el9_8.s390x.rpm repoid: rhel-9-for-s390x-baseos-rpms - size: 325700 - checksum: sha256:cb7edc5131da954868e8053a9203ec7d94375627c1c8b717a3e42e7768b037e1 + size: 325539 + checksum: sha256:a240480901672e62f1d3f9b46c4b8beed69fa912d9871ccc11080b0ef35c5fd4 name: glibc-common - evr: 2.34-275.el9_8 - sourcerpm: glibc-2.34-275.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/os/Packages/g/glibc-gconv-extra-2.34-275.el9_8.s390x.rpm + evr: 2.34-283.el9_8 + sourcerpm: glibc-2.34-283.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/os/Packages/g/glibc-gconv-extra-2.34-283.el9_8.s390x.rpm repoid: rhel-9-for-s390x-baseos-rpms - size: 1755391 - checksum: sha256:7959a606ce9cab72ff1f0221e4f1d43a4cdf905a9b49bf868401b9409cc324cc + size: 1757088 + checksum: sha256:e4d30d442cc59041e259199420b8be9e73f6526671983020526586fbbf50b940 name: glibc-gconv-extra - evr: 2.34-275.el9_8 - sourcerpm: glibc-2.34-275.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/os/Packages/g/glibc-minimal-langpack-2.34-275.el9_8.s390x.rpm + evr: 2.34-283.el9_8 + sourcerpm: glibc-2.34-283.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/os/Packages/g/glibc-minimal-langpack-2.34-283.el9_8.s390x.rpm repoid: rhel-9-for-s390x-baseos-rpms - size: 30885 - checksum: sha256:96398be130a7db017656673be8f39dbd063d0fce335c1eb20b300b6c503e8dbc + size: 31037 + checksum: sha256:86d08f88de137ba5dfef4aff54bbb29b628a9b774f0930423f44fc5a2e340000 name: glibc-minimal-langpack - evr: 2.34-275.el9_8 - sourcerpm: glibc-2.34-275.el9_8.src.rpm + evr: 2.34-283.el9_8 + sourcerpm: glibc-2.34-283.el9_8.src.rpm - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/os/Packages/g/gmp-6.2.0-13.el9.s390x.rpm repoid: rhel-9-for-s390x-baseos-rpms size: 296399 @@ -3781,13 +3781,13 @@ arches: name: libblkid evr: 2.37.4-25.el9 sourcerpm: util-linux-2.37.4-25.el9.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/os/Packages/l/libbrotli-1.0.9-9.el9_7.s390x.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/os/Packages/l/libbrotli-1.0.9-10.el9_8.s390x.rpm repoid: rhel-9-for-s390x-baseos-rpms - size: 329308 - checksum: sha256:ea47c24d8670923c31472fac1c2887ee8124b0a142ffb8a3c4953da8bf65c238 + size: 329468 + checksum: sha256:1d94d6401d4dd4c75b96b810046f1918c82460e0c3e9651e98d0e0c810ba0e22 name: libbrotli - evr: 1.0.9-9.el9_7 - sourcerpm: brotli-1.0.9-9.el9_7.src.rpm + evr: 1.0.9-10.el9_8 + sourcerpm: brotli-1.0.9-10.el9_8.src.rpm - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/os/Packages/l/libcap-2.48-10.el9_8.1.s390x.rpm repoid: rhel-9-for-s390x-baseos-rpms size: 77818 @@ -3809,13 +3809,13 @@ arches: name: libcom_err evr: 1.46.5-8.el9 sourcerpm: e2fsprogs-1.46.5-8.el9.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/os/Packages/l/libcurl-7.76.1-40.el9_8.5.s390x.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/os/Packages/l/libcurl-7.76.1-40.el9_8.8.s390x.rpm repoid: rhel-9-for-s390x-baseos-rpms - size: 291750 - checksum: sha256:27ec5fc1d1420007c387595e76ce70f944ac51b19f5afe7b867f4f528da43ee4 + size: 292806 + checksum: sha256:fba30ce3801d491bd946c7df555b671f8973fab988413c006abe5874d5547207 name: libcurl - evr: 7.76.1-40.el9_8.5 - sourcerpm: curl-7.76.1-40.el9_8.5.src.rpm + evr: 7.76.1-40.el9_8.8 + sourcerpm: curl-7.76.1-40.el9_8.8.src.rpm - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/os/Packages/l/libdb-5.3.28-57.el9_6.s390x.rpm repoid: rhel-9-for-s390x-baseos-rpms size: 721041 @@ -3830,13 +3830,13 @@ arches: name: libeconf evr: 0.4.1-7.el9_8 sourcerpm: libeconf-0.4.1-7.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/os/Packages/l/libevent-2.1.12-8.el9_4.s390x.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/os/Packages/l/libevent-2.1.13-1.el9_8.s390x.rpm repoid: rhel-9-for-s390x-baseos-rpms - size: 264391 - checksum: sha256:0abf1b13779d3aea3820b2ab76ce687f1f9675e531fb13bfff89ff97a288ba6c + size: 267419 + checksum: sha256:191d3f8958d23f242aea3b332b200653740f6e5d3e78a4608768301ae2fb4155 name: libevent - evr: 2.1.12-8.el9_4 - sourcerpm: libevent-2.1.12-8.el9_4.src.rpm + evr: 2.1.13-1.el9_8 + sourcerpm: libevent-2.1.13-1.el9_8.src.rpm - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/os/Packages/l/libfdisk-2.37.4-25.el9.s390x.rpm repoid: rhel-9-for-s390x-baseos-rpms size: 156062 @@ -4096,13 +4096,13 @@ arches: name: openldap evr: 2.6.8-4.el9 sourcerpm: openldap-2.6.8-4.el9.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/os/Packages/o/openssl-3.5.5-6.el9_8.s390x.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/os/Packages/o/openssl-3.5.8-2.el9_8.s390x.rpm repoid: rhel-9-for-s390x-baseos-rpms - size: 1549454 - checksum: sha256:55ace1358d336a4bc54659df2c4f1317d6638e70dbabc95b83a70d29cf6e113d + size: 1554288 + checksum: sha256:45353765ef5b07378507001e3a16b9752fb25ce4c98fba108fe4272902661c43 name: openssl - evr: 1:3.5.5-6.el9_8 - sourcerpm: openssl-3.5.5-6.el9_8.src.rpm + evr: 1:3.5.8-2.el9_8 + sourcerpm: openssl-3.5.8-2.el9_8.src.rpm - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/os/Packages/o/openssl-fips-provider-3.0.7-11.el9_8.s390x.rpm repoid: rhel-9-for-s390x-baseos-rpms size: 14236 @@ -4117,13 +4117,13 @@ arches: name: openssl-fips-provider-so evr: 3.0.7-11.el9_8 sourcerpm: openssl-fips-provider-3.0.7-11.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/os/Packages/o/openssl-libs-3.5.5-6.el9_8.s390x.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/os/Packages/o/openssl-libs-3.5.8-2.el9_8.s390x.rpm repoid: rhel-9-for-s390x-baseos-rpms - size: 2028396 - checksum: sha256:5f2f1608c0ea78bcbc58c5bd5d4b0c6c5c4acbbc1a1bcde569d2d30e3846d04d + size: 2034568 + checksum: sha256:0c2715769f47c21fdaf465e61ee350d939903cc06f50ee0f2fcb9448809c4f5c name: openssl-libs - evr: 1:3.5.5-6.el9_8 - sourcerpm: openssl-3.5.5-6.el9_8.src.rpm + evr: 1:3.5.8-2.el9_8 + sourcerpm: openssl-3.5.8-2.el9_8.src.rpm - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/os/Packages/p/p11-kit-0.26.4-1.el9_8.s390x.rpm repoid: rhel-9-for-s390x-baseos-rpms size: 628346 @@ -4152,20 +4152,20 @@ arches: name: pcre evr: 8.44-4.el9 sourcerpm: pcre-8.44-4.el9.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/os/Packages/p/pcre2-10.40-6.el9.s390x.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/os/Packages/p/pcre2-10.40-7.el9_8.s390x.rpm repoid: rhel-9-for-s390x-baseos-rpms - size: 224385 - checksum: sha256:b7166437e0179c46304403ddb126fd8a3d6c15d29b33a395b951e54b67697559 + size: 227201 + checksum: sha256:fee820347bd080be9dabf5dc7ce23a1d354240703f2665c5791607fcf2b67aec name: pcre2 - evr: 10.40-6.el9 - sourcerpm: pcre2-10.40-6.el9.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/os/Packages/p/pcre2-syntax-10.40-6.el9.noarch.rpm + evr: 10.40-7.el9_8 + sourcerpm: pcre2-10.40-7.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/os/Packages/p/pcre2-syntax-10.40-7.el9_8.noarch.rpm repoid: rhel-9-for-s390x-baseos-rpms - size: 147926 - checksum: sha256:d386b5e9b3a4b077b2ba143882e605750855dd3354f13c55fa12ed26908cb442 + size: 150069 + checksum: sha256:e7466a43ef2bfda2b1dc07e855b0db743d48b11c0bdc1402e1d2ea6fb23d33a3 name: pcre2-syntax - evr: 10.40-6.el9 - sourcerpm: pcre2-10.40-6.el9.src.rpm + evr: 10.40-7.el9_8 + sourcerpm: pcre2-10.40-7.el9_8.src.rpm - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/os/Packages/p/pigz-2.8-1.el9.s390x.rpm repoid: rhel-9-for-s390x-baseos-rpms size: 96630 @@ -4250,34 +4250,34 @@ arches: name: sqlite-libs evr: 3.34.1-11.el9_8 sourcerpm: sqlite-3.34.1-11.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/os/Packages/s/systemd-252-67.el9_8.4.s390x.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/os/Packages/s/systemd-252-67.el9_8.6.s390x.rpm repoid: rhel-9-for-s390x-baseos-rpms - size: 4167506 - checksum: sha256:b2db6892cf6b5e562ebebc828f8b85d709fb9ababf0582492693f3fe75df3be4 + size: 4148771 + checksum: sha256:f6522ccf722b7bbc014a3aa935d0a0410a096ab3d9bbcb9b345ed9b0f7f123b4 name: systemd - evr: 252-67.el9_8.4 - sourcerpm: systemd-252-67.el9_8.4.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/os/Packages/s/systemd-libs-252-67.el9_8.4.s390x.rpm + evr: 252-67.el9_8.6 + sourcerpm: systemd-252-67.el9_8.6.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/os/Packages/s/systemd-libs-252-67.el9_8.6.s390x.rpm repoid: rhel-9-for-s390x-baseos-rpms - size: 641241 - checksum: sha256:d2bf594df308844dcf204aba2c4341249cdc24d13654169755364946d8ec52f0 + size: 622880 + checksum: sha256:d851aa92c51f9432358cdb2e6a26b503f54a06154efc1415608a674e44a5ee85 name: systemd-libs - evr: 252-67.el9_8.4 - sourcerpm: systemd-252-67.el9_8.4.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/os/Packages/s/systemd-pam-252-67.el9_8.4.s390x.rpm + evr: 252-67.el9_8.6 + sourcerpm: systemd-252-67.el9_8.6.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/os/Packages/s/systemd-pam-252-67.el9_8.6.s390x.rpm repoid: rhel-9-for-s390x-baseos-rpms - size: 266273 - checksum: sha256:b52f54b47c27177f53e2344b86ac01f0e10482bc5a1dfae988051502d94df6e0 + size: 247723 + checksum: sha256:1043bd2359f6a9f64a90adf15bfe0718b36f2d752df3ead427983a52365e446d name: systemd-pam - evr: 252-67.el9_8.4 - sourcerpm: systemd-252-67.el9_8.4.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/os/Packages/s/systemd-rpm-macros-252-67.el9_8.4.noarch.rpm + evr: 252-67.el9_8.6 + sourcerpm: systemd-252-67.el9_8.6.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/os/Packages/s/systemd-rpm-macros-252-67.el9_8.6.noarch.rpm repoid: rhel-9-for-s390x-baseos-rpms - size: 59475 - checksum: sha256:7d671ec39a7caeb7346be6d5fcb44212545844ced6f4974c4b409fef6a12a891 + size: 40844 + checksum: sha256:974a0352427799559a3e90dcdb38200d767631452cca7717c5b0fbe7760df313 name: systemd-rpm-macros - evr: 252-67.el9_8.4 - sourcerpm: systemd-252-67.el9_8.4.src.rpm + evr: 252-67.el9_8.6 + sourcerpm: systemd-252-67.el9_8.6.src.rpm - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/os/Packages/t/tar-1.34-13.el9_8.s390x.rpm repoid: rhel-9-for-s390x-baseos-rpms size: 910326 @@ -4285,13 +4285,13 @@ arches: name: tar evr: 2:1.34-13.el9_8 sourcerpm: tar-1.34-13.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/os/Packages/t/tzdata-2026c-1.el9_8.noarch.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/os/Packages/t/tzdata-2026e-1.el9_8.noarch.rpm repoid: rhel-9-for-s390x-baseos-rpms - size: 933286 - checksum: sha256:8d6196e02853c0900c3c2e2367665beffb62cb2d0ff5f465ea2d00848a9a35dc + size: 936099 + checksum: sha256:c105d92f6cacb9bb8337b77041cedd9c9c906a72c4b5233909b9b69b78f4369f name: tzdata - evr: 2026c-1.el9_8 - sourcerpm: tzdata-2026c-1.el9_8.src.rpm + evr: 2026e-1.el9_8 + sourcerpm: tzdata-2026e-1.el9_8.src.rpm - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/os/Packages/u/util-linux-2.37.4-25.el9.s390x.rpm repoid: rhel-9-for-s390x-baseos-rpms size: 2327681 @@ -4321,12 +4321,12 @@ arches: evr: 1.2.11-40.el9 sourcerpm: zlib-1.2.11-40.el9.src.rpm source: - - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/appstream/source/SRPMS/Packages/g/golang-1.26.7-1.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/appstream/source/SRPMS/Packages/g/golang-1.26.7-2.el9_8.src.rpm repoid: rhel-9-for-s390x-appstream-source-rpms - size: 36535123 - checksum: sha256:3e46d00b71773429b84079992fff32610eda8917d7319d09c3cee5e6e4bd5bf5 + size: 36539286 + checksum: sha256:7a9ea792be9d09b61bc321ce8b65a040430d06891d6372aeb929753c2f270770 name: golang - evr: 1.26.7-1.el9_8 + evr: 1.26.7-2.el9_8 - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/appstream/source/SRPMS/Packages/l/libmpc-1.2.1-4.el9.src.rpm repoid: rhel-9-for-s390x-appstream-source-rpms size: 846236 @@ -4351,18 +4351,18 @@ arches: checksum: sha256:2f5ece89d6a8d892816f386462d8be291ad83f1500b4c4b3655dcc7ed5192c0d name: mpdecimal evr: 2.5.1-3.el9 - - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/appstream/source/SRPMS/Packages/p/postgresql-15.18-1.module+el9.8.0+24358+32c5830e.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/appstream/source/SRPMS/Packages/p/postgresql-16.15-1.module+el9.8.0+24803+9dca000b.src.rpm repoid: rhel-9-for-s390x-appstream-source-rpms - size: 45775054 - checksum: sha256:5955f781730fe817b08b7ddc3d2117a7c0a0c95ed2fd2044cbc1ff7d1eba1b28 + size: 48516429 + checksum: sha256:fdb3a4e84c097bb87061fbf6b3f1f11a03b4aa6adf13b0b20cc1d439b5a2c7d7 name: postgresql - evr: 15.18-1.module+el9.8.0+24358+32c5830e - - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/appstream/source/SRPMS/Packages/p/python3.12-3.12.14-1.el9_8.src.rpm + evr: 16.15-1.module+el9.8.0+24803+9dca000b + - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/appstream/source/SRPMS/Packages/p/python3.12-3.12.15-1.el9_8.src.rpm repoid: rhel-9-for-s390x-appstream-source-rpms - size: 20894742 - checksum: sha256:d855a90132b827b528e26c617484c250fd02dbe2cc8fdb8ef1f7d0d0a9f3f4f7 + size: 20904561 + checksum: sha256:8a3db1154cbfe206ac68b31268348da6039522d09be22520dd94207417146ebd name: python3.12 - evr: 3.12.14-1.el9_8 + evr: 3.12.15-1.el9_8 - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/appstream/source/SRPMS/Packages/p/python3.12-pip-23.2.1-5.el9.src.rpm repoid: rhel-9-for-s390x-appstream-source-rpms size: 9384965 @@ -4411,12 +4411,12 @@ arches: checksum: sha256:82174416ee39df7795da7fab8d37ea5dbbe25f1dbc2df39f5fb3f8a168bf5120 name: binutils evr: 2.35.2-72.el9 - - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/source/SRPMS/Packages/b/brotli-1.0.9-9.el9_7.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/source/SRPMS/Packages/b/brotli-1.0.9-10.el9_8.src.rpm repoid: rhel-9-for-s390x-baseos-source-rpms - size: 517498 - checksum: sha256:814868e0bec831c79d3e12ff76d31e06e5e62c462a1a4b6607b1f3cab7014438 + size: 519221 + checksum: sha256:c833ffbd6c6555543472ef4034a958cf4b8b8dee35b8661b2144ca6fc38908c7 name: brotli - evr: 1.0.9-9.el9_7 + evr: 1.0.9-10.el9_8 - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/source/SRPMS/Packages/b/bzip2-1.0.8-11.el9.src.rpm repoid: rhel-9-for-s390x-baseos-source-rpms size: 828199 @@ -4453,12 +4453,12 @@ arches: checksum: sha256:775d926429179caeade6af8dc7dea15a0bea49102c2592d5b712f996a329ec38 name: crypto-policies evr: 20260224-1.gitea0f072.el9_8 - - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/source/SRPMS/Packages/c/curl-7.76.1-40.el9_8.5.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/source/SRPMS/Packages/c/curl-7.76.1-40.el9_8.8.src.rpm repoid: rhel-9-for-s390x-baseos-source-rpms - size: 2576796 - checksum: sha256:5a455f6c35ae1069b8c54ade4c9d0d3d260134f76bee10f22efef9683c31b03f + size: 2581541 + checksum: sha256:303a97cbdfaaac1d709ef7621b2b349dc403da6a553ecfe5e3114f76d757d554 name: curl - evr: 7.76.1-40.el9_8.5 + evr: 7.76.1-40.el9_8.8 - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/source/SRPMS/Packages/c/cyrus-sasl-2.1.27-22.el9.src.rpm repoid: rhel-9-for-s390x-baseos-source-rpms size: 4025677 @@ -4495,12 +4495,12 @@ arches: checksum: sha256:643279e796ded16c5be5cdc2a91839c787e62e59757008675eb0580a4a42af21 name: elfutils evr: 0.194-1.el9 - - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/source/SRPMS/Packages/e/expat-2.5.0-6.el9_8.3.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/source/SRPMS/Packages/e/expat-2.5.0-6.el9_8.5.src.rpm repoid: rhel-9-for-s390x-baseos-source-rpms - size: 8403095 - checksum: sha256:0cff2a2213384dc43eb1874bf6e77b2b8230be848f50387d8057e0e6cde3d392 + size: 8411609 + checksum: sha256:38d7acfd1130c02c6a00010159a1350ca0f56cd7ed64f3d8394aa5b3d6512ddd name: expat - evr: 2.5.0-6.el9_8.3 + evr: 2.5.0-6.el9_8.5 - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/source/SRPMS/Packages/f/filesystem-3.16-5.el9.src.rpm repoid: rhel-9-for-s390x-baseos-source-rpms size: 20486 @@ -4513,12 +4513,12 @@ arches: checksum: sha256:48bd4d4dd081120bcc6ab772b930a150f30b2fc89a4a14a24220383d24a30b3f name: findutils evr: 1:4.8.0-7.el9 - - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/source/SRPMS/Packages/g/gawk-5.1.0-6.el9.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/source/SRPMS/Packages/g/gawk-5.1.0-6.el9_8.1.src.rpm repoid: rhel-9-for-s390x-baseos-source-rpms - size: 3190934 - checksum: sha256:37571947707e835d36ceb5641b187aba13ef8f5f605a6762ce72aeea3e745b8d + size: 3197459 + checksum: sha256:8f156f11c96b1720ba2e9e287f2ddf5e0588a9c9ad17753f779ebbdf0c4e99df name: gawk - evr: 5.1.0-6.el9 + evr: 5.1.0-6.el9_8.1 - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/source/SRPMS/Packages/g/gcc-11.5.0-14.el9.src.rpm repoid: rhel-9-for-s390x-baseos-source-rpms size: 81978017 @@ -4531,12 +4531,12 @@ arches: checksum: sha256:ad42264274c2a792220395a4dbe736a1de6100c4e14611707ec1dd447583271f name: gdbm evr: 1:1.23-1.el9 - - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/source/SRPMS/Packages/g/glibc-2.34-275.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/source/SRPMS/Packages/g/glibc-2.34-283.el9_8.src.rpm repoid: rhel-9-for-s390x-baseos-source-rpms - size: 20442764 - checksum: sha256:bd7a453f66e13da24d073f53070c2d209fcd88ca2aaa24ab3b2f81cae198b46c + size: 20462553 + checksum: sha256:9007b0a97151f43f812049a925cb418753f9fd643fe1283cc7eddc7e6785e2f3 name: glibc - evr: 2.34-275.el9_8 + evr: 2.34-283.el9_8 - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/source/SRPMS/Packages/g/gmp-6.2.0-13.el9.src.rpm repoid: rhel-9-for-s390x-baseos-source-rpms size: 2503825 @@ -4567,12 +4567,12 @@ arches: checksum: sha256:c4c76ebfd66ba6d00edf672797d7f077b29d279b7866a04e05258a257a5bc306 name: json-c evr: 0.14-11.el9 - - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/source/SRPMS/Packages/k/kernel-5.14.0-687.46.1.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/source/SRPMS/Packages/k/kernel-5.14.0-687.57.1.el9_8.src.rpm repoid: rhel-9-for-s390x-baseos-source-rpms - size: 152431117 - checksum: sha256:378c1016ec891505f10477bf4f32f695033e3d4a94e7366d457bc0b076c826fd + size: 152563149 + checksum: sha256:a2660af0b87ac6a4d161ccc76c7d8a8338a44b4fbaad6da9e5529e3027f25aa2 name: kernel - evr: 5.14.0-687.46.1.el9_8 + evr: 5.14.0-687.57.1.el9_8 - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/source/SRPMS/Packages/k/keyutils-1.6.3-1.el9.src.rpm repoid: rhel-9-for-s390x-baseos-source-rpms size: 150790 @@ -4621,12 +4621,12 @@ arches: checksum: sha256:425009c96135f39ca7bdb8a6ea948187d052d339dd76235979439fbd169da331 name: libeconf evr: 0.4.1-7.el9_8 - - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/source/SRPMS/Packages/l/libevent-2.1.12-8.el9_4.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/source/SRPMS/Packages/l/libevent-2.1.13-1.el9_8.src.rpm repoid: rhel-9-for-s390x-baseos-source-rpms - size: 1123179 - checksum: sha256:8c00dc837b8685fc660cc0bcdfd4f533888facaa8c83655c26d2fb068cb7b135 + size: 1152974 + checksum: sha256:39aef29e588e3815189ca7b54326a4e1247e8a1f5a44c908ca4325c8cae83acb name: libevent - evr: 2.1.12-8.el9_4 + evr: 2.1.13-1.el9_8 - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/source/SRPMS/Packages/l/libffi-3.4.2-8.el9.src.rpm repoid: rhel-9-for-s390x-baseos-source-rpms size: 1367398 @@ -4783,12 +4783,12 @@ arches: checksum: sha256:0d21c12c55d40d1fc2f006c8ec187b5fcc799b794cfd31ed2d98434189c62800 name: openldap evr: 2.6.8-4.el9 - - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/source/SRPMS/Packages/o/openssl-3.5.5-6.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/source/SRPMS/Packages/o/openssl-3.5.8-2.el9_8.src.rpm repoid: rhel-9-for-s390x-baseos-source-rpms - size: 53369050 - checksum: sha256:b79f08d2d04536fdb6801b6ba7da7174942d174dd2b7969316402c737689d735 + size: 53435636 + checksum: sha256:1e67b59efe228f804c0544a31ab3de0bb4a0c8250d3d5f5fc53a3c7794104795 name: openssl - evr: 1:3.5.5-6.el9_8 + evr: 1:3.5.8-2.el9_8 - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/source/SRPMS/Packages/o/openssl-fips-provider-3.0.7-11.el9_8.src.rpm repoid: rhel-9-for-s390x-baseos-source-rpms size: 28686020 @@ -4813,12 +4813,12 @@ arches: checksum: sha256:7edbd87b866a3f6e3df1426d660b902e063193d6186027bf99f6d77626a43817 name: pcre evr: 8.44-4.el9 - - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/source/SRPMS/Packages/p/pcre2-10.40-6.el9.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/source/SRPMS/Packages/p/pcre2-10.40-7.el9_8.src.rpm repoid: rhel-9-for-s390x-baseos-source-rpms - size: 1789790 - checksum: sha256:a570f7192be555222aa3704882b9199fb013a84ad4d7dcf40a93d8de2ecf6e0a + size: 1805958 + checksum: sha256:43c40093332890a77f7d7c573a1b540867319bbcaaec5a6dfd73101765dc6ea0 name: pcre2 - evr: 10.40-6.el9 + evr: 10.40-7.el9_8 - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/source/SRPMS/Packages/p/pigz-2.8-1.el9.src.rpm repoid: rhel-9-for-s390x-baseos-source-rpms size: 131701 @@ -4873,24 +4873,24 @@ arches: checksum: sha256:4efcc956008f0468362b41bdba79111c41027b682bcdea3ecca3744cf50ebfd7 name: sqlite evr: 3.34.1-11.el9_8 - - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/source/SRPMS/Packages/s/systemd-252-67.el9_8.4.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/source/SRPMS/Packages/s/systemd-252-67.el9_8.6.src.rpm repoid: rhel-9-for-s390x-baseos-source-rpms - size: 45009674 - checksum: sha256:e44181d1de2a135a5507b956d18a9eb11951a35aaa9c15dbc0f144ed8313f732 + size: 45003976 + checksum: sha256:f535f4c20ed82f56cc7f4c86202e3cd582815f702bb0c24005a07a496ec94c97 name: systemd - evr: 252-67.el9_8.4 + evr: 252-67.el9_8.6 - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/source/SRPMS/Packages/t/tar-1.34-13.el9_8.src.rpm repoid: rhel-9-for-s390x-baseos-source-rpms size: 2312101 checksum: sha256:15eeffee75eaef17e056cef4d5207825782a755db6dfd509a759e672ffd03b6c name: tar evr: 2:1.34-13.el9_8 - - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/source/SRPMS/Packages/t/tzdata-2026c-1.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/source/SRPMS/Packages/t/tzdata-2026e-1.el9_8.src.rpm repoid: rhel-9-for-s390x-baseos-source-rpms - size: 933774 - checksum: sha256:4cc10832b19807c03a30bd9317fb37dc811d2f13c11b1ed35af8d2efa481622f + size: 943814 + checksum: sha256:016ab67407e6f67418d8f36c5944396fe82c85896b9e945441f93d3cf1b823b4 name: tzdata - evr: 2026c-1.el9_8 + evr: 2026e-1.el9_8 - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/baseos/source/SRPMS/Packages/u/util-linux-2.37.4-25.el9.src.rpm repoid: rhel-9-for-s390x-baseos-source-rpms size: 6291867 @@ -4916,10 +4916,10 @@ arches: name: zstd evr: 1.5.5-1.el9 module_metadata: - - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/appstream/os/repodata/d7098b11cf478a131c610b3ffbb18970f2ee9f73e3fc55449a8f8ffb790ce054-modules.yaml.gz + - url: https://cdn.redhat.com/content/dist/rhel9/9/s390x/appstream/os/repodata/7dc4986dbd0c0869d9d96782d955fa25fd75b6262959b8b115c35b4a58ed5570-modules.yaml.gz repoid: rhel-9-for-s390x-appstream-rpms - size: 63885 - checksum: sha256:d7098b11cf478a131c610b3ffbb18970f2ee9f73e3fc55449a8f8ffb790ce054 + size: 65738 + checksum: sha256:7dc4986dbd0c0869d9d96782d955fa25fd75b6262959b8b115c35b4a58ed5570 - arch: x86_64 packages: - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/appstream/os/Packages/c/cpp-11.5.0-14.el9.x86_64.rpm @@ -4936,13 +4936,13 @@ arches: name: delve evr: 1.26.1-1.el9_8 sourcerpm: delve-1.26.1-1.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/appstream/os/Packages/g/gawk-all-langpacks-5.1.0-6.el9.x86_64.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/appstream/os/Packages/g/gawk-all-langpacks-5.1.0-6.el9_8.1.x86_64.rpm repoid: rhel-9-for-x86_64-appstream-rpms - size: 216340 - checksum: sha256:c1fcc71c1cc1160d58ace4b60cc6733b68d6f6d406e5ec5ce24327787f452cd1 + size: 218134 + checksum: sha256:bedaac1d71ca9f41e3398dc413dea2008bfd20799de1b4db14e37ebb7a7ce74d name: gawk-all-langpacks - evr: 5.1.0-6.el9 - sourcerpm: gawk-5.1.0-6.el9.src.rpm + evr: 5.1.0-6.el9_8.1 + sourcerpm: gawk-5.1.0-6.el9_8.1.src.rpm - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/appstream/os/Packages/g/gcc-11.5.0-14.el9.x86_64.rpm repoid: rhel-9-for-x86_64-appstream-rpms size: 33982584 @@ -4950,62 +4950,62 @@ arches: name: gcc evr: 11.5.0-14.el9 sourcerpm: gcc-11.5.0-14.el9.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/appstream/os/Packages/g/glibc-devel-2.34-275.el9_8.x86_64.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/appstream/os/Packages/g/glibc-devel-2.34-283.el9_8.x86_64.rpm repoid: rhel-9-for-x86_64-appstream-rpms - size: 46499 - checksum: sha256:a3b6ed698d21192fa7c421094a5d6648411fba4252db28c96d629778c86e6cd5 + size: 46663 + checksum: sha256:5f47e3ae6aea8fde6cbb02357463b3e8c884971284267ced3806b16a93a5c2e5 name: glibc-devel - evr: 2.34-275.el9_8 - sourcerpm: glibc-2.34-275.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/appstream/os/Packages/g/glibc-headers-2.34-275.el9_8.x86_64.rpm + evr: 2.34-283.el9_8 + sourcerpm: glibc-2.34-283.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/appstream/os/Packages/g/glibc-headers-2.34-283.el9_8.x86_64.rpm repoid: rhel-9-for-x86_64-appstream-rpms - size: 567171 - checksum: sha256:2124192aba2e7931cdf00c2dcd4b70b71b313790c28dcf09b2fb09cc9831c86f + size: 567260 + checksum: sha256:796a7079041c288eec9e74437c2f9f85513c0dfade393877a9281828bb55e966 name: glibc-headers - evr: 2.34-275.el9_8 - sourcerpm: glibc-2.34-275.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/appstream/os/Packages/g/go-toolset-1.26.7-1.el9_8.x86_64.rpm + evr: 2.34-283.el9_8 + sourcerpm: glibc-2.34-283.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/appstream/os/Packages/g/go-toolset-1.26.7-2.el9_8.x86_64.rpm repoid: rhel-9-for-x86_64-appstream-rpms - size: 12393 - checksum: sha256:e8d30ba284a372bbdbf1f899231ad3c59ddac6a783415f0784d194a1f4d314f1 + size: 12485 + checksum: sha256:d90108b27b68942ac00068421d4cb3551320fb8345bdabf5684d6868dca0b25c name: go-toolset - evr: 1.26.7-1.el9_8 - sourcerpm: golang-1.26.7-1.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/appstream/os/Packages/g/golang-1.26.7-1.el9_8.x86_64.rpm + evr: 1.26.7-2.el9_8 + sourcerpm: golang-1.26.7-2.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/appstream/os/Packages/g/golang-1.26.7-2.el9_8.x86_64.rpm repoid: rhel-9-for-x86_64-appstream-rpms - size: 1520026 - checksum: sha256:ab786d635b438822c9fa3ddc2a0f056e1cf9ab83bcfcca285c2ac9714a9b903c + size: 1519594 + checksum: sha256:120adc77ba187e12ba0f564e989ad2a495a3cd4db854ff8950bb0fa820d440d3 name: golang - evr: 1.26.7-1.el9_8 - sourcerpm: golang-1.26.7-1.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/appstream/os/Packages/g/golang-bin-1.26.7-1.el9_8.x86_64.rpm + evr: 1.26.7-2.el9_8 + sourcerpm: golang-1.26.7-2.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/appstream/os/Packages/g/golang-bin-1.26.7-2.el9_8.x86_64.rpm repoid: rhel-9-for-x86_64-appstream-rpms - size: 47194775 - checksum: sha256:d68cc646382e339b5860d44cdf3c23c135523dc52a5cf52c4919f25130ad7c07 + size: 47210487 + checksum: sha256:d62137e48551c075bf6addd0946a49d833a63e57eee66199220a2102039abc32 name: golang-bin - evr: 1.26.7-1.el9_8 - sourcerpm: golang-1.26.7-1.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/appstream/os/Packages/g/golang-race-1.26.7-1.el9_8.x86_64.rpm + evr: 1.26.7-2.el9_8 + sourcerpm: golang-1.26.7-2.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/appstream/os/Packages/g/golang-race-1.26.7-2.el9_8.x86_64.rpm repoid: rhel-9-for-x86_64-appstream-rpms - size: 1742998 - checksum: sha256:c4f7bcb59a53fb8881935b88869ccb6cac3facf6444b344e2f5adb76e16cf932 + size: 1743083 + checksum: sha256:afbb626a86be3ed06007041a4d1c9c1fc82ab06d79ab9e8e1f32ece08427290a name: golang-race - evr: 1.26.7-1.el9_8 - sourcerpm: golang-1.26.7-1.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/appstream/os/Packages/g/golang-src-1.26.7-1.el9_8.noarch.rpm + evr: 1.26.7-2.el9_8 + sourcerpm: golang-1.26.7-2.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/appstream/os/Packages/g/golang-src-1.26.7-2.el9_8.noarch.rpm repoid: rhel-9-for-x86_64-appstream-rpms - size: 12881267 - checksum: sha256:b570b95df0bc6429486a71a10fb433f56bb3a694f5de8a777131b2a841e81181 + size: 12879471 + checksum: sha256:ff54c6f194fcf25d743af1af7893242085c798b7ce04056066fee993c2167166 name: golang-src - evr: 1.26.7-1.el9_8 - sourcerpm: golang-1.26.7-1.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/appstream/os/Packages/k/kernel-headers-5.14.0-687.46.1.el9_8.x86_64.rpm + evr: 1.26.7-2.el9_8 + sourcerpm: golang-1.26.7-2.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/appstream/os/Packages/k/kernel-headers-5.14.0-687.57.1.el9_8.x86_64.rpm repoid: rhel-9-for-x86_64-appstream-rpms - size: 2921665 - checksum: sha256:a33898add57c43e68cc37c0cfb99d8b96cbc0be46b47e58d69b2e9738b9ad998 + size: 2979225 + checksum: sha256:c5766b2f8e4531f824575546028de7d8eb9fa95d7246dfafd4883c58312a2ef2 name: kernel-headers - evr: 5.14.0-687.46.1.el9_8 - sourcerpm: kernel-5.14.0-687.46.1.el9_8.src.rpm + evr: 5.14.0-687.57.1.el9_8 + sourcerpm: kernel-5.14.0-687.57.1.el9_8.src.rpm - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/appstream/os/Packages/l/libmpc-1.2.1-4.el9.x86_64.rpm repoid: rhel-9-for-x86_64-appstream-rpms size: 66075 @@ -5041,41 +5041,41 @@ arches: name: mpdecimal evr: 2.5.1-3.el9 sourcerpm: mpdecimal-2.5.1-3.el9.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/appstream/os/Packages/o/openssl-devel-3.5.5-6.el9_8.x86_64.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/appstream/os/Packages/o/openssl-devel-3.5.8-2.el9_8.x86_64.rpm repoid: rhel-9-for-x86_64-appstream-rpms - size: 5029526 - checksum: sha256:84e54b3467ecfe70c75688f28dbc0e071e268d845db17b28a1f35a35d45640cd + size: 5050455 + checksum: sha256:72a693633446cd95202dd926109bf25aeb8ace8d91a630583f6d25e0ce10c0f3 name: openssl-devel - evr: 1:3.5.5-6.el9_8 - sourcerpm: openssl-3.5.5-6.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/appstream/os/Packages/p/postgresql-15.18-1.module+el9.8.0+24358+32c5830e.x86_64.rpm + evr: 1:3.5.8-2.el9_8 + sourcerpm: openssl-3.5.8-2.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/appstream/os/Packages/p/postgresql-16.15-1.module+el9.8.0+24803+9dca000b.x86_64.rpm repoid: rhel-9-for-x86_64-appstream-rpms - size: 1832108 - checksum: sha256:1f2f8e5526bac45da979c876fbb9a069459ec5a6476d89398433048005fb786b + size: 2067493 + checksum: sha256:f078cf1183f6bb750e39cdcab4d2ecb3f936d745b7360b741a6919e926855ad7 name: postgresql - evr: 15.18-1.module+el9.8.0+24358+32c5830e - sourcerpm: postgresql-15.18-1.module+el9.8.0+24358+32c5830e.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/appstream/os/Packages/p/postgresql-private-libs-15.18-1.module+el9.8.0+24358+32c5830e.x86_64.rpm + evr: 16.15-1.module+el9.8.0+24803+9dca000b + sourcerpm: postgresql-16.15-1.module+el9.8.0+24803+9dca000b.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/appstream/os/Packages/p/postgresql-private-libs-16.15-1.module+el9.8.0+24803+9dca000b.x86_64.rpm repoid: rhel-9-for-x86_64-appstream-rpms - size: 154248 - checksum: sha256:a8fca7c9e1d9cf9aa6eb95fd39e90068960190b40cac303f546930cab667ae11 + size: 153488 + checksum: sha256:f36cf284eb08753b6b2576f8eed63c8c2651ef82e618fe1641a6b0ff4cd2d4ca name: postgresql-private-libs - evr: 15.18-1.module+el9.8.0+24358+32c5830e - sourcerpm: postgresql-15.18-1.module+el9.8.0+24358+32c5830e.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/appstream/os/Packages/p/python3.12-3.12.14-1.el9_8.x86_64.rpm + evr: 16.15-1.module+el9.8.0+24803+9dca000b + sourcerpm: postgresql-16.15-1.module+el9.8.0+24803+9dca000b.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/appstream/os/Packages/p/python3.12-3.12.15-1.el9_8.x86_64.rpm repoid: rhel-9-for-x86_64-appstream-rpms - size: 32484 - checksum: sha256:10640d8db1555fb7ae4e63c62be4b8f341032fb3ee52cc7176047438ab893b1f + size: 32669 + checksum: sha256:819f912b87f620c462ab6500eea6ac8acf1c41c395af39746c30db2ab84e5629 name: python3.12 - evr: 3.12.14-1.el9_8 - sourcerpm: python3.12-3.12.14-1.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/appstream/os/Packages/p/python3.12-libs-3.12.14-1.el9_8.x86_64.rpm + evr: 3.12.15-1.el9_8 + sourcerpm: python3.12-3.12.15-1.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/appstream/os/Packages/p/python3.12-libs-3.12.15-1.el9_8.x86_64.rpm repoid: rhel-9-for-x86_64-appstream-rpms - size: 10211157 - checksum: sha256:0eaade47a20924ba0fe3fb0a93898e053772248793069f40c1ba80c5115fddbb + size: 10213038 + checksum: sha256:d2791de143c4172a6a2c272521071f580a78d3527781e074d8d2405de66fda2c name: python3.12-libs - evr: 3.12.14-1.el9_8 - sourcerpm: python3.12-3.12.14-1.el9_8.src.rpm + evr: 3.12.15-1.el9_8 + sourcerpm: python3.12-3.12.15-1.el9_8.src.rpm - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/appstream/os/Packages/p/python3.12-pip-wheel-23.2.1-5.el9.noarch.rpm repoid: rhel-9-for-x86_64-appstream-rpms size: 1527128 @@ -5251,13 +5251,13 @@ arches: name: elfutils-libs evr: 0.194-1.el9 sourcerpm: elfutils-0.194-1.el9.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/os/Packages/e/expat-2.5.0-6.el9_8.3.x86_64.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/os/Packages/e/expat-2.5.0-6.el9_8.5.x86_64.rpm repoid: rhel-9-for-x86_64-baseos-rpms - size: 128577 - checksum: sha256:3c9c96529f94f84fc19c8039d8852269e1085d16b5af2933f44ff286dec66a35 + size: 129088 + checksum: sha256:e6e7edd632fdd1dc4ad94b19b7ab88646f3ef8c1c7956bac58985c3e7118a362 name: expat - evr: 2.5.0-6.el9_8.3 - sourcerpm: expat-2.5.0-6.el9_8.3.src.rpm + evr: 2.5.0-6.el9_8.5 + sourcerpm: expat-2.5.0-6.el9_8.5.src.rpm - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/os/Packages/f/filesystem-3.16-5.el9.x86_64.rpm repoid: rhel-9-for-x86_64-baseos-rpms size: 5003807 @@ -5272,13 +5272,13 @@ arches: name: findutils evr: 1:4.8.0-7.el9 sourcerpm: findutils-4.8.0-7.el9.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/os/Packages/g/gawk-5.1.0-6.el9.x86_64.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/os/Packages/g/gawk-5.1.0-6.el9_8.1.x86_64.rpm repoid: rhel-9-for-x86_64-baseos-rpms - size: 1045534 - checksum: sha256:99fda6725a2c668bae29fbab74d1b347e074f4e8c8ed18d656cb928fb6fc92b7 + size: 1046649 + checksum: sha256:fcc5e724c32597cf781626728f0faff2f0e5ed6455ab95af4883eefca30a074e name: gawk - evr: 5.1.0-6.el9 - sourcerpm: gawk-5.1.0-6.el9.src.rpm + evr: 5.1.0-6.el9_8.1 + sourcerpm: gawk-5.1.0-6.el9_8.1.src.rpm - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/os/Packages/g/gdbm-libs-1.23-1.el9.x86_64.rpm repoid: rhel-9-for-x86_64-baseos-rpms size: 60152 @@ -5286,34 +5286,34 @@ arches: name: gdbm-libs evr: 1:1.23-1.el9 sourcerpm: gdbm-1.23-1.el9.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/os/Packages/g/glibc-2.34-275.el9_8.x86_64.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/os/Packages/g/glibc-2.34-283.el9_8.x86_64.rpm repoid: rhel-9-for-x86_64-baseos-rpms - size: 2083064 - checksum: sha256:7d2d420b97c05c09ee1e9bd881cb0725fe8d89688b933f411f278cb23210c65d + size: 2083811 + checksum: sha256:ac0a85530d147cc35d56422d2f6eab14800eec63c6d5318f2bef576252426939 name: glibc - evr: 2.34-275.el9_8 - sourcerpm: glibc-2.34-275.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/os/Packages/g/glibc-common-2.34-275.el9_8.x86_64.rpm + evr: 2.34-283.el9_8 + sourcerpm: glibc-2.34-283.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/os/Packages/g/glibc-common-2.34-283.el9_8.x86_64.rpm repoid: rhel-9-for-x86_64-baseos-rpms - size: 321585 - checksum: sha256:f23581b888783f576bd3a55503618a48f74f468fcfd4837bbd7a2d00fe7f3530 + size: 321942 + checksum: sha256:87a1528415c5a1680faf8a816bf4a79e423f1b13c9a7d1aac387a5080ea48738 name: glibc-common - evr: 2.34-275.el9_8 - sourcerpm: glibc-2.34-275.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/os/Packages/g/glibc-gconv-extra-2.34-275.el9_8.x86_64.rpm + evr: 2.34-283.el9_8 + sourcerpm: glibc-2.34-283.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/os/Packages/g/glibc-gconv-extra-2.34-283.el9_8.x86_64.rpm repoid: rhel-9-for-x86_64-baseos-rpms - size: 1763577 - checksum: sha256:91899acba57caeb8768bf2ce4631d7f56c6b8e052f2bdf20003382205eb8eee8 + size: 1767979 + checksum: sha256:d421d4318c25a5817f72f4547b0be36c6be99303138a738080cdbe161577d31a name: glibc-gconv-extra - evr: 2.34-275.el9_8 - sourcerpm: glibc-2.34-275.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/os/Packages/g/glibc-minimal-langpack-2.34-275.el9_8.x86_64.rpm + evr: 2.34-283.el9_8 + sourcerpm: glibc-2.34-283.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/os/Packages/g/glibc-minimal-langpack-2.34-283.el9_8.x86_64.rpm repoid: rhel-9-for-x86_64-baseos-rpms - size: 30913 - checksum: sha256:6cc48d78bf2ceacfa5b58633b648c564b66505f4677adea8eb663fe90acd76f2 + size: 31065 + checksum: sha256:4031293a63d3851b03969172779a9b0f6669e00a544c80425c9eae74e08c70b0 name: glibc-minimal-langpack - evr: 2.34-275.el9_8 - sourcerpm: glibc-2.34-275.el9_8.src.rpm + evr: 2.34-283.el9_8 + sourcerpm: glibc-2.34-283.el9_8.src.rpm - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/os/Packages/g/gmp-6.2.0-13.el9.x86_64.rpm repoid: rhel-9-for-x86_64-baseos-rpms size: 326840 @@ -5398,13 +5398,13 @@ arches: name: libblkid evr: 2.37.4-25.el9 sourcerpm: util-linux-2.37.4-25.el9.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/os/Packages/l/libbrotli-1.0.9-9.el9_7.x86_64.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/os/Packages/l/libbrotli-1.0.9-10.el9_8.x86_64.rpm repoid: rhel-9-for-x86_64-baseos-rpms - size: 326278 - checksum: sha256:81096e6aed022489306e2fe1d1496b2b689d8f0bf6c70a94b5bddb82356eeda1 + size: 326501 + checksum: sha256:ecf2cda794cb9f68a7f67742ce0aeef4c3480795cce0e9bc8f49634072fd2e07 name: libbrotli - evr: 1.0.9-9.el9_7 - sourcerpm: brotli-1.0.9-9.el9_7.src.rpm + evr: 1.0.9-10.el9_8 + sourcerpm: brotli-1.0.9-10.el9_8.src.rpm - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/os/Packages/l/libcap-2.48-10.el9_8.1.x86_64.rpm repoid: rhel-9-for-x86_64-baseos-rpms size: 78928 @@ -5426,13 +5426,13 @@ arches: name: libcom_err evr: 1.46.5-8.el9 sourcerpm: e2fsprogs-1.46.5-8.el9.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/os/Packages/l/libcurl-7.76.1-40.el9_8.5.x86_64.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/os/Packages/l/libcurl-7.76.1-40.el9_8.8.x86_64.rpm repoid: rhel-9-for-x86_64-baseos-rpms - size: 297551 - checksum: sha256:428b87ca3eb808d769f6f0f68019a97d3c487c86268ccff2ab7ad7223beab01e + size: 297409 + checksum: sha256:cc12ee8e4fb07d93ad55dc59406ff65a3acbb795b3eca30b32195e51b3a12965 name: libcurl - evr: 7.76.1-40.el9_8.5 - sourcerpm: curl-7.76.1-40.el9_8.5.src.rpm + evr: 7.76.1-40.el9_8.8 + sourcerpm: curl-7.76.1-40.el9_8.8.src.rpm - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/os/Packages/l/libdb-5.3.28-57.el9_6.x86_64.rpm repoid: rhel-9-for-x86_64-baseos-rpms size: 755192 @@ -5447,13 +5447,13 @@ arches: name: libeconf evr: 0.4.1-7.el9_8 sourcerpm: libeconf-0.4.1-7.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/os/Packages/l/libevent-2.1.12-8.el9_4.x86_64.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/os/Packages/l/libevent-2.1.13-1.el9_8.x86_64.rpm repoid: rhel-9-for-x86_64-baseos-rpms - size: 272588 - checksum: sha256:072426910a254b797bbe977b3397ab90513911d020580a0135179f700a48df44 + size: 276162 + checksum: sha256:c28b28573118d5cf0f1f68d96bc7c46d56671e45360698c894ca06ddf40163ae name: libevent - evr: 2.1.12-8.el9_4 - sourcerpm: libevent-2.1.12-8.el9_4.src.rpm + evr: 2.1.13-1.el9_8 + sourcerpm: libevent-2.1.13-1.el9_8.src.rpm - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/os/Packages/l/libfdisk-2.37.4-25.el9.x86_64.rpm repoid: rhel-9-for-x86_64-baseos-rpms size: 161769 @@ -5713,13 +5713,13 @@ arches: name: openldap evr: 2.6.8-4.el9 sourcerpm: openldap-2.6.8-4.el9.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/os/Packages/o/openssl-3.5.5-6.el9_8.x86_64.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/os/Packages/o/openssl-3.5.8-2.el9_8.x86_64.rpm repoid: rhel-9-for-x86_64-baseos-rpms - size: 1564334 - checksum: sha256:1c502507f42674119318b66b111448f618efe2767a55edde5fadddcecb47ac64 + size: 1570074 + checksum: sha256:4a560a738babd422ff2ba6077da7abfe1b9ce5ef89c056ec5f693334dbebf928 name: openssl - evr: 1:3.5.5-6.el9_8 - sourcerpm: openssl-3.5.5-6.el9_8.src.rpm + evr: 1:3.5.8-2.el9_8 + sourcerpm: openssl-3.5.8-2.el9_8.src.rpm - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/os/Packages/o/openssl-fips-provider-3.0.7-11.el9_8.x86_64.rpm repoid: rhel-9-for-x86_64-baseos-rpms size: 14256 @@ -5734,13 +5734,13 @@ arches: name: openssl-fips-provider-so evr: 3.0.7-11.el9_8 sourcerpm: openssl-fips-provider-3.0.7-11.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/os/Packages/o/openssl-libs-3.5.5-6.el9_8.x86_64.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/os/Packages/o/openssl-libs-3.5.8-2.el9_8.x86_64.rpm repoid: rhel-9-for-x86_64-baseos-rpms - size: 2427181 - checksum: sha256:a289cdf4da547031cd39a4f31decd0bb22649bbcb5fe4f88b939d341a83708be + size: 2431317 + checksum: sha256:6448671d67b300025edac8382995707a0763ae0843e097cbe717d1cbc29817e2 name: openssl-libs - evr: 1:3.5.5-6.el9_8 - sourcerpm: openssl-3.5.5-6.el9_8.src.rpm + evr: 1:3.5.8-2.el9_8 + sourcerpm: openssl-3.5.8-2.el9_8.src.rpm - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/os/Packages/p/p11-kit-0.26.4-1.el9_8.x86_64.rpm repoid: rhel-9-for-x86_64-baseos-rpms size: 625862 @@ -5769,20 +5769,20 @@ arches: name: pcre evr: 8.44-4.el9 sourcerpm: pcre-8.44-4.el9.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/os/Packages/p/pcre2-10.40-6.el9.x86_64.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/os/Packages/p/pcre2-10.40-7.el9_8.x86_64.rpm repoid: rhel-9-for-x86_64-baseos-rpms - size: 241900 - checksum: sha256:75db1e5a50e7b1794d7ba18212d95cd2684559da9e7c52eee46490302c7f24dd + size: 244785 + checksum: sha256:ef2c65a463e1ef1bfbf3d9ee66986e14cca0fbae88343f099dd5b16619276f1f name: pcre2 - evr: 10.40-6.el9 - sourcerpm: pcre2-10.40-6.el9.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/os/Packages/p/pcre2-syntax-10.40-6.el9.noarch.rpm + evr: 10.40-7.el9_8 + sourcerpm: pcre2-10.40-7.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/os/Packages/p/pcre2-syntax-10.40-7.el9_8.noarch.rpm repoid: rhel-9-for-x86_64-baseos-rpms - size: 147926 - checksum: sha256:d386b5e9b3a4b077b2ba143882e605750855dd3354f13c55fa12ed26908cb442 + size: 150069 + checksum: sha256:e7466a43ef2bfda2b1dc07e855b0db743d48b11c0bdc1402e1d2ea6fb23d33a3 name: pcre2-syntax - evr: 10.40-6.el9 - sourcerpm: pcre2-10.40-6.el9.src.rpm + evr: 10.40-7.el9_8 + sourcerpm: pcre2-10.40-7.el9_8.src.rpm - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/os/Packages/p/pigz-2.8-1.el9.x86_64.rpm repoid: rhel-9-for-x86_64-baseos-rpms size: 99148 @@ -5867,34 +5867,34 @@ arches: name: sqlite-libs evr: 3.34.1-11.el9_8 sourcerpm: sqlite-3.34.1-11.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/os/Packages/s/systemd-252-67.el9_8.4.x86_64.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/os/Packages/s/systemd-252-67.el9_8.6.x86_64.rpm repoid: rhel-9-for-x86_64-baseos-rpms - size: 4401138 - checksum: sha256:e3cbe70aaa847f1b02bd4ea9470625434c26b25368cbfcb0e9a18de99e3bc1c7 + size: 4383786 + checksum: sha256:025ffe42235a9d4d40138bab7511995392d2a50ba6912be97b47e634b15823b8 name: systemd - evr: 252-67.el9_8.4 - sourcerpm: systemd-252-67.el9_8.4.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/os/Packages/s/systemd-libs-252-67.el9_8.4.x86_64.rpm + evr: 252-67.el9_8.6 + sourcerpm: systemd-252-67.el9_8.6.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/os/Packages/s/systemd-libs-252-67.el9_8.6.x86_64.rpm repoid: rhel-9-for-x86_64-baseos-rpms - size: 681056 - checksum: sha256:ca5a11f102b0e3a32fdddf017a4509984db83290d7364c9566d037d0ef7f1e66 + size: 662007 + checksum: sha256:d491d7375ed820bf4fa0d5f6d80a6f1a72cfa6ff31e79dabf9288246061cf88e name: systemd-libs - evr: 252-67.el9_8.4 - sourcerpm: systemd-252-67.el9_8.4.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/os/Packages/s/systemd-pam-252-67.el9_8.4.x86_64.rpm + evr: 252-67.el9_8.6 + sourcerpm: systemd-252-67.el9_8.6.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/os/Packages/s/systemd-pam-252-67.el9_8.6.x86_64.rpm repoid: rhel-9-for-x86_64-baseos-rpms - size: 276960 - checksum: sha256:de8408dbe8ee06afa99fbb914377384774e27b9b337cb3b491a37f84ccca7e9b + size: 258340 + checksum: sha256:eb780b309cd671d4b3bec7d3b31bf148179e527d7222663544470310f4cb43ee name: systemd-pam - evr: 252-67.el9_8.4 - sourcerpm: systemd-252-67.el9_8.4.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/os/Packages/s/systemd-rpm-macros-252-67.el9_8.4.noarch.rpm + evr: 252-67.el9_8.6 + sourcerpm: systemd-252-67.el9_8.6.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/os/Packages/s/systemd-rpm-macros-252-67.el9_8.6.noarch.rpm repoid: rhel-9-for-x86_64-baseos-rpms - size: 59475 - checksum: sha256:7d671ec39a7caeb7346be6d5fcb44212545844ced6f4974c4b409fef6a12a891 + size: 40844 + checksum: sha256:974a0352427799559a3e90dcdb38200d767631452cca7717c5b0fbe7760df313 name: systemd-rpm-macros - evr: 252-67.el9_8.4 - sourcerpm: systemd-252-67.el9_8.4.src.rpm + evr: 252-67.el9_8.6 + sourcerpm: systemd-252-67.el9_8.6.src.rpm - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/os/Packages/t/tar-1.34-13.el9_8.x86_64.rpm repoid: rhel-9-for-x86_64-baseos-rpms size: 914200 @@ -5902,13 +5902,13 @@ arches: name: tar evr: 2:1.34-13.el9_8 sourcerpm: tar-1.34-13.el9_8.src.rpm - - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/os/Packages/t/tzdata-2026c-1.el9_8.noarch.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/os/Packages/t/tzdata-2026e-1.el9_8.noarch.rpm repoid: rhel-9-for-x86_64-baseos-rpms - size: 933286 - checksum: sha256:8d6196e02853c0900c3c2e2367665beffb62cb2d0ff5f465ea2d00848a9a35dc + size: 936099 + checksum: sha256:c105d92f6cacb9bb8337b77041cedd9c9c906a72c4b5233909b9b69b78f4369f name: tzdata - evr: 2026c-1.el9_8 - sourcerpm: tzdata-2026c-1.el9_8.src.rpm + evr: 2026e-1.el9_8 + sourcerpm: tzdata-2026e-1.el9_8.src.rpm - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/os/Packages/u/util-linux-2.37.4-25.el9.x86_64.rpm repoid: rhel-9-for-x86_64-baseos-rpms size: 2382511 @@ -5944,12 +5944,12 @@ arches: checksum: sha256:5fa267daa0e7df3e072c17e81db41b809b256da8cfb0372669d9a1bea937a01a name: delve evr: 1.26.1-1.el9_8 - - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/appstream/source/SRPMS/Packages/g/golang-1.26.7-1.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/appstream/source/SRPMS/Packages/g/golang-1.26.7-2.el9_8.src.rpm repoid: rhel-9-for-x86_64-appstream-source-rpms - size: 36535123 - checksum: sha256:3e46d00b71773429b84079992fff32610eda8917d7319d09c3cee5e6e4bd5bf5 + size: 36539286 + checksum: sha256:7a9ea792be9d09b61bc321ce8b65a040430d06891d6372aeb929753c2f270770 name: golang - evr: 1.26.7-1.el9_8 + evr: 1.26.7-2.el9_8 - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/appstream/source/SRPMS/Packages/l/libmpc-1.2.1-4.el9.src.rpm repoid: rhel-9-for-x86_64-appstream-source-rpms size: 846236 @@ -5974,18 +5974,18 @@ arches: checksum: sha256:2f5ece89d6a8d892816f386462d8be291ad83f1500b4c4b3655dcc7ed5192c0d name: mpdecimal evr: 2.5.1-3.el9 - - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/appstream/source/SRPMS/Packages/p/postgresql-15.18-1.module+el9.8.0+24358+32c5830e.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/appstream/source/SRPMS/Packages/p/postgresql-16.15-1.module+el9.8.0+24803+9dca000b.src.rpm repoid: rhel-9-for-x86_64-appstream-source-rpms - size: 45775054 - checksum: sha256:5955f781730fe817b08b7ddc3d2117a7c0a0c95ed2fd2044cbc1ff7d1eba1b28 + size: 48516429 + checksum: sha256:fdb3a4e84c097bb87061fbf6b3f1f11a03b4aa6adf13b0b20cc1d439b5a2c7d7 name: postgresql - evr: 15.18-1.module+el9.8.0+24358+32c5830e - - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/appstream/source/SRPMS/Packages/p/python3.12-3.12.14-1.el9_8.src.rpm + evr: 16.15-1.module+el9.8.0+24803+9dca000b + - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/appstream/source/SRPMS/Packages/p/python3.12-3.12.15-1.el9_8.src.rpm repoid: rhel-9-for-x86_64-appstream-source-rpms - size: 20894742 - checksum: sha256:d855a90132b827b528e26c617484c250fd02dbe2cc8fdb8ef1f7d0d0a9f3f4f7 + size: 20904561 + checksum: sha256:8a3db1154cbfe206ac68b31268348da6039522d09be22520dd94207417146ebd name: python3.12 - evr: 3.12.14-1.el9_8 + evr: 3.12.15-1.el9_8 - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/appstream/source/SRPMS/Packages/p/python3.12-pip-23.2.1-5.el9.src.rpm repoid: rhel-9-for-x86_64-appstream-source-rpms size: 9384965 @@ -6034,12 +6034,12 @@ arches: checksum: sha256:82174416ee39df7795da7fab8d37ea5dbbe25f1dbc2df39f5fb3f8a168bf5120 name: binutils evr: 2.35.2-72.el9 - - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/source/SRPMS/Packages/b/brotli-1.0.9-9.el9_7.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/source/SRPMS/Packages/b/brotli-1.0.9-10.el9_8.src.rpm repoid: rhel-9-for-x86_64-baseos-source-rpms - size: 517498 - checksum: sha256:814868e0bec831c79d3e12ff76d31e06e5e62c462a1a4b6607b1f3cab7014438 + size: 519221 + checksum: sha256:c833ffbd6c6555543472ef4034a958cf4b8b8dee35b8661b2144ca6fc38908c7 name: brotli - evr: 1.0.9-9.el9_7 + evr: 1.0.9-10.el9_8 - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/source/SRPMS/Packages/b/bzip2-1.0.8-11.el9.src.rpm repoid: rhel-9-for-x86_64-baseos-source-rpms size: 828199 @@ -6076,12 +6076,12 @@ arches: checksum: sha256:775d926429179caeade6af8dc7dea15a0bea49102c2592d5b712f996a329ec38 name: crypto-policies evr: 20260224-1.gitea0f072.el9_8 - - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/source/SRPMS/Packages/c/curl-7.76.1-40.el9_8.5.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/source/SRPMS/Packages/c/curl-7.76.1-40.el9_8.8.src.rpm repoid: rhel-9-for-x86_64-baseos-source-rpms - size: 2576796 - checksum: sha256:5a455f6c35ae1069b8c54ade4c9d0d3d260134f76bee10f22efef9683c31b03f + size: 2581541 + checksum: sha256:303a97cbdfaaac1d709ef7621b2b349dc403da6a553ecfe5e3114f76d757d554 name: curl - evr: 7.76.1-40.el9_8.5 + evr: 7.76.1-40.el9_8.8 - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/source/SRPMS/Packages/c/cyrus-sasl-2.1.27-22.el9.src.rpm repoid: rhel-9-for-x86_64-baseos-source-rpms size: 4025677 @@ -6118,12 +6118,12 @@ arches: checksum: sha256:643279e796ded16c5be5cdc2a91839c787e62e59757008675eb0580a4a42af21 name: elfutils evr: 0.194-1.el9 - - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/source/SRPMS/Packages/e/expat-2.5.0-6.el9_8.3.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/source/SRPMS/Packages/e/expat-2.5.0-6.el9_8.5.src.rpm repoid: rhel-9-for-x86_64-baseos-source-rpms - size: 8403095 - checksum: sha256:0cff2a2213384dc43eb1874bf6e77b2b8230be848f50387d8057e0e6cde3d392 + size: 8411609 + checksum: sha256:38d7acfd1130c02c6a00010159a1350ca0f56cd7ed64f3d8394aa5b3d6512ddd name: expat - evr: 2.5.0-6.el9_8.3 + evr: 2.5.0-6.el9_8.5 - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/source/SRPMS/Packages/f/filesystem-3.16-5.el9.src.rpm repoid: rhel-9-for-x86_64-baseos-source-rpms size: 20486 @@ -6136,12 +6136,12 @@ arches: checksum: sha256:48bd4d4dd081120bcc6ab772b930a150f30b2fc89a4a14a24220383d24a30b3f name: findutils evr: 1:4.8.0-7.el9 - - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/source/SRPMS/Packages/g/gawk-5.1.0-6.el9.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/source/SRPMS/Packages/g/gawk-5.1.0-6.el9_8.1.src.rpm repoid: rhel-9-for-x86_64-baseos-source-rpms - size: 3190934 - checksum: sha256:37571947707e835d36ceb5641b187aba13ef8f5f605a6762ce72aeea3e745b8d + size: 3197459 + checksum: sha256:8f156f11c96b1720ba2e9e287f2ddf5e0588a9c9ad17753f779ebbdf0c4e99df name: gawk - evr: 5.1.0-6.el9 + evr: 5.1.0-6.el9_8.1 - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/source/SRPMS/Packages/g/gcc-11.5.0-14.el9.src.rpm repoid: rhel-9-for-x86_64-baseos-source-rpms size: 81978017 @@ -6154,12 +6154,12 @@ arches: checksum: sha256:ad42264274c2a792220395a4dbe736a1de6100c4e14611707ec1dd447583271f name: gdbm evr: 1:1.23-1.el9 - - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/source/SRPMS/Packages/g/glibc-2.34-275.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/source/SRPMS/Packages/g/glibc-2.34-283.el9_8.src.rpm repoid: rhel-9-for-x86_64-baseos-source-rpms - size: 20442764 - checksum: sha256:bd7a453f66e13da24d073f53070c2d209fcd88ca2aaa24ab3b2f81cae198b46c + size: 20462553 + checksum: sha256:9007b0a97151f43f812049a925cb418753f9fd643fe1283cc7eddc7e6785e2f3 name: glibc - evr: 2.34-275.el9_8 + evr: 2.34-283.el9_8 - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/source/SRPMS/Packages/g/gmp-6.2.0-13.el9.src.rpm repoid: rhel-9-for-x86_64-baseos-source-rpms size: 2503825 @@ -6190,12 +6190,12 @@ arches: checksum: sha256:c4c76ebfd66ba6d00edf672797d7f077b29d279b7866a04e05258a257a5bc306 name: json-c evr: 0.14-11.el9 - - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/source/SRPMS/Packages/k/kernel-5.14.0-687.46.1.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/source/SRPMS/Packages/k/kernel-5.14.0-687.57.1.el9_8.src.rpm repoid: rhel-9-for-x86_64-baseos-source-rpms - size: 152431117 - checksum: sha256:378c1016ec891505f10477bf4f32f695033e3d4a94e7366d457bc0b076c826fd + size: 152563149 + checksum: sha256:a2660af0b87ac6a4d161ccc76c7d8a8338a44b4fbaad6da9e5529e3027f25aa2 name: kernel - evr: 5.14.0-687.46.1.el9_8 + evr: 5.14.0-687.57.1.el9_8 - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/source/SRPMS/Packages/k/keyutils-1.6.3-1.el9.src.rpm repoid: rhel-9-for-x86_64-baseos-source-rpms size: 150790 @@ -6244,12 +6244,12 @@ arches: checksum: sha256:425009c96135f39ca7bdb8a6ea948187d052d339dd76235979439fbd169da331 name: libeconf evr: 0.4.1-7.el9_8 - - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/source/SRPMS/Packages/l/libevent-2.1.12-8.el9_4.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/source/SRPMS/Packages/l/libevent-2.1.13-1.el9_8.src.rpm repoid: rhel-9-for-x86_64-baseos-source-rpms - size: 1123179 - checksum: sha256:8c00dc837b8685fc660cc0bcdfd4f533888facaa8c83655c26d2fb068cb7b135 + size: 1152974 + checksum: sha256:39aef29e588e3815189ca7b54326a4e1247e8a1f5a44c908ca4325c8cae83acb name: libevent - evr: 2.1.12-8.el9_4 + evr: 2.1.13-1.el9_8 - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/source/SRPMS/Packages/l/libffi-3.4.2-8.el9.src.rpm repoid: rhel-9-for-x86_64-baseos-source-rpms size: 1367398 @@ -6406,12 +6406,12 @@ arches: checksum: sha256:0d21c12c55d40d1fc2f006c8ec187b5fcc799b794cfd31ed2d98434189c62800 name: openldap evr: 2.6.8-4.el9 - - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/source/SRPMS/Packages/o/openssl-3.5.5-6.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/source/SRPMS/Packages/o/openssl-3.5.8-2.el9_8.src.rpm repoid: rhel-9-for-x86_64-baseos-source-rpms - size: 53369050 - checksum: sha256:b79f08d2d04536fdb6801b6ba7da7174942d174dd2b7969316402c737689d735 + size: 53435636 + checksum: sha256:1e67b59efe228f804c0544a31ab3de0bb4a0c8250d3d5f5fc53a3c7794104795 name: openssl - evr: 1:3.5.5-6.el9_8 + evr: 1:3.5.8-2.el9_8 - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/source/SRPMS/Packages/o/openssl-fips-provider-3.0.7-11.el9_8.src.rpm repoid: rhel-9-for-x86_64-baseos-source-rpms size: 28686020 @@ -6436,12 +6436,12 @@ arches: checksum: sha256:7edbd87b866a3f6e3df1426d660b902e063193d6186027bf99f6d77626a43817 name: pcre evr: 8.44-4.el9 - - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/source/SRPMS/Packages/p/pcre2-10.40-6.el9.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/source/SRPMS/Packages/p/pcre2-10.40-7.el9_8.src.rpm repoid: rhel-9-for-x86_64-baseos-source-rpms - size: 1789790 - checksum: sha256:a570f7192be555222aa3704882b9199fb013a84ad4d7dcf40a93d8de2ecf6e0a + size: 1805958 + checksum: sha256:43c40093332890a77f7d7c573a1b540867319bbcaaec5a6dfd73101765dc6ea0 name: pcre2 - evr: 10.40-6.el9 + evr: 10.40-7.el9_8 - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/source/SRPMS/Packages/p/pigz-2.8-1.el9.src.rpm repoid: rhel-9-for-x86_64-baseos-source-rpms size: 131701 @@ -6496,24 +6496,24 @@ arches: checksum: sha256:4efcc956008f0468362b41bdba79111c41027b682bcdea3ecca3744cf50ebfd7 name: sqlite evr: 3.34.1-11.el9_8 - - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/source/SRPMS/Packages/s/systemd-252-67.el9_8.4.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/source/SRPMS/Packages/s/systemd-252-67.el9_8.6.src.rpm repoid: rhel-9-for-x86_64-baseos-source-rpms - size: 45009674 - checksum: sha256:e44181d1de2a135a5507b956d18a9eb11951a35aaa9c15dbc0f144ed8313f732 + size: 45003976 + checksum: sha256:f535f4c20ed82f56cc7f4c86202e3cd582815f702bb0c24005a07a496ec94c97 name: systemd - evr: 252-67.el9_8.4 + evr: 252-67.el9_8.6 - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/source/SRPMS/Packages/t/tar-1.34-13.el9_8.src.rpm repoid: rhel-9-for-x86_64-baseos-source-rpms size: 2312101 checksum: sha256:15eeffee75eaef17e056cef4d5207825782a755db6dfd509a759e672ffd03b6c name: tar evr: 2:1.34-13.el9_8 - - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/source/SRPMS/Packages/t/tzdata-2026c-1.el9_8.src.rpm + - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/source/SRPMS/Packages/t/tzdata-2026e-1.el9_8.src.rpm repoid: rhel-9-for-x86_64-baseos-source-rpms - size: 933774 - checksum: sha256:4cc10832b19807c03a30bd9317fb37dc811d2f13c11b1ed35af8d2efa481622f + size: 943814 + checksum: sha256:016ab67407e6f67418d8f36c5944396fe82c85896b9e945441f93d3cf1b823b4 name: tzdata - evr: 2026c-1.el9_8 + evr: 2026e-1.el9_8 - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/source/SRPMS/Packages/u/util-linux-2.37.4-25.el9.src.rpm repoid: rhel-9-for-x86_64-baseos-source-rpms size: 6291867 @@ -6539,7 +6539,7 @@ arches: name: zstd evr: 1.5.5-1.el9 module_metadata: - - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/appstream/os/repodata/e95e500c807e82466f58d9c5c003da512340e61b83c81070a541c9e041768cf4-modules.yaml.gz + - url: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/appstream/os/repodata/23e894ddbf1b6da3354d9713960e5b9ec453ba7417208b4441fcc9eb979cd456-modules.yaml.gz repoid: rhel-9-for-x86_64-appstream-rpms - size: 68115 - checksum: sha256:e95e500c807e82466f58d9c5c003da512340e61b83c81070a541c9e041768cf4 + size: 72012 + checksum: sha256:23e894ddbf1b6da3354d9713960e5b9ec453ba7417208b4441fcc9eb979cd456 diff --git a/scale/dev/kill-sensors.sh b/scale/dev/kill-sensors.sh index 37fed2d19c707..94c4279c722d1 100755 --- a/scale/dev/kill-sensors.sh +++ b/scale/dev/kill-sensors.sh @@ -3,8 +3,17 @@ set -eoux pipefail echo "Killing sensors" -mapfile -t sensor_namespaces < <(kubectl get namespaces -o custom-columns=:metadata.name | grep -E 'stackrox[0-9]+') +if [[ -n ${1:-} ]]; then + mapfile -t sensor_namespaces < <(for i in $(seq 1 $1); do echo "stackrox${i}"; done) +else + mapfile -t sensor_namespaces < <(kubectl get namespaces -o custom-columns=:metadata.name | grep -E 'stackrox[0-9]+') +fi nnamespace="${#sensor_namespaces[@]}" +for ((i = 0; i < nnamespace; i = i + 1)); do + roxie teardown secured-cluster --set securedCluster.namespace="${sensor_namespaces[i]}" +done +# The pods need a while to shut down which blocks namespace deletion, +# so deleting the namespaces separately speeds things up esp. when there are many. for ((i = 0; i < nnamespace; i = i + 1)); do kubectl delete namespace "${sensor_namespaces[i]}" done diff --git a/scale/dev/launch_central.sh b/scale/dev/launch_central.sh index 2426f50e5c088..74fe4bf2eb18f 100755 --- a/scale/dev/launch_central.sh +++ b/scale/dev/launch_central.sh @@ -4,23 +4,56 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)" local_port=${1:-8000} -export STORAGE=pvc -export STORAGE_SIZE=100 # This is GKE specific so we may need to be careful in the future if kubectl version -o json | jq .serverVersion.gitVersion | grep "gke" > /dev/null; then - echo "Setting storage class to faster" - export STORAGE_CLASS=faster + echo "Setting storage class to SSD-based" + extra_args=(--set central.spec.central.db.persistence.persistentVolumeClaim.storageClassName=premium-rwo) fi # Launch Central -$DIR/../../deploy/k8s/central.sh -kubectl -n stackrox set env deploy/central MUTEX_WATCHDOG_TIMEOUT_SECS=0 ROX_SCALE_TEST=true -if [[ $(kubectl get nodes -o json | jq '.items | length') == 1 ]]; then - exit 0 +roxie_config=$(mktemp) +trap 'rm -f "${roxie_config}"' EXIT +cat > "${roxie_config}" < /dev/null; then >&2 echo "Running the scale workload requires a PVC" exit 1 fi -kubectl -n "${namespace}" delete deploy/admission-control -kubectl -n "${namespace}" delete daemonset collector +roxie_config=$(mktemp) +trap 'rm -f "${roxie_config}"' EXIT + +CENTRAL_ENDPOINT=${CENTRAL_ENDPOINT:-central.stackrox.svc:443} + +cat > "${roxie_config}" < "${PGDATA}/PG_VERSION" +} + +# given_prev_binaries mimics the postgres executable under /usr/lib64/pgsql. +function given_prev_binaries() { + local major="$1" + mock_executable "${prev_dir}/postgresql-${major}/bin/postgres" \ + "echo 'PostgreSQL ${major} server'" +} + +function mock_executable() { + local target_path="$1" + local script_body="$2" + + mkdir -p "$(dirname "$target_path")" + printf '#!/usr/bin/env bash\n%s\n' "$script_body" > "$target_path" + chmod +x "$target_path" +} + +# Calls rox_use_matching_binaries and gathers results. +function use_matching_binaries() { + local status=0 + + rox_use_matching_binaries "$prev_dir" || status=$? + printf 'first-path=%s\n' "${PATH%%:*}" + printf 'path=%s\n' "$PATH" + return "$status" +} + +# == rox_use_matching_binaries == +# +# The function must always return 0: under `set -e` a non-zero return takes the +# container down. + +@test "rox_use_matching_binaries - fresh install, no PG_VERSION yet" { + run use_matching_binaries + assert_success + assert_line "first-path=${image_bin}" +} + +@test "rox_use_matching_binaries - normal boot" { + given_binary_version 16 + given_data_version 16 + run use_matching_binaries + assert_success + refute_output --partial "no executable" + assert_line "first-path=${image_bin}" +} + +@test "rox_use_matching_binaries - data are newer than the image" { + # Unsupported. The image has no newer binaries. + given_binary_version 16 + given_data_version 17 + run use_matching_binaries + assert_success + refute_output --partial "no executable" + assert_line "first-path=${image_bin}" +} + +@test "rox_use_matching_binaries - data match the previous binaries" { + local data_major=15 + local matching_bin_dir="${prev_dir}/postgresql-${data_major}/bin" + given_binary_version 17 + given_data_version "$data_major" + given_prev_binaries "$data_major" + local before="$PATH" + run use_matching_binaries + assert_success + assert_output --partial \ + "Data are still in PostgreSQL ${data_major}, starting the binaries in ${matching_bin_dir}" + assert_line "path=${matching_bin_dir}:${before}" +} + +@test "rox_use_matching_binaries - data do not match the previous binaries" { + local data_major=14 + local matching_bin_dir="${prev_dir}/postgresql-${data_major}/bin" + given_binary_version 16 + given_prev_binaries 15 + given_data_version "$data_major" + run use_matching_binaries + assert_success + assert_output --partial \ + "Data are in PostgreSQL ${data_major}, but there is no executable ${matching_bin_dir}/postgres" + assert_line "first-path=${image_bin}" +} + +@test "rox_use_matching_binaries - matching postgres is not executable" { + local data_major=15 + local matching_bin_dir="${prev_dir}/postgresql-${data_major}/bin" + given_binary_version 16 + given_data_version "$data_major" + given_prev_binaries "$data_major" + chmod -x "${matching_bin_dir}/postgres" + run use_matching_binaries + assert_success + assert_output --partial "no executable" + assert_line "first-path=${image_bin}" +} + +@test "rox_use_matching_binaries - corrupted PG_VERSION" { + given_data_version "not-a-version" + run use_matching_binaries + assert_success + assert_output --partial "Cannot read a valid major version from ${PGDATA}/PG_VERSION" + assert_line "first-path=${image_bin}" +} + +@test "rox_use_matching_binaries - unparsable binary version" { + mock_executable "${image_bin}/postgres" "echo 'something else entirely'" + given_data_version 15 + run use_matching_binaries + assert_success + assert_output --partial "Cannot read a valid major version from postgres -V" + assert_line "first-path=${image_bin}" +} + +@test "rox_use_matching_binaries - postgres -V failure does not crash the container" { + mock_executable "${image_bin}/postgres" "exit 127" + given_data_version 15 + # Called without `run`, which would swallow an abort. + rox_use_matching_binaries "$prev_dir" + assert_equal "${PATH%%:*}" "$image_bin" +} diff --git a/scanner/image/db/konflux.Dockerfile b/scanner/image/db/konflux.Dockerfile index 306822c3d4e71..a4b3f6bfc6890 100644 --- a/scanner/image/db/konflux.Dockerfile +++ b/scanner/image/db/konflux.Dockerfile @@ -1,4 +1,4 @@ -FROM registry.redhat.io/rhel9/postgresql-15:latest@sha256:26ca481f6fea9df09cb9e758188ad96382262d7487b104b1d6fd97b9b1ad15c9 +FROM registry.redhat.io/rhel9/postgresql-15:latest@sha256:04dc558560697443edac184d16684147eba4d6bb7a6dd646928ad433def33c95 ARG BUILD_TAG RUN if [[ "$BUILD_TAG" == "" ]]; then >&2 echo "error: required BUILD_TAG arg is unset"; exit 6; fi @@ -36,6 +36,8 @@ RUN localedef -f UTF-8 -i en_US en_US.UTF-8 && \ usermod -u 70 postgres -d /var/lib/postgresql && \ chown -R postgres:postgres /var/lib/postgresql && \ chown -R postgres:postgres /var/run/postgresql && \ + # Update ownership of directories that are owned by the original postgres uid. + chown -R postgres /var/lib/pgsql && chown -R postgres /opt/app-root && \ dnf clean all && \ rpm --verbose -e --nodeps $(rpm -qa curl '*rpm*' '*dnf*' '*libsolv*' '*hawkey*' 'yum*') && \ rm -rf /var/cache/dnf /var/cache/yum diff --git a/scanner/image/db/scripts/docker-entrypoint.sh b/scanner/image/db/scripts/docker-entrypoint.sh index 2848ddbe4af01..705762aa70ba9 100755 --- a/scanner/image/db/scripts/docker-entrypoint.sh +++ b/scanner/image/db/scripts/docker-entrypoint.sh @@ -311,6 +311,51 @@ _pg_want_help() { return 1 } +### STACKROX MODIFIED - Always run the server binaries matching the on-disk +### data directory. If init-entrypoint.sh declined or failed to upgrade, starting +### the newer server against it would make the pod crashloop. +### +### The base image ships the previous major under +### /usr/lib64/pgsql/postgresql- (see POSTGRESQL_PREV_VERSION). +### +### This function returns 0. Parameter $1 is the root of the previous binaries. +rox_use_matching_binaries() { + local prev_dir="$1" + local major_regex='^[0-9]+$' + local data_version binary_version matching_bin_dir + + # A fresh install has no usable PG_VERSION file yet. + [ -s "$PGDATA/PG_VERSION" ] || return 0 + + data_version="$(< "$PGDATA/PG_VERSION")" || true + if ! [[ "$data_version" =~ $major_regex ]]; then + printf >&2 'Cannot read a valid major version from %s/PG_VERSION: "%s"\n' \ + "$PGDATA" "$data_version" + return 0 + fi + + binary_version="$(postgres -V 2>/dev/null | sed 's/postgres (PostgreSQL) \([0-9]*\).*/\1/')" || true + if ! [[ "$binary_version" =~ $major_regex ]]; then + printf >&2 'Cannot read a valid major version from postgres -V: "%s"\n' \ + "$binary_version" + return 0 + fi + + [ "$data_version" -lt "$binary_version" ] || return 0 + + # Binaries for the data version, which is the previous major. + matching_bin_dir="${prev_dir}/postgresql-${data_version}/bin" + if [ ! -x "$matching_bin_dir/postgres" ]; then + printf >&2 'Data are in PostgreSQL %s, but there is no executable %s/postgres; startup will fail\n' \ + "$data_version" "$matching_bin_dir" + return 0 + fi + + printf >&2 'Data are still in PostgreSQL %s, starting the binaries in %s\n' \ + "$data_version" "$matching_bin_dir" + export PATH="$matching_bin_dir:$PATH" +} + _main() { # if first arg looks like a flag, assume we want to run postgres server if [ "${1:0:1}" = '-' ]; then @@ -318,6 +363,12 @@ _main() { fi if [ "$1" = 'postgres' ] && ! _pg_want_help "$@"; then + ### STACKROX MODIFIED - Must run before anything that resolves a + ### PostgreSQL binary through PATH. The server itself is launched as + ### `flock ... "$@" &` below, which resolves `postgres` at exec time, + ### so exporting PATH here is enough. + rox_use_matching_binaries /usr/lib64/pgsql + docker_setup_env # setup data directories and permissions (when run as root) docker_create_db_directories diff --git a/scanner/image/scanner/konflux.Dockerfile b/scanner/image/scanner/konflux.Dockerfile index dc3384a800b4f..cfec85c4ce01c 100644 --- a/scanner/image/scanner/konflux.Dockerfile +++ b/scanner/image/scanner/konflux.Dockerfile @@ -16,9 +16,9 @@ WORKDIR /src RUN make -C scanner NODEPS=1 CGO_ENABLED=1 image/scanner/bin/scanner copy-scripts -FROM registry.access.redhat.com/ubi9/ubi-micro:latest@sha256:f332c99eb8f798a8486821c91937f10ad64ee83d7e739303be2df051040918f6 AS ubi-micro-base +FROM registry.access.redhat.com/ubi9/ubi-micro:latest@sha256:5be877a2a280ae36eb9ab80ca4efb28bbf77c57abbba38137cdc37a03b8465e6 AS ubi-micro-base -FROM registry.access.redhat.com/ubi9/ubi:latest@sha256:25a147defd01e19674714f55d17538c8dbe55d8c305fa157ecc3f9c8977b05b6 AS package_installer +FROM registry.access.redhat.com/ubi9/ubi:latest@sha256:16e9e43d99e181463513cc84a514859b1abb9460f1c4d9e208da4b4e51cd5cc3 AS package_installer COPY --from=ubi-micro-base / /out/ diff --git a/scanner/services/validators/validators.go b/scanner/services/validators/validators.go index d912f65eca071..d3b6e15c938bd 100644 --- a/scanner/services/validators/validators.go +++ b/scanner/services/validators/validators.go @@ -154,6 +154,20 @@ func validateContents(contents *v4.Contents) error { return nil } +// validateCPE reports an error if s is a non-empty string that isn't a valid +// bound CPE WFN. An empty string is treated as "no CPE" and is not an error, +// matching the same convention mappers.toClairCoreCPE uses for the wire +// format: ClairCore's own zero-value WFN and this package's empty string are +// both accepted as "unset", even though StackRox's own mappers now always +// serialize "unset" as the bound wildcard CPE rather than "". +func validateCPE(s string) error { + if s == "" { + return nil + } + _, err := cpe.Unbind(s) + return err +} + func validateMap[T hasIDAndCPE](m map[string]T, fieldName string, validateF func(T) error) error { for k, v := range m { if reflect.ValueOf(v).IsZero() { @@ -162,8 +176,7 @@ func validateMap[T hasIDAndCPE](m map[string]T, fieldName string, validateF func if v.GetId() == "" { return fmt.Errorf("%s element %q: ID is empty", fieldName, k) } - _, err := cpe.Unbind(v.GetCpe()) - if err != nil { + if err := validateCPE(v.GetCpe()); err != nil { return fmt.Errorf("%s element %q: invalid CPE: %w", fieldName, k, err) } if err := validateF(v); err != nil { @@ -182,8 +195,7 @@ func validateList[T hasIDAndCPE](l []T, fieldName string, validateF func(T) erro if o.GetId() == "" { return fmt.Errorf("%s element #%d: Id is empty", fieldName, n) } - _, err := cpe.Unbind(o.GetCpe()) - if err != nil { + if err := validateCPE(o.GetCpe()); err != nil { return fmt.Errorf("%s element #%d (id: %q): invalid CPE: %w", fieldName, n, o.GetId(), err) } if err := validateF(o); err != nil { diff --git a/scanner/services/validators/validators_test.go b/scanner/services/validators/validators_test.go index 5150f073f46cd..d64c289f316a0 100644 --- a/scanner/services/validators/validators_test.go +++ b/scanner/services/validators/validators_test.go @@ -131,6 +131,14 @@ func Test_validateGetVulnerabilitiesRequest(t *testing.T) { addPackageDEPRECATED(&v4.Package{Id: "foobar", Cpe: "cpe:2.3:*:*:*:*:*:*:*:*:*:*:*"}), }, }, + "when a package has an empty CPE": { + // An empty CPE is treated the same as an unset one (e.g. the bound + // wildcard), not an invalid CPE. See mappers.toClairCoreCPE. + argOpts: []opts{ + addPackage(&v4.Package{Id: "foobar", Cpe: ""}), + addPackageDEPRECATED(&v4.Package{Id: "foobar", Cpe: ""}), + }, + }, "when a package has a source package with another source package": { wantErr: `Contents.Packages element "foo": package ID="foo" has a source with a source`, argOpts: []opts{ diff --git a/scanner/updater/ci/source-config.yaml b/scanner/updater/ci/source-config.yaml index 26c66ad004d41..e39335eaf0fd3 100644 --- a/scanner/updater/ci/source-config.yaml +++ b/scanner/updater/ci/source-config.yaml @@ -10,6 +10,14 @@ # updaters: per-updater configuration. Each updater inherits from 'default' # unless it overrides a field. New configuration sections can be added here # as the pipeline evolves. +# +# interval: minimum age of the last successful upload before a refresh is due. +# +# attempt_cadence: optional spacing between eligible one-hour scheduling windows, +# aligned to UTC epoch hours. Must be a positive whole-hour duration. +# For example, 4h permits attempts during UTC hours 00, 04, 08, 12, 16, and 20. +# If omitted, due refreshes may be attempted on every scheduler run. +# Failed attempts do not change the windows or the last successful upload time. storage: bucket: definitions.stackrox.io @@ -76,3 +84,6 @@ bundles: updaters: default: interval: 4h + oracle: + interval: 8h + attempt_cadence: 4h diff --git a/scanner/updater/export.go b/scanner/updater/export.go index faf2d5158bda7..ca0ce59f53503 100644 --- a/scanner/updater/export.go +++ b/scanner/updater/export.go @@ -8,6 +8,7 @@ import ( "net/http" "os" "path/filepath" + "strconv" "time" "github.com/klauspost/compress/zstd" @@ -201,26 +202,40 @@ func rhelVexOpts() []updates.ManagerOption { updates.WithEnabled([]string{rhelVexUpdaterName}), updates.WithConfigs(map[string]driver.ConfigUnmarshaler{ rhelVexUpdaterName: func(i any) error { - ctx := context.Background() - ctx = log.With(ctx, "updater", rhelVexUpdaterName) + ctx := log.With(context.Background(), "updater", rhelVexUpdaterName) + // Validate during factory configuration so invalid input fails manager + // initialization; updater configuration errors only skip the updater. + ignoreKernel := false + if value := os.Getenv("STACKROX_RHEL_VEX_IGNORE_KERNEL_PACKAGES"); value != "" { + var err error + ignoreKernel, err = strconv.ParseBool(value) + if err != nil { + return fmt.Errorf("STACKROX_RHEL_VEX_IGNORE_KERNEL_PACKAGES: %w", err) + } + } - // This function gets called for both the Factory and the Updater. - // We only need to configure the Factory (which has the CompressedFileTimeout field). + // The factory passes the download timeout to the updater; UpdaterConfig + // has no timeout field. Kernel exclusion is set on UpdaterConfig because + // the manager configures the updater after construction, overwriting any + // kernel-exclusion value inherited from the factory. switch cfg := i.(type) { case *vex.FactoryConfig: - // Configure the factory with custom timeout. - timeout := os.Getenv("STACKROX_RHEL_VEX_COMPRESSED_FILE_TIMEOUT") - if timeout != "" { - parsedTimeout, err := time.ParseDuration(timeout) + var timeout *claircore.Duration + if value := os.Getenv("STACKROX_RHEL_VEX_COMPRESSED_FILE_TIMEOUT"); value != "" { + parsedTimeout, err := time.ParseDuration(value) if err != nil { slog.WarnContext(ctx, "using default STACKROX_RHEL_VEX_COMPRESSED_FILE_TIMEOUT due to invalid duration", "reason", err) } else { - cfg.CompressedFileTimeout = claircore.Duration(parsedTimeout) + duration := claircore.Duration(parsedTimeout) + timeout = &duration slog.InfoContext(ctx, "using compressed file timeout", "timeout", parsedTimeout.String()) } } + if timeout != nil { + cfg.CompressedFileTimeout = *timeout + } case *vex.UpdaterConfig: - // Updater config - nothing to configure here. + cfg.IgnoreKernelPackages = ignoreKernel default: return fmt.Errorf("rhel-vex: unexpected config type: %T", i) } diff --git a/scanner/updater/export_test.go b/scanner/updater/export_test.go index 23c33dc90a945..caca347d2be5c 100644 --- a/scanner/updater/export_test.go +++ b/scanner/updater/export_test.go @@ -1,15 +1,101 @@ package updater import ( + "context" "maps" + "net/http" "slices" "testing" + "time" + "github.com/quay/claircore" + "github.com/quay/claircore/libvuln/driver" "github.com/quay/claircore/libvuln/updates" + "github.com/quay/claircore/rhel/vex" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) +// configCaptureFactory captures the callback registered with the updates manager. +type configCaptureFactory struct { + driver.UpdaterSetFactory + configure driver.ConfigUnmarshaler +} + +func (f *configCaptureFactory) Configure(_ context.Context, configure driver.ConfigUnmarshaler, _ *http.Client) error { + f.configure = configure + return nil +} + +func rhelVexConfigForTest(t *testing.T) driver.ConfigUnmarshaler { + t.Helper() + factory := &configCaptureFactory{} + opts := append(rhelVexOpts(), updates.WithFactories(map[string]driver.UpdaterSetFactory{ + rhelVexUpdaterName: factory, + })) + _, err := updates.NewManager(context.Background(), nil, nil, http.DefaultClient, opts...) + require.NoError(t, err) + require.NotNil(t, factory.configure) + return factory.configure +} + +func TestRHELVexOpts(t *testing.T) { + configure := rhelVexConfigForTest(t) + for name, tc := range map[string]struct { + value string + want bool + err bool + }{ + "unset": {}, + "enabled": {value: "true", want: true}, + "disabled": {value: "false"}, + "invalid": {value: "invalid", err: true}, + } { + t.Run(name, func(t *testing.T) { + t.Setenv("STACKROX_RHEL_VEX_IGNORE_KERNEL_PACKAGES", tc.value) + t.Setenv("STACKROX_RHEL_VEX_COMPRESSED_FILE_TIMEOUT", "10m") + factory := &vex.FactoryConfig{} + updater := &vex.UpdaterConfig{} + for _, cfg := range []any{factory, updater} { + err := configure(cfg) + if tc.err { + require.ErrorContains(t, err, "STACKROX_RHEL_VEX_IGNORE_KERNEL_PACKAGES") + } else { + require.NoError(t, err) + } + } + if !tc.err { + assert.False(t, factory.IgnoreKernelPackages) + assert.Equal(t, tc.want, updater.IgnoreKernelPackages) + assert.Equal(t, claircore.Duration(10*time.Minute), factory.CompressedFileTimeout) + } + }) + } +} + +func TestRHELVexOptsTimeout(t *testing.T) { + configure := rhelVexConfigForTest(t) + for name, tc := range map[string]struct { + value string + want time.Duration + }{ + "empty preserves default": {want: time.Minute}, + "invalid preserves default": {value: "invalid", want: time.Minute}, + "valid overrides default": {value: "10m", want: 10 * time.Minute}, + } { + t.Run(name, func(t *testing.T) { + t.Setenv("STACKROX_RHEL_VEX_COMPRESSED_FILE_TIMEOUT", tc.value) + t.Setenv("STACKROX_RHEL_VEX_IGNORE_KERNEL_PACKAGES", "true") + factory := &vex.FactoryConfig{CompressedFileTimeout: claircore.Duration(time.Minute)} + require.NoError(t, configure(factory)) + assert.Equal(t, claircore.Duration(tc.want), factory.CompressedFileTimeout) + updater := &vex.UpdaterConfig{} + require.NoError(t, configure(updater)) + assert.True(t, updater.IgnoreKernelPackages) + }) + } +} + func TestFilterSources(t *testing.T) { bundles := map[string][]updates.ManagerOption{ "alpha": nil, diff --git a/scanner/updater/version/RELEASE_VERSION b/scanner/updater/version/RELEASE_VERSION index f2688bca0a8fd..bd9facc9a0966 100644 --- a/scanner/updater/version/RELEASE_VERSION +++ b/scanner/updater/version/RELEASE_VERSION @@ -8,6 +8,8 @@ # offline bundle for that release. 4.10.0 4.10.1 +4.10.10 +4.10.11 4.10.2 4.10.3 4.10.4 @@ -15,11 +17,14 @@ 4.10.6 4.10.7 4.10.8 +4.10.9 4.11.0 4.11.1 4.11.2 4.11.3 4.11.4 +4.11.5 +4.11.6 4.4.0 4.4.1 4.4.2 @@ -84,3 +89,4 @@ 4.9.7 4.9.8 4.9.9 +5.0.0 diff --git a/scanner/updater/version/VULNERABILITY_BUNDLE_VERSION b/scanner/updater/version/VULNERABILITY_BUNDLE_VERSION index 8cf08d06206d0..8409e0debc779 100644 --- a/scanner/updater/version/VULNERABILITY_BUNDLE_VERSION +++ b/scanner/updater/version/VULNERABILITY_BUNDLE_VERSION @@ -6,7 +6,7 @@ # This process ensures that each version's vulnerability data is accurately captured and maintained in accordance with its respective version. dev heads/master v2 heads/release-4.9.x/scanner-updater-v2 -# release-4.11 at 2026-08-06, after 4.11.3-rc.0. -v3 heads/2e8d7a35b1200eb29d5a75cad2a443719cf265e1 +# release-4.11 with claircore v1.5.55 +v3 heads/1e51a275092d9421b9acabaf09bca3ae3d59d3fc # master until the release branch is available. v4 heads/master diff --git a/scripts/ci/add-vms/action.yml b/scripts/ci/add-vms/action.yml index 3b300baf010ec..41eca4d2c9bda 100644 --- a/scripts/ci/add-vms/action.yml +++ b/scripts/ci/add-vms/action.yml @@ -1,4 +1,4 @@ -name: "Add VMs to ACS Cluster" +name: "Ensure VMs on ACS Cluster" description: "Install OpenShift Virtualization, deploy VMs, and install roxagent on an Infra-managed cluster" inputs: @@ -6,11 +6,11 @@ inputs: description: "Infra cluster name (from `infractl list`)" required: true num-vms: - description: "Number of VMs to deploy" + description: "Desired count of {os}-1..N. Existing VMs are reused." required: false default: "1" vm-os: - description: "VM OS: rhel9 or rhel10" + description: "VM OS: rhel8, rhel9, or rhel10" required: false default: "rhel9" ssh-public-key: diff --git a/scripts/ci/add-vms/add-vms.bats b/scripts/ci/add-vms/add-vms.bats index 4b37bc3dba926..1c6ce5090598f 100644 --- a/scripts/ci/add-vms/add-vms.bats +++ b/scripts/ci/add-vms/add-vms.bats @@ -21,6 +21,7 @@ load "../../test_helpers.bats" ' _ "${BATS_TEST_DIRNAME}/add-vms.sh" assert_success + assert_output --partial "::error title=Add VMs incomplete::Skipped: rhel10-3; agent failed: rhel10-3" run cat "$summary_file" assert_output --partial "## Add VMs to Cluster" diff --git a/scripts/ci/add-vms/add-vms.sh b/scripts/ci/add-vms/add-vms.sh index 517a0143a5625..fd4f89cc880d5 100755 --- a/scripts/ci/add-vms/add-vms.sh +++ b/scripts/ci/add-vms/add-vms.sh @@ -7,7 +7,7 @@ # Options: # --cluster NAME Infra cluster name (calls infractl for kubeconfig) # --num-vms N Number of VMs (default: 1) -# --os OS VM OS: rhel9|rhel10 (default: rhel9) +# --os OS VM OS: rhel8|rhel9|rhel10 (default: rhel9) # --ssh-key PATH Path to user SSH public key to add to target VMs # --namespace NS Target namespace (default: openshift-cnv) # --vm-prefix PREFIX VM name prefix (default: same as OS) @@ -64,7 +64,7 @@ parse_args() { if ! [[ "$NUM_VMS" =~ ^[0-9]+$ ]] || (( NUM_VMS < 1 )); then die "--num-vms must be a positive integer" fi - [[ "$VM_OS" =~ ^rhel(9|10)$ ]] || die "--os must be rhel9 or rhel10" + [[ "$VM_OS" =~ ^rhel(8|9|10)$ ]] || die "--os must be rhel8, rhel9, or rhel10" } # Sets KUBECONFIG: either fetches it from infractl for the given cluster @@ -218,7 +218,11 @@ write_github_summary() { echo "" } >> "$GITHUB_STEP_SUMMARY" - echo "::notice title=VM action summary::See the job summary for VM access, key download, and native service verification." + if [[ ${#SKIPPED_VMS[@]} -gt 0 || ${#NATIVE_AGENT_FAILED_VMS[@]} -gt 0 ]]; then + echo "::error title=Add VMs incomplete::Skipped: ${SKIPPED_VMS[*]}; agent failed: ${NATIVE_AGENT_FAILED_VMS[*]}. See the job summary." + else + echo "::notice title=VM action summary::See the job summary for VM access, key download, and native service verification." + fi } cleanup() { @@ -268,6 +272,8 @@ main() { accessible_vms+=("${MANAGED_VMS[@]}" "${ADOPTED_VMS[@]}") if [[ ${#accessible_vms[@]} -eq 0 ]]; then + # Summary first so the ::error annotation still names the skipped VMs. + print_summary die "No accessible VMs — cannot install agent. All VMs failed SSH readiness." else export AUTOMATION_SSH_PRIVKEY @@ -278,6 +284,9 @@ main() { # Step 4: Summary print_summary + if [[ ${#SKIPPED_VMS[@]} -gt 0 || ${#NATIVE_AGENT_FAILED_VMS[@]} -gt 0 ]]; then + die "Some VMs were skipped or the native agent failed to start" + fi } if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then diff --git a/scripts/ci/bats/scanner-updater-config.bats b/scripts/ci/bats/scanner-updater-config.bats new file mode 100644 index 0000000000000..d9680a53c5a86 --- /dev/null +++ b/scripts/ci/bats/scanner-updater-config.bats @@ -0,0 +1,67 @@ +#!/usr/bin/env bats +# shellcheck disable=SC1091 + +load "../../test_helpers.bats" + +function setup() { + repo_root="$(cd "${BATS_TEST_DIRNAME}/../../.." && pwd)" + config_script="${repo_root}/.github/workflows/scripts/scanner-updater-config.sh" + export SOURCE_CONFIG="${BATS_TEST_TMPDIR}/source-config.yaml" +} + +@test "Oracle uses eight-hour freshness and four-hour attempt cadence" { + run env SOURCE_CONFIG="${repo_root}/scanner/updater/ci/source-config.yaml" \ + "$config_script" interval-secs oracle + assert_success + assert_output "28800" + + run env SOURCE_CONFIG="${repo_root}/scanner/updater/ci/source-config.yaml" \ + "$config_script" attempt-cadence-secs oracle + assert_success + assert_output "14400" +} + +@test "sources without a cadence retain default freshness and unrestricted attempts" { + run env SOURCE_CONFIG="${repo_root}/scanner/updater/ci/source-config.yaml" \ + "$config_script" interval-secs debian + assert_success + assert_output "14400" + + run env SOURCE_CONFIG="${repo_root}/scanner/updater/ci/source-config.yaml" \ + "$config_script" attempt-cadence-secs debian + assert_success + assert_output "0" +} + +@test "attempt cadence inherits the default and supports per-source overrides" { + cat > "$SOURCE_CONFIG" <<'YAML' +updaters: + default: + attempt_cadence: 6h + oracle: + attempt_cadence: 240m +YAML + run "$config_script" attempt-cadence-secs debian + assert_success + assert_output "21600" + + run "$config_script" attempt-cadence-secs oracle + assert_success + assert_output "14400" +} + +@test "attempt cadence rejects zero and fractional-hour durations" { + for cadence in 0h 30m 1h30m; do + printf 'updaters:\n oracle:\n attempt_cadence: %s\n' "$cadence" > "$SOURCE_CONFIG" + run "$config_script" attempt-cadence-secs oracle + assert_failure + assert_output --partial "attempt_cadence must be a positive whole-hour duration" + done +} + +@test "attempt cadence rejects malformed durations" { + printf 'updaters:\n oracle:\n attempt_cadence: invalid\n' > "$SOURCE_CONFIG" + run "$config_script" attempt-cadence-secs oracle + assert_failure + assert_output --partial "cannot parse duration" +} diff --git a/scripts/ci/bats/scanner-updater-matrix.bats b/scripts/ci/bats/scanner-updater-matrix.bats new file mode 100644 index 0000000000000..62147b86af1e8 --- /dev/null +++ b/scripts/ci/bats/scanner-updater-matrix.bats @@ -0,0 +1,124 @@ +#!/usr/bin/env bats +# shellcheck disable=SC1091 + +load "../../test_helpers.bats" + +function setup() { + bats_require_minimum_version 1.5.0 + repo_root="$(cd "${BATS_TEST_DIRNAME}/../../.." && pwd)" + fixture="${BATS_TEST_TMPDIR}/repo" + scripts="${fixture}/.github/workflows/scripts" + mkdir -p "$scripts" + cp "${repo_root}/.github/workflows/scripts/scanner-updater-matrix.sh" "$scripts/" + cp "${repo_root}/.github/workflows/scripts/scanner-updater-config.sh" "$scripts/" + export SOURCE_CONFIG="${fixture}/source-config.yaml" + export FRESHNESS_CALLS="${BATS_TEST_TMPDIR}/freshness-calls" + export SOURCE_FRESH=false + export FRESHNESS_ERROR=false + export SCHEDULE_TIME="2026-10-14T08:27:00Z" + : > "$FRESHNESS_CALLS" + + cat > "$SOURCE_CONFIG" <<'YAML' +storage: + bucket: test-bucket + prefix: test-prefix +bundles: + dev: [oracle, debian] + v4: [oracle, debian] +updaters: + default: + interval: 4h + oracle: + interval: 8h + attempt_cadence: 4h +YAML + + cat > "${scripts}/scanner-get-released-tags.sh" <<'SH' +#!/usr/bin/env bash +echo '[{"version":"dev","ref":"master"},{"version":"v4","ref":"release"}]' +SH + cat > "${scripts}/scanner-updater-check-freshness.sh" <<'SH' +#!/usr/bin/env bash +printf '%s %s\n' "$GCS_OBJECT" "$*" >> "$FRESHNESS_CALLS" +if [[ "$FRESHNESS_ERROR" == true ]]; then + exit 1 +fi +echo "$SOURCE_FRESH" +SH + chmod +x "${scripts}/scanner-get-released-tags.sh" \ + "${scripts}/scanner-updater-check-freshness.sh" + cd "$fixture" || return 1 +} + +@test "due sources are scheduled in eligible hours across streams" { + run "${scripts}/scanner-updater-matrix.sh" + assert_success + run jq -e '.has_due == "true" and .has_errors == "false" and + ([.matrix.include[] | select(.source == "oracle")] | length == 2)' <<< "$output" + assert_success + run grep -c 'oracle.json.zst --max-age 28800' "$FRESHNESS_CALLS" + assert_success + assert_output "2" + run grep -c 'debian.json.zst --max-age 14400' "$FRESHNESS_CALLS" + assert_success + assert_output "2" +} + +@test "ineligible hours skip Oracle before freshness checks but retain other sources" { + run env SCHEDULE_TIME="2026-10-14T09:27:00Z" \ + "${scripts}/scanner-updater-matrix.sh" + assert_success + run jq -e '.matrix.include | length == 2 and all(.[]; .source == "debian")' <<< "$output" + assert_success + run grep oracle "$FRESHNESS_CALLS" + assert_failure +} + +@test "fresh sources are not scheduled even in eligible hours" { + run env SOURCE_FRESH=true "${scripts}/scanner-updater-matrix.sh" + assert_success + run jq -e '.has_due == "false" and .has_errors == "false" and + (.matrix.include | length == 0)' <<< "$output" + assert_success +} + +@test "eligible windows include the whole hour and cross midnight" { + for timestamp in 2026-10-14T23:59:59Z 2026-10-15T00:00:00Z 2026-10-15T00:59:59Z 2026-10-15T01:00:00Z; do + expected=0 + [[ "$timestamp" == *T00:* ]] && expected=2 + run env SCHEDULE_TIME="$timestamp" "${scripts}/scanner-updater-matrix.sh" + assert_success + run jq -e --argjson expected "$expected" \ + '[.matrix.include[] | select(.source == "oracle")] | length == $expected' <<< "$output" + assert_success + done +} + +@test "changing cadence changes eligible hours using UTC epoch alignment" { + yq eval -i '.updaters.oracle.attempt_cadence = "5h"' "$SOURCE_CONFIG" + run env SCHEDULE_TIME="1970-01-02T00:27:00Z" \ + "${scripts}/scanner-updater-matrix.sh" + assert_success + run jq -e '[.matrix.include[] | select(.source == "oracle")] | length == 0' <<< "$output" + assert_success + + run env SCHEDULE_TIME="1970-01-02T01:27:00Z" \ + "${scripts}/scanner-updater-matrix.sh" + assert_success + run jq -e '[.matrix.include[] | select(.source == "oracle")] | length == 2' <<< "$output" + assert_success +} + +@test "freshness lookup failures remain visible scheduling errors" { + run --separate-stderr env FRESHNESS_ERROR=true "${scripts}/scanner-updater-matrix.sh" + assert_success + [[ "$stderr" == *"::error::gs://test-bucket/test-prefix/dev/sources/oracle.json.zst: freshness check failed"* ]] + run jq -e '.has_errors == "true" and (.errors | length == 4) and + (.matrix.include | length == 0)' <<< "$output" + assert_success +} + +@test "invalid scheduling time fails rather than using the current time" { + run env SCHEDULE_TIME="invalid" "${scripts}/scanner-updater-matrix.sh" + assert_failure +} diff --git a/scripts/ci/collect-collector-metrics.sh b/scripts/ci/collect-collector-metrics.sh index 777e922197db9..6d9ef92fd4af7 100755 --- a/scripts/ci/collect-collector-metrics.sh +++ b/scripts/ci/collect-collector-metrics.sh @@ -53,6 +53,7 @@ main() { exit 0 fi + exit_code=0 for pod in ${pods}; do remote="${pod}:${pod_port}" metrics_file="${pod}.txt" @@ -73,11 +74,17 @@ main() { done echo echo "set up port-forwarding from $remote to $local" - curl --silent --fail -k "${local}/${metrics_path}" > "${metrics_dir}/${metrics_file}" - echo "finished download ${metrics_file}" + if curl --silent --fail -k "${local}/${metrics_path}" > "${metrics_dir}/${metrics_file}"; then + echo "finished download ${metrics_file}" + else + echo >&2 "failed to download metrics from $pod" + exit_code=1 + fi kill ${PID} echo "finished tear down of port-forwarding from $remote to $local" done + + return "${exit_code}" } main "$@" diff --git a/scripts/ci/collect-service-logs.sh b/scripts/ci/collect-service-logs.sh index 82f0753973a3c..6564f669f4aa9 100755 --- a/scripts/ci/collect-service-logs.sh +++ b/scripts/ci/collect-service-logs.sh @@ -69,7 +69,8 @@ main() { set +e for object in daemonsets deployments services pods secrets serviceaccounts validatingwebhookconfigurations \ - catalogsources subscriptions clusterserviceversions central securedclusters nodes persistentvolumeclaims; do + catalogsources subscriptions clusterserviceversions central securedclusters nodes persistentvolumeclaims \ + storageclasses; do # A feel good command before pulling logs info ">>> Collecting ${object} from namespace ${namespace} <<<" out="$(mktemp)" diff --git a/scripts/ci/collect-vm-guest-logs.sh b/scripts/ci/collect-vm-guest-logs.sh new file mode 100755 index 0000000000000..ed9fae05bd5fe --- /dev/null +++ b/scripts/ci/collect-vm-guest-logs.sh @@ -0,0 +1,287 @@ +#!/usr/bin/env bash + +set -euo pipefail + +# collect-vm-guest-logs.sh copies roxagent journals from VM-scanning e2e guests +# via virtctl ssh. Best-effort: always exits 0. +# +# Usage: +# collect-vm-guest-logs.sh +# +# Environment: +# VM_SCAN_NAMESPACE_PREFIX default: vm-scan-e2e +# VM_GUEST_USER default: cloud-user +# VM_SCAN_E2E_DIR host files shared with the test run (default: /tmp/vm-scan-e2e) +# VM_SSH_PRIVATE_KEY_PATH PEM identity for virtctl (default: $VM_SCAN_E2E_DIR/ssh-identity) +# VIRTCTL_PATH optional virtctl override +# VM_GUEST_JOURNAL_TIMEOUT per-VM virtctl ssh ceiling (default: 90s) +# VM_GUEST_COLLECT_DEADLINE total collection budget (default: 540s) + +SCRIPTS_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")"/../.. && pwd)" +# shellcheck source=../../scripts/ci/lib.sh +source "$SCRIPTS_ROOT/scripts/ci/lib.sh" + +usage() { + echo "./scripts/ci/collect-vm-guest-logs.sh " +} + +vm_scan_e2e_dir() { + printf '%s\n' "${VM_SCAN_E2E_DIR:-/tmp/vm-scan-e2e}" +} + +resolve_virtctl() { + if [[ -n "${VIRTCTL_PATH:-}" ]]; then + if [[ -x "$VIRTCTL_PATH" ]]; then + printf '%s\n' "$VIRTCTL_PATH" + return 0 + fi + info "VIRTCTL_PATH is not executable: ${VIRTCTL_PATH}" >&2 + return 1 + fi + local persisted + persisted="$(vm_scan_e2e_dir)/virtctl" + if [[ -x "$persisted" ]]; then + printf '%s\n' "$persisted" + return 0 + fi + local pointed + pointed="$(vm_scan_e2e_dir)/virtctl-path" + if [[ -f "$pointed" ]]; then + local src + src="$(<"$pointed")" + if [[ -n "$src" && -x "$src" ]]; then + printf '%s\n' "$src" + return 0 + fi + fi + command -v virtctl +} + +resolve_ssh_identity() { + if [[ -n "${VM_SSH_PRIVATE_KEY_PATH:-}" && -f "${VM_SSH_PRIVATE_KEY_PATH}" ]]; then + printf '%s\n' "${VM_SSH_PRIVATE_KEY_PATH}" + return 0 + fi + local persisted + persisted="$(vm_scan_e2e_dir)/ssh-identity" + if [[ -f "$persisted" ]]; then + printf '%s\n' "$persisted" + return 0 + fi + return 1 +} + +# list_vm_scan_vmis prints "namespace name" lines for VMIs in vm-scan-e2e namespaces. +# Returns 1 when kubectl cannot list VMIs (distinct from zero matches). +list_vm_scan_vmis() { + local prefix="${VM_SCAN_NAMESPACE_PREFIX:-vm-scan-e2e}" + local out err ns name + out="$(mktemp)" + err="$(mktemp)" + if ! kubectl --request-timeout=30s get vmi -A \ + -o jsonpath='{range .items[*]}{.metadata.namespace}{" "}{.metadata.name}{"\n"}{end}' \ + > "$out" 2>"$err"; then + info "kubectl get vmi failed: $(<"$err")" >&2 + rm -f "$out" "$err" + return 1 + fi + rm -f "$err" + while read -r ns name; do + [[ -z "$ns" || -z "$name" ]] && continue + if [[ "$ns" == "$prefix" || "$ns" == "${prefix}-"* ]]; then + printf '%s %s\n' "$ns" "$name" + fi + done < "$out" + rm -f "$out" + return 0 +} + +run_with_timeout() { + local seconds="$1" + shift + if command -v timeout >/dev/null; then + timeout -k 5s "${seconds}s" "$@" + else + "$@" + fi +} + +guest_ssh() { + local virtctl_bin="$1" + local identity="$2" + local guest_user="$3" + local ns="$4" + local vmi="$5" + local ssh_timeout="$6" + local remote_cmd="$7" + + # virtctl ssh reads stdin (OpenSSH without -n) and would consume the VMI + # list from the caller's while-read loop. + run_with_timeout "$ssh_timeout" \ + "${virtctl_bin}" ssh \ + --namespace "$ns" \ + --identity-file "$identity" \ + --local-ssh-opts="-n" \ + --local-ssh-opts="-o StrictHostKeyChecking=no" \ + --local-ssh-opts="-o IdentitiesOnly=yes" \ + --local-ssh-opts="-o UserKnownHostsFile=/dev/null" \ + --local-ssh-opts="-o BatchMode=yes" \ + --local-ssh-opts="-o ConnectTimeout=30" \ + --username "$guest_user" \ + "vmi/${vmi}" \ + --command "$remote_cmd" \ + < /dev/null +} + +# seconds_left is the timeout for the next virtctl ssh. Collection stops +# on its own before the 10 minute post-test kill, which fails the job. +seconds_left() { + local cap="${VM_GUEST_JOURNAL_TIMEOUT:-90}" + local left=$((collect_deadline_at - SECONDS)) + if ((left < 1)); then + return 1 + fi + if ((left < cap)); then + printf '%s\n' "$left" + return 0 + fi + printf '%s\n' "$cap" +} + +# collect_roxagent_container_journal writes container stdout that RHEL 8 +# Podman stores in its own log, not the journal. Quadlet names that +# container systemd-roxagent. +collect_roxagent_container_journal() { + local virtctl_bin="$1" + local identity="$2" + local guest_user="$3" + local ns="$4" + local vmi="$5" + local out_file="$6" + local ssh_timeout="$7" + local stderr_file + + stderr_file="$(mktemp)" + if ! guest_ssh "$virtctl_bin" "$identity" "$guest_user" "$ns" "$vmi" "$ssh_timeout" \ + "sudo podman logs --timestamps systemd-roxagent || true" \ + > "$out_file" 2>"$stderr_file"; then + { + echo "roxagent container journal collection failed for ${ns}/${vmi}" + echo "virtctl: ${virtctl_bin}" + echo "guest_user: ${guest_user}" + echo "--- stderr ---" + cat "$stderr_file" + } >> "$out_file" + elif [[ -s "$stderr_file" ]]; then + { + echo "--- stderr ---" + cat "$stderr_file" + } >> "$out_file" + fi + rm -f "$stderr_file" +} + +# collect_roxagent_journal is enough on RHEL 9 and 10, where Podman files +# container stdout on roxagent.service. On RHEL 8 that stdout is missing +# here, so the container journal is collected separately. +collect_roxagent_journal() { + local virtctl_bin="$1" + local identity="$2" + local guest_user="$3" + local ns="$4" + local vmi="$5" + local out_file="$6" + local container_file="$7" + local ssh_timeout + + ssh_timeout="$(seconds_left)" || return 1 + + local stderr_file + stderr_file="$(mktemp)" + + if ! guest_ssh "$virtctl_bin" "$identity" "$guest_user" "$ns" "$vmi" "$ssh_timeout" \ + "sudo journalctl -u roxagent.service -u roxagent-serve.service -b --no-pager -o short-iso" \ + > "$out_file" 2>"$stderr_file"; then + { + echo "roxagent journal collection failed for ${ns}/${vmi}" + echo "virtctl: ${virtctl_bin}" + echo "guest_user: ${guest_user}" + echo "--- stderr ---" + cat "$stderr_file" + } >> "$out_file" + fi + rm -f "$stderr_file" + ssh_timeout="$(seconds_left)" || return 1 + collect_roxagent_container_journal "$virtctl_bin" "$identity" "$guest_user" "$ns" "$vmi" "$container_file" "$ssh_timeout" || true +} + +collect_journals() { + local output_dir="$1" + local guest_user="${VM_GUEST_USER:-cloud-user}" + local virtctl_bin="" identity="" + virtctl_bin="$(resolve_virtctl)" || virtctl_bin="" + identity="$(resolve_ssh_identity)" || identity="" + + if [[ -n "$virtctl_bin" && -n "$identity" ]]; then + info ">>> Collecting roxagent journals into ${output_dir} <<<" + collect_deadline_at=$((SECONDS + ${VM_GUEST_COLLECT_DEADLINE:-540})) + local vmi_count=0 ns vmi out_file container_file vmi_list list_err + vmi_list="$(mktemp)" + list_err="$(mktemp)" + if ! list_vm_scan_vmis > "$vmi_list" 2>"$list_err"; then + info "Failed to list VMIs; writing collection-failed.txt" + { + echo "kubectl get vmi failed (not an empty match)" + cat "$list_err" + } > "${output_dir}/collection-failed.txt" + rm -f "$vmi_list" "$list_err" + return 0 + fi + rm -f "$list_err" + while read -r ns vmi; do + [[ -z "$ns" || -z "$vmi" ]] && continue + vmi_count=$((vmi_count + 1)) + out_file="${output_dir}/${ns}_${vmi}_roxagent.journal.log" + container_file="${output_dir}/${ns}_${vmi}_roxagent.container.journal.log" + info "Collecting roxagent journals for ${ns}/${vmi} -> ${out_file} ${container_file}" + if ! collect_roxagent_journal "$virtctl_bin" "$identity" "$guest_user" "$ns" "$vmi" "$out_file" "$container_file"; then + echo "stopped at ${ns}/${vmi}: collect deadline reached" \ + > "${output_dir}/collection-partial.txt" + break + fi + done < "$vmi_list" + rm -f "$vmi_list" + + if [[ "$vmi_count" -eq 0 ]]; then + info "No VMIs found in VM scan namespaces" + echo "no VMIs matched prefix ${VM_SCAN_NAMESPACE_PREFIX:-vm-scan-e2e}" \ + > "${output_dir}/collection-skipped.txt" + fi + return 0 + fi + + if [[ -z "$virtctl_bin" ]]; then + info "virtctl not found; skipping VM guest journal collection" + echo "virtctl not found" > "${output_dir}/collection-skipped.txt" + else + info "VM SSH identity not found; skipping VM guest journal collection" + echo "ssh identity not found at $(vm_scan_e2e_dir)/ssh-identity" \ + > "${output_dir}/collection-skipped.txt" + fi +} + +main() { + cd "$SCRIPTS_ROOT" + + if [[ $# -lt 1 ]]; then + usage + exit 1 + fi + + local output_dir="$1" + mkdir -p "$output_dir" + collect_journals "$output_dir" || true + exit 0 +} + +main "$@" diff --git a/scripts/ci/delete-vm-ns.sh b/scripts/ci/delete-vm-ns.sh new file mode 100755 index 0000000000000..a733d1b5e012e --- /dev/null +++ b/scripts/ci/delete-vm-ns.sh @@ -0,0 +1,61 @@ +#!/usr/bin/env bash + +set -euo pipefail + +SCRIPTS_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")"/../.. && pwd)" +# shellcheck source=../../scripts/ci/lib.sh +source "$SCRIPTS_ROOT/scripts/ci/lib.sh" + +usage() { + cat <>> Cleaning up VM scan e2e namespaces <<<" + ns_list="$(mktemp)" + if ! list_vm_scan_namespaces > "$ns_list"; then + info "Skipping namespace delete: kubectl get ns failed" + rm -f "$ns_list" + return 0 + fi + while IFS= read -r ns; do + [[ -z "$ns" ]] && continue + info "Deleting namespace ${ns}" + # 10s leaves room for the namespace list inside the 60s cleanup budget. + kubectl delete namespace "$ns" --wait=false --request-timeout=10s &1 || \ + info "Namespace delete for ${ns} failed or already removed" + done < "$ns_list" + rm -f "$ns_list" +} + +main() { + case "${1:-}" in + -h|--help) + usage + exit 0 + ;; + "") + ;; + *) + usage >&2 + exit 1 + ;; + esac + + cd "$SCRIPTS_ROOT" + delete_vm_scan_namespaces + exit 0 +} + +main "$@" diff --git a/scripts/ci/get-slack-user-id.sh b/scripts/ci/get-slack-user-id.sh index b8287adce5be9..4f246c5179d7b 100755 --- a/scripts/ci/get-slack-user-id.sh +++ b/scripts/ci/get-slack-user-id.sh @@ -57,6 +57,7 @@ case "$github_login" in 'parametalol') slack_user='U02MJ72K1B5' ;; 'pedrottimark') slack_user='U01RN8V8DEH' ;; 'porridge') slack_user='U020XCUG2LA' ;; +'rhmdnd') slack_user='U01C24L97D1' ;; 'rhybrillou') slack_user='U02GPRG4NHF' ;; 'robbycochran') slack_user='U03NAEPKDE1' ;; 'rukletsov') slack_user='U01G6P17RTK' ;; diff --git a/scripts/ci/jobs/aks_qa_e2e_tests.py b/scripts/ci/jobs/aks_qa_e2e_tests.py index cd5cd84e514c9..fb4e65c757c02 100755 --- a/scripts/ci/jobs/aks_qa_e2e_tests.py +++ b/scripts/ci/jobs/aks_qa_e2e_tests.py @@ -10,6 +10,7 @@ # set required test parameters os.environ["ORCHESTRATOR_FLAVOR"] = "k8s" os.environ["KUBERNETES_PROVIDER"] = "aks" +os.environ["USE_ROXIE_DEPLOY"] = "true" os.environ["ROX_RISK_REPROCESSING_INTERVAL"] = "15s" os.environ["ROX_SENSOR_CONNECTION_RETRY_MAX_INTERVAL"] = "30s" diff --git a/scripts/ci/jobs/eks_qa_e2e_tests.py b/scripts/ci/jobs/eks_qa_e2e_tests.py index b52672293ebae..4e3dc19bd1ea4 100755 --- a/scripts/ci/jobs/eks_qa_e2e_tests.py +++ b/scripts/ci/jobs/eks_qa_e2e_tests.py @@ -10,6 +10,7 @@ # set required test parameters os.environ["ORCHESTRATOR_FLAVOR"] = "k8s" os.environ["KUBERNETES_PROVIDER"] = "eks" +os.environ["USE_ROXIE_DEPLOY"] = "true" os.environ["ROX_RISK_REPROCESSING_INTERVAL"] = "15s" os.environ["ROX_SENSOR_CONNECTION_RETRY_MAX_INTERVAL"] = "30s" diff --git a/scripts/ci/jobs/gke_external_pg_17_qa_e2e_tests.py b/scripts/ci/jobs/gke_external_pg_17_qa_e2e_tests.py index 2c652d5e83a9a..bed50919fccbe 100755 --- a/scripts/ci/jobs/gke_external_pg_17_qa_e2e_tests.py +++ b/scripts/ci/jobs/gke_external_pg_17_qa_e2e_tests.py @@ -13,8 +13,10 @@ # set test parameters os.environ["ORCHESTRATOR_FLAVOR"] = "k8s" os.environ["KUBERNETES_PROVIDER"] = "gke" +os.environ["SCANNER_V4_DB_STORAGE_CLASS"] = "stackrox-gke-ssd" os.environ["POSTGRES_VERSION"] = "17" os.environ["BYODB_TEST"] = "true" +os.environ["USE_ROXIE_DEPLOY"] = "true" os.environ["ROX_RISK_REPROCESSING_INTERVAL"] = "15s" os.environ["ROX_SENSOR_CONNECTION_RETRY_MAX_INTERVAL"] = "30s" diff --git a/scripts/ci/jobs/gke_qa_e2e_tests.py b/scripts/ci/jobs/gke_qa_e2e_tests.py index cf8f78280e1cd..65a1dd9f2ac0b 100755 --- a/scripts/ci/jobs/gke_qa_e2e_tests.py +++ b/scripts/ci/jobs/gke_qa_e2e_tests.py @@ -12,6 +12,7 @@ os.environ["KUBERNETES_PROVIDER"] = "gke" os.environ["GCP_IMAGE_TYPE"] = "cos_containerd" os.environ["OUTPUT_FORMAT"] = "helm" +os.environ["USE_ROXIE_DEPLOY"] = "true" os.environ["SCANNER_V4_DB_STORAGE_CLASS"] = "stackrox-gke-ssd" diff --git a/scripts/ci/jobs/gke_ui_e2e_tests.py b/scripts/ci/jobs/gke_ui_e2e_tests.py index a09dc8276720c..99cba4e19242b 100755 --- a/scripts/ci/jobs/gke_ui_e2e_tests.py +++ b/scripts/ci/jobs/gke_ui_e2e_tests.py @@ -16,7 +16,6 @@ # Override test env defaults here: # (for defaults see: tests/e2e/lib.sh export_test_environment()) -os.environ["OUTPUT_FORMAT"] = "helm" os.environ["SCANNER_V4_DB_STORAGE_CLASS"] = "stackrox-gke-ssd" os.environ["SENSOR_SCANNER_SUPPORT"] = "true" # Optimize Scanner V4 startup time by loading only RHEL vulnerability bundles diff --git a/scripts/ci/jobs/ocp-perf-scale-tests-post.sh b/scripts/ci/jobs/ocp-perf-scale-tests-post.sh index ca83582ff7713..cb0d75324c3fe 100755 --- a/scripts/ci/jobs/ocp-perf-scale-tests-post.sh +++ b/scripts/ci/jobs/ocp-perf-scale-tests-post.sh @@ -89,12 +89,24 @@ else info "Warning: Failed to get central diagnostics" fi +# Collect collector metrics +COLLECTOR_METRICS_OUTPUT="collector-metrics" +info "Collecting collector metrics to ${COLLECTOR_METRICS_OUTPUT}" +if "${ROOT}/scripts/ci/collect-collector-metrics.sh" stackrox "${COLLECTOR_METRICS_OUTPUT}"; then + info "Collected collector metrics to ${COLLECTOR_METRICS_OUTPUT}" +else + info "Warning: Failed to collect collector metrics" +fi + # Store artifacts to OpenShift CI artifact directory if [[ -n "${ARTIFACT_DIR:-}" ]]; then info "Copying diagnostics to ${ARTIFACT_DIR}" if [[ -d "${DIAGNOSTIC_OUTPUT}" ]]; then cp -r "${DIAGNOSTIC_OUTPUT}" "${ARTIFACT_DIR}/" || info "Warning: Failed to copy ${DIAGNOSTIC_OUTPUT}" fi + if [[ -d "${COLLECTOR_METRICS_OUTPUT}" ]]; then + cp -r "${COLLECTOR_METRICS_OUTPUT}" "${ARTIFACT_DIR}/" || info "Warning: Failed to copy ${COLLECTOR_METRICS_OUTPUT}" + fi else info "Warning: ARTIFACT_DIR not set, diagnostics not copied to artifacts" fi diff --git a/scripts/ci/jobs/ocp_qa_e2e_tests.py b/scripts/ci/jobs/ocp_qa_e2e_tests.py index 27d29566d7c84..4e7d7049e18b0 100755 --- a/scripts/ci/jobs/ocp_qa_e2e_tests.py +++ b/scripts/ci/jobs/ocp_qa_e2e_tests.py @@ -12,6 +12,7 @@ os.environ["DEPLOY_STACKROX_VIA_OPERATOR"] = "true" os.environ["ORCHESTRATOR_FLAVOR"] = "openshift" os.environ["KUBERNETES_PROVIDER"] = "ocp" +os.environ["USE_ROXIE_DEPLOY"] = "true" # Workload identities are only set up for `openshift-4` infra clusters. if 'openshift-4' in os.environ.get('CLUSTER_FLAVOR_VARIANT', ''): os.environ["SETUP_WORKLOAD_IDENTITIES"] = "true" diff --git a/scripts/ci/jobs/ocp_ui_e2e_tests.py b/scripts/ci/jobs/ocp_ui_e2e_tests.py index f3e4dfe4eeb8b..b5f28a700bd22 100755 --- a/scripts/ci/jobs/ocp_ui_e2e_tests.py +++ b/scripts/ci/jobs/ocp_ui_e2e_tests.py @@ -11,7 +11,6 @@ from post_tests import PostClusterTest, FinalPost # set required test parameters -os.environ["DEPLOY_STACKROX_VIA_OPERATOR"] = "true" os.environ["INSTALL_COMPLIANCE_OPERATOR"] = "true" os.environ["ORCHESTRATOR_FLAVOR"] = "openshift" os.environ["KUBERNETES_PROVIDER"] = "ocp" diff --git a/scripts/ci/jobs/ocp_vm_scanning_e2e_tests.py b/scripts/ci/jobs/ocp_vm_scanning_e2e_tests.py index 695d9d77640fc..a77f458cb16b8 100755 --- a/scripts/ci/jobs/ocp_vm_scanning_e2e_tests.py +++ b/scripts/ci/jobs/ocp_vm_scanning_e2e_tests.py @@ -23,6 +23,9 @@ os.environ["SENSOR_HELM_MANAGED"] = "true" os.environ["INSTALL_CNV_OPERATOR"] = "true" os.environ["ROX_VIRTUAL_MACHINES"] = "true" +# Leave guests up so post-test can collect roxagent journals, then +# delete-vm-ns.sh deletes the test namespaces. +os.environ["VM_SCAN_SKIP_CLEANUP"] = "true" # Selectively enable vulnerability bundles to prevent timeouts of matcher not being ready in 40 minutes. # The rhel-vex bundle alone has ~3M records and can take >30 min to import. # Drops alpine, aws, debian, oracle, osv, photon, suse, ubuntu (unused for RHEL guests). @@ -36,10 +39,10 @@ class VMScanningPostTest(PostClusterTest): - """Extends standard post-test with CNV namespace logs.""" + """Extends standard post-test with CNV namespace logs and guest roxagent journals.""" def __init__(self, **kwargs): - super().__init__(**kwargs) + super().__init__(collect_vm_guest_logs=True, **kwargs) self.k8s_namespaces.extend([ "openshift-cnv", ]) diff --git a/scripts/ci/lib.sh b/scripts/ci/lib.sh index 3f7096f605151..c87e420a12158 100755 --- a/scripts/ci/lib.sh +++ b/scripts/ci/lib.sh @@ -14,6 +14,35 @@ source "$SCRIPTS_ROOT/scripts/ci/gcp.sh" set -euo pipefail +# ensure_writable_bash_env points BASH_ENV at a temp file when the CI image +# default (/etc/initial-bash.env) is not readable or writable by the process +# UID. Child bash then stops erroring on source, and cci-export can persist env. +ensure_writable_bash_env() { + if [[ -z "${BASH_ENV:-}" ]]; then + return 0 + fi + if [[ -r "${BASH_ENV}" && -w "${BASH_ENV}" ]]; then + return 0 + fi + + local new_bash_env + new_bash_env="$(mktemp)" || return 1 + if [[ -r "${BASH_ENV}" ]]; then + if ! cp "${BASH_ENV}" "${new_bash_env}"; then + rm -f "${new_bash_env}" + return 1 + fi + fi + BASH_ENV="${new_bash_env}" + export BASH_ENV +} + +# OpenShift CI cannot read /etc/initial-bash.env (random user). Switch BASH_ENV +# to a writable file now, before make and status.sh start more bash processes. +if is_CI; then + ensure_writable_bash_env +fi + ensure_CI() { if ! is_CI; then die "A CI environment is required." @@ -44,11 +73,7 @@ ci_export() { echo "${env_name}=${env_value}" >> "$GITHUB_ENV" fi elif command -v cci-export >/dev/null; then - # cci-export writes to $BASH_ENV which defaults to read-only /etc/initial-bash.env in the CI container - if [[ -n "${BASH_ENV:-}" && ! -w "${BASH_ENV}" ]]; then - BASH_ENV=$(mktemp) - export BASH_ENV - fi + ensure_writable_bash_env || return 1 cci-export "$env_name" "$env_value" else export "$env_name"="$env_value" @@ -657,7 +682,7 @@ _image_prefetcher_prebuilt_start() { image_prefetcher_start_set qa-e2e _set_quay_pull_policy ;; - *nongroovy-e2e-tests) + *nongroovy-e2e-tests*) image_prefetcher_start_set qa-nongroovy-e2e _set_quay_pull_policy ;; @@ -825,7 +850,7 @@ _image_prefetcher_prebuilt_await() { *qa-e2e-tests*) image_prefetcher_await_set qa-e2e ;; - *nongroovy-e2e-tests) + *nongroovy-e2e-tests*) image_prefetcher_await_set qa-nongroovy-e2e ;; *compatibility-tests) @@ -915,28 +940,15 @@ EOM rm -f "${query}" fi info "Now retrieving prefetcher metrics..." - local attempt=0 - local service="service/${name}-metrics" - while [[ -z $(kubectl -n "${ns}" get "${service}" -o jsonpath="{.status.loadBalancer.ingress}" 2>/dev/null) ]]; do - if [ "$attempt" -lt "60" ]; then - info "Waiting for ${service} to obtain endpoint ..." - ((attempt++)) - sleep 10 - else - info "Something is wrong with the ${service} service. See the following 'describe' output." - kubectl -n "${ns}" describe "${service}" || true - die "Timeout waiting for ${service} to obtain endpoint!" - fi - done - local endpoint - endpoint="$(kubectl -n "${ns}" get "${service}" -o json | service_get_endpoint)" + make image-prefetcher-deploy-bin + local image_prefetcher_deploy_bin + image_prefetcher_deploy_bin="$(make print-image-prefetcher-deploy-bin)" local fetcher_metrics fetcher_metrics="$(mktemp --suffix=.csv)" local fetcher_metrics_json fetcher_metrics_json="$(mktemp --suffix=.json)" - local metrics_url="http://${endpoint}:8080/metrics" - if ! curl --silent --show-error --fail --retry 3 --retry-connrefused "${metrics_url}" > "${fetcher_metrics_json}"; then - die "Failed to fetch prefetcher metrics from ${metrics_url}" + if ! "${image_prefetcher_deploy_bin}" --fetch-metrics --namespace="${ns}" "${name}" > "${fetcher_metrics_json}"; then + die "Failed to fetch prefetcher metrics for set ${name}" fi # See the stackrox_image_prefetches table definition in https://github.com/stackrox/automation-iac/blob/main/resources/testing/stackrox-ci/metrics.tf # for the order of columns. @@ -1055,7 +1067,7 @@ scanner-v4-db ${tag} roxctl ${tag} END ;; - *qa-e2e-tests*) + *nongroovy-e2e-tests*|*qa-e2e-tests*) if [[ "${USE_KONFLUX_IMAGES:-false}" == "true" ]]; then cat >> "${image_list}" << END release-operator ${operator_controller_tag} @@ -1514,6 +1526,8 @@ get_pr_details() { openshift_ci_mods() { info "BEGIN OpenShift CI mods" + ensure_writable_bash_env + openshift_ci_debug info "Current Status:" @@ -2730,6 +2744,26 @@ _record_cluster_info() { set_ci_shared_export "cut_container_runtime_version" "$containerRuntimeVersion" } +# list_vm_scan_namespaces prints VM-scanning e2e namespace names, one per line. +# Returns 1 when kubectl cannot list namespaces, distinct from zero matches. +list_vm_scan_namespaces() { + local prefix="${VM_SCAN_NAMESPACE_PREFIX:-vm-scan-e2e}" + local out err + out="$(mktemp)" + err="$(mktemp)" + if ! kubectl --request-timeout=30s get ns \ + -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}' \ + > "$out" 2>"$err"; then + info "kubectl get ns failed: $(<"$err")" >&2 + rm -f "$out" "$err" + return 1 + fi + rm -f "$err" + grep -E "^${prefix}(-|$)" "$out" || true + rm -f "$out" + return 0 +} + if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then if [[ "$#" -lt 1 ]]; then die "When invoked at the command line a method is required." diff --git a/scripts/ci/logcheck/restart-ok-patterns.json b/scripts/ci/logcheck/restart-ok-patterns.json index a560532741d71..464531694d915 100644 --- a/scripts/ci/logcheck/restart-ok-patterns.json +++ b/scripts/ci/logcheck/restart-ok-patterns.json @@ -54,15 +54,9 @@ "logline": "Socket closed" }, { - "comment": "Scanner V4 slow to start indexer with external DB", - "job": "(gke-external-pg-17-qa-e2e-tests|gke-byodb-qa-e2e-tests)", - "logfile": "indexer-previous", - "logline": "panic: migrate: failed to connect to" - }, - { - "comment": "Scanner V4 slow to start matcher with external DB", - "job": "(gke-external-pg-17-qa-e2e-tests|gke-byodb-qa-e2e-tests)", - "logfile": "matcher-previous", + "comment": "Scanner V4 components can start before scanner-v4-db is ready to accept connections", + "job": ".*", + "logfile": "(indexer|matcher)-previous", "logline": "panic: migrate: failed to connect to" }, { diff --git a/scripts/ci/push-as-multiarch-manifest-list.sh b/scripts/ci/push-as-multiarch-manifest-list.sh index 6c55d6f5ed9b4..01c6387506ef2 100755 --- a/scripts/ci/push-as-multiarch-manifest-list.sh +++ b/scripts/ci/push-as-multiarch-manifest-list.sh @@ -22,7 +22,10 @@ do image_list+=("$arch_image") done -docker manifest create "$image" "${image_list[@]}" +# --amend: this script is retried on failure (see push_*_manifest_lists in +# scripts/ci/lib.sh), and "docker manifest create" errors out if a local +# manifest list of the same name already exists, which it would on a retry. +docker manifest create --amend "$image" "${image_list[@]}" # Try pushing manifest a few times for the case when quay.io has issues pushed=0 diff --git a/scripts/fixxxers/config-controller/10-generate.sh b/scripts/fixxxers/config-controller/10-generate.sh new file mode 100755 index 0000000000000..22fcfa5a44923 --- /dev/null +++ b/scripts/fixxxers/config-controller/10-generate.sh @@ -0,0 +1,4 @@ +#!/bin/bash +set -euo pipefail + +make config-controller-gen diff --git a/scripts/go-files-to-packages.sh b/scripts/go-files-to-packages.sh new file mode 100755 index 0000000000000..f87926393c81c --- /dev/null +++ b/scripts/go-files-to-packages.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +set -euo pipefail +# Reads a list of files (one per line) from stdin and prints on stdout a list of go packages. +# The arguments are passed to `go list` that is used to perform the transformation. +# That go list command is retried, to help with go proxy unavailability. + +num_retries=4 + +dir_list=$(mktemp) +sed -e 's@^@./@g' | xargs -n 1 dirname | sort | uniq > "${dir_list}" +output=$(mktemp) +for attempt in $(seq 0 $num_retries) +do + sleep_sec=$((attempt * 5)) + if [[ $sleep_sec -gt 0 ]]; then + echo >&2 "Sleeping ${sleep_sec} before retrying..." + sleep "${sleep_sec}" + fi + if xargs go list "$@" < "${dir_list}" > "${output}"; then + grep -v '^github.com/stackrox/rox/tests$' "${output}" + exit 0 + fi +done +echo >&2 "Running 'go list $*' failed despite $num_retries retries." +exit 1 diff --git a/scripts/offline-bundle/.gitignore b/scripts/offline-bundle/.gitignore deleted file mode 100644 index 8bc06143b8a41..0000000000000 --- a/scripts/offline-bundle/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -**/*.img -**/bin -*.tgz diff --git a/scripts/offline-bundle/create.sh b/scripts/offline-bundle/create.sh deleted file mode 100755 index 0bf4e1b614dce..0000000000000 --- a/scripts/offline-bundle/create.sh +++ /dev/null @@ -1,63 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail -IFS=$'\n\t' - -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)" - -export_image() { - local name=$1 - local image=$2 - local last_dir=$3 - - docker pull "$image" | cat - - mkdir -p "${DIR}/${last_dir}" - echo "Saving $image to ${DIR}/${last_dir}/${name}.img" - docker save "$image" -o "${DIR}/${last_dir}/${name}.img" -} - -save() { - local registry=$1 - local name=$2 - local tag=$3 - local last_dir=$4 - - export_image "$name" "${registry}/${name}:${tag}" "${last_dir}" -} - -bundle() { - local name=$1 - pushd "${DIR}" - tar -czvf "${name}.tgz" "${name}" - popd -} - -store_roxctl() { - output_path=$1 - mkdir -p "${DIR}/${output_path}/bin" - gsutil -m cp -r "gs://sr-roxc/${main_tag}/bin/darwin" "${DIR}/${output_path}/bin" - gsutil -m cp -r "gs://sr-roxc/${main_tag}/bin/linux" "${DIR}/${output_path}/bin" - gsutil -m cp -r "gs://sr-roxc/${main_tag}/bin/windows" "${DIR}/${output_path}/bin" - chmod +x "${DIR}/${output_path}/bin/darwin/roxctl" "${DIR}/${output_path}/bin/linux/roxctl" -} - -main() { - # Main uses the version reported by make tag. - local main_tag - main_tag="$(make --quiet --no-print-directory tag)" - save "stackrox.io" "main" "${main_tag}" "image-bundle" - - # Scanner uses the same version as Main. - save "stackrox.io" "scanner" "${main_tag}" "image-bundle" - save "stackrox.io" "scanner-db" "${main_tag}" "image-bundle" - - # Collector uses the same version as Main. - save "collector.stackrox.io" "collector" "${main_tag}" "image-collector-bundle" - - store_roxctl "image-bundle" - - bundle "image-bundle" - bundle "image-collector-bundle" -} - -main "$@" diff --git a/scripts/offline-bundle/image-bundle/README.txt b/scripts/offline-bundle/image-bundle/README.txt deleted file mode 100644 index 5375d77249f1e..0000000000000 --- a/scripts/offline-bundle/image-bundle/README.txt +++ /dev/null @@ -1,18 +0,0 @@ -This bundle contains archives of the images necessary to run the -StackRox Kubernetes Security Platform. - -To secure a cluster, your private registry must be able to pull the images. -The import script loads images onto your local Docker engine, but can also -push the images to a private registry. - -To install, first reimport the images: - ./import.sh - -See product documentation for complete setup steps. To view documentation: - - Go to https://help.stackrox.com, or - - Run import.sh, then follow the instructions displayed. - -When you generate your installation configuration and follow the -instructions, use your private registry image names. - -See product documentation for additional details. diff --git a/scripts/offline-bundle/image-bundle/import.sh b/scripts/offline-bundle/image-bundle/import.sh deleted file mode 100755 index 625de26a13d37..0000000000000 --- a/scripts/offline-bundle/image-bundle/import.sh +++ /dev/null @@ -1,61 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail -IFS=$'\n\t' - -print_docs_usage() { - echo - echo "To view complete product documentation go to https://help.stackrox.com" -} - -main() { - cd "$(dirname "${BASH_SOURCE[0]}")" - - echo "This script can optionally push imported images into a private registry." - echo "Most users add a path segment like \"/stackrox\"." - echo "For example, you might input: my-registry.example.com:5000/stackrox" - echo "To skip pushing, simply do not enter a prefix." - echo -n "Enter your private registry prefix: " - read registry_prefix - echo - - echo "Loading main image..." - main_tag="$(docker load -i main.img | tag)" - main_image_local="stackrox.io/main:${main_tag}" - main_image_remote="${registry_prefix}/main:${main_tag}" - - echo "Loading scanner images..." - scanner_tag="$(docker load -i scanner.img | tag)" - scanner_image_local="stackrox.io/scanner:${scanner_tag}" - scanner_image_remote="${registry_prefix}/scanner:${scanner_tag}" - - scanner_db_tag="$(docker load -i scanner-db.img | tag)" - scanner_db_image_local="stackrox.io/scanner-db:${scanner_db_tag}" - scanner_db_image_remote="${registry_prefix}/scanner-db:${scanner_db_tag}" - - if [[ -z "$registry_prefix" ]]; then - echo "No registry prefix given, all done!" - print_docs_usage - return - fi - - echo "Pushing image: ${main_image_local} as ${main_image_remote}" - docker tag "${main_image_local}" "${main_image_remote}" - docker push "${main_image_remote}" | cat - - echo "Pushing image: ${scanner_image_local} as ${scanner_image_remote}" - docker tag "${scanner_image_local}" "${scanner_image_remote}" - docker push "${scanner_image_remote}" | cat - - echo "Pushing image: ${scanner_db_image_local} as ${scanner_db_image_remote}" - docker tag "${scanner_db_image_local}" "${scanner_db_image_remote}" - docker push "${scanner_db_image_remote}" | cat - - echo "All done!" - print_docs_usage -} - -tag() { - sed 's/.*:\(.*$\)/\1/' -} - -main diff --git a/scripts/offline-bundle/image-collector-bundle/README.txt b/scripts/offline-bundle/image-collector-bundle/README.txt deleted file mode 100644 index 6c5b4ab778c6b..0000000000000 --- a/scripts/offline-bundle/image-collector-bundle/README.txt +++ /dev/null @@ -1,7 +0,0 @@ -This bundle contains archives of the Collector image which integrates with -the StackRox Kubernetes Security Platform. - -To install, first reimport the image: - ./import.sh - -See product documentation for additional details. diff --git a/scripts/offline-bundle/image-collector-bundle/import.sh b/scripts/offline-bundle/image-collector-bundle/import.sh deleted file mode 100755 index 024f0edd5a629..0000000000000 --- a/scripts/offline-bundle/image-collector-bundle/import.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail -IFS=$'\n\t' - -main() { - cd "$(dirname "${BASH_SOURCE[0]}")" - - echo "This script can optionally push imported images into a private registry." - echo "Most users add a path segment like \"/stackrox\"." - echo "For example, you might input: my-registry.example.com:5000/stackrox" - echo "To skip pushing, simply do not enter a prefix." - echo -n "Enter your private registry prefix: " - read registry_prefix - echo - - echo "Loading collector image..." - collector_tag="$(docker load -i collector.img | tag)" - collector_image_local="collector.stackrox.io/collector:${collector_tag}" - collector_image_remote="${registry_prefix}/collector:${collector_tag}" - - if [[ -z "$registry_prefix" ]]; then - echo "No registry prefix given, all done!" - return - fi - - echo "Pushing image: ${collector_image_local} as ${collector_image_remote}" - docker tag "${collector_image_local}" "${collector_image_remote}" - docker push "${collector_image_remote}" | cat - - echo "All done!" -} - -tag() { - sed 's/.*:\(.*$\)/\1/' -} - -main diff --git a/deploy/common/pull-secret.sh b/scripts/pull-secret.sh similarity index 80% rename from deploy/common/pull-secret.sh rename to scripts/pull-secret.sh index 869de8c44d6fc..900b8c093441e 100755 --- a/deploy/common/pull-secret.sh +++ b/scripts/pull-secret.sh @@ -2,7 +2,7 @@ set -euo pipefail -DIR="$(cd "$(dirname "$0")" && pwd)" +ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)" die() { echo >&2 "$@" @@ -16,7 +16,7 @@ name="$1" registry="$2" [[ -n "$registry" ]] || die "No registry specified" -registry_auth="$("${DIR}/docker-auth.sh" -m k8s "$registry")" +registry_auth="$("${ROOT_DIR}/image/assets/docker-auth.sh" -m k8s "$registry")" [[ -n "$registry_auth" ]] || die "Unable to get registry auth info." cat <&2 'Note: $GITHUB_TOKEN not found, querying GitHub without an Authorization header may result in throttling.' + fi + + asset_id="$(curl -fsS --retry 3 --retry-delay 5 --retry-connrefused "${auth_headers[@]}" \ -H "Accept: application/vnd.github+json" \ -H "X-GitHub-Api-Version: 2026-03-10" \ "https://api.github.com/repos/${repo}/releases/${version}" \ @@ -117,7 +125,7 @@ gh_download_release() { echo >&2 "Error: No asset ID found for asset name ${asset_name} for release tag ${version} in repo ${repo}" exit 1 fi - curl -fsSL --retry 3 --retry-delay 5 --retry-connrefused \ + curl -fsSL --retry 3 --retry-delay 5 --retry-connrefused "${auth_headers[@]}" \ -H 'Accept: application/octet-stream' \ -o "$target" \ "https://api.github.com/repos/${repo}/releases/assets/${asset_id}" diff --git a/sensor/common/deduper/deduper.go b/sensor/common/deduper/deduper.go index 3e8734f205ef6..d33c8379be41c 100644 --- a/sensor/common/deduper/deduper.go +++ b/sensor/common/deduper/deduper.go @@ -80,11 +80,12 @@ func (d *deduper) Send(msg *central.MsgFromSensor) error { ResourceType: reflect.TypeOf(event.GetResource()), } if event.GetAction() == central.ResourceAction_REMOVE_RESOURCE { - priorLen := len(d.lastSent) + _, previouslySent := d.lastSent[key] delete(d.lastSent, key) - // Do not send a remove message for something that has not been seen before - // This also effectively dedupes REMOVE actions - if priorLen == len(d.lastSent) { + // Runtime alerts bypass lastSent, so alert removals must reach Central + // even if no deploy-time result has been sent yet. Other resource + // removals can be dropped if the resource was never sent or already removed. + if !previouslySent && event.GetAlertResults() == nil { return nil } if err := d.stream.Send(msg); err != nil { diff --git a/sensor/common/deduper/runtime_removal_test.go b/sensor/common/deduper/runtime_removal_test.go new file mode 100644 index 0000000000000..3525142767491 --- /dev/null +++ b/sensor/common/deduper/runtime_removal_test.go @@ -0,0 +1,117 @@ +package deduper + +import ( + "testing" + + "github.com/stackrox/rox/generated/internalapi/central" + "github.com/stackrox/rox/generated/storage" + "github.com/stretchr/testify/require" +) + +func TestRuntimeAlertRemovalIsForwarded(t *testing.T) { + cases := map[string]bool{ + "runtime alert only": false, + "deploy result before runtime alert": true, + } + + for name, sendDeployResult := range cases { + t.Run(name, func(t *testing.T) { + downstream := new(fakeStream) + stream := NewDedupingMessageStream(downstream, nil, false) + + makeMessage := func(action central.ResourceAction, stage storage.LifecycleStage) *central.MsgFromSensor { + return ¢ral.MsgFromSensor{ + Msg: ¢ral.MsgFromSensor_Event{ + Event: ¢ral.SensorEvent{ + Id: "deployment-1", + Action: action, + Resource: ¢ral.SensorEvent_AlertResults{ + AlertResults: ¢ral.AlertResults{ + DeploymentId: "deployment-1", + Stage: stage, + }, + }, + }, + }, + } + } + + if sendDeployResult { + msg := makeMessage(central.ResourceAction_CREATE_RESOURCE, storage.LifecycleStage_DEPLOY) + require.NoError(t, stream.Send(msg)) + require.Len(t, downstream.orderedMessages, 1) + } + + runtime := makeMessage(central.ResourceAction_CREATE_RESOURCE, storage.LifecycleStage_RUNTIME) + runtime.GetEvent().GetAlertResults().Alerts = []*storage.Alert{ + { + Id: "runtime-alert-1", + LifecycleStage: storage.LifecycleStage_RUNTIME, + State: storage.ViolationState_ACTIVE, + }, + } + beforeRuntime := len(downstream.orderedMessages) + require.NoError(t, stream.Send(runtime)) + require.Len(t, downstream.orderedMessages, beforeRuntime+1) + + // Sensor's removal message is empty and has the default lifecycle + // stage, DEPLOY, even when the deployment has runtime alerts. + removal := makeMessage(central.ResourceAction_REMOVE_RESOURCE, storage.LifecycleStage_DEPLOY) + beforeRemoval := len(downstream.orderedMessages) + require.NoError(t, stream.Send(removal)) + require.Len(t, downstream.orderedMessages, beforeRemoval+1, + "alert removal must reach Central even without a prior deploy-time result") + require.Same(t, removal, downstream.orderedMessages[len(downstream.orderedMessages)-1]) + + // Repeated alert removals must also reach Central. + require.NoError(t, stream.Send(removal)) + require.Len(t, downstream.orderedMessages, beforeRemoval+2) + require.Same(t, removal, downstream.orderedMessages[len(downstream.orderedMessages)-1]) + + // Removal must clear any cached deploy-time result. + if sendDeployResult { + msg := makeMessage(central.ResourceAction_CREATE_RESOURCE, storage.LifecycleStage_DEPLOY) + require.NoError(t, stream.Send(msg)) + require.Len(t, downstream.orderedMessages, beforeRemoval+3) + } + }) + } +} + +func TestDeploymentRemovalDeduplication(t *testing.T) { + cases := map[string]bool{ + "previously sent": true, + "never sent": false, + } + for name, previouslySent := range cases { + t.Run(name, func(t *testing.T) { + downstream := new(fakeStream) + stream := NewDedupingMessageStream(downstream, nil, false) + msg := ¢ral.MsgFromSensor{ + Msg: ¢ral.MsgFromSensor_Event{ + Event: ¢ral.SensorEvent{ + Id: "deployment-1", + Action: central.ResourceAction_CREATE_RESOURCE, + Resource: ¢ral.SensorEvent_Deployment{ + Deployment: &storage.Deployment{Id: "deployment-1"}, + }, + }, + }, + } + if previouslySent { + require.NoError(t, stream.Send(msg)) + require.Len(t, downstream.orderedMessages, 1) + } + removal := msg.CloneVT() + removal.GetEvent().Action = central.ResourceAction_REMOVE_RESOURCE + require.NoError(t, stream.Send(removal)) + require.NoError(t, stream.Send(removal)) + if previouslySent { + require.Len(t, downstream.orderedMessages, 2) + require.Same(t, removal, downstream.orderedMessages[1]) + } else { + require.Empty(t, downstream.orderedMessages) + } + }) + } +} diff --git a/sensor/common/detector/detector.go b/sensor/common/detector/detector.go index ef9b94103e2ef..5eae96f0afdc9 100644 --- a/sensor/common/detector/detector.go +++ b/sensor/common/detector/detector.go @@ -427,7 +427,11 @@ func (d *detectorImpl) Notify(e common.SensorComponentEvent) { } func (d *detectorImpl) Capabilities() []centralsensor.SensorCapability { - return []centralsensor.SensorCapability{centralsensor.SensorDetectionCap} + caps := []centralsensor.SensorCapability{centralsensor.SensorDetectionCap} + if features.PolicyWorkloadKindExclusion.Enabled() { + caps = append(caps, centralsensor.WorkloadKindExclusionCap) + } + return caps } // ProcessPolicySync reconciles policies and flush all deployments through the detector diff --git a/sensor/common/scan/scan.go b/sensor/common/scan/scan.go index 897f58e37b318..afcfe2346d431 100644 --- a/sensor/common/scan/scan.go +++ b/sensor/common/scan/scan.go @@ -154,7 +154,8 @@ func (s *LocalScan) EnrichLocalImageInNamespace(ctx context.Context, centralClie // Check if there is a local Scanner. // No need to continue if there is no local Scanner. - if s.scannerClientSingleton() == nil { + scannerClient := s.scannerClientSingleton() + if scannerClient == nil { return nil, errors.Join(ErrNoLocalScanner, ErrEnrichNotStarted) } @@ -197,7 +198,7 @@ func (s *LocalScan) EnrichLocalImageInNamespace(ctx context.Context, centralClie // Only proceed if metadata was fetched successfully if errorList.Empty() { // Perform partial scan (image analysis / identify components) via local scanner. - scannerResp = s.fetchImageAnalysis(ctx, errorList, reg, pullSourceImage) + scannerResp = s.fetchImageAnalysis(ctx, errorList, reg, pullSourceImage, scannerClient) // Fetch signatures associated with image from registry. Do this even if the scan above failed, because that // doesn't necessarily mean signatures cannot be fetched @@ -413,9 +414,9 @@ func (s *LocalScan) enrichImageWithMetadata(ctx context.Context, errorList *erro } // fetchImageAnalysis analyzes an image via the local scanner. -func (s *LocalScan) fetchImageAnalysis(ctx context.Context, errorList *errorhelpers.ErrorList, registry registryTypes.ImageRegistry, image *storage.Image) *scannerclient.ImageAnalysis { +func (s *LocalScan) fetchImageAnalysis(ctx context.Context, errorList *errorhelpers.ErrorList, registry registryTypes.ImageRegistry, image *storage.Image, scannerClient scannerclient.ScannerClient) *scannerclient.ImageAnalysis { // Scan the image via local scanner. - scannerResp, err := s.scanImg(ctx, image, registry, s.scannerClientSingleton()) + scannerResp, err := s.scanImg(ctx, image, registry, scannerClient) if err != nil { log.Debugf("Scan for image %q with id %v failed: %v", image.GetName().GetFullName(), image.GetId(), err) image.Notes = append(image.Notes, storage.Image_MISSING_SCAN_DATA) diff --git a/sensor/common/scan/scan_test.go b/sensor/common/scan/scan_test.go index d40bd633c82b4..cb86d76abb3d6 100644 --- a/sensor/common/scan/scan_test.go +++ b/sensor/common/scan/scan_test.go @@ -122,6 +122,65 @@ func (suite *scanTestSuite) TestLocalEnrichment() { suite.Assert().True(getRegistriesTriggered, "get registry was not triggered") } +// TestScannerClientCapturedOnce is a regression guard for a TOCTOU nil-client +// dereference: the scanner client singleton must be consulted once per +// enrichment and the client captured at the nil-check must be the one handed to +// the scan. Otherwise a concurrent reset of the singleton (e.g. on Central +// reconnect) could return non-nil at the check but nil at the scan, panicking +// when a method is invoked on the nil client. +func (suite *scanTestSuite) TestScannerClientCapturedOnce() { + fakeRegStore := &fakeRegistryStore{} + mirrorStore := mirrorStoreMocks.NewMockStore(gomock.NewController(suite.T())) + + // Returns a valid client on the first call, then nil, simulating a + // concurrent singleton reset occurring mid-enrichment. + capturedClient := &emptyClient{} + singletonCalls := 0 + singleton := func() scannerclient.ScannerClient { + singletonCalls++ + if singletonCalls == 1 { + return capturedClient + } + return nil + } + + var scannedWithClient scannerclient.ScannerClient + recordingScan := func(_ context.Context, _ *storage.Image, + reg registryTypes.ImageRegistry, client scannerclient.ScannerClient) (*scannerclient.ImageAnalysis, error) { + scannedWithClient = client + return successfulScan(context.Background(), nil, reg, client) + } + + scan := LocalScan{ + scanImg: recordingScan, + fetchSignaturesWithRetry: successfulFetchSignatures, + getPullSecretRegistries: func(*storage.ImageName, string, []string) ([]registryTypes.ImageRegistry, error) { + return []registryTypes.ImageRegistry{&fakeRegistry{fail: false}}, nil + }, + getGlobalRegistries: func(*storage.ImageName) ([]registryTypes.ImageRegistry, error) { + return []registryTypes.ImageRegistry{&fakeRegistry{fail: false}}, nil + }, + scannerClientSingleton: singleton, + scanSemaphore: semaphore.NewWeighted(10), + getCentralRegistries: fakeRegStore.GetMatchingCentralRegistryIntegrations, + mirrorStore: mirrorStore, + maxSemaphoreWaitTime: defaultMaxSemaphoreWaitTime, + } + + containerImg, err := utils.GenerateImageFromString("docker.io/nginx") + suite.Require().NoError(err, "failed creating test image") + + imageServiceClient := suite.createMockImageServiceClient(types.ToImage(containerImg), false) + mirrorStore.EXPECT().PullSources(containerImg.GetName().GetFullName()) + + // Must not panic even though the singleton starts returning nil after the check. + _, err = scan.EnrichLocalImageInNamespace(context.Background(), imageServiceClient, genScanReq(containerImg, "fake-namespace", "", false)) + suite.Require().NoError(err, "unexpected error when enriching image") + + suite.Assert().Equal(1, singletonCalls, "scanner client singleton should be consulted exactly once") + suite.Assert().Same(capturedClient, scannedWithClient, "scan should use the client captured at the nil-check") +} + func (suite *scanTestSuite) TestEnrichImageFailures() { type testCase struct { scanImg func(ctx context.Context, image *storage.Image, diff --git a/sensor/common/scannerclient/grpc_client.go b/sensor/common/scannerclient/grpc_client.go index 1dd8853914d86..6f689846963b2 100644 --- a/sensor/common/scannerclient/grpc_client.go +++ b/sensor/common/scannerclient/grpc_client.go @@ -3,24 +3,18 @@ package scannerclient import ( "context" "fmt" - "strings" "github.com/google/go-containerregistry/pkg/authn" "github.com/pkg/errors" v4 "github.com/stackrox/rox/generated/internalapi/scanner/v4" "github.com/stackrox/rox/generated/storage" - "github.com/stackrox/rox/pkg/clientconn" "github.com/stackrox/rox/pkg/env" - "github.com/stackrox/rox/pkg/images/utils" "github.com/stackrox/rox/pkg/logging" - "github.com/stackrox/rox/pkg/mtls" "github.com/stackrox/rox/pkg/registries/types" pkgscanner "github.com/stackrox/rox/pkg/scannerv4" "github.com/stackrox/rox/pkg/scannerv4/client" "github.com/stackrox/rox/sensor/common/centralcabundle" scannerV1 "github.com/stackrox/scanner/generated/scanner/api/v1" - "google.golang.org/grpc" - "google.golang.org/grpc/credentials" ) var ( @@ -45,13 +39,6 @@ type ImageAnalysis struct { V4Contents *v4.Contents } -// v2Client is the client for StackRox Scanner based on Clair V2, also -// known as Scanner V2. -type v2Client struct { - scannerV1.ImageScanServiceClient - conn *grpc.ClientConn -} - // v4Client is the client for StackRox Scanner Indexer, also // known as Scanner V4 Indexer. type v4Client struct { @@ -103,57 +90,6 @@ func (i *ImageAnalysis) GetIndexerVersion() string { return "" } -// getScannerEndpoint reads and validate the Scanner gRPC endpoint setting. If -// the endpoint is empty or not configured properly (invalid) the value is -// returned and error will be set. -func getScannerEndpoint(s env.Setting) (string, error) { - e := s.Setting() - if e == "" { - return e, errors.Errorf("%s is not set or empty", s.EnvVar()) - } - e = strings.TrimPrefix(e, "https://") - if strings.Contains(e, "://") { - return e, errors.Errorf("%s has unsupported scheme: %s", s.EnvVar(), e) - } - return e, nil -} - -// dial the scanner and returns a new ScannerClient. The function is non-blocking and -// returns a non-nil error upon configuration error. -func dial(endpoint string, certID mtls.Subject) (*grpc.ClientConn, error) { - tlsConfig, err := clientconn.TLSConfig(certID, clientconn.TLSConfigOptions{ - UseClientCert: clientconn.MustUseClientCert, - }) - if err != nil { - return nil, fmt.Errorf("TLS config failed: %w", err) - } - // This is non-blocking. If we ever want this to block, then add the - // grpc.WithBlock() DialOption. - log.Infof("dialing scanner at %s", endpoint) - conn, err := grpc.Dial(endpoint, grpc.WithTransportCredentials(credentials.NewTLS(tlsConfig))) - if err != nil { - return nil, fmt.Errorf("grpc dial failed: %w", err) - } - return conn, nil -} - -// dialV2 connect to scanner V1 gRPC and return a new ScannerClient. -func dialV2() (ScannerClient, error) { - endpoint, err := getScannerEndpoint(env.ScannerSlimGRPCEndpoint) - if err != nil { - return nil, err - } - log.Infof("dialing scanner-v2 client: %s", endpoint) - conn, err := dial(endpoint, mtls.ScannerSubject) - if err != nil { - return nil, err - } - return &v2Client{ - ImageScanServiceClient: scannerV1.NewImageScanServiceClient(conn), - conn: conn, - }, nil -} - // dialV4 connect to scanner V4 gRPC and return a new ScannerClient. func dialV4() (ScannerClient, error) { ctx := context.Background() @@ -172,45 +108,6 @@ func dialV4() (ScannerClient, error) { return &v4Client{client: c}, nil } -// GetImageAnalysis retrieves the image analysis results for the given image. -func (c *v2Client) GetImageAnalysis(ctx context.Context, image *storage.Image, cfg *types.Config) (*ImageAnalysis, error) { - imgName := image.GetName().GetFullName() - - // The WaitForReady option will cause invocations to block (until server ready or - // ctx done/expires) This was added so that on fresh installation of sensor when - // scanner is not ready yet, local scans will not all fail and have to wait for - // next reprocess to succeed - resp, err := c.GetImageComponents(ctx, &scannerV1.GetImageComponentsRequest{ - Image: utils.GetFullyQualifiedFullName(image), - Registry: &scannerV1.RegistryData{ - Url: cfg.URL, - Username: cfg.Username, - Password: cfg.Password, - Insecure: cfg.Insecure, - }, - }, grpc.WaitForReady(true)) - if err != nil { - log.Debugf("Unable to get image components from local Scanner for image %s: %v", imgName, err) - return nil, errors.Wrap(err, "getting image components from scanner") - } - - log.Debugf("Received image components from local Scanner for image: %q", imgName) - - return &ImageAnalysis{ - ScanStatus: resp.GetStatus(), - ScanNotes: resp.GetNotes(), - V1Components: resp.GetComponents(), - }, nil -} - -// Close closes and cleanup the client connection. -func (c *v2Client) Close() error { - if err := c.conn.Close(); err != nil { - return errors.Wrap(err, "closing v2 scanner gRPC connection") - } - return nil -} - func convertIndexReportToAnalysis(ir *v4.IndexReport, indexerVersion string) *ImageAnalysis { var st scannerV1.ScanStatus switch ir.GetState() { diff --git a/sensor/common/scannerclient/singleton.go b/sensor/common/scannerclient/singleton.go index a1851e02c7187..1b38b06b2cd20 100644 --- a/sensor/common/scannerclient/singleton.go +++ b/sensor/common/scannerclient/singleton.go @@ -12,12 +12,14 @@ import ( var ( scannerClient ScannerClient scannerClientMutex sync.Mutex + loggedNoCentralV4 bool isScannerV4Enabled = features.ScannerV4.Enabled() ) // GRPCClientSingleton returns a gRPC ScannerClient to a local Scanner. -// Only one ScannerClient per Sensor is required. +// Only one ScannerClient per Sensor is required. A nil client may +// be returned. func GRPCClientSingleton() ScannerClient { scannerClientMutex.Lock() defer scannerClientMutex.Unlock() @@ -31,14 +33,27 @@ func GRPCClientSingleton() ScannerClient { env.LocalImageScanningEnabled.EnvVar()) return nil } - var err error - if isScannerV4Enabled && centralcaps.Has(centralsensor.ScannerV4Supported) { - log.Info("Creating Scanner V4 client") - scannerClient, err = dialV4() - } else { - log.Info("Creating Scanner V2 client") - scannerClient, err = dialV2() + + // Scanner V4 is the only local scanner Sensor connects to. Using it requires + // both Scanner V4 to be installed locally and Central to advertise support + // for Scanner V4. + // When either is missing there is no local scanner to talk to, so we return a nil + // client. + if !isScannerV4Enabled { + log.Warn("Local image scanning is enabled but Scanner V4 is disabled in Sensor; no local scanner will be used") + return nil } + if !centralcaps.Has(centralsensor.ScannerV4Supported) { + if !loggedNoCentralV4 { + log.Info("Local image scanning is enabled but Central does not support Scanner V4; no local scanner will be used") + loggedNoCentralV4 = true + } + return nil + } + + log.Info("Creating Scanner V4 client") + var err error + scannerClient, err = dialV4() utils.Should(err) return scannerClient @@ -50,6 +65,7 @@ func resetGRPCClient() { scannerClientMutex.Lock() defer scannerClientMutex.Unlock() + loggedNoCentralV4 = false if scannerClient == nil { return } diff --git a/sensor/common/scannerclient/singleton_test.go b/sensor/common/scannerclient/singleton_test.go new file mode 100644 index 0000000000000..cec1350033c66 --- /dev/null +++ b/sensor/common/scannerclient/singleton_test.go @@ -0,0 +1,90 @@ +package scannerclient + +import ( + "strconv" + "testing" + + "github.com/stackrox/rox/pkg/centralsensor" + "github.com/stackrox/rox/pkg/env" + "github.com/stackrox/rox/pkg/logging" + "github.com/stackrox/rox/sensor/common/centralcaps" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +type infoCountingLogger struct { + logging.Logger + infoCalls int +} + +func (l *infoCountingLogger) Info(_ ...interface{}) { + l.infoCalls++ +} + +func TestGRPCClientSingleton(t *testing.T) { + tests := map[string]struct { + localImageScanningEnabled bool + scannerV4Enabled bool + centralCaps []centralsensor.CentralCapability + }{ + "local image scanning disabled": { + localImageScanningEnabled: false, + scannerV4Enabled: true, + centralCaps: []centralsensor.CentralCapability{centralsensor.ScannerV4Supported}, + }, + "scanner v4 disabled in sensor": { + localImageScanningEnabled: true, + scannerV4Enabled: false, + centralCaps: []centralsensor.CentralCapability{centralsensor.ScannerV4Supported}, + }, + "central does not support scanner v4": { + localImageScanningEnabled: true, + scannerV4Enabled: true, + centralCaps: nil, + }, + } + + for name, tt := range tests { + t.Run(name, func(t *testing.T) { + t.Setenv(env.LocalImageScanningEnabled.EnvVar(), strconv.FormatBool(tt.localImageScanningEnabled)) + + origScannerV4Enabled := isScannerV4Enabled + isScannerV4Enabled = tt.scannerV4Enabled + t.Cleanup(func() { isScannerV4Enabled = origScannerV4Enabled }) + + centralcaps.Set(tt.centralCaps) + t.Cleanup(func() { centralcaps.Set(nil) }) + + scannerClient = nil + t.Cleanup(func() { scannerClient = nil }) + + assert.Nil(t, GRPCClientSingleton()) + }) + } +} + +func TestGRPCClientSingletonLogsMissingCentralCapabilityOncePerReset(t *testing.T) { + t.Setenv(env.LocalImageScanningEnabled.EnvVar(), "true") + centralcaps.Set(nil) + t.Cleanup(func() { centralcaps.Set(nil) }) + + origScannerV4Enabled := isScannerV4Enabled + isScannerV4Enabled = true + t.Cleanup(func() { isScannerV4Enabled = origScannerV4Enabled }) + + resetGRPCClient() + t.Cleanup(resetGRPCClient) + + origLog := log + countingLog := &infoCountingLogger{Logger: origLog} + log = countingLog + t.Cleanup(func() { log = origLog }) + + assert.Nil(t, GRPCClientSingleton()) + assert.Nil(t, GRPCClientSingleton()) + require.Equal(t, 1, countingLog.infoCalls) + + resetGRPCClient() // The client is still nil, but the log should be enabled again. + assert.Nil(t, GRPCClientSingleton()) + assert.Equal(t, 2, countingLog.infoCalls) +} diff --git a/sensor/common/virtualmachine/vmscraper/scraper.go b/sensor/common/virtualmachine/vmscraper/scraper.go index 5760d3835a452..b4e5b119af6dd 100644 --- a/sensor/common/virtualmachine/vmscraper/scraper.go +++ b/sensor/common/virtualmachine/vmscraper/scraper.go @@ -118,8 +118,8 @@ type VMScraper struct { warnMaxBytes int stopper concurrency.Stopper started atomic.Bool - // loggedSkip is set after the first skip log for a missing-capability stretch - // so a 10s ticker does not repeat it until the capability returns. + // loggedSkip is set after the first skip log for a feature-disabled stretch + // so a 10s ticker does not repeat it until Central is reachable again. loggedSkip atomic.Bool // indexReportsDisabled is set from a feature-disabled ACK and cleared on // CentralReachable so a later connection can scrape again. @@ -206,7 +206,6 @@ func (s *VMScraper) Notify(e common.SensorComponentEvent) { case common.SensorComponentEventCentralReachable: s.centralReady.Signal() s.indexReportsDisabled.Store(false) - s.loggedSkip.Store(false) case common.SensorComponentEventOfflineMode: s.centralReady.Reset() } @@ -331,17 +330,15 @@ func (s *VMScraper) run() { } func (s *VMScraper) tick(ctx context.Context, forceReconcile bool) { - disabled := s.indexReportsDisabled.Load() - if disabled || !centralcaps.Has(centralsensor.VirtualMachinesSupported) { + if s.indexReportsDisabled.Load() { if s.loggedSkip.CompareAndSwap(false, true) { - if disabled { - log.Infof("VMScraper: skipping pulling index reports from VMs; Central ACKed feature disabled") - } else { - log.Infof("VMScraper: skipping pulling index reports from VMs; Central does not advertise VirtualMachinesSupported") - } + log.Infof("VMScraper: skipping pulling index reports from VMs; Central ACKed feature disabled") } return } + if !centralcaps.Has(centralsensor.VirtualMachinesSupported) { + return + } s.loggedSkip.Store(false) tickStart := s.now() @@ -412,12 +409,15 @@ func (s *VMScraper) reconcile() { liveKeys.Add(key) st, ok := s.vmState[key] if !ok { + nextAt := now.Add(randOffset(newVMWindow, s.randFloat64())) st = &vmState{ - nextAttemptAt: now.Add(randOffset(newVMWindow, s.randFloat64())), + nextAttemptAt: nextAt, vmID: vm.ID, mappingPath: metrics.MappingPathUnspecified, } s.vmState[key] = st + log.Infof("VMScraper: queued %q for first index pull in %s (spread window %s)", + key, nextAt.Sub(now), newVMWindow) } else if st.vmID != vm.ID { // namespace/name can outlive a KubeVirt recreate; do not inherit scrape state. st = &vmState{ @@ -426,6 +426,7 @@ func (s *VMScraper) reconcile() { mappingPath: metrics.MappingPathUnspecified, } s.vmState[key] = st + log.Infof("VMScraper: re-queued %q for index pull (VM identity changed)", key) } } for key := range s.vmState { diff --git a/sensor/common/virtualmachine/vmscraper/scraper_test.go b/sensor/common/virtualmachine/vmscraper/scraper_test.go index f5f3aa6955a1e..e2460edbba2ca 100644 --- a/sensor/common/virtualmachine/vmscraper/scraper_test.go +++ b/sensor/common/virtualmachine/vmscraper/scraper_test.go @@ -434,10 +434,9 @@ func TestVMScraper_SkipsWhenCentralLacksCapability(t *testing.T) { assert.Empty(t, client.calls) } -// TestVMScraper_LogsSkipOnceWhileCapabilityMissing covers a missing-capability -// stretch that lasts more than one tick, then a later drop after the -// capability returns, so the skip log fires once per stretch not once per tick. -func TestVMScraper_LogsSkipOnceWhileCapabilityMissing(t *testing.T) { +// TestVMScraper_SilentWhileCapabilityMissing covers a missing-capability +// stretch: ticks do not Info-log Central's missing cap, and they do not dial. +func TestVMScraper_SilentWhileCapabilityMissing(t *testing.T) { core, logs := observer.New(zap.InfoLevel) orig := log log = &logging.LoggerImpl{InnerLogger: zap.New(core).Sugar()} @@ -452,14 +451,13 @@ func TestVMScraper_LogsSkipOnceWhileCapabilityMissing(t *testing.T) { s.pollOnce(t.Context()) s.pollOnce(t.Context()) - assert.Equal(t, 1, logs.FilterMessageSnippet("skipping pull").Len()) + assert.Equal(t, 0, logs.FilterMessageSnippet("skipping pull").Len()) + assert.Zero(t, forwardedCount(s)) centralcaps.Set([]centralsensor.CentralCapability{centralsensor.VirtualMachinesSupported}) s.pollOnce(t.Context()) - - centralcaps.Set(nil) - s.pollOnce(t.Context()) - assert.Equal(t, 2, logs.FilterMessageSnippet("skipping pull").Len()) + assert.Equal(t, 0, logs.FilterMessageSnippet("will pull index reports").Len()) + assert.Equal(t, 1, forwardedCount(s)) } func TestVMScraper_SkipsUnchangedToken(t *testing.T) { diff --git a/sensor/kubernetes/clusterhealth/updater.go b/sensor/kubernetes/clusterhealth/updater.go index 3b206f7f82869..c902553822d82 100644 --- a/sensor/kubernetes/clusterhealth/updater.go +++ b/sensor/kubernetes/clusterhealth/updater.go @@ -33,9 +33,6 @@ const ( admissionControlDeploymentName = "admission-control" admissionControlContainerName = "admission-control" - localScannerDeploymentName = "scanner" - localScannerDBDeploymentName = "scanner-db" - localScannerV4IndexerDeploymentName = "scanner-v4-indexer" localScannerV4DBDeploymentName = "scanner-v4-db" ) @@ -205,19 +202,29 @@ func (u *updaterImpl) getLocalScannerInfo() *storage.ScannerHealthInfo { return nil } - // It's possible that both Scanner and Scanner V4 are installed in the secured cluster - // at the same time, but only one will be used by Sensor at any given time, therefore - // only report the health of the active scanner. - scannerV4Active := features.ScannerV4.Enabled() && centralcaps.Has(centralsensor.ScannerV4Supported) - - analyzerDeploymentName := localScannerDeploymentName - dbDeploymentName := localScannerDBDeploymentName - if scannerV4Active { - analyzerDeploymentName = localScannerV4IndexerDeploymentName - dbDeploymentName = localScannerV4DBDeploymentName + // Local image scanning requires Scanner V4; Scanner V2 is no longer supported. + // When Scanner V4 is not active, local scanning cannot function. Pod state is irrelevant + // in these cases. The two failure modes are reported distinctly: + // - Scanner V4 is not enabled on this secured cluster, or + // - Scanner V4 is enabled but Central does not advertise Scanner V4 support. + if !features.ScannerV4.Enabled() { + return &storage.ScannerHealthInfo{ + StatusErrors: []string{ + "local image scanning is enabled but Scanner V4 is not enabled in secured cluster; local image " + + "scanning requires Scanner V4", + }, + } + } + if !centralcaps.Has(centralsensor.ScannerV4Supported) { + return &storage.ScannerHealthInfo{ + StatusErrors: []string{ + "local image scanning and Scanner V4 are enabled in secured cluster, but Central is not reporting " + + "support for Scanner V4; enable Scanner V4 in Central to enable local image scanning", + }, + } } - result := u.getScannerHealthInfo(analyzerDeploymentName, dbDeploymentName) + result := u.getScannerHealthInfo(localScannerV4IndexerDeploymentName, localScannerV4DBDeploymentName) if len(result.GetStatusErrors()) > 0 { log.Errorf("Errors while getting local scanner info: %v", result.GetStatusErrors()) } diff --git a/sensor/kubernetes/clusterhealth/updater_test.go b/sensor/kubernetes/clusterhealth/updater_test.go index ff1c9e8d2f0b2..7f2ea8ea312fa 100644 --- a/sensor/kubernetes/clusterhealth/updater_test.go +++ b/sensor/kubernetes/clusterhealth/updater_test.go @@ -9,8 +9,11 @@ import ( "github.com/stackrox/rox/generated/internalapi/central" "github.com/stackrox/rox/generated/storage" + "github.com/stackrox/rox/pkg/centralsensor" + "github.com/stackrox/rox/pkg/features" "github.com/stackrox/rox/pkg/namespaces" "github.com/stackrox/rox/sensor/common" + "github.com/stackrox/rox/sensor/common/centralcaps" "github.com/stackrox/rox/sensor/common/message" "github.com/stretchr/testify/suite" appsV1 "k8s.io/api/apps/v1" @@ -290,6 +293,81 @@ func (s *UpdaterTestSuite) TestExpiredMessage() { } } +func (s *UpdaterTestSuite) TestLocalScannerDisabled() { + s.T().Setenv("ROX_LOCAL_IMAGE_SCANNING_ENABLED", "false") + + updater := s.createNewUpdater(updateInterval) + s.Nil(updater.getLocalScannerInfo(), "no scanner health info should be reported when local scanning is disabled") +} + +func (s *UpdaterTestSuite) TestLocalScannerV4NotSupportedByCentral() { + s.T().Setenv("ROX_LOCAL_IMAGE_SCANNING_ENABLED", "true") + s.T().Setenv(features.ScannerV4.EnvVar(), "true") + s.setCentralCaps() // Central does not advertise ScannerV4Supported. + + updater := s.createNewUpdater(updateInterval) + info := updater.getLocalScannerInfo() + + s.Require().NotNil(info) + // Pod counts must not be reported: the failure is a misconfiguration, not pod state. + s.Nil(info.GetTotalDesiredAnalyzerPodsOpt()) + s.Nil(info.GetTotalReadyAnalyzerPodsOpt()) + s.Require().Len(info.GetStatusErrors(), 1) + s.Contains(info.GetStatusErrors()[0], "Central is not reporting support for Scanner V4") +} + +func (s *UpdaterTestSuite) TestLocalScannerV4FeatureDisabled() { + s.T().Setenv("ROX_LOCAL_IMAGE_SCANNING_ENABLED", "true") + s.T().Setenv(features.ScannerV4.EnvVar(), "false") + s.setCentralCaps(centralsensor.ScannerV4Supported) + + updater := s.createNewUpdater(updateInterval) + info := updater.getLocalScannerInfo() + + s.Require().NotNil(info) + s.Nil(info.GetTotalDesiredAnalyzerPodsOpt()) + s.Require().Len(info.GetStatusErrors(), 1) + s.Contains(info.GetStatusErrors()[0], "Scanner V4 is not enabled") + // This case is distinct from Central lacking Scanner V4 support. + s.NotContains(info.GetStatusErrors()[0], "Central") +} + +func (s *UpdaterTestSuite) TestLocalScannerV4Healthy() { + s.T().Setenv("ROX_LOCAL_IMAGE_SCANNING_ENABLED", "true") + s.T().Setenv(features.ScannerV4.EnvVar(), "true") + s.setCentralCaps(centralsensor.ScannerV4Supported) + s.addDeployment(makeScannerDeployment("scanner-v4-indexer", 3, 3)) + s.addDeployment(makeScannerDeployment("scanner-v4-db", 1, 1)) + + updater := s.createNewUpdater(updateInterval) + info := updater.getLocalScannerInfo() + + s.Require().NotNil(info) + s.Empty(info.GetStatusErrors()) + s.Equal(int32(3), info.GetTotalDesiredAnalyzerPods()) + s.Equal(int32(3), info.GetTotalReadyAnalyzerPods()) + s.Equal(int32(1), info.GetTotalDesiredDbPods()) + s.Equal(int32(1), info.GetTotalReadyDbPods()) +} + +func (s *UpdaterTestSuite) setCentralCaps(caps ...centralsensor.CentralCapability) { + centralcaps.Set(caps) + s.T().Cleanup(func() { centralcaps.Set(nil) }) +} + +func makeScannerDeployment(name string, replicas, ready int32) appsV1.Deployment { + return appsV1.Deployment{ + ObjectMeta: metaV1.ObjectMeta{ + Name: name, + Namespace: "stackrox-mock-ns", + }, + Status: appsV1.DeploymentStatus{ + Replicas: replicas, + ReadyReplicas: ready, + }, + } +} + func (s *UpdaterTestSuite) createNewUpdater(interval time.Duration) *updaterImpl { updaterComponent := NewUpdater(s.client, interval) updater, ok := updaterComponent.(*updaterImpl) diff --git a/sensor/kubernetes/fake/virtualmachines.go b/sensor/kubernetes/fake/virtualmachines.go index d5ceb5cd40f5d..07139406828dc 100644 --- a/sensor/kubernetes/fake/virtualmachines.go +++ b/sensor/kubernetes/fake/virtualmachines.go @@ -167,15 +167,18 @@ func toUnstructuredVM(vm *kubeVirtV1.VirtualMachine) *unstructured.Unstructured return &unstructured.Unstructured{Object: unstructuredObj} } -// toUnstructuredVMI converts a VirtualMachineInstance to unstructured.Unstructured +// toUnstructuredVMI converts a VirtualMachineInstance to unstructured.Unstructured. func toUnstructuredVMI(vmi *kubeVirtV1.VirtualMachineInstance) *unstructured.Unstructured { - unstructuredObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(vmi) + // A uint64 above MaxInt64 makes unstructured conversion fail the whole object. + sanitized := *vmi + sanitized.Status.RuntimeUser = uint64(jsonSafeUint64(sanitized.Status.RuntimeUser)) + unstructuredObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&sanitized) if err != nil { - log.Warnf("failed to convert VMI %s to unstructured object: %v", vmi.GetName(), err) + log.Warnf("failed to convert VMI %s to unstructured object: %v", sanitized.GetName(), err) return &unstructured.Unstructured{Object: map[string]interface{}{}} } obj := &unstructured.Unstructured{Object: unstructuredObj} - normalizeVMIUnsignedFields(obj, vmi.Status) + normalizeVMIUnsignedFields(obj, sanitized.Status) return obj } diff --git a/sensor/kubernetes/listener/resources/convert.go b/sensor/kubernetes/listener/resources/convert.go index 79650f98be89c..7329c81b51fb4 100644 --- a/sensor/kubernetes/listener/resources/convert.go +++ b/sensor/kubernetes/listener/resources/convert.go @@ -476,14 +476,14 @@ func (w *deploymentWrap) getLabelSelector(spec reflect.Value) (*metav1.LabelSele } // Selector is of map type for replication controller - if labelMap, ok := s.Interface().(map[string]string); ok { + if labelMap, ok := reflect.TypeAssert[map[string]string](s); ok { return &metav1.LabelSelector{ MatchLabels: labelMap, }, nil } // All other resources uses labelSelector. - if ls, ok := s.Interface().(*metav1.LabelSelector); ok { + if ls, ok := reflect.TypeAssert[*metav1.LabelSelector](s); ok { return ls, nil } diff --git a/sensor/kubernetes/listener/resources/route.go b/sensor/kubernetes/listener/resources/route.go index d9bf38affd1a7..54c6375d36085 100644 --- a/sensor/kubernetes/listener/resources/route.go +++ b/sensor/kubernetes/listener/resources/route.go @@ -30,7 +30,7 @@ func (r *routeDispatcher) ProcessEvent(obj, _ interface{}, action central.Resour return nil } - if action == central.ResourceAction_CREATE_RESOURCE || action == central.ResourceAction_UPDATE_RESOURCE { + if action == central.ResourceAction_CREATE_RESOURCE || action == central.ResourceAction_UPDATE_RESOURCE || action == central.ResourceAction_SYNC_RESOURCE { r.serviceStore.upsertRoute(route) } if action == central.ResourceAction_REMOVE_RESOURCE { diff --git a/sensor/upgrader/common/bundle_resources_completeness_test.go b/sensor/upgrader/common/bundle_resources_completeness_test.go index 91061a51bcdfe..065bc075d33d6 100644 --- a/sensor/upgrader/common/bundle_resources_completeness_test.go +++ b/sensor/upgrader/common/bundle_resources_completeness_test.go @@ -46,18 +46,15 @@ func TestBundleResourcesComplete(t *testing.T) { MainVersion: "3.0.49.0", CollectorVersion: "1.2.3", }, - MainRegistry: "stackrox.io", // TODO: custom? - ImageRemote: "main", - ImageTag: "3.0.49.0", - CollectorRegistry: "collector.stackrox.io", - CollectorImageRemote: "collector", - CollectorImageTag: "1.2.3", - FactRegistry: "fact.stackrox.io", - FactImageRemote: "fact", - FactImageTag: "0.1.0", - ScannerImageRemote: "scanner", - ScannerSlimImageRemote: "scanner", - ScannerImageTag: "1.2.3", + MainRegistry: "stackrox.io", // TODO: custom? + ImageRemote: "main", + ImageTag: "3.0.49.0", + CollectorRegistry: "collector.stackrox.io", + CollectorImageRemote: "collector", + CollectorImageTag: "1.2.3", + FactRegistry: "fact.stackrox.io", + FactImageRemote: "fact", + FactImageTag: "0.1.0", ChartRepo: defaults.ChartRepo{ URL: "http://mirror.openshift.com/pub/rhacs/charts", IconURL: "https://raw.githubusercontent.com/stackrox/stackrox/master/image/templates/helm/shared/assets/Red_Hat-Hat_icon.png", diff --git a/status.sh b/status.sh index 86abea6859457..5aed6d6bad31a 100755 --- a/status.sh +++ b/status.sh @@ -4,6 +4,5 @@ echo "STABLE_MAIN_VERSION $(make --quiet --no-print-directory tag)" echo "STABLE_COLLECTOR_VERSION $(make --quiet --no-print-directory collector-tag)" echo "STABLE_FACT_VERSION $(make --quiet --no-print-directory fact-tag)" -echo "STABLE_SCANNER_VERSION $(make --quiet --no-print-directory scanner-tag)" echo "STABLE_SCANNER_V4_VULNERABILITY_VERSION $(cat scanner/VULNERABILITY_VERSION)" echo "STABLE_GIT_SHORT_SHA $(make --quiet --no-print-directory shortcommit)" diff --git a/tests/byodb/lib.sh b/tests/byodb/lib.sh index 55fe4e0d82f90..38ebe7f5e7ed9 100644 --- a/tests/byodb/lib.sh +++ b/tests/byodb/lib.sh @@ -19,7 +19,8 @@ deploy_external_postgres() { kubectl create namespace database envsubst < ./tests/byodb/simple-postgres.yaml | kubectl apply -f - - kubectl wait --for=condition=Ready pod -l app=postgres -n database --timeout=180s + # The StatefulSet exists, but its pod may not have been created yet. + kubectl rollout status statefulset/postgres -n database --timeout=180s } preamble() { diff --git a/tests/cli_download_test.go b/tests/cli_download_test.go new file mode 100644 index 0000000000000..5f9510c9d73ff --- /dev/null +++ b/tests/cli_download_test.go @@ -0,0 +1,153 @@ +//go:build test_e2e + +package tests + +import ( + "bytes" + "context" + "encoding/json" + "io" + "net/http" + "strings" + "testing" + "time" + + "github.com/stackrox/rox/pkg/testutils/centralgrpc" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// fetchIsReleaseBuild calls /v1/metadata and returns whether Central was built as a release build. +func fetchIsReleaseBuild(t *testing.T) bool { + t.Helper() + client := centralgrpc.HTTPClientForCentral(t) + + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, "/v1/metadata", nil) + require.NoError(t, err) + + resp, err := client.Do(req) + require.NoError(t, err) + t.Cleanup(func() { assert.NoError(t, resp.Body.Close()) }) + require.Equal(t, http.StatusOK, resp.StatusCode) + + var metadata struct { + ReleaseBuild bool `json:"release_build"` + } + require.NoError(t, json.NewDecoder(resp.Body).Decode(&metadata)) + return metadata.ReleaseBuild +} + +func TestCLIDownload(t *testing.T) { + t.Run("all platform binaries are downloadable", func(t *testing.T) { + type binaryCase struct { + filename string + magic []byte + } + + const ( + // Magic byte sequences that identify each platform's binary format. + linuxMagic = "\x7fELF" + darwinMagic = "\xcf\xfa\xed\xfe" + windowsMagic = "MZ" + + // stubPrefix is the known prefix of CI stub files created by + // .github/workflows/build.yaml in "Create CLI stub files" step + // for non-native-arch binaries in non-release builds. + stubPrefix = "This is a placeholder" + + // headerBytes must cover the longest magic sequence (4 bytes) and the stub prefix (21 bytes). + headerBytes = max(len(linuxMagic), len(darwinMagic), len(windowsMagic), len(stubPrefix)) + ) + + testCases := []binaryCase{ + {"roxctl-linux-amd64", []byte(linuxMagic)}, + {"roxctl-linux-arm64", []byte(linuxMagic)}, + {"roxctl-linux-ppc64le", []byte(linuxMagic)}, + {"roxctl-linux-s390x", []byte(linuxMagic)}, + {"roxctl-darwin-amd64", []byte(darwinMagic)}, + {"roxctl-darwin-arm64", []byte(darwinMagic)}, + {"roxctl-windows-amd64.exe", []byte(windowsMagic)}, + } + + releaseBuild := fetchIsReleaseBuild(t) + + for _, tc := range testCases { + t.Run(tc.filename, func(t *testing.T) { + client := centralgrpc.HTTPClientForCentral(t) + client.Timeout = 2 * time.Minute + + ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute) + defer cancel() + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, + "/api/cli/download/"+tc.filename, nil) + require.NoError(t, err) + + resp, err := client.Do(req) + require.NoError(t, err) + t.Cleanup(func() { assert.NoError(t, resp.Body.Close()) }) + + require.Equal(t, http.StatusOK, resp.StatusCode) + + header := make([]byte, headerBytes) + _, err = io.ReadFull(resp.Body, header) + require.NoError(t, err) + + hasMagic := bytes.Equal(header[:len(tc.magic)], tc.magic) + + if releaseBuild || tc.filename == "roxctl-linux-amd64" { + // Release build contains real binaries for all platforms. + // In PR CI builds, linux-amd64 is the native runner arch and thus always real. + assert.True(t, hasMagic, "%s: expected binary magic bytes %x, got: %q", + tc.filename, tc.magic, header) + } else if !hasMagic { + // Non-release builds may serve CI stub files for non-native arches. + // Anything other than real binary or known stub is unexpected. + assert.True(t, strings.HasPrefix(string(header), stubPrefix), + "%s: expected binary magic bytes or CI stub content, got: %q", tc.filename, header) + } + + _, err = io.Copy(io.Discard, resp.Body) + require.NoError(t, err) + }) + } + }) + + t.Run("nonexistent binary returns 404", func(t *testing.T) { + client := centralgrpc.HTTPClientForCentral(t) + + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, + "/api/cli/download/roxctl-nonexistent", nil) + require.NoError(t, err) + + resp, err := client.Do(req) + require.NoError(t, err) + t.Cleanup(func() { assert.NoError(t, resp.Body.Close()) }) + + assert.Equal(t, http.StatusNotFound, resp.StatusCode) + }) + + t.Run("unauthenticated returns 401", func(t *testing.T) { + unauthClient := centralgrpc.UnauthenticatedHTTPClientForCentral(t) + unauthClient.Timeout = 30 * time.Second + + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, + "/api/cli/download/roxctl-linux-amd64", nil) + require.NoError(t, err) + + resp, err := unauthClient.Do(req) + require.NoError(t, err) + t.Cleanup(func() { assert.NoError(t, resp.Body.Close()) }) + + assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) + }) +} diff --git a/tests/cluster_delete_test.go b/tests/cluster_delete_test.go index 10ea65ad63a29..149e04acce00c 100644 --- a/tests/cluster_delete_test.go +++ b/tests/cluster_delete_test.go @@ -32,6 +32,14 @@ func (a *allCounts) AllZero() bool { return allIntsZero(a.PodCount, a.ClusterCount, a.NodeCount, a.DeploymentCount, a.SecretCount) } +func (a *allCounts) Less(other *allCounts) bool { + return a.PodCount < other.PodCount || + a.ClusterCount < other.ClusterCount || + a.NodeCount < other.NodeCount || + a.DeploymentCount < other.DeploymentCount || + a.SecretCount < other.SecretCount +} + type summaryCountsResp struct { ClusterCount, NodeCount, ViolationCount, DeploymentCount, SecretCount int } @@ -105,7 +113,7 @@ func TestClusterDeletion(t *testing.T) { t.Logf("deployment count is still not zero: %d", counts.DeploymentCount) } - if previous.DeploymentCount > 0 && previous.DeploymentCount > counts.DeploymentCount { + if counts.Less(&previous) { noChangeCount = 0 } else { noChangeCount++ diff --git a/tests/common.go b/tests/common.go index 54565e09ea603..945cc36266b0e 100644 --- a/tests/common.go +++ b/tests/common.go @@ -1443,6 +1443,11 @@ func isOpenshift() bool { return os.Getenv("ORCHESTRATOR_FLAVOR") == "openshift" } +// usingKonfluxImages returns true when StackRox was deployed from Konflux-built images. +func usingKonfluxImages() bool { + return os.Getenv("USE_KONFLUX_IMAGES") == "true" +} + // mustGetCluster returns the details of the one and only known secured cluster. func mustGetCluster(t *testing.T, ctx context.Context) *storage.Cluster { conn := centralgrpc.GRPCConnectionToCentral(t) diff --git a/tests/delegated_scanning_test.go b/tests/delegated_scanning_test.go index 8e014122ff79d..8b932e00991e2 100644 --- a/tests/delegated_scanning_test.go +++ b/tests/delegated_scanning_test.go @@ -124,8 +124,8 @@ var ( // delegation, the scan attempt should be retried. // // ex: - // - no connection to "a21b168a-280e-40d1-a175-e84d14ed8232" - "no connection to", + // - no connection to cluster "remote", verify the cluster is healthy and connected + "no connection to cluster", // A registry having gateway issues (Quay.io in particular) may return a 502 (Bad Gateway) // or 504 (Gateway Timeout) along with some HTML, retry when this happens. diff --git a/tests/e2e/lib-compat.sh b/tests/e2e/lib-compat.sh index a61a322db363c..396d78b901c77 100644 --- a/tests/e2e/lib-compat.sh +++ b/tests/e2e/lib-compat.sh @@ -85,6 +85,9 @@ roxie_config_from_environment_compat() { handle_pod_security_policies + info "Configuring Konflux images..." + handle_konflux_images "$config_file" + info "Configuring TRUSTED_CA_FILE..." handle_trusted_ca_file "$config_file" @@ -94,6 +97,13 @@ roxie_config_from_environment_compat() { info "Configuring load balancer..." handle_load_balancer_setting "$config_file" + handle_endpoints_for_test "$config_file" # Echoes info internally. + + if [[ -n "${EXTERNAL_DB:-}" ]]; then + info "Configuring external database..." + handle_external_database_settings "$config_file" "$namespace" + fi + info "Configuring custom central environment..." while read -r var_val; do local name="${var_val%%=*}" @@ -153,6 +163,10 @@ roxie_config_from_environment_compat() { env_with_default ROX_NETFLOW_BATCHING "true" # pkg/env/sensor.go. env_with_default ROX_NETFLOW_CACHE_LIMITING "true" # pkg/env/sensor.go. + # Scan every 9-11 minutes in roxie-deployed QA tests, including GHA. + env_with_default ROX_NODE_SCANNING_INTERVAL "10m" + env_with_default ROX_NODE_SCANNING_INTERVAL_DEVIATION "60s" + collect_feature_flags ) @@ -176,10 +190,18 @@ roxie_config_from_environment_compat() { fi ) + info "Configuring storage classes..." + handle_storage_classes "$config_file" + info "Configuring scanner V4..." - handle_scanner_v4_setting "$config_file" ".central.spec.scannerV4.scannerComponent" "Enabled" - handle_scanner_v4_setting "$config_file" ".securedCluster.spec.scannerV4.scannerComponent" "AutoSense" - handle_scanner_v4_vuln_readiness "$config_file" + if [[ ${ROX_SCANNER_V4:-} == false ]]; then + handle_scanner_v4_setting "$config_file" ".central.spec.scannerV4.scannerComponent" "Disabled" + handle_scanner_v4_setting "$config_file" ".securedCluster.spec.scannerV4.scannerComponent" "Disabled" + else + handle_scanner_v4_setting "$config_file" ".central.spec.scannerV4.scannerComponent" "Enabled" + handle_scanner_v4_setting "$config_file" ".securedCluster.spec.scannerV4.scannerComponent" "AutoSense" + handle_scanner_v4_vuln_readiness "$config_file" + fi info "Configuring declarative configuration..." handle_declarative_configuration "$config_file" @@ -191,6 +213,32 @@ roxie_config_from_environment_compat() { handle_virtual_machines_configuration "$config_file" } +handle_external_database_settings() { + local config_file="$1" + local namespace="$2" + + merge_yaml "$config_file" < "$overlay_tmp" <<'OVERLAY' +central: + spec: + overlays: + - apiVersion: v1 + kind: ConfigMap + name: central-endpoints + patches: + - path: data.endpoints\.yaml + verbatim: | +OVERLAY + sed 's/^/ /' "${ROXDEPLOY_CONFIG_FILE_MAP}" >> "$overlay_tmp" + merge_yaml "$config_file" < "$overlay_tmp" + rm -f "$overlay_tmp" + fi +} + handle_declarative_configuration() { local config_file="$1" merge_yaml "$config_file" <_/roxie and put it +# ahead of any pre-installed roxie on PATH. +ensure_roxie_on_path() { + local os arch + case "$(uname -s)" in + Linux*) os="linux" ;; + Darwin*) os="darwin" ;; + *) die "Unsupported operating system: $(uname -s)" ;; + esac + case "$(uname -m)" in + x86_64) arch="amd64" ;; + arm64|aarch64) arch="arm64" ;; + *) die "Unsupported architecture: $(uname -m)" ;; + esac + + # Triggers the download/install of the pinned roxie version if it is not present yet. + "$ROOT/scripts/roxie.sh" version + + # Put ONLY roxie at the front of PATH, via a dedicated directory. We must not prepend + # "$ROOT/bin/${os}_${arch}" directly: it also contains roxctl, which the bats tests move out + # of that directory mid-run, after which bare `roxctl` would resolve to the now-missing path + # (instead of the stable /usr/local/bin/roxctl copy) and later phases (e.g. proxy tests) fail. + local roxie_bindir; roxie_bindir="$(mktemp -d)" + ln -sf "$ROOT/bin/${os}_${arch}/roxie" "${roxie_bindir}/roxie" + export PATH="${roxie_bindir}:$PATH" + + check_for_roxie +} + # Deploy StackRox using roxie. # # This is the preferred way of deploying StackRox for tests as of 2026Q2. @@ -125,8 +157,6 @@ deploy_stackrox_with_roxie() { ROX_ADMIN_PASSWORD="$(gen_admin_password)" export ROX_ADMIN_PASSWORD # Let roxie pick it up automatically. - prepare_for_konflux "$config_file" - workaround_label_length_limitation "$config_file" # Print out the config file in use for transparency. @@ -146,9 +176,9 @@ deploy_stackrox_with_roxie() { local roxie_envrc; roxie_envrc="$(mktemp)" # Note, we use early-readiness=false here so that roxie waits until all workloads are ready. - # For Scanner V2 this means that it will also wait until vulnerabilities are loaded into the DB. + # For Scanner V4 this means that it will also wait until vulnerabilities are loaded into the DB. roxie deploy \ - --early-readiness=false --central-wait=40m --secured-cluster-wait=40m \ + --early-readiness=false --central-wait=2h --secured-cluster-wait=2h \ --envrc "$roxie_envrc" \ --config "$config_file" @@ -180,35 +210,6 @@ deploy_stackrox_with_roxie() { info "╚═════════════════════╝" } -prepare_for_konflux() { - local config_file="$1" - local use_konflux - use_konflux=$(yq eval ".roxie.konfluxImages" "$config_file") - local main_image_tag - main_image_tag=$(yq eval ".roxie.version" "$config_file") - if [[ "$use_konflux" == "true" ]]; then - # We need to be able to pull operator bundle images. - registry_ro_login "quay.io/rhacs-eng" - - info "Checking if ACS main image tag needs to be patched for Konflux usage: current tag is ${main_image_tag}" - if is_CI; then - # get_branch_name() may only be called in CI context. - local branch_name - branch_name="$(get_branch_name)" - if [[ "$branch_name" =~ ^release- ]]; then - info "On release branch (${branch_name}), skipping main image tag patching for Konflux usage" - return - fi - fi - info "Patching main image tag for Konflux usage: using ${main_image_tag}" - if [[ "$main_image_tag" != *-fast ]]; then - main_image_tag="${main_image_tag}-fast" - patch_yaml "$config_file" ".roxie.version = \"${main_image_tag}\"" - info "Main image tag patched for Konflux usage: ${main_image_tag}" - fi - fi -} - # When deploying Konflux-built images, we might get an additional "-fast" suffix on the main image version, # which can easily cause the Helm chart labels to exceed the 63 character limit. To work around this, we # use shorter labels for the the roxie-deployed resources. @@ -297,36 +298,18 @@ securedCluster: clusterName: remote EOF - # Expose plaintext endpoints required by endpoints_test.go. - set_custom_env "$config_file" "central" "ROX_PLAINTEXT_ENDPOINTS" "8080,grpc@8081" + # Scan every 9-11 minutes during compatibility tests. + set_custom_env "$config_file" "securedCluster" "ROX_NODE_SCANNING_INTERVAL" "10m" + set_custom_env "$config_file" "securedCluster" "ROX_NODE_SCANNING_INTERVAL_DEVIATION" "60s" + + # Configure the endpoints required by endpoints_test.go. + handle_endpoints_for_test "$config_file" # Speed up baseline generation so TestPod can observe process events within the test window. # The default is 1h; tests time out long before baselines would be generated. set_custom_env "$config_file" "central" "ROX_BASELINE_GENERATION_DURATION" "1m" set_custom_env "$config_file" "central" "ROX_NETWORK_BASELINE_OBSERVATION_PERIOD" "2m" - # Inject the full endpoint config into the central-endpoints ConfigMap so that - # Central also listens on ports 8082 and 8444-8448 (used by endpoints_test.go). - if [[ -n "${ROXDEPLOY_CONFIG_FILE_MAP:-}" && -f "${ROXDEPLOY_CONFIG_FILE_MAP}" ]]; then - local overlay_tmp; overlay_tmp="$(mktemp)" - # \. in the path escapes the dot so the operator treats "endpoints.yaml" as a - # single ConfigMap key rather than a path separator. verbatim preserves newlines. - cat > "$overlay_tmp" <<'OVERLAY' -central: - spec: - overlays: - - apiVersion: v1 - kind: ConfigMap - name: central-endpoints - patches: - - path: data.endpoints\.yaml - verbatim: | -OVERLAY - sed 's/^/ /' "${ROXDEPLOY_CONFIG_FILE_MAP}" >> "$overlay_tmp" - merge_yaml "$config_file" < "$overlay_tmp" - rm -f "$overlay_tmp" - fi - # Add the test CA so Central accepts client-cert auth during endpoints_test.go. if [[ -n "${TRUSTED_CA_FILE:-}" && -f "${TRUSTED_CA_FILE}" ]]; then local trusted_ca_content @@ -418,6 +401,8 @@ export_test_environment() { ci_export ROX_COMPLIANCE_ENHANCEMENTS "${ROX_COMPLIANCE_ENHANCEMENTS:-true}" ci_export ROX_TELEMETRY_STORAGE_KEY_V1 "DISABLED" ci_export ROX_COMPLIANCE_REPORTING "${ROX_COMPLIANCE_REPORTING:-true}" + ci_export ROX_COMPLIANCE_SURFACE_STALE_DATA "${ROX_COMPLIANCE_SURFACE_STALE_DATA:-true}" + ci_export ROX_COMPLIANCE_CUSTOM_NODE_ROLES "${ROX_COMPLIANCE_CUSTOM_NODE_ROLES:-true}" ci_export ROX_REGISTRY_RESPONSE_TIMEOUT "${ROX_REGISTRY_RESPONSE_TIMEOUT:-90s}" ci_export ROX_REGISTRY_CLIENT_TIMEOUT "${ROX_REGISTRY_CLIENT_TIMEOUT:-120s}" ci_export ROX_SCAN_SCHEDULE_REPORT_JOBS "${ROX_SCAN_SCHEDULE_REPORT_JOBS:-true}" @@ -430,7 +415,6 @@ export_test_environment() { ci_export ROX_CUSTOMIZABLE_PLATFORM_COMPONENTS "${ROX_CUSTOMIZABLE_PLATFORM_COMPONENTS:-true}" ci_export ROX_ADMISSION_CONTROLLER_CONFIG "${ROX_ADMISSION_CONTROLLER_CONFIG:-true}" ci_export ROX_CISA_KEV "${ROX_CISA_KEV:-true}" - ci_export ROX_DEPRECATED_COMPLIANCE_DASHBOARD "${ROX_DEPRECATED_COMPLIANCE_DASHBOARD:-true}" ci_export ROX_SENSITIVE_FILE_ACTIVITY "${ROX_SENSITIVE_FILE_ACTIVITY:-true}" ci_export ROX_CVE_FIX_TIMESTAMP "${ROX_CVE_FIX_TIMESTAMP:-true}" ci_export ROX_BASE_IMAGE_DETECTION "${ROX_BASE_IMAGE_DETECTION:-true}" @@ -440,6 +424,7 @@ export_test_environment() { ci_export ROX_NETFLOW_BATCHING "${ROX_NETFLOW_BATCHING:-true}" ci_export ROX_NETFLOW_CACHE_LIMITING "${ROX_NETFLOW_CACHE_LIMITING:-true}" ci_export ROX_INIT_CONTAINER_SUPPORT "${ROX_INIT_CONTAINER_SUPPORT:-true}" + ci_export ROX_POLICY_WORKLOAD_KIND_EXCLUSION "${ROX_POLICY_WORKLOAD_KIND_EXCLUSION:-true}" ci_export ROX_VIRTUAL_MACHINES_ENHANCED_DATA_MODEL "${ROX_VIRTUAL_MACHINES_ENHANCED_DATA_MODEL:-true}" ci_export ROX_UI_SECRETS_PAGE_MIGRATION "${ROX_UI_SECRETS_PAGE_MIGRATION:-true}" ci_export ROX_AI_INTEGRATIONS "${ROX_AI_INTEGRATIONS:-true}" @@ -578,6 +563,10 @@ deploy_central_via_operator() { customize_envVars+=$'\n value: "true"' customize_envVars+=$'\n - name: ROX_COMPLIANCE_REPORTING' customize_envVars+=$'\n value: "true"' + customize_envVars+=$'\n - name: ROX_COMPLIANCE_SURFACE_STALE_DATA' + customize_envVars+=$'\n value: "true"' + customize_envVars+=$'\n - name: ROX_COMPLIANCE_CUSTOM_NODE_ROLES' + customize_envVars+=$'\n value: "true"' customize_envVars+=$'\n - name: ROX_REGISTRY_RESPONSE_TIMEOUT' customize_envVars+=$'\n value: '"${ROX_REGISTRY_RESPONSE_TIMEOUT:-90s}" customize_envVars+=$'\n - name: ROX_REGISTRY_CLIENT_TIMEOUT' @@ -604,8 +593,6 @@ deploy_central_via_operator() { customize_envVars+=$'\n value: "true"' customize_envVars+=$'\n - name: ROX_CISA_KEV' customize_envVars+=$'\n value: "true"' - customize_envVars+=$'\n - name: ROX_DEPRECATED_COMPLIANCE_DASHBOARD' - customize_envVars+=$'\n value: "true"' customize_envVars+=$'\n - name: ROX_SENSITIVE_FILE_ACTIVITY' customize_envVars+=$'\n value: "'"${ROX_SENSITIVE_FILE_ACTIVITY}"'"' customize_envVars+=$'\n - name: ROX_CVE_FIX_TIMESTAMP' @@ -620,6 +607,8 @@ deploy_central_via_operator() { customize_envVars+=$'\n value: "true"' customize_envVars+=$'\n - name: ROX_INIT_CONTAINER_SUPPORT' customize_envVars+=$'\n value: "true"' + customize_envVars+=$'\n - name: ROX_POLICY_WORKLOAD_KIND_EXCLUSION' + customize_envVars+=$'\n value: "true"' customize_envVars+=$'\n - name: ROX_VIRTUAL_MACHINES_ENHANCED_DATA_MODEL' customize_envVars+=$'\n value: "'"${ROX_VIRTUAL_MACHINES_ENHANCED_DATA_MODEL:-true}"'"' customize_envVars+=$'\n - name: ROX_UI_SECRETS_PAGE_MIGRATION' @@ -749,13 +738,11 @@ deploy_sensor_via_operator() { fi customize_envVars="" - # Shorten node-scan cadence for e2e (production: 5m initial, 4h interval). - # Matcher-not-ready drops the first index as unretryable; a short interval - # covers the next scan without restarting collector. - customize_envVars+=$'\n - name: ROX_NODE_SCANNING_MAX_INITIAL_WAIT' - customize_envVars+=$'\n value: "1s"' + # Scan every 9-11 minutes during operator-deployed e2e tests. customize_envVars+=$'\n - name: ROX_NODE_SCANNING_INTERVAL' - customize_envVars+=$'\n value: "30s"' + customize_envVars+=$'\n value: "10m"' + customize_envVars+=$'\n - name: ROX_NODE_SCANNING_INTERVAL_DEVIATION' + customize_envVars+=$'\n value: "60s"' if [[ -n "${ROX_NETFLOW_BATCHING:-}" ]]; then customize_envVars+=$'\n - name: ROX_NETFLOW_BATCHING' customize_envVars+=$'\n value: "'"${ROX_NETFLOW_BATCHING}"'"' @@ -773,6 +760,10 @@ deploy_sensor_via_operator() { customize_envVars+=$'\n - name: ROX_INIT_CONTAINER_SUPPORT' customize_envVars+=$'\n value: "'"${ROX_INIT_CONTAINER_SUPPORT}"'"' fi + if [[ -n "${ROX_POLICY_WORKLOAD_KIND_EXCLUSION:-}" ]]; then + customize_envVars+=$'\n - name: ROX_POLICY_WORKLOAD_KIND_EXCLUSION' + customize_envVars+=$'\n value: "'"${ROX_POLICY_WORKLOAD_KIND_EXCLUSION}"'"' + fi local scannerV4DbPersistenceYaml scannerV4DbPersistenceYaml="$(_scanner_v4_db_persistence_yaml)" @@ -1640,7 +1631,8 @@ wait_for_scanner_V4() { info "Listing available storage classes:" kubectl describe storageclasses 2>/dev/null || true - matcher_max_seconds=${SCANNER_V4_VULN_READINESS_TIMEOUT:-3600} + # (todo) re-visit the default timeout of 2h and make vuln loading more performant + matcher_max_seconds=${SCANNER_V4_VULN_READINESS_TIMEOUT:-7200} info "Waiting ${matcher_max_seconds}s for matcher vulnerability readiness..." fi @@ -1802,8 +1794,8 @@ _record_build_info() { set_ci_shared_export "build" "${build_info}" } -restore_4_6_postgres_backup() { - info "Restoring a 4.6 postgres backup" +restore_postgres_backup() { + info "Restoring a postgres backup" require_environment "API_ENDPOINT" require_environment "ROX_ADMIN_PASSWORD" @@ -1813,10 +1805,10 @@ restore_4_6_postgres_backup() { if is_CI; then setup_gcp fi - gsutil cp gs://stackrox-ci-upgrade-test-fixtures/upgrade-test-dbs/postgres_db_4_6.sql.zip . + gsutil cp gs://stackrox-ci-upgrade-test-fixtures/upgrade-test-dbs/postgres_db_4.10.0.sql.zip . roxctl -e "$API_ENDPOINT" --ca "" --insecure-skip-tls-verify \ - central db restore --timeout 5m postgres_db_4_6.sql.zip + central db restore --timeout 5m postgres_db_4.10.0.sql.zip } update_public_config() { diff --git a/tests/e2e/run-scanner-v4-install.bats b/tests/e2e/run-scanner-v4-install.bats index 4d8ab27e02314..0f1311b8c9b48 100755 --- a/tests/e2e/run-scanner-v4-install.bats +++ b/tests/e2e/run-scanner-v4-install.bats @@ -1671,15 +1671,15 @@ create_central_pull_secrets() { local namespace="$1" info "Creating image pull secrets for central in namespace $namespace..." echo "{ \"apiVersion\": \"v1\", \"kind\": \"Namespace\", \"metadata\": { \"name\": \"$namespace\" } }" | "${ORCH_CMD}" apply -f - - "${ROOT}/deploy/common/pull-secret.sh" stackrox "$DEFAULT_IMAGE_REGISTRY_HOST" | "${ORCH_CMD}" -n "$central_namespace" apply -f - + "${ROOT}/scripts/pull-secret.sh" stackrox "$DEFAULT_IMAGE_REGISTRY_HOST" | "${ORCH_CMD}" -n "$central_namespace" apply -f - } create_sensor_pull_secrets() { local namespace="$1" info "Creating image pull secrets for secured cluster in namespace $namespace..." echo "{ \"apiVersion\": \"v1\", \"kind\": \"Namespace\", \"metadata\": { \"name\": \"$namespace\" } }" | "${ORCH_CMD}" apply -f - - "${ROOT}/deploy/common/pull-secret.sh" stackrox "$DEFAULT_IMAGE_REGISTRY_HOST" | "${ORCH_CMD}" -n "$namespace" apply -f - - "${ROOT}/deploy/common/pull-secret.sh" collector-stackrox "$DEFAULT_IMAGE_REGISTRY_HOST" | "${ORCH_CMD}" -n "$namespace" apply -f - + "${ROOT}/scripts/pull-secret.sh" stackrox "$DEFAULT_IMAGE_REGISTRY_HOST" | "${ORCH_CMD}" -n "$namespace" apply -f - + "${ROOT}/scripts/pull-secret.sh" collector-stackrox "$DEFAULT_IMAGE_REGISTRY_HOST" | "${ORCH_CMD}" -n "$namespace" apply -f - } resolve_previous_version() { diff --git a/tests/e2e/run-ui-e2e.sh b/tests/e2e/run-ui-e2e.sh index 26fc0f439c808..5ad7dfa5d33ff 100755 --- a/tests/e2e/run-ui-e2e.sh +++ b/tests/e2e/run-ui-e2e.sh @@ -60,14 +60,26 @@ test_ui_e2e() { export DEPLOY_DIR="deploy/${ORCHESTRATOR_FLAVOR}" export_test_environment - setup_deployment_env false false remove_existing_stackrox_resources setup_default_TLS_certs # deploy the optional components before stackrox deploy_optional_e2e_components - deploy_stackrox + ensure_roxie_on_path + local roxie_config; roxie_config="$(mktemp)" + cat < "${roxie_config}" +central: + pauseReconciliation: true + namespace: stackrox + resourceProfile: ci +securedCluster: + pauseReconciliation: true + namespace: stackrox + resourceProfile: ci +EOF + deploy_stackrox_with_roxie_compat "$roxie_config" + rm -f "$roxie_config" # Enable the console plugin for OpenShift if the ConsolePlugin resource exists if [[ "${ORCHESTRATOR_FLAVOR}" == "openshift" ]] && kubectl get consoleplugin advanced-cluster-security &>/dev/null; then diff --git a/tests/e2e/run-vm-scanning.sh b/tests/e2e/run-vm-scanning.sh index 2587aeb93f57f..e54198d332529 100755 --- a/tests/e2e/run-vm-scanning.sh +++ b/tests/e2e/run-vm-scanning.sh @@ -47,6 +47,8 @@ test_vm_scanning_e2e() { deploy_stackrox cd "$ROOT" + ensure_vm_scan_ssh_identity + persist_vm_scan_virtctl rm -f FAIL # Run the full VM scanning e2e suite. make -C tests TESTFLAGS="-race -p 1 -timeout 90m" vm-scanning-tests || touch FAIL diff --git a/tests/e2e/run.sh b/tests/e2e/run.sh index 04a2c1a505d55..17557806f0f44 100755 --- a/tests/e2e/run.sh +++ b/tests/e2e/run.sh @@ -35,6 +35,7 @@ test_e2e() { setup_deployment_env false false remove_existing_stackrox_resources setup_default_TLS_certs + setup_client_TLS_certs info "Creating mocked compliance operator data for compliance v1 tests" "$ROOT/tests/complianceoperator/create.sh" kubectl get compliancecheckresults.compliance.openshift.io -n openshift-compliance @@ -43,7 +44,30 @@ test_e2e() { # If deploy_optional_e2e_components is called after deploy_stackrox it causes an unnecessary Sensor restart deploy_optional_e2e_components - deploy_stackrox + + # Make sure we use the roxie version pinned in ROXIE_VERSION. Under Prow the test image + # ships an older roxie that does not recognize a generic (non-Infra) GKE cluster: it reports + # "cluster type: Unknown" and defaults Central exposure to a localhost port-forward instead of + # the LoadBalancer. That breaks endpoints_test.go, which dials all of Central's ports at the + # API host. The pinned version detects GKE and exposes Central via the LoadBalancer, matching + # the GHA runner (which installs the pinned version explicitly). + ensure_roxie_on_path + + local roxie_config + roxie_config="$(mktemp)" + merge_yaml "$roxie_config" <<'EOF' +central: + namespace: stackrox + pauseReconciliation: true + resourceProfile: ci +securedCluster: + namespace: stackrox + pauseReconciliation: true + resourceProfile: ci +EOF + + deploy_stackrox_with_roxie_compat "$roxie_config" + rm -f "$roxie_config" # Background streamers are not explicitly stopped. They die when the CI # runner terminates, same as the port-forward processes in setup_proxy_tests. @@ -94,7 +118,7 @@ test_e2e() { # Give some time for previous tests to finish up wait_for_api - restore_4_6_postgres_backup + restore_postgres_backup wait_for_api trap cleanup_workload_identities EXIT diff --git a/tests/e2e/vm-scanning-lib.sh b/tests/e2e/vm-scanning-lib.sh index 58d771a00eb62..87d65f137746d 100755 --- a/tests/e2e/vm-scanning-lib.sh +++ b/tests/e2e/vm-scanning-lib.sh @@ -270,3 +270,79 @@ ensure_virtctl_binary_insecure() { is_CI || die "Secure virtctl download failed; refusing insecure curl -k fallback outside CI. Set VIRTCTL_PATH or fix cluster ingress trust material." _download_and_install_virtctl -k } + +# Host-side files shared between the Go suite (via exported env) and post-test +# guest journal collection. Kept out of test_outputs so the private key is not +# uploaded as a CI artifact. +vm_scan_e2e_dir() { + printf '%s\n' "${VM_SCAN_E2E_DIR:-/tmp/vm-scan-e2e}" +} + +# export_vm_scan_public_key fills VM_SSH_PUBLIC_KEY from identity when unset. +# LoadVMScanConfig requires both halves of the keypair. +export_vm_scan_public_key() { + local identity="$1" + if [[ -n "${VM_SSH_PUBLIC_KEY:-}" ]]; then + return 0 + fi + if [[ -f "${identity}.pub" ]]; then + VM_SSH_PUBLIC_KEY="$(<"${identity}.pub")" + export VM_SSH_PUBLIC_KEY + return 0 + fi + VM_SSH_PUBLIC_KEY="$(ssh-keygen -y -f "$identity")" + printf '%s\n' "$VM_SSH_PUBLIC_KEY" > "${identity}.pub" + export VM_SSH_PUBLIC_KEY +} + +# ensure_vm_scan_ssh_identity writes or reuses an SSH key under vm_scan_e2e_dir +# so the Go suite and post-test guest log collection share the same identity. +ensure_vm_scan_ssh_identity() { + local dir identity + dir="$(vm_scan_e2e_dir)" + mkdir -p "$dir" + identity="${dir}/ssh-identity" + + if [[ -n "${VM_SSH_PRIVATE_KEY:-}" ]]; then + printf '%s\n' "${VM_SSH_PRIVATE_KEY}" > "$identity" + chmod 600 "$identity" + export VM_SSH_PRIVATE_KEY_PATH="$identity" + export_vm_scan_public_key "$identity" + return 0 + fi + + if [[ -f "$identity" ]]; then + export VM_SSH_PRIVATE_KEY_PATH="$identity" + VM_SSH_PRIVATE_KEY="$(<"$identity")" + export VM_SSH_PRIVATE_KEY + export_vm_scan_public_key "$identity" + return 0 + fi + + ssh-keygen -t ed25519 -f "$identity" -N "" -C "stackrox-vm-scan-e2e" >/dev/null + chmod 600 "$identity" + VM_SSH_PRIVATE_KEY="$(<"$identity")" + VM_SSH_PUBLIC_KEY="$(<"${identity}.pub")" + export VM_SSH_PRIVATE_KEY VM_SSH_PUBLIC_KEY VM_SSH_PRIVATE_KEY_PATH="$identity" + info "Ephemeral VM scan SSH identity written to ${identity}" +} + +# persist_vm_scan_virtctl copies virtctl next to the SSH identity and records +# the resolved path so post-test can find it after the test process's PATH +# goes away. +persist_vm_scan_virtctl() { + local dir src dest + dir="$(vm_scan_e2e_dir)" + mkdir -p "$dir" + src="$(command -v virtctl)" || { + info "virtctl not on PATH; post-test guest journal collection will skip" + return 0 + } + printf '%s\n' "$src" > "${dir}/virtctl-path" + dest="${dir}/virtctl" + if cp "$src" "$dest" && chmod +x "$dest"; then + info "Persisted virtctl to ${dest} for post-test guest journal collection" + else + info "Could not copy virtctl to ${dest}; post-test will use ${src}" + fi +} diff --git a/tests/e2e/yaml/central-cr-with-scanner-v4.envsubst.yaml b/tests/e2e/yaml/central-cr-with-scanner-v4.envsubst.yaml index ac7d459a4901e..2dd550ae2f319 100644 --- a/tests/e2e/yaml/central-cr-with-scanner-v4.envsubst.yaml +++ b/tests/e2e/yaml/central-cr-with-scanner-v4.envsubst.yaml @@ -59,10 +59,8 @@ $centralAdditionalCAIndented resources: requests: cpu: "400m" - memory: "4Gi" limits: cpu: "6000m" - memory: "4Gi" db: resources: requests: diff --git a/tests/e2e/yaml/central-cr.envsubst.yaml b/tests/e2e/yaml/central-cr.envsubst.yaml index 99132f6d00924..ea69d2e7a5b33 100644 --- a/tests/e2e/yaml/central-cr.envsubst.yaml +++ b/tests/e2e/yaml/central-cr.envsubst.yaml @@ -55,9 +55,6 @@ $centralAdditionalCAIndented resources: requests: cpu: "400m" - memory: "4Gi" - limits: - memory: "4Gi" db: $scannerV4DbPersistenceYaml resources: diff --git a/tests/excluded_scopes_test.go b/tests/excluded_scopes_test.go index e65841ee177e5..f1fd7e827fa97 100644 --- a/tests/excluded_scopes_test.go +++ b/tests/excluded_scopes_test.go @@ -48,10 +48,9 @@ func verifyNoAlertForExcludedScopes(t *testing.T, deploymentName string) { require.NoError(t, err) latestPolicy.Exclusions = []*storage.Exclusion{ - { - Deployment: &storage.Exclusion_Deployment{ - Name: deploymentName, - }, + {Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{ + Name: deploymentName, + }}, }, } ctx, cancel = context.WithTimeout(context.Background(), time.Minute) diff --git a/tests/external_backup_test.go b/tests/external_backup_test.go index 36617867a31f8..f8646549caf38 100644 --- a/tests/external_backup_test.go +++ b/tests/external_backup_test.go @@ -31,11 +31,17 @@ import ( "google.golang.org/grpc/status" ) +const ( + backupRetryTries = 5 + backupRetryInterval = 10 * time.Second + centralReadinessMaxTries = 10 +) + type backupTestCase struct { name string setup func(t *testing.T) ( backup *storage.ExternalBackup, - countBackups func(ctx context.Context, t *testing.T, prefix string) int, + countBackups func(ctx context.Context, t *testing.T, prefix string) (int, error), cleanupBackups func(ctx context.Context, t *testing.T, prefix string), ) } @@ -51,7 +57,7 @@ func newObjectPrefix() string { } func newGCSBucketFuncs(t *testing.T, bucket, serviceAccount string) ( - countFn func(ctx context.Context, t *testing.T, prefix string) int, + countFn func(ctx context.Context, t *testing.T, prefix string) (int, error), cleanupFn func(ctx context.Context, t *testing.T, prefix string), ) { var opts []option.ClientOption @@ -62,15 +68,17 @@ func newGCSBucketFuncs(t *testing.T, bucket, serviceAccount string) ( require.NoError(t, err) bkt := client.Bucket(bucket) - countFn = func(ctx context.Context, t *testing.T, prefix string) int { + countFn = func(ctx context.Context, _ *testing.T, prefix string) (int, error) { it := bkt.Objects(ctx, &googleStorage.Query{Prefix: prefix}) count := 0 var iterErr error for _, iterErr = it.Next(); iterErr == nil; _, iterErr = it.Next() { count++ } - require.Equal(t, iterator.Done, iterErr) - return count + if iterErr != iterator.Done { + return 0, iterErr + } + return count, nil } cleanupFn = func(ctx context.Context, t *testing.T, prefix string) { it := bkt.Objects(ctx, &googleStorage.Query{Prefix: prefix}) @@ -95,8 +103,9 @@ func gcsTestCases() []backupTestCase { return []backupTestCase{ { name: "GCS/service_account_key", - setup: func(t *testing.T) (*storage.ExternalBackup, func(context.Context, *testing.T, string) int, func(context.Context, *testing.T, string)) { - env := testutils.EnvOrFail(t, + setup: func(t *testing.T) (*storage.ExternalBackup, func(context.Context, *testing.T, string) (int, error), func(context.Context, *testing.T, string)) { + env := testutils.EnvOrFail( + t, "GCP_GCS_BACKUP_TEST_BUCKET_NAME_V2", "GOOGLE_GCS_BACKUP_SERVICE_ACCOUNT_V2", ) @@ -113,7 +122,7 @@ func gcsTestCases() []backupTestCase { }, { name: "GCS/workload_identity", - setup: func(t *testing.T) (*storage.ExternalBackup, func(context.Context, *testing.T, string) int, func(context.Context, *testing.T, string)) { + setup: func(t *testing.T) (*storage.ExternalBackup, func(context.Context, *testing.T, string) (int, error), func(context.Context, *testing.T, string)) { env := testutils.EnvOrSkip(t, "GCP_GCS_BACKUP_TEST_BUCKET_NAME_V2", "SETUP_WORKLOAD_IDENTITIES") if env["SETUP_WORKLOAD_IDENTITIES"] != "true" { t.Skip("SETUP_WORKLOAD_IDENTITIES not set to true") @@ -132,10 +141,11 @@ func gcsTestCases() []backupTestCase { } func newS3BucketFuncs(t *testing.T, endpoint, region, accessKeyID, secretAccessKey, bucket string, pathStyle bool) ( - countFn func(ctx context.Context, t *testing.T, prefix string) int, + countFn func(ctx context.Context, t *testing.T, prefix string) (int, error), cleanupFn func(ctx context.Context, t *testing.T, prefix string), ) { - cfg, err := awsConfig.LoadDefaultConfig(context.Background(), + cfg, err := awsConfig.LoadDefaultConfig( + context.Background(), awsConfig.WithRegion(region), awsConfig.WithCredentialsProvider( credentials.NewStaticCredentialsProvider(accessKeyID, secretAccessKey, ""), @@ -159,13 +169,15 @@ func newS3BucketFuncs(t *testing.T, endpoint, region, accessKeyID, secretAccessK } client := s3.NewFromConfig(cfg, clientOpts...) - countFn = func(ctx context.Context, t *testing.T, prefix string) int { + countFn = func(ctx context.Context, _ *testing.T, prefix string) (int, error) { out, err := client.ListObjectsV2(ctx, &s3.ListObjectsV2Input{ Bucket: aws.String(bucket), Prefix: aws.String(prefix), }) - require.NoError(t, err) - return int(aws.ToInt32(out.KeyCount)) + if err != nil { + return 0, err + } + return int(aws.ToInt32(out.KeyCount)), nil } cleanupFn = func(ctx context.Context, t *testing.T, prefix string) { out, err := client.ListObjectsV2(ctx, &s3.ListObjectsV2Input{ @@ -192,7 +204,7 @@ func newAWSS3Setup(name string, makeConfig func(t *testing.T) *storage.S3Config) fullName := "AWS_S3/" + name return backupTestCase{ name: fullName, - setup: func(t *testing.T) (*storage.ExternalBackup, func(context.Context, *testing.T, string) int, func(context.Context, *testing.T, string)) { + setup: func(t *testing.T) (*storage.ExternalBackup, func(context.Context, *testing.T, string) (int, error), func(context.Context, *testing.T, string)) { config := makeConfig(t) config.ObjectPrefix = newObjectPrefix() countFn, cleanupFn := newS3BucketFuncs(t, "", config.GetRegion(), @@ -208,7 +220,8 @@ func newAWSS3Setup(name string, makeConfig func(t *testing.T) *storage.S3Config) func awsS3Config(withEndpoint bool) func(t *testing.T) *storage.S3Config { return func(t *testing.T) *storage.S3Config { - env := testutils.EnvOrFail(t, + env := testutils.EnvOrFail( + t, "AWS_S3_BACKUP_TEST_BUCKET_NAME", "AWS_S3_BACKUP_TEST_BUCKET_REGION", "AWS_ACCESS_KEY_ID", @@ -238,7 +251,7 @@ func newS3CompatibleSetup(name string, makeConfig func(t *testing.T) *storage.S3 fullName := "S3Compatible/" + name return backupTestCase{ name: fullName, - setup: func(t *testing.T) (*storage.ExternalBackup, func(context.Context, *testing.T, string) int, func(context.Context, *testing.T, string)) { + setup: func(t *testing.T) (*storage.ExternalBackup, func(context.Context, *testing.T, string) (int, error), func(context.Context, *testing.T, string)) { config := makeConfig(t) config.ObjectPrefix = newObjectPrefix() pathStyle := config.GetUrlStyle() == storage.S3URLStyle_S3_URL_STYLE_PATH @@ -255,7 +268,8 @@ func newS3CompatibleSetup(name string, makeConfig func(t *testing.T) *storage.S3 func r2Config(withScheme bool, urlStyle storage.S3URLStyle) func(t *testing.T) *storage.S3Compatible { return func(t *testing.T) *storage.S3Compatible { - env := testutils.EnvOrFail(t, + env := testutils.EnvOrFail( + t, "CLOUDFLARE_R2_BACKUP_TEST_ACCOUNT_ID", "CLOUDFLARE_R2_BACKUP_TEST_BUCKET_NAME", "CLOUDFLARE_R2_BACKUP_TEST_REGION", @@ -276,7 +290,8 @@ func r2Config(withScheme bool, urlStyle storage.S3URLStyle) func(t *testing.T) * func odfConfig(withScheme bool) func(t *testing.T) *storage.S3Compatible { return func(t *testing.T) *storage.S3Compatible { - env := testutils.EnvOrFail(t, + env := testutils.EnvOrFail( + t, "ODF_S3_BACKUP_TEST_ENDPOINT", "ODF_S3_BACKUP_TEST_BUCKET_NAME", "ODF_S3_BACKUP_TEST_REGION", @@ -310,11 +325,40 @@ func s3CompatibleTestCases() []backupTestCase { } } +func requireBackupCount( + t *testing.T, + countBackups func(ctx context.Context, t *testing.T, prefix string) (int, error), + prefix string, + expected int, +) error { + return retry.WithRetry( + func() error { + ctx, cancel := context.WithTimeout(context.Background(), backupRetryInterval) + defer cancel() + n, err := countBackups(ctx, t, prefix) + if err != nil { + return err + } + if n != expected { + return fmt.Errorf("expected %d backups, got %d", expected, n) + } + return nil + }, + retry.Tries(backupRetryTries), + retry.BetweenAttempts(func(_ int) { + time.Sleep(backupRetryInterval) + }), + retry.OnFailedAttempts(func(err error) { + t.Logf("Error verifying backup count: %v", err) + }), + ) +} + func runBackupLifecycleTest( t *testing.T, service v1.ExternalBackupServiceClient, backup *storage.ExternalBackup, - countBackups func(ctx context.Context, t *testing.T, prefix string) int, + countBackups func(ctx context.Context, t *testing.T, prefix string) (int, error), cleanupBackups func(ctx context.Context, t *testing.T, prefix string), ) { var prefix string @@ -330,15 +374,16 @@ func runBackupLifecycleTest( t.Logf("Using object prefix: %s", prefix) // Retry TestExternalBackup in case Central is not fully ready yet. - err := retry.WithRetry(func() error { - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - _, err := service.TestExternalBackup(ctx, backup) - return err - }, - retry.Tries(10), + err := retry.WithRetry( + func() error { + ctx, cancel := context.WithTimeout(context.Background(), backupRetryInterval) + defer cancel() + _, err := service.TestExternalBackup(ctx, backup) + return err + }, + retry.Tries(centralReadinessMaxTries), retry.BetweenAttempts(func(_ int) { - time.Sleep(10 * time.Second) + time.Sleep(backupRetryInterval) }), retry.OnFailedAttempts(func(err error) { t.Logf("Error testing external backup: %v", err) @@ -364,9 +409,7 @@ func runBackupLifecycleTest( } }) - countCtx, countCancel := context.WithTimeout(context.Background(), 10*time.Second) - assert.Equal(t, 0, countBackups(countCtx, t, prefix)) - countCancel() + require.NoError(t, requireBackupCount(t, countBackups, prefix, 0)) for i := 1; i <= 3; i++ { triggerCtx, triggerCancel := context.WithTimeout(context.Background(), 2*time.Minute) @@ -375,31 +418,12 @@ func runBackupLifecycleTest( triggerCancel() if i <= 2 { - verifyCtx, verifyCancel := context.WithTimeout(context.Background(), 10*time.Second) - assert.Equal(t, i, countBackups(verifyCtx, t, prefix)) - verifyCancel() + assert.NoError(t, requireBackupCount(t, countBackups, prefix, i)) } } // Third backup should prune the first, keeping only BackupsToKeep=2. - err = retry.WithRetry(func() error { - retryCtx, retryCancel := context.WithTimeout(context.Background(), 10*time.Second) - defer retryCancel() - n := countBackups(retryCtx, t, prefix) - if n != 2 { - return fmt.Errorf("expected 2 backups after pruning, got %d", n) - } - return nil - }, - retry.Tries(10), - retry.BetweenAttempts(func(_ int) { - time.Sleep(1 * time.Second) - }), - retry.OnFailedAttempts(func(err error) { - t.Logf("Error waiting for backup pruning: %v", err) - }), - ) - require.NoError(t, err) + require.NoError(t, requireBackupCount(t, countBackups, prefix, 2)) } func TestExternalBackup(t *testing.T) { diff --git a/tests/init_container_test.go b/tests/init_container_test.go index ebf7a61e4b431..c7b108dbbf12a 100644 --- a/tests/init_container_test.go +++ b/tests/init_container_test.go @@ -180,12 +180,38 @@ func (s *InitContainerSuite) createPolicyWithCleanup(policy *storage.Policy) *st } func (s *InitContainerSuite) waitForViolationAlert(deploymentName, policyName string, expectedCount int) { + waitForAlert(s.T(), s.alertService, s.violationAlertRequest(deploymentName, policyName), expectedCount) +} + +// activeViolationText waits until one active alert exists and returns its violation messages. +func (s *InitContainerSuite) activeViolationText(deploymentName, policyName string) string { + s.waitForViolationAlert(deploymentName, policyName, 1) + + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + listResp, err := s.alertService.ListAlerts(ctx, s.violationAlertRequest(deploymentName, policyName)) + cancel() + s.Require().NoError(err) + s.Require().Len(listResp.GetAlerts(), 1) + + ctx, cancel = context.WithTimeout(context.Background(), time.Minute) + alert, err := s.alertService.GetAlert(ctx, &v1.ResourceByID{Id: listResp.GetAlerts()[0].GetId()}) + cancel() + s.Require().NoError(err) + s.Require().NotEmpty(alert.GetViolations()) + + messages := make([]string, 0, len(alert.GetViolations())) + for _, violation := range alert.GetViolations() { + messages = append(messages, violation.GetMessage()) + } + return strings.Join(messages, "\n") +} + +func (s *InitContainerSuite) violationAlertRequest(deploymentName, policyName string) *v1.ListAlertsRequest { query := search.NewQueryBuilder(). AddStrings(search.DeploymentName, deploymentName). AddStrings(search.PolicyName, policyName). AddStrings(search.ViolationState, storage.ViolationState_ACTIVE.String()) - - waitForAlert(s.T(), s.alertService, &v1.ListAlertsRequest{Query: query.Query()}, expectedCount) + return &v1.ListAlertsRequest{Query: query.Query()} } func (s *InitContainerSuite) TestInitContainerExtraction() { @@ -381,28 +407,85 @@ func (s *InitContainerSuite) TestPolicyEvaluatesBothContainerTypes() { t.Logf("Verified: both init and regular containers with :latest tag triggered policy violation") } -func (s *InitContainerSuite) TestEvaluationFilterSkipsInitContainers() { +func (s *InitContainerSuite) TestEvaluationFilterSkipsContainers() { t := s.T() ns := fmt.Sprintf("init-test-filter-%d", rand.IntN(10000)) createNamespaceWithLabels(t, ns, nil) defer deleteNamespace(t, ns) - policy := s.newLatestTagPolicy( - fmt.Sprintf("Test - Skip Init %d", rand.IntN(10000)), ns, - ) - policy.EvaluationFilter = &storage.EvaluationFilter{ - SkipContainerTypes: []storage.ContainerType{storage.ContainerType_INIT}, - } - createdPolicy := s.createPolicyWithCleanup(policy) + unfiltered := s.createPolicyWithCleanup(s.newLatestTagPolicy( + fmt.Sprintf("Test - Evaluate Init %d", rand.IntN(10000)), ns, + )) + + s.Require().Empty(unfiltered.GetEvaluationFilter().GetSkipContainerTypes()) - // Init uses :latest (would violate), regular uses tagged image (no violation). - // With skip-init filter, the only violating container is skipped — expect 0 alerts. + // Both containers use :latest. Require an alert naming both before checking filters. deployName := fmt.Sprintf("init-filter-skip-%d", rand.IntN(10000)) - s.createDeploymentWithInitContainers(deployName, ns, []string{busyboxLatest}, nginxTagged) + s.createDeploymentWithInitContainers(deployName, ns, []string{busyboxLatest}, nginxLatest) defer teardownDeploymentWithoutCheck(t, deployName, ns) - s.waitForDeploymentWithContainers(deployName, 2) + dep := s.waitForDeploymentWithContainers(deployName, 2) + var initContainer, regularContainer *storage.Container + for _, c := range dep.GetContainers() { + switch c.GetType() { + case storage.ContainerType_INIT: + initContainer = c + case storage.ContainerType_REGULAR: + regularContainer = c + } + } + s.Require().NotNil(initContainer, "expected an init container") + s.Require().NotNil(regularContainer, "expected a regular container") + s.Equal("init-0", initContainer.GetName()) + s.Equal(deployName, regularContainer.GetName()) + s.Contains(initContainer.GetImage().GetName().GetFullName(), "busybox") + s.Contains(regularContainer.GetImage().GetName().GetFullName(), "nginx") - s.waitForViolationAlert(deployName, createdPolicy.GetName(), 0) - t.Logf("Verified: policy with skip init filter produced no violations") + regularContainerRef := fmt.Sprintf("Container '%s'", deployName) + unfilteredText := s.activeViolationText(deployName, unfiltered.GetName()) + s.Require().Contains(unfilteredText, regularContainerRef) + s.Require().Contains(unfilteredText, "Container 'init-0'") + s.Require().Contains(unfilteredText, "tag 'latest'") + t.Logf("Verified unfiltered alert names both containers: %s", unfilteredText) + + tests := map[string]struct { + skipType storage.ContainerType + evaluatedContainer string + skippedContainer string + skippedImage string + }{ + "skip init": { + skipType: storage.ContainerType_INIT, + evaluatedContainer: deployName, + skippedContainer: "init-0", + skippedImage: "busybox", + }, + "skip regular": { + skipType: storage.ContainerType_REGULAR, + evaluatedContainer: "init-0", + skippedContainer: deployName, + skippedImage: "nginx", + }, + } + for name, tc := range tests { + s.Run(name, func() { + policy := s.newLatestTagPolicy(fmt.Sprintf("Test - %s %d", name, rand.IntN(10000)), ns) + policy.EvaluationFilter = &storage.EvaluationFilter{ + SkipContainerTypes: []storage.ContainerType{tc.skipType}, + } + filtered := s.createPolicyWithCleanup(policy) + + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + storedPolicy, err := s.policyService.GetPolicy(ctx, &v1.ResourceByID{Id: filtered.GetId()}) + cancel() + s.Require().NoError(err) + s.Require().Equal([]storage.ContainerType{tc.skipType}, storedPolicy.GetEvaluationFilter().GetSkipContainerTypes()) + + filteredText := s.activeViolationText(deployName, filtered.GetName()) + s.Require().Contains(filteredText, fmt.Sprintf("Container '%s'", tc.evaluatedContainer)) + s.Require().Contains(filteredText, "tag 'latest'") + s.Require().NotContains(filteredText, fmt.Sprintf("Container '%s'", tc.skippedContainer)) + s.Require().NotContains(filteredText, tc.skippedImage) + }) + } } diff --git a/tests/metadata_test.go b/tests/metadata_test.go index fa9521ff7ffb8..e7af3d35aca39 100644 --- a/tests/metadata_test.go +++ b/tests/metadata_test.go @@ -5,25 +5,62 @@ package tests import ( "context" "os" + "strings" "testing" "time" v1 "github.com/stackrox/rox/generated/api/v1" "github.com/stackrox/rox/pkg/buildinfo" + "github.com/stackrox/rox/pkg/clientconn" "github.com/stackrox/rox/pkg/testutils/centralgrpc" "github.com/stackrox/rox/pkg/version" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "google.golang.org/grpc" + "google.golang.org/grpc/metadata" ) func getMetadata(t *testing.T, conn *grpc.ClientConn) *v1.Metadata { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() service := v1.NewMetadataServiceClient(conn) - metadata, err := service.GetMetadata(ctx, &v1.Empty{}) + resp, err := service.GetMetadata(ctx, &v1.Empty{}) require.NoError(t, err) - return metadata + return resp +} + +func TestCentralVersionHeader(t *testing.T) { + conn := centralgrpc.GRPCConnectionToCentral(t) + + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + var metadataMD metadata.MD + resp, err := v1.NewMetadataServiceClient(conn).GetMetadata(ctx, &v1.Empty{}, grpc.Header(&metadataMD)) + require.NoError(t, err) + + metadataVals := metadataMD.Get(clientconn.CentralVersionHeader) + require.Len(t, metadataVals, 1, "expected %s response header from GetMetadata", clientconn.CentralVersionHeader) + assert.Equal(t, resp.GetVersion(), metadataVals[0]) + + pingVals := pingAndGetHeader(t, conn, ctx) + require.Len(t, pingVals, 1, "expected %s response header from Ping", clientconn.CentralVersionHeader) + assert.Equal(t, metadataVals[0], pingVals[0], "version header must be consistent across services") +} + +func TestCentralVersionHeader_AbsentForAnonymous(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + vals := pingAndGetHeader(t, centralgrpc.UnauthenticatedGRPCConnectionToCentral(t), ctx) + assert.Empty(t, vals, "anonymous requests must not receive %s", clientconn.CentralVersionHeader) +} + +func pingAndGetHeader(t *testing.T, conn *grpc.ClientConn, ctx context.Context) []string { + var md metadata.MD + _, err := v1.NewPingServiceClient(conn).Ping(ctx, &v1.Empty{}, grpc.Header(&md)) + require.NoError(t, err) + return md.Get(clientconn.CentralVersionHeader) } func TestMetadataIsSetCorrectly(t *testing.T) { @@ -33,7 +70,14 @@ func TestMetadataIsSetCorrectly(t *testing.T) { } metadataWithAuth := getMetadata(t, centralgrpc.GRPCConnectionToCentral(t)) - assert.Equal(t, buildinfo.BuildFlavor, metadataWithAuth.GetBuildFlavor()) - assert.Equal(t, buildinfo.ReleaseBuild, metadataWithAuth.GetReleaseBuild()) - assert.Equal(t, version.GetMainVersion(), metadataWithAuth.GetVersion()) + + if usingKonfluxImages() { + assert.Equal(t, "release", metadataWithAuth.GetBuildFlavor()) + assert.True(t, metadataWithAuth.GetReleaseBuild()) + assert.Equal(t, strings.TrimSuffix(version.GetMainVersion(), "-fast"), strings.TrimSuffix(metadataWithAuth.GetVersion(), "-fast")) + } else { + assert.Equal(t, buildinfo.BuildFlavor, metadataWithAuth.GetBuildFlavor()) + assert.Equal(t, buildinfo.ReleaseBuild, metadataWithAuth.GetReleaseBuild()) + assert.Equal(t, version.GetMainVersion(), metadataWithAuth.GetVersion()) + } } diff --git a/tests/performance/load/package-lock.json b/tests/performance/load/package-lock.json index 9655f48ba9e60..2dd22a073539b 100644 --- a/tests/performance/load/package-lock.json +++ b/tests/performance/load/package-lock.json @@ -258,10 +258,11 @@ "dev": true }, "node_modules/brace-expansion": { - "version": "1.1.16", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.16.tgz", - "integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==", + "version": "1.1.21", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz", + "integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -1697,10 +1698,11 @@ } }, "node_modules/moment": { - "version": "2.29.4", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", - "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", + "version": "2.31.0", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.31.0.tgz", + "integrity": "sha512-0acOTfMiWOheYS4eoWb80yYMb/JLvVv9SHbs2PehaDzfUG0Bw855SKyk0IKTnPGa5+U2bmi3W68l1+sGLX/pvw==", "dev": true, + "license": "MIT", "engines": { "node": "*" } @@ -1718,10 +1720,17 @@ "dev": true }, "node_modules/nanoid": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "version": "3.3.19", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.19.tgz", + "integrity": "sha512-Y2tUNy4ouw6tq5oDSKeQYGOyhkUBhNOcGV/02KC+6kd9eDGqdZd++mjMiIDilrBYvjEnCYvVtsuHCuP+okSfug==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -2708,9 +2717,9 @@ "dev": true }, "brace-expansion": { - "version": "1.1.16", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.16.tgz", - "integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==", + "version": "1.1.21", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz", + "integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==", "dev": true, "requires": { "balanced-match": "^1.0.0", @@ -3837,9 +3846,9 @@ } }, "moment": { - "version": "2.29.4", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", - "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", + "version": "2.31.0", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.31.0.tgz", + "integrity": "sha512-0acOTfMiWOheYS4eoWb80yYMb/JLvVv9SHbs2PehaDzfUG0Bw855SKyk0IKTnPGa5+U2bmi3W68l1+sGLX/pvw==", "dev": true }, "ms": { @@ -3855,9 +3864,9 @@ "dev": true }, "nanoid": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "version": "3.3.19", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.19.tgz", + "integrity": "sha512-Y2tUNy4ouw6tq5oDSKeQYGOyhkUBhNOcGV/02KC+6kd9eDGqdZd++mjMiIDilrBYvjEnCYvVtsuHCuP+okSfug==", "dev": true }, "natural-compare": { diff --git a/tests/performance/scale/go.mod b/tests/performance/scale/go.mod index 67cb702d7e08f..711815f73608c 100644 --- a/tests/performance/scale/go.mod +++ b/tests/performance/scale/go.mod @@ -4,11 +4,11 @@ go 1.26.0 require ( github.com/cloud-bulldozer/go-commons v1.0.19 - github.com/go-git/go-git/v5 v5.19.2 + github.com/go-git/go-git/v5 v5.19.3 github.com/hashicorp/go-multierror v1.1.1 github.com/spf13/cobra v1.10.2 go.yaml.in/yaml/v3 v3.0.5 - k8s.io/client-go v0.36.4 + k8s.io/client-go v0.37.1 ) require ( @@ -20,53 +20,61 @@ require ( github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/emicklei/go-restful/v3 v3.13.0 // indirect github.com/emirpasic/gods v1.18.1 // indirect - github.com/fxamacker/cbor/v2 v2.9.0 // indirect + github.com/fxamacker/cbor/v2 v2.9.1 // indirect github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect - github.com/go-git/go-billy/v5 v5.9.0 // indirect + github.com/go-git/go-billy/v5 v5.9.2 // indirect github.com/go-logr/logr v1.4.3 // indirect - github.com/go-openapi/jsonpointer v0.21.0 // indirect - github.com/go-openapi/jsonreference v0.20.2 // indirect - github.com/go-openapi/swag v0.23.0 // indirect + github.com/go-openapi/jsonpointer v1.0.0 // indirect + github.com/go-openapi/jsonreference v1.0.0 // indirect + github.com/go-openapi/swag v0.27.1 // indirect + github.com/go-openapi/swag/cmdutils v0.27.1 // indirect + github.com/go-openapi/swag/conv v0.27.1 // indirect + github.com/go-openapi/swag/fileutils v0.27.1 // indirect + github.com/go-openapi/swag/jsonutils v0.27.1 // indirect + github.com/go-openapi/swag/loading v0.27.1 // indirect + github.com/go-openapi/swag/mangling v0.27.1 // indirect + github.com/go-openapi/swag/netutils v0.27.1 // indirect + github.com/go-openapi/swag/pools v0.27.1 // indirect + github.com/go-openapi/swag/stringutils v0.27.1 // indirect + github.com/go-openapi/swag/typeutils v0.27.1 // indirect + github.com/go-openapi/swag/yamlutils v0.27.1 // indirect github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect github.com/google/gnostic-models v0.7.0 // indirect github.com/google/uuid v1.6.0 // indirect github.com/hashicorp/errwrap v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect - github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/kevinburke/ssh_config v1.2.0 // indirect - github.com/klauspost/cpuid/v2 v2.3.0 // indirect - github.com/mailru/easyjson v0.7.7 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/pjbgf/sha1cd v0.6.0 // indirect + github.com/pjbgf/sha1cd v0.7.0 // indirect github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect github.com/skeema/knownhosts v1.3.1 // indirect - github.com/spf13/pflag v1.0.9 // indirect + github.com/spf13/pflag v1.0.10 // indirect github.com/x448/float16 v0.8.4 // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect - go.yaml.in/yaml/v2 v2.4.3 // indirect - golang.org/x/crypto v0.53.0 // indirect - golang.org/x/net v0.56.0 // indirect - golang.org/x/oauth2 v0.34.0 // indirect - golang.org/x/sys v0.46.0 // indirect - golang.org/x/term v0.44.0 // indirect - golang.org/x/text v0.39.0 // indirect - golang.org/x/time v0.14.0 // indirect + go.yaml.in/yaml/v2 v2.4.4 // indirect + golang.org/x/crypto v0.56.0 // indirect + golang.org/x/net v0.57.0 // indirect + golang.org/x/oauth2 v0.36.0 // indirect + golang.org/x/sys v0.47.0 // indirect + golang.org/x/term v0.45.0 // indirect + golang.org/x/text v0.41.0 // indirect + golang.org/x/time v0.15.0 // indirect google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af // indirect gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/api v0.36.4 // indirect - k8s.io/apimachinery v0.36.4 // indirect + k8s.io/api v0.37.1 // indirect + k8s.io/apimachinery v0.37.1 // indirect k8s.io/klog/v2 v2.140.0 // indirect - k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a // indirect - k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 // indirect + k8s.io/kube-openapi v0.0.0-20260721132016-d427ff9ee9ad // indirect + k8s.io/utils v0.0.0-20260626114624-be93311217bd // indirect sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/randfill v1.0.0 // indirect - sigs.k8s.io/structured-merge-diff/v6 v6.3.3 // indirect + sigs.k8s.io/structured-merge-diff/v6 v6.4.2 // indirect sigs.k8s.io/yaml v1.6.0 // indirect ) diff --git a/tests/performance/scale/go.sum b/tests/performance/scale/go.sum index 3ef00b9025f19..7962276a38121 100644 --- a/tests/performance/scale/go.sum +++ b/tests/performance/scale/go.sum @@ -14,7 +14,6 @@ github.com/cloud-bulldozer/go-commons v1.0.19/go.mod h1:CKmdWhyxN6p4leLhdwKxQHJ3 github.com/cloudflare/circl v1.6.3 h1:9GPOhQGF9MCYUeXyMYlqTR6a5gTrgR/fBLXvUgtVcg8= github.com/cloudflare/circl v1.6.3/go.mod h1:2eXP6Qfat4O/Yhh8BznvKnJ+uzEoTQ6jVKJRn81BiS4= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/cyphar/filepath-securejoin v0.6.1 h1:5CeZ1jPXEiYt3+Z6zqprSAgSWiggmpVyciv8syjIpVE= github.com/cyphar/filepath-securejoin v0.6.1/go.mod h1:A8hd4EnAeyujCJRrICiOWqjS1AX0a9kM5XL+NwKoYSc= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -27,28 +26,54 @@ github.com/emicklei/go-restful/v3 v3.13.0 h1:C4Bl2xDndpU6nJ4bc1jXd+uTmYPVUwkD6bF github.com/emicklei/go-restful/v3 v3.13.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= -github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM= -github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= +github.com/fxamacker/cbor/v2 v2.9.1 h1:2rWm8B193Ll4VdjsJY28jxs70IdDsHRWgQYAI80+rMQ= +github.com/fxamacker/cbor/v2 v2.9.1/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c= github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= -github.com/go-git/go-billy/v5 v5.9.0 h1:jItGXszUDRtR/AlferWPTMN4j38BQ88XnXKbilmmBPA= -github.com/go-git/go-billy/v5 v5.9.0/go.mod h1:jCnQMLj9eUgGU7+ludSTYoZL/GGmii14RxKFj7ROgHw= +github.com/go-git/go-billy/v5 v5.9.2 h1:OXFSRyz4g20upsGDJgQG9Bak1l/ZEv8GHVYB52O71sE= +github.com/go-git/go-billy/v5 v5.9.2/go.mod h1:ExsU+jcGwXTBOnyilvAnEM1wug1IxHr4yP2ZXsNRtV0= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII= -github.com/go-git/go-git/v5 v5.19.2 h1:wkfn7vOlUBu8ivAWKBWisTiwJK4jYHzTF8Ndv1LyGqY= -github.com/go-git/go-git/v5 v5.19.2/go.mod h1:QqCBE1EFN5ddFmrliLQ3/ntRCUjZU3EJuwuB/jWEHjk= +github.com/go-git/go-git/v5 v5.19.3 h1:qHttbZ+Am7wEjdTpR1XMQ4rl42FK9SIXzZ4o9x7s6M4= +github.com/go-git/go-git/v5 v5.19.3/go.mod h1:Ye4C8dVigkqrv9UsB4NMdSLV4yAIkLiIhW61gcOyhl4= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= -github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= -github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= -github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= -github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= -github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= -github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= -github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= -github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= +github.com/go-openapi/jsonpointer v1.0.0 h1:kR9tHqY0CtZaOPVFm622dPVNhrvYpwr4uCxgL3h1H8s= +github.com/go-openapi/jsonpointer v1.0.0/go.mod h1:Z3rw7dWu1p9IgitXCFamSlA5lmDiklEB6vkaxcNZW5Y= +github.com/go-openapi/jsonreference v1.0.0 h1:jlmTr6torcd1YgDQvSfNmRtKzYDO4FGBkrAdlAVWnpY= +github.com/go-openapi/jsonreference v1.0.0/go.mod h1:jtwdyGbJk0Xhe5Y+rwtglQP6Sb1WZST4rT32LWB+sv0= +github.com/go-openapi/swag v0.27.1 h1:VotvOLWW8q/EAxB0YdsBBGC8XYyeL1YwBj2ungAGPNg= +github.com/go-openapi/swag v0.27.1/go.mod h1:GTkJPwHfhJp6MWr4/rCh64HVI3Ofu+tcsbfjfHmTxpE= +github.com/go-openapi/swag/cmdutils v0.27.1 h1:I7sYqaWVl5mq0NEmNQkAmFDyNin9ufvMX/p2zwtQaOE= +github.com/go-openapi/swag/cmdutils v0.27.1/go.mod h1:Sm1MVFMkF6guJJ+pQqHnQA3N0j9qALV3NxzDSv6bETM= +github.com/go-openapi/swag/conv v0.27.1 h1:8wi9ZG+olmY1wXphl93EWniPtbSPkXM/feH7FgjsvrU= +github.com/go-openapi/swag/conv v0.27.1/go.mod h1:QbqMivkpKhC3g1B1GGGOJ6ANewI3S62dbzYu3Duowqs= +github.com/go-openapi/swag/fileutils v0.27.1 h1:QQqBSoi5mW4XpU85nS0mLcA+zAE6vLzrb0QkmLKf9oM= +github.com/go-openapi/swag/fileutils v0.27.1/go.mod h1:VvJFZLTZS0AI854gEQz5tk7dBESdLjiNUMSZ/th2ry8= +github.com/go-openapi/swag/jsonutils v0.27.1 h1:SVgK3i4USzCU5mibOOS/l4ea2h9UQXy7J7RNLTjuXjU= +github.com/go-openapi/swag/jsonutils v0.27.1/go.mod h1:tdlEpZqdcQ17uj6J4YdK9vd8It5qWMwjWXOs0tjpRlk= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.27.1 h1:mJu3COL9WEaZVp/Kf2PRMi7tPszPEJfSr/OO75ynCs8= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.27.1/go.mod h1:mofwUWx70wvskwESqRJ//k/9kURmCgyJl5m5Ppoh5kY= +github.com/go-openapi/swag/loading v0.27.1 h1:/DxUgDXKbBX4bcn7r9uEXfJyzN5XpiJmZplzQTjrRCY= +github.com/go-openapi/swag/loading v0.27.1/go.mod h1:jvGh3iA2+zyUUycB5fgJWzeHnhrpvGnJJM0RVE9ZShE= +github.com/go-openapi/swag/mangling v0.27.1 h1:yC9D0HyUE8gbP+BfmGx9+AA89ikwZTMjESK3OnnoaqA= +github.com/go-openapi/swag/mangling v0.27.1/go.mod h1:jtBE2+V+3pILxOR7Vgce+Cwp6A2PgZbvVqfNntbVs0w= +github.com/go-openapi/swag/netutils v0.27.1 h1:mICMFoS82F5TZ4Zy3cqmcQk+BFeCp3Uyq3Np7GI0/qU= +github.com/go-openapi/swag/netutils v0.27.1/go.mod h1:J+WYyFMLtvtCGqa6jLv+YNUmIKI3ZRQRrvfNDMoQoEQ= +github.com/go-openapi/swag/pools v0.27.1 h1:9LeadcMyb2GJCbXX5hVQDbZ2Lq9TL4dCs/nx1j5DO0E= +github.com/go-openapi/swag/pools v0.27.1/go.mod h1:kVQefhSK5RWuRe7BXsL8htgBPAMpN7HDGpGEknqugeE= +github.com/go-openapi/swag/stringutils v0.27.1 h1:ZXePZ0r2p1qSjo8tD3Un4vFj8+FqlCkczxDrJIhYUp8= +github.com/go-openapi/swag/stringutils v0.27.1/go.mod h1:lzRN95CxXmA03XcDWHLOb6nOMcxCqR5rGY0lOgsfRoM= +github.com/go-openapi/swag/typeutils v0.27.1 h1:KSTdFlfnse4r6dP9IrEnwMldjE+zs71UeEB3//PtVXc= +github.com/go-openapi/swag/typeutils v0.27.1/go.mod h1:Srm0xFNRZ1Y+vCxJclo5qzx8aj+1pAKda/YfFPrG0dQ= +github.com/go-openapi/swag/yamlutils v0.27.1 h1:ftxv6xvXb1E3zohUc+okZ9nSqNb9StQX/FXnKZ98sQA= +github.com/go-openapi/swag/yamlutils v0.27.1/go.mod h1:bnxFIB1qewGRiZHypXGZ3fNgf13/0HfRgnS/iZBDrOo= +github.com/go-openapi/testify/enable/yaml/v2 v2.6.0 h1:gGHwAJ0R/5jU8BEGDbfRNR3hL68dAVi84WuOApp29B0= +github.com/go-openapi/testify/enable/yaml/v2 v2.6.0/go.mod h1:tY+St1SGq4NFl0QIqdTY4aEdbChAHxhyB77XQi9iJCo= +github.com/go-openapi/testify/v2 v2.6.0 h1:5PKH2HE7YJ/LuRPQGvSxBRlFXNQhSetBLlGAgUEu3ug= +github.com/go-openapi/testify/v2 v2.6.0/go.mod h1:SgsVHtfooshd0tublTtJ50FPKhujf47YRqauXXOUxfw= github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ= github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw= github.com/google/gnostic-models v0.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo= @@ -66,24 +91,17 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= -github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= -github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= -github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= -github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= 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/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -94,8 +112,8 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k= github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY= -github.com/pjbgf/sha1cd v0.6.0 h1:3WJ8Wz8gvDz29quX1OcEmkAlUg9diU4GxJHqs0/XiwU= -github.com/pjbgf/sha1cd v0.6.0/go.mod h1:lhpGlyHLpQZoxMv8HcgXvZEhcGs0PG/vsZnEJ7H0iCM= +github.com/pjbgf/sha1cd v0.7.0 h1:ZRNPKHj+gfkLBf0KJv/p1Hmz+7bqCT5o311YX0nq+DA= +github.com/pjbgf/sha1cd v0.7.0/go.mod h1:pKR5Li+qTCo+ebqITZfwPlJGoCFCvSO00qxjbNtTUFQ= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -111,56 +129,52 @@ github.com/skeema/knownhosts v1.3.1 h1:X2osQ+RAjK76shCbvhHHHVl3ZlgDm8apHEHFqRjnB github.com/skeema/knownhosts v1.3.1/go.mod h1:r7KTdC8l4uxWRyK2TpQZ/1o5HaSzh06ePQNxPwTcfiY= github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU= github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4= -github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY= github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= +github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/objx v0.5.3 h1:jmXUvGomnU1o3W/V5h2VEradbpJDwGrzugQQvL0POH4= +github.com/stretchr/objx v0.5.3/go.mod h1:rDQraq+vQZU7Fde9LOZLr8Tax6zZvy4kuNKF+QYS+U0= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -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.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= -go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= -go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= +go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ= +go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= go.yaml.in/yaml/v3 v3.0.5 h1:N6y/pJk8buWs9NY5ERU2HSMfm+IuD/OtfdAnq6kESPw= go.yaml.in/yaml/v3 v3.0.5/go.mod h1:HVTZu1O7/Vkt2N+BFy8Zza+lnLsABggaTM2ZpNIGuKg= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.53.0 h1:QZ4Muo8THX6CizN2vPPd5fBGHyogrdK9fG4wLPFUsto= -golang.org/x/crypto v0.53.0/go.mod h1:DNLU434OwVakk9PzuwV8w62mAJpRJL3vsgcfp4Qnsio= +golang.org/x/crypto v0.56.0 h1:GUh5Ii4J5jtcseSMiRqr1jXCNHoxjeV9Fmekc2oLy6Y= +golang.org/x/crypto v0.56.0/go.mod h1:OMW5y6CY9l38uPLmxU6l6pwcXp1obtLo3e6gT7gQR2I= golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f h1:W3F4c+6OLc6H2lb//N1q4WpJkhzJCK5J6kUi1NTVXfM= golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f/go.mod h1:J1xhfL/vlindoeF/aINzNzt2Bket5bjo9sdOYzOsU80= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o= -golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec= -golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw= -golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= +golang.org/x/net v0.57.0 h1:K5+3DljvIuDG9/Jv9rvyMywYNFCQ9RSUY6OOTTkT+tE= +golang.org/x/net v0.57.0/go.mod h1:KpXc8iv+r3XplLAG/f7Jsf9RPszJzdR0f58q9vGOuEU= +golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs= +golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw= -golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs= +golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.44.0 h1:0rLvDRCtNj0gZkyIXhCyOb2OAzEhLVqc4B+hrsBhrmc= -golang.org/x/term v0.44.0/go.mod h1:7ze4MdzUzLXpSAoFP1H0bOI9aXDqveSvatT5vKcFh2Y= +golang.org/x/term v0.45.0 h1:NwWyBmoJCbfTHpxrWoZ9C6/VxOf7ic219I8xZZFdrf0= +golang.org/x/term v0.45.0/go.mod h1:9aqxs0blBcrm/n0L9QW0aRVD+ktan8ssZromtqJC43w= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.39.0 h1:UbZz4pLOvn600D6Oh6GGEI6VAmndrEBLv8/6BEXzyus= -golang.org/x/text v0.39.0/go.mod h1:3UwRclnC2g0TU9x8PZiyfOajCd1zaUNHF9cvqcQZ+ZM= -golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= -golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= +golang.org/x/text v0.41.0 h1:vz/seA0lnX87Othu2f/0L24RcgrXD9/YFTSuGjj3rH8= +golang.org/x/text v0.41.0/go.mod h1:jvf1O8ajNzZqhSrQBPbutR/EB83Cc0CFrezNQIwbb5M= +golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U= +golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af h1:+5/Sw3GsDNlEmu7TfklWKPdQ0Ykja5VEmq2i817+jbI= google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= @@ -176,26 +190,25 @@ gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -k8s.io/api v0.36.4 h1:RxrvqCL6vgH5/+UnTeu1IIFqYmGfy0hnyrod1rn35Oo= -k8s.io/api v0.36.4/go.mod h1:S2B3orCFBDhrgyWbLeuKcT2QdHIpQesBkCYSlWtwUOw= -k8s.io/apimachinery v0.36.4 h1:PT2UzkupGuAx/+xT5XjiMJ1WGpY3fn9/hdAvjweRet4= -k8s.io/apimachinery v0.36.4/go.mod h1:p2I2dipt7JHG+quVwQ1d02d28O4GdDi77RByQ13MTpk= -k8s.io/client-go v0.36.4 h1:MDvfDNvMSt0Br94SK8neviVlwL9qifw9B26hJCpD1K0= -k8s.io/client-go v0.36.4/go.mod h1:pNK4WKELbwlEDvtbE8l22lEZL5THYF61H5EealokZmA= +k8s.io/api v0.37.1 h1:l6N77U7tjwB5L056bgrBTJIEdevac/naBZ3iSvDNfpM= +k8s.io/api v0.37.1/go.mod h1:zSlbB1YpJ1YQlFVQy20UYll81UJSJJUMLhkhvg6Z78M= +k8s.io/apimachinery v0.37.1 h1:hGCYyvKHCwtwMitj2vU4vYx0Z16N9GyZk9BBnz0wDAE= +k8s.io/apimachinery v0.37.1/go.mod h1:jF84AyUi/IRIXRot5f+lm6MpxoWI+F1XgjaMmwCdTFw= +k8s.io/client-go v0.37.1 h1:QTv/5ha4jAHtW9qxxVBkQVFBRDb4jHfFopQqqMdc+wM= +k8s.io/client-go v0.37.1/go.mod h1:dnAPtTnCNY38Ho04D2KdY1F4IKausa9UbqaAZKl60SY= k8s.io/klog/v2 v2.140.0 h1:Tf+J3AH7xnUzZyVVXhTgGhEKnFqye14aadWv7bzXdzc= k8s.io/klog/v2 v2.140.0/go.mod h1:o+/RWfJ6PwpnFn7OyAG3QnO47BFsymfEfrz6XyYSSp0= -k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a h1:xCeOEAOoGYl2jnJoHkC3hkbPJgdATINPMAxaynU2Ovg= -k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a/go.mod h1:uGBT7iTA6c6MvqUvSXIaYZo9ukscABYi2btjhvgKGZ0= -k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 h1:AZYQSJemyQB5eRxqcPky+/7EdBj0xi3g0ZcxxJ7vbWU= -k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk= +k8s.io/kube-openapi v0.0.0-20260721132016-d427ff9ee9ad h1:oXImqH8mQNk7PmvzKhmN3ddJoY6OnyM225MXwGHPm0A= +k8s.io/kube-openapi v0.0.0-20260721132016-d427ff9ee9ad/go.mod h1:0/mqHCVhlumdJ3BhCfnjSZQE037nAhNodh1/hK0T8/I= +k8s.io/utils v0.0.0-20260626114624-be93311217bd h1:Ea7fgQ5we8Y9T0OX5o0dAHzQOBRI07D/dEYRaB9ZZEs= +k8s.io/utils v0.0.0-20260626114624-be93311217bd/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk= sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg= sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v6 v6.3.3 h1:u08YRbVUi59ri4YD6cg0UqNM4Dimn0sIl+wldcx5PYw= -sigs.k8s.io/structured-merge-diff/v6 v6.3.3/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= +sigs.k8s.io/structured-merge-diff/v6 v6.4.2 h1:qdOxHwrl2Kaag1aQEarlYcOA9vSyGCp3CIki3aW8c4Q= +sigs.k8s.io/structured-merge-diff/v6 v6.4.2/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/tests/pods_test.go b/tests/pods_test.go index a2e3b911163bd..b96ade2c69aed 100644 --- a/tests/pods_test.go +++ b/tests/pods_test.go @@ -10,7 +10,6 @@ import ( "time" "github.com/graph-gophers/graphql-go" - "github.com/stackrox/rox/central/graphql/resolvers/inputtypes" "github.com/stackrox/rox/generated/storage" "github.com/stackrox/rox/pkg/sliceutils" "github.com/stackrox/rox/pkg/testutils" @@ -194,18 +193,6 @@ func getPods(t testutils.T, deploymentID string) []Pod { Pods []Pod `json:"pods"` } - // Using this to ensure pagination does not fail. - offset := int32(0) - limit := int32(10) - field := "Pod Name" - pagination := inputtypes.Pagination{ - Offset: &offset, - Limit: &limit, - SortOption: &inputtypes.SortOption{ - Field: &field, - }, - } - makeGraphQLRequest(t, ` query getPods($podsQuery: String, $pagination: Pagination) { pods(query: $podsQuery, pagination: $pagination) { @@ -221,7 +208,7 @@ func getPods(t testutils.T, deploymentID string) []Pod { } `, map[string]interface{}{ "podsQuery": fmt.Sprintf("Deployment ID: %s", deploymentID), - "pagination": pagination, + "pagination": nil, }, &respData, timeout) t.Logf("%+v", respData) diff --git a/tests/policy_as_code_test.go b/tests/policy_as_code_test.go index 6f55908167678..2a023d61826b3 100644 --- a/tests/policy_as_code_test.go +++ b/tests/policy_as_code_test.go @@ -473,23 +473,34 @@ func (pc *PolicyAsCodeSuite) createCRAndObserveInCentral(policyCR *v1alpha1.Secu } func (pc *PolicyAsCodeSuite) TestCRWithEvaluationFilter() { - k8sPolicy := createBasePolicyStruct("test-eval-filter-cr") - k8sPolicy.Spec.EvaluationFilter = &v1alpha1.EvaluationFilter{ - SkipContainerTypes: []v1alpha1.ContainerType{"INIT"}, + tests := map[string]struct { + containerType v1alpha1.ContainerType + protoType storage.ContainerType + }{ + "init": {containerType: "INIT", protoType: storage.ContainerType_INIT}, + "regular": {containerType: "REGULAR", protoType: storage.ContainerType_REGULAR}, } + for name, tc := range tests { + pc.Run(name, func() { + k8sPolicy := createBasePolicyStruct("test-eval-filter-cr-" + name) + k8sPolicy.Spec.EvaluationFilter = &v1alpha1.EvaluationFilter{ + SkipContainerTypes: []v1alpha1.ContainerType{tc.containerType}, + } - id := pc.createCRAndObserveInCentral(k8sPolicy) - pc.Require().NotEmpty(id) + id := pc.createCRAndObserveInCentral(k8sPolicy) + pc.Require().NotEmpty(id) - policy, err := pc.policyClient.GetPolicy(pc.ctx, &v1.ResourceByID{Id: id}) - pc.Require().NoError(err) - pc.policies = append(pc.policies, policy) + policy, err := pc.policyClient.GetPolicy(pc.ctx, &v1.ResourceByID{Id: id}) + pc.Require().NoError(err) + pc.policies = append(pc.policies, policy) - pc.Require().NotNil(policy.GetEvaluationFilter()) - pc.Require().Equal( - []storage.ContainerType{storage.ContainerType_INIT}, - policy.GetEvaluationFilter().GetSkipContainerTypes(), - ) + pc.Require().NotNil(policy.GetEvaluationFilter()) + pc.Require().Equal( + []storage.ContainerType{tc.protoType}, + policy.GetEvaluationFilter().GetSkipContainerTypes(), + ) + }) + } } func (pc *PolicyAsCodeSuite) TearDownSuite() { diff --git a/tests/policy_test.go b/tests/policy_test.go index ab1ba5a7bb1ac..fd57f8515840e 100644 --- a/tests/policy_test.go +++ b/tests/policy_test.go @@ -519,12 +519,11 @@ func verifyExclusionsRemoved(t *testing.T) { policy.Id = "verifyExcludedScopesRemoved policy ID" policy.Name = "verifyExcludedScopesRemoved is a valid policy" policy.Exclusions = []*storage.Exclusion{ - { - Deployment: &storage.Exclusion_Deployment{ - Scope: &storage.Scope{ - Cluster: "This is not a cluster", - }, + {Matcher: &storage.Exclusion_Deployment_{Deployment: &storage.Exclusion_Deployment{ + Scope: &storage.Scope{ + Cluster: "This is not a cluster", }, + }}, }, } diff --git a/tests/roxctl/bats-tests/cluster/sensor-generate-image-overrides.bats b/tests/roxctl/bats-tests/cluster/sensor-generate-image-overrides.bats index 2ea36893fcd2b..e42e1558289bb 100755 --- a/tests/roxctl/bats-tests/cluster/sensor-generate-image-overrides.bats +++ b/tests/roxctl/bats-tests/cluster/sensor-generate-image-overrides.bats @@ -3,7 +3,7 @@ load "../helpers.bash" out_dir="" -cluster_name="override-test-cluster" +cluster_name="" central_flavor="" setup_file() { @@ -11,11 +11,20 @@ setup_file() { command -v yq || skip "Tests in this file require yq" [[ -n "$API_ENDPOINT" ]] || fail "API_ENDPOINT environment variable required" [[ -n "$ROX_ADMIN_PASSWORD" ]] || fail "ROX_ADMIN_PASSWORD environment variable required" - central_flavor="$(kubectl -n stackrox exec -it deployment/central -- env | grep -i ROX_IMAGE_FLAVOR | sed 's/ROX_IMAGE_FLAVOR=//')" } setup() { out_dir="$(mktemp -d -u)" + # Unique cluster name per test so that tests with different overrides don't affect + # each other due to '--continue-if-exists'. + cluster_name="override-test-cluster-${BATS_TEST_NUMBER}" + central_flavor="$(kubectl -n stackrox exec deployment/central -- env 2>&1 | grep -i '^ROX_IMAGE_FLAVOR=' | sed 's/ROX_IMAGE_FLAVOR=//' | tr -d '\r\n')" + if [[ -z "$central_flavor" ]]; then + echo "Failed to detect Central image flavor. Checking Central pod status:" >&3 + kubectl -n stackrox get pod -l app=central >&3 || true + fail "Could not detect Central image flavor from deployment/central" + fi + echo "Detected central flavor: '$central_flavor'" >&3 } teardown() { @@ -30,41 +39,58 @@ registry_from_flavor() { "opensource") echo "quay.io/stackrox-io" ;; + "rhacs") + echo "registry.redhat.io/advanced-cluster-security" + ;; + *) + fail "Unknown central flavor: '$central_flavor'" + ;; + esac +} + +image_name_from_flavor() { + local component="$1" + case "$central_flavor" in + "rhacs") + echo "rhacs-${component}-rhel9" + ;; + *) + echo "$component" + ;; esac } -any_version_latest="${any_version}[0-9]+\-latest" -any_version_slim="${any_version}[0-9]+\-slim" +any_version_regex="${any_version}(x|[0-9]+)(-.*)?$" @test "roxctl sensor generate: no overrides" { generate_bundle k8s --name "$cluster_name" assert_success - assert_bundle_registry "$out_dir" "sensor" "$(registry_from_flavor)/main:$any_version" - assert_bundle_registry "$out_dir" "collector" "$(registry_from_flavor)/collector:$any_version" + assert_bundle_registry "$out_dir" "sensor" "$(registry_from_flavor)/$(image_name_from_flavor main):$any_version_regex" + assert_bundle_registry "$out_dir" "collector" "$(registry_from_flavor)/$(image_name_from_flavor collector):$any_version_regex" delete_cluster "$cluster_name" } @test "roxctl sensor generate: with main image override. Collector should be derived from main override" { generate_bundle k8s "--main-image-repository=example.com/stackrox/main" --name "$cluster_name" assert_success - assert_bundle_registry "$out_dir" "sensor" "example\.com/stackrox/main:$any_version" - assert_bundle_registry "$out_dir" "collector" "example\.com/stackrox/collector:$any_version" + assert_bundle_registry "$out_dir" "sensor" "example\.com/stackrox/main:$any_version_regex" + assert_bundle_registry "$out_dir" "collector" "example\.com/stackrox/$(image_name_from_flavor collector):$any_version_regex" delete_cluster "$cluster_name" } @test "roxctl sensor generate: with collector override" { generate_bundle k8s "--collector-image-repository=example2.com/stackrox/collector" --name "$cluster_name" assert_success - assert_bundle_registry "$out_dir" "sensor" "$(registry_from_flavor)/main:$any_version" - assert_bundle_registry "$out_dir" "collector" "example2\.com/stackrox/collector:$any_version" + assert_bundle_registry "$out_dir" "sensor" "$(registry_from_flavor)/$(image_name_from_flavor main):$any_version_regex" + assert_bundle_registry "$out_dir" "collector" "example2\.com/stackrox/collector:$any_version_regex" delete_cluster "$cluster_name" } @test "roxctl sensor generate: with different overrides" { generate_bundle k8s "--main-image-repository=example.com/stackrox/main" "--collector-image-repository=example2.com/stackrox/collector" --name "$cluster_name" assert_success - assert_bundle_registry "$out_dir" "sensor" "example\.com/stackrox/main:$any_version" - assert_bundle_registry "$out_dir" "collector" "example2\.com/stackrox/collector:$any_version" + assert_bundle_registry "$out_dir" "sensor" "example\.com/stackrox/main:$any_version_regex" + assert_bundle_registry "$out_dir" "collector" "example2\.com/stackrox/collector:$any_version_regex" delete_cluster "$cluster_name" } diff --git a/tests/upgrade/lib.sh b/tests/upgrade/lib.sh index cbe1d1ee0997c..7755bacf0b10b 100644 --- a/tests/upgrade/lib.sh +++ b/tests/upgrade/lib.sh @@ -105,143 +105,47 @@ get_target_bg_migration_seqnum() { "$TEST_ROOT/central/backgroundmigrations/seq_num.go" } -deploy_earlier_postgres_central() { +deploy_earlier_tag_central() { info "Deploying: $EARLIER_TAG..." - make cli - - PATH="bin/$TEST_HOST_PLATFORM:$PATH" command -v roxctl - PATH="bin/$TEST_HOST_PLATFORM:$PATH" roxctl version - - # Let's try helm - # BSD tr cannot filter /dev/urandom (NUL bytes). gen_admin_password - # produces a value shared with Helm --set and later restore/auth. - ROX_ADMIN_PASSWORD="$(gen_admin_password)" - export ROX_ADMIN_PASSWORD - PATH="bin/$TEST_HOST_PLATFORM:$PATH" roxctl helm output central-services --image-defaults opensource --output-dir /tmp/early-stackrox-central-services-chart --remove - - helm install -n stackrox --create-namespace stackrox-central-services /tmp/early-stackrox-central-services-chart \ - --set central.adminPassword.value="${ROX_ADMIN_PASSWORD}" \ - --set central.db.enabled=true \ - --set central.db.persistence.persistentVolumeClaim.size="${PVC_SIZE:-100Gi}" \ - --set central.persistence.none=true \ - --set central.exposure.loadBalancer.enabled=true \ - --set system.enablePodSecurityPolicies=false \ - --set central.image.tag="${EARLIER_TAG}" \ - --set central.db.image.tag="${EARLIER_TAG}" - - # Installing this way returns faster than the scripts but everything isn't running when it finishes like with - # the scripts. So we will give it a minute for things to get started before we proceed - sleep 60 - - ROX_USERNAME="admin" + local roxie_envrc + roxie_envrc="$(mktemp)" + roxie deploy central --verbose \ + --single-namespace \ + --envrc "${roxie_envrc}" \ + --tag "${EARLIER_TAG}" \ + --resources ci \ + --pause-reconciliation `# subsequent tests mangle resources and image` \ + --exposure loadbalancer \ + --set central.spec.central.db.persistence.persistentVolumeClaim.storageClassName=premium-rwo `# i.e. type: pd-ssd` \ + --set central.spec.scannerV4.db.persistence.persistentVolumeClaim.storageClassName=premium-rwo \ + "$@" + # shellcheck disable=SC1090 + source "${roxie_envrc}" + rm -f "${roxie_envrc}" ci_export "ROX_USERNAME" "$ROX_USERNAME" ci_export "ROX_ADMIN_PASSWORD" "$ROX_ADMIN_PASSWORD" } -# upgrade_central_helm_to_head applies the HEAD chart to the existing -# stackrox-central-services release so Scanner V4 is installed. kubectl set -# image does not create V4, and HEAD Central does not use leftover Scanner V2. -upgrade_central_helm_to_head() { +# upgrade_operator_to_head upgrades the operator to the HEAD version +# and resumes central reconciliation so the upgrade is processed. +upgrade_operator_to_head() { local namespace="${1:-stackrox}" local image_tag="${2:-$CURRENT_TAG}" - local registry="${3:-$REGISTRY}" - info "Upgrading central Helm release to HEAD chart with Scanner V4" + info "Upgrading central to HEAD version with Scanner V4" - if ! helm -n "$namespace" status stackrox-central-services >/dev/null 2>&1; then - die "Helm release stackrox-central-services not found in namespace ${namespace}" - fi - - local chart_dir - chart_dir="$(mktemp -d)" - "$TEST_ROOT/bin/$TEST_HOST_PLATFORM/roxctl" helm output central-services \ - --image-defaults opensource \ - --output-dir "${chart_dir}" --remove - - # Retrieve the generated-values secret from installation time. - # The helm chart needs the CA stored there to sign the V4 TLS certs. - local helm_generated_values_file - helm_generated_values_file="$(mktemp)" - local generated_secrets_json - generated_secrets_json="$(kubectl -n "$namespace" get secrets -o json | jq '[.items[] - | select(.metadata.name | startswith("stackrox-generated-")) - | select(.data["generated-values.yaml"] != null)]')" - local generated_secret_count - generated_secret_count="$(jq 'length' <<<"$generated_secrets_json")" - if [[ "$generated_secret_count" -lt 1 ]]; then - die "Expected a Helm generated-values secret in ${namespace}, found 0" - fi - # Helm pre-upgrade hooks use resource-policy=keep, so extra generated-values - # secrets can exist. V4 certs must use the install-time CA in the oldest. - local helm_generated_secret_name - helm_generated_secret_name="$(jq -r 'sort_by(.metadata.creationTimestamp)[0].metadata.name' <<<"$generated_secrets_json")" - if [[ "$generated_secret_count" -gt 1 ]]; then - info "Found ${generated_secret_count} generated-values secrets; using install-time ${helm_generated_secret_name}" - fi - jq -r --arg name "$helm_generated_secret_name" \ - '.[] | select(.metadata.name == $name) | .data["generated-values.yaml"] | @base64d' \ - <<<"$generated_secrets_json" > "$helm_generated_values_file" - if [[ ! -s "$helm_generated_values_file" ]]; then - die "Helm generated-values secret ${helm_generated_secret_name} was empty" - fi - - # 4.6 installs this CRD outside Helm ownership; HEAD templates it. Helm - # refuses the upgrade until the existing CRD is adopted. - if kubectl get crd securitypolicies.config.stackrox.io >/dev/null 2>&1; then - kubectl annotate crd/securitypolicies.config.stackrox.io \ - meta.helm.sh/release-name=stackrox-central-services \ - meta.helm.sh/release-namespace="${namespace}" \ - --overwrite - kubectl label crd/securitypolicies.config.stackrox.io \ - app.kubernetes.io/managed-by=Helm \ - --overwrite - fi - - local helm_extra_args=() - if [[ -n "${SCANNER_V4_DB_STORAGE_CLASS:-}" ]]; then - if [[ "${SCANNER_V4_DB_STORAGE_CLASS}" == "faster" ]]; then - kubectl apply -f "${TEST_ROOT}/deploy/common/ssd-storageclass.yaml" - fi - helm_extra_args+=(--set "scannerV4.db.persistence.persistentVolumeClaim.storageClass=${SCANNER_V4_DB_STORAGE_CLASS}") - fi - # The image walk uses kubectl patch/set, so Helm 4 SSA will not overwrite - # those fields (central-config, CPU/memory) without --force-conflicts. - if helm upgrade --help 2>&1 | grep -q -- '--force-conflicts'; then - helm_extra_args+=(--force-conflicts) - fi + roxie deploy operator --verbose \ + --single-namespace \ + --tag "${image_tag}" - # The chart emits the Scanner V4 DB PVC only when createClaim is true; - # this is an upgrade so .Release.IsInstall is false. # SCANNER_V4_MATCHER_READINESS=vulnerability keeps matcher unready until # the vuln DB is loaded, which wait_for_scanner_V4 then waits on. - helm -n "$namespace" upgrade --reuse-values \ - -f "$helm_generated_values_file" \ - -f - \ - "${helm_extra_args[@]}" \ - stackrox-central-services "${chart_dir}" </tmp/force_rollback_patch local central_config - central_config=$(yq e '.data["central-config.yaml"]' /tmp/force_rollback_patch | yq e ".maintenance.forceRollbackVersion = \"$FORCE_ROLLBACK_VERSION\"" -) + central_config=$(yq e '.data["central-config.yaml"]' /tmp/force_rollback_patch | yq e ".maintenance.forceRollbackVersion = \"${EARLIER_TAG}\"" -) local config_patch config_patch=$(yq e ".data[\"central-config.yaml\"] |= \"$central_config\"" /tmp/force_rollback_patch) echo "config patch: $config_patch" kubectl -n stackrox patch configmap/central-config -p "$config_patch" - kubectl -n stackrox set image deploy/central "central=$REGISTRY/main:$FORCE_ROLLBACK_VERSION" + kubectl -n stackrox set image deploy/central "central=$REGISTRY/main:${EARLIER_TAG}" } validate_sensor_bundle_via_upgrader() { @@ -584,3 +488,35 @@ preamble() { require_executable yq fi } + +deploy_scaled_workload() { + info "Deploying a scaled workload" + + roxie deploy secured-cluster --verbose \ + --single-namespace \ + --tag "${EARLIER_TAG}" \ + --resources ci \ + --pause-reconciliation \ + --early-readiness \ + --set securedCluster.spec.clusterName=scale-remote + + ./scale/launch_workload.sh scale-test + + # The historical scale script requests 5 CPUs per component. Leave room for + # both scanners by reducing Central and Central DB's CPU reservations. + kubectl -n stackrox patch deploy/central --type=strategic -p \ + '{"spec":{"template":{"spec":{"containers":[{"name":"central","resources":{"requests":{"cpu":"2"}}}]}}}}' + # Init-container requests also count toward the pod's CPU reservation. + kubectl -n stackrox patch deploy/central-db --type=strategic -p \ + '{"spec":{"template":{"spec":{"containers":[{"name":"central-db","resources":{"requests":{"cpu":"2"}}}],"initContainers":[{"name":"init-db","resources":{"requests":{"cpu":"2"}}}]}}}}' + wait_for_api + + info "Sleep for a bit to let the scale build" + # shellcheck disable=SC2034 + for i in $(seq 1 150); do + echo -n . + sleep 5 + done + + info "Done with our nap for scaling" +} diff --git a/tests/upgrade/postgres_run.sh b/tests/upgrade/postgres_run.sh index 8d954ee285d85..5e28c565a78fa 100755 --- a/tests/upgrade/postgres_run.sh +++ b/tests/upgrade/postgres_run.sh @@ -7,11 +7,11 @@ set -euo pipefail TEST_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")"/../.. && pwd)" -EARLIER_TAG="4.6.2" -EARLIER_SHA="ecff2a443c8b9a2dc7bf606162da89da81dd8e9e" +EARLIER_TAG="4.10.0" +EARLIER_SHA="7b817fa511ac4533cdf2d79a1b8e04d4d7557ad2" CURRENT_TAG="${MAIN_IMAGE_TAG:-"$(make --quiet --no-print-directory tag)"}" COLLECTOR_TAG="${MAIN_IMAGE_TAG:-"$(make --quiet --no-print-directory collector-tag)"}" -PREVIOUS_RELEASES=("4.6.10" "4.7.9" "4.8.11" "4.9.11" "4.10.7" "4.11.3") +PREVIOUS_RELEASES=("4.10.7" "4.11.3") # shellcheck source=../../scripts/lib.sh source "$TEST_ROOT/scripts/lib.sh" @@ -43,18 +43,13 @@ test_upgrade() { # repo for old version with legacy database REPO_FOR_TIME_TRAVEL="/tmp/rox-postgres-upgrade-test" - DEPLOY_DIR="deploy/k8s" - QUAY_REPO="stackrox-io" + QUAY_REPO="rhacs-eng" REGISTRY="quay.io/$QUAY_REPO" - export OUTPUT_FORMAT="helm" - export STORAGE="pvc" export CLUSTER_TYPE_FOR_TEST=K8S if is_CI; then export ROXCTL_IMAGE_REPO="quay.io/$QUAY_REPO/roxctl" - require_environment "LONGTERM_LICENSE" - export ROX_LICENSE_KEY="${LONGTERM_LICENSE}" fi preamble @@ -76,9 +71,6 @@ test_upgrade_paths() { local log_output_dir="$1" - # To test we remain backwards compatible rollback to 4.6.x - FORCE_ROLLBACK_VERSION="${EARLIER_TAG}" - cd "$REPO_FOR_TIME_TRAVEL" git checkout "$EARLIER_SHA" @@ -89,13 +81,20 @@ test_upgrade_paths() { export MAX_WAIT_SECONDS=600 ######################################################################################## - # Use roxctl to generate helm files and deploy older central # + # Use roxie to deploy older central # ######################################################################################## - deploy_earlier_postgres_central + deploy_earlier_tag_central wait_for_api setup_client_TLS_certs - restore_4_6_backup + # Older checkouts force GOTOOLCHAIN=local during dependency checks. + # Put the toolchain selected for this checkout first on PATH for the build. + # Needed for restore_backup to find roxctl. + local build_goroot + build_goroot="$(go env GOROOT)" + PATH="${build_goroot}/bin:${PATH}" make cli + + restore_backup wait_for_api # Run with some scale to have data populated to migrate @@ -133,8 +132,6 @@ test_upgrade_paths() { kubectl -n stackrox delete po "$(kubectl -n stackrox get po -l app=central -o=jsonpath='{.items[0].metadata.name}')" --grace-period=0 wait_for_api sensor_wait - # Bounce collectors to avoid restarts on initial module pull - kubectl -n stackrox delete pod -l app=collector --grace-period=0 # Verify data is still there checkForPostgresAccessScopes @@ -216,33 +213,36 @@ test_upgrade_paths() { touch "${UPGRADE_PROGRESS_POSTGRES_ROLLBACK}" - # Now go back to the current release. The HEAD chart installs Scanner V4, - # which smoke test needs. - upgrade_central_helm_to_head + # Now go back to the current release. The HEAD installs Scanner V4, + # which smoke test needs. Secured cluster still has reconciliation paused at this point. + upgrade_operator_to_head wait_for_background_migrations # Cleanup the scaled sensor before smoke tests - helm uninstall -n stackrox stackrox-secured-cluster-services + roxie teardown secured-cluster --verbose --single-namespace # Remove scaled Sensor from Central - "$TEST_ROOT/bin/$TEST_HOST_PLATFORM/roxctl" -e "$API_ENDPOINT" --ca "" --insecure-skip-tls-verify cluster delete --name scale-remote + "$TEST_ROOT/bin/$TEST_HOST_PLATFORM/roxctl" cluster delete --name scale-remote - info "Fetching a sensor bundle for cluster 'remote'" + info "Fetching an init bundle for cluster 'remote'" + # This is necessary since the cluster already exists in the database restored from backup, so the CRS + # created by roxie is useless (you cannot re-register a cluster using CRS by design). + # TODO(ROX-37449): switch to just sensor cert when possible. "$TEST_ROOT/bin/$TEST_HOST_PLATFORM/roxctl" version - rm -rf sensor-remote - "$TEST_ROOT/bin/$TEST_HOST_PLATFORM/roxctl" -e "$API_ENDPOINT" --ca "" --insecure-skip-tls-verify sensor get-bundle remote - [[ -d sensor-remote ]] + local init_bundle + init_bundle="$(mktemp)" + "$TEST_ROOT/bin/$TEST_HOST_PLATFORM/roxctl" central init-bundles generate remote --output-secrets - > "${init_bundle}" + kubectl apply -n stackrox -f "${init_bundle}" + rm -f "${init_bundle}" info "Installing sensor" - ./sensor-remote/sensor.sh - kubectl -n stackrox set image deploy/sensor "*=$REGISTRY/main:$CURRENT_TAG" - kubectl -n stackrox set image deploy/admission-control "*=$REGISTRY/main:$CURRENT_TAG" - kubectl -n stackrox set image ds/collector "collector=$REGISTRY/collector:${COLLECTOR_TAG}" \ - "compliance=$REGISTRY/main:$CURRENT_TAG" + roxie deploy secured-cluster --verbose \ + --single-namespace \ + --tag "${CURRENT_TAG}" \ + --resources ci \ + --set securedCluster.spec.clusterName=remote sensor_wait - # Bounce collectors to avoid restarts on initial module pull - kubectl -n stackrox delete pod -l app=collector --grace-period=0 wait_for_central_reconciliation @@ -260,7 +260,7 @@ test_upgrade_paths() { } force_rollback_to_previous_postgres() { - info "Forcing a rollback to $FORCE_ROLLBACK_VERSION" + info "Forcing a rollback to ${EARLIER_TAG}" local upgradeStatus upgradeStatus=$(curl -sSk -X GET --config <(curl_cfg user "admin:${ROX_ADMIN_PASSWORD}") https://"${API_ENDPOINT}"/v1/centralhealth/upgradestatus) @@ -270,7 +270,7 @@ force_rollback_to_previous_postgres() { kubectl -n stackrox get configmap/central-config -o yaml | yq e '{"data": .data}' - >/tmp/force_rollback_patch local central_config - central_config=$(yq e '.data["central-config.yaml"]' /tmp/force_rollback_patch | yq e ".maintenance.forceRollbackVersion = \"$FORCE_ROLLBACK_VERSION\"" -) + central_config=$(yq e '.data["central-config.yaml"]' /tmp/force_rollback_patch | yq e ".maintenance.forceRollbackVersion = \"${EARLIER_TAG}\"" -) local config_patch config_patch=$(yq e ".data[\"central-config.yaml\"] |= \"$central_config\"" /tmp/force_rollback_patch) echo "config patch: $config_patch" @@ -284,43 +284,10 @@ force_rollback_to_previous_postgres() { kubectl -n stackrox set env deploy/sensor ROX_PROCESSES_LISTENING_ON_PORT=false kubectl -n stackrox patch configmap/central-config -p "$config_patch" - kubectl -n stackrox set image deploy/central "central=$REGISTRY/main:$FORCE_ROLLBACK_VERSION" - - # Do not rollback central-db image, since downgrade from PG15 to PG13 is - # not possible. -} - -deploy_scaled_workload() { - info "Deploying a scaled workload" - - PATH="bin/$TEST_HOST_PLATFORM:$PATH" roxctl version - - PATH="bin/$TEST_HOST_PLATFORM:$PATH" roxctl helm output secured-cluster-services --image-defaults opensource --output-dir /tmp/early-stackrox-secured-services-chart --remove - - PATH="bin/$TEST_HOST_PLATFORM:$PATH" roxctl -e "$API_ENDPOINT" central init-bundles generate scale-remote --output /tmp/cluster-init-bundle.yaml - - helm install -n stackrox --create-namespace \ - stackrox-secured-cluster-services /tmp/early-stackrox-secured-services-chart \ - -f /tmp/cluster-init-bundle.yaml \ - --set system.enablePodSecurityPolicies=false \ - --set clusterName=scale-remote \ - --set image.main.tag="${EARLIER_TAG}" \ - --set image.collector.tag="${EARLIER_TAG}" \ - --set centralEndpoint="$API_ENDPOINT" - - sensor_wait - - ./scale/launch_workload.sh scale-test - wait_for_api - - info "Sleep for a bit to let the scale build" - # shellcheck disable=SC2034 - for i in $(seq 1 150); do - echo -n . - sleep 5 - done + kubectl -n stackrox set image deploy/central "central=$REGISTRY/main:${EARLIER_TAG}" - info "Done with our nap for scaling" + # Keep the upgraded central-db image when rolling Central back, since the + # upgraded data directory cannot be used by an older PostgreSQL major version. } if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then diff --git a/tests/upgrade/postgres_upgrade_run.sh b/tests/upgrade/postgres_upgrade_run.sh index 28c1e62969ece..be6b603515778 100755 --- a/tests/upgrade/postgres_upgrade_run.sh +++ b/tests/upgrade/postgres_upgrade_run.sh @@ -3,29 +3,67 @@ set -euo pipefail -# Tests upgrade to Postgres. +# Tests PostgreSQL major-version upgrades. TEST_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")"/../.. && pwd)" -EARLIER_TAG="4.7.2" -EARLIER_SHA="ef2060ed332c7b8513cb9eb52b9745df9a8285cc" -CURRENT_TAG="${MAIN_IMAGE_TAG:-"$(make --quiet --no-print-directory tag)"}" -PREVIOUS_RELEASES=("4.7.3") +EARLIER_TAG="4.10.0" +EARLIER_SHA="7b817fa511ac4533cdf2d79a1b8e04d4d7557ad2" # shellcheck source=../../scripts/lib.sh source "$TEST_ROOT/scripts/lib.sh" -# shellcheck source=../../scripts/ci/lib.sh -source "$TEST_ROOT/scripts/ci/lib.sh" -# shellcheck source=../../scripts/ci/sensor-wait.sh -source "$TEST_ROOT/scripts/ci/sensor-wait.sh" -# shellcheck source=../../scripts/setup-certs.sh -source "$TEST_ROOT/tests/scripts/setup-certs.sh" -# shellcheck source=../../tests/e2e/lib.sh -source "$TEST_ROOT/tests/e2e/lib.sh" -# shellcheck source=../../tests/upgrade/lib.sh -source "$TEST_ROOT/tests/upgrade/lib.sh" -# shellcheck source=../../tests/upgrade/validation.sh -source "$TEST_ROOT/tests/upgrade/validation.sh" + +postgres_major_version() { + # Current images use ARG PG_VERSION; older releases put the major directly in FROM. + local version + version="$(sed -n \ + -e 's/^[[:space:]]*ARG[[:space:]]\+PG_VERSION=\([1-9][0-9]*\)[[:space:]]*$/\1/p' \ + -e 's/^[[:space:]]*FROM[[:space:]].*\/postgresql-\([1-9][0-9]*\)-.*$/\1/p')" + # Missing or ambiguous versions must fail the check, not silently skip coverage. + [[ "$version" =~ ^[1-9][0-9]*$ ]] || return 1 + echo "$version" +} + +check_postgres_upgrade() { + local earlier_version current_version + earlier_version="$(git -C "$TEST_ROOT" show "$EARLIER_SHA:image/postgres/Dockerfile" | postgres_major_version)" || \ + die "Cannot determine PostgreSQL major version for $EARLIER_TAG ($EARLIER_SHA)" + current_version="$(postgres_major_version < "$TEST_ROOT/image/postgres/Dockerfile")" || \ + die "Cannot determine PostgreSQL major version for the current checkout" + + EARLIER_POSTGRES_VERSION="$earlier_version" + CURRENT_POSTGRES_VERSION="$current_version" + + POSTGRES_UPGRADE_REQUIRED=false + if (( current_version > earlier_version )); then + POSTGRES_UPGRADE_REQUIRED=true + POSTGRES_UPGRADE_REASON="Running PostgreSQL upgrade suite: $EARLIER_TAG uses PostgreSQL $earlier_version; current checkout uses PostgreSQL $current_version." + else + POSTGRES_UPGRADE_REASON="Skipping PostgreSQL upgrade suite: $EARLIER_TAG uses PostgreSQL $earlier_version; current checkout uses PostgreSQL $current_version. No major-version upgrade." + fi + info "$POSTGRES_UPGRADE_REASON" +} + +check_postgres_version() { + local expected_version="$1" + local db_password actual_version + + kubectl -n stackrox rollout status deployment/central-db --timeout="${MAX_WAIT_SECONDS:-300}s" || \ + die "Central DB rollout did not complete" + + db_password="$(kubectl -n stackrox get secret central-db-password -o jsonpath='{.data.password}' | base64 -d)" || \ + die "Cannot read the Central DB password" + + # Pass the password on stdin so it does not appear in the exec command. + # shellcheck disable=SC2016 + actual_version="$(kubectl -n stackrox exec -i deploy/central-db -c central-db -- \ + bash -c 'PGPASSWORD="$(cat)" \ + psql -X -w -h 127.0.0.1 -U postgres -d postgres -v ON_ERROR_STOP=1 -Atc "SHOW server_version"' <<< "$db_password")" || \ + die "Cannot query the running PostgreSQL version" + + info "Central DB is running PostgreSQL $actual_version; expected major version $expected_version" + test_equals_non_silent "${actual_version%%.*}" "$expected_version" +} test_upgrade() { info "Starting postgres upgrade test" @@ -42,18 +80,13 @@ test_upgrade() { # repo for old version with legacy database REPO_FOR_TIME_TRAVEL="/tmp/rox-postgres-upgrade-test" - DEPLOY_DIR="deploy/k8s" - QUAY_REPO="stackrox-io" + QUAY_REPO="rhacs-eng" REGISTRY="quay.io/$QUAY_REPO" - export OUTPUT_FORMAT="helm" - export STORAGE="pvc" export CLUSTER_TYPE_FOR_TEST=K8S if is_CI; then export ROXCTL_IMAGE_REPO="quay.io/$QUAY_REPO/roxctl" - require_environment "LONGTERM_LICENSE" - export ROX_LICENSE_KEY="${LONGTERM_LICENSE}" fi preamble @@ -65,7 +98,7 @@ test_upgrade() { test_upgrade_path "$log_output_dir" - remove_existing_stackrox_resources + roxie teardown both --verbose --single-namespace test_not_enough_disk_space "$log_output_dir" } @@ -79,8 +112,6 @@ test_upgrade_path() { local log_output_dir="$1" - FORCE_ROLLBACK_VERSION="4.7.2" - cd "$REPO_FOR_TIME_TRAVEL" git checkout "$EARLIER_SHA" @@ -91,15 +122,23 @@ test_upgrade_path() { export MAX_WAIT_SECONDS=600 ######################################################################################## - # Use roxctl to generate helm files and deploy older central # + # Use roxie to deploy older central # ######################################################################################## - deploy_earlier_postgres_central + deploy_earlier_tag_central wait_for_api + check_postgres_version "$EARLIER_POSTGRES_VERSION" setup_client_TLS_certs + # Older checkouts force GOTOOLCHAIN=local during dependency checks. + # Put the toolchain selected for this checkout first on PATH for the build. + # Needed for restore_backup to find roxctl. + local build_goroot + build_goroot="$(go env GOROOT)" + PATH="${build_goroot}/bin:${PATH}" make cli + # It's damn fiddly, restore is needed because later test will search for a # default secured cluster, created by it :( - restore_4_6_backup + restore_backup wait_for_api # Run with some scale to have data populated to migrate @@ -133,11 +172,12 @@ test_upgrade_path() { # Extend the MUTEX timeout for this case as a restart of the db will cause locks to be held longer as it should kubectl -n stackrox set env deploy/central MUTEX_WATCHDOG_TIMEOUT_SECS=600 - # Upgrade the image to PG15 + # Upgrade the image to PG16 info "Upgrade ${EARLIER_TAG} => ${CURRENT_TAG}" kubectl -n stackrox set image deploy/central "*=${REGISTRY}/main:${CURRENT_TAG}" kubectl -n stackrox set image deploy/central-db "*=${REGISTRY}/central-db:${CURRENT_TAG}" wait_for_api + check_postgres_version "$CURRENT_POSTGRES_VERSION" ######################################################################################## # Bounce central to ensure everything starts back up. # @@ -146,8 +186,6 @@ test_upgrade_path() { kubectl -n stackrox delete po "$(kubectl -n stackrox get po -l app=central -o=jsonpath='{.items[0].metadata.name}')" --grace-period=0 wait_for_api sensor_wait - # Bounce collectors to avoid restarts on initial module pull - kubectl -n stackrox delete pod -l app=collector --grace-period=0 # Verify data is still there checkForPostgresAccessScopes @@ -165,6 +203,7 @@ test_upgrade_path() { kubectl -n stackrox delete po "$(kubectl -n stackrox get po -l app=central-db -o=jsonpath='{.items[0].metadata.name}')" --grace-period=0 wait_for_api wait_for_central_db + check_postgres_version "$CURRENT_POSTGRES_VERSION" # Verify data is still there checkForPostgresAccessScopes @@ -191,8 +230,6 @@ test_not_enough_disk_space() { local log_output_dir="$1" - FORCE_ROLLBACK_VERSION="4.7.2" - cd "$REPO_FOR_TIME_TRAVEL" git checkout "$EARLIER_SHA" @@ -205,25 +242,52 @@ test_not_enough_disk_space() { ######################################################################################## # Deploy older central using small PVC to face disk space shortage # ######################################################################################## - PVC_SIZE="1Gi" - deploy_earlier_postgres_central - unset PVC_SIZE + deploy_earlier_tag_central \ + --set central.spec.central.db.persistence.persistentVolumeClaim.size=1Gi wait_for_api + check_postgres_version "$EARLIER_POSTGRES_VERSION" setup_client_TLS_certs # It's damn fiddly, restore is needed because later test will search for a # default secured cluster, created by it :( - restore_4_6_backup + restore_backup wait_for_api - # Do not apply scaled workload to control disk space, do fallocate instead - kubectl -n stackrox exec -it deploy/central-db -- \ - fallocate -l 700mb "/var/lib/postgresql/data/pgdata/fake_data" - kubectl -n stackrox exec -it deploy/central-db -- \ - bash -c 'df "${PGDATA}" -H' - kubectl -n stackrox exec -it deploy/central-db -- \ - bash -c 'du -sch "${PGDATA}"/*' + # The 4.10 deployment mounts the backup PVC only in init-db. Expose the same + # volume to central-db so the running container can fill it before upgrading. + kubectl -n stackrox patch deployment/central-db --type=strategic -p \ + '{"spec":{"template":{"spec":{"containers":[{"name":"central-db","volumeMounts":[{"name":"backup","mountPath":"/var/lib/postgresql/backup"}]}]}}}}' + kubectl -n stackrox rollout status deployment/central-db --timeout="${MAX_WAIT_SECONDS}s" + wait_for_api + # Fill both PVCs: the operator creates a separate backup PVC twice the data PVC size. + # Neither backup location should have room for a backup and its verification copy. + # Expand PGDATA inside the container, and use the same KiB units as the entrypoint. + # shellcheck disable=SC2016 + kubectl -n stackrox exec deploy/central-db -c central-db -- bash -euo pipefail -c ' + for location in /var/lib/postgresql/data /var/lib/postgresql/backup; do + mounted_at=$(df -Pk "$location" | awk "END {print \$6}") + if [[ "$mounted_at" != "$location" ]]; then + echo "Expected a volume mounted at $location, found $mounted_at" >&2 + exit 1 + fi + done + + fallocate -l 700mb "${PGDATA}/fake_data" + fallocate -l 1GiB /var/lib/postgresql/backup/fake_data + df -H "$PGDATA" /var/lib/postgresql/backup + du -sch "$PGDATA"/* /var/lib/postgresql/backup/fake_data + + required=$(du -sk "$PGDATA" | awk "{print \$1 * 2}") + for location in /var/lib/postgresql/data /var/lib/postgresql/backup; do + available=$(df -Pk "$location" | awk "END {print \$4}") + echo "$location: $available KiB available; $required KiB required for backup and verification" + if (( available >= required )); then + echo "Low-space fixture still has enough space at $location" >&2 + exit 1 + fi + done + ' # Get the API_TOKEN for the upgrades export API_TOKEN="$(roxcurl /v1/apitokens/generate -d '{"name": "helm-upgrade-test", "role": "Admin"}' | jq -r '.token')" @@ -253,7 +317,7 @@ test_not_enough_disk_space() { # Extend the MUTEX timeout for this case as a restart of the db will cause locks to be held longer as it should kubectl -n stackrox set env deploy/central MUTEX_WATCHDOG_TIMEOUT_SECS=600 - # Upgrade the image to PG15 + # Upgrade the image to PG16 info "Upgrade ${EARLIER_TAG} => ${CURRENT_TAG}" kubectl -n stackrox set image \ deploy/central "*=${REGISTRY}/main:${CURRENT_TAG}" @@ -266,83 +330,42 @@ test_not_enough_disk_space() { '{"spec": {"resources": {"requests": {"storage": "4Gi"}}}}' kubectl -n stackrox rollout restart deployment/central-db wait_for_api + check_postgres_version "$CURRENT_POSTGRES_VERSION" # Make sure we can restore from a physical backup and run with old binaries # after upgrade if needed. - kubectl -n stackrox set env deploy/central-db RESTORE_BACKUP=true - kubectl -n stackrox set env deploy/central-db FORCE_OLD_BINARIES=true + kubectl -n stackrox set env deploy/central-db RESTORE_BACKUP=true FORCE_OLD_BINARIES=true wait_for_api + check_postgres_version "$EARLIER_POSTGRES_VERSION" collect_and_check_stackrox_logs "$log_output_dir" "disk_space_01_final" } -force_rollback_to_previous_postgres() { - info "Forcing a rollback to $FORCE_ROLLBACK_VERSION" - - local upgradeStatus - upgradeStatus=$(curl -sSk -X GET --config <(curl_cfg user "admin:${ROX_ADMIN_PASSWORD}") https://"${API_ENDPOINT}"/v1/centralhealth/upgradestatus) - echo "upgrade status: ${upgradeStatus}" - test_equals_non_silent "$(echo "$upgradeStatus" | jq '.upgradeStatus.version' -r)" "${CURRENT_TAG}" - test_equals_non_silent "$(echo "$upgradeStatus" | jq '.upgradeStatus.canRollbackAfterUpgrade' -r)" "true" - - kubectl -n stackrox get configmap/central-config -o yaml | yq e '{"data": .data}' - >/tmp/force_rollback_patch - local central_config - central_config=$(yq e '.data["central-config.yaml"]' /tmp/force_rollback_patch | yq e ".maintenance.forceRollbackVersion = \"$FORCE_ROLLBACK_VERSION\"" -) - local config_patch - config_patch=$(yq e ".data[\"central-config.yaml\"] |= \"$central_config\"" /tmp/force_rollback_patch) - echo "config patch: $config_patch" - - # downgrading to a version that does not understand process listening on ports - # so turning that off in sensor and collector to prevent central crashes. - # Sensor and Collector will be deleted a few steps after this so no need - # to turn these back on. Going forward unexpected messages will result in - # an `UNEXPECTED` log instead of crashing central. However that change is - # not present in the initial 3.74 version. - kubectl -n stackrox set env deploy/sensor ROX_PROCESSES_LISTENING_ON_PORT=false - - kubectl -n stackrox patch configmap/central-config -p "$config_patch" - kubectl -n stackrox set image deploy/central "central=$REGISTRY/main:$FORCE_ROLLBACK_VERSION" - - # Do not rollback central-db image, since downgrade from PG15 to PG13 is - # not possible. -} - -deploy_scaled_workload() { - info "Deploying a scaled workload" - WAIT_ITERATIONS="${1:-150}" - - PATH="bin/$TEST_HOST_PLATFORM:$PATH" roxctl version - - PATH="bin/$TEST_HOST_PLATFORM:$PATH" roxctl helm output secured-cluster-services --image-defaults opensource --output-dir /tmp/early-stackrox-secured-services-chart --remove - - # Make sure no init bundle from previous runs is there - rm -f /tmp/cluster-init-bundle.yaml - PATH="bin/$TEST_HOST_PLATFORM:$PATH" roxctl -e "$API_ENDPOINT" central init-bundles generate scale-remote --output /tmp/cluster-init-bundle.yaml - - helm install -n stackrox --create-namespace \ - stackrox-secured-cluster-services /tmp/early-stackrox-secured-services-chart \ - -f /tmp/cluster-init-bundle.yaml \ - --set system.enablePodSecurityPolicies=false \ - --set clusterName=scale-remote \ - --set image.main.tag="${EARLIER_TAG}" \ - --set image.collector.tag="${EARLIER_TAG}" \ - --set centralEndpoint="$API_ENDPOINT" - - sensor_wait - - ./scale/launch_workload.sh scale-test - wait_for_api - - info "Sleep for a bit to let the scale build" - # shellcheck disable=SC2034 - for i in $(seq 1 $WAIT_ITERATIONS); do - echo -n . - sleep 5 - done - - info "Done with our nap for scaling" -} - if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then - test_upgrade "$*" + check_postgres_upgrade + if [[ "${1:-}" == "--check" ]]; then + # CI checks eligibility before provisioning a cluster or running pre/post-test hooks. + if [[ -n "${GITHUB_OUTPUT:-}" ]]; then + echo "required=$POSTGRES_UPGRADE_REQUIRED" >> "$GITHUB_OUTPUT" + fi + if [[ -n "${GITHUB_STEP_SUMMARY:-}" ]]; then + echo "$POSTGRES_UPGRADE_REASON" >> "$GITHUB_STEP_SUMMARY" + fi + elif [[ "$POSTGRES_UPGRADE_REQUIRED" == true ]]; then + CURRENT_TAG="${MAIN_IMAGE_TAG:-"$(make --quiet --no-print-directory tag)"}" + # Load deployment helpers only when the suite will actually run. + # shellcheck source=../../scripts/ci/lib.sh + source "$TEST_ROOT/scripts/ci/lib.sh" + # shellcheck source=../../scripts/ci/sensor-wait.sh + source "$TEST_ROOT/scripts/ci/sensor-wait.sh" + # shellcheck source=../../scripts/setup-certs.sh + source "$TEST_ROOT/tests/scripts/setup-certs.sh" + # shellcheck source=../../tests/e2e/lib.sh + source "$TEST_ROOT/tests/e2e/lib.sh" + # shellcheck source=../../tests/upgrade/lib.sh + source "$TEST_ROOT/tests/upgrade/lib.sh" + # shellcheck source=../../tests/upgrade/validation.sh + source "$TEST_ROOT/tests/upgrade/validation.sh" + test_upgrade "$@" + fi fi diff --git a/tests/versions_test.go b/tests/versions_test.go index 28f99014f663d..29eafba439517 100644 --- a/tests/versions_test.go +++ b/tests/versions_test.go @@ -5,6 +5,7 @@ package tests import ( "encoding/json" "net/http" + "strings" "testing" "github.com/stackrox/rox/pkg/testutils/centralgrpc" @@ -26,12 +27,16 @@ func TestVersions(t *testing.T) { var versions version.Versions require.NoError(t, json.NewDecoder(resp.Body).Decode(&versions)) - kind := version.GetVersionKind(versions.MainVersion) - require.NotEqualf(t, version.InvalidKind, kind, "invalid main version %s", versions.MainVersion) + mainVersion := versions.MainVersion + if usingKonfluxImages() { + mainVersion = strings.TrimSuffix(mainVersion, "-fast") + } + + kind := version.GetVersionKind(mainVersion) + require.NotEqualf(t, version.InvalidKind, kind, "invalid main version %s", mainVersion) if kind == version.DevelopmentKind || kind == version.NightlyKind { t.Skip("nothing to be checked on development versions") } assert.Equal(t, kind, version.GetVersionKind(versions.CollectorVersion), "rc and release builds should reference a corresponding collector version") - assert.Equal(t, kind, version.GetVersionKind(versions.ScannerVersion), "rc and release builds should reference a corresponding scanner version") } diff --git a/tests/vm_scanning_suite_test.go b/tests/vm_scanning_suite_test.go index c2266513aa0cd..f529470ab7e9b 100644 --- a/tests/vm_scanning_suite_test.go +++ b/tests/vm_scanning_suite_test.go @@ -200,9 +200,9 @@ func (s *VMScanningSuite) TearDownSuite() { defer s.cancel() } - // When VM_SCAN_SKIP_CLEANUP is set, leave VMs and the namespace intact so a - // developer can SSH into the guests or inspect cluster state after a failure - // without having to re-provision from scratch. + // When VM_SCAN_SKIP_CLEANUP is set, skip VM/namespace deletion here so CI + // post-test can collect guest journals first; local runs use this to debug + // without re-provisioning. if s.cfg != nil && s.cfg.SkipCleanup { s.logf("teardown: VM_SCAN_SKIP_CLEANUP is set — skipping VM and namespace deletion (VMs and namespace left intact for debugging)") s.closeConn() diff --git a/tests/vm_scanning_test.go b/tests/vm_scanning_test.go index 28d44ff6f9ae8..d495dc82a373c 100644 --- a/tests/vm_scanning_test.go +++ b/tests/vm_scanning_test.go @@ -169,13 +169,10 @@ func (s *VMScanningSuite) TestScanPipeline() { } distinct := distinctCVEIDs(cves) - require.Equal(t, int32(len(distinct)), vmhelpers.VulnCountBySeverityTotal(listed.GetCveSeverityCounts()), - "ListVMs.cveSeverityCounts totals must match distinct CVEs from ListVMCVEsByVM") - summary, err := s.vmV2Client.GetVMVulnSummary(s.ctx, &v2.GetVMVulnSummaryRequest{Id: snapshot.ID}) require.NoError(t, err) - require.Equal(t, int32(len(distinct)), vmhelpers.VulnCountBySeverityTotal(summary.GetSeverityCounts()), - "GetVMVulnSummary severity totals must match distinct CVEs from ListVMCVEsByVM") + requireChipsAgree(t, listed.GetCveSeverityCounts(), summary.GetSeverityCounts()) + requireChipsCoverTable(t, listed.GetCveSeverityCounts(), cves, len(distinct)) }) t.Run("VirtualMachineV2ListVMCVEsByVM", func(t *testing.T) { @@ -330,6 +327,49 @@ func requireForwardedAgentFacts(t *testing.T, facts map[string]string) { "facts.agentVersion should be the roxagent version from ResponseMeta") } +// requireChipsAgree checks ListVMs and GetVMVulnSummary use the same chip grain. +func requireChipsAgree(t *testing.T, listed, summary *v2.VulnCountBySeverity) { + t.Helper() + require.Equal(t, listed.GetCritical().GetTotal(), summary.GetCritical().GetTotal(), "critical") + require.Equal(t, listed.GetImportant().GetTotal(), summary.GetImportant().GetTotal(), "important") + require.Equal(t, listed.GetModerate().GetTotal(), summary.GetModerate().GetTotal(), "moderate") + require.Equal(t, listed.GetLow().GetTotal(), summary.GetLow().GetTotal(), "low") + require.Equal(t, listed.GetUnknown().GetTotal(), summary.GetUnknown().GetTotal(), "unknown") + require.Equal(t, listed.GetCritical().GetFixable(), summary.GetCritical().GetFixable(), "critical fixable") + require.Equal(t, listed.GetImportant().GetFixable(), summary.GetImportant().GetFixable(), "important fixable") + require.Equal(t, listed.GetModerate().GetFixable(), summary.GetModerate().GetFixable(), "moderate fixable") + require.Equal(t, listed.GetLow().GetFixable(), summary.GetLow().GetFixable(), "low fixable") + require.Equal(t, listed.GetUnknown().GetFixable(), summary.GetUnknown().GetFixable(), "unknown fixable") +} + +// requireChipsCoverTable allows a CVE in more than one severity chip, matching +// imageCVECountBySeverity. Each chip still covers table rows at that severity +// and cannot exceed the distinct CVE count. +func requireChipsCoverTable(t *testing.T, chips *v2.VulnCountBySeverity, tableRows []*v2.VMCVERow, distinct int) { + t.Helper() + table := vmhelpers.CountVMCVERowsBySeverity(tableRows) + require.GreaterOrEqual(t, vmhelpers.VulnCountBySeverityTotal(chips), int32(distinct), + "chip total must cover distinct ListVMCVEsByVM CVE IDs") + for _, tc := range []struct { + name string + chip *v2.VulnFixableCount + table *v2.VulnFixableCount + }{ + {"critical", chips.GetCritical(), table.GetCritical()}, + {"important", chips.GetImportant(), table.GetImportant()}, + {"moderate", chips.GetModerate(), table.GetModerate()}, + {"low", chips.GetLow(), table.GetLow()}, + {"unknown", chips.GetUnknown(), table.GetUnknown()}, + } { + require.GreaterOrEqual(t, tc.chip.GetTotal(), tc.table.GetTotal(), + "%s chip must cover table rows at that severity", tc.name) + require.LessOrEqual(t, tc.chip.GetTotal(), int32(distinct), + "%s chip cannot exceed distinct CVE IDs", tc.name) + require.LessOrEqual(t, tc.chip.GetFixable(), tc.chip.GetTotal(), + "%s fixable cannot exceed that chip total", tc.name) + } +} + func distinctCVEIDs(cves []*v2.VMCVERow) []string { seen := make(map[string]struct{}, len(cves)) ids := make([]string, 0, len(cves)) diff --git a/tests/vmhelpers/central_v2.go b/tests/vmhelpers/central_v2.go index eb3448cea1ac2..d74569860e47e 100644 --- a/tests/vmhelpers/central_v2.go +++ b/tests/vmhelpers/central_v2.go @@ -248,6 +248,38 @@ func VulnCountBySeverityTotal(c *v2.VulnCountBySeverity) int32 { return n } +// CountVMCVERowsBySeverity counts ListVMCVEsByVM rows by the severity shown on +// each row (max severity for that CVE). +func CountVMCVERowsBySeverity(cves []*v2.VMCVERow) *v2.VulnCountBySeverity { + out := &v2.VulnCountBySeverity{} + for _, row := range cves { + b := severityBucket(out, row.GetSeverity()) + b.Total++ + if row.GetIsFixable() { + b.Fixable++ + } + } + return out +} + +func severityBucket(c *v2.VulnCountBySeverity, sev v2.VulnerabilitySeverity) *v2.VulnFixableCount { + ptr := &c.Unknown + switch sev { + case v2.VulnerabilitySeverity_CRITICAL_VULNERABILITY_SEVERITY: + ptr = &c.Critical + case v2.VulnerabilitySeverity_IMPORTANT_VULNERABILITY_SEVERITY: + ptr = &c.Important + case v2.VulnerabilitySeverity_MODERATE_VULNERABILITY_SEVERITY: + ptr = &c.Moderate + case v2.VulnerabilitySeverity_LOW_VULNERABILITY_SEVERITY: + ptr = &c.Low + } + if *ptr == nil { + *ptr = &v2.VulnFixableCount{} + } + return *ptr +} + // WaitForV2ScanMissingComponent polls until packageName is absent from a scan // whose latest_scan.scan_time has advanced at least minScanAdvances times past after. func WaitForV2ScanMissingComponent( diff --git a/tests/vmhelpers/central_v2_test.go b/tests/vmhelpers/central_v2_test.go index 666271ce1ef39..bafa2ff5f4bff 100644 --- a/tests/vmhelpers/central_v2_test.go +++ b/tests/vmhelpers/central_v2_test.go @@ -340,6 +340,35 @@ func TestVulnCountBySeverityTotal(t *testing.T) { } } +func TestCountVMCVERowsBySeverity(t *testing.T) { + tests := map[string]struct { + in []*v2.VMCVERow + want *v2.VulnCountBySeverity + }{ + "empty": {in: nil, want: &v2.VulnCountBySeverity{}}, + "by max severity": {in: []*v2.VMCVERow{ + {Cve: "CVE-1", Severity: v2.VulnerabilitySeverity_CRITICAL_VULNERABILITY_SEVERITY, IsFixable: true}, + {Cve: "CVE-2", Severity: v2.VulnerabilitySeverity_MODERATE_VULNERABILITY_SEVERITY}, + {Cve: "CVE-3", Severity: v2.VulnerabilitySeverity_MODERATE_VULNERABILITY_SEVERITY, IsFixable: true}, + }, want: &v2.VulnCountBySeverity{ + Critical: &v2.VulnFixableCount{Total: 1, Fixable: 1}, + Moderate: &v2.VulnFixableCount{Total: 2, Fixable: 1}, + }}, + } + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + got := CountVMCVERowsBySeverity(tc.in) + require.Equal(t, tc.want.GetCritical().GetTotal(), got.GetCritical().GetTotal()) + require.Equal(t, tc.want.GetCritical().GetFixable(), got.GetCritical().GetFixable()) + require.Equal(t, tc.want.GetImportant().GetTotal(), got.GetImportant().GetTotal()) + require.Equal(t, tc.want.GetModerate().GetTotal(), got.GetModerate().GetTotal()) + require.Equal(t, tc.want.GetModerate().GetFixable(), got.GetModerate().GetFixable()) + require.Equal(t, tc.want.GetLow().GetTotal(), got.GetLow().GetTotal()) + require.Equal(t, tc.want.GetUnknown().GetTotal(), got.GetUnknown().GetTotal()) + }) + } +} + func TestWaitForV2ScanMissingComponent(t *testing.T) { ctx := t.Context() opts := WaitOptions{Timeout: 400 * time.Millisecond, PollInterval: 5 * time.Millisecond} diff --git a/tools/generate-helpers/config-as-code-helper/main.go b/tools/generate-helpers/config-as-code-helper/main.go index cba3d849424c0..5b69d7f5b28de 100644 --- a/tools/generate-helpers/config-as-code-helper/main.go +++ b/tools/generate-helpers/config-as-code-helper/main.go @@ -83,19 +83,31 @@ func generateTemplateData(t reflect.Type, visited set.StringSet) []ConvertType { continue } + if _, ok := field.Tag.Lookup("protobuf_oneof"); ok { + continue + } + fieldType := field.Type.String() isSlice := strings.HasPrefix(fieldType, "[]") isStringer := strings.Contains(yamlTag, ",stringer") if isStringer { yamlTag = strings.Replace(yamlTag, ",stringer", "", 1) fieldType = utils.IfThenElse(isSlice, "[]string", "string") + needUpdate = true } isTimeStamp := strings.Contains(yamlTag, ",timestamp") if isTimeStamp { yamlTag = strings.Replace(yamlTag, ",timestamp", "", 1) fieldType = utils.IfThenElse(isSlice, "[]string", "string") + needUpdate = true } + // A stringer or timestamp field is rewritten as a string. A message that + // contains only those fields still needs its own converted type, otherwise + // the parent embeds the proto and YAML uses the Go field name and wire value. + if isStringer || isTimeStamp { + needUpdate = true + } needConversion := !isStringer && !isTimeStamp && checkForConversion(field) if needConversion { if !visited.Contains(field.Name) { @@ -120,6 +132,41 @@ func generateTemplateData(t reflect.Type, visited set.StringSet) []ConvertType { NeedConversion: needConversion, }) } + + if typeName == "Exclusion" { + // Oneof arms are not exported fields on Exclusion (Matcher is an + // interface). Flatten them using the same crYaml tags as the proto. + for _, extra := range []struct { + name string + yamlTag string + typ reflect.Type + }{ + {"Deployment", ",omitempty", reflect.TypeFor[*storage.Exclusion_Deployment]()}, + {"ExcludeByKind", "excludeByKind,omitempty", reflect.TypeFor[*storage.Exclusion_ExcludeByKind]()}, + } { + fieldType := extra.typ.String() + needConversion := protoreflect.IsProtoMessage(getBaseType(extra.typ)) + if needConversion { + if !visited.Contains(extra.name) { + newList := generateTemplateData(getBaseType(extra.typ), visited) + conversionList = append(conversionList, newList...) + if len(newList) == 0 { + needConversion = false + } + } + needUpdate = true + } + fields = append(fields, Field{ + Name: extra.name, + Type: fieldType, + TrimmedType: strings.Replace(fieldType, "storage.", "", 1), + BaseType: getBaseType(extra.typ).Name(), + YamlTag: extra.yamlTag, + NeedConversion: needConversion, + }) + } + } + if needUpdate { conversionList = append(conversionList, ConvertType{ Fields: fields, diff --git a/tools/generate-helpers/config-as-code-helper/policy.go.tpl b/tools/generate-helpers/config-as-code-helper/policy.go.tpl index 2f012b7c93f76..67f64ad0baeaa 100644 --- a/tools/generate-helpers/config-as-code-helper/policy.go.tpl +++ b/tools/generate-helpers/config-as-code-helper/policy.go.tpl @@ -27,9 +27,9 @@ func convert{{.TypeName}}(p *storage.{{.TypeName}}) *{{.TypeName}} { return &{{.TypeName}}{ {{- range .Fields }} - {{- $fieldName := printf "p.%s" .Name }} + {{- $fieldName := printf "p.Get%s()" .Name }} {{- if .IsTimestamp }} - {{- $fieldName = printf "timestampToFormatRFC3339(%s)" $fieldName }} + {{- $fieldName = printf "timestampToFormatRFC3339(p.Get%s())" .Name }} {{- end }} {{ .Name }}: {{- if .IsStringer -}} diff --git a/tools/generate-helpers/release-versions/main.go b/tools/generate-helpers/release-versions/main.go new file mode 100644 index 0000000000000..22fb7efc69d08 --- /dev/null +++ b/tools/generate-helpers/release-versions/main.go @@ -0,0 +1,308 @@ +// release-versions generates initial-release database sequences from Git tags. +package main + +import ( + "bytes" + "errors" + "flag" + "fmt" + "go/ast" + "go/format" + "go/parser" + "go/token" + "maps" + "os" + "os/exec" + "path/filepath" + "regexp" + "slices" + "strconv" + "strings" + + "github.com/stackrox/rox/pkg/version/productstreams" +) + +const sequencePath = "pkg/migrations/internal/seq_num.go" + +var initialRelease = regexp.MustCompile(`^[1-9][0-9]*\.(0|[1-9][0-9]*)\.0(-rc\.(0|[1-9][0-9]*))?$`) + +func main() { + target := flag.String("target", "", "target version (defaults to make tag)") + flag.Parse() + if err := run(*target); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} + +func command(dir, name string, args ...string) (string, error) { + cmd := exec.Command(name, args...) + cmd.Dir = dir + var stderr bytes.Buffer + cmd.Stderr = &stderr + data, err := cmd.Output() + if err != nil { + return "", fmt.Errorf("%s %v: %w: %s", name, args, err, stderr.String()) + } + return string(data), nil +} + +func run(target string) error { + root, err := command("", "git", "rev-parse", "--show-toplevel") + if err != nil { + return fmt.Errorf("find repository root: %w", err) + } + dir := strings.TrimSpace(root) + if target == "" { + data, err := command(dir, "make", "--quiet", "--no-print-directory", "tag") + if err != nil { + return fmt.Errorf("determine target version with make tag: %w", err) + } + target = strings.TrimSpace(data) + } + data, err := generate(dir, target) + if err != nil { + return fmt.Errorf("generate release versions: %w", err) + } + outputPath := filepath.Join(dir, "pkg/migrations/release_versions.go") + if err := os.WriteFile(outputPath, data, 0644); err != nil { + return fmt.Errorf("write generated release versions to %s: %w", outputPath, err) + } + return nil +} + +func generate(dir, target string) ([]byte, error) { + targetXy, err := parseTargetStream(target) + if err != nil { + return nil, err + } + tags, err := listReleaseTags(dir) + if err != nil { + return nil, err + } + releaseTags, err := selectReleaseTags(tags, targetXy) + if err != nil { + return nil, err + } + sequences, err := readReleaseSequences(dir, releaseTags) + if err != nil { + return nil, err + } + if err := ensureTargetSequence(dir, target, targetXy, sequences); err != nil { + return nil, err + } + streams, err := validateReleaseSequences(target, targetXy, sequences) + if err != nil { + return nil, err + } + return renderReleaseVersions(streams, sequences) +} + +func parseTargetStream(target string) (productstreams.XYVersion, error) { + targetXy, err := productstreams.ParseXYFromVersionString(target) + if err != nil { + return productstreams.XYVersion{}, fmt.Errorf("parse target stream from %q: %w", target, err) + } + if err := validateReleaseStream(targetXy); err != nil { + return productstreams.XYVersion{}, fmt.Errorf("validate target stream %s: %w", targetXy, err) + } + return targetXy, nil +} + +func listReleaseTags(dir string) (string, error) { + shallow, err := command(dir, "git", "rev-parse", "--is-shallow-repository") + if err != nil { + return "", fmt.Errorf("check whether checkout is shallow: %w", err) + } + if strings.TrimSpace(shallow) != "false" { + return "", errors.New("release generation requires a full checkout with release tags") + } + tags, err := command(dir, "git", "tag", "--list", + "[0-9]*.[0-9]*.0", + "[0-9]*.[0-9]*.0-rc.[0-9]*", + ) + if err != nil { + return "", fmt.Errorf("list release tags: %w", err) + } + return tags, nil +} + +func selectReleaseTags(tags string, targetXy productstreams.XYVersion) (map[productstreams.XYVersion]string, error) { + releaseTags := make(map[productstreams.XYVersion]string) + for tag := range strings.FieldsSeq(tags) { + if !initialRelease.MatchString(tag) { + continue + } + stream, err := productstreams.ParseXYFromVersionString(tag) + if err != nil { + return nil, fmt.Errorf("parse release stream from tag %q: %w", tag, err) + } + if stream.Compare(productstreams.XYVersion{X: 4, Y: 4}) < 0 || stream.Compare(targetXy) > 0 { + continue + } + if err := validateReleaseStream(stream); err != nil { + return nil, fmt.Errorf("validate historical release stream %s: %w", stream, err) + } + selected, exists := releaseTags[stream] + if !exists { + releaseTags[stream] = tag + continue + } + newer, err := newerInitialRelease(tag, selected) + if err != nil { + return nil, err + } + if newer { + releaseTags[stream] = tag + } + } + return releaseTags, nil +} + +func readReleaseSequences(dir string, releaseTags map[productstreams.XYVersion]string) (map[productstreams.XYVersion]int, error) { + sequences := make(map[productstreams.XYVersion]int) + for stream, tag := range releaseTags { + data, err := command(dir, "git", "show", "refs/tags/"+tag+":"+sequencePath) + if err != nil { + return nil, fmt.Errorf("read %s from release tag %s: %w", sequencePath, tag, err) + } + sequence, err := parseSequence(data) + if err != nil { + return nil, fmt.Errorf("release %s: %w", tag, err) + } + sequences[stream] = sequence + } + return sequences, nil +} + +// ensureTargetSequence adds a working-tree baseline only when no tag baseline exists. +// The target must have been validated by parseTargetStream. +func ensureTargetSequence(dir, target string, targetXy productstreams.XYVersion, sequences map[productstreams.XYVersion]int) error { + if _, exists := sequences[targetXy]; exists { + return nil + } + patch, _, _ := strings.Cut(strings.Split(target, ".")[2], "-") + if patch != "0" && patch != "x" { + return fmt.Errorf("missing initial release tag %s.0 for patch target %s", targetXy, target) + } + data, err := os.ReadFile(filepath.Join(dir, sequencePath)) + if err != nil { + return fmt.Errorf("read current database sequence from %s: %w", sequencePath, err) + } + sequence, err := parseSequence(string(data)) + if err != nil { + return fmt.Errorf("parse current database sequence from %s: %w", sequencePath, err) + } + sequences[targetXy] = sequence + return nil +} + +func validateReleaseSequences(target string, targetXy productstreams.XYVersion, sequences map[productstreams.XYVersion]int) ([]productstreams.XYVersion, error) { + stream := targetXy + for i := range 4 { + if err := validateReleaseStream(stream); err != nil { + return nil, fmt.Errorf("validate release stream %s required by %s: %w", stream, target, err) + } + // Every supported stream needs a baseline; RC-only streams count too. + if _, exists := sequences[stream]; !exists { + return nil, fmt.Errorf("missing initial release tag %s.0 required by %s; fetch release tags before generation", stream, target) + } + if i == 3 { + break + } + var err error + stream, err = productstreams.GetPreviousYStream(stream) + if err != nil { + return nil, fmt.Errorf("find minimum supported stream for %s: %w", target, err) + } + } + streams := slices.Collect(maps.Keys(sequences)) + slices.SortFunc(streams, productstreams.XYVersion.Compare) + last := 0 + for _, stream := range streams { + sequence := sequences[stream] + if sequence < last { + return nil, fmt.Errorf("release %s sequence %d is less than previous sequence %d", stream, sequence, last) + } + last = sequence + } + return streams, nil +} + +// renderReleaseVersions expects sorted streams returned by validateReleaseSequences. +func renderReleaseVersions(streams []productstreams.XYVersion, sequences map[productstreams.XYVersion]int) ([]byte, error) { + var output bytes.Buffer + fmt.Fprintln(&output, `// Code generated by release-versions. DO NOT EDIT. + +package migrations + +var releaseVersions = []ReleaseVersion{`) + for _, stream := range streams { + sequence := sequences[stream] + fmt.Fprintf(&output, "{Version: %q, Sequence: %d},\n", stream.String(), sequence) + } + fmt.Fprintln(&output, "}") + formatted, err := format.Source(output.Bytes()) + if err != nil { + return nil, fmt.Errorf("format generated release versions: %w", err) + } + return formatted, nil +} + +func validateReleaseStream(stream productstreams.XYVersion) error { + previous, err := productstreams.GetPreviousYStream(productstreams.GetNextYStream(stream)) + if err != nil { + return err + } + if previous != stream { + return fmt.Errorf("invalid release stream %s", stream) + } + return nil +} + +// GA supersedes RCs; otherwise select the highest numeric RC ordinal. +func newerInitialRelease(candidate, selected string) (bool, error) { + _, candidateRC, candidateIsRC := strings.Cut(candidate, "-rc.") + _, selectedRC, selectedIsRC := strings.Cut(selected, "-rc.") + if !candidateIsRC { + return true, nil + } + if !selectedIsRC { + return false, nil + } + candidateOrdinal, err := strconv.Atoi(candidateRC) + if err != nil { + return false, fmt.Errorf("parse RC ordinal from %q: %w", candidate, err) + } + selectedOrdinal, err := strconv.Atoi(selectedRC) + if err != nil { + return false, fmt.Errorf("parse RC ordinal from %q: %w", selected, err) + } + return candidateOrdinal > selectedOrdinal, nil +} + +func parseSequence(data string) (int, error) { + file, err := parser.ParseFile(token.NewFileSet(), "seq_num.go", data, 0) + if err != nil { + return 0, fmt.Errorf("parse seq_num.go: %w", err) + } + sequence := 0 + ast.Inspect(file, func(node ast.Node) bool { + decl, ok := node.(*ast.ValueSpec) + if !ok { + return true + } + for i, name := range decl.Names { + if name.Name == "CurrentDBVersionSeqNum" && i < len(decl.Values) { + if literal, ok := decl.Values[i].(*ast.BasicLit); ok && literal.Kind == token.INT { + sequence, _ = strconv.Atoi(literal.Value) + } + } + } + return true + }) + if sequence <= 0 { + return 0, errors.New("missing positive CurrentDBVersionSeqNum in seq_num.go") + } + return sequence, nil +} diff --git a/tools/generate-helpers/release-versions/main_test.go b/tools/generate-helpers/release-versions/main_test.go new file mode 100644 index 0000000000000..3a8c2794b7844 --- /dev/null +++ b/tools/generate-helpers/release-versions/main_test.go @@ -0,0 +1,622 @@ +package main + +import ( + "fmt" + "os" + "os/exec" + "path/filepath" + "strings" + "testing" + + "github.com/stackrox/rox/pkg/version/productstreams" + "github.com/stretchr/testify/require" +) + +func repository(t *testing.T) (string, func(...string), func(int, string)) { + t.Helper() + dir := t.TempDir() + git := func(args ...string) { + t.Helper() + cmd := exec.Command("git", args...) + cmd.Dir = dir + output, err := cmd.CombinedOutput() + require.NoError(t, err, "%s", output) + } + git("init", "-q", "--initial-branch=master") + git("config", "core.hooksPath", "/dev/null") + git("config", "user.email", "test@example.com") + git("config", "user.name", "Test") + git("config", "commit.gpgsign", "false") + git("config", "tag.gpgsign", "false") + require.NoError(t, os.MkdirAll(filepath.Join(dir, "pkg/migrations/internal"), 0755)) + write := func(sequence int, tag string) { + t.Helper() + require.NoError(t, os.WriteFile(filepath.Join(dir, sequencePath), []byte(fmt.Sprintf("package internal\nvar CurrentDBVersionSeqNum int = %d\n", sequence)), 0644)) + git("add", sequencePath) + git("commit", "-qm", "sequence", "--allow-empty") + if tag != "" { + git("tag", tag) + } + } + return dir, git, write +} + +func TestDevelopmentBaseline(t *testing.T) { + dir, git, write := repository(t) + write(220, "4.10.0") + write(225, "4.11.0") + write(226, "5.0.0") + write(227, "5.1.x") + before, err := generate(dir, "5.1.x-105-g66fd4ac964") + require.NoError(t, err) + require.Contains(t, string(before), `Version: "5.1", Sequence: 227`) + write(228, "") + before, err = generate(dir, "5.1.x-106-gabcdef-dirty") + require.NoError(t, err) + require.Contains(t, string(before), `Version: "5.1", Sequence: 228`) + git("tag", "5.1.0") + after, err := generate(dir, "5.1.0") + require.NoError(t, err) + require.Equal(t, before, after) + write(229, "5.1.1") + after, err = generate(dir, "5.1.1") + require.NoError(t, err) + require.Equal(t, before, after) + write(240, "5.2.0") + after, err = generate(dir, "5.1.1") + require.NoError(t, err) + require.Equal(t, before, after) +} + +func TestHistoricalPatchMigration(t *testing.T) { + dir, _, write := repository(t) + write(205, "4.5.0") + write(206, "4.5.1") + write(209, "4.6.0") + write(209, "4.7.0") + write(211, "4.8.x") + data, err := generate(dir, "4.8.x") + require.NoError(t, err) + require.Contains(t, string(data), `Version: "4.5", Sequence: 205`) + require.NotContains(t, string(data), "206") +} + +func TestGenerationFailures(t *testing.T) { + for name, tc := range map[string]struct { + target, tag, source, want string + completeHistory bool + }{ + "missing floor": {target: "5.1.x", want: "4.10.0", completeHistory: true}, + "nightly is not release": {target: "5.1.x", tag: "4.10.0-nightly-20260930", want: "4.10.0", completeHistory: true}, + "missing patch baseline": {target: "5.1.1", tag: "4.10.0", want: "5.1.0", completeHistory: true}, + "patch RC missing baseline": {target: "5.1.1-rc.0", tag: "4.10.0", want: "5.1.0", completeHistory: true}, + "patch nightly missing baseline": {target: "5.1.1-nightly-20260930", tag: "4.10.0", want: "5.1.0", completeHistory: true}, + "invalid target": {target: "garbage", want: "parse target stream"}, + "phantom target": {target: "4.12.x", want: "stream"}, + "malformed sequence": {target: "5.1.x", tag: "4.10.0", source: "package internal\nvar CurrentDBVersionSeqNum = 0", want: "positive"}, + } { + t.Run(name, func(t *testing.T) { + dir, _, write := repository(t) + write(220, tc.tag) + if tc.completeHistory { + write(225, "4.11.0") + write(226, "5.0.0") + } + if tc.source != "" { + require.NoError(t, os.WriteFile(filepath.Join(dir, sequencePath), []byte(tc.source), 0644)) + } + _, err := generate(dir, tc.target) + require.ErrorContains(t, err, tc.want) + }) + } +} + +func TestPendingStreams(t *testing.T) { + for name, tc := range map[string]struct { + floor, latest, pending, target string + withRC bool + }{ + "major boundary RC-only": {"4.10", "4.11", "5.0", "5.1.x", true}, + "future development": {"5.3", "5.4", "5.5", "5.6.x", true}, + "RC target": {"5.3", "5.4", "5.5", "5.6.0-rc.1", true}, + "no RC tags": {"5.3", "5.4", "5.5", "5.6.x", false}, + } { + t.Run(name, func(t *testing.T) { + dir, _, write := repository(t) + write(220, tc.floor+".0") + write(225, tc.latest+".0") + if tc.withRC { + write(226, tc.pending+".0-rc.1") + } + write(227, "") + data, err := generate(dir, tc.target) + if !tc.withRC { + require.ErrorContains(t, err, tc.pending+".0") + return + } + require.NoError(t, err) + require.Contains(t, string(data), fmt.Sprintf(`Version: %q, Sequence: 220`, tc.floor)) + require.Contains(t, string(data), fmt.Sprintf(`Version: %q, Sequence: 225`, tc.latest)) + require.Contains(t, string(data), fmt.Sprintf(`Version: %q, Sequence: 226`, tc.pending)) + require.Contains(t, string(data), fmt.Sprintf(`Version: %q, Sequence: 227`, strings.Join(strings.Split(tc.target, ".")[:2], "."))) + }) + } +} + +func TestMissingIntermediateRelease(t *testing.T) { + for name, rc := range map[string]bool{"no tags": false, "old RC tags": true} { + t.Run(name, func(t *testing.T) { + dir, _, write := repository(t) + write(220, "5.3.0") + if rc { + write(221, "5.4.0-rc.1") + } + write(225, "5.5.0") + write(227, "") + _, err := generate(dir, "5.6.x") + if rc { + require.NoError(t, err) + } else { + require.ErrorContains(t, err, "missing initial release tag 5.4.0") + } + }) + } +} + +func TestPendingStreamLifecycle(t *testing.T) { + dir, _, write := repository(t) + write(220, "5.3.0") + write(225, "5.4.0") + write(226, "5.5.0-rc.1") + write(230, "") + before, err := generate(dir, "5.6.x") + require.NoError(t, err) + require.Contains(t, string(before), `Version: "5.5", Sequence: 226`) + write(228, "5.5.0") + write(230, "") + baseline, err := generate(dir, "5.6.x") + require.NoError(t, err) + require.Contains(t, string(baseline), `Version: "5.5", Sequence: 228`) + require.Contains(t, string(baseline), `Version: "5.6", Sequence: 230`) + for _, tag := range []string{"5.5.1-rc.1", "5.5.1"} { + write(229, tag) + write(230, "") + after, err := generate(dir, "5.6.x") + require.NoError(t, err) + require.Equal(t, baseline, after) + } +} + +func TestGenerationCommand(t *testing.T) { + dir, git, write := repository(t) + write(220, "4.10.0") + write(225, "4.11.0") + write(226, "5.0.0") + write(227, "5.1.x") + versionMakefile(t, dir) + t.Chdir(dir) + t.Setenv("BUILD_TAG", "") + require.NoError(t, run("")) + output := filepath.Join(dir, "pkg/migrations/release_versions.go") + before, err := os.ReadFile(output) + require.NoError(t, err) + require.Contains(t, string(before), `Version: "5.1", Sequence: 227`) + git("tag", "5.1.0") + t.Setenv("BUILD_TAG", "5.1.0") + require.NoError(t, run("")) + after, err := os.ReadFile(output) + require.NoError(t, err) + require.Equal(t, before, after) + t.Setenv("BUILD_TAG", "5.5.x") + require.ErrorContains(t, run(""), "5.4.0") + after, err = os.ReadFile(output) + require.NoError(t, err) + require.Equal(t, before, after, "failed generation must not overwrite the output") + require.NoError(t, run("5.1.0"), "explicit target takes precedence over BUILD_TAG") +} + +func versionMakefile(t *testing.T, dir string) { + t.Helper() + require.NoError(t, os.MkdirAll(filepath.Join(dir, "make"), 0755)) + for _, name := range []string{"env.mk", "goproxy.mk"} { + data, err := os.ReadFile(filepath.Join("../../../make", name)) + require.NoError(t, err) + require.NoError(t, os.WriteFile(filepath.Join(dir, "make", name), data, 0644)) + } + require.NoError(t, os.WriteFile(filepath.Join(dir, "Makefile"), []byte("include make/env.mk\ntag:\n\t@echo $(TAG)\n"), 0644)) +} + +func TestReleaseBranchLifecycle(t *testing.T) { + dir, git, write := repository(t) + versionMakefile(t, dir) + t.Chdir(dir) + t.Setenv("BUILD_TAG", "") + write(220, "4.10.0") + write(225, "4.11.0") + write(227, "5.0.0") + git("tag", "-a", "5.1.x", "-m", "development") + write(228, "") + git("checkout", "-qb", "release-5.1") + write(228, "") + git("tag", "-a", "5.1.0-rc.0", "-m", "release candidate") + git("checkout", "master") + write(230, "") + git("tag", "-a", "5.2.x", "-m", "next development stream") + git("checkout", "release-5.1") + write(229, "") + git("tag", "-a", "5.1.0-rc.1", "-m", "release candidate with migration") + + readOutput := func() []byte { + t.Helper() + require.NoError(t, run("")) + data, err := os.ReadFile("pkg/migrations/release_versions.go") + require.NoError(t, err) + return data + } + before := readOutput() + require.Contains(t, string(before), `Version: "5.1", Sequence: 229`) + require.NotContains(t, string(before), `Version: "5.2"`) + git("tag", "-a", "5.1.0", "-m", "GA") + git("branch", "5.1.0", "master") // A branch name must not shadow the GA tag. + require.Equal(t, before, readOutput()) + git("checkout", "--detach", "refs/tags/5.1.0") + require.Equal(t, before, readOutput(), "detached release CI checkout") + git("checkout", "release-5.1") + write(231, "") + git("tag", "-a", "5.1.1-rc.0", "-m", "patch migration") + require.Equal(t, before, readOutput()) + git("tag", "-a", "5.1.1", "-m", "patch GA") + require.Equal(t, before, readOutput()) + + git("checkout", "master") + write(240, "") + git("tag", "-a", "5.2.0", "-m", "newer GA") + after := readOutput() + require.Contains(t, string(after), `Version: "5.1", Sequence: 229`, "GA on another branch is authoritative") + require.Contains(t, string(after), `Version: "5.2", Sequence: 240`) + git("checkout", "release-5.1") + require.Equal(t, before, readOutput(), "newer release tags must not change old branch output") +} + +func TestMultipleReleaseBranchesWithRCs(t *testing.T) { + dir, git, write := repository(t) + write(220, "4.10.0") + git("checkout", "-qb", "release-4.10") + git("checkout", "master") + write(225, "4.11.0") + git("checkout", "-qb", "release-4.11") + git("checkout", "master") + write(227, "5.0.0-rc.0") + write(228, "5.1.x") + + before, err := generate(dir, "5.1.x") + require.NoError(t, err) + require.Contains(t, string(before), `Version: "4.10", Sequence: 220`) + require.Contains(t, string(before), `Version: "4.11", Sequence: 225`) + require.Contains(t, string(before), `Version: "5.1", Sequence: 228`) + require.Contains(t, string(before), `Version: "5.0", Sequence: 227`) + + // Each release line can advance independently while RCs are in flight. + git("checkout", "release-4.10") + write(221, "4.10.10-rc.1") + git("checkout", "release-4.11") + for sequence, tag := range []string{ + "4.11.1-rc.0", + "4.11.1-rc.1", + "4.11.1-rc.2", + "4.11.1-rc.3", + "4.11.1-rc.4", + } { + write(226+sequence, tag) + } + git("checkout", "-qb", "release-5.0", "refs/tags/4.11.0") + write(227, "5.0.0-rc.2") + git("checkout", "master") + + after, err := generate(dir, "5.1.x") + require.NoError(t, err) + require.Equal(t, before, after, "patch RCs must not change baselines, and an unchanged initial RC sequence is stable") +} + +func TestNightlyVersionDiscovery(t *testing.T) { + dir, git, write := repository(t) + versionMakefile(t, dir) + t.Chdir(dir) + t.Setenv("BUILD_TAG", "") + write(220, "4.10.0") + write(225, "4.11.0") + write(226, "5.0.0") + write(227, "") + git("tag", "-a", "5.1.x", "-m", "development") + write(228, "") + git("tag", "-a", "5.1.x-nightly-20260930", "-m", "nightly") + tag, err := command(dir, "make", "--quiet", "tag") + require.NoError(t, err) + require.Contains(t, tag, "5.1.x-1-g") + require.NotContains(t, tag, "nightly") + require.NoError(t, run("")) + before, err := os.ReadFile("pkg/migrations/release_versions.go") + require.NoError(t, err) + t.Setenv("BUILD_TAG", "5.1.x-nightly-20260930") + require.NoError(t, run("")) + after, err := os.ReadFile("pkg/migrations/release_versions.go") + require.NoError(t, err) + require.Equal(t, before, after, "explicit nightly BUILD_TAG must select the same stream") + require.NoError(t, os.WriteFile(sequencePath, []byte("package internal\nvar CurrentDBVersionSeqNum = 229\n"), 0644)) + t.Setenv("BUILD_TAG", "") + tag, err = command(dir, "make", "--quiet", "tag") + require.NoError(t, err) + require.Contains(t, tag, "-dirty") + require.NoError(t, run("")) + after, err = os.ReadFile("pkg/migrations/release_versions.go") + require.NoError(t, err) + require.Contains(t, string(after), `Version: "5.1", Sequence: 229`) +} + +func TestPatchVersionSuffixes(t *testing.T) { + dir, _, write := repository(t) + write(220, "4.10.0") + write(225, "4.11.0") + write(226, "5.0.0") + write(227, "5.1.0") + write(228, "5.1.1") + baseline, err := generate(dir, "5.1.0") + require.NoError(t, err) + for name, target := range map[string]string{ + "patch RC": "5.1.2-rc.1", + "patch nightly": "5.1.1-nightly-20260930", + "RC nightly": "5.1.2-rc.1-nightly-20260930", + "patch git describe": "5.1.1-12-gabcdef-dirty", + "release branch nightly": "5.1.x-nightly-20260930", + } { + t.Run(name, func(t *testing.T) { + data, err := generate(dir, target) + require.NoError(t, err) + require.Equal(t, baseline, data) + }) + } +} + +func TestInvalidHistoricalSequence(t *testing.T) { + for name, sequence := range map[string]int{"invalid": 0, "decreasing": 230} { + t.Run(name, func(t *testing.T) { + dir, _, write := repository(t) + write(sequence, "4.10.0") + write(225, "4.11.0") + write(226, "5.0.0") + write(227, "5.1.x") + _, err := generate(dir, "5.1.x") + require.Error(t, err) + }) + } +} + +func TestPhantomHistoricalStream(t *testing.T) { + dir, _, write := repository(t) + write(220, "4.10.0") + write(225, "4.12.0") + write(227, "5.1.x") + _, err := generate(dir, "5.1.x") + require.ErrorContains(t, err, "4.12") +} + +func TestCommandIgnoresSuccessfulStderr(t *testing.T) { + output, err := command(t.TempDir(), "sh", "-c", "printf '5.1.x'; printf 'warning' >&2") + require.NoError(t, err) + require.Equal(t, "5.1.x", output) +} + +func TestMajorBoundaryAndReleaseCandidate(t *testing.T) { + dir, _, write := repository(t) + write(211, "4.8.0") + write(213, "4.9.0") + write(220, "4.10.0") + write(225, "4.11.0") + write(227, "5.0.0-rc.1") + data, err := generate(dir, "5.0.0-rc.1") + require.NoError(t, err) + require.Contains(t, string(data), `Version: "5.0", Sequence: 227`) + write(228, "5.0.0-rc.2") + data, err = generate(dir, "5.0.0-rc.2") + require.NoError(t, err) + require.Contains(t, string(data), `Version: "5.0", Sequence: 228`) +} + +func TestShallowCheckout(t *testing.T) { + dir, _, write := repository(t) + write(220, "4.10.0") + write(227, "5.1.x") + clone := filepath.Join(t.TempDir(), "clone") + _, err := command("", "git", "clone", "--depth=1", "file://"+dir, clone) + require.NoError(t, err) + _, err = generate(clone, "5.1.x") + require.ErrorContains(t, err, "full checkout") +} + +func TestParseSequence(t *testing.T) { + for name, tc := range map[string]struct { + source string + want int + }{ + "typed": {"package internal\nvar CurrentDBVersionSeqNum int = 205", 205}, + "untyped": {"package internal\nvar CurrentDBVersionSeqNum = 227", 227}, + "missing": {"package internal", 0}, + "malformed": {"not Go", 0}, + "negative": {"package internal\nvar CurrentDBVersionSeqNum = -1", 0}, + "expression": {"package internal\nvar CurrentDBVersionSeqNum = 200 + 1", 0}, + } { + t.Run(name, func(t *testing.T) { + got, err := parseSequence(tc.source) + if tc.want == 0 { + require.Error(t, err) + } else { + require.NoError(t, err) + require.Equal(t, tc.want, got) + } + }) + } +} + +func TestInitialReleaseCandidateSelection(t *testing.T) { + dir, _, write := repository(t) + write(220, "4.10.0") + write(225, "4.11.0") + write(226, "5.0.0-rc.2") + write(227, "5.0.0-rc.10") + write(229, "5.0.1-rc.0") + write(0, "5.0.0-rc.11-nightly-20261008") + write(230, "") + data, err := generate(dir, "5.1.x") + require.NoError(t, err) + require.Contains(t, string(data), `Version: "5.0", Sequence: 227`) + // GA is authoritative even when its sequence differs from the last RC. + write(228, "5.0.0") + write(230, "") + data, err = generate(dir, "5.1.x") + require.NoError(t, err) + require.Contains(t, string(data), `Version: "5.0", Sequence: 228`) +} + +func TestDecreasingReleaseCandidateSequence(t *testing.T) { + dir, _, write := repository(t) + write(220, "4.10.0") + write(225, "4.11.0") + write(229, "5.0.0-rc.0") + write(228, "") + _, err := generate(dir, "5.1.x") + require.ErrorContains(t, err, "less than previous sequence") +} + +func TestPatchTargetWithReleaseCandidateBaseline(t *testing.T) { + dir, _, write := repository(t) + write(213, "4.9.0") + write(220, "4.10.0") + write(225, "4.11.0") + write(227, "5.0.0-rc.0") + write(229, "5.0.1-rc.0") + data, err := generate(dir, "5.0.1-rc.0") + require.NoError(t, err) + require.Contains(t, string(data), `Version: "5.0", Sequence: 227`) +} + +func TestParseTargetStream(t *testing.T) { + for name, tc := range map[string]struct { + target string + want productstreams.XYVersion + wantError string + }{ + "stream": {target: "5.1", want: productstreams.XYVersion{X: 5, Y: 1}}, + "development": {target: "5.1.x-106-gabcdef-dirty", want: productstreams.XYVersion{X: 5, Y: 1}}, + "patch RC": {target: "5.1.2-rc.1", want: productstreams.XYVersion{X: 5, Y: 1}}, + "nightly": {target: "5.1.x-nightly-20260930", want: productstreams.XYVersion{X: 5, Y: 1}}, + "invalid syntax": {target: "garbage", wantError: `parse target stream from "garbage"`}, + "phantom stream": {target: "4.12.x", wantError: "validate target stream 4.12"}, + } { + t.Run(name, func(t *testing.T) { + got, err := parseTargetStream(tc.target) + if tc.wantError != "" { + require.ErrorContains(t, err, tc.wantError) + return + } + require.NoError(t, err) + require.Equal(t, tc.want, got) + }) + } +} + +func TestSelectReleaseTags(t *testing.T) { + for name, tc := range map[string]struct { + tags string + want map[productstreams.XYVersion]string + wantError string + }{ + "numeric RC ordering": { + tags: "5.0.0-rc.10 5.0.0-rc.2 5.0.0-rc.9", + want: map[productstreams.XYVersion]string{{X: 5, Y: 0}: "5.0.0-rc.10"}, + }, + "GA supersedes RC in either order": { + tags: "4.11.0-rc.10 4.11.0 5.0.0 5.0.0-rc.10", + want: map[productstreams.XYVersion]string{{X: 4, Y: 11}: "4.11.0", {X: 5, Y: 0}: "5.0.0"}, + }, + "ignored tags and stream bounds": { + tags: "4.3.0 4.4.0 5.1.0 5.2.0 5.0.1 5.0.1-rc.0 5.0.0-nightly-20261008 5.0.0-rc.11-nightly-20261008 5.0.x 5.0.0-rc.01 garbage", + want: map[productstreams.XYVersion]string{{X: 4, Y: 4}: "4.4.0", {X: 5, Y: 1}: "5.1.0"}, + }, + "no candidates": {want: map[productstreams.XYVersion]string{}}, + "phantom historical stream": {tags: "4.12.0", wantError: "validate historical release stream 4.12"}, + } { + t.Run(name, func(t *testing.T) { + got, err := selectReleaseTags(tc.tags, productstreams.XYVersion{X: 5, Y: 1}) + if tc.wantError != "" { + require.ErrorContains(t, err, tc.wantError) + return + } + require.NoError(t, err) + require.Equal(t, tc.want, got) + }) + } +} + +func TestValidateReleaseSequences(t *testing.T) { + for name, tc := range map[string]struct { + missing productstreams.XYVersion + change productstreams.XYVersion + sequence int + wantError string + }{ + "major boundary and sorted streams": {}, + "equal sequences": {change: productstreams.XYVersion{X: 5, Y: 0}, sequence: 225}, + "missing floor": {missing: productstreams.XYVersion{X: 4, Y: 10}, wantError: "missing initial release tag 4.10.0 required by 5.1.x"}, + "missing intermediate": {missing: productstreams.XYVersion{X: 5, Y: 0}, wantError: "missing initial release tag 5.0.0 required by 5.1.x"}, + "missing target": {missing: productstreams.XYVersion{X: 5, Y: 1}, wantError: "missing initial release tag 5.1.0 required by 5.1.x"}, + "decreasing": {change: productstreams.XYVersion{X: 5, Y: 0}, sequence: 224, wantError: "release 5.0 sequence 224 is less than previous sequence 225"}, + "older historical sequence also checked": {change: productstreams.XYVersion{X: 4, Y: 9}, sequence: 221, wantError: "release 4.10 sequence 220 is less than previous sequence 221"}, + } { + t.Run(name, func(t *testing.T) { + sequences := map[productstreams.XYVersion]int{ + {X: 5, Y: 1}: 227, + {X: 4, Y: 11}: 225, + {X: 4, Y: 9}: 213, + {X: 5, Y: 0}: 226, + {X: 4, Y: 10}: 220, + } + delete(sequences, tc.missing) + if tc.change.X != 0 { + sequences[tc.change] = tc.sequence + } + got, err := validateReleaseSequences("5.1.x", productstreams.XYVersion{X: 5, Y: 1}, sequences) + if tc.wantError != "" { + require.ErrorContains(t, err, tc.wantError) + return + } + require.NoError(t, err) + require.Equal(t, []productstreams.XYVersion{{X: 4, Y: 9}, {X: 4, Y: 10}, {X: 4, Y: 11}, {X: 5, Y: 0}, {X: 5, Y: 1}}, got) + }) + } +} + +func TestValidateReleaseSequencesRejectsPhantomTarget(t *testing.T) { + _, err := validateReleaseSequences("4.12.x", productstreams.XYVersion{X: 4, Y: 12}, nil) + require.ErrorContains(t, err, "validate release stream 4.12 required by 4.12.x: invalid release stream 4.12") +} + +func TestRenderReleaseVersions(t *testing.T) { + streams := []productstreams.XYVersion{{X: 4, Y: 11}, {X: 5, Y: 0}} + sequences := map[productstreams.XYVersion]int{{X: 5, Y: 0}: 226, {X: 4, Y: 11}: 225} + got, err := renderReleaseVersions(streams, sequences) + require.NoError(t, err) + require.Equal(t, `// Code generated by release-versions. DO NOT EDIT. + +package migrations + +var releaseVersions = []ReleaseVersion{ + {Version: "4.11", Sequence: 225}, + {Version: "5.0", Sequence: 226}, +} +`, string(got)) +} + +func TestInitialReleaseOrdinalOverflow(t *testing.T) { + _, err := selectReleaseTags("5.1.0-rc.1 5.1.0-rc.999999999999999999999999999999", productstreams.XYVersion{X: 5, Y: 1}) + require.ErrorContains(t, err, "parse RC ordinal") +} diff --git a/tools/linters/go.mod b/tools/linters/go.mod index ab424a14e39e4..7a7478d0cf497 100644 --- a/tools/linters/go.mod +++ b/tools/linters/go.mod @@ -1,38 +1,39 @@ module github.com/stackrox/stackrox/tools/linters -go 1.26.3 +go 1.26.7 require ( - github.com/golangci/golangci-lint/v2 v2.12.2 + actionlint.kjanat.dev v1.17.0 + github.com/golangci/golangci-lint/v2 v2.14.0 github.com/nilslice/protolock v0.17.0 - github.com/rhysd/actionlint v1.7.12 github.com/sethvargo/ratchet v0.12.0 - golang.org/x/vuln v1.6.0 + golang.org/x/vuln v1.9.0 ) require ( - 4d63.com/gocheckcompilerdirectives v1.3.0 // indirect + 4d63.com/gocheckcompilerdirectives v1.4.0 // indirect 4d63.com/gochecknoglobals v0.2.2 // indirect - charm.land/lipgloss/v2 v2.0.3 // indirect - codeberg.org/chavacava/garif v0.2.0 // indirect + charm.land/lipgloss/v2 v2.0.6 // indirect + codeberg.org/chavacava/garif v0.2.1 // indirect codeberg.org/polyfloyd/go-errorlint v1.9.0 // indirect dev.gaijin.team/go/exhaustruct/v4 v4.0.0 // indirect - dev.gaijin.team/go/golib v0.6.0 // indirect - github.com/4meepo/tagalign v1.4.3 // indirect - github.com/Abirdcfly/dupword v0.1.7 // indirect + dev.gaijin.team/go/exhaustruct/v5 v5.2.0 // indirect + dev.gaijin.team/go/golib v0.8.1 // indirect + github.com/4meepo/tagalign v1.4.4 // indirect + github.com/Abirdcfly/dupword v0.1.8 // indirect github.com/AdminBenni/iota-mixing v1.0.0 // indirect - github.com/AlwxSin/noinlineerr v1.0.5 // indirect - github.com/Antonboom/errname v1.1.1 // indirect - github.com/Antonboom/nilnil v1.1.1 // indirect + github.com/AlwxSin/noinlineerr v1.0.6 // indirect + github.com/Antonboom/errname v1.1.2 // indirect + github.com/Antonboom/nilnil v1.1.2 // indirect github.com/Antonboom/testifylint v1.6.4 // indirect github.com/BurntSushi/toml v1.6.0 // indirect - github.com/ClickHouse/clickhouse-go-linter v1.2.0 // indirect + github.com/ClickHouse/clickhouse-go-linter v1.2.1 // indirect github.com/Djarvur/go-err113 v0.1.1 // indirect github.com/Masterminds/semver/v3 v3.5.0 // indirect github.com/MirrexOne/unqueryvet v1.5.4 // indirect github.com/OpenPeeDeeP/depguard/v2 v2.2.1 // indirect - github.com/alecthomas/chroma/v2 v2.24.1 // indirect - github.com/alecthomas/go-check-sumtype v0.3.1 // indirect + github.com/alecthomas/chroma/v2 v2.27.0 // indirect + github.com/alecthomas/go-check-sumtype v0.5.1-0.20260828200218-ae6904d28606 // indirect github.com/alexkohler/nakedret/v2 v2.0.6 // indirect github.com/alexkohler/prealloc v1.1.0 // indirect github.com/alfatraining/structtag v1.0.0 // indirect @@ -45,19 +46,19 @@ require ( github.com/blizzy78/varnamelen v0.8.0 // indirect github.com/bmatcuk/doublestar/v4 v4.10.0 // indirect github.com/bombsimon/wsl/v4 v4.7.0 // indirect - github.com/bombsimon/wsl/v5 v5.8.0 // indirect + github.com/bombsimon/wsl/v5 v5.9.0 // indirect github.com/braydonk/yaml v0.9.0 // indirect github.com/breml/bidichk v0.3.3 // indirect github.com/breml/errchkjson v0.4.1 // indirect github.com/butuzov/ireturn v0.4.1 // indirect - github.com/butuzov/mirror v1.3.0 // indirect + github.com/butuzov/mirror v1.3.3 // indirect github.com/catenacyber/perfsprint v0.10.1 // indirect github.com/ccojocar/zxcvbn-go v1.0.4 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/charithe/durationcheck v0.0.11 // indirect github.com/charmbracelet/colorprofile v0.4.3 // indirect - github.com/charmbracelet/ultraviolet v0.0.0-20251205161215-1948445e3318 // indirect - github.com/charmbracelet/x/ansi v0.11.7 // indirect + github.com/charmbracelet/ultraviolet v0.0.0-20260811164956-006e29f97886 // indirect + github.com/charmbracelet/x/ansi v0.11.8 // indirect github.com/charmbracelet/x/term v0.2.2 // indirect github.com/charmbracelet/x/termios v0.1.1 // indirect github.com/charmbracelet/x/windows v0.2.2 // indirect @@ -67,20 +68,19 @@ require ( github.com/curioswitch/go-reassign v0.3.0 // indirect github.com/daixiang0/gci v0.13.7 // indirect github.com/dave/dst v0.27.3 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect github.com/denis-tingaikin/go-header v0.5.0 // indirect - github.com/dlclark/regexp2 v1.12.0 // indirect + github.com/dlclark/regexp2/v2 v2.2.1 // indirect github.com/docker/cli v29.6.2+incompatible // indirect github.com/docker/docker-credential-helpers v0.9.8 // indirect github.com/emicklei/proto v1.9.1 // indirect github.com/ettle/strcase v0.2.0 // indirect github.com/fatih/color v1.19.0 // indirect github.com/fatih/structtag v1.2.0 // indirect - github.com/firefart/nonamedreturns v1.0.6 // indirect - github.com/fsnotify/fsnotify v1.5.4 // indirect + github.com/firefart/nonamedreturns v1.0.8 // indirect + github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/fzipp/gocyclo v0.6.0 // indirect - github.com/ghostiam/protogetter v0.3.20 // indirect - github.com/go-critic/go-critic v0.14.3 // indirect + github.com/ghostiam/protogetter v1.0.1 // indirect + github.com/go-critic/go-critic v0.15.0 // indirect github.com/go-toolsmith/astcast v1.1.0 // indirect github.com/go-toolsmith/astcopy v1.1.0 // indirect github.com/go-toolsmith/astequal v1.2.0 // indirect @@ -91,13 +91,14 @@ require ( github.com/go-viper/mapstructure/v2 v2.5.0 // indirect github.com/go-xmlfmt/xmlfmt v1.1.3 // indirect github.com/gobwas/glob v0.2.3 // indirect - github.com/godoc-lint/godoc-lint v0.11.2 // indirect - github.com/gofrs/flock v0.13.0 // indirect + github.com/godoc-lint/godoc-lint v0.11.4 // indirect + github.com/gofrs/flock v0.13.1 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/golangci/asciicheck v0.5.0 // indirect + github.com/golangci/canonicalheader v0.0.0-20260827115959-a25c71c521f6 // indirect github.com/golangci/dupl v0.0.0-20260401084720-c99c5cf5c202 // indirect github.com/golangci/go-printf-func-name v0.1.1 // indirect - github.com/golangci/gofmt v0.0.0-20250106114630-d62b90e6713d // indirect + github.com/golangci/gofmt v0.0.0-20260820135601-e84e05053792 // indirect github.com/golangci/golines v0.15.0 // indirect github.com/golangci/misspell v0.8.0 // indirect github.com/golangci/plugin-module-register v0.1.2 // indirect @@ -120,24 +121,23 @@ require ( github.com/hashicorp/hcl v1.0.0 // indirect github.com/hexops/gotextdiff v1.0.3 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/jgautheron/goconst v1.10.0 // indirect + github.com/jgautheron/goconst v1.11.0 // indirect github.com/jjti/go-spancheck v0.6.5 // indirect github.com/julz/importas v0.2.0 // indirect github.com/karamaru-alpha/copyloopvar v1.2.2 // indirect - github.com/kisielk/errcheck v1.10.0 // indirect + github.com/kisielk/errcheck v1.20.0 // indirect github.com/kkHAIKE/contextcheck v1.1.6 // indirect github.com/klauspost/compress v1.19.0 // indirect github.com/kulti/thelper v0.7.1 // indirect github.com/kunwardeep/paralleltest v1.0.15 // indirect - github.com/lasiar/canonicalheader v1.1.2 // indirect github.com/ldez/exptostd v0.4.5 // indirect - github.com/ldez/gomoddirectives v0.8.0 // indirect + github.com/ldez/gomoddirectives v0.10.0 // indirect github.com/ldez/grignotin v0.10.1 // indirect github.com/ldez/structtags v0.6.1 // indirect - github.com/ldez/tagliatelle v0.7.2 // indirect + github.com/ldez/tagliatelle v0.8.0 // indirect github.com/ldez/usetesting v0.5.0 // indirect github.com/leonklingele/grouper v1.1.2 // indirect - github.com/lucasb-eyer/go-colorful v1.4.0 // indirect + github.com/lucasb-eyer/go-colorful v1.4.1 // indirect github.com/macabu/inamedparam v0.2.0 // indirect github.com/magiconair/properties v1.8.6 // indirect github.com/manuelarte/embeddedstructfieldcheck v0.4.0 // indirect @@ -145,25 +145,24 @@ require ( github.com/maratori/testableexamples v1.0.1 // indirect github.com/maratori/testpackage v1.1.2 // indirect github.com/matoous/godox v1.1.0 // indirect - github.com/mattn/go-colorable v0.1.14 // indirect - github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-runewidth v0.0.23 // indirect - github.com/mattn/go-shellwords v1.0.12 // indirect + github.com/mattn/go-colorable v0.1.15 // indirect + github.com/mattn/go-isatty v0.0.24 // indirect + github.com/mattn/go-runewidth v0.0.28 // indirect + github.com/mattn/go-shellwords v1.0.14 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect - github.com/mgechev/revive v1.15.0 // indirect + github.com/mgechev/revive v1.17.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/moricho/tparallel v0.3.2 // indirect github.com/muesli/cancelreader v0.2.2 // indirect github.com/nakabonne/nestif v0.3.1 // indirect - github.com/nishanths/exhaustive v0.12.0 // indirect + github.com/nishanths/exhaustive v0.13.0 // indirect github.com/nishanths/predeclared v0.2.2 // indirect - github.com/nunnatsa/ginkgolinter v0.23.0 // indirect + github.com/nunnatsa/ginkgolinter v0.24.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.1 // indirect github.com/pelletier/go-toml v1.9.5 // indirect - github.com/pelletier/go-toml/v2 v2.3.1 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/pelletier/go-toml/v2 v2.4.3 // indirect github.com/prometheus/client_golang v1.12.1 // indirect github.com/prometheus/client_model v0.2.0 // indirect github.com/prometheus/common v0.32.1 // indirect @@ -173,22 +172,22 @@ require ( github.com/quasilyte/gogrep v0.5.0 // indirect github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 // indirect github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 // indirect - github.com/raeperd/recvcheck v0.2.0 // indirect + github.com/raeperd/recvcheck v0.3.1 // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/robfig/cron/v3 v3.0.1 // indirect - github.com/rogpeppe/go-internal v1.14.1 // indirect + github.com/rogpeppe/go-internal v1.16.0 // indirect github.com/ryancurrah/gomodguard v1.4.1 // indirect github.com/ryancurrah/gomodguard/v2 v2.1.3 // indirect github.com/ryanrolds/sqlclosecheck v0.6.0 // indirect github.com/sanposhiho/wastedassign/v2 v2.1.0 // indirect - github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 // indirect + github.com/santhosh-tekuri/jsonschema/v6 v6.0.3 // indirect github.com/sashamelentyev/interfacebloat v1.1.0 // indirect github.com/sashamelentyev/usestdlibvars v1.29.0 // indirect - github.com/securego/gosec/v2 v2.26.1 // indirect - github.com/sirupsen/logrus v1.9.4 // indirect + github.com/securego/gosec/v2 v2.29.0 // indirect + github.com/sirupsen/logrus v1.10.2 // indirect github.com/sivchari/containedctx v1.0.3 // indirect github.com/sonatard/noctx v0.5.1 // indirect - github.com/sourcegraph/go-diff v0.8.0 // indirect + github.com/sourcegraph/go-diff v0.9.0 // indirect github.com/spf13/afero v1.15.0 // indirect github.com/spf13/cast v1.5.0 // indirect github.com/spf13/cobra v1.10.2 // indirect @@ -197,20 +196,20 @@ require ( github.com/spf13/viper v1.13.0 // indirect github.com/ssgreg/nlreturn/v2 v2.2.1 // indirect github.com/stbenjam/no-sprintf-host-port v0.3.1 // indirect - github.com/stretchr/objx v0.5.2 // indirect - github.com/stretchr/testify v1.11.1 // indirect + github.com/stretchr/objx v0.5.3 // indirect + github.com/stretchr/testify v1.12.1 // indirect github.com/subosito/gotenv v1.4.1 // indirect github.com/tetafro/godot v1.5.6 // indirect - github.com/timakin/bodyclose v0.0.0-20260129054331-73d1f95b84b4 // indirect - github.com/timonwong/loggercheck v0.11.0 // indirect + github.com/timakin/bodyclose v0.0.0-20260723120731-857993a2939c // indirect + github.com/timonwong/loggercheck v0.12.0 // indirect github.com/tomarrell/wrapcheck/v2 v2.12.0 // indirect github.com/tommy-muehle/go-mnd/v2 v2.5.1 // indirect github.com/ultraware/funlen v0.2.0 // indirect github.com/ultraware/whitespace v0.2.0 // indirect github.com/uudashr/gocognit v1.2.1 // indirect - github.com/uudashr/iface v1.4.2 // indirect + github.com/uudashr/iface v1.5.1 // indirect github.com/xen0n/gosmopolitan v1.3.0 // indirect - github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect + github.com/xo/terminfo v1.0.0 // indirect github.com/yagipy/maintidx v1.0.0 // indirect github.com/yeya24/promlinter v0.3.0 // indirect github.com/ykadowak/zerologlint v0.1.5 // indirect @@ -218,24 +217,24 @@ require ( go-simpler.org/musttag v0.14.0 // indirect go-simpler.org/sloglint v0.12.0 // indirect go.augendre.info/arangolint v0.4.0 // indirect - go.augendre.info/fatcontext v0.9.0 // indirect + go.augendre.info/fatcontext v0.10.1 // indirect go.uber.org/multierr v1.10.0 // indirect go.uber.org/zap v1.27.0 // indirect - go.yaml.in/yaml/v3 v3.0.4 // indirect - go.yaml.in/yaml/v4 v4.0.0-rc.3 // indirect - golang.org/x/exp/typeparams v0.0.0-20260209203927-2842357ff358 // indirect - golang.org/x/mod v0.38.0 // indirect + go.yaml.in/yaml/v3 v3.0.5 // indirect + go.yaml.in/yaml/v4 v4.0.0-rc.6 // indirect + golang.org/x/exp/typeparams v0.0.0-20260811152304-ee035b5b010f // indirect + golang.org/x/mod v0.42.0 // indirect golang.org/x/oauth2 v0.36.0 // indirect - golang.org/x/sync v0.22.0 // indirect - golang.org/x/sys v0.47.0 // indirect - golang.org/x/telemetry v0.0.0-20260708182218-49f421fb7959 // indirect - golang.org/x/text v0.36.0 // indirect - golang.org/x/tools v0.48.0 // indirect - google.golang.org/protobuf v1.36.10 // indirect + golang.org/x/sync v0.24.0 // indirect + golang.org/x/sys v0.49.0 // indirect + golang.org/x/telemetry v0.0.0-20261010193011-f71dc92da45e // indirect + golang.org/x/text v0.41.0 // indirect + golang.org/x/tools v0.52.0 // indirect + google.golang.org/protobuf v1.36.12 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - honnef.co/go/tools v0.7.0 // indirect - mvdan.cc/gofumpt v0.9.2 // indirect - mvdan.cc/unparam v0.0.0-20251027182757-5beb8c8f8f15 // indirect + honnef.co/go/tools v0.8.1 // indirect + mvdan.cc/gofumpt v0.12.0 // indirect + mvdan.cc/unparam v0.0.0-20260823230713-2fa3d841b0c8 // indirect ) diff --git a/tools/linters/go.sum b/tools/linters/go.sum index cee066806ecae..48f60e63ee6e5 100644 --- a/tools/linters/go.sum +++ b/tools/linters/go.sum @@ -1,9 +1,11 @@ -4d63.com/gocheckcompilerdirectives v1.3.0 h1:Ew5y5CtcAAQeTVKUVFrE7EwHMrTO6BggtEj8BZSjZ3A= -4d63.com/gocheckcompilerdirectives v1.3.0/go.mod h1:ofsJ4zx2QAuIP/NO/NAh1ig6R1Fb18/GI7RVMwz7kAY= +4d63.com/gocheckcompilerdirectives v1.4.0 h1:ZLq62rbGWVmQhiZ8kuNVIT/M09xCSTdJz9K3xOdT/CY= +4d63.com/gocheckcompilerdirectives v1.4.0/go.mod h1:9ZOAiMOjqC/nRwci2fcUXVHUNLG/cH6r6rhUh+jTFtQ= 4d63.com/gochecknoglobals v0.2.2 h1:H1vdnwnMaZdQW/N+NrkT1SZMTBmcwHe9Vq8lJcYYTtU= 4d63.com/gochecknoglobals v0.2.2/go.mod h1:lLxwTQjL5eIesRbvnzIP3jZtG140FnTdz+AlMa+ogt0= -charm.land/lipgloss/v2 v2.0.3 h1:yM2zJ4Cf5Y51b7RHIwioil4ApI/aypFXXVHSwlM6RzU= -charm.land/lipgloss/v2 v2.0.3/go.mod h1:7myLU9iG/3xluAWzpY/fSxYYHCgoKTie7laxk6ATwXA= +actionlint.kjanat.dev v1.17.0 h1:wzkg6amflGqcF4QlkSERw0L1kdGSb/z2KZ7aidlgD74= +actionlint.kjanat.dev v1.17.0/go.mod h1:9BVNedMJ1sZTdAiszWaOl+H4IiKD9PfKrkwqpxeB+ao= +charm.land/lipgloss/v2 v2.0.6 h1:EaGKeuA8FvF+v2BT5VmZd2LoYLaMZJXA5n34th8nCIQ= +charm.land/lipgloss/v2 v2.0.6/go.mod h1:ipDDJNSGa1hlwDtSfW1s2/xR8Vdhbut4PXh2zEKZd0Q= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= @@ -36,35 +38,37 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -codeberg.org/chavacava/garif v0.2.0 h1:F0tVjhYbuOCnvNcU3YSpO6b3Waw6Bimy4K0mM8y6MfY= -codeberg.org/chavacava/garif v0.2.0/go.mod h1:P2BPbVbT4QcvLZrORc2T29szK3xEOlnl0GiPTJmEqBQ= +codeberg.org/chavacava/garif v0.2.1 h1:K9oYxSlvlXrHXyW26Z4q61bTpJDo1wbvXcYKar/F/LM= +codeberg.org/chavacava/garif v0.2.1/go.mod h1:oHnDSmc0f9K1MeE+MQD/yjkiIB5Xsn5y3S9Dg96Xk84= codeberg.org/polyfloyd/go-errorlint v1.9.0 h1:VkdEEmA1VBpH6ecQoMR4LdphVI3fA4RrCh2an7YmodI= codeberg.org/polyfloyd/go-errorlint v1.9.0/go.mod h1:GPRRu2LzVijNn4YkrZYJfatQIdS+TrcK8rL5Xs24qw8= dev.gaijin.team/go/exhaustruct/v4 v4.0.0 h1:873r7aNneqoBB3IaFIzhvt2RFYTuHgmMjoKfwODoI1Y= dev.gaijin.team/go/exhaustruct/v4 v4.0.0/go.mod h1:aZ/k2o4Y05aMJtiux15x8iXaumE88YdiB0Ai4fXOzPI= -dev.gaijin.team/go/golib v0.6.0 h1:v6nnznFTs4bppib/NyU1PQxobwDHwCXXl15P7DV5Zgo= -dev.gaijin.team/go/golib v0.6.0/go.mod h1:uY1mShx8Z/aNHWDyAkZTkX+uCi5PdX7KsG1eDQa2AVE= +dev.gaijin.team/go/exhaustruct/v5 v5.2.0 h1:HZB49Fshn8qHJCi9VzYtrcnR1jbLteRHXfnQz8Adams= +dev.gaijin.team/go/exhaustruct/v5 v5.2.0/go.mod h1:5IshpqhgGdKIrF8lBmi3M6YKmI7T3hMzAL9nrflko88= +dev.gaijin.team/go/golib v0.8.1 h1:JYju4x9BSo+QD/AYeHULVDcvEhiFg8wOi6pT0IaZF5E= +dev.gaijin.team/go/golib v0.8.1/go.mod h1:c5fu7t1RSGMxSQgcUYO1sODbzsYnOCXJLmHeNG1Eb+0= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/4meepo/tagalign v1.4.3 h1:Bnu7jGWwbfpAie2vyl63Zup5KuRv21olsPIha53BJr8= -github.com/4meepo/tagalign v1.4.3/go.mod h1:00WwRjiuSbrRJnSVeGWPLp2epS5Q/l4UEy0apLLS37c= -github.com/Abirdcfly/dupword v0.1.7 h1:2j8sInznrje4I0CMisSL6ipEBkeJUJAmK1/lfoNGWrQ= -github.com/Abirdcfly/dupword v0.1.7/go.mod h1:K0DkBeOebJ4VyOICFdppB23Q0YMOgVafM0zYW0n9lF4= +github.com/4meepo/tagalign v1.4.4 h1:052JDGj2pBORc6NkD30dDXpsUpoYszDeUwr9/5YZuVA= +github.com/4meepo/tagalign v1.4.4/go.mod h1:00WwRjiuSbrRJnSVeGWPLp2epS5Q/l4UEy0apLLS37c= +github.com/Abirdcfly/dupword v0.1.8 h1:SrhcUuGsROBuChFxHALRYzyyPODWn9zwghmzPvD9Cd8= +github.com/Abirdcfly/dupword v0.1.8/go.mod h1:XZrhVnI7YGpsTiWZANSQaBJ4QpL/Tq5vIEdKJJAs9WI= github.com/AdminBenni/iota-mixing v1.0.0 h1:Os6lpjG2dp/AE5fYBPAA1zfa2qMdCAWwPMCgpwKq7wo= github.com/AdminBenni/iota-mixing v1.0.0/go.mod h1:i4+tpAaB+qMVIV9OK3m4/DAynOd5bQFaOu+2AhtBCNY= -github.com/AlwxSin/noinlineerr v1.0.5 h1:RUjt63wk1AYWTXtVXbSqemlbVTb23JOSRiNsshj7TbY= -github.com/AlwxSin/noinlineerr v1.0.5/go.mod h1:+QgkkoYrMH7RHvcdxdlI7vYYEdgeoFOVjU9sUhw/rQc= -github.com/Antonboom/errname v1.1.1 h1:bllB7mlIbTVzO9jmSWVWLjxTEbGBVQ1Ff/ClQgtPw9Q= -github.com/Antonboom/errname v1.1.1/go.mod h1:gjhe24xoxXp0ScLtHzjiXp0Exi1RFLKJb0bVBtWKCWQ= -github.com/Antonboom/nilnil v1.1.1 h1:9Mdr6BYd8WHCDngQnNVV0b554xyisFioEKi30sksufQ= -github.com/Antonboom/nilnil v1.1.1/go.mod h1:yCyAmSw3doopbOWhJlVci+HuyNRuHJKIv6V2oYQa8II= +github.com/AlwxSin/noinlineerr v1.0.6 h1:KAvuxunTe9QxvqrFB7nZTdb/7Wzas4AvifslTnG0Ld8= +github.com/AlwxSin/noinlineerr v1.0.6/go.mod h1:+QgkkoYrMH7RHvcdxdlI7vYYEdgeoFOVjU9sUhw/rQc= +github.com/Antonboom/errname v1.1.2 h1:dxwONZJua3VB8Xh/VaCjqAcqF645sWWv7xj26zy7tdQ= +github.com/Antonboom/errname v1.1.2/go.mod h1:YeZIpgLMxT+SNkruGgYkLhzq/9vs3fsolTZegKaKDZI= +github.com/Antonboom/nilnil v1.1.2 h1:aNlFuJhaEseXe4fHO3xbjXlSeEiQVYa2lEkWD2s2hAY= +github.com/Antonboom/nilnil v1.1.2/go.mod h1:0ynwvphOLmAuMwTNDyBnDZmSwZoDpcFXmUHmzoHH2WA= github.com/Antonboom/testifylint v1.6.4 h1:gs9fUEy+egzxkEbq9P4cpcMB6/G0DYdMeiFS87UiqmQ= github.com/Antonboom/testifylint v1.6.4/go.mod h1:YO33FROXX2OoUfwjz8g+gUxQXio5i9qpVy7nXGbxDD4= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk= github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/ClickHouse/clickhouse-go-linter v1.2.0 h1:zbm174up3hTKjp0wKZVnTzRiG7tSF5XZF0FJG/MuCBI= -github.com/ClickHouse/clickhouse-go-linter v1.2.0/go.mod h1:pLorS7ffPTfuUV9M0SJgfHA/h/WQPQUk2FWG9x74cQ4= +github.com/ClickHouse/clickhouse-go-linter v1.2.1 h1:zGEKIyd5YL08ieWG/LOUmlau2DxbxPVOfAeo+4Jz3ck= +github.com/ClickHouse/clickhouse-go-linter v1.2.1/go.mod h1:pLorS7ffPTfuUV9M0SJgfHA/h/WQPQUk2FWG9x74cQ4= github.com/Djarvur/go-err113 v0.1.1 h1:eHfopDqXRwAi+YmCUas75ZE0+hoBHJ2GQNLYRSxao4g= github.com/Djarvur/go-err113 v0.1.1/go.mod h1:IaWJdYFLg76t2ihfflPZnM1LIQszWOsFDh2hhhAVF6k= github.com/Masterminds/semver/v3 v3.5.0 h1:kQceYJfbupGfZOKZQg0kou0DgAKhzDg2NZPAwZ/2OOE= @@ -75,10 +79,10 @@ github.com/OpenPeeDeeP/depguard/v2 v2.2.1 h1:vckeWVESWp6Qog7UZSARNqfu/cZqvki8zsu github.com/OpenPeeDeeP/depguard/v2 v2.2.1/go.mod h1:q4DKzC4UcVaAvcfd41CZh0PWpGgzrVxUYBlgKNGquUo= github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= -github.com/alecthomas/chroma/v2 v2.24.1 h1:m5ffpfZbIb++k8AqFEKy9uVgY12xIQtBsQlc6DfZJQM= -github.com/alecthomas/chroma/v2 v2.24.1/go.mod h1:l+ohZ9xRXIbGe7cIW+YZgOGbvuVLjMps/FYN/CwuabI= -github.com/alecthomas/go-check-sumtype v0.3.1 h1:u9aUvbGINJxLVXiFvHUlPEaD7VDULsrxJb4Aq31NLkU= -github.com/alecthomas/go-check-sumtype v0.3.1/go.mod h1:A8TSiN3UPRw3laIgWEUOHHLPa6/r9MtoigdlP5h3K/E= +github.com/alecthomas/chroma/v2 v2.27.0 h1:FodwmyOBgJULFYmDqibcp9pvfDLWdtPRh9v/r5BXYZs= +github.com/alecthomas/chroma/v2 v2.27.0/go.mod h1:NjJ3ciIgrqBNeIkWZ4e46nseoLDslxU1LmfCoL+wcY8= +github.com/alecthomas/go-check-sumtype v0.5.1-0.20260828200218-ae6904d28606 h1:dXPJ+uOJLWb8rjlAuLX7JPiRJtZKw/53Ol+WxdDJ1Eo= +github.com/alecthomas/go-check-sumtype v0.5.1-0.20260828200218-ae6904d28606/go.mod h1:ZH31IJyNpxpStxP2ayCcPQz+3T2G/OnxIQqe4LWvSDw= github.com/alecthomas/repr v0.5.2 h1:SU73FTI9D1P5UNtvseffFSGmdNci/O6RsqzeXJtP0Qs= github.com/alecthomas/repr v0.5.2/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -112,8 +116,8 @@ github.com/bmatcuk/doublestar/v4 v4.10.0 h1:zU9WiOla1YA122oLM6i4EXvGW62DvKZVxIe6 github.com/bmatcuk/doublestar/v4 v4.10.0/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= github.com/bombsimon/wsl/v4 v4.7.0 h1:1Ilm9JBPRczjyUs6hvOPKvd7VL1Q++PL8M0SXBDf+jQ= github.com/bombsimon/wsl/v4 v4.7.0/go.mod h1:uV/+6BkffuzSAVYD+yGyld1AChO7/EuLrCF/8xTiapg= -github.com/bombsimon/wsl/v5 v5.8.0 h1:JTkyfs4yl8SPejrCF2GdABXE+mO1WvM7iUYzRWlsxDs= -github.com/bombsimon/wsl/v5 v5.8.0/go.mod h1:AbOLsulgkqP4ZnitHf9gwPtCOGlrzkk0jb0uNxRSY0o= +github.com/bombsimon/wsl/v5 v5.9.0 h1:WCrgZ7RQnZO5oEwbVTlYgBdU3wL294kR1BSWV8vTfsU= +github.com/bombsimon/wsl/v5 v5.9.0/go.mod h1:kjo4HiAV5FDkHC8/uzJq9mBffEEd6WT/nvN7DoMovDM= github.com/braydonk/yaml v0.9.0 h1:ewGMrVmEVpsm3VwXQDR388sLg5+aQ8Yihp6/hc4m+h4= github.com/braydonk/yaml v0.9.0/go.mod h1:hcm3h581tudlirk8XEUPDBAimBPbmnL0Y45hCRl47N4= github.com/breml/bidichk v0.3.3 h1:WSM67ztRusf1sMoqH6/c4OBCUlRVTKq+CbSeo0R17sE= @@ -122,8 +126,8 @@ github.com/breml/errchkjson v0.4.1 h1:keFSS8D7A2T0haP9kzZTi7o26r7kE3vymjZNeNDRDw github.com/breml/errchkjson v0.4.1/go.mod h1:a23OvR6Qvcl7DG/Z4o0el6BRAjKnaReoPQFciAl9U3s= github.com/butuzov/ireturn v0.4.1 h1:vWb3NO4t77iku/sjCQ/2pHTQeOmxEhjIriJqRLg1Y+I= github.com/butuzov/ireturn v0.4.1/go.mod h1:q+DXKzTDV5guNuXLnIab9fKXizTn2miZHLhxH7V/GB4= -github.com/butuzov/mirror v1.3.0 h1:HdWCXzmwlQHdVhwvsfBb2Au0r3HyINry3bDWLYXiKoc= -github.com/butuzov/mirror v1.3.0/go.mod h1:AEij0Z8YMALaq4yQj9CPPVYOyJQyiexpQEQgihajRfI= +github.com/butuzov/mirror v1.3.3 h1:v0RsWBhfFc1RQqE/f3sHpSttKDtodFn0gFmtYyD4/hA= +github.com/butuzov/mirror v1.3.3/go.mod h1:h9BzzwYnTiHO0GzgvaTqIg7VSsOUhdIv51cHFFBmX1w= github.com/catenacyber/perfsprint v0.10.1 h1:u7Riei30bk46XsG8nknMhKLXG9BcXz3+3tl/WpKm0PQ= github.com/catenacyber/perfsprint v0.10.1/go.mod h1:DJTGsi/Zufpuus6XPGJyKOTMELe347o6akPvWG9Zcsc= github.com/ccojocar/zxcvbn-go v1.0.4 h1:FWnCIRMXPj43ukfX000kvBZvV6raSxakYr1nzyNrUcc= @@ -137,10 +141,10 @@ github.com/charithe/durationcheck v0.0.11 h1:g1/EX1eIiKS57NTWsYtHDZ/APfeXKhye1Di github.com/charithe/durationcheck v0.0.11/go.mod h1:x5iZaixRNl8ctbM+3B2RrPG5t856TxRyVQEnbIEM2X4= github.com/charmbracelet/colorprofile v0.4.3 h1:QPa1IWkYI+AOB+fE+mg/5/4HRMZcaXex9t5KX76i20Q= github.com/charmbracelet/colorprofile v0.4.3/go.mod h1:/zT4BhpD5aGFpqQQqw7a+VtHCzu+zrQtt1zhMt9mR4Q= -github.com/charmbracelet/ultraviolet v0.0.0-20251205161215-1948445e3318 h1:OqDqxQZliC7C8adA7KjelW3OjtAxREfeHkNcd66wpeI= -github.com/charmbracelet/ultraviolet v0.0.0-20251205161215-1948445e3318/go.mod h1:Y6kE2GzHfkyQQVCSL9r2hwokSrIlHGzZG+71+wDYSZI= -github.com/charmbracelet/x/ansi v0.11.7 h1:kzv1kJvjg2S3r9KHo8hDdHFQLEqn4RBCb39dAYC84jI= -github.com/charmbracelet/x/ansi v0.11.7/go.mod h1:9qGpnAVYz+8ACONkZBUWPtL7lulP9No6p1epAihUZwQ= +github.com/charmbracelet/ultraviolet v0.0.0-20260811164956-006e29f97886 h1:rdnVWKgJpTVXKuKuJyxDJ+NFJdUaUqGvyGy61OcvlbA= +github.com/charmbracelet/ultraviolet v0.0.0-20260811164956-006e29f97886/go.mod h1:nAw0d9PhFp1qdzi2xhQU5YOu5sVpDIHWlaW2Uz/bCro= +github.com/charmbracelet/x/ansi v0.11.8 h1:JMFwp0CgDC2+jcOB162HH5k7I3FVbgFSMMYg7dSPBQQ= +github.com/charmbracelet/x/ansi v0.11.8/go.mod h1:ZNN+3mXny/516oTQPLMPIBeSINvNJJQ8uQXDgbeJxY0= github.com/charmbracelet/x/term v0.2.2 h1:xVRT/S2ZcKdhhOuSP4t5cLi5o+JxklsoEObBSgfgZRk= github.com/charmbracelet/x/term v0.2.2/go.mod h1:kF8CY5RddLWrsgVwpw4kAa6TESp6EB5y3uxGLeCqzAI= github.com/charmbracelet/x/termios v0.1.1 h1:o3Q2bT8eqzGnGPOYheoYS8eEleT5ZVNYNy8JawjaNZY= @@ -174,6 +178,8 @@ github.com/denis-tingaikin/go-header v0.5.0 h1:SRdnP5ZKvcO9KKRP1KJrhFR3RrlGuD+42 github.com/denis-tingaikin/go-header v0.5.0/go.mod h1:mMenU5bWrok6Wl2UsZjy+1okegmwQ3UgWl4V1D8gjlY= github.com/dlclark/regexp2 v1.12.0 h1:0j4c5qQmnC6XOWNjP3PIXURXN2gWx76rd3KvgdPkCz8= github.com/dlclark/regexp2 v1.12.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +github.com/dlclark/regexp2/v2 v2.2.1 h1:mf4KkFUj0gJuarK8P+LgiS+Lit7m9N1yAwEfPbee7R0= +github.com/dlclark/regexp2/v2 v2.2.1/go.mod h1:avUrQvPaLz2DrFNHJF0taWAFFX2C1GMSSoeiqFjcBmU= github.com/docker/cli v29.6.2+incompatible h1:/bjePvcbbFTnRrMfWJBY7AjfICdsiLVgHn6LwTVOcqw= github.com/docker/cli v29.6.2+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/docker-credential-helpers v0.9.8 h1:bIREROb7So6PRlq6KTtdS9MPEjC29OQRkFNlvK2OX8Q= @@ -190,18 +196,18 @@ github.com/fatih/color v1.19.0 h1:Zp3PiM21/9Ld6FzSKyL5c/BULoe/ONr9KlbYVOfG8+w= github.com/fatih/color v1.19.0/go.mod h1:zNk67I0ZUT1bEGsSGyCZYZNrHuTkJJB+r6Q9VuMi0LE= github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4= github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= -github.com/firefart/nonamedreturns v1.0.6 h1:vmiBcKV/3EqKY3ZiPxCINmpS431OcE1S47AQUwhrg8E= -github.com/firefart/nonamedreturns v1.0.6/go.mod h1:R8NisJnSIpvPWheCq0mNRXJok6D8h7fagJTF8EMEwCo= +github.com/firefart/nonamedreturns v1.0.8 h1:iB32Dl17zJl1zlVEj/WlUWgx0HiRyQ85OUw1WHa4/II= +github.com/firefart/nonamedreturns v1.0.8/go.mod h1:vxFNvm5AfP/8rgAKFzYmnqx0yp1HjrYsErZ9pHPTznA= github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= -github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= -github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= +github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= +github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/fzipp/gocyclo v0.6.0 h1:lsblElZG7d3ALtGMx9fmxeTKZaLLpU8mET09yN4BBLo= github.com/fzipp/gocyclo v0.6.0/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA= -github.com/ghostiam/protogetter v0.3.20 h1:oW7OPFit2FxZOpmMRPP9FffU4uUpfeE/rEdE1f+MzD0= -github.com/ghostiam/protogetter v0.3.20/go.mod h1:FjIu5Yfs6FT391m+Fjp3fbAYJ6rkL/J6ySpZBfnODuI= -github.com/go-critic/go-critic v0.14.3 h1:5R1qH2iFeo4I/RJU8vTezdqs08Egi4u5p6vOESA0pog= -github.com/go-critic/go-critic v0.14.3/go.mod h1:xwntfW6SYAd7h1OqDzmN6hBX/JxsEKl5up/Y2bsxgVQ= +github.com/ghostiam/protogetter v1.0.1 h1:q4LLTx2KJHJpxrfO3BniUDWoFkoqWD/UlHhClBlUlLM= +github.com/ghostiam/protogetter v1.0.1/go.mod h1:50Fh5yZfs6SFGrd1FlmT04NcguyEOxyjNK5zGD6/EvM= +github.com/go-critic/go-critic v0.15.0 h1:MDUZIQKytIl+vPEc0Igw51m4uLTdi1ZGz2jatEqNs1g= +github.com/go-critic/go-critic v0.15.0/go.mod h1:3BPrw8nHATGm3o2n37cssOmJzpySGKCdY8JWkCzxgKQ= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -211,10 +217,10 @@ github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vb github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= -github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= -github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI= -github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow= +github.com/go-logr/logr v1.4.4 h1:tG4xh9yMsRCAiodLVTxyrkzSZ9+o0L1Kg/+cPVcbP/8= +github.com/go-logr/logr v1.4.4/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-quicktest/qt v1.102.0 h1:HSQxCeh5YZH3EL3W39ixjtyaEhcWSXQHtHnMBzSs474= +github.com/go-quicktest/qt v1.102.0/go.mod h1:p4lGIVX+8Wa6ZPNDvqcxq36XpUDLh42FLetFU7odllI= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= @@ -243,10 +249,10 @@ github.com/go-xmlfmt/xmlfmt v1.1.3 h1:t8Ey3Uy7jDSEisW2K3somuMKIpzktkWptA0iFCnRUW github.com/go-xmlfmt/xmlfmt v1.1.3/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= -github.com/godoc-lint/godoc-lint v0.11.2 h1:Bp0FkJWoSdNsBikdNgIcgtaoo+xz6I/Y9s5WSBQUeeM= -github.com/godoc-lint/godoc-lint v0.11.2/go.mod h1:iVpGdL1JCikNH2gGeAn3Hh+AgN5Gx/I/cxV+91L41jo= -github.com/gofrs/flock v0.13.0 h1:95JolYOvGMqeH31+FC7D2+uULf6mG61mEZ/A8dRYMzw= -github.com/gofrs/flock v0.13.0/go.mod h1:jxeyy9R1auM5S6JYDBhDt+E2TCo7DkratH4Pgi8P+Z0= +github.com/godoc-lint/godoc-lint v0.11.4 h1:N9zUYVJ/OkznBbrBsU/zODvua64EUplMBLQWStO3+1M= +github.com/godoc-lint/godoc-lint v0.11.4/go.mod h1:7usTXoxS0QYIi5usTSCPwR0w/6xLjcz450shXjLn3t4= +github.com/gofrs/flock v0.13.1 h1:jjREztyBeSKBZYAC+mgc1laB+xsgy4kYMf3FbKF2UBo= +github.com/gofrs/flock v0.13.1/go.mod h1:sf4BFiHwnvgxa25DlQoDqXQnwRMEOwqxRq37P6MzzmE= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -279,14 +285,16 @@ github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golangci/asciicheck v0.5.0 h1:jczN/BorERZwK8oiFBOGvlGPknhvq0bjnysTj4nUfo0= github.com/golangci/asciicheck v0.5.0/go.mod h1:5RMNAInbNFw2krqN6ibBxN/zfRFa9S6tA1nPdM0l8qQ= +github.com/golangci/canonicalheader v0.0.0-20260827115959-a25c71c521f6 h1:fVLolA3dG6s0brGetsiDAtcnpMSwVa2LqXJEw/9RJG4= +github.com/golangci/canonicalheader v0.0.0-20260827115959-a25c71c521f6/go.mod h1:1xo+NFW5S+bEf2DKXhaxuzvcDN5AR6o/KMwvqC5Mkpo= github.com/golangci/dupl v0.0.0-20260401084720-c99c5cf5c202 h1:CbTB8KpqnViI6lIXxp03Oclc4VFHi3K4BWC1TacsZ+A= github.com/golangci/dupl v0.0.0-20260401084720-c99c5cf5c202/go.mod h1:NUw9Zr2Sy7+HxzdjIULge71wI6yEg1lWQr7Evcu8K0E= github.com/golangci/go-printf-func-name v0.1.1 h1:hIYTFJqAGp1iwoIfsNTpoq1xZAarogrvjO9AfiW3B4U= github.com/golangci/go-printf-func-name v0.1.1/go.mod h1:Es64MpWEZbh0UBtTAICOZiB+miW53w/K9Or/4QogJss= -github.com/golangci/gofmt v0.0.0-20250106114630-d62b90e6713d h1:viFft9sS/dxoYY0aiOTsLKO2aZQAPT4nlQCsimGcSGE= -github.com/golangci/gofmt v0.0.0-20250106114630-d62b90e6713d/go.mod h1:ivJ9QDg0XucIkmwhzCDsqcnxxlDStoTl89jDMIoNxKY= -github.com/golangci/golangci-lint/v2 v2.12.2 h1:7+d1uY0bq1MU2UV3R5pW5Q7QWdcoq4naMRXM+gsJKrs= -github.com/golangci/golangci-lint/v2 v2.12.2/go.mod h1:opqHHuIcTG2R+4akzWMd4o1BnD9/1LcjICWOujr91U8= +github.com/golangci/gofmt v0.0.0-20260820135601-e84e05053792 h1:WL8YKrt3UbOBqSRU7GpP5BTtQTMWtVtj+mfPijgZeIg= +github.com/golangci/gofmt v0.0.0-20260820135601-e84e05053792/go.mod h1:te5hX0dW4C5r6YbXs+6ysNr8Q5UTmdIqGbb+mlFiYmA= +github.com/golangci/golangci-lint/v2 v2.14.0 h1:ot8QffRa4LzAAEgtvNYrVs9esxQ7xoTwoAv6uhp4ngA= +github.com/golangci/golangci-lint/v2 v2.14.0/go.mod h1:amHimCzNDP1GfVno3hIiNssjvqXmuW+CPZAHOdR4cIc= github.com/golangci/golines v0.15.0 h1:Qnph25g8Y1c5fdo1X7GaRDGgnMHgnxh4Gk4VfPTtRx0= github.com/golangci/golines v0.15.0/go.mod h1:AZjXd23tbHMpowhtnGlj9KCNsysj72aeZVVHnVcZx10= github.com/golangci/misspell v0.8.0 h1:qvxQhiE2/5z+BVRo1kwYA8yGz+lOlu5Jfvtx2b04Jbg= @@ -335,8 +343,8 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -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/pprof v0.0.0-20260802141513-ef3492d7dac3 h1:LMLX+LgTNWpfvCBdFebv6EsYotImrt/Ppc5cXIriCSo= +github.com/google/pprof v0.0.0-20260802141513-ef3492d7dac3/go.mod h1:jl5iWTm0/hd5PjEYEOuwAJ57L/CibdZfrqZ5XA5GrCk= github.com/google/renameio v0.1.0 h1:GOZbcHa3HfsPKPlmyPyN2KEohoMXOhdMbHrvbpl2QaA= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= @@ -373,8 +381,8 @@ github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSo github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/jgautheron/goconst v1.10.0 h1:Ptt+OoE4NaEWKhLrWrrN3IpZdGLiqaf7WLnEX/iv4Jw= -github.com/jgautheron/goconst v1.10.0/go.mod h1:0p+wv1lFOiUr0IlNNT1nrm6+8DB8u2sU6KHGzFRXHDc= +github.com/jgautheron/goconst v1.11.0 h1:KgN90z5qXt5f0Uzf3cWXev3hfMMFUyNeKdpkSBRvLDk= +github.com/jgautheron/goconst v1.11.0/go.mod h1:0p+wv1lFOiUr0IlNNT1nrm6+8DB8u2sU6KHGzFRXHDc= github.com/jjti/go-spancheck v0.6.5 h1:lmi7pKxa37oKYIMScialXUK6hP3iY5F1gu+mLBPgYB8= github.com/jjti/go-spancheck v0.6.5/go.mod h1:aEogkeatBrbYsyW6y5TgDfihCulDYciL1B7rG2vSsrU= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= @@ -390,8 +398,8 @@ github.com/julz/importas v0.2.0 h1:y+MJN/UdL63QbFJHws9BVC5RpA2iq0kpjrFajTGivjQ= github.com/julz/importas v0.2.0/go.mod h1:pThlt589EnCYtMnmhmRYY/qn9lCf/frPOK+WMx3xiJY= github.com/karamaru-alpha/copyloopvar v1.2.2 h1:yfNQvP9YaGQR7VaWLYcfZUlRP2eo2vhExWKxD/fP6q0= github.com/karamaru-alpha/copyloopvar v1.2.2/go.mod h1:oY4rGZqZ879JkJMtX3RRkcXRkmUvH0x35ykgaKgsgJY= -github.com/kisielk/errcheck v1.10.0 h1:Lvs/YAHP24YKg08LA8oDw2z9fJVme090RAXd90S+rrw= -github.com/kisielk/errcheck v1.10.0/go.mod h1:kQxWMMVZgIkDq7U8xtG/n2juOjbLgZtedi0D+/VL/i8= +github.com/kisielk/errcheck v1.20.0 h1:9rwHBNKzd4wkDWcROy3DvFGNqEPlkxBg305rvk7HabI= +github.com/kisielk/errcheck v1.20.0/go.mod h1:O+f80MKNwX8Oor2jwgpeQ9An7uJm+hRSgT+h22knRJU= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkHAIKE/contextcheck v1.1.6 h1:7HIyRcnyzxL9Lz06NGhiKvenXq7Zw6Q0UQu/ttjfJCE= github.com/kkHAIKE/contextcheck v1.1.6/go.mod h1:3dDbMRNBFaq8HFXWC1JyvDSPm43CmE6IuHam8Wr0rkg= @@ -411,24 +419,22 @@ github.com/kulti/thelper v0.7.1 h1:fI8QITAoFVLx+y+vSyuLBP+rcVIB8jKooNSCT2EiI98= github.com/kulti/thelper v0.7.1/go.mod h1:NsMjfQEy6sd+9Kfw8kCP61W1I0nerGSYSFnGaxQkcbs= github.com/kunwardeep/paralleltest v1.0.15 h1:ZMk4Qt306tHIgKISHWFJAO1IDQJLc6uDyJMLyncOb6w= github.com/kunwardeep/paralleltest v1.0.15/go.mod h1:di4moFqtfz3ToSKxhNjhOZL+696QtJGCFe132CbBLGk= -github.com/lasiar/canonicalheader v1.1.2 h1:vZ5uqwvDbyJCnMhmFYimgMZnJMjwljN5VGY0VKbMXb4= -github.com/lasiar/canonicalheader v1.1.2/go.mod h1:qJCeLFS0G/QlLQ506T+Fk/fWMa2VmBUiEI2cuMK4djI= github.com/ldez/exptostd v0.4.5 h1:kv2ZGUVI6VwRfp/+bcQ6Nbx0ghFWcGIKInkG/oFn1aQ= github.com/ldez/exptostd v0.4.5/go.mod h1:QRjHRMXJrCTIm9WxVNH6VW7oN7KrGSht69bIRwvdFsM= -github.com/ldez/gomoddirectives v0.8.0 h1:JqIuTtgvFC2RdH1s357vrE23WJF2cpDCPFgA/TWDGpk= -github.com/ldez/gomoddirectives v0.8.0/go.mod h1:jutzamvZR4XYJLr0d5Honycp4Gy6GEg2mS9+2YX3F1Q= +github.com/ldez/gomoddirectives v0.10.0 h1:Zb23rfMMkG21B6pZ9OfESzemByP5Qr7YvWcXQZE/S3Q= +github.com/ldez/gomoddirectives v0.10.0/go.mod h1:W9uh0721Vc7aaVoiMXTpKIveLmtHC9uaOSiHM4OK5a8= github.com/ldez/grignotin v0.10.1 h1:keYi9rYsgbvqAZGI1liek5c+jv9UUjbvdj3Tbn5fn4o= github.com/ldez/grignotin v0.10.1/go.mod h1:UlDbXFCARrXbWGNGP3S5vsysNXAPhnSuBufpTEbwOas= github.com/ldez/structtags v0.6.1 h1:bUooFLbXx41tW8SvkfwfFkkjPYvFFs59AAMgVg6DUBk= github.com/ldez/structtags v0.6.1/go.mod h1:YDxVSgDy/MON6ariaxLF2X09bh19qL7MtGBN5MrvbdY= -github.com/ldez/tagliatelle v0.7.2 h1:KuOlL70/fu9paxuxbeqlicJnCspCRjH0x8FW+NfgYUk= -github.com/ldez/tagliatelle v0.7.2/go.mod h1:PtGgm163ZplJfZMZ2sf5nhUT170rSuPgBimoyYtdaSI= +github.com/ldez/tagliatelle v0.8.0 h1:QczqVPa22JdT40p3m5JTTVmPMv5wDORqdomJn6/Pnn0= +github.com/ldez/tagliatelle v0.8.0/go.mod h1:K9n83Wv0wyVq3JYF9WI28BX8xXhDBVP3thHJ0ENuiEs= github.com/ldez/usetesting v0.5.0 h1:3/QtzZObBKLy1F4F8jLuKJiKBjjVFi1IavpoWbmqLwc= github.com/ldez/usetesting v0.5.0/go.mod h1:Spnb4Qppf8JTuRgblLrEWb7IE6rDmUpGvxY3iRrzvDQ= github.com/leonklingele/grouper v1.1.2 h1:o1ARBDLOmmasUaNDesWqWCIFH3u7hoFlM84YrjT3mIY= github.com/leonklingele/grouper v1.1.2/go.mod h1:6D0M/HVkhs2yRKRFZUoGjeDy7EZTfFBE9gl4kjmIGkA= -github.com/lucasb-eyer/go-colorful v1.4.0 h1:UtrWVfLdarDgc44HcS7pYloGHJUjHV/4FwW4TvVgFr4= -github.com/lucasb-eyer/go-colorful v1.4.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= +github.com/lucasb-eyer/go-colorful v1.4.1 h1:1EO+WB73+EH8EVbzlrG3KLAfEypQWVHIBqlTf+2hNss= +github.com/lucasb-eyer/go-colorful v1.4.1/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/macabu/inamedparam v0.2.0 h1:VyPYpOc10nkhI2qeNUdh3Zket4fcZjEWe35poddBCpE= github.com/macabu/inamedparam v0.2.0/go.mod h1:+Pee9/YfGe5LJ62pYXqB89lJ+0k5bsR8Wgz/C0Zlq3U= github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= @@ -445,18 +451,18 @@ github.com/matoous/godox v1.1.0 h1:W5mqwbyWrwZv6OQ5Z1a/DHGMOvXYCBP3+Ht7KMoJhq4= github.com/matoous/godox v1.1.0/go.mod h1:jgE/3fUXiTurkdHOLT5WEkThTSuE7yxHv5iWPa80afs= github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE= github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= -github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= -github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= -github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= -github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-runewidth v0.0.23 h1:7ykA0T0jkPpzSvMS5i9uoNn2Xy3R383f9HDx3RybWcw= -github.com/mattn/go-runewidth v0.0.23/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs= -github.com/mattn/go-shellwords v1.0.12 h1:M2zGm7EW6UQJvDeQxo4T51eKPurbeFbe8WtebGE2xrk= -github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= +github.com/mattn/go-colorable v0.1.15 h1:+u9SLTRGnXv73cEsnsmoZBom+dMU88B2M0aDcWy0/jY= +github.com/mattn/go-colorable v0.1.15/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= +github.com/mattn/go-isatty v0.0.24 h1:tGZZoVgT/KiqK1c8ocVLeDS8BSWMRd47J3Lbz7vsReI= +github.com/mattn/go-isatty v0.0.24/go.mod h1:nMCL3Zebbrt45jsMDgnfIwz6ydEQApk5oEI3HqDio6A= +github.com/mattn/go-runewidth v0.0.28 h1:rPyg2ybwEKPebvpzVWe1gKBkH8EQFkxO4Y0hjBeLaBU= +github.com/mattn/go-runewidth v0.0.28/go.mod h1:3qAiGCV4Koz/yuveO58qUefmUTRm8r0IGEXZ9jeHp/8= +github.com/mattn/go-shellwords v1.0.14 h1:yUKzIgsCnosndOASY6/enly1EAuaXeFSQ7cdyA3OuYg= +github.com/mattn/go-shellwords v1.0.14/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/mgechev/revive v1.15.0 h1:vJ0HzSBzfNyPbHKolgiFjHxLek9KUijhqh42yGoqZ8Q= -github.com/mgechev/revive v1.15.0/go.mod h1:LlAKO3QQe9OJ0pVZzI2GPa8CbXGZ/9lNpCGvK4T/a8A= +github.com/mgechev/revive v1.17.0 h1:hwTTVC3svSv9X2FA2hiYT17Uws+lfxDWhPxzBZZCREg= +github.com/mgechev/revive v1.17.0/go.mod h1:uiVNUF8ruVh4WHm/aPs7kKEeuo+m6oO3tuOfniyzP/g= 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/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= @@ -476,16 +482,16 @@ github.com/nakabonne/nestif v0.3.1 h1:wm28nZjhQY5HyYPx+weN3Q65k6ilSBxDb8v5S81B81 github.com/nakabonne/nestif v0.3.1/go.mod h1:9EtoZochLn5iUprVDmDjqGKPofoUEBL8U4Ngq6aY7OE= github.com/nilslice/protolock v0.17.0 h1:sYvcukABl62tZX77H6NuV+jtlwTIfQbn0ln0ixTqr4A= github.com/nilslice/protolock v0.17.0/go.mod h1:DYFqop7QlHjmBCaJKfcVO1Mw5b8JejJZgMvmFng/N9Y= -github.com/nishanths/exhaustive v0.12.0 h1:vIY9sALmw6T/yxiASewa4TQcFsVYZQQRUQJhKRf3Swg= -github.com/nishanths/exhaustive v0.12.0/go.mod h1:mEZ95wPIZW+x8kC4TgC+9YCUgiST7ecevsVDTgc2obs= +github.com/nishanths/exhaustive v0.13.0 h1:Rof0axOSNQaaPaPmLK5RxcRrJV2Vcv+vfUmuRy+2EAM= +github.com/nishanths/exhaustive v0.13.0/go.mod h1:3/adQjJgvD/UFHHSYBjpK9Wbz8DOvf0FBtzx+zI0Rlo= github.com/nishanths/predeclared v0.2.2 h1:V2EPdZPliZymNAn79T8RkNApBjMmVKh5XRpLm/w98Vk= github.com/nishanths/predeclared v0.2.2/go.mod h1:RROzoN6TnGQupbC+lqggsOlcgysk3LMK/HI84Mp280c= -github.com/nunnatsa/ginkgolinter v0.23.0 h1:x3o4DGYOWbBMP/VdNQKgSj+25aJKx2Pe6lHr8gBcgf8= -github.com/nunnatsa/ginkgolinter v0.23.0/go.mod h1:9qN1+0akwXEccwV1CAcCDfcoBlWXHB+ML9884pL4SZ4= -github.com/onsi/ginkgo/v2 v2.28.2 h1:DTrMfpqxiNUyQ3Y0zhn1n3cOO2euFgQPYIpkWwxVFps= -github.com/onsi/ginkgo/v2 v2.28.2/go.mod h1:CLtbVInNckU3/+gC8LzkGUb9oF+e8W8TdUsxPwvdOgE= -github.com/onsi/gomega v1.39.1 h1:1IJLAad4zjPn2PsnhH70V4DKRFlrCzGBNrNaru+Vf28= -github.com/onsi/gomega v1.39.1/go.mod h1:hL6yVALoTOxeWudERyfppUcZXjMwIMLnuSfruD2lcfg= +github.com/nunnatsa/ginkgolinter v0.24.0 h1:Mp0EagluLFP98JatP6nqp/gGEoljNG97uf9AcxcBVy8= +github.com/nunnatsa/ginkgolinter v0.24.0/go.mod h1:2ZMRuzX6+3XXyY6UZOwb6n+MCocVGbkIsDBC4vuWz5c= +github.com/onsi/ginkgo/v2 v2.32.1 h1:6tlvcDm/3sE8lGJbZ4+d4mO3RLy24/tQWOFzVSQNIfw= +github.com/onsi/ginkgo/v2 v2.32.1/go.mod h1:+aXOY+vzZ5mu2iI2HpTZUPmM//oQfsNFX6gU9kNcA44= +github.com/onsi/gomega v1.42.1 h1:iN1rCUX+44NZ1Dc97MPoeFYbFR0vh8zxoxMFwKdyZ6I= +github.com/onsi/gomega v1.42.1/go.mod h1:REff/hsDsodHoKlWsP2mAPhu1+5/6hVYNf9rIEBpeSg= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= @@ -499,12 +505,11 @@ github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT9 github.com/otiai10/mint v1.3.1/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= -github.com/pelletier/go-toml/v2 v2.3.1 h1:MYEvvGnQjeNkRF1qUuGolNtNExTDwct51yp7olPtrEc= -github.com/pelletier/go-toml/v2 v2.3.1/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= +github.com/pelletier/go-toml/v2 v2.4.3 h1:GTRvJQutkOSftxIFD5xw9aepkYNuPWmVJpffdDPYVpY= +github.com/pelletier/go-toml/v2 v2.4.3/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= @@ -538,17 +543,15 @@ github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 h1:TCg2WBOl github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727/go.mod h1:rlzQ04UMyJXu/aOvhd8qT+hvDrFpiwqp8MRXDY9szc0= github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 h1:M8mH9eK4OUR4lu7Gd+PU1fV2/qnDNfzT635KRSObncs= github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567/go.mod h1:DWNGW8A4Y+GyBgPuaQJuWiy0XYftx4Xm/y5Jqk9I6VQ= -github.com/raeperd/recvcheck v0.2.0 h1:GnU+NsbiCqdC2XX5+vMZzP+jAJC5fht7rcVTAhX74UI= -github.com/raeperd/recvcheck v0.2.0/go.mod h1:n04eYkwIR0JbgD73wT8wL4JjPC3wm0nFtzBnWNocnYU= -github.com/rhysd/actionlint v1.7.12 h1:vQ4GeJN86C0QH+gTUQcs8McmK62OLT3kmakPMtEWYnY= -github.com/rhysd/actionlint v1.7.12/go.mod h1:krOUhujIsJusovkaYzQ/VNH8PFexjNKqU0q5XI/4w+g= +github.com/raeperd/recvcheck v0.3.1 h1:p7nZMxiCWkdUtY2i3o+pv1h4fJCR5gpvqAXr9326hEY= +github.com/raeperd/recvcheck v0.3.1/go.mod h1:CbE7iRocQ4uc71JwpW/CPSh4BShnkre4A9Gb508RypU= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= -github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= +github.com/rogpeppe/go-internal v1.16.0 h1:O9DK+vNMDVGLr2BeZqmpLeMjiMNkuXfcqntWbZV6S5g= +github.com/rogpeppe/go-internal v1.16.0/go.mod h1:DrUVZyrJU+txYW5/1kwtXQSMFio52ZOxX7yM1VHvnxs= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryancurrah/gomodguard v1.4.1 h1:eWC8eUMNZ/wM/PWuZBv7JxxqT5fiIKSIyTvjb7Elr+g= github.com/ryancurrah/gomodguard v1.4.1/go.mod h1:qnMJwV1hX9m+YJseXEBhd2s90+1Xn6x9dLz11ualI1I= @@ -558,14 +561,14 @@ github.com/ryanrolds/sqlclosecheck v0.6.0 h1:pEyL9okISdg1F1SEpJNlrEotkTGerv5BMk7 github.com/ryanrolds/sqlclosecheck v0.6.0/go.mod h1:xyX16hsDaCMXHrMJ3JMzGf5OpDfHTOTTQrT7HOFUmeU= github.com/sanposhiho/wastedassign/v2 v2.1.0 h1:crurBF7fJKIORrV85u9UUpePDYGWnwvv3+A96WvwXT0= github.com/sanposhiho/wastedassign/v2 v2.1.0/go.mod h1:+oSmSC+9bQ+VUAxA66nBb0Z7N8CK7mscKTDYC6aIek4= -github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ= -github.com/santhosh-tekuri/jsonschema/v6 v6.0.2/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU= +github.com/santhosh-tekuri/jsonschema/v6 v6.0.3 h1:1EYB5IzjZawrrnELUi78f9fPu57HuXjmddZPjrls/28= +github.com/santhosh-tekuri/jsonschema/v6 v6.0.3/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU= github.com/sashamelentyev/interfacebloat v1.1.0 h1:xdRdJp0irL086OyW1H/RTZTr1h/tMEOsumirXcOJqAw= github.com/sashamelentyev/interfacebloat v1.1.0/go.mod h1:+Y9yU5YdTkrNvoX0xHc84dxiN1iBi9+G8zZIhPVoNjQ= github.com/sashamelentyev/usestdlibvars v1.29.0 h1:8J0MoRrw4/NAXtjQqTHrbW9NN+3iMf7Knkq057v4XOQ= github.com/sashamelentyev/usestdlibvars v1.29.0/go.mod h1:8PpnjHMk5VdeWlVb4wCdrB8PNbLqZ3wBZTZWkrpZZL8= -github.com/securego/gosec/v2 v2.26.1 h1:gdkttGhQFVehqRJ8grKH4DrpqM/QlPKNHBnl8QgcEC4= -github.com/securego/gosec/v2 v2.26.1/go.mod h1:57UW4p0uoP3kxoTkhoo3axLdVAi+OWrLg/Ax/kdqtPE= +github.com/securego/gosec/v2 v2.29.0 h1:pF2HSLcnY5voqpxQumEe0O5YAAbvF4Syu4qeIewpLyc= +github.com/securego/gosec/v2 v2.29.0/go.mod h1:47C7ej+L2bC1NOxteU2aCGnCi4cZaoKzRt5y9plIvuY= github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sethvargo/ratchet v0.12.0 h1:UY1sEevYHi28ryw9c8eHOLonc6oePZDUXHbzx0ESQqw= @@ -573,14 +576,14 @@ github.com/sethvargo/ratchet v0.12.0/go.mod h1:Unu+6zOcsnJj5x/hKgiaRKbGKPZkysoYk github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= -github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w= -github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g= +github.com/sirupsen/logrus v1.10.2 h1:G2SED73/qrAu6YwbdxOD6peLkCBI3z7L+ykJFTXJBBo= +github.com/sirupsen/logrus v1.10.2/go.mod h1:SLEg8TqYulVKKfIGHldVp2K2aYz2DKSVBq4g/H5bR7Q= github.com/sivchari/containedctx v1.0.3 h1:x+etemjbsh2fB5ewm5FeLNi5bUjK0V8n0RB+Wwfd0XE= github.com/sivchari/containedctx v1.0.3/go.mod h1:c1RDvCbnJLtH4lLcYD/GqwiBSSf4F5Qk0xld2rBqzJ4= github.com/sonatard/noctx v0.5.1 h1:wklWg9c9ZYugOAk7qG4yP4PBrlQsmSLPTvW1K4PRQMs= github.com/sonatard/noctx v0.5.1/go.mod h1:64XdbzFb18XL4LporKXp8poqZtPKbCrqQ402CV+kJas= -github.com/sourcegraph/go-diff v0.8.0 h1:ipIyu4cTsLbIrln4l0qtHA3r0a7gyK4ntKjtQytHhvY= -github.com/sourcegraph/go-diff v0.8.0/go.mod h1:hWlcO7Al+UZStZAP8rBumHpCK5ZHQ5BXsMls8p4+F5E= +github.com/sourcegraph/go-diff v0.9.0 h1:7xcVsayWHhvxZGrqt1o89vvBApCa4nyCgO7tNxDHJ+Q= +github.com/sourcegraph/go-diff v0.9.0/go.mod h1:hWlcO7Al+UZStZAP8rBumHpCK5ZHQ5BXsMls8p4+F5E= github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg= github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= @@ -601,13 +604,13 @@ github.com/stbenjam/no-sprintf-host-port v0.3.1 h1:AyX7+dxI4IdLBPtDbsGAyqiTSLpCP github.com/stbenjam/no-sprintf-host-port v0.3.1/go.mod h1:ODbZesTCHMVKthBHskvUUexdcNHAQRXk9NpSsL8p/HQ= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/objx v0.5.3 h1:jmXUvGomnU1o3W/V5h2VEradbpJDwGrzugQQvL0POH4= +github.com/stretchr/objx v0.5.3/go.mod h1:rDQraq+vQZU7Fde9LOZLr8Tax6zZvy4kuNKF+QYS+U0= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= -github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/stretchr/testify v1.12.1 h1:EuwCh5fleGS7H32xRwO3wRGT7DxrDhLAT6FF8MpWDWE= +github.com/stretchr/testify v1.12.1/go.mod h1:MDEgiDPPsNp5cuIrHPPCyornHKgEVbtFUmoNlxoYthg= github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs= github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= github.com/tenntenn/modver v1.0.1 h1:2klLppGhDgzJrScMpkj9Ujy3rXPUspSjAcev9tSEBgA= @@ -616,10 +619,10 @@ github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3 h1:f+jULpR github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3/go.mod h1:ON8b8w4BN/kE1EOhwT0o+d62W65a6aPw1nouo9LMgyY= github.com/tetafro/godot v1.5.6 h1:IEkrFCwXaYHlOn4mGzGS3F3dkP6m9t0jpwqBFPIkKiA= github.com/tetafro/godot v1.5.6/go.mod h1:eOkMrVQurDui411nBY2FA05EYH01r14LuWY/NrVDVcU= -github.com/timakin/bodyclose v0.0.0-20260129054331-73d1f95b84b4 h1:SiHe5XLTn9sFWJ5pBwJ5FN/4j34q9ZlOAD//kMoMYp0= -github.com/timakin/bodyclose v0.0.0-20260129054331-73d1f95b84b4/go.mod h1:sDHLK7rb/59v/ZxZ7KtymgcoxuUMxjXq8gtu9VMOK8M= -github.com/timonwong/loggercheck v0.11.0 h1:jdaMpYBl+Uq9mWPXv1r8jc5fC3gyXx4/WGwTnnNKn4M= -github.com/timonwong/loggercheck v0.11.0/go.mod h1:HEAWU8djynujaAVX7QI65Myb8qgfcZ1uKbdpg3ZzKl8= +github.com/timakin/bodyclose v0.0.0-20260723120731-857993a2939c h1:d/FUP8GD4QiY/rdFzZmBu3KqL9eBNVzMu7W/5pGkaMM= +github.com/timakin/bodyclose v0.0.0-20260723120731-857993a2939c/go.mod h1:sDHLK7rb/59v/ZxZ7KtymgcoxuUMxjXq8gtu9VMOK8M= +github.com/timonwong/loggercheck v0.12.0 h1:7Cb9XGLJZSWYNjgL459DIhpSiEHupD+MLQ6vaN2Pl3g= +github.com/timonwong/loggercheck v0.12.0/go.mod h1:Wa6Y+SJHQR01mViZlLLY5GAZVOWOLNMbkXddMjFWQCs= github.com/tomarrell/wrapcheck/v2 v2.12.0 h1:H/qQ1aNWz/eeIhxKAFvkfIA+N7YDvq6TWVFL27Of9is= github.com/tomarrell/wrapcheck/v2 v2.12.0/go.mod h1:AQhQuZd0p7b6rfW+vUwHm5OMCGgp63moQ9Qr/0BpIWo= github.com/tommy-muehle/go-mnd/v2 v2.5.1 h1:NowYhSdyE/1zwK9QCLeRb6USWdoif80Ie+v+yU8u1Zw= @@ -630,12 +633,12 @@ github.com/ultraware/whitespace v0.2.0 h1:TYowo2m9Nfj1baEQBjuHzvMRbp19i+RCcRYrSW github.com/ultraware/whitespace v0.2.0/go.mod h1:XcP1RLD81eV4BW8UhQlpaR+SDc2givTvyI8a586WjW8= github.com/uudashr/gocognit v1.2.1 h1:CSJynt5txTnORn/DkhiB4mZjwPuifyASC8/6Q0I/QS4= github.com/uudashr/gocognit v1.2.1/go.mod h1:acaubQc6xYlXFEMb9nWX2dYBzJ/bIjEkc1zzvyIZg5Q= -github.com/uudashr/iface v1.4.2 h1:06Vq5RKVYThBsj0Bnw4oasMjD1r+7CE/bcKOA8dVSvg= -github.com/uudashr/iface v1.4.2/go.mod h1:pbeBPlbuU2qkNDn0mmfrxP2X+wjPMIQAy+r1MBXSXtg= +github.com/uudashr/iface v1.5.1 h1:BS3yrgaT55s3dAtJoxuTnsZNbsejq/mVuzp49YDyfBA= +github.com/uudashr/iface v1.5.1/go.mod h1:5UWoT6SvTdTww/KToRj6clO+n4Kg3/NrAQvgOB+5Ggw= github.com/xen0n/gosmopolitan v1.3.0 h1:zAZI1zefvo7gcpbCOrPSHJZJYA9ZgLfJqtKzZ5pHqQM= github.com/xen0n/gosmopolitan v1.3.0/go.mod h1:rckfr5T6o4lBtM1ga7mLGKZmLxswUoH1zxHgNXOsEt4= -github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= -github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= +github.com/xo/terminfo v1.0.0 h1:2ZpYzqWzyyytjk3TP6aJVDhkMAkc99/1xKQdA3TDTBY= +github.com/xo/terminfo v1.0.0/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= github.com/yagipy/maintidx v1.0.0 h1:h5NvIsCz+nRDapQ0exNv4aJ0yXSI0420omVANTv3GJM= github.com/yagipy/maintidx v1.0.0/go.mod h1:0qNf/I/CCZXSMhsRsrEPDZ+DkekpKLXAJfsTACwgXLk= github.com/yeya24/promlinter v0.3.0 h1:JVDbMp08lVCP7Y6NP3qHroGAO6z2yGKQtS5JsjqtoFs= @@ -658,8 +661,8 @@ go-simpler.org/sloglint v0.12.0 h1:UzWDlLWNE5FLqsvyq3tWYHuQMbqrervOhT8qPl4Mmw4= go-simpler.org/sloglint v0.12.0/go.mod h1:jBjjC2bm8rYrs88oTRlFX497kWjJsyZWYoNaXkGRI6I= go.augendre.info/arangolint v0.4.0 h1:xSCZjRoS93nXazBSg5d0OGCi9APPLNMmmLrC995tR50= go.augendre.info/arangolint v0.4.0/go.mod h1:l+f/b4plABuFISuKnTGD4RioXiCCgghv2xqst/xOvAA= -go.augendre.info/fatcontext v0.9.0 h1:Gt5jGD4Zcj8CDMVzjOJITlSb9cEch54hjRRlN3qDojE= -go.augendre.info/fatcontext v0.9.0/go.mod h1:L94brOAT1OOUNue6ph/2HnwxoNlds9aXDF2FcUntbNw= +go.augendre.info/fatcontext v0.10.1 h1:HCS/+eob32cM0mEtmZM6NiXdqvS5KiZmsR+fCubTpbc= +go.augendre.info/fatcontext v0.10.1/go.mod h1:pqpGvA9GlrXy+aXkp8L2dKz12Zp4g2FhzcAtwToU+2w= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -671,10 +674,11 @@ go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= -go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= -go.yaml.in/yaml/v4 v4.0.0-rc.3 h1:3h1fjsh1CTAPjW7q/EMe+C8shx5d8ctzZTrLcs/j8Go= -go.yaml.in/yaml/v4 v4.0.0-rc.3/go.mod h1:aZqd9kCMsGL7AuUv/m/PvWLdg5sjJsZ4oHDEnfPPfY0= +go.yaml.in/yaml/v3 v3.0.5 h1:N6y/pJk8buWs9NY5ERU2HSMfm+IuD/OtfdAnq6kESPw= +go.yaml.in/yaml/v3 v3.0.5/go.mod h1:HVTZu1O7/Vkt2N+BFy8Zza+lnLsABggaTM2ZpNIGuKg= +go.yaml.in/yaml/v4 v4.0.0-rc.6 h1:1h7H1ohdUh93/FyE4YaDa1Zh64K6VVbjF4K6WUxMtH4= +go.yaml.in/yaml/v4 v4.0.0-rc.6/go.mod h1:aZqd9kCMsGL7AuUv/m/PvWLdg5sjJsZ4oHDEnfPPfY0= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -696,8 +700,8 @@ golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b h1:M2rDM6z3Fhozi9O7NWsxAkg/y golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8= golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/exp/typeparams v0.0.0-20230203172020-98cc5a0785f9/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= -golang.org/x/exp/typeparams v0.0.0-20260209203927-2842357ff358 h1:qWFG1Dj7TBjOjOvhEOkmyGPVoquqUKnIU0lEVLp8xyk= -golang.org/x/exp/typeparams v0.0.0-20260209203927-2842357ff358/go.mod h1:4Mzdyp/6jzw9auFDJ3OMF5qksa7UvPnzKqTVGcb04ms= +golang.org/x/exp/typeparams v0.0.0-20260811152304-ee035b5b010f h1:+lI8cDJ4uceLipg2f1ODay7fEuLkk0BIHXd6PB8icxo= +golang.org/x/exp/typeparams v0.0.0-20260811152304-ee035b5b010f/go.mod h1:PqrXSW65cXDZH0k4IeUbhmg/bcAZDbzNz3byBpKCsXo= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -722,8 +726,8 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.38.0 h1:MECBjubtXD7yj4HrhIUcywNaGeNVUdfVnxmPajOk4yk= -golang.org/x/mod v0.38.0/go.mod h1:V6Xz0pq8TQ3dGqVQ1FVHuelZpAL0uNhSkk9ogYP3c40= +golang.org/x/mod v0.42.0 h1:ICeL3t2L30ljSPHHxDnR4fqVcBt/zR2zJAb9juavmQg= +golang.org/x/mod v0.42.0/go.mod h1:u5fzIrRInkL8MaO1cbRkUHT64v303YIT5KEqpNr7jRs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -758,8 +762,8 @@ golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.57.0 h1:K5+3DljvIuDG9/Jv9rvyMywYNFCQ9RSUY6OOTTkT+tE= -golang.org/x/net v0.57.0/go.mod h1:KpXc8iv+r3XplLAG/f7Jsf9RPszJzdR0f58q9vGOuEU= +golang.org/x/net v0.61.0 h1:RR+6j/BTBCrggOLugxa+66R8FvoN6MHlzDlZIbN9YFw= +golang.org/x/net v0.61.0/go.mod h1:WgDCOTH8iwtB66T4/GfI94AHo/hhdb7Hah9NDseQfiI= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -781,8 +785,8 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.22.0 h1:SZjpbeLmrCk4xhRSZFNZW5gFUeCeFgjekvI/+gfScek= -golang.org/x/sync v0.22.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= +golang.org/x/sync v0.24.0 h1:iqiDrGoDgyuvAKrhLQthUEzU/R378N78gXbBjxed7oA= +golang.org/x/sync v0.24.0/go.mod h1:sUUOizhqBxiL6pEWpqNLUiaJn1ShEbZ6BBqskPbjZm0= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -823,15 +827,13 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211105183446-c75c47738b0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs= -golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= -golang.org/x/telemetry v0.0.0-20260708182218-49f421fb7959 h1:RJhm5l6Fo4rmEIcndxDllNhhf/fAx8qIm4t6A7vpm2A= -golang.org/x/telemetry v0.0.0-20260708182218-49f421fb7959/go.mod h1:LV7u5Oco+Z/g6XI7PqN+EUUUGGkEcmB1uj2ceI0fOVg= +golang.org/x/sys v0.49.0 h1:XbzkgYJHdqh/8m2Uu0W/dQv8nktxx4BFHp1M0gROTXA= +golang.org/x/sys v0.49.0/go.mod h1:hNLxWAXmnKAxqDtdwIYC4bM9oQPEecfsnNMuSxOs3og= +golang.org/x/telemetry v0.0.0-20261010193011-f71dc92da45e h1:P6NGsugec4oASJ+yKMNgTndeo0h2CbixZLvQIe9h5R4= +golang.org/x/telemetry v0.0.0-20261010193011-f71dc92da45e/go.mod h1:GNu+nb+E5axfGmP+Uu3ZVQu5lE/Xk42MjZOHWUD94/o= 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= @@ -843,8 +845,8 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg= -golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164= +golang.org/x/text v0.41.0 h1:vz/seA0lnX87Othu2f/0L24RcgrXD9/YFTSuGjj3rH8= +golang.org/x/text v0.41.0/go.mod h1:jvf1O8ajNzZqhSrQBPbutR/EB83Cc0CFrezNQIwbb5M= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -895,14 +897,14 @@ golang.org/x/tools v0.1.1-0.20210302220138-2ac05c832e1a/go.mod h1:9bzcO0MWcOuT0t golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.48.0 h1:3+hClM1aLL5mjMKm5ovokw9epgRXPuu2tILgismM6RE= -golang.org/x/tools v0.48.0/go.mod h1:08xX0orndb/F7jJxGDicx061tyd5pcMto75YMAXr6lk= +golang.org/x/tools v0.52.0 h1:ryxg4U63oaUYk7uOLTF37n43f4qgtGvqV4Ioit1BaEs= +golang.org/x/tools v0.52.0/go.mod h1:ItcP5UNaVGG+Yc4eIYmaFLNJ4soEopkx5Y2d4lcEurs= golang.org/x/tools/go/expect v0.1.1-deprecated h1:jpBZDwmgPhXsKZC6WhL20P4b/wmnpsEAGHaNy0n/rJM= 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.6.0 h1:FeMO9Rm/HwyduOztbvKcOw+zvDEPr4I4aQNSfevFcKY= -golang.org/x/vuln v1.6.0/go.mod h1:bWlG2493/sjR7ksvicBgMrznH3eYQEyK8ifUYBrqUbg= +golang.org/x/vuln v1.9.0 h1:12VaqnI9kJfqwRoPptxoqsUhQtdfrSbdksT7X/KY/sc= +golang.org/x/vuln v1.9.0/go.mod h1:E/Frwm0xp49fTyBW+6CQHdkvobknbwUM49yEpMGUauw= 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= @@ -982,14 +984,13 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= -google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +google.golang.org/protobuf v1.36.12 h1:pJOKDDOyeXErUroCihFAd5LQuwXBSpVnKGrj5o/fwxc= +google.golang.org/protobuf v1.36.12/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= @@ -1011,12 +1012,12 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.7.0 h1:w6WUp1VbkqPEgLz4rkBzH/CSU6HkoqNLp6GstyTx3lU= -honnef.co/go/tools v0.7.0/go.mod h1:pm29oPxeP3P82ISxZDgIYeOaf9ta6Pi0EWvCFoLG2vc= -mvdan.cc/gofumpt v0.9.2 h1:zsEMWL8SVKGHNztrx6uZrXdp7AX8r421Vvp23sz7ik4= -mvdan.cc/gofumpt v0.9.2/go.mod h1:iB7Hn+ai8lPvofHd9ZFGVg2GOr8sBUw1QUWjNbmIL/s= -mvdan.cc/unparam v0.0.0-20251027182757-5beb8c8f8f15 h1:ssMzja7PDPJV8FStj7hq9IKiuiKhgz9ErWw+m68e7DI= -mvdan.cc/unparam v0.0.0-20251027182757-5beb8c8f8f15/go.mod h1:4M5MMXl2kW6fivUT6yRGpLLPNfuGtU2Z0cPvFquGDYU= +honnef.co/go/tools v0.8.1 h1:+JKf3xJ1ni4CwrhVg4/pqsfPGP6vNAXcKbMXJodYx3w= +honnef.co/go/tools v0.8.1/go.mod h1:XA+OnlRA9EDh/ukGvXMNSZNKGwFQJ+5dER0ioUkOxks= +mvdan.cc/gofumpt v0.12.0 h1:1Lbudkz2kpM9Cjz2pL4M19u7q+GaEhCTNf7N9mfpcho= +mvdan.cc/gofumpt v0.12.0/go.mod h1:SmBHHrljiZu/uoypeKup3rFzP6eoC9UwCp2iH5E3jZA= +mvdan.cc/unparam v0.0.0-20260823230713-2fa3d841b0c8 h1:Re1NRyLpiAt9kB+ImaaoapwWiQXrKwER4tY8fLOkDew= +mvdan.cc/unparam v0.0.0-20260823230713-2fa3d841b0c8/go.mod h1:MrS/+zJ1M2xvGXhKktiHbNQeQPyg3Qel+KkzT+f7/i4= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/tools/linters/tools-import.go b/tools/linters/tools-import.go index c25dd3d3ed84e..ba96ee84647f5 100644 --- a/tools/linters/tools-import.go +++ b/tools/linters/tools-import.go @@ -8,9 +8,9 @@ package tools import ( // Tool dependencies, not used anywhere in the code. + _ "actionlint.kjanat.dev/cmd/actionlint" _ "github.com/golangci/golangci-lint/v2/cmd/golangci-lint" _ "github.com/nilslice/protolock" - _ "github.com/rhysd/actionlint/cmd/actionlint" _ "github.com/sethvargo/ratchet" _ "golang.org/x/vuln/cmd/govulncheck" ) diff --git a/tools/proto/go.mod b/tools/proto/go.mod index b86088a333a04..cf4a606c9fb9a 100644 --- a/tools/proto/go.mod +++ b/tools/proto/go.mod @@ -1,35 +1,36 @@ module github.com/stackrox/stackrox/tools/proto -go 1.26.3 +go 1.26.7 require ( - github.com/bufbuild/buf v1.72.0 + github.com/bufbuild/buf v1.73.0 github.com/favadi/protoc-go-inject-tag v1.4.0 google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.6.2 - google.golang.org/protobuf v1.36.11 + google.golang.org/protobuf v1.36.12 ) require ( - buf.build/gen/go/bufbuild/bufplugin/protocolbuffers/go v1.36.11-20260626152828-968bf0468096.1 // indirect - buf.build/gen/go/bufbuild/protodescriptor/protocolbuffers/go v1.36.11-20250109164928-1da0de137947.1 // indirect - buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-20260709200747-435963d16310.1 // indirect - buf.build/gen/go/bufbuild/registry/connectrpc/go v1.20.0-20260713175918-10d915f5b43b.1 // indirect - buf.build/gen/go/bufbuild/registry/protocolbuffers/go v1.36.11-20260713175918-10d915f5b43b.1 // indirect - buf.build/gen/go/pluginrpc/pluginrpc/protocolbuffers/go v1.36.11-20241007202033-cf42259fcbfc.1 // indirect - buf.build/go/app v0.2.1-0.20260626143626-be153867abea // indirect + buf.build/gen/go/bufbuild/bufplugin/protocolbuffers/go v1.36.12-20260722160903-4d94f3df3a7b.2 // indirect + buf.build/gen/go/bufbuild/protodescriptor/protocolbuffers/go v1.36.12-20250109164928-1da0de137947.2 // indirect + buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.12-20260825204119-511051f7f437.2 // indirect + buf.build/gen/go/bufbuild/registry/connectrpc/go v1.20.0-20260831211851-b4432e12a6e7.1 // indirect + buf.build/gen/go/bufbuild/registry/protocolbuffers/go v1.36.12-20260831211851-b4432e12a6e7.2 // indirect + buf.build/gen/go/pluginrpc/pluginrpc/protocolbuffers/go v1.36.12-20241007202033-cf42259fcbfc.2 // indirect + buf.build/go/app v0.2.1-0.20260824172350-b0e76892c61a // indirect buf.build/go/bufplugin v0.10.0 // indirect buf.build/go/bufprivateusage v0.1.0 // indirect buf.build/go/interrupt v1.1.0 // indirect - buf.build/go/protovalidate v1.2.0 // indirect + buf.build/go/protovalidate v1.4.0 // indirect buf.build/go/protoyaml v0.7.0 // indirect buf.build/go/spdx v0.2.0 // indirect buf.build/go/standard v0.1.1-0.20260325175353-2b287e071df5 // indirect - cel.dev/expr v0.25.2 // indirect + cel.dev/cel-go v0.32.0 // indirect + cel.dev/expr v0.25.3 // indirect connectrpc.com/connect v1.20.0 // indirect connectrpc.com/otelconnect v0.9.0 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect github.com/antlr4-go/antlr/v4 v4.13.1 // indirect - github.com/bufbuild/protocompile v0.14.2-0.20260716165721-bb5762d29672 // indirect + github.com/bufbuild/protocompile v0.14.2-0.20260910151042-7436f7c76201 // indirect github.com/bufbuild/protoplugin v0.0.0-20260414125817-25d1d281b46b // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cli/browser v1.3.0 // indirect @@ -37,37 +38,36 @@ require ( github.com/containerd/errdefs/pkg v0.3.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect github.com/distribution/reference v0.6.0 // indirect - github.com/docker/cli v29.6.1+incompatible // indirect - github.com/docker/docker-credential-helpers v0.9.8 // indirect - github.com/docker/go-connections v0.7.0 // indirect + github.com/docker/cli v29.8.0+incompatible // indirect + github.com/docker/docker-credential-helpers v0.9.9 // indirect + github.com/docker/go-connections v0.8.1 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/felixge/httpsnoop v1.1.0 // indirect - github.com/go-logr/logr v1.4.3 // indirect + github.com/go-logr/logr v1.4.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect - github.com/gofrs/flock v0.13.0 // indirect - github.com/google/cel-go v0.29.2 // indirect - github.com/google/go-containerregistry v0.21.7 // indirect + github.com/gofrs/flock v0.13.1 // indirect + github.com/google/go-containerregistry v0.22.1 // indirect github.com/google/uuid v1.6.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jdx/go-netrc v1.0.0 // indirect - github.com/klauspost/compress v1.19.0 // indirect + github.com/klauspost/compress v1.20.0 // indirect github.com/klauspost/pgzip v1.2.6 // indirect github.com/mattn/go-colorable v0.1.15 // indirect - github.com/mattn/go-isatty v0.0.23 // indirect + github.com/mattn/go-isatty v0.0.24 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect - github.com/moby/moby/api v1.55.0 // indirect - github.com/moby/moby/client v0.5.0 // indirect + github.com/moby/moby/api v1.56.0 // indirect + github.com/moby/moby/client v0.6.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.1 // indirect - github.com/petermattis/goid v0.0.0-20260716134002-a9b348f0a2b9 // indirect + github.com/petermattis/goid v0.0.0-20260820044319-269ab09b5261 // indirect github.com/quic-go/qpack v0.6.0 // indirect - github.com/quic-go/quic-go v0.60.0 // indirect + github.com/quic-go/quic-go v0.62.0 // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/rs/cors v1.11.1 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/segmentio/asm v1.2.1 // indirect github.com/segmentio/encoding v0.5.4 // indirect - github.com/sirupsen/logrus v1.9.4 // indirect + github.com/sirupsen/logrus v1.10.2 // indirect github.com/spf13/cobra v1.10.2 // indirect github.com/spf13/pflag v1.0.10 // indirect github.com/tetratelabs/wazero v1.12.0 // indirect @@ -77,24 +77,24 @@ require ( go.lsp.dev/protocol v0.12.0 // indirect go.lsp.dev/uri v0.3.0 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0 // indirect - go.opentelemetry.io/otel v1.44.0 // indirect - go.opentelemetry.io/otel/metric v1.44.0 // indirect - go.opentelemetry.io/otel/trace v1.44.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.71.0 // indirect + go.opentelemetry.io/otel v1.46.0 // indirect + go.opentelemetry.io/otel/metric v1.46.0 // indirect + go.opentelemetry.io/otel/trace v1.46.0 // indirect go.uber.org/mock v0.6.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.28.0 // indirect - go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/crypto v0.54.0 // indirect - golang.org/x/exp v0.0.0-20260709172345-9ea1abe57597 // indirect - golang.org/x/mod v0.38.0 // indirect - golang.org/x/net v0.57.0 // indirect - golang.org/x/sync v0.22.0 // indirect + go.yaml.in/yaml/v3 v3.0.5 // indirect + golang.org/x/crypto v0.56.0 // indirect + golang.org/x/exp v0.0.0-20260824195058-e88cd73687aa // indirect + golang.org/x/mod v0.40.0 // indirect + golang.org/x/net v0.58.0 // indirect + golang.org/x/sync v0.23.0 // indirect golang.org/x/sys v0.47.0 // indirect golang.org/x/term v0.45.0 // indirect - golang.org/x/text v0.40.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20260715232425-e75dac1f907d // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20260715232425-e75dac1f907d // indirect + golang.org/x/text v0.41.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20260904194346-d0f1323225a4 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260904194346-d0f1323225a4 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect mvdan.cc/xurls/v2 v2.6.0 // indirect pluginrpc.com/pluginrpc v0.5.0 // indirect diff --git a/tools/proto/go.sum b/tools/proto/go.sum index d51ed71ab7c1d..ab10596db0edb 100644 --- a/tools/proto/go.sum +++ b/tools/proto/go.sum @@ -1,33 +1,35 @@ -buf.build/gen/go/bufbuild/bufplugin/protocolbuffers/go v1.36.11-20260626152828-968bf0468096.1 h1:bHi5/cwz7IPRhFcrRA4iytTjDI3WwFkv1m5K7y+YOTc= -buf.build/gen/go/bufbuild/bufplugin/protocolbuffers/go v1.36.11-20260626152828-968bf0468096.1/go.mod h1:1Znr6gmYBhbxWUPRrrVnSLXQsz8bvFVw1HHJq2bI3VQ= -buf.build/gen/go/bufbuild/protodescriptor/protocolbuffers/go v1.36.11-20250109164928-1da0de137947.1 h1:HwzzCRS4ZrEm1++rzSDxHnO0DOjiT1b8I/24e8a4exY= -buf.build/gen/go/bufbuild/protodescriptor/protocolbuffers/go v1.36.11-20250109164928-1da0de137947.1/go.mod h1:8PRKXhgNes29Tjrnv8KdZzg3I1QceOkzibW1QK7EXv0= -buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-20260709200747-435963d16310.1 h1:fXh8CsdNpjRr8R5vFdqtIxPt/Lno2IIJlYOdZBIZn0w= -buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-20260709200747-435963d16310.1/go.mod h1:tvtbpgaVXZX4g6Pn+AnzFycuRK3MOz5HJfEGeEllXYM= -buf.build/gen/go/bufbuild/registry/connectrpc/go v1.20.0-20260713175918-10d915f5b43b.1 h1:c4w6fQ6wAhZLgVI+HZozlWX9I2aVPN34vrl/8cuovVc= -buf.build/gen/go/bufbuild/registry/connectrpc/go v1.20.0-20260713175918-10d915f5b43b.1/go.mod h1:mbcuFKpnCQsF8H2fBs1lN1dQVAiASPQKwFgTkXqYscI= -buf.build/gen/go/bufbuild/registry/protocolbuffers/go v1.36.11-20260713175918-10d915f5b43b.1 h1:qJUlFKLFdb3OFCpmA+r5AQbysgBD7WLRapE9lOs08r8= -buf.build/gen/go/bufbuild/registry/protocolbuffers/go v1.36.11-20260713175918-10d915f5b43b.1/go.mod h1:1JJi9jvOqRxSMa+JxiZSm57doB+db/1WYCIa2lHfc40= -buf.build/gen/go/pluginrpc/pluginrpc/protocolbuffers/go v1.36.11-20241007202033-cf42259fcbfc.1 h1:iGPvEJltOXUMANWf0zajcRcbiOXLD90ZwPUFvbcuv6Q= -buf.build/gen/go/pluginrpc/pluginrpc/protocolbuffers/go v1.36.11-20241007202033-cf42259fcbfc.1/go.mod h1:nWVKKRA29zdt4uvkjka3i/y4mkrswyWwiu0TbdX0zts= -buf.build/go/app v0.2.1-0.20260626143626-be153867abea h1:krHaIyUJSTnurb0fbYQtsXkZWiWQ/ydOgfm61TPSODc= -buf.build/go/app v0.2.1-0.20260626143626-be153867abea/go.mod h1:V32mBaPWsfq6REAeZvvs/rQl7ZCl9Dn7eW1BBrmH0GQ= +buf.build/gen/go/bufbuild/bufplugin/protocolbuffers/go v1.36.12-20260722160903-4d94f3df3a7b.2 h1:z5+rVknD0AvorY/QV9cb3ohUXw4E7HvxU4+2JUH6EHU= +buf.build/gen/go/bufbuild/bufplugin/protocolbuffers/go v1.36.12-20260722160903-4d94f3df3a7b.2/go.mod h1:Owcuj2phVyvThVYCD74iSV8ki0dAXw/uxkdcdZScdCc= +buf.build/gen/go/bufbuild/protodescriptor/protocolbuffers/go v1.36.12-20250109164928-1da0de137947.2 h1:tE4A2RVukQOSd4K+6ndK+8s65FbjiBt2k5CiddXxCCo= +buf.build/gen/go/bufbuild/protodescriptor/protocolbuffers/go v1.36.12-20250109164928-1da0de137947.2/go.mod h1:Gjxz0o7qPHokNsmlX8D+/aKd29NRLRr9CCUkPeMAzJ0= +buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.12-20260825204119-511051f7f437.2 h1:NbnlmV26O7oZ1iM5tsCI+GEx+3ZSdrhvnKQ/eWSrLiY= +buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.12-20260825204119-511051f7f437.2/go.mod h1:TCt1lluMFnctISJXvkIQ4x3ABrPuUKCWKyjKdkJNBpw= +buf.build/gen/go/bufbuild/registry/connectrpc/go v1.20.0-20260831211851-b4432e12a6e7.1 h1:BpToyjv+oz0qldatN/ZFTL+vVtPVavFCY+g4rRu03bs= +buf.build/gen/go/bufbuild/registry/connectrpc/go v1.20.0-20260831211851-b4432e12a6e7.1/go.mod h1:hMqlU8iWXqCU7UOBs8PTDG/z7BFnhIknJZ4XMWcBx3E= +buf.build/gen/go/bufbuild/registry/protocolbuffers/go v1.36.12-20260831211851-b4432e12a6e7.2 h1:cik2XvKM1UV8HgLWD2vnBvV4GgT5NfpLJBb9UgLKzzg= +buf.build/gen/go/bufbuild/registry/protocolbuffers/go v1.36.12-20260831211851-b4432e12a6e7.2/go.mod h1:91H8i3iR9GoomNkM9X13RTFL8cVNAHnS44BdgAnbqz4= +buf.build/gen/go/pluginrpc/pluginrpc/protocolbuffers/go v1.36.12-20241007202033-cf42259fcbfc.2 h1:9xw8g8Q6zHLC7CO/jtpl2UK0kQticxIG+mI6N86f2/M= +buf.build/gen/go/pluginrpc/pluginrpc/protocolbuffers/go v1.36.12-20241007202033-cf42259fcbfc.2/go.mod h1:+0bw+k8FY5MU3tojFh33HeA5xMfGWjAUQpr+maW5Z3o= +buf.build/go/app v0.2.1-0.20260824172350-b0e76892c61a h1:m3hkeJOeLSq/1yTSMLyV5ipY6u3XrfS3gV8ZIqkUJJA= +buf.build/go/app v0.2.1-0.20260824172350-b0e76892c61a/go.mod h1:w19H+Lh2cAV/uL1FhcdDlyoxLTm8SkQAHW3CfmXZbFU= buf.build/go/bufplugin v0.10.0 h1:vZBX0mq9as5UIBug8U+/DkGRaHNlM/HVOw59O8fvOIU= buf.build/go/bufplugin v0.10.0/go.mod h1:ax7obVurKDH1I2nR4pFTS+TE6K3kZhTmwDCN2YgdV8I= buf.build/go/bufprivateusage v0.1.0 h1:SzCoCcmzS3zyXHEXHeSQhGI7OTkgtljoknLzsUz9Gg4= buf.build/go/bufprivateusage v0.1.0/go.mod h1:GlCCJ3VVF7EqqU0CoRmo1FzAwwaKymEWSr+ty69xU5w= buf.build/go/interrupt v1.1.0 h1:olBuhgv9Sav4/9pkSLoxgiOsZDgM5VhRhvRpn3DL0lE= buf.build/go/interrupt v1.1.0/go.mod h1:ql56nXPG1oHlvZa6efNC7SKAQ/tUjS6z0mhJl0gyeRM= -buf.build/go/protovalidate v1.2.0 h1:DQVrUWkmGTBij+kOYv/x2LLxwcLaGKMdzShj1/6/3H0= -buf.build/go/protovalidate v1.2.0/go.mod h1:7rYiQEhqvAipoazpVNBBH2S2f8bjG4huMVy1V2Yofn4= +buf.build/go/protovalidate v1.4.0 h1:UjLrYbt5VX7+TMOs2+pG5FhZhIG1mSfK4EIopbb4LcM= +buf.build/go/protovalidate v1.4.0/go.mod h1:8vJfzNT6NIG2qm3uFsJDXMlRmG+bQJzbcIn1Aa0vPGs= buf.build/go/protoyaml v0.7.0 h1:z4oVoFicbpPefhT7WAykxUdfp0yEQlhMQ2mCZOY5V38= buf.build/go/protoyaml v0.7.0/go.mod h1:+a0cavd0uMvirb87xdu2ZMMmjlIQoiH/N2Ich5MGSQ0= buf.build/go/spdx v0.2.0 h1:IItqM0/cMxvFJJumcBuP8NrsIzMs/UYjp/6WSpq8LTw= buf.build/go/spdx v0.2.0/go.mod h1:bXdwQFem9Si3nsbNy8aJKGPoaPi5DKwdeEp5/ArZ6w8= buf.build/go/standard v0.1.1-0.20260325175353-2b287e071df5 h1:njYKSWoLiq2i5O7y2bPPU2Yzp7iAU0Wk9KJ2OoAhNiU= buf.build/go/standard v0.1.1-0.20260325175353-2b287e071df5/go.mod h1:DQmodNT9EHX94WzUaWiZK+/4EaFa/xZTc1gzfCxZVXU= -cel.dev/expr v0.25.2 h1:K6j46C81hXtZQfuX60cVWQFBJahKSE2gfRbNuvr5bFs= -cel.dev/expr v0.25.2/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4= +cel.dev/cel-go v0.32.0 h1:irvpFKr5EuGPyxeME03ERh0rii1TX+BDAnB9eL3IvNk= +cel.dev/cel-go v0.32.0/go.mod h1:DnVip7tpJSsgZymwfT+m1tnEVy3ivAjSMXPx12YrMkU= +cel.dev/expr v0.25.3 h1:A2jO8jwOugrrovveCWfj0KEZOfqiLgAcwjpHPhzIGw0= +cel.dev/expr v0.25.3/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4= connectrpc.com/connect v1.20.0 h1:6TNDAB+WeNd2uolWNlYczB5E0KNNaVMNUEx8JEUsPmQ= connectrpc.com/connect v1.20.0/go.mod h1:A2ygJrukXwWy32vkCAAHNVguZrqZ+jeZ9rGRnGR4dN4= connectrpc.com/grpcreflect v1.3.0 h1:Y4V+ACf8/vOb1XOc251Qun7jMB75gCUNw6llvB9csXc= @@ -42,10 +44,10 @@ github.com/bmatcuk/doublestar/v4 v4.10.0 h1:zU9WiOla1YA122oLM6i4EXvGW62DvKZVxIe6 github.com/bmatcuk/doublestar/v4 v4.10.0/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= github.com/brianvoe/gofakeit/v6 v6.28.0 h1:Xib46XXuQfmlLS2EXRuJpqcw8St6qSZz75OUo0tgAW4= github.com/brianvoe/gofakeit/v6 v6.28.0/go.mod h1:Xj58BMSnFqcn/fAQeSK+/PLtC5kSb7FJIq4JyGa8vEs= -github.com/bufbuild/buf v1.72.0 h1:VMmGFtCLrxyS2wkpghExmhhiqJDdmc8DcwAvsGJGJ94= -github.com/bufbuild/buf v1.72.0/go.mod h1:bhtIlPDo3q/PDw4yaTdx2+jxkc33Aq+ygFIi6Diz2yU= -github.com/bufbuild/protocompile v0.14.2-0.20260716165721-bb5762d29672 h1:6xykiXQPoF/hhOjAhwiHQ0kgcAvrDZw0Tjl1VQkpu5c= -github.com/bufbuild/protocompile v0.14.2-0.20260716165721-bb5762d29672/go.mod h1:jPUiZUFWc8E3Kc2Y4SRlGAdjde4amGkHY0BUACNS43E= +github.com/bufbuild/buf v1.73.0 h1:fDNKlxaf+PYi20dmVM7Yt3kOfXEhwrgKDLMNZFjztDs= +github.com/bufbuild/buf v1.73.0/go.mod h1:rfWpi8FmfTPW4CbLFIXZYAux2FWBiCMY6BUOlGqnR84= +github.com/bufbuild/protocompile v0.14.2-0.20260910151042-7436f7c76201 h1:jBaIQ1eixwqtjBKJk8gw+dKtmbkp3w8sLJtJ7kav1EE= +github.com/bufbuild/protocompile v0.14.2-0.20260910151042-7436f7c76201/go.mod h1:bX3ObJfML+aki7PJevkWLSlOfEZ8EnNsfCz0hiYkhiI= github.com/bufbuild/protoplugin v0.0.0-20260414125817-25d1d281b46b h1:b7wvo9ZhjLzCp7tGbOUMvgtYTnd33zGSAmMxcdxMnhQ= github.com/bufbuild/protoplugin v0.0.0-20260414125817-25d1d281b46b/go.mod h1:c5D8gWRIZ2HLWO3gXYTtUfw/hbJyD8xikv2ooPxnklQ= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= @@ -59,16 +61,14 @@ github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmC github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/cpuguy83/go-md2man/v2 v2.0.7 h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3sHPnBo= github.com/cpuguy83/go-md2man/v2 v2.0.7/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= -github.com/docker/cli v29.6.1+incompatible h1:oO7F4nn3Ovr/5TlfTUWFbMwBSS/B7Xs6Epv26gBrUP8= -github.com/docker/cli v29.6.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= -github.com/docker/docker-credential-helpers v0.9.8 h1:bIREROb7So6PRlq6KTtdS9MPEjC29OQRkFNlvK2OX8Q= -github.com/docker/docker-credential-helpers v0.9.8/go.mod h1:v1S+hepowrQXITkEfw6o4+BMbGot02wiKpzWhGUZK6c= -github.com/docker/go-connections v0.7.0 h1:6SsRfJddP22WMrCkj19x9WKjEDTB+ahsdiGYf0mN39c= -github.com/docker/go-connections v0.7.0/go.mod h1:no1qkHdjq7kLMGUXYAduOhYPSJxxvgWBh7ogVvptn3Q= +github.com/docker/cli v29.8.0+incompatible h1:ih0c2jq/nN7QfES8zIfwSzIhRScjs4ehER+kZ60aeSk= +github.com/docker/cli v29.8.0+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/docker-credential-helpers v0.9.9 h1:BkydjIgZ46JnDbqyM2p2fc63KMw6y+KHL3Em/2AGJ7w= +github.com/docker/docker-credential-helpers v0.9.9/go.mod h1:v1S+hepowrQXITkEfw6o4+BMbGot02wiKpzWhGUZK6c= +github.com/docker/go-connections v0.8.1 h1:JibmG5hULs5qXSr/cp/w3Pw5fZuStt4MOHMUExb29/M= +github.com/docker/go-connections v0.8.1/go.mod h1:no1qkHdjq7kLMGUXYAduOhYPSJxxvgWBh7ogVvptn3Q= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/favadi/protoc-go-inject-tag v1.4.0 h1:K3KXxbgRw5WT4f43LbglARGz/8jVsDOS7uMjG4oNvXY= @@ -76,19 +76,17 @@ github.com/favadi/protoc-go-inject-tag v1.4.0/go.mod h1:AZ+PK+QDKUOLlBRG0rYiKkUX github.com/felixge/httpsnoop v1.1.0 h1:3YtUj32ZZkqZtt3sZZsClsymw/QDuVfpNhoA31zeORc= github.com/felixge/httpsnoop v1.1.0/go.mod h1:Zqxgdd+1Rkcz8euOqdr7lqgCRJztwr5hp9vDSi5UZCE= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= -github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.4 h1:tG4xh9yMsRCAiodLVTxyrkzSZ9+o0L1Kg/+cPVcbP/8= +github.com/go-logr/logr v1.4.4/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/gofrs/flock v0.13.0 h1:95JolYOvGMqeH31+FC7D2+uULf6mG61mEZ/A8dRYMzw= -github.com/gofrs/flock v0.13.0/go.mod h1:jxeyy9R1auM5S6JYDBhDt+E2TCo7DkratH4Pgi8P+Z0= -github.com/google/cel-go v0.29.2 h1:ZtDxkeiMmz0mxbKDYiNkE5Lk7V5edMRcaaDf2jX002k= -github.com/google/cel-go v0.29.2/go.mod h1:X0bD6iVNR8pkROSOoHVdgTkzmRcosof7WQqCD6wcMc8= +github.com/gofrs/flock v0.13.1 h1:jjREztyBeSKBZYAC+mgc1laB+xsgy4kYMf3FbKF2UBo= +github.com/gofrs/flock v0.13.1/go.mod h1:sf4BFiHwnvgxa25DlQoDqXQnwRMEOwqxRq37P6MzzmE= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 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/go-containerregistry v0.21.7 h1:/vPFuVXDjtFREsVArW+0h1CIl5urnOhzei4X2DMW9IU= -github.com/google/go-containerregistry v0.21.7/go.mod h1:kjSbt7/zMsKLWfnHrIvKvhXHUw91jbe9DNjPPJ32gXE= +github.com/google/go-containerregistry v0.22.1 h1:RZuuSYhTvlDvtsK+NkutoCZ//C0X2ebLK8X8l3ULs84= +github.com/google/go-containerregistry v0.22.1/go.mod h1:bJR35SK8XgisYmhg/FMQ/5RK0S/XrOAqLBV5/LR2XE0= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= @@ -97,8 +95,8 @@ github.com/jdx/go-netrc v1.0.0 h1:QbLMLyCZGj0NA8glAhxUpf1zDg6cxnWgMBbjq40W0gQ= github.com/jdx/go-netrc v1.0.0/go.mod h1:Gh9eFQJnoTNIRHXl2j5bJXA1u84hQWJWgGh569zF3v8= github.com/jhump/protoreflect/v2 v2.0.0-beta.2 h1:qZU+rEZUOYTz1Bnhi3xbwn+VxdXkLVeEpAeZzVXLY88= github.com/jhump/protoreflect/v2 v2.0.0-beta.2/go.mod h1:4tnOYkB/mq7QTyS3YKtVtNrJv4Psqout8HA1U+hZtgM= -github.com/klauspost/compress v1.19.0 h1:sXLILfc9jV2QYWkzFOPWStmcUVH2RHEB1JCdY2oVvCQ= -github.com/klauspost/compress v1.19.0/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ= +github.com/klauspost/compress v1.20.0 h1:a3C1ke2ohxFymNlb2HWAHjDeKCI90scRskErZkR0ezA= +github.com/klauspost/compress v1.20.0/go.mod h1:LUdAzn7YLVvxLpc7y3V1m40wESHTgc1422pwwBSKYuI= github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU= github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -107,20 +105,20 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mattn/go-colorable v0.1.15 h1:+u9SLTRGnXv73cEsnsmoZBom+dMU88B2M0aDcWy0/jY= github.com/mattn/go-colorable v0.1.15/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= -github.com/mattn/go-isatty v0.0.23 h1:cYwCQTQf3HB6xUC+BtyCLZNr7IzbOmoZbmssVNzSyiQ= -github.com/mattn/go-isatty v0.0.23/go.mod h1:nMCL3Zebbrt45jsMDgnfIwz6ydEQApk5oEI3HqDio6A= +github.com/mattn/go-isatty v0.0.24 h1:tGZZoVgT/KiqK1c8ocVLeDS8BSWMRd47J3Lbz7vsReI= +github.com/mattn/go-isatty v0.0.24/go.mod h1:nMCL3Zebbrt45jsMDgnfIwz6ydEQApk5oEI3HqDio6A= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= -github.com/moby/moby/api v1.55.0 h1:2/sexvQyqIWS8pRSCFddBfpW2qE7vR7FCL+vN8pxwMc= -github.com/moby/moby/api v1.55.0/go.mod h1:+RQ6wluLwtYaTd1WnPLykIDPekkuyD/ROWQClE83pzs= -github.com/moby/moby/client v0.5.0 h1:5XhyPk2fuOWf6RlSFa3MkIIgDZkF25xToXW8Q/BH7cc= -github.com/moby/moby/client v0.5.0/go.mod h1:rcVpF8ncl9vo5gaIBdol6CnbEtSj1uxMvEV/UrykF/s= +github.com/moby/moby/api v1.56.0 h1:GQzua3NA599ASSIICx0iFgiJeO9YkdDARvQsm23ZZuQ= +github.com/moby/moby/api v1.56.0/go.mod h1:sZ+THbVWkjOmBPPfbnzdD/G1LuIexWhqlSHHPTDQ1Uk= +github.com/moby/moby/client v0.6.0 h1:AJjEB21QPbXSXjDsZorFBoDZPhMrfbpaPLgSMAW9Bgs= +github.com/moby/moby/client v0.6.0/go.mod h1:OCo00wNRyA3m4lmJ228W3JbyCN4ZNNYjpOXiJydBdcQ= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= -github.com/petermattis/goid v0.0.0-20260716134002-a9b348f0a2b9 h1:UyKlK0Ke63afxhHrgJAk8KlCt+kP9KYBRUsWG6lK2WM= -github.com/petermattis/goid v0.0.0-20260716134002-a9b348f0a2b9/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= +github.com/petermattis/goid v0.0.0-20260820044319-269ab09b5261 h1:lcWAnrqr2nNfDiArwFNHCE4787Mw2tCdVSOXCru0/0E= +github.com/petermattis/goid v0.0.0-20260820044319-269ab09b5261/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/protocolbuffers/protoscope v0.0.0-20221109213918-8e7a6aafa2c9 h1:arwj11zP0yJIxIRiDn22E0H8PxfF7TsTrc2wIPFIsf4= @@ -129,8 +127,8 @@ github.com/quic-go/go-ossfuzz-seeds v0.1.0 h1:APacT+iIaNF6fd8AGEiN3bT/Jtkd2jz4v4 github.com/quic-go/go-ossfuzz-seeds v0.1.0/go.mod h1:3IOHRbJIc+L6YKMwfDtJAM9Vj9k0YY4muhuyUYk5tbk= github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8= github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII= -github.com/quic-go/quic-go v0.60.0 h1:xcQioE8OM66UQLeUMHltK1CCcOu3JbVB4JAQdDQSB+0= -github.com/quic-go/quic-go v0.60.0/go.mod h1:wpKpjmPpftl30sL6pFh7REVpjbcCVy4zt2vDyK1TuJk= +github.com/quic-go/quic-go v0.62.0 h1:ZHDjCk5OacATwGvs8PWE97CTvX7AqZiVoW7++ZOXTf8= +github.com/quic-go/quic-go v0.62.0/go.mod h1:RAro2j2yN9a9EiPACLHT9IB2NXCvGQmmo/alT0yYI0w= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rodaine/protogofakeit v0.1.1 h1:ZKouljuRM3A+TArppfBqnH8tGZHOwM/pjvtXe9DaXH8= @@ -145,15 +143,15 @@ github.com/segmentio/asm v1.2.1 h1:DTNbBqs57ioxAD4PrArqftgypG4/qNpXoJx8TVXxPR0= github.com/segmentio/asm v1.2.1/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= github.com/segmentio/encoding v0.5.4 h1:OW1VRern8Nw6ITAtwSZ7Idrl3MXCFwXHPgqESYfvNt0= github.com/segmentio/encoding v0.5.4/go.mod h1:HS1ZKa3kSN32ZHVZ7ZLPLXWvOVIiZtyJnO1gPH1sKt0= -github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w= -github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g= +github.com/sirupsen/logrus v1.10.2 h1:G2SED73/qrAu6YwbdxOD6peLkCBI3z7L+ykJFTXJBBo= +github.com/sirupsen/logrus v1.10.2/go.mod h1:SLEg8TqYulVKKfIGHldVp2K2aYz2DKSVBq4g/H5bR7Q= github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU= github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4= github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= -github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/stretchr/testify v1.12.1 h1:EuwCh5fleGS7H32xRwO3wRGT7DxrDhLAT6FF8MpWDWE= +github.com/stretchr/testify v1.12.1/go.mod h1:MDEgiDPPsNp5cuIrHPPCyornHKgEVbtFUmoNlxoYthg= github.com/tetratelabs/wazero v1.12.0 h1:DuWcpNu/FzgEXgGBDp8J1Spc+CWOvvtvVyjKlaZopYU= github.com/tetratelabs/wazero v1.12.0/go.mod h1:LvKtzl2RqO4gyF27BiXU+nKAjcV8f38U+kP/q2vgxh0= github.com/tidwall/btree v1.8.1 h1:27ehoXvm5AG/g+1VxLS1SD3vRhp/H7LuEfwNvddEdmA= @@ -168,18 +166,18 @@ go.lsp.dev/uri v0.3.0 h1:KcZJmh6nFIBeJzTugn5JTU6OOyG0lDOo3R9KwTxTYbo= go.lsp.dev/uri v0.3.0/go.mod h1:P5sbO1IQR+qySTWOCnhnK7phBx+W3zbLqSMDJNTw88I= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0 h1:8tvICD4vSTOOsNrsI4Ljf6C+6UKvpTEH5XY3JMoyPoo= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0/go.mod h1:z9+yiacE0IHRqM4qFfkbt/JYlmYXgss8GY/jXoNuPJI= -go.opentelemetry.io/otel v1.44.0 h1:JjwHmHpA4iZ3wBxluu2fbbE7j4kqlE8jXyAyPXH7HqU= -go.opentelemetry.io/otel v1.44.0/go.mod h1:BMgjTHL9WPRlRjL2oZCBTL4whCGtXch2H4BhOPIAyYc= -go.opentelemetry.io/otel/metric v1.44.0 h1:1w0gILTcHdr3YI+ixLyjemwrVnsMURbTZFrSYCdDdmc= -go.opentelemetry.io/otel/metric v1.44.0/go.mod h1:8O7hanEPBNgEMmybD3s2VBKcgWOCsA6tzHBPODAiquo= -go.opentelemetry.io/otel/sdk v1.44.0 h1:nHYwb9lK+fJPU/dnT6s7W7Z8itMWyqrnVfbheVYrZ58= -go.opentelemetry.io/otel/sdk v1.44.0/go.mod h1:Osuydd3Se74nqjAKxid74N5eC+jfEqfTegHRnq58oK0= -go.opentelemetry.io/otel/sdk/metric v1.44.0 h1:3LlKgI+VjbVsjNRFZJZAJ30WjXC5VkNRks6si09iEfI= -go.opentelemetry.io/otel/sdk/metric v1.44.0/go.mod h1:5B5pMARnXxKhltooO4xUuCBorl65a4EpnTalObqOigA= -go.opentelemetry.io/otel/trace v1.44.0 h1:jxF5CsGYCe74MCRx2X4g7WsY/VBKRqqpNvXlX/6gtIk= -go.opentelemetry.io/otel/trace v1.44.0/go.mod h1:oLl1jrMQAVo6v3GAggN+1VH9VIz9iUSvW53sW1Q8PIE= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.71.0 h1:3g7B90UzBltIDKq1/5mrTGxTnOFDV0ICOhLoxiZ8jlg= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.71.0/go.mod h1:Ef8SuTh59BT7+ofpDxN9z+yOlc4t2GjLmKDgYNJL/NU= +go.opentelemetry.io/otel v1.46.0 h1:FHt5/CDyVxi/8IM1CH7VE/rRgq3kLHa2mSTVMO8AWyc= +go.opentelemetry.io/otel v1.46.0/go.mod h1:Gj3SEScelsNC45tp4nSxRYlS+f5iez7W8XPMCt905kE= +go.opentelemetry.io/otel/metric v1.46.0 h1:yBnkXvgV7AXFILZc5K6IZe/CBFF3OS7BJ8ov6/lj0K8= +go.opentelemetry.io/otel/metric v1.46.0/go.mod h1:iPmdWqifKUdzziPkvvzIJXITl56fQx2mGM/DHLB3/2o= +go.opentelemetry.io/otel/sdk v1.46.0 h1:h5CNQQjEbuQXY/JfZtgt3i7HVFV3aHPO2OAwO2eTYPI= +go.opentelemetry.io/otel/sdk v1.46.0/go.mod h1:GAERFXFt5SYCEB+YiKUbMBeza6UaDH7GmGOZEfh2gSM= +go.opentelemetry.io/otel/sdk/metric v1.46.0 h1:0piZ26EG4RBfebb2jhDH6ERCYHoVWduc3kLgPCwSnSE= +go.opentelemetry.io/otel/sdk/metric v1.46.0/go.mod h1:I1PbKrdVc8Qu8HYVDNtqVIwLwjNrhsV/uFuxfwg8mO4= +go.opentelemetry.io/otel/trace v1.46.0 h1:OULy7ccdJnZtJ0UDYFOIGaCmiWzJ8Vi2G/Rsu60qs1c= +go.opentelemetry.io/otel/trace v1.46.0/go.mod h1:J7GAXweO77XSFkB/rmAqk9D6ihszhFjLU+d9WuUxDLI= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y= @@ -188,37 +186,38 @@ go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.28.0 h1:IZzaP1Fv73/T/pBMLk4VutPl36uNC+OSUh3JLG3FIjo= go.uber.org/zap v1.28.0/go.mod h1:rDLpOi171uODNm/mxFcuYWxDsqWSAVkFdX4XojSKg/Q= -go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= -golang.org/x/crypto v0.54.0 h1:YLIA59K4fiNzHzjnZt2tUJQjQtUWfWbeHBqKtk3eScw= -golang.org/x/crypto v0.54.0/go.mod h1:KWL8ny2AZdGR2cWmzeHrp2azQPGogOv+HeQaVEXC2dk= -golang.org/x/exp v0.0.0-20260709172345-9ea1abe57597 h1:qLvzZeaANDgyVOA8pyHCOStGlXn0rseXma+GQjeuv2g= -golang.org/x/exp v0.0.0-20260709172345-9ea1abe57597/go.mod h1:EdfpwwqSu+0Li0mzskwHU6FWDV3t9Q+RZDo3QMUtL3Q= -golang.org/x/mod v0.38.0 h1:MECBjubtXD7yj4HrhIUcywNaGeNVUdfVnxmPajOk4yk= -golang.org/x/mod v0.38.0/go.mod h1:V6Xz0pq8TQ3dGqVQ1FVHuelZpAL0uNhSkk9ogYP3c40= -golang.org/x/net v0.57.0 h1:K5+3DljvIuDG9/Jv9rvyMywYNFCQ9RSUY6OOTTkT+tE= -golang.org/x/net v0.57.0/go.mod h1:KpXc8iv+r3XplLAG/f7Jsf9RPszJzdR0f58q9vGOuEU= -golang.org/x/sync v0.22.0 h1:SZjpbeLmrCk4xhRSZFNZW5gFUeCeFgjekvI/+gfScek= -golang.org/x/sync v0.22.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= +go.yaml.in/yaml/v3 v3.0.5 h1:N6y/pJk8buWs9NY5ERU2HSMfm+IuD/OtfdAnq6kESPw= +go.yaml.in/yaml/v3 v3.0.5/go.mod h1:HVTZu1O7/Vkt2N+BFy8Zza+lnLsABggaTM2ZpNIGuKg= +golang.org/x/crypto v0.56.0 h1:GUh5Ii4J5jtcseSMiRqr1jXCNHoxjeV9Fmekc2oLy6Y= +golang.org/x/crypto v0.56.0/go.mod h1:OMW5y6CY9l38uPLmxU6l6pwcXp1obtLo3e6gT7gQR2I= +golang.org/x/exp v0.0.0-20260824195058-e88cd73687aa h1:QSyA8ishJCyT21kER9KwNt0b7BM3iRK4x9QXhjN5Fdk= +golang.org/x/exp v0.0.0-20260824195058-e88cd73687aa/go.mod h1:zeBbvyFKDaLwa7CH/zI8KXt7gTl14SF7sO08Pl5jBCM= +golang.org/x/mod v0.40.0 h1:hUv+3cXcdRHz08UmSiOob7sadHig73uo5bkXxQ/tvUs= +golang.org/x/mod v0.40.0/go.mod h1:0/weTWkPWGBikyTWAX3dkjVztMmBA5hM0DH6BElSupE= +golang.org/x/net v0.58.0 h1:ynWG7rqYi4ccpTEuPZ2QGWHktVEM9DMCj9yzDE0Q7To= +golang.org/x/net v0.58.0/go.mod h1:YwCddHnFlT7eLQqVprV19OnhLGtc5xOKgE0RyqgfWAU= +golang.org/x/sync v0.23.0 h1:KameEIfc1IkluZyXWLn39Wd4tURc6GbCiISGiZm2bQk= +golang.org/x/sync v0.23.0/go.mod h1:sUUOizhqBxiL6pEWpqNLUiaJn1ShEbZ6BBqskPbjZm0= golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs= golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/term v0.45.0 h1:NwWyBmoJCbfTHpxrWoZ9C6/VxOf7ic219I8xZZFdrf0= golang.org/x/term v0.45.0/go.mod h1:9aqxs0blBcrm/n0L9QW0aRVD+ktan8ssZromtqJC43w= -golang.org/x/text v0.40.0 h1:Ub2Z6/xjgF1WrYQz2nuITOEegKFtiIy+rieRJ5lHZKs= -golang.org/x/text v0.40.0/go.mod h1:hpnzDAfGV753zIKo+wk3u1bVKCGPbrnF7+7LBF/UHVY= -golang.org/x/tools v0.48.0 h1:3+hClM1aLL5mjMKm5ovokw9epgRXPuu2tILgismM6RE= -golang.org/x/tools v0.48.0/go.mod h1:08xX0orndb/F7jJxGDicx061tyd5pcMto75YMAXr6lk= +golang.org/x/text v0.41.0 h1:vz/seA0lnX87Othu2f/0L24RcgrXD9/YFTSuGjj3rH8= +golang.org/x/text v0.41.0/go.mod h1:jvf1O8ajNzZqhSrQBPbutR/EB83Cc0CFrezNQIwbb5M= +golang.org/x/tools v0.49.0 h1:3NI7VXzL9+1WZD52Dx2ttoPwD5DWrFGpl9mFZDlmisI= +golang.org/x/tools v0.49.0/go.mod h1:SJNXV9DBKT0UbdttsQjbfJlAE/q+y36++zo3uL3N0Oo= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/genproto/googleapis/api v0.0.0-20260715232425-e75dac1f907d h1:QwnJwPte4XXAkhPu26LTDIahnsMSUV0kK8HkxbC+Pc4= -google.golang.org/genproto/googleapis/api v0.0.0-20260715232425-e75dac1f907d/go.mod h1:WRrQ7/7N19PypuT0fxLOL5Lq0waoiRri4FbtHDEKrGE= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260715232425-e75dac1f907d h1:Jkpk39hlTZOIp3RbfvNX9R8Hv+Sw0X89nlU/xFOErsc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260715232425-e75dac1f907d/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= -google.golang.org/grpc v1.81.0 h1:W3G9N3KQf3BU+YuCtGKJk0CmxQNbAISICD/9AORxLIw= -google.golang.org/grpc v1.81.0/go.mod h1:xGH9GfzOyMTGIOXBJmXt+BX/V0kcdQbdcuwQ/zNw42I= +google.golang.org/genproto/googleapis/api v0.0.0-20260904194346-d0f1323225a4 h1:NCe/UiklGd/9xjT+ROBVhJ1kf6TRQaFedsR+z7u1gvo= +google.golang.org/genproto/googleapis/api v0.0.0-20260904194346-d0f1323225a4/go.mod h1:fJ2lYaWjqNknJyQBOCd0fA3HnEElJqGplH71a2txi+g= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260904194346-d0f1323225a4 h1:5t+ZydAFj5kGVLrgCvLmpmCf9ylGRd64hpEronfRaws= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260904194346-d0f1323225a4/go.mod h1:DjtHYE8FKJLivXcBEjGwndXfIC23G0VpXiXKqG179uA= +google.golang.org/grpc v1.83.1 h1:HIO0+BEtBP6soyqvqC8sNUjZ7bTs+0hFQuFF+RAy++Y= +google.golang.org/grpc v1.83.1/go.mod h1:kDyl6SKsiHKt0uylY5gtn5cEjkrIOhQOGDgIc4JGwzQ= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.6.2 h1:rgSNvqscFZ1JgV/4wH5GOsZFSFkR2Eua9As3KIr2LlM= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.6.2/go.mod h1:iMEtFwDlAhjDU9L5mY6U1XLwlIId/G3h+QcBHDIvrJ8= -google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= -google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +google.golang.org/protobuf v1.36.12 h1:pJOKDDOyeXErUroCihFAd5LQuwXBSpVnKGrj5o/fwxc= +google.golang.org/protobuf v1.36.12/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= diff --git a/tools/roxvet/common/traverse.go b/tools/roxvet/common/traverse.go index 5a4d2ce5fd22c..358a16d3498a9 100644 --- a/tools/roxvet/common/traverse.go +++ b/tools/roxvet/common/traverse.go @@ -2,6 +2,7 @@ package common import ( "go/ast" + "slices" "golang.org/x/tools/go/ast/inspector" ) @@ -11,7 +12,7 @@ import ( func FilteredPreorder(inspector *inspector.Inspector, fileFilter FileFilter, nodeTypes []ast.Node, fn func(n ast.Node)) { // Limit the nodeTypes slice's capacity to its length. This ensures that any call to `append` will not write into // the backing storage, but allocate a new slice. - effectiveTypes := nodeTypes[:len(nodeTypes):len(nodeTypes)] + effectiveTypes := slices.Clip(nodeTypes) hadFile := hasFile(nodeTypes) if !hadFile { effectiveTypes = append(effectiveTypes, (*ast.File)(nil)) @@ -33,7 +34,7 @@ func FilteredPreorder(inspector *inspector.Inspector, fileFilter FileFilter, nod // FilteredNodes calls `inspector.Nodes(nodeTypes, fn)`, but filters out all files that do not pass the given // fileFilter. func FilteredNodes(inspector *inspector.Inspector, fileFilter FileFilter, nodeTypes []ast.Node, fn func(n ast.Node, push bool) bool) { - effTypes := nodeTypes[:len(nodeTypes):len(nodeTypes)] + effTypes := slices.Clip(nodeTypes) hadFile := hasFile(nodeTypes) if !hadFile { effTypes = append(effTypes, (*ast.File)(nil)) diff --git a/tools/test/go.mod b/tools/test/go.mod index 507306861087c..a3abe16a62fec 100644 --- a/tools/test/go.mod +++ b/tools/test/go.mod @@ -4,24 +4,24 @@ go 1.26.3 require ( github.com/jstemmer/go-junit-report/v2 v2.1.0 - github.com/stackrox/image-prefetcher/deploy v0.5.2 + github.com/stackrox/image-prefetcher/deploy v0.6.0 github.com/stackrox/prometheus-metric-parser v0.0.0-20240718111853-be492d554cd5 ) require ( - cloud.google.com/go/auth v0.5.1 // indirect - cloud.google.com/go/auth/oauth2adapt v0.2.2 // indirect + cloud.google.com/go/auth v0.18.2 // indirect + cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect cloud.google.com/go/compute/metadata v0.9.0 // indirect - cloud.google.com/go/monitoring v1.19.0 // indirect + cloud.google.com/go/monitoring v1.24.3 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect - github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.4 // indirect - github.com/google/s2a-go v0.1.7 // indirect - github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect - github.com/googleapis/gax-go/v2 v2.12.4 // indirect + github.com/google/s2a-go v0.1.9 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.11 // indirect + github.com/googleapis/gax-go/v2 v2.17.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/pkg/errors v0.9.1 // indirect @@ -31,24 +31,24 @@ require ( github.com/prometheus/prom2json v1.3.3 // indirect github.com/spf13/cobra v1.10.1 // indirect github.com/spf13/pflag v1.0.10 // indirect - go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.52.0 // indirect - go.opentelemetry.io/otel v1.43.0 // indirect - go.opentelemetry.io/otel/metric v1.43.0 // indirect - go.opentelemetry.io/otel/trace v1.43.0 // indirect - golang.org/x/crypto v0.52.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect + go.opentelemetry.io/otel v1.44.0 // indirect + go.opentelemetry.io/otel/metric v1.44.0 // indirect + go.opentelemetry.io/otel/trace v1.44.0 // indirect + golang.org/x/crypto v0.55.0 // indirect golang.org/x/exp v0.0.0-20240604190554-fc45aab8b7f8 // indirect - golang.org/x/net v0.55.0 // indirect + golang.org/x/net v0.58.0 // indirect golang.org/x/oauth2 v0.36.0 // indirect - golang.org/x/sync v0.20.0 // indirect - golang.org/x/sys v0.45.0 // indirect - golang.org/x/text v0.37.0 // indirect - golang.org/x/time v0.5.0 // indirect - google.golang.org/api v0.183.0 // indirect - google.golang.org/genproto v0.0.0-20240610135401-a8a62080eff3 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20260414002931-afd174a4e478 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478 // indirect - google.golang.org/grpc v1.82.1 // indirect + golang.org/x/sync v0.22.0 // indirect + golang.org/x/sys v0.47.0 // indirect + golang.org/x/text v0.41.0 // indirect + golang.org/x/time v0.14.0 // indirect + google.golang.org/api v0.264.0 // indirect + google.golang.org/genproto v0.0.0-20260128011058-8636f8732409 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa // indirect + google.golang.org/grpc v1.83.2 // indirect google.golang.org/protobuf v1.36.11 // indirect ) diff --git a/tools/test/go.sum b/tools/test/go.sum index f7ff091e5b80e..9e50e8218aac6 100644 --- a/tools/test/go.sum +++ b/tools/test/go.sum @@ -1,73 +1,44 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go/auth v0.5.1 h1:0QNO7VThG54LUzKiQxv8C6x1YX7lUrzlAa1nVLF8CIw= -cloud.google.com/go/auth v0.5.1/go.mod h1:vbZT8GjzDf3AVqCcQmqeeM32U9HBFc32vVVAbwDsa6s= -cloud.google.com/go/auth/oauth2adapt v0.2.2 h1:+TTV8aXpjeChS9M+aTtN/TjdQnzJvmzKFt//oWu7HX4= -cloud.google.com/go/auth/oauth2adapt v0.2.2/go.mod h1:wcYjgpZI9+Yu7LyYBg4pqSiaRkfEK3GQcpb7C/uyF1Q= +cloud.google.com/go/auth v0.18.2 h1:+Nbt5Ev0xEqxlNjd6c+yYUeosQ5TtEUaNcN/3FozlaM= +cloud.google.com/go/auth v0.18.2/go.mod h1:xD+oY7gcahcu7G2SG2DsBerfFxgPAJz17zz2joOFF3M= +cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc= +cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c= cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs= cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10= -cloud.google.com/go/monitoring v1.19.0 h1:NCXf8hfQi+Kmr56QJezXRZ6GPb80ZI7El1XztyUuLQI= -cloud.google.com/go/monitoring v1.19.0/go.mod h1:25IeMR5cQ5BoZ8j1eogHE5VPJLlReQ7zFp5OiLgiGZw= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +cloud.google.com/go/monitoring v1.24.3 h1:dde+gMNc0UhPZD1Azu6at2e79bfdztVDS5lvhOdsgaE= +cloud.google.com/go/monitoring v1.24.3/go.mod h1:nYP6W0tm3N9H/bOw8am7t62YTzZY+zUeQ+Bi6+2eonI= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/xds/go v0.0.0-20260202195803-dba9d589def2 h1:aBangftG7EVZoUb69Os8IaYg++6uMOdKK83QtkkvJik= github.com/cncf/xds/go v0.0.0-20260202195803-dba9d589def2/go.mod h1:qwXFYgsP6T7XnJtbKlf1HP8AjxZZyzxMmc+Lq5GjlU4= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.14.0 h1:hbG2kr4RuFj222B6+7T83thSPqLjwBIfQawTkC++2HA= github.com/envoyproxy/go-control-plane/envoy v1.37.0 h1:u3riX6BoYRfF4Dr7dwSOroNfdSbEPe9Yyl09/B6wBrQ= github.com/envoyproxy/go-control-plane/envoy v1.37.0/go.mod h1:DReE9MMrmecPy+YvQOAOHNYMALuowAnbjjEMkkWOi6A= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v1.3.3 h1:MVQghNeW+LZcmXe7SY1V36Z+WFMDjpqGAGacLe2T0ds= github.com/envoyproxy/protoc-gen-validate v1.3.3/go.mod h1:TsndJ/ngyIdQRhMcVVGDDHINPLWB7C82oDArY51KfB0= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 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/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= -github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= -github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0= +github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= -github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= -github.com/googleapis/gax-go/v2 v2.12.4 h1:9gWcmF85Wvq4ryPFvGFaOgPIs1AQX0d0bcbGw4Z96qg= -github.com/googleapis/gax-go/v2 v2.12.4/go.mod h1:KYEYLorsnIGDi/rPC8b5TdlB9kbKoFubselGIoBMCwI= +github.com/googleapis/enterprise-certificate-proxy v0.3.11 h1:vAe81Msw+8tKUxi2Dqh/NZMz7475yUvmRIkXr4oN2ao= +github.com/googleapis/enterprise-certificate-proxy v0.3.11/go.mod h1:RFV7MUdlb7AgEq2v7FmMCfeSMCllAzWxFgRdusoGks8= +github.com/googleapis/gax-go/v2 v2.17.0 h1:RksgfBpxqff0EZkDWYuz9q/uWsTVz+kf43LsZ1J6SMc= +github.com/googleapis/gax-go/v2 v2.17.0/go.mod h1:mzaqghpQp4JDh3HvADwrat+6M3MOIDp5YKHhb9PAgDY= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jstemmer/go-junit-report/v2 v2.1.0 h1:X3+hPYlSczH9IMIpSC9CQSZA0L+BipYafciZUWHEmsc= @@ -78,10 +49,8 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo= github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= github.com/prometheus/common v0.54.0 h1:ZlZy0BgJhTwVZUn7dLOkwCZHUkrAqd3WYtcFCWnM1D8= @@ -94,115 +63,59 @@ github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4 github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/stackrox/image-prefetcher/deploy v0.5.2 h1:b8VP/i6xD46aAxMHq9nLgyq4vMYqOxrkssUkxGMskh0= -github.com/stackrox/image-prefetcher/deploy v0.5.2/go.mod h1:bAhl/GuKJnAchWpAYkEaoqfaJHqCkbBKhLDWHm1GXLs= +github.com/stackrox/image-prefetcher/deploy v0.6.0 h1:KLH2unXZSFEbPOakWliu9XXRmzInytkGiNk3zQtuWxs= +github.com/stackrox/image-prefetcher/deploy v0.6.0/go.mod h1:rz+MNwLZL+Ur3rNABFPggUIfW/z/BOdfKfmCS/3L83g= github.com/stackrox/prometheus-metric-parser v0.0.0-20240718111853-be492d554cd5 h1:gAg8XyBlWRq8Ia4uTPmhNUnVYtiDN4eiqviJ+tD87xw= github.com/stackrox/prometheus-metric-parser v0.0.0-20240718111853-be492d554cd5/go.mod h1:y4d4bwvOygvByIxM/g0XCzBKMryqXilCk4Lj+mMBsVM= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -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.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= -go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= -go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.52.0 h1:vS1Ao/R55RNV4O7TA2Qopok8yN+X0LIP6RVWLFkprck= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.52.0/go.mod h1:BMsdeOxN04K0L5FNUBfjFdvwWGNe/rkmSwH4Aelu/X0= -go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I= -go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0= -go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM= -go.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY= -go.opentelemetry.io/otel/sdk v1.43.0 h1:pi5mE86i5rTeLXqoF/hhiBtUNcrAGHLKQdhg4h4V9Dg= -go.opentelemetry.io/otel/sdk v1.43.0/go.mod h1:P+IkVU3iWukmiit/Yf9AWvpyRDlUeBaRg6Y+C58QHzg= -go.opentelemetry.io/otel/sdk/metric v1.43.0 h1:S88dyqXjJkuBNLeMcVPRFXpRw2fuwdvfCGLEo89fDkw= -go.opentelemetry.io/otel/sdk/metric v1.43.0/go.mod h1:C/RJtwSEJ5hzTiUz5pXF1kILHStzb9zFlIEe85bhj6A= -go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A= -go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.52.0 h1:RMs7fP2rXdep0CftQlK8Uf+kibLm7qkCcradZWYz988= -golang.org/x/crypto v0.52.0/go.mod h1:1QgfPxDqh0T2M/elOJtp9RvuR95kVjir0e6/BvEmGbc= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 h1:q4XOmH/0opmeuJtPsbFNivyl7bCt7yRBbeEm2sC/XtQ= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0/go.mod h1:snMWehoOh2wsEwnvvwtDyFCxVeDAODenXHtn5vzrKjo= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q= +go.opentelemetry.io/otel v1.44.0 h1:JjwHmHpA4iZ3wBxluu2fbbE7j4kqlE8jXyAyPXH7HqU= +go.opentelemetry.io/otel v1.44.0/go.mod h1:BMgjTHL9WPRlRjL2oZCBTL4whCGtXch2H4BhOPIAyYc= +go.opentelemetry.io/otel/metric v1.44.0 h1:1w0gILTcHdr3YI+ixLyjemwrVnsMURbTZFrSYCdDdmc= +go.opentelemetry.io/otel/metric v1.44.0/go.mod h1:8O7hanEPBNgEMmybD3s2VBKcgWOCsA6tzHBPODAiquo= +go.opentelemetry.io/otel/sdk v1.44.0 h1:nHYwb9lK+fJPU/dnT6s7W7Z8itMWyqrnVfbheVYrZ58= +go.opentelemetry.io/otel/sdk v1.44.0/go.mod h1:Osuydd3Se74nqjAKxid74N5eC+jfEqfTegHRnq58oK0= +go.opentelemetry.io/otel/sdk/metric v1.44.0 h1:3LlKgI+VjbVsjNRFZJZAJ30WjXC5VkNRks6si09iEfI= +go.opentelemetry.io/otel/sdk/metric v1.44.0/go.mod h1:5B5pMARnXxKhltooO4xUuCBorl65a4EpnTalObqOigA= +go.opentelemetry.io/otel/trace v1.44.0 h1:jxF5CsGYCe74MCRx2X4g7WsY/VBKRqqpNvXlX/6gtIk= +go.opentelemetry.io/otel/trace v1.44.0/go.mod h1:oLl1jrMQAVo6v3GAggN+1VH9VIz9iUSvW53sW1Q8PIE= +golang.org/x/crypto v0.55.0 h1:+KWHjbgOaAQ66dh/YlkZKHlz9ZUlq61AFirAR9ntP8M= +golang.org/x/crypto v0.55.0/go.mod h1:uq0V9dE/fzQuJtbnL+2EhWOE63vo164FY8xqEnV9xis= golang.org/x/exp v0.0.0-20240604190554-fc45aab8b7f8 h1:LoYXNGAShUG3m/ehNk4iFctuhGX/+R1ZpfJ4/ia80JM= golang.org/x/exp v0.0.0-20240604190554-fc45aab8b7f8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8= -golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/net v0.58.0 h1:ynWG7rqYi4ccpTEuPZ2QGWHktVEM9DMCj9yzDE0Q7To= +golang.org/x/net v0.58.0/go.mod h1:YwCddHnFlT7eLQqVprV19OnhLGtc5xOKgE0RyqgfWAU= golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs= golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= -golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY= -golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc= -golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38= -golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= -golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/sync v0.22.0 h1:SZjpbeLmrCk4xhRSZFNZW5gFUeCeFgjekvI/+gfScek= +golang.org/x/sync v0.22.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= +golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs= +golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/text v0.41.0 h1:vz/seA0lnX87Othu2f/0L24RcgrXD9/YFTSuGjj3rH8= +golang.org/x/text v0.41.0/go.mod h1:jvf1O8ajNzZqhSrQBPbutR/EB83Cc0CFrezNQIwbb5M= +golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= +golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= -google.golang.org/api v0.183.0 h1:PNMeRDwo1pJdgNcFQ9GstuLe/noWKIc89pRWRLMvLwE= -google.golang.org/api v0.183.0/go.mod h1:q43adC5/pHoSZTx5h2mSmdF7NcyfW9JuDyIOJAgS9ZQ= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20240610135401-a8a62080eff3 h1:8RTI1cmuvdY9J7q/jpJWEj5UfgWjhV5MCoXaYmwLBYQ= -google.golang.org/genproto v0.0.0-20240610135401-a8a62080eff3/go.mod h1:qb66gsewNb7Ghv1enkhJiRfYGWUklv3n6G8UvprOhzA= -google.golang.org/genproto/googleapis/api v0.0.0-20260414002931-afd174a4e478 h1:yQugLulqltosq0B/f8l4w9VryjV+N/5gcW0jQ3N8Qec= -google.golang.org/genproto/googleapis/api v0.0.0-20260414002931-afd174a4e478/go.mod h1:C6ADNqOxbgdUUeRTU+LCHDPB9ttAMCTff6auwCVa4uc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478 h1:RmoJA1ujG+/lRGNfUnOMfhCy5EipVMyvUE+KNbPbTlw= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.82.1 h1:NnAxzGRA0677vCa4BUkOAnO5+FfQqVl9iUXeD0IqcGE= -google.golang.org/grpc v1.82.1/go.mod h1:yzTZ1TB1Z3SG+LIYaI+WiE8D5+PZ3ArnrSp8zF3+/ZA= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/api v0.264.0 h1:+Fo3DQXBK8gLdf8rFZ3uLu39JpOnhvzJrLMQSoSYZJM= +google.golang.org/api v0.264.0/go.mod h1:fAU1xtNNisHgOF5JooAs8rRaTkl2rT3uaoNGo9NS3R8= +google.golang.org/genproto v0.0.0-20260128011058-8636f8732409 h1:VQZ/yAbAtjkHgH80teYd2em3xtIkkHd7ZhqfH2N9CsM= +google.golang.org/genproto v0.0.0-20260128011058-8636f8732409/go.mod h1:rxKD3IEILWEu3P44seeNOAwZN4SaoKaQ/2eTg4mM6EM= +google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa h1:Kjn0N0tCrDgiAFW+lGO4JZ3ck44CehvJQMAwj9QF0G8= +google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:q4lMZS6kskjT5HvCPrnnypcDPVJqT/f4nfxmkE7gryY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa h1:mZHHdPZl0dbGHCflZgAq/Q468DWVFcU2whhB2KAo8fk= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= +google.golang.org/grpc v1.83.2 h1:EManeRomTObA0BU7I8vXgg/78uE5MJ9M8B39EX2WscU= +google.golang.org/grpc v1.83.2/go.mod h1:YPI1hK3kDked6iHvgX3tR0y+nX/qpMFKhPgFsokw1S8= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/ui/apps/platform/README.md b/ui/apps/platform/README.md index 456c6968fbfaf..9ef4fa12b792f 100644 --- a/ui/apps/platform/README.md +++ b/ui/apps/platform/README.md @@ -452,6 +452,12 @@ Given a feature flag environment variable `"ROX_WHATEVER"` in pkg/features/list. customize_envVars+=$'\n value: "true"' ``` + * Add `env_with_default ROX_WHATEVER "true"` to `collect_feature_flags` function in tests/e2e/lib-compat.sh + + roxie-based e2e deployments read feature flag overrides from this separate list, not from + `export_test_environment`. Skipping this step makes `TestFeatureFlagSettings` fail in + roxie-based jobs because the Go test process and the deployed Central disagree on the flag's value. + The value of feature flags for **demo** and **release** builds is in pkg/features/list.go 5. To turn on a feature flag for **local deployment**, do either or both of the following: @@ -523,6 +529,8 @@ Given a feature flag environment variable `"ROX_WHATEVER"` in pkg/features/list. customize_envVars+=$'\n value: "true"' ``` + * Delete `env_with_default ROX_WHATEVER "true"` from `collect_feature_flags` function in tests/e2e/lib-compat.sh + ### Routes #### Add a route diff --git a/ui/apps/platform/TESTING_E2E.md b/ui/apps/platform/TESTING_E2E.md index 8f8756a146f28..bc4d28eddacba 100644 --- a/ui/apps/platform/TESTING_E2E.md +++ b/ui/apps/platform/TESTING_E2E.md @@ -116,7 +116,7 @@ This sets `localStorage.access_token` from the `ROX_AUTH_TOKEN` env var in `befo ## Feature Flag Gating -Tests that depend on a feature flag should skip when the flag is not enabled. The test runner scripts (`scripts/cypress.sh`) fetch flags from the deployment API and export them as `CYPRESS_ROX_*` env vars. +Tests that depend on a feature flag should skip when the flag is not enabled. The test runner scripts (`scripts/cypress.sh`) fetch flags from the deployment API and export them as `CYPRESS_ROX_*` env vars, which `cypress.config.js` copies to `Cypress.expose()` for synchronous access in tests. For individual tests, skip inside the `it` block: @@ -263,7 +263,7 @@ Globally applicable helper functions (`cypress/helpers/*`). Use these frequently | `helpers/request.js` | API interception and waiting | `interceptRequests`, `waitForResponses`, `interactAndWaitForResponses`, `interceptAndWatchRequests`, `interceptAndOverridePermissions`, `interceptAndOverrideFeatureFlags` | | `helpers/visit.js` | Page navigation with auto auth handling and request awaiting | `visit`, `visitWithStaticResponseForPermissions`, `visitWithStaticResponseForAuthStatus` | | `helpers/basicAuth.js` | Test authentication setup | `withAuth` (default export) | -| `helpers/features.js` | Feature flag and orchestrator checks | `hasFeatureFlag`, `hasOrchestratorFlavor` | +| `helpers/features.js` | Feature flag and orchestrator checks via `Cypress.expose()` | `hasFeatureFlag`, `hasOrchestratorFlavor` | | `helpers/nav.ts` | Left navigation interactions | `visitFromLeftNav`, `visitFromLeftNavExpandable` | | `helpers/formHelpers.js` | Form element interactions | `getInputByLabel`, `getSelectButtonByLabel`, `getSelectOption`, `generateNameWithDate` | | `helpers/tableHelpers.ts` | Table row/column interactions | `getTableRowLinkByName`, `openTableRowActionMenu`, `sortByTableHeader`, `assertOnEachRowForColumn` | diff --git a/ui/apps/platform/cypress.config.js b/ui/apps/platform/cypress.config.js index d41c983d4040a..d0b0de761e573 100644 --- a/ui/apps/platform/cypress.config.js +++ b/ui/apps/platform/cypress.config.js @@ -7,6 +7,24 @@ const cypressVite = require('cypress-vite'); // and make the path available at test runtime when injecting the axe core. const axeCorePath = require.resolve('axe-core/axe.min.js'); +const PUBLIC_ENV_KEYS = ['ORCHESTRATOR_FLAVOR']; + +/* + * Cypress only fills expose from the config file or the --expose CLI flag, so copy the public + * CYPRESS_* values exported by scripts/cypress.sh. Feature flag names come from /v1/featureflags + * at runtime, so match them by prefix and boolean value. Secrets such as ROX_AUTH_TOKEN, + * DEMO_PASSWORD, and the OCP console credentials stay readable only through cy.env(). + */ +function getPublicEnv(env = {}) { + return Object.fromEntries( + Object.entries(env).filter( + ([key, value]) => + PUBLIC_ENV_KEYS.includes(key) || + (key.startsWith('ROX_') && typeof value === 'boolean') + ) + ); +} + /* * The helper function intended to provide automatic code completion for configuration in many popular code editors * had subtle side-effect to cause some typescript-eslint/no-unsafe-return errors in unit test files. @@ -16,6 +34,7 @@ const axeCorePath = require.resolve('axe-core/axe.min.js'); */ module.exports = { + allowCypressEnv: false, chromeWebSecurity: false, // Browser options defaultCommandTimeout: 8000, // Timeouts options numTestsKeptInMemory: 0, // Global options @@ -37,7 +56,11 @@ module.exports = { viewportWidth: 1440, // Viewport options setupNodeEvents: (on, config) => { // eslint-disable-next-line no-param-reassign - config.env.AXE_CORE_PATH = axeCorePath; + config.expose = { + ...config.expose, + ...getPublicEnv(config.env), + AXE_CORE_PATH: axeCorePath, + }; on('task', { beforeSuite(spec) { // eslint-disable-next-line no-console diff --git a/ui/apps/platform/cypress/helpers/features.js b/ui/apps/platform/cypress/helpers/features.js index fabd7989c2447..4102f03468a91 100644 --- a/ui/apps/platform/cypress/helpers/features.js +++ b/ui/apps/platform/cypress/helpers/features.js @@ -2,9 +2,9 @@ * Return whether or not the testing environment has a feature flag. */ export function hasFeatureFlag(flag) { - return Cypress.env(flag) || false; + return Cypress.expose(flag) || false; } export function hasOrchestratorFlavor(value) { - return Cypress.env('ORCHESTRATOR_FLAVOR') === value; + return Cypress.expose('ORCHESTRATOR_FLAVOR') === value; } diff --git a/ui/apps/platform/cypress/helpers/main.js b/ui/apps/platform/cypress/helpers/main.js index d5cc4298bd905..bc5dc00a201d2 100644 --- a/ui/apps/platform/cypress/helpers/main.js +++ b/ui/apps/platform/cypress/helpers/main.js @@ -1,6 +1,5 @@ import pf6 from '../selectors/pf6'; -import { hasFeatureFlag } from './features'; import { getRouteMatcherMapForGraphQL } from './request'; import { visit, visitConsole, visitWithStaticResponseForPermissions } from './visit'; @@ -42,9 +41,6 @@ const routeMatcherMapForViolationsByPolicyCategory = { url: '/v1/alerts/summary/counts?request.query=&group_by=CATEGORY', }, }; -const routeMatcherMapForComplianceLevelsByStandard = getRouteMatcherMapForGraphQL([ - getAggregatedResultsOpname, -]); function getRouteMatcherMap() { return { @@ -55,9 +51,6 @@ function getRouteMatcherMap() { ...routeMatcherMapForDeploymentsAtMostRisk, ...routeMatcherMapForAgingImages, ...routeMatcherMapForViolationsByPolicyCategory, - ...(hasFeatureFlag('ROX_DEPRECATED_COMPLIANCE_DASHBOARD') - ? routeMatcherMapForComplianceLevelsByStandard - : {}), }; } diff --git a/ui/apps/platform/cypress/integration-ocp/smoke.test.ts b/ui/apps/platform/cypress/integration-ocp/smoke.test.ts index 13cfd9b1a9cbb..ff6b5fa915c08 100644 --- a/ui/apps/platform/cypress/integration-ocp/smoke.test.ts +++ b/ui/apps/platform/cypress/integration-ocp/smoke.test.ts @@ -32,12 +32,10 @@ describe('Basic tests of the OCP plugin', () => { it('should display plugin information in cluster settings', () => { visitConsoleDynamicPluginsStatusPage(); - cy.get('td[data-label="name"]:contains("advanced-cluster-security")') + cy.get('td:has(a:contains("advanced-cluster-security"))') .parent() .within(() => { - cy.get('td[data-label="version"]') - .invoke('text') - .should('match', /^[1-9]\d*\.\d+\.\d+/); + cy.contains('td', /^[1-9]\d*\.\d+\.\d+/); }); }); }); diff --git a/ui/apps/platform/cypress/integration/baseImages/baseImages.test.ts b/ui/apps/platform/cypress/integration/baseImages/baseImages.test.ts index fd4cf8da93a38..ac126cc95443a 100644 --- a/ui/apps/platform/cypress/integration/baseImages/baseImages.test.ts +++ b/ui/apps/platform/cypress/integration/baseImages/baseImages.test.ts @@ -1,5 +1,4 @@ import withAuth from '../../helpers/basicAuth'; -import { hasFeatureFlag } from '../../helpers/features'; import { interactAndWaitForResponses } from '../../helpers/request'; import { getRegExpForTitleWithBranding } from '../../helpers/title'; @@ -8,12 +7,6 @@ import { addBaseImage, visitBaseImages, visitBaseImagesFromLeftNav } from './bas describe('Base Images', () => { withAuth(); - before(function () { - if (!hasFeatureFlag('ROX_BASE_IMAGE_DETECTION')) { - this.skip(); - } - }); - it('should navigate to Base Images page from left nav', () => { visitBaseImagesFromLeftNav(); diff --git a/ui/apps/platform/cypress/integration/compliance/Compliance.helpers.js b/ui/apps/platform/cypress/integration/compliance/Compliance.helpers.js deleted file mode 100644 index f2afd1c987a40..0000000000000 --- a/ui/apps/platform/cypress/integration/compliance/Compliance.helpers.js +++ /dev/null @@ -1,211 +0,0 @@ -import { getRouteMatcherMapForGraphQL, interactAndWaitForResponses } from '../../helpers/request'; -import { visit } from '../../helpers/visit'; - -// path - -export const basePath = '/main/compliance'; - -function getEntitiesPath(entitiesKey) { - return `${basePath}/${entitiesKey}`; -} - -const segmentForEntity = { - clusters: 'cluster', - controls: 'control', - deployments: 'deployment', - namespaces: 'namespace', - nodes: 'node', -}; - -function getEntityPagePath(entitiesKey) { - return `${basePath}/${segmentForEntity[entitiesKey]}`; -} - -// opname - -const opnamesWithoutStandards = [ - 'clustersCount', - 'namespacesCount', - 'nodesCount', - 'deploymentsCount', - 'runStatuses', - 'getAggregatedResultsAcrossEntity_CLUSTER', - 'getAggregatedResultsByEntity_CLUSTER', - 'getAggregatedResultsAcrossEntity_NAMESPACE', - 'getAggregatedResultsAcrossEntity_NODE', -]; - -export const routeMatcherMapWithoutStandards = - getRouteMatcherMapForGraphQL(opnamesWithoutStandards); - -// TODO are these reliable after hideScanResults feature? -/* -const opnamesOfStandards = [ - 'complianceStandards_CIS_Kubernetes_v1_5', - 'complianceStandards_HIPAA_164', - 'complianceStandards_NIST_800_190', - 'complianceStandards_NIST_SP_800_53_Rev_4', - 'complianceStandards_PCI_DSS_3_2', -]; -*/ - -const routeMatcherMapForComplianceDashboard = getRouteMatcherMapForGraphQL(opnamesWithoutStandards); - -const opnameForEntities = { - clusters: 'clustersList', // just clusters would be even better, and so on - controls: 'controls', - deployments: 'deploymentsList', - namespaces: 'namespaceList', // singular: too bad, so sad - nodes: 'nodesList', -}; - -const opnameForEntity = { - clusters: 'getClusterName', - deployments: 'getDeployment', - namespaces: 'getNamespace', - nodes: 'getNode', -}; - -// heading - -export const headingPlural = { - clusters: 'Clusters', - deployments: 'Deployments', - namespaces: 'Namespaces', - nodes: 'Nodes', -}; - -export const headingSingular = { - clusters: 'Cluster', - deployments: 'Deployment', - namespaces: 'Namespace', - nodes: 'Node', -}; - -// assert - -// assert instead of interact because query might be cached. -export function assertComplianceEntityPage(entitiesKey) { - cy.location('pathname').should('contain', getEntityPagePath(entitiesKey)); // contain because pathname has id - cy.get(`h1 + div:contains("${headingSingular[entitiesKey]}")`); -} - -// visit - -export function visitComplianceDashboard() { - visit(basePath, routeMatcherMapForComplianceDashboard); - - cy.get(`h1:contains("Compliance")`); -} - -/* - * Assume location is compliance dashboard. - */ -function scanCompliance() { - const routeMatcherMapForTriggerScan = getRouteMatcherMapForGraphQL(['triggerScan']); - const routeMatcherMap = { - ...routeMatcherMapForTriggerScan, - ...routeMatcherMapForComplianceDashboard, - }; - - const scanButton = '[data-testid="scan-button"]'; - - interactAndWaitForResponses( - () => { - cy.get(scanButton).click(); - }, - routeMatcherMap, - undefined, - { timeout: 20000 } - ); - - // Note: scan results are polled for every 10 seconds, this should give us plenty of time - // to await completion of the scan. - cy.get('div:contains("Compliance scanning complete")', { - timeout: 60000, - }); -} - -/* - * Call directly in first test (of a test file for another container) which assumes that scan results are available. - * Although compliance test file bends the guideline that tests should not depend on side effects within the same test file, - * configmanagement test files break the guideline if they assume that compliance test file has already run. - * Cypress 10 apparently no longer runs tests files in a determinate order. - */ -export function triggerScan() { - visitComplianceDashboard(); - scanCompliance(); -} - -/* - * For example, visitComplianceEntities('clusters') - */ -export function visitComplianceEntities(entitiesKey) { - const routeMatcherMap = getRouteMatcherMapForGraphQL([ - 'searchOptions', - opnameForEntities[entitiesKey], - ]); - - visit(getEntitiesPath(entitiesKey), routeMatcherMap); - - cy.get(`h1:contains("${headingPlural[entitiesKey]}")`); -} - -/* - * For example, visitComplianceStandard('CIS Docker v1.2.0') - */ -export function visitComplianceStandard(standardName) { - const routeMatcherMap = getRouteMatcherMapForGraphQL([ - 'searchOptions', - 'getComplianceStandards', - 'controls', - ]); - - visit(`${getEntitiesPath('controls')}?s[standard]=${standardName}`, routeMatcherMap); - - cy.get(`h1:contains("${standardName}")`); -} - -export function interactAndWaitForComplianceEntities(interactionCallback, entitiesKey) { - const opname = opnameForEntities[entitiesKey]; - const routeMatcherMap = getRouteMatcherMapForGraphQL([opname]); - interactAndWaitForResponses(interactionCallback, routeMatcherMap); - - cy.location('pathname').should('eq', getEntitiesPath(entitiesKey)); - cy.get(`h1:contains("${headingPlural[entitiesKey]}")`); -} - -export function interactAndWaitForComplianceEntityInSidePanel(interactionCallback, entitiesKey) { - const opname = opnameForEntity[entitiesKey]; - const routeMatcherMap = getRouteMatcherMapForGraphQL([opname]); - interactAndWaitForResponses(interactionCallback, routeMatcherMap); - - cy.location('pathname').should('contain', getEntitiesPath(entitiesKey)); // contain because pathname has id -} - -export function interactAndWaitForComplianceStandard(interactionCallback) { - const entitiesKey = 'controls'; - const opname = opnameForEntities[entitiesKey]; - const routeMatcherMap = getRouteMatcherMapForGraphQL([opname]); - interactAndWaitForResponses(interactionCallback, routeMatcherMap); - - cy.location('pathname').should('eq', getEntitiesPath(entitiesKey)); - cy.get('h1 + div:contains("Standard")'); -} - -// verify - -/* - * For example, verifyDashboardEntityLink('clusters', /^\d+ clusters?/)) - */ -export function verifyDashboardEntityLink(entitiesKey, entityRegExp) { - cy.get('[data-testid="page-header"]') - .contains('a', entityRegExp) - .then(($a) => { - const [, count] = /^(\d+) /.exec($a.text()); - interactAndWaitForComplianceEntities(() => { - cy.wrap($a).click(); - }, entitiesKey); - cy.get(`[data-testid="panel-header"]:contains("${count}")`); - }); -} diff --git a/ui/apps/platform/cypress/integration/compliance/Compliance.selectors.js b/ui/apps/platform/cypress/integration/compliance/Compliance.selectors.js deleted file mode 100644 index 9d761aa263966..0000000000000 --- a/ui/apps/platform/cypress/integration/compliance/Compliance.selectors.js +++ /dev/null @@ -1,13 +0,0 @@ -export const selectors = { - list: { - table: { - firstGroup: '.table-group-active:first', - firstTableGroup: '.rt-table:first', - firstRow: 'div.rt-tr-group > .rt-tr.-odd:first', - firstRowName: 'div.rt-tr-group > .rt-tr.-odd:first .rt-td a', - secondRowName: 'div.rt-tr-group > .rt-tr.-even:first .rt-td a', - firstStandard: 'div.rt-table .rt-thead .rt-th:nth-child(3)', - firstPercentage: 'div.rt-tr-group > .rt-tr.-odd > .rt-td:nth-child(3)', - }, - }, -}; diff --git a/ui/apps/platform/cypress/integration/compliance/complianceDashboard.test.js b/ui/apps/platform/cypress/integration/compliance/complianceDashboard.test.js deleted file mode 100644 index 51b372c1ae4b7..0000000000000 --- a/ui/apps/platform/cypress/integration/compliance/complianceDashboard.test.js +++ /dev/null @@ -1,96 +0,0 @@ -import withAuth from '../../helpers/basicAuth'; -import { hasFeatureFlag } from '../../helpers/features'; -import { getRegExpForTitleWithBranding } from '../../helpers/title'; - -import { - interactAndWaitForComplianceStandard, - triggerScan, - verifyDashboardEntityLink, - visitComplianceDashboard, -} from './Compliance.helpers'; -import { selectors } from './Compliance.selectors'; - -function getWidgetSelector(headerText) { - return `.widget:has([data-testid="widget-header"]:contains("${headerText}"))`; -} - -function getStandardAcrossEntitiesLink(entityNameOrdinaryCasePlural) { - return `${getWidgetSelector(`Passing standards across ${entityNameOrdinaryCasePlural}`)} a`; -} - -describe('Compliance Dashboard', () => { - withAuth(); - - before(function () { - if (!hasFeatureFlag('ROX_DEPRECATED_COMPLIANCE_DASHBOARD')) { - this.skip(); - } - }); - - it('should scan for compliance data', () => { - triggerScan(); // prerequisite for the following tests - }); - - it('should have title', () => { - visitComplianceDashboard(); - - cy.title().should('match', getRegExpForTitleWithBranding('Compliance')); - }); - - it('should show the same amount of clusters as list', () => { - visitComplianceDashboard(); - - verifyDashboardEntityLink('clusters', /^\d+ clusters?/); // include ^ but omit $ - }); - - it('should show the same amount of namespaces as list', () => { - visitComplianceDashboard(); - - verifyDashboardEntityLink('namespaces', /^\d+ namespaces?/); // include ^ but omit $ - }); - - it('should show the same amount of nodes as list', () => { - visitComplianceDashboard(); - - verifyDashboardEntityLink('nodes', /^\d+ nodes?/); // include ^ but omit $ - }); - - it('should show the same amount of deployments as list', () => { - visitComplianceDashboard(); - - verifyDashboardEntityLink('deployments', /^\d+ deployments?/); // include ^ but omit $ - }); - - it('should link from Passing Standards Across Clusters widget to standards grouped by clusters list', () => { - visitComplianceDashboard(); - - interactAndWaitForComplianceStandard(() => { - cy.get(getStandardAcrossEntitiesLink('clusters')).first().click(); - }); - cy.location('search').should('contain', '?s[groupBy]=CLUSTER'); // followed by a standard - cy.get('[data-testid="panel-header"]').contains('cluster'); - cy.get(selectors.list.table.firstGroup).should('be.visible'); - }); - - it('should link from Passing Standards Across Namespaces widget to standards grouped by namespaces list', () => { - visitComplianceDashboard(); - - interactAndWaitForComplianceStandard(() => { - cy.get(getStandardAcrossEntitiesLink('namespaces')).first().click(); - }); - cy.location('search').should('contain', '?s[groupBy]=NAMESPACE'); // followed by a standard - cy.get('[data-testid="panel-header"]').contains('namespace'); - cy.get(selectors.list.table.firstGroup).should('be.visible'); - }); - - it('should link from Passing Standards Across Nodes widget to standards grouped by nodes list', () => { - visitComplianceDashboard(); - - interactAndWaitForComplianceStandard(() => { - cy.get(getStandardAcrossEntitiesLink('nodes')).first().click(); - }); - cy.location('search').should('contain', '?s[groupBy]=NODE'); // followed by a standard - cy.get('[data-testid="panel-header"]').contains('node'); - cy.get(selectors.list.table.firstGroup).should('be.visible'); - }); -}); diff --git a/ui/apps/platform/cypress/integration/compliance/complianceList.test.js b/ui/apps/platform/cypress/integration/compliance/complianceList.test.js deleted file mode 100644 index 32a6ca5097d6c..0000000000000 --- a/ui/apps/platform/cypress/integration/compliance/complianceList.test.js +++ /dev/null @@ -1,134 +0,0 @@ -import withAuth from '../../helpers/basicAuth'; -import { hasFeatureFlag } from '../../helpers/features'; -import searchSelectors from '../../selectors/search'; - -import { - assertComplianceEntityPage, - interactAndWaitForComplianceEntities, - interactAndWaitForComplianceEntityInSidePanel, - triggerScan, - visitComplianceEntities, - visitComplianceStandard, -} from './Compliance.helpers'; -import { selectors } from './Compliance.selectors'; - -describe('Compliance entities list', () => { - withAuth(); - - before(function () { - if (!hasFeatureFlag('ROX_DEPRECATED_COMPLIANCE_DASHBOARD')) { - this.skip(); - } - }); - - // TODO: ROX-30939: fix test for OCP4.20 "1 namespace" (openshift-cloud-credential-operator) - it.skip('should filter namespaces table with passing controls', () => { - triggerScan(); // in case complianceDashboard.test.js is skipped - visitComplianceEntities('namespaces'); - - interactAndWaitForComplianceEntities(() => { - cy.get(searchSelectors.input).type('Compliance State:'); - cy.get(searchSelectors.input).type('{enter}'); - cy.get(searchSelectors.input).type('Pass'); - cy.get(searchSelectors.input).type('{enter}'); - }, 'namespaces'); - cy.get('.rt-tbody .rt-tr').should('not.exist'); - cy.get('[data-testid="panel-header"]').should('contain', '0 namespaces'); - }); - - it('should filter namespaces table with failing controls', () => { - visitComplianceEntities('namespaces'); - - interactAndWaitForComplianceEntities(() => { - cy.get(searchSelectors.input).type('Compliance State:'); - cy.get(searchSelectors.input).type('{enter}'); - cy.get(searchSelectors.input).type('Fail'); - cy.get(searchSelectors.input).type('{enter}'); - }, 'namespaces'); - cy.get('.rt-tbody .rt-tr'); - cy.get('[data-testid="panel-header"]').should('contain', 'namespace'); - }); - - it('should open/close side panel when clicking on a table row', () => { - visitComplianceEntities('clusters'); - - cy.get(selectors.list.table.firstRowName) - .invoke('text') - .then((name) => { - cy.get('[data-testid="panel-header"]').should('contain', 'cluster'); - cy.get(selectors.list.table.firstRow).click(); - cy.get('[data-testid="side-panel"]').should('exist'); - cy.get('[data-testid="side-panel-header"]').contains(name); - cy.get('[data-testid="side-panel"] [aria-label="Close"]').click(); - cy.get('[data-testid="side-panel"]').should('not.exist'); - cy.get('[data-testid="panel-header"]').should('contain', 'cluster'); - }); - }); - - it('should have the same percentage from list to entity widget', () => { - visitComplianceEntities('clusters'); - - cy.get(selectors.list.table.firstRow).click(); - cy.get(selectors.list.table.firstStandard) - .invoke('text') - .then((firstStandard) => { - cy.get(selectors.list.table.firstPercentage) - .invoke('text') - .then((firstTablePercentage) => { - cy.get(`[data-testid="${firstStandard}-compliance"] div.rv-sunburst text`) - .invoke('text') - .then((firstWidgetPercentage) => - expect(firstTablePercentage).to.equal(firstWidgetPercentage) - ); - }); - }); - }); - - it('should link to entity page when clicking on side panel header', () => { - visitComplianceEntities('clusters'); - - cy.get(selectors.list.table.firstRowName) - .invoke('text') - .then((name) => { - interactAndWaitForComplianceEntityInSidePanel(() => { - cy.get(selectors.list.table.firstRow).click(); - }, 'clusters'); - cy.get('[data-testid="side-panel-header"]').contains(name); - cy.get('[data-testid="side-panel-header"]').click(); - assertComplianceEntityPage('clusters'); - }); - }); - - it('should be sorted by version in standards list', () => { - visitComplianceStandard('CIS Kubernetes v1.5'); - - cy.get(selectors.list.table.firstRowName) - .invoke('text') - .then((text1) => { - cy.get(selectors.list.table.secondRowName) - .invoke('text') - .then((text2) => { - const arr1 = text1.split(' ')[0]; - const controlArr1 = arr1.split('.'); - const arr2 = text2.split(' ')[0]; - const controlArr2 = arr2.split('.'); - expect(parseInt(controlArr1[0], 10)).to.be.at.most( - parseInt(controlArr2[0], 10) - ); - if (controlArr1[1] && controlArr2[1]) { - expect(parseInt(controlArr1[1], 10)).to.be.at.most( - parseInt(controlArr2[1], 10) - ); - } - }); - }); - }); - - it('should collapse/open table grouping', () => { - visitComplianceStandard('PCI DSS 3.2.1'); - - cy.get(selectors.list.table.firstTableGroup).should('be.visible'); - cy.get(selectors.list.table.firstGroup).click(); - cy.get(selectors.list.table.firstTableGroup).should('not.be.visible'); - }); -}); diff --git a/ui/apps/platform/cypress/integration/compliance/hideScanResults.helpers.js b/ui/apps/platform/cypress/integration/compliance/hideScanResults.helpers.js deleted file mode 100644 index ff12927049367..0000000000000 --- a/ui/apps/platform/cypress/integration/compliance/hideScanResults.helpers.js +++ /dev/null @@ -1,52 +0,0 @@ -import { interactAndWaitForResponses } from '../../helpers/request'; - -import { routeMatcherMapWithoutStandards } from './Compliance.helpers'; - -// selectors - -export const selectorForModal = `[role="dialog"]:has('h1:contains("Manage standards")')`; - -export function selectorInModal(selector) { - return `${selectorForModal} ${selector}`; -} -export function selectorForWidget(title) { - return `.widget:has('[data-testid="widget-header"]:contains("${title}")')`; -} - -export function selectorInWidget(title, selector) { - return `${selectorForWidget(title)} ${selector}`; -} - -// interactions - -export function openModal() { - const routeMatcherMap = { - 'compliance/standards': { - method: 'GET', - url: '/v1/compliance/standards', - }, - }; - - interactAndWaitForResponses(() => { - cy.get('button:contains("Manage standards")').click(); - }, routeMatcherMap); - - cy.get(selectorForModal); -} - -export function clickSaveAndWaitForPatchComplianceStandards(standardIds) { - const routeMatcherMapForPatch = Object.fromEntries( - standardIds.map((standardId) => [ - `PATCH_${standardId}`, - { method: 'PATCH', url: `/v1/compliance/standards/${standardId}` }, - ]) - ); - const routeMatcherMap = { - ...routeMatcherMapForPatch, - ...routeMatcherMapWithoutStandards, - }; - - return interactAndWaitForResponses(() => { - cy.get(selectorInModal('button:contains("Save")')).click(); - }, routeMatcherMap); // TODO GraphQL requests? -} diff --git a/ui/apps/platform/cypress/integration/compliance/hideScanResults.test.js b/ui/apps/platform/cypress/integration/compliance/hideScanResults.test.js deleted file mode 100644 index ddb88bd6ded79..0000000000000 --- a/ui/apps/platform/cypress/integration/compliance/hideScanResults.test.js +++ /dev/null @@ -1,128 +0,0 @@ -import withAuth from '../../helpers/basicAuth'; -import { hasFeatureFlag } from '../../helpers/features'; -import { getInputByLabel } from '../../helpers/formHelpers'; - -import { triggerScan, visitComplianceDashboard } from './Compliance.helpers'; -import { - clickSaveAndWaitForPatchComplianceStandards, - openModal, - selectorForModal, - selectorInModal, - selectorInWidget, -} from './hideScanResults.helpers'; - -const titleAcrossClusters = 'Passing standards across clusters'; -const titleAcrossNamespaces = 'Passing standards across namespaces'; - -const forHIPAA = { - standardId: 'HIPAA_164', - barLink: 'a:contains("HIPAA")', - checkboxLabel: 'HIPAA 164', -}; - -const forNIST190 = { - standardId: 'NIST_800_190', - barLink: 'a:contains("NIST SP 800-190")', - checkboxLabel: 'NIST SP 800-190', -}; - -const forNIST53 = { - standardId: 'NIST_SP_800_53_Rev_4', - barLink: 'a:contains("NIST SP 800-53")', - checkboxLabel: 'NIST SP 800-53', -}; - -function assertExistenceOfStandard(forStandard, existence) { - const { barLink } = forStandard; - const existOrNot = existence ? 'exist' : 'not.exist'; - - cy.get(selectorInWidget(titleAcrossClusters, barLink)).should(existOrNot); - cy.get(selectorInWidget(titleAcrossNamespaces, barLink)).should(existOrNot); - - // TODO columns in entity tables -} - -function assertCheckedAndClickStandard(forStandard, checked) { - const { checkboxLabel } = forStandard; - const haveAttrOrNot = checked ? 'have.attr' : 'not.have.attr'; - - getInputByLabel(checkboxLabel).should(haveAttrOrNot, 'checked'); - getInputByLabel(checkboxLabel).click(); -} - -describe('Compliance hideScanResults', () => { - withAuth(); - - before(function () { - if (!hasFeatureFlag('ROX_DEPRECATED_COMPLIANCE_DASHBOARD')) { - this.skip(); - } - }); - - it('should open modal and then cancel', () => { - triggerScan(); // in case complianceDashboard.test.js is skipped - openModal(); - - cy.get(selectorInModal('button:contains("Save")')).should('be.disabled'); - cy.get(selectorInModal('button:contains("Cancel")')).click(); - cy.get(selectorForModal).should('not.exist'); - }); - - it('should hide HIPAA standard', () => { - visitComplianceDashboard(); - - assertExistenceOfStandard(forHIPAA, true); - - openModal(); - - assertCheckedAndClickStandard(forHIPAA, true); - clickSaveAndWaitForPatchComplianceStandards([forHIPAA.standardId]); - - assertExistenceOfStandard(forHIPAA, false); - }); - - // The following test depends on the preceding test. - - it('should show HIPAA standard and hide NIST standards', () => { - visitComplianceDashboard(); - - assertExistenceOfStandard(forHIPAA, false); - assertExistenceOfStandard(forNIST190, true); - assertExistenceOfStandard(forNIST53, true); - - openModal(); - assertCheckedAndClickStandard(forHIPAA, false); - assertCheckedAndClickStandard(forNIST190, true); - assertCheckedAndClickStandard(forNIST53, true); - - clickSaveAndWaitForPatchComplianceStandards([ - forHIPAA.standardId, - forNIST190.standardId, - forNIST53.standardId, - ]); - - assertExistenceOfStandard(forHIPAA, true); - assertExistenceOfStandard(forNIST190, false); - assertExistenceOfStandard(forNIST53, false); - }); - - // The following test depends on the preceding test. - - it('should show NIST standards', () => { - visitComplianceDashboard(); - - assertExistenceOfStandard(forNIST190, false); - assertExistenceOfStandard(forNIST53, false); - - openModal(); - assertCheckedAndClickStandard(forNIST190, false); - assertCheckedAndClickStandard(forNIST53, false); - - clickSaveAndWaitForPatchComplianceStandards([forNIST190.standardId, forNIST53.standardId]); - - assertExistenceOfStandard(forNIST190, true); - assertExistenceOfStandard(forNIST53, true); - }); - - // hideScanResults is same at the end as it was at the beginning -}); diff --git a/ui/apps/platform/cypress/integration/configmanagement/ConfigurationManagement.helpers.js b/ui/apps/platform/cypress/integration/configmanagement/ConfigurationManagement.helpers.js index 3e45540f1e401..a9b78b2fcc5e6 100644 --- a/ui/apps/platform/cypress/integration/configmanagement/ConfigurationManagement.helpers.js +++ b/ui/apps/platform/cypress/integration/configmanagement/ConfigurationManagement.helpers.js @@ -15,7 +15,6 @@ function getEntitiesPath(entitiesKey) { const segmentForEntity = { clusters: 'cluster', - controls: 'control', deployments: 'deployment', images: 'image', namespaces: 'namespace', @@ -34,7 +33,6 @@ function getEntityPagePath(entitiesKey, id = '') { // Heading on entities page has sentence case for entity type. const headingForEntities = { clusters: 'Clusters', - controls: 'Controls', deployments: 'Deployments', images: 'Images', namespaces: 'Namespaces', @@ -49,7 +47,6 @@ const headingForEntities = { // Heading on entity page or side panel has sentence case for entity type. const headingForEntity = { clusters: 'Cluster', - controls: 'Control', deployments: 'Deployment', images: 'Image', namespaces: 'Namespace', @@ -62,10 +59,8 @@ const headingForEntity = { }; function tableHeaderRegExp(entitiesKey) { - const singular = - entitiesKey === 'controls' ? 'CIS Control' : headingForEntity[entitiesKey].toLowerCase(); - const plural = - entitiesKey === 'controls' ? 'CIS Controls' : headingForEntities[entitiesKey].toLowerCase(); + const singular = headingForEntity[entitiesKey].toLowerCase(); + const plural = headingForEntities[entitiesKey].toLowerCase(); // Complexity to exclude 1 for plural. // Double backslash \\d needed for RegExp constructor unlike RegExp literal. @@ -74,7 +69,6 @@ function tableHeaderRegExp(entitiesKey) { const countNounRegExp = { // clusters has singular link by name - controls: /\d+ Controls?$/, deployments: /^\d+ deployments?$/, images: /\d+ images?$/, // namespaces @@ -89,7 +83,6 @@ const countNounRegExp = { // Title of widget is title case but has uppercase style. const widgetTitleForEntities = { clusters: 'Clusters', - controls: 'CIS Controls', deployments: 'Deployments', images: 'Images', namespaces: 'Namespaces', @@ -117,7 +110,6 @@ function getRouteMatcherMapForEntities(entitiesKey) { const opnameForEntity = { clusters: 'getCluster', - controls: 'getControl', deployments: 'getDeployment', images: 'getImage', namespaces: 'getNamespace', @@ -136,7 +128,6 @@ function getRouteMatcherMapForEntity(entitiesKey) { const typeOfEntity = { clusters: 'CLUSTER', - controls: 'CONTROL', deployments: 'DEPLOYMENT', images: 'IMAGE', namespaces: 'NAMESPACE', @@ -152,12 +143,8 @@ function opnameForPrimaryAndSecondaryEntities(entitiesKey1, entitiesKey2) { return `${opnameForEntity[entitiesKey1]}_${typeOfEntity[entitiesKey2]}`; } -const routeMatcherMapForConfigurationManagementDashboard = getRouteMatcherMapForGraphQL([ - 'complianceByControls', -]); - export function visitConfigurationManagementDashboard() { - visit(basePath, routeMatcherMapForConfigurationManagementDashboard); + visit(basePath); cy.get('h1:contains("Configuration Management")'); } @@ -245,22 +232,6 @@ export function interactAndWaitForConfigurationManagementSecondaryEntities( interactAndWaitForResponses(interactionCallback, routeMatcherMap); } -export function interactAndWaitForConfigurationManagementScan(interactionCallback) { - interactAndWaitForResponses( - interactionCallback, - routeMatcherMapForConfigurationManagementDashboard - ); - - // ROX-24912 - // Comment out for now and assume that scan results are available from compliance tests. - // Maybe interactAndWaitForResponses waits only for the first pair of responses from page visit. - // Apparently the negative assertion sometimes passes before ComplianceScanProgress renders. - // But auto-disappears prevents positive assertion as in scanCompliance helper function. - cy.get('div:contains("Compliance scanning in progress")', { - timeout: 60000, - }).should('not.exist'); -} - export function navigateToSingleEntityPage(entitiesKey) { // interactAndWaitForConfigurationManagementEntityPage(() => { // cy.get('[data-testid="side-panel"] [aria-label="link"]').click(); @@ -370,18 +341,11 @@ function verifyWidgetLinkToTable(entitiesKey1, entitiesKey2, contextSelector) { cy.get(`${selectors.countWidgets}:contains('${listEntity}') button`).click(); } - if ( - (entitiesKey1 === 'controls' && entitiesKey2 === 'nodes') || - (entitiesKey1 === 'nodes' && entitiesKey2 === 'controls') - ) { - clickCountWidget(); // no request - } else { - interactAndWaitForConfigurationManagementSecondaryEntities( - clickCountWidget, - entitiesKey1, - entitiesKey2 - ); - } + interactAndWaitForConfigurationManagementSecondaryEntities( + clickCountWidget, + entitiesKey1, + entitiesKey2 + ); cy.get(`${contextSelector} .rt-tr-group`); cy.get(`${contextSelector} [data-testid="panel-header"]`).contains( diff --git a/ui/apps/platform/cypress/integration/configmanagement/ConfigurationManagement.selectors.js b/ui/apps/platform/cypress/integration/configmanagement/ConfigurationManagement.selectors.js index 58dd303d26071..2600eb55be4dc 100644 --- a/ui/apps/platform/cypress/integration/configmanagement/ConfigurationManagement.selectors.js +++ b/ui/apps/platform/cypress/integration/configmanagement/ConfigurationManagement.selectors.js @@ -9,16 +9,6 @@ export const dashboardSelectors = { getWidget: (title) => { return `[data-testid="widget"]:contains('${title}')`; }, - cisStandardsAcrossClusters: { - widget: '[data-testid="compliance-by-controls"]', - select: { - input: '[data-testid="compliance-by-controls"] .react-select__control', - value: '[data-testid="compliance-by-controls"] .react-select__single-value', - options: '[data-testid="compliance-by-controls"] .react-select__option', - }, - passingControlsLink: 'a:contains("Controls Passing")', - failingControlsLinks: 'a:contains("Controls Failing")', - }, horizontalBars: '.rv-xy-plot__series.rv-xy-plot__series--bar > rect', }; diff --git a/ui/apps/platform/cypress/integration/configmanagement/ciscontrols.test.js b/ui/apps/platform/cypress/integration/configmanagement/ciscontrols.test.js deleted file mode 100644 index 51a1e8374087b..0000000000000 --- a/ui/apps/platform/cypress/integration/configmanagement/ciscontrols.test.js +++ /dev/null @@ -1,103 +0,0 @@ -import withAuth from '../../helpers/basicAuth'; -import { hasFeatureFlag, hasOrchestratorFlavor } from '../../helpers/features'; -import { triggerScan } from '../compliance/Compliance.helpers'; - -import { - clickOnCountWidget, - hasCountWidgetsFor, - hasTabsFor, - interactAndWaitForConfigurationManagementScan, - navigateToSingleEntityPage, - verifyWidgetLinkToTableFromSidePanel, - verifyWidgetLinkToTableFromSinglePage, - visitConfigurationManagementDashboard, - visitConfigurationManagementEntitiesWithSearch, - visitConfigurationManagementEntityInSidePanel, -} from './ConfigurationManagement.helpers'; - -const entitiesKey = 'controls'; - -describe('Configuration Management Controls', () => { - withAuth(); - - // Skip although Controls and CIS Kubernetes v1.5 are visible, because these tests assume compliance tests ran and triggered a scan (pardon rhyme). - before(function () { - if (!hasFeatureFlag('ROX_DEPRECATED_COMPLIANCE_DASHBOARD')) { - this.skip(); - } - }); - - before(function beforeHook() { - if (hasOrchestratorFlavor('openshift')) { - this.skip(); - } - }); - - it('should render the controls list and open the side panel when a row is clicked', () => { - // ROX-13537: See if compliance scan prevents failure of last tests because no Pass or no Fail status. - triggerScan(); - - visitConfigurationManagementDashboard(); - - // This and the following tests assumes that scan results are available - interactAndWaitForConfigurationManagementScan(() => { - cy.get('[data-testid="scan-button"]').click(); - }); - - visitConfigurationManagementEntityInSidePanel(entitiesKey); - }); - - it('should take you to a control single when the "navigate away" button is clicked', () => { - visitConfigurationManagementEntityInSidePanel(entitiesKey); - navigateToSingleEntityPage(entitiesKey); - }); - - it('should have the correct count widgets for a single entity view', () => { - visitConfigurationManagementEntityInSidePanel(entitiesKey); - navigateToSingleEntityPage(entitiesKey); - hasCountWidgetsFor(['Nodes']); - }); - - // ROX-13028: skip pending investigation why sometimes 0 nodes for control, therefore widget is disabled. - it.skip('should click on the nodes count widget in the entity page and show the nodes tab', () => { - visitConfigurationManagementEntityInSidePanel(entitiesKey); - navigateToSingleEntityPage(entitiesKey); - clickOnCountWidget('nodes', 'entityList'); - }); - - it('should have the correct tabs for a single entity view', () => { - visitConfigurationManagementEntityInSidePanel(entitiesKey); - navigateToSingleEntityPage(entitiesKey); - hasTabsFor(['nodes']); - }); - - describe('should go to nodes table from widget link', () => { - const entitiesKey2 = 'nodes'; - - it('in single page', () => { - verifyWidgetLinkToTableFromSinglePage(entitiesKey, entitiesKey2); - }); - - it('in side panel', () => { - verifyWidgetLinkToTableFromSidePanel(entitiesKey, entitiesKey2); - }); - }); - - it('should show no failing nodes in the control findings section of a passing control', () => { - visitConfigurationManagementEntitiesWithSearch(entitiesKey, '?s[Compliance%20State]=Pass'); - - // Click first row which has pass in Control Status column to open control in side panel. - cy.get(`.rt-td:nth-child(4):contains("Pass"):nth(0)`).click(); - // Control Findings - cy.get('[data-testid="widget"] .rt-tbody .rt-tr').should('have.length', 0); - }); - - it('should show failing nodes in the control findings section of a failing control', () => { - visitConfigurationManagementEntitiesWithSearch(entitiesKey, '?s[Compliance%20State]=Fail'); - - // Click first row which has fail in Control Status column to open control in side panel. - cy.get(`.rt-td:nth-child(4):contains("Fail"):nth(0)`).click(); - // Control Findings - cy.get('[data-testid="widget"] .rt-tbody .rt-tr').should('not.have.length', 0); - }); -}); diff --git a/ui/apps/platform/cypress/integration/configmanagement/clusters.test.js b/ui/apps/platform/cypress/integration/configmanagement/clusters.test.js index d0cd978d94576..e115a0ac38910 100644 --- a/ui/apps/platform/cypress/integration/configmanagement/clusters.test.js +++ b/ui/apps/platform/cypress/integration/configmanagement/clusters.test.js @@ -3,12 +3,10 @@ import withAuth from '../../helpers/basicAuth'; import { hasCountWidgetsFor, hasTabsFor, - interactAndWaitForConfigurationManagementScan, navigateToSingleEntityPage, verifyTableLinkToSidePanelTable, verifyWidgetLinkToTableFromSidePanel, verifyWidgetLinkToTableFromSinglePage, - visitConfigurationManagementDashboard, visitConfigurationManagementEntities, visitConfigurationManagementEntityInSidePanel, } from './ConfigurationManagement.helpers'; @@ -40,7 +38,6 @@ describe('Configuration Management Clusters', () => { 'Users & Groups', 'Service Accounts', 'Roles', - 'Controls', ]); }); @@ -56,7 +53,6 @@ describe('Configuration Management Clusters', () => { 'subjects', 'serviceaccounts', 'roles', - 'controls', ]); }); @@ -154,30 +150,6 @@ describe('Configuration Management Clusters', () => { }); }); - describe('should go to controls table from widget link', () => { - const entitiesKey2 = 'controls'; - - it('in single page', () => { - verifyWidgetLinkToTableFromSinglePage(entitiesKey, entitiesKey2); - }); - - it('in side panel', () => { - verifyWidgetLinkToTableFromSidePanel(entitiesKey, entitiesKey2); - }); - }); - - // ROX-13011: Prevent failures, pending investigation into reason why No Controls instead of link sometimes. - it.skip('should go from table link to controls table in side panel', () => { - visitConfigurationManagementDashboard(); - - // This test assumes that scan results are available - interactAndWaitForConfigurationManagementScan(() => { - cy.get('[data-testid="scan-button"]').click(); - }); - - verifyTableLinkToSidePanelTable(entitiesKey, 'controls'); - }); - it('should go from table link to subjects table in side panel', () => { verifyTableLinkToSidePanelTable(entitiesKey, 'subjects'); }); diff --git a/ui/apps/platform/cypress/integration/configmanagement/dashboard.test.js b/ui/apps/platform/cypress/integration/configmanagement/dashboard.test.js index 9c7d7f84d46f6..aba8af05eee90 100644 --- a/ui/apps/platform/cypress/integration/configmanagement/dashboard.test.js +++ b/ui/apps/platform/cypress/integration/configmanagement/dashboard.test.js @@ -1,11 +1,9 @@ import withAuth from '../../helpers/basicAuth'; -import { hasFeatureFlag, hasOrchestratorFlavor } from '../../helpers/features'; import { getRegExpForTitleWithBranding } from '../../helpers/title'; import { interactAndWaitForConfigurationManagementEntities, interactAndWaitForConfigurationManagementEntityInSidePanel, - // interactAndWaitForConfigurationManagementScan, visitConfigurationManagementDashboard, } from './ConfigurationManagement.helpers'; import { selectors } from './ConfigurationManagement.selectors'; @@ -56,33 +54,6 @@ describe('Configuration Management Dashboard', () => { }); }); - it('should show same number of controls between the tile and the controls list', function () { - // Skip although Controls and CIS Kubernetes v1.5 are visible, because these tests assume compliance tests ran and triggered a scan (pardon rhyme). - if (!hasFeatureFlag('ROX_DEPRECATED_COMPLIANCE_DASHBOARD')) { - this.skip(); - } - - const entitiesKey = 'controls'; - - visitConfigurationManagementDashboard(); - - cy.get(`${selectors.tileLinks}:eq(1) ${selectors.tileLinkValue}`) - .invoke('text') - .then((value) => { - const numControls = value; - - interactAndWaitForConfigurationManagementEntities(() => { - cy.get(`${selectors.tileLinks}:eq(1)`).click(); - }, entitiesKey); - - cy.get(`[data-testid="panel"] [data-testid="panel-header"]`) - .invoke('text') - .then((panelHeaderText) => { - expect(parseInt(panelHeaderText, 10)).to.equal(parseInt(numControls, 10)); - }); - }); - }); - it('should properly navigate to the policies list', () => { const entitiesKey = 'policies'; @@ -93,21 +64,6 @@ describe('Configuration Management Dashboard', () => { }, entitiesKey); }); - it('should properly navigate to the cis controls list', function () { - // Skip although Controls and CIS Kubernetes v1.5 are visible, because these tests assume compliance tests ran and triggered a scan (pardon rhyme). - if (!hasFeatureFlag('ROX_DEPRECATED_COMPLIANCE_DASHBOARD')) { - this.skip(); - } - - const entitiesKey = 'controls'; - - visitConfigurationManagementDashboard(); - - interactAndWaitForConfigurationManagementEntities(() => { - cy.get(`${selectors.tileLinks}:eq(1)`).click(); - }, entitiesKey); - }); - it('should properly navigate to the clusters list', () => { const entitiesKey = 'clusters'; @@ -219,23 +175,6 @@ describe('Configuration Management Dashboard', () => { }, entitiesKey); }); - it('go to controls list from View link in CIS widget', function () { - // Skip although Controls and CIS Kubernetes v1.5 are visible, because these tests assume compliance tests ran and triggered a scan (pardon rhyme). - if (!hasFeatureFlag('ROX_DEPRECATED_COMPLIANCE_DASHBOARD')) { - this.skip(); - } - - const entitiesKey = 'controls'; - - visitConfigurationManagementDashboard(); - - interactAndWaitForConfigurationManagementEntities(() => { - cy.get(selectors.cisStandardsAcrossClusters.widget) - .find('a:contains("View standard")') - .click(); - }, entitiesKey); - }); - it('should go to subjects (users and groups) list from View link in Users widget', () => { const entitiesKey = 'subjects'; @@ -289,62 +228,6 @@ describe('Configuration Management Dashboard', () => { cy.location('search').should('contain', '[Policy%20Status]='); // either Fail (for rated as Whatever) or Pass (for policies without violations) }); - it('clicking the "CIS Standard Across Clusters" widget\'s "passing controls" link should take you to the controls list and filter by passing controls', function () { - // Skip although Controls and CIS Kubernetes v1.5 are visible, because these tests assume compliance tests ran and triggered a scan (pardon rhyme). - if (!hasFeatureFlag('ROX_DEPRECATED_COMPLIANCE_DASHBOARD')) { - this.skip(); - } - - if (hasOrchestratorFlavor('openshift')) { - this.skip(); - } - - const entitiesKey = 'controls'; - - visitConfigurationManagementDashboard(); - - // This and the following test assumes that scan results are available - // ROX-24912 - // Comment out for now and assume that scan results are available from compliance tests. - // See function for more details. - /* - interactAndWaitForConfigurationManagementScan(() => { - cy.get('[data-testid="scan-button"]').click(); - }); - */ - - interactAndWaitForConfigurationManagementEntities(() => { - cy.get(selectors.cisStandardsAcrossClusters.widget) - .find(selectors.cisStandardsAcrossClusters.passingControlsLink) - .click(); - }, entitiesKey); - - cy.location('search').should('contain', '[Compliance%20State]=Pass'); - }); - - it('clicking the "CIS Standard Across Clusters" widget\'s "failing controls" link should take you to the controls list and filter by failing controls', function () { - // Skip although Controls and CIS Kubernetes v1.5 are visible, because these tests assume compliance tests ran and triggered a scan (pardon rhyme). - if (!hasFeatureFlag('ROX_DEPRECATED_COMPLIANCE_DASHBOARD')) { - this.skip(); - } - - if (hasOrchestratorFlavor('openshift')) { - this.skip(); - } - - const entitiesKey = 'controls'; - - visitConfigurationManagementDashboard(); - - interactAndWaitForConfigurationManagementEntities(() => { - cy.get(selectors.cisStandardsAcrossClusters.widget) - .find(selectors.cisStandardsAcrossClusters.failingControlsLinks) - .click(); - }, entitiesKey); - - cy.location('search').should('contain', '[Compliance%20State]=Fail'); - }); - it('should open side panel from link in Secrets widget', () => { const entitiesKey = 'secrets'; diff --git a/ui/apps/platform/cypress/integration/configmanagement/nodes.test.js b/ui/apps/platform/cypress/integration/configmanagement/nodes.test.js index 0a67650f72de9..87551bbab72f2 100644 --- a/ui/apps/platform/cypress/integration/configmanagement/nodes.test.js +++ b/ui/apps/platform/cypress/integration/configmanagement/nodes.test.js @@ -1,18 +1,10 @@ import withAuth from '../../helpers/basicAuth'; -import { hasFeatureFlag, hasOrchestratorFlavor } from '../../helpers/features'; -import { triggerScan } from '../compliance/Compliance.helpers'; import { - clickEntityTableRowThatHasLinkInColumn, - clickOnCountWidget, clickOnSingleEntityInTable, clickOnSingularEntityWidgetInSidePanel, - hasCountWidgetsFor, hasRelatedEntityFor, - hasTabsFor, navigateToSingleEntityPage, - verifyWidgetLinkToTableFromSidePanel, - verifyWidgetLinkToTableFromSinglePage, visitConfigurationManagementEntityInSidePanel, } from './ConfigurationManagement.helpers'; @@ -44,53 +36,4 @@ describe('Configuration Management Nodes', () => { navigateToSingleEntityPage(entitiesKey); hasRelatedEntityFor('Cluster'); }); - - it('should have the correct count widgets for a single entity view', () => { - visitConfigurationManagementEntityInSidePanel(entitiesKey); - navigateToSingleEntityPage(entitiesKey); - hasCountWidgetsFor(['Controls']); - }); - - it('should have the correct tabs for a single entity view', () => { - visitConfigurationManagementEntityInSidePanel(entitiesKey); - navigateToSingleEntityPage(entitiesKey); - hasTabsFor(['controls']); - }); - - it('should click on the controls count widget in the entity page and show the controls tab', function () { - // Skip although Controls and CIS Kubernetes v1.5 are visible, because these tests assume compliance tests ran and triggered a scan (pardon rhyme). - if (!hasFeatureFlag('ROX_DEPRECATED_COMPLIANCE_DASHBOARD')) { - this.skip(); - } - - if (hasOrchestratorFlavor('openshift')) { - this.skip(); - } - - triggerScan(); // because test assumes that scan results are available - - const columnIndexForControls = 7; - clickEntityTableRowThatHasLinkInColumn(entitiesKey, columnIndexForControls); - navigateToSingleEntityPage(entitiesKey); - clickOnCountWidget('controls', 'entityList'); - }); - - describe('should go to controls table from widget link', () => { - // Skip although Controls and CIS Kubernetes v1.5 are visible, because these tests assume compliance tests ran and triggered a scan (pardon rhyme). - before(function () { - if (!hasFeatureFlag('ROX_DEPRECATED_COMPLIANCE_DASHBOARD')) { - this.skip(); - } - }); - - const entitiesKey2 = 'controls'; - - it('in single page', () => { - verifyWidgetLinkToTableFromSinglePage(entitiesKey, entitiesKey2); - }); - - it('in side panel', () => { - verifyWidgetLinkToTableFromSidePanel(entitiesKey, entitiesKey2); - }); - }); }); diff --git a/ui/apps/platform/cypress/integration/cypressExpose.test.js b/ui/apps/platform/cypress/integration/cypressExpose.test.js new file mode 100644 index 0000000000000..b8bd7a530c1da --- /dev/null +++ b/ui/apps/platform/cypress/integration/cypressExpose.test.js @@ -0,0 +1,62 @@ +import { hasFeatureFlag, hasOrchestratorFlavor } from '../helpers/features'; + +// Assertions report key names only, so a failure never prints a secret value into the CI log. +const SECRET_KEYS = [ + 'ROX_AUTH_TOKEN', + 'OPENSHIFT_CONSOLE_USERNAME', + 'OPENSHIFT_CONSOLE_PASSWORD', + 'DEMO_PASSWORD', +]; + +describe('Cypress.expose public config', () => { + it('does not expose secrets to the browser', () => { + const exposed = Cypress.expose(); + const leakedKeys = SECRET_KEYS.filter((key) => key in exposed); + // Feature flags are always booleans, so any other ROX_* value is an unexpected leak. + const nonBooleanRoxKeys = Object.keys(exposed).filter( + (key) => key.startsWith('ROX_') && typeof exposed[key] !== 'boolean' + ); + + expect(leakedKeys, 'secrets in Cypress.expose()').to.be.empty; + expect(nonBooleanRoxKeys, 'non-boolean ROX_* values in Cypress.expose()').to.be.empty; + }); + + it('copies feature flags exported by scripts/cypress.sh as booleans', function () { + // scripts/cypress.sh always exports ROX_AUTH_TOKEN alongside the feature flags, so use it to + // detect a runner launch. If the copy breaks, flag-gated tests skip silently, so fail here. + cy.env(['ROX_AUTH_TOKEN']).then(({ ROX_AUTH_TOKEN }) => { + if (!ROX_AUTH_TOKEN) { + this.skip(); + } + + const flagKeys = Object.keys(Cypress.expose()).filter((key) => key.startsWith('ROX_')); + + expect(flagKeys, 'ROX_* feature flags in Cypress.expose()').to.not.be.empty; + }); + }); + + it('rejects the deprecated Cypress.env() because allowCypressEnv is false', () => { + expect(() => Cypress.env('AXE_CORE_PATH')).to.throw(); + }); + + it('feature helpers read from Cypress.expose', () => { + Cypress.expose({ + ROX_FAKE_FLAG: true, + ROX_OTHER_FLAG: false, + ORCHESTRATOR_FLAVOR: 'openshift', + }); + + expect(hasFeatureFlag('ROX_FAKE_FLAG')).to.equal(true); + expect(hasFeatureFlag('ROX_OTHER_FLAG')).to.equal(false); + expect(hasFeatureFlag('ROX_MISSING_FLAG')).to.equal(false); + expect(hasOrchestratorFlavor('openshift')).to.equal(true); + expect(hasOrchestratorFlavor('k8s')).to.equal(false); + }); + + it('injects axe-core from the exposed AXE_CORE_PATH', () => { + // Inject directly rather than through checkAccessibility so the assertion covers the + // exposed path itself and does not depend on the accessibility of the current page. + cy.injectAxe({ axeCorePath: Cypress.expose('AXE_CORE_PATH') }); + cy.window().its('axe').should('exist'); + }); +}); diff --git a/ui/apps/platform/cypress/integration/policies/policyWizardStep3-dnd.test.js b/ui/apps/platform/cypress/integration/policies/policyWizardStep3-dnd.test.js index 5302dbe7d207a..7f878f08194cb 100644 --- a/ui/apps/platform/cypress/integration/policies/policyWizardStep3-dnd.test.js +++ b/ui/apps/platform/cypress/integration/policies/policyWizardStep3-dnd.test.js @@ -1,6 +1,5 @@ import * as api from '../../constants/apiEndpoints'; import withAuth from '../../helpers/basicAuth'; -import { hasFeatureFlag } from '../../helpers/features'; import { cloneFirstPolicyFromTable, doPolicyRowAction, @@ -33,12 +32,6 @@ function clearPolicyCriteriaCards() { describe('Policy wizard, Step 3 Policy Criteria', () => { withAuth(); - before(function () { - if (hasFeatureFlag('ROX_POLICY_CRITERIA_MODAL')) { - this.skip(); - } - }); - it('should not allow user to edit policy criteria for default policies', () => { visitPolicies(); editFirstPolicyFromTable(); diff --git a/ui/apps/platform/cypress/integration/policies/policyWizardStep3.test.js b/ui/apps/platform/cypress/integration/policies/policyWizardStep3.test.js deleted file mode 100644 index c5a01305dbcfe..0000000000000 --- a/ui/apps/platform/cypress/integration/policies/policyWizardStep3.test.js +++ /dev/null @@ -1,480 +0,0 @@ -import * as api from '../../constants/apiEndpoints'; -import withAuth from '../../helpers/basicAuth'; -import { hasFeatureFlag } from '../../helpers/features'; -import { closeModalByButton } from '../../helpers/modal'; -import { - cloneFirstPolicyFromTable, - doPolicyRowAction, - editFirstPolicyFromTable, - goToStep3, - visitPolicies, -} from './Policies.helpers'; -import { selectors } from './Policies.selectors'; - -const TREE_VIEW_SEARCH_INPUT = '.pf-v6-c-tree-view__search input[name="search-input"]'; -const TREE_VIEW_FIRST_LEVEL_CHILD = '.pf-v6-c-tree-view__list-item .pf-v6-c-tree-view__list-item'; - -// open Policy Fields modal, select given field, and add it to the section card -function addPolicyField(fieldName) { - cy.get('.policy-section-card button:contains("Add policy field")').click(); - - // Note: we only use the first word of the field name to filter, because the PatternFly 4 - // TreeView search field has a bug where it doesn't accept spaces - const firstWordOfFieldName = fieldName.split(' ')[0]; - // cy.log(firstWordOfFieldName); - cy.get(TREE_VIEW_SEARCH_INPUT).type(firstWordOfFieldName); - - // Match entire title to distinguish CVSS From NVD CVSS. - cy.get(`${TREE_VIEW_FIRST_LEVEL_CHILD} .pf-v6-c-tree-view__node-title`) - .contains(new RegExp(`^${fieldName}$`)) - .click(); - - cy.get(`${TREE_VIEW_FIRST_LEVEL_CHILD} .pf-v6-c-tree-view__node`).should( - 'have.class', - 'pf-m-current' - ); - - closeModalByButton('Add policy field'); -} - -// open Policy Fields modal and ensure a given field is not available -function assertPolicyFieldNotAvailable(fieldName) { - cy.get('.policy-section-card button:contains("Add policy field")').click(); - - // Note: we only use the first word of the field name to filter, because the PatternFly 4 - // TreeView search field has a bug where it doesn't accept spaces - const firstWordOfFieldName = fieldName.split(' ')[0]; - // cy.log(firstWordOfFieldName); - cy.get(TREE_VIEW_SEARCH_INPUT).type(firstWordOfFieldName); - - cy.get( - `${TREE_VIEW_FIRST_LEVEL_CHILD} .pf-v6-c-tree-view__node-title:contains(${fieldName})` - ).should('not.exist'); - - closeModalByButton('Cancel'); -} - -function goToPoliciesAndCloneToStep3() { - visitPolicies(); - cloneFirstPolicyFromTable(); - goToStep3(); -} - -function clearPolicyCriteriaCards() { - // starting from clean slate - cy.get(selectors.step3.policyCriteria.groupCards).then((cards) => { - if (cards.length > 0) { - cy.get(selectors.step3.policyCriteria.deleteBtn).eq(0).click(); - } - }); -} - -describe.skip('Policy wizard, Step 3 Policy Criteria', () => { - withAuth(); - - before(function () { - if (!hasFeatureFlag('ROX_POLICY_CRITERIA_MODAL')) { - this.skip(); - } - }); - - it('should not allow user to edit policy criteria for default policies', () => { - visitPolicies(); - editFirstPolicyFromTable(); - goToStep3(); - - cy.get(selectors.step3.defaultPolicyAlert).should('exist'); - cy.get(selectors.step3.policyCriteria.value.numberInput).should('be.disabled'); - cy.get(selectors.step3.policySection.addBtn).should('not.exist'); - }); - - it('should have a modal with nested policy field keys', () => { - goToPoliciesAndCloneToStep3(); - - // open policy fields modal - cy.get('.policy-section-card button:contains("Add policy field")').click(); - cy.get('.pf-v6-c-modal-box__title-text:contains("Add policy criteria field")'); - - // check that all Deploy-time categories are available - // after filtering for Lifecycle was added, the number of groups for a Deploy-only policy is 7 - const GROUPS_AVAILABLE_FOR_DEPLOY_POLICY = [ - 'Image registry', - 'Image contents', - 'Image scanning', - 'Container configuration', - 'Deployment metadata', - 'Storage', - 'Networking', - 'Service account', - ]; - cy.get('.pf-v6-c-tree-view__list-item').each((element, index) => { - element.get( - `.pf-v6-c-tree-view__node-title:contains(${GROUPS_AVAILABLE_FOR_DEPLOY_POLICY[index]})` - ); - }); - - // now, check the criteria in a category - const FIELDS_AVAILABLE_FOR_DEPLOY_POLICY = [ - 'Image registry', - 'Image name', - 'Image tag', - 'Require image signature', - ]; - cy.get('.pf-v6-c-tree-view__list-item:first').click(); - cy.get(TREE_VIEW_FIRST_LEVEL_CHILD).each((element, index) => { - element.get( - `.pf-v6-c-tree-view__node-title:contains(${FIELDS_AVAILABLE_FOR_DEPLOY_POLICY[index]})` - ); - }); - - closeModalByButton('Cancel'); - }); - - describe('Policy section', () => { - it('should allow the user to add and delete a policy section card', () => { - goToPoliciesAndCloneToStep3(); - - // add policy section card - cy.get(selectors.step3.policySection.cards).then((sections) => { - cy.get(selectors.step3.policySection.addBtn).click(); - cy.get(selectors.step3.policySection.cards).then((newSections) => { - expect(newSections).to.have.length(sections.length + 1); - }); - }); - cy.get(selectors.step3.policySection.orDivider).should('exist'); - - // delete policy section card - cy.get(selectors.step3.policySection.cards).then((sections) => { - cy.get(selectors.step3.policySection.deleteBtn).first().click(); - cy.get(selectors.step3.policySection.cards).then((newSections) => { - expect(newSections).to.have.length(sections.length - 1); - }); - }); - }); - - it('should allow editing a policy section name and retain new name value', () => { - goToPoliciesAndCloneToStep3(); - - cy.get(selectors.step3.policySection.nameEditBtn).click(); - cy.get(selectors.step3.policySection.nameInput).clear(); - cy.get(selectors.step3.policySection.nameInput).type('New Section'); - cy.get(selectors.step3.policySection.nameSaveBtn).click(); - cy.get(selectors.step3.policySection.name).contains('New Section'); - }); - - it('should allow the user to add/delete a policy field card in the same policy section', () => { - goToPoliciesAndCloneToStep3(); - - // add policy field card - cy.get(selectors.step3.policyCriteria.groupCards).then((cards) => { - addPolicyField('Image registry', 0); - cy.get(selectors.step3.policyCriteria.groupCards).then((newCards) => { - expect(newCards).to.have.length(cards.length + 1); - }); - }); - - // delete policy field card - cy.get(selectors.step3.policyCriteria.groupCards).then((cards) => { - cy.get(selectors.step3.policyCriteria.deleteBtn).eq(0).click(); - cy.get(selectors.step3.policyCriteria.groupCards).then((newCards) => { - expect(newCards).to.have.length(cards.length - 1); - }); - }); - }); - - it('should allow the user to add multiple non-duplicate policy field cards in the same policy section', () => { - goToPoliciesAndCloneToStep3(); - - cy.get(selectors.step3.policyCriteria.groupCards).then((cards) => { - addPolicyField('Image registry'); - addPolicyField('Image name'); - addPolicyField('Image tag'); - cy.get(selectors.step3.policyCriteria.groupCards).then((newCards) => { - expect(newCards).to.have.length(cards.length + 3); - }); - }); - }); - - it('should not be able to add duplicate policy field cards in the same policy section', () => { - goToPoliciesAndCloneToStep3(); - - cy.get(selectors.step3.policyCriteria.groupCards).then((cards) => { - addPolicyField('Image name'); - assertPolicyFieldNotAvailable('Image name'); - cy.get(selectors.step3.policyCriteria.groupCards).then((newCards) => { - expect(newCards).to.have.length(cards.length + 1); - }); - }); - }); - }); - - describe('Policy field card', () => { - describe('values', () => { - it('should add/delete multiple field values for the same field if applicable', () => { - goToPoliciesAndCloneToStep3(); - clearPolicyCriteriaCards(); - - // add field values for Image Registry - addPolicyField('Image name'); - cy.get(selectors.step3.policyCriteria.value.deleteBtn).should('not.exist'); - cy.get(selectors.step3.policyCriteria.value.addBtn).first().click(); - cy.get(selectors.step3.policyCriteria.value.textInput).then((inputs) => { - expect(inputs).to.have.length(2); - cy.get(selectors.step3.policyCriteria.value.deleteBtn).should('have.length', 2); - }); - cy.get(selectors.step3.policyCriteria.booleanOperator).should('have.length', 1); - cy.get(selectors.step3.policyCriteria.booleanOperator).should('not.be.disabled'); - - // delete field value - cy.get(selectors.step3.policyCriteria.value.deleteBtn).first().click(); - cy.get(selectors.step3.policyCriteria.value.textInput).then((inputs) => { - expect(inputs).to.have.length(1); - cy.get(selectors.step3.policyCriteria.value.deleteBtn).should('not.exist'); - cy.get(selectors.step3.policyCriteria.booleanOperator).should('not.exist'); - }); - }); - - it('should not add multiple field values for the same field if not applicable', () => { - goToPoliciesAndCloneToStep3(); - clearPolicyCriteriaCards(); - - addPolicyField('Mounted volume writability'); - cy.get(selectors.step3.policyCriteria.value.radioGroup).should('exist'); - cy.get(selectors.step3.policyCriteria.value.addBtn).should('not.exist'); - }); - }); - - describe('negation', () => { - it('should negate field if applicable and change wording', () => { - goToPoliciesAndCloneToStep3(); - clearPolicyCriteriaCards(); - - addPolicyField('Image registry'); - cy.get(selectors.step3.policyCriteria.value.negateCheckbox).should( - 'not.be.checked' - ); - cy.get(selectors.step3.policyCriteria.value.negateCheckbox).click(); - cy.get(selectors.step3.policyCriteria.value.negateCheckbox).should('be.checked'); - cy.get(selectors.step3.policyCriteria.groupCardTitle).first().contains('not'); - }); - - it('should not show negate field if not applicable', () => { - goToPoliciesAndCloneToStep3(); - clearPolicyCriteriaCards(); - - addPolicyField('Mounted volume writability'); - cy.get(selectors.step3.policyCriteria.value.negateCheckbox).should('not.exist'); - }); - }); - - describe('boolean operator', () => { - it('should toggle AND/OR if applicable', () => { - goToPoliciesAndCloneToStep3(); - clearPolicyCriteriaCards(); - - addPolicyField('Image registry'); - cy.get(selectors.step3.policyCriteria.value.addBtn).first().click(); - cy.get(selectors.step3.policyCriteria.booleanOperator).should('not.be.disabled'); - cy.get(selectors.step3.policyCriteria.booleanOperator).contains('or'); - cy.get(selectors.step3.policyCriteria.booleanOperator).click(); - cy.get(selectors.step3.policyCriteria.booleanOperator).contains('and'); - }); - - it('should have AND/OR toggle disabled if not applicable', () => { - goToPoliciesAndCloneToStep3(); - clearPolicyCriteriaCards(); - - addPolicyField('Image age'); - cy.get(selectors.step3.policyCriteria.value.addBtn).first().click(); - cy.get(selectors.step3.policyCriteria.booleanOperator).should('be.disabled'); - cy.get(selectors.step3.policyCriteria.booleanOperator).contains('or'); - }); - }); - - describe('input', () => { - it('should populate boolean radio buttons w default value and respect changed values', () => { - goToPoliciesAndCloneToStep3(); - clearPolicyCriteriaCards(); - - addPolicyField('Image scan status'); - cy.get(selectors.step3.policyCriteria.value.radioGroup).should('exist'); - cy.get( - `${selectors.step3.policyCriteria.value.radioGroupItem}:contains('Scanned') button` - ).should('not.have.class', 'pf-m-selected'); - cy.get( - `${selectors.step3.policyCriteria.value.radioGroupItem}:contains('Not scanned') button` - ).should('have.class', 'pf-m-selected'); - cy.get( - `${selectors.step3.policyCriteria.value.radioGroupItem}:contains('Scanned') button` - ).click(); - cy.get( - `${selectors.step3.policyCriteria.value.radioGroupItem}:contains('Scanned') button` - ).should('have.class', 'pf-m-selected'); - cy.get( - `${selectors.step3.policyCriteria.value.radioGroupItem}:contains('Not scanned') button` - ).should('not.have.class', 'pf-m-selected'); - }); - - it('should populate string radio buttons w default value and respect changed values', () => { - goToPoliciesAndCloneToStep3(); - clearPolicyCriteriaCards(); - - addPolicyField('Seccomp profile type'); - cy.get(selectors.step3.policyCriteria.value.radioGroupString).should('exist'); - cy.get( - `${selectors.step3.policyCriteria.value.radioGroupStringItem} button.pf-m-selected` - ).should('have.length', 0); - cy.get( - `${selectors.step3.policyCriteria.value.radioGroupStringItem}:contains('Unconfined') button` - ).click(); - cy.get( - `${selectors.step3.policyCriteria.value.radioGroupStringItem}:contains('Unconfined') button` - ).should('have.class', 'pf-m-selected'); - cy.get( - `${selectors.step3.policyCriteria.value.radioGroupStringItem} button.pf-m-selected` - ).should('have.length', 1); - }); - - it('should populate text input and respect changed values', () => { - goToPoliciesAndCloneToStep3(); - clearPolicyCriteriaCards(); - - addPolicyField('Image registry'); - cy.get(selectors.step3.policyCriteria.value.textInput).should('have.value', ''); - cy.get(selectors.step3.policyCriteria.value.textInput).type('test'); - cy.get(selectors.step3.policyCriteria.value.textInput).should('have.value', 'test'); - }); - - it('should populate select dropdown and respect changed values', () => { - goToPoliciesAndCloneToStep3(); - clearPolicyCriteriaCards(); - - addPolicyField('Drop capabilities'); - cy.get(selectors.step3.policyCriteria.value.select).should('have.value', ''); - cy.get(selectors.step3.policyCriteria.value.select).click(); - cy.get(selectors.step3.policyCriteria.value.selectOption) - .first() - .then((option) => { - cy.wrap(option).click(); - cy.get(selectors.step3.policyCriteria.value.select).contains(option.text()); - }); - }); - - it('should populate policy field input nested group and parse value string to object and respect changed values', () => { - goToPoliciesAndCloneToStep3(); - clearPolicyCriteriaCards(); - - addPolicyField('CVSS'); - cy.get(selectors.step3.policyCriteria.value.select).should('have.value', ''); - cy.get(selectors.step3.policyCriteria.value.numberInput).should('have.value', ''); - cy.get(selectors.step3.policyCriteria.value.select).click(); - cy.get(selectors.step3.policyCriteria.value.selectOption) - .first() - .then((option) => { - cy.wrap(option).click(); - cy.get(selectors.step3.policyCriteria.value.select).contains(option.text()); - }); - cy.get(selectors.step3.policyCriteria.value.numberInput).type('10'); - cy.get(selectors.step3.policyCriteria.value.numberInput).should('have.value', '10'); - }); - }); - - describe('table modal', () => { - beforeEach(() => { - cy.intercept('GET', api.integrations.signatureIntegrations, { - fixture: 'integrations/signatureIntegrations.json', - }).as('getSignatureIntegrations'); - - goToPoliciesAndCloneToStep3(); - clearPolicyCriteriaCards(); - addPolicyField('Require image signature'); - cy.wait('@getSignatureIntegrations'); - }); - - it('should populate table modal select and respect changed values on save', () => { - cy.get(selectors.step3.policyCriteria.value.tableModal.textInput).should( - 'have.value', - 'Add trusted image signers' - ); - cy.get(selectors.step3.policyCriteria.value.tableModal.openButton).click(); - cy.get(selectors.step3.policyCriteria.value.tableModal.firstRowCheckbox).click(); - cy.get(selectors.step3.policyCriteria.value.tableModal.saveBtn).click(); - cy.get(selectors.step3.policyCriteria.value.tableModal.textInput).should( - 'have.value', - 'Selected 1 trusted image signer' - ); - }); - - it('should populate table modal select and not change values on cancel', () => { - cy.get(selectors.step3.policyCriteria.value.tableModal.openButton).click(); - cy.get(selectors.step3.policyCriteria.value.tableModal.firstRowCheckbox).click(); - cy.get(selectors.step3.policyCriteria.value.tableModal.cancelBtn).click(); - cy.get(selectors.step3.policyCriteria.value.tableModal.textInput).should( - 'have.value', - 'Add trusted image signers' - ); - }); - - it('should go to link when table row is clicked', () => { - cy.get(selectors.step3.policyCriteria.value.tableModal.openButton).click(); - cy.get(selectors.step3.policyCriteria.value.tableModal.firstRowName).click(); - cy.location('pathname').should('contain', 'signatureIntegrations'); - }); - }); - }); - - describe('Existing values', () => { - it('should populate boolean radio buttons', () => { - visitPolicies(); - doPolicyRowAction(`${selectors.table.rows}:contains('root filesystem')`, 'Clone'); - goToStep3(); - cy.get(selectors.step3.policyCriteria.value.radioGroup).should('exist'); - cy.get( - `${selectors.step3.policyCriteria.value.radioGroupItem}:contains('Writable') button` - ).should('have.class', 'pf-m-selected'); - cy.get( - `${selectors.step3.policyCriteria.value.radioGroupItem} button.pf-m-selected` - ).should('have.length', 1); - }); - - it('should populate string radio buttons', () => { - visitPolicies(); - doPolicyRowAction(`${selectors.table.rows}:contains('seccomp profile')`, 'Clone'); - goToStep3(); - cy.get(selectors.step3.policyCriteria.value.radioGroupString).should('exist'); - cy.get( - `${selectors.step3.policyCriteria.value.radioGroupStringItem}:contains('Unconfined') button` - ).should('have.class', 'pf-m-selected'); - cy.get( - `${selectors.step3.policyCriteria.value.radioGroupStringItem} button.pf-m-selected` - ).should('have.length', 1); - }); - - it('should populate text input', () => { - visitPolicies(); - doPolicyRowAction(`${selectors.table.rows}:contains('Latest tag')`, 'Clone'); - goToStep3(); - cy.get(selectors.step3.policyCriteria.value.textInput).should('have.value', 'latest'); - }); - - it('should populate select dropdown', () => { - visitPolicies(); - doPolicyRowAction(`${selectors.table.rows}:contains('capability')`, 'Clone'); - goToStep3(); - cy.get(selectors.step3.policyCriteria.value.select).contains('SYS_ADMIN'); - }); - - it('should populate policy field input nested group', () => { - visitPolicies(); - doPolicyRowAction(`${selectors.table.rows}:contains('CVSS >= 6')`, 'Clone'); - goToStep3(); - cy.get(selectors.step3.policyCriteria.value.select).contains( - 'Is greater than or equal to' - ); - cy.get(selectors.step3.policyCriteria.value.numberInput).should( - 'have.value', - '6.000000' - ); - }); - }); -}); diff --git a/ui/apps/platform/cypress/integration/vulnerabilities/reports/reportsOverviewNav.test.ts b/ui/apps/platform/cypress/integration/vulnerabilities/reports/reportsOverviewNav.test.ts index 68e360a6b7555..49ef7cc346922 100644 --- a/ui/apps/platform/cypress/integration/vulnerabilities/reports/reportsOverviewNav.test.ts +++ b/ui/apps/platform/cypress/integration/vulnerabilities/reports/reportsOverviewNav.test.ts @@ -1,8 +1,5 @@ import withAuth from '../../../helpers/basicAuth'; -import { - interceptAndOverrideFeatureFlags, - interceptAndOverridePermissions, -} from '../../../helpers/request'; +import { interceptAndOverridePermissions } from '../../../helpers/request'; import { visit } from '../../../helpers/visit'; import pf6 from '../../../selectors/pf6'; @@ -24,7 +21,6 @@ describe('Vulnerability Reports Overview Navigation', () => { it('navigates to the node vulnerability reports page', () => { interceptAndOverridePermissions({ Cluster: 'READ_ACCESS', Node: 'READ_ACCESS' }); - interceptAndOverrideFeatureFlags({ ROX_NODE_VULNERABILITY_REPORTS: true }); visit(vulnerabilityReportsOverviewPath); diff --git a/ui/apps/platform/cypress/integration/vulnerabilities/workloadCves/imageSingle.test.ts b/ui/apps/platform/cypress/integration/vulnerabilities/workloadCves/imageSingle.test.ts index 8ce81d5520e73..c784b117e70ed 100644 --- a/ui/apps/platform/cypress/integration/vulnerabilities/workloadCves/imageSingle.test.ts +++ b/ui/apps/platform/cypress/integration/vulnerabilities/workloadCves/imageSingle.test.ts @@ -49,20 +49,11 @@ describe('Workload CVE Image Single page', () => { // see: https://issues.redhat.com/browse/ROX-24254 // https://github.com/stackrox/stackrox/pull/6156 it('should display nested component data correctly when processed via apollo client', () => { - const isFlattenImageData = hasFeatureFlag('ROX_FLATTEN_IMAGE_DATA'); - const imageRootKey = isFlattenImageData ? 'imageV2' : 'image'; - const opname = 'getCVEsForImage'; const imageData = { - id: isFlattenImageData - ? '4c657931-d333-5cb8-8f0d-7e3836525ec7' - : 'sha256:010fec71f42f4b5e65f3f56f10af94a7c05c9c271a9bbc3026684ba170698cb5', - ...(isFlattenImageData - ? { - digest: 'sha256:010fec71f42f4b5e65f3f56f10af94a7c05c9c271a9bbc3026684ba170698cb5', - } - : {}), + id: '4c657931-d333-5cb8-8f0d-7e3836525ec7', + digest: 'sha256:010fec71f42f4b5e65f3f56f10af94a7c05c9c271a9bbc3026684ba170698cb5', name: { registry: 'quay.io', remote: 'openshift-release-dev/ocp-v4.0-art-dev', @@ -82,7 +73,7 @@ describe('Workload CVE Image Single page', () => { }, __typename: 'ImageMetadata', }, - __typename: isFlattenImageData ? 'ImageV2' : 'Image', + __typename: 'ImageV2', imageCVECountBySeverity: { unknown: { total: 0, @@ -182,7 +173,7 @@ describe('Workload CVE Image Single page', () => { const body = { data: { - [imageRootKey]: imageData, + imageV2: imageData, }, }; diff --git a/ui/apps/platform/cypress/integration/vulnerabilities/workloadCves/workloadCveOverviewPage.test.ts b/ui/apps/platform/cypress/integration/vulnerabilities/workloadCves/workloadCveOverviewPage.test.ts index 5b685bca9a27e..12bb73e18817b 100644 --- a/ui/apps/platform/cypress/integration/vulnerabilities/workloadCves/workloadCveOverviewPage.test.ts +++ b/ui/apps/platform/cypress/integration/vulnerabilities/workloadCves/workloadCveOverviewPage.test.ts @@ -363,8 +363,6 @@ describe('Workload CVE overview page tests', () => { describe('Layer type filter tests', () => { it('should apply Layer type filter correctly', () => { - interceptAndOverrideFeatureFlags({ ROX_BASE_IMAGE_DETECTION: true }); - visitWorkloadCveOverview(); addCheckboxSelectFilter('Image component', 'Layer type', 'Base image'); diff --git a/ui/apps/platform/cypress/support/commands.js b/ui/apps/platform/cypress/support/commands.js index 7a744a01b2f2c..59ebccb397525 100644 --- a/ui/apps/platform/cypress/support/commands.js +++ b/ui/apps/platform/cypress/support/commands.js @@ -16,7 +16,7 @@ Cypress.Commands.add('checkAccessibility', (context = null) => { // inject axe only if it hasn't been injected yet cy.window().then((win) => { if (!win.axe) { - cy.injectAxe({ axeCorePath: Cypress.env('AXE_CORE_PATH') }); + cy.injectAxe({ axeCorePath: Cypress.expose('AXE_CORE_PATH') }); } }); diff --git a/ui/apps/platform/eslint-plugins/pluginLimited.js b/ui/apps/platform/eslint-plugins/pluginLimited.js index f5697047dcc81..031212372b678 100644 --- a/ui/apps/platform/eslint-plugins/pluginLimited.js +++ b/ui/apps/platform/eslint-plugins/pluginLimited.js @@ -379,6 +379,38 @@ const rules = { }; }, }, + 'no-import-from-Containers-in-Components': { + // Prevent soft circular dependency: + // * A generic file in Components has import from a specific file in Containers. + // * Another specific file in Containers might have import of that generic file from Components. + // Although the rule cannot know for sure, Components exists for import into Containers. + meta: { + type: 'problem', + docs: { + description: + 'Fix soft circular dependency between specific Containers and generic Components', + }, + schema: [], + }, + create(context) { + return { + ImportDeclaration(node) { + const { filename } = context; + if ( + filename.includes('ui/apps/platform/src/Components/') && + typeof node.source?.value === 'string' && + node.source.value.startsWith('Containers/') + ) { + context.report({ + node, + message: + 'Fix soft circular dependency between specific Containers and generic Components', + }); + } + }, + }; + }, + }, 'no-logical-or-preceding-array-or-object': { // Consistently write more precise nullish coalescing operator. meta: { diff --git a/ui/apps/platform/eslint-plugins/pluginPatternFly.js b/ui/apps/platform/eslint-plugins/pluginPatternFly.js index 38edad0b83686..90a28cf80bb67 100644 --- a/ui/apps/platform/eslint-plugins/pluginPatternFly.js +++ b/ui/apps/platform/eslint-plugins/pluginPatternFly.js @@ -46,6 +46,145 @@ const rules = { }; }, }, + 'PageSection-type-breadcrumb': { + // Require that PageSection element has type="breadcrumb" prop if Breadcrumb is a child. + meta: { + type: 'problem', + docs: { + description: + 'Require that PageSection element has type="breadcrumb" prop if Breadcrumb is a child.', + }, + schema: [], + }, + create(context) { + return { + JSXOpeningElement(node) { + if ( + node.name?.name === 'PageSection' && + !node.attributes.some( + (attribute) => + attribute.name?.name === 'type' && + attribute.value?.value === 'breadcrumb' + ) + ) { + const ancestors = context.sourceCode.getAncestors(node); + if ( + ancestors.length > 0 && + Array.isArray(ancestors[ancestors.length - 1].children) && + ancestors[ancestors.length - 1].children.some( + (child) => child.openingElement?.name?.name === 'Breadcrumb' + ) + ) { + context.report({ + node, + message: + 'PageSection element needs type="breadcrumb" prop if Breadcrumb is a child', + }); + } + } + }, + }; + }, + }, + 'PageSection-type-tabs': { + // Require that PageSection element has type="tabs" prop if Tabs is a child. + meta: { + type: 'problem', + docs: { + description: + 'Require that PageSection element has type="tabs" prop if Tabs is a child.', + }, + schema: [], + }, + create(context) { + return { + JSXOpeningElement(node) { + if ( + node.name?.name === 'PageSection' && + !node.attributes.some( + (attribute) => + attribute.name?.name === 'type' && attribute.value?.value === 'tabs' + ) + ) { + const ancestors = context.sourceCode.getAncestors(node); + if ( + ancestors.length > 0 && + Array.isArray(ancestors[ancestors.length - 1].children) && + ancestors[ancestors.length - 1].children.some( + (child) => child.openingElement?.name?.name === 'Tabs' + ) + ) { + context.report({ + node, + message: + 'PageSection element needs type="tabs" prop if Tabs is a child', + }); + } + } + }, + }; + }, + }, + 'PageSection-type-wizard': { + // Require that PageSection element has type="wizard" prop if Wizard is a child. + meta: { + type: 'problem', + docs: { + description: + 'Require that PageSection element has type="wizard" prop if Wizard is a child.', + }, + schema: [], + }, + create(context) { + return { + JSXOpeningElement(node) { + if ( + node.name?.name === 'PageSection' && + !node.attributes.some( + (attribute) => + attribute.name?.name === 'type' && + attribute.value?.value === 'wizard' + ) + ) { + const ancestors = context.sourceCode.getAncestors(node); + if ( + ancestors.length > 0 && + Array.isArray(ancestors[ancestors.length - 1].children) && + ancestors[ancestors.length - 1].children.some( + (child) => child.openingElement?.name?.name === 'Wizard' + ) + ) { + context.report({ + node, + message: + 'PageSection element needs type="wizard" prop if Wizard is a child', + }); + } else if ( + ancestors.length > 1 && + Array.isArray(ancestors[ancestors.length - 1].children) + ) { + const childFound = ancestors[ancestors.length - 1].children.find( + (child) => child.openingElement?.name?.name === 'FormikProvider' + ); + if ( + childFound && + Array.isArray(childFound.children) && + childFound.children.some( + (child) => child.openingElement?.name?.name === 'Wizard' + ) + ) { + context.report({ + node, + message: + 'PageSection element needs type="wizard" prop if Wizard is a descendant', + }); + } + } + } + }, + }; + }, + }, 'Td-dataLabel-Th-text': { // Require that if Td element has dataLabel prop with string value, // then Th element with same index has corresponding text (or screenReaderText). diff --git a/ui/apps/platform/eslint.config.js b/ui/apps/platform/eslint.config.js index a6f13c2547d36..1f61d3908f56e 100644 --- a/ui/apps/platform/eslint.config.js +++ b/ui/apps/platform/eslint.config.js @@ -788,7 +788,6 @@ module.exports = [ }, { files: ['src/*/**/*.{jsx,ts,tsx}'], // product files, except for unit tests (including test-utils folder) - ignores: ['src/Containers/Compliance/**'], // languageOptions from previous configuration object @@ -797,14 +796,13 @@ module.exports = [ limited: pluginLimited, }, rules: { - 'import/no-cycle': ['error', { maxDepth: '∞' }], // classic compliance has 7 errors + 'import/no-cycle': ['error', { maxDepth: '∞' }], 'limited/react-export-default': 'error', }, }, { files: ['**/*.{js,jsx,ts,tsx}'], // generic configuration includes cypress and src folders ignores: [ - 'src/Containers/Compliance/**', // deprecated 'src/Containers/VulnMgmt/**', // deprecated ], @@ -823,7 +821,6 @@ module.exports = [ { files: ['src/*/**/*.{js,jsx,ts,tsx}'], ignores: [ - 'src/Containers/Compliance/**', // deprecated 'src/Containers/VulnMgmt/**', // deprecated 'src/Containers/Workflow/**', // deprecated ], @@ -839,13 +836,36 @@ module.exports = [ 'limited/no-relative-path-to-src-in-import': 'error', }, }, + { + files: ['src/*/**/*.{js,jsx,ts,tsx}'], + ignores: [ + 'src/Components/CompoundSearchFilter/attributes/imageCVE.ts', // refactor: originDisplayNames + 'src/Components/CompoundSearchFilter/attributes/imageComponent.ts', // refactor: sourceTypeLabels, sourceTypes + 'src/Components/CompoundSearchFilter/attributes/virtualMachine.ts', // refactor: sourceTypeLabels, sourceTypes + 'src/Components/EmailNotifier/EmailNotifierForm.tsx', // refactor + 'src/Components/EmailNotifier/EmailNotifierModal.tsx', // refactor + 'src/Components/RelatedEntity.jsx', // deprecated + 'src/Components/RelatedEntityListCount.jsx', // deprecated + 'src/Components/URLSearchInputWithAutocomplete.jsx', // deprecated + 'src/Components/workflow/EntitiesMenu/EntitiesMenu.jsx', // deprecated + ], + + // languageOptions from previous configuration object + + // Key of plugin is namespace of its rules. + plugins: { + limited: pluginLimited, + }, + rules: { + 'limited/no-import-from-Containers-in-Components': 'error', + }, + }, { files: ['src/*/**/*.{js,jsx,ts,tsx}'], ignores: [ 'src/Components/GroupedTabs.jsx', // deprecated 'src/Components/ReactSelect/ReactSelect.jsx', // deprecated 'src/Components/URLSearchInputWithAutocomplete.jsx', // deprecated - 'src/Containers/Compliance/**', // deprecated 'src/Containers/VulnMgmt/**', // deprecated 'src/sagas/authSagas.js', // deprecated 'src/sagas/groupSagas.js', // deprecated @@ -913,7 +933,6 @@ module.exports = [ 'src/Components/visuals/**', // deprecated 'src/Components/workflow/**', // deprecated - 'src/Containers/Compliance/**', // deprecated 'src/Containers/ConfigManagement/**', 'src/Containers/Images/**', // deprecated 'src/Containers/Login/**', // rewrite in PatternFly, and then delete; also in tailwind.config.js file @@ -939,7 +958,6 @@ module.exports = [ ignores: [ 'cypress/constants/**', 'cypress/integration/clusters/**', // delete obsolete tests - 'cypress/integration/compliance/**', // deprecated 'cypress/integration/configmanagement/**', // deprecated/modernized 'cypress/integration/integrations/**', // replace 'cypress/integration/networkGraph/**', // replace @@ -950,7 +968,6 @@ module.exports = [ 'src/Components/**', // replace non-deprecated 'src/Containers/AccessControl/**', // replace 'src/Containers/Clusters/**', // delete obsolete tests - 'src/Containers/Compliance/**', // deprecated 'src/Containers/ConfigManagement/**', // deprecated/modernized 'src/Containers/Integrations/**', // replace 'src/Containers/Login/**', // replace @@ -990,7 +1007,6 @@ module.exports = [ 'src/Components/Tabs.jsx', // deprecated 'src/Components/visuals/Sunburst.jsx', // deprecated 'src/Components/visuals/SunburstDetailSection.jsx', // deprecated - 'src/Containers/Compliance/**', // deprecated 'src/Containers/Login/LoginPage.jsx', // rewrite 'src/Containers/MainPage/asyncComponent.tsx', // replace 'src/Containers/Risk/KeyValuePairs.jsx', // rewrite? @@ -1013,7 +1029,6 @@ module.exports = [ 'src/**/*.test.jsx', // unit test 'src/**/*.cy.jsx', // component test 'src/Components/**', // research - 'src/Containers/Compliance/**', // deprecated 'src/Containers/ConfigManagement/**', // deferred 'src/Containers/Images/**', // deprecated 'src/Containers/Login/LoginPage.jsx', // rewrite pending PatternFly 6 @@ -1102,7 +1117,6 @@ module.exports = [ 'src/Components/**', // most or all deprecated 'src/constants/entityPageProps.js', // deprecated 'src/constants/reduxFormPropTypes.js', // deprecated - 'src/Containers/Compliance/**', // deprecated 'src/Containers/ConfigManagement/**', // deprecated 'src/Containers/Images/**', // deprecated 'src/Containers/Login/LoginPage.jsx', // rewrite in TypeScript @@ -1136,7 +1150,6 @@ module.exports = [ 'src/Containers/AccessControl/AuthProviders/AuthProviders.tsx', // replace 'src/Containers/AccessControl/AuthProviders/AuthProvidersList.tsx', // replace 'src/Containers/Clusters/DownloadHelmValues.tsx', // replace - 'src/Containers/Compliance/**', // deprecated 'src/Containers/Login/LoginPage.jsx', // replace 'src/Containers/Login/TestLoginResultsPage.jsx', // replace 'src/Containers/MainPage/AcsFeedbackModal.tsx', // replace diff --git a/ui/apps/platform/package-lock.json b/ui/apps/platform/package-lock.json index 5b559226ccd98..b46d16429e0c9 100644 --- a/ui/apps/platform/package-lock.json +++ b/ui/apps/platform/package-lock.json @@ -21,7 +21,6 @@ "@patternfly/react-styles": "^6.4.0", "@patternfly/react-table": "^6.4.1", "@patternfly/react-topology": "^6.4.0", - "@patternfly/react-user-feedback": "^6.2.0", "@segment/analytics-next": "^1.81.1", "axios": "^1.18.0", "connected-react-router": "^6.9.3", @@ -2150,9 +2149,9 @@ } }, "node_modules/@openshift-console/dynamic-plugin-sdk/node_modules/immutable": { - "version": "3.8.3", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.8.3.tgz", - "integrity": "sha512-AUY/VyX0E5XlibOmWt10uabJzam1zlYjwiEgQSDc5+UIkFNaF9WM0JxXKaNMGf+F/ffUF+7kRKXM9A7C0xXqMg==", + "version": "3.8.4", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.8.4.tgz", + "integrity": "sha512-ZQv17KolYrYmsDoDB8N67zhIKsNi9mGYlk96y/yuxyAqJB2hLzSGSM7k/sB0/ZvO4kx27U9+fBeD/XlLGh/uXQ==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -2454,20 +2453,6 @@ "react-dom": "^17 || ^18 || ^19" } }, - "node_modules/@patternfly/react-user-feedback": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/@patternfly/react-user-feedback/-/react-user-feedback-6.2.0.tgz", - "integrity": "sha512-grhaZQwcESNZD2ifpbPoodCJ/NRTt4B24jVNYgDi23EVvQ0oGpyIXAvbUhX3siSkLjdqdYLsY9o5wNRJM78VkA==", - "license": "MIT", - "dependencies": { - "@patternfly/react-core": "^6.0.0", - "@patternfly/react-icons": "^6.0.0" - }, - "peerDependencies": { - "react": "^17 || ^18 || ^19", - "react-dom": "^17 || ^18 || ^19" - } - }, "node_modules/@peculiar/asn1-cms": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/@peculiar/asn1-cms/-/asn1-cms-2.7.0.tgz", @@ -10604,9 +10589,9 @@ } }, "node_modules/immutable": { - "version": "4.3.8", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.8.tgz", - "integrity": "sha512-d/Ld9aLbKpNwyl0KiM2CT1WYvkitQ1TSvmRtkcV8FKStiDoA7Slzgjmb/1G2yhKM1p0XeNOieaTbFZmU1d3Xuw==", + "version": "4.3.9", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.9.tgz", + "integrity": "sha512-ObHy4YN7ycwZOUCLI1/6svfyAFu7vL8RhAvVu/bh/RZW9EPlOyDaQ9jDQWCtdqzaXUjgXZCW1migtHE7YI7UGQ==", "license": "MIT", "optional": true }, diff --git a/ui/apps/platform/package.json b/ui/apps/platform/package.json index e43032dc8ed86..00001ee218471 100644 --- a/ui/apps/platform/package.json +++ b/ui/apps/platform/package.json @@ -24,7 +24,6 @@ "@patternfly/react-styles": "^6.4.0", "@patternfly/react-table": "^6.4.1", "@patternfly/react-topology": "^6.4.0", - "@patternfly/react-user-feedback": "^6.2.0", "@segment/analytics-next": "^1.81.1", "axios": "^1.18.0", "connected-react-router": "^6.9.3", diff --git a/ui/apps/platform/src/Components/CompoundSearchFilter/attributes/imageCVE.ts b/ui/apps/platform/src/Components/CompoundSearchFilter/attributes/imageCVE.ts index c8bb26a4920c4..b37c0e88a79ce 100644 --- a/ui/apps/platform/src/Components/CompoundSearchFilter/attributes/imageCVE.ts +++ b/ui/apps/platform/src/Components/CompoundSearchFilter/attributes/imageCVE.ts @@ -51,7 +51,7 @@ export const KnownExploit: CompoundSearchFilterAttribute = { }, ], }, - featureFlagDependency: ['ROX_SCANNER_V4', 'ROX_CISA_KEV'], + featureFlagDependency: ['ROX_SCANNER_V4'], }; // The filter value is the VulnOrigin enum name (e.g. VULN_ORIGIN_RED_HAT), which the diff --git a/ui/apps/platform/src/Components/CompoundSearchFilter/attributes/imageComponent.ts b/ui/apps/platform/src/Components/CompoundSearchFilter/attributes/imageComponent.ts index e4556f1ca8ea4..72e9c5fbeb2a2 100644 --- a/ui/apps/platform/src/Components/CompoundSearchFilter/attributes/imageComponent.ts +++ b/ui/apps/platform/src/Components/CompoundSearchFilter/attributes/imageComponent.ts @@ -35,7 +35,6 @@ export const LayerType: CompoundSearchFilterAttribute = { filterChipLabel: 'Image component layer type', searchTerm: 'Component Layer Type', inputType: 'select', - featureFlagDependency: ['ROX_BASE_IMAGE_DETECTION'], inputProps: { options: [ { label: 'Application', value: 'APPLICATION' }, diff --git a/ui/apps/platform/src/Components/ControlDetails.jsx b/ui/apps/platform/src/Components/ControlDetails.jsx deleted file mode 100644 index 347017c03c5c6..0000000000000 --- a/ui/apps/platform/src/Components/ControlDetails.jsx +++ /dev/null @@ -1,43 +0,0 @@ -import PropTypes from 'prop-types'; - -import { standardLabels } from 'messages/standards'; - -import Widget from 'Components/Widget'; - -const ControlDetails = ({ standardId, standardName, control, description, className }) => ( - -

-
- Standard: - - {standardLabels[standardId] || standardName} - -
-
- Control: - {control} -
-
-
{description}
- -); - -ControlDetails.propTypes = { - standardId: PropTypes.string.isRequired, - control: PropTypes.string.isRequired, - description: PropTypes.string.isRequired, - className: PropTypes.string, - standardName: PropTypes.string, -}; - -ControlDetails.defaultProps = { - className: '', - standardName: '', -}; - -export default ControlDetails; diff --git a/ui/apps/platform/src/Components/CountWidget.jsx b/ui/apps/platform/src/Components/CountWidget.jsx deleted file mode 100644 index 606f477897b01..0000000000000 --- a/ui/apps/platform/src/Components/CountWidget.jsx +++ /dev/null @@ -1,54 +0,0 @@ -import { connect } from 'react-redux'; -import PropTypes from 'prop-types'; -import { Link } from 'react-router-dom-v5-compat'; -import Widget from 'Components/Widget'; - -const CountWidget = ({ title, count, description, linkUrl }) => { - const countNode = ( -
0 ? `hover:bg-tertiary-200` : `` - } text-6xl px-5 py-8 h-full flex items-center justify-center`} - > - {count} -
- ); - const descNode = description &&
{description}
; - return ( - - {linkUrl ? ( - - {countNode} - {descNode} - - ) : ( - <> - {countNode} - {descNode} - - )} - - ); -}; - -CountWidget.propTypes = { - title: PropTypes.string.isRequired, - count: PropTypes.number, - description: PropTypes.string, - linkUrl: PropTypes.string, -}; - -CountWidget.defaultProps = { - description: null, - linkUrl: null, - count: 0, -}; - -export default connect()(CountWidget); diff --git a/ui/apps/platform/src/Components/EntityIcon.jsx b/ui/apps/platform/src/Components/EntityIcon.jsx index 545764667c7c7..11503a90aba0e 100644 --- a/ui/apps/platform/src/Components/EntityIcon.jsx +++ b/ui/apps/platform/src/Components/EntityIcon.jsx @@ -12,7 +12,6 @@ import policy from 'images/side-panel-icons/policy.svg'; import role from 'images/side-panel-icons/role.svg'; import secrets from 'images/side-panel-icons/secrets.svg'; import serviceAccount from 'images/side-panel-icons/service-account.svg'; -import control from 'images/side-panel-icons/control.svg'; const imageMap = { [entityTypes.CLUSTER]: cluster, @@ -32,7 +31,6 @@ const imageMap = { [entityTypes.ROLE]: role, [entityTypes.SECRET]: secrets, [entityTypes.SERVICE_ACCOUNT]: serviceAccount, - [entityTypes.CONTROL]: control, }; const EntityIcon = ({ className, entityType }) => ( diff --git a/ui/apps/platform/src/Components/ExportButton.jsx b/ui/apps/platform/src/Components/ExportButton.jsx deleted file mode 100644 index 7988a13464865..0000000000000 --- a/ui/apps/platform/src/Components/ExportButton.jsx +++ /dev/null @@ -1,116 +0,0 @@ -import { Component } from 'react'; -import PropTypes from 'prop-types'; -import { FileText } from 'react-feather'; -import onClickOutside from 'react-onclickoutside'; -import { Button } from '@patternfly/react-core'; - -import downloadCSV from 'services/CSVDownloadService'; -import ButtonClassic from 'Components/Button'; -import entityTypes from 'constants/entityTypes'; -import useCaseTypes from 'constants/useCaseTypes'; -import { addBrandedTimestampToString } from 'utils/dateUtils'; - -const queryParamMap = { - [entityTypes.CLUSTER]: 'clusterId', - [entityTypes.STANDARD]: 'standardId', - ALL: '', -}; - -class ExportButton extends Component { - static propTypes = { - className: PropTypes.string, - textClass: PropTypes.string, - fileName: PropTypes.string, - type: PropTypes.string, - id: PropTypes.string, - page: PropTypes.string, - disabled: PropTypes.bool, - }; - - static defaultProps = { - className: 'btn btn-base h-10', - textClass: null, - fileName: 'compliance', - type: null, - id: '', - page: '', - disabled: false, - }; - - constructor(props) { - super(props); - - this.state = { - toggleWidget: false, - }; - } - - handleClickOutside = () => this.setState({ toggleWidget: false }); - - downloadCSVFile = () => { - const { id, fileName, type } = this.props; - const csvName = addBrandedTimestampToString(fileName); - - let queryStr = ''; - if (queryParamMap[type] && id) { - queryStr = `${queryParamMap[type]}=${id}`; - } - - downloadCSV(csvName, '/api/compliance/export/csv', queryStr); - }; - - isSupported = () => { - const { page, type } = this.props; - return page === useCaseTypes.COMPLIANCE && Object.keys(queryParamMap).includes(type); - }; - - renderContent = () => { - if (!this.state.toggleWidget) { - return null; - } - - return this.isSupported() ? ( -
-
-
    -
  • -
    - -
    -
  • -
-
- ) : null; - }; - - toggleWidget = () => { - this.setState(({ toggleWidget }) => ({ toggleWidget: !toggleWidget })); - }; - - render() { - return ( -
- } - onClick={this.toggleWidget} - /> - {this.renderContent()} -
- ); - } -} - -export default onClickOutside(ExportButton); diff --git a/ui/apps/platform/src/Components/IconWidget.jsx b/ui/apps/platform/src/Components/IconWidget.jsx deleted file mode 100644 index c81b78d283ad5..0000000000000 --- a/ui/apps/platform/src/Components/IconWidget.jsx +++ /dev/null @@ -1,59 +0,0 @@ -import { connect } from 'react-redux'; -import PropTypes from 'prop-types'; -import { Link } from 'react-router-dom-v5-compat'; -import Widget from 'Components/Widget'; -import Loader from 'Components/Loader'; - -const IconWidget = ({ title, icon, description, linkUrl, loading, textSizeClass }) => { - const contents = loading ? ( - - ) : ( - <> -
- {title} -
-
- {description} -
- - ); - - return ( - - {linkUrl && !loading ? ( - - {contents} - - ) : ( -
{contents}
- )} -
- ); -}; - -IconWidget.propTypes = { - title: PropTypes.string.isRequired, - icon: PropTypes.node.isRequired, - description: PropTypes.string, - textSizeClass: PropTypes.string, - linkUrl: PropTypes.string, - loading: PropTypes.bool, -}; - -IconWidget.defaultProps = { - description: null, - linkUrl: null, - textSizeClass: 'text-2xl', - loading: false, -}; - -export default connect()(IconWidget); diff --git a/ui/apps/platform/src/Components/InfoWidget.jsx b/ui/apps/platform/src/Components/InfoWidget.jsx deleted file mode 100644 index b14be1fbe5976..0000000000000 --- a/ui/apps/platform/src/Components/InfoWidget.jsx +++ /dev/null @@ -1,51 +0,0 @@ -import { connect } from 'react-redux'; -import PropTypes from 'prop-types'; -import { Link } from 'react-router-dom-v5-compat'; -import Widget from 'Components/Widget'; -import Loader from 'Components/Loader'; - -const InfoWidget = ({ title, headline, description, linkUrl, loading }) => { - const contents = loading ? ( - - ) : ( -
-
{headline}
-
{description}
-
- ); - return ( - - {linkUrl && !loading ? ( - - {contents} - - ) : ( - contents - )} - - ); -}; - -InfoWidget.propTypes = { - title: PropTypes.string.isRequired, - headline: PropTypes.string, - description: PropTypes.string, - linkUrl: PropTypes.string, - loading: PropTypes.bool, -}; - -InfoWidget.defaultProps = { - description: null, - headline: null, - linkUrl: null, - loading: false, -}; - -export default connect()(InfoWidget); diff --git a/ui/apps/platform/src/Components/NotifierConfiguration/NotifierConfigurationView.tsx b/ui/apps/platform/src/Components/NotifierConfiguration/NotifierConfigurationView.tsx deleted file mode 100644 index 9459a9416d830..0000000000000 --- a/ui/apps/platform/src/Components/NotifierConfiguration/NotifierConfigurationView.tsx +++ /dev/null @@ -1,111 +0,0 @@ -import { useState } from 'react'; -import type { ReactElement } from 'react'; -import { Button, Flex, FlexItem, Title } from '@patternfly/react-core'; -import { Table, Tbody, Td, Th, Thead, Tr } from '@patternfly/react-table'; - -import { isDefaultEmailTemplate } from 'Components/EmailTemplate/EmailTemplate.utils'; -import EmailTemplateModal from 'Components/EmailTemplate/EmailTemplateModal'; -import type { TemplatePreviewArgs } from 'Components/EmailTemplate/EmailTemplateModal'; -import useIndexKey from 'hooks/useIndexKey'; -import type { NotifierConfiguration } from 'services/ReportsService.types'; - -export type NotifierConfigurationViewProps = { - headingLevel: 'h2' | 'h3'; - customBodyDefault: string; - customSubjectDefault: string; - notifierConfigurations: NotifierConfiguration[]; - renderTemplatePreview?: (args: TemplatePreviewArgs) => ReactElement; -}; - -function NotifierConfigurationView({ - headingLevel, - customBodyDefault, - customSubjectDefault, - notifierConfigurations, - renderTemplatePreview, -}: NotifierConfigurationViewProps): ReactElement { - const { keyFor } = useIndexKey(); - const [notifierConfigurationSelected, setNotifierConfigurationSelected] = - useState(null); - - return ( - <> - - - Delivery destinations - - - {notifierConfigurations.length === 0 ? ( - 'No delivery destinations' - ) : ( - - - - - - - - - - {notifierConfigurations.map((notifierConfiguration, index) => { - const { emailConfig, notifierName } = notifierConfiguration; - const { customBody, customSubject, mailingLists } = emailConfig; - const isDefaultEmailTemplateApplied = isDefaultEmailTemplate({ - customBody, - customSubject, - }); - return ( - - - - - - ); - })} - -
Email notifierDistribution listEmail template
{notifierName} - {mailingLists.join(', ')} - - -
- )} -
-
- {notifierConfigurationSelected && ( - { - setNotifierConfigurationSelected(null); - }} - renderTemplatePreview={renderTemplatePreview} - title={ - isDefaultEmailTemplate({ - customBody: notifierConfigurationSelected.emailConfig.customBody, - customSubject: notifierConfigurationSelected.emailConfig.customSubject, - }) - ? 'Default template applied' - : 'Custom template applied' - } - /> - )} - - ); -} - -export default NotifierConfigurationView; diff --git a/ui/apps/platform/src/Components/ReportJob/ReportJobStatus.test.tsx b/ui/apps/platform/src/Components/ReportJob/ReportJobStatus.test.tsx index 19f638afd45ae..575c38f7b72e1 100644 --- a/ui/apps/platform/src/Components/ReportJob/ReportJobStatus.test.tsx +++ b/ui/apps/platform/src/Components/ReportJob/ReportJobStatus.test.tsx @@ -71,7 +71,7 @@ describe('ReportJobStatus', () => { reportRequestType: 'ON_DEMAND', reportNotificationMethod: 'DOWNLOAD', completedAt: '', - errorMsg: 'This is an error message', + errorMsg: 'scan failed on Cluster "Prod-East"', }} isDownloadAvailable={false} areDownloadActionsDisabled={false} @@ -88,7 +88,7 @@ describe('ReportJobStatus', () => { // trigger the hover action fireEvent.mouseEnter(statusIconElement); - const tooltipElement = await screen.findByText('This is an error message'); + const tooltipElement = await screen.findByText('scan failed on Cluster "Prod-East"'); expect(tooltipElement).toBeInTheDocument(); diff --git a/ui/apps/platform/src/Components/ReportJob/ReportJobStatus.tsx b/ui/apps/platform/src/Components/ReportJob/ReportJobStatus.tsx index e9f204ef47638..67c8854ae405f 100644 --- a/ui/apps/platform/src/Components/ReportJob/ReportJobStatus.tsx +++ b/ui/apps/platform/src/Components/ReportJob/ReportJobStatus.tsx @@ -9,7 +9,6 @@ import { PendingIcon, } from '@patternfly/react-icons'; import { Button, Flex, FlexItem, Tooltip } from '@patternfly/react-core'; -import capitalize from 'lodash/capitalize'; import type { ReportStatus } from 'types/reportJob'; import PartialReportModal from './PartialReportModal'; @@ -47,9 +46,7 @@ function ReportJobStatus({ statusIconColorClass = 'pf-v6-u-icon-color-status-danger'; statusTextColorClass = 'pf-v6-u-text-color-status-danger'; statusIcon = ( - + ); diff --git a/ui/apps/platform/src/Components/Reports/View/DeliveryView.tsx b/ui/apps/platform/src/Components/Reports/View/DeliveryView.tsx index ea4548cf21741..3f88899f15278 100644 --- a/ui/apps/platform/src/Components/Reports/View/DeliveryView.tsx +++ b/ui/apps/platform/src/Components/Reports/View/DeliveryView.tsx @@ -1,20 +1,11 @@ import type { ReactElement } from 'react'; -import { - DescriptionList, - DescriptionListDescription, - DescriptionListGroup, - DescriptionListTerm, - Flex, - FlexItem, - Title, -} from '@patternfly/react-core'; +import { DescriptionList, Flex, FlexItem, Title } from '@patternfly/react-core'; import type { BreakpointModifiers } from '@patternfly/react-core'; -import { formatRecurringSchedule } from 'utils/dateUtils'; - import type { DeliveryType } from '../reports.types'; -import NotifierConfigurationDescriptionList from './NotifierConfigurationDescriptionList'; +import NotifierConfigurationsDescriptionListGroup from './NotifierConfigurationsDescriptionListGroup'; +import ScheduleDescriptionListGroup from './ScheduleDescriptionListGroup'; export type DeliveryViewProps = { headingLevel: 'h2' | 'h3'; @@ -27,7 +18,6 @@ function DeliveryView({ horizontalTermWidthModifier, values, }: DeliveryViewProps): ReactElement { - /* eslint-disable react/no-array-index-key */ return ( @@ -39,37 +29,12 @@ function DeliveryView({ isHorizontal horizontalTermWidthModifier={horizontalTermWidthModifier} > - - Destinations - - {values.notifiers.length === 0 ? ( - '-' - ) : ( - - {values.notifiers.map((notifier, index) => ( - - ))} - - )} - - - - Schedule - - {values.schedule ? formatRecurringSchedule(values.schedule) : '-'} - - + + ); - /* eslint-enable react/no-array-index-key */ } export default DeliveryView; diff --git a/ui/apps/platform/src/Components/Reports/View/DetailsDescriptionListGroups.tsx b/ui/apps/platform/src/Components/Reports/View/DetailsDescriptionListGroups.tsx new file mode 100644 index 0000000000000..0d7e409dc218e --- /dev/null +++ b/ui/apps/platform/src/Components/Reports/View/DetailsDescriptionListGroups.tsx @@ -0,0 +1,35 @@ +import type { ReactElement } from 'react'; +import { + DescriptionListDescription, + DescriptionListGroup, + DescriptionListTerm, +} from '@patternfly/react-core'; + +// Generic component for use cases: +// Parameters of compliance scan schedule configuration +// Details of vulnerability report configuration + +export type DetailsDescriptionListGroupsProps = { + description: string; + name: string; +}; + +function DetailsDescriptionListGroups({ + description, + name, +}: DetailsDescriptionListGroupsProps): ReactElement { + return ( + <> + + Name + {name || '-'} + + + Description + {description || '-'} + + + ); +} + +export default DetailsDescriptionListGroups; diff --git a/ui/apps/platform/src/Components/Reports/View/DetailsView.tsx b/ui/apps/platform/src/Components/Reports/View/DetailsView.tsx index 92d9f6b8e7b0a..5cde41afc9feb 100644 --- a/ui/apps/platform/src/Components/Reports/View/DetailsView.tsx +++ b/ui/apps/platform/src/Components/Reports/View/DetailsView.tsx @@ -1,17 +1,11 @@ import type { ReactElement } from 'react'; -import { - DescriptionList, - DescriptionListDescription, - DescriptionListGroup, - DescriptionListTerm, - Flex, - FlexItem, - Title, -} from '@patternfly/react-core'; +import { DescriptionList, Flex, FlexItem, Title } from '@patternfly/react-core'; import type { BreakpointModifiers } from '@patternfly/react-core'; import type { DetailsType } from '../reports.types'; +import DetailsDescriptionListGroups from './DetailsDescriptionListGroups'; + export type DetailsViewProps = { headingLevel: 'h2' | 'h3'; horizontalTermWidthModifier: BreakpointModifiers; @@ -34,18 +28,10 @@ function DetailsView({ isHorizontal horizontalTermWidthModifier={horizontalTermWidthModifier} > - - Name - - {values.name || '-'} - - - - Description - - {values.description || '-'} - - + diff --git a/ui/apps/platform/src/Components/Reports/View/NotifierConfigurationsDescriptionListGroup.tsx b/ui/apps/platform/src/Components/Reports/View/NotifierConfigurationsDescriptionListGroup.tsx new file mode 100644 index 0000000000000..978195737cbb9 --- /dev/null +++ b/ui/apps/platform/src/Components/Reports/View/NotifierConfigurationsDescriptionListGroup.tsx @@ -0,0 +1,47 @@ +import type { ReactElement } from 'react'; +import { + DescriptionListDescription, + DescriptionListGroup, + DescriptionListTerm, + Flex, +} from '@patternfly/react-core'; + +import type { NotifierConfiguration } from 'services/ReportsService.types'; + +import NotifierConfigurationDescriptionList from './NotifierConfigurationDescriptionList'; + +// Generic component for use cases: +// Delivery of compliance scan schedule configuration does not have schedules +// Delivery of vulnerability report configuration does have schedules + +export type NotifierConfigurationsDescriptionListGroupProps = { + notifiers: NotifierConfiguration[]; +}; + +function NotifierConfigurationsDescriptionListGroup({ + notifiers, +}: NotifierConfigurationsDescriptionListGroupProps): ReactElement { + /* eslint-disable react/no-array-index-key */ + return ( + + Destinations + + {notifiers.length === 0 ? ( + '-' + ) : ( + + {notifiers.map((notifier, index) => ( + + ))} + + )} + + + ); + /* eslint-enable react/no-array-index-key */ +} + +export default NotifierConfigurationsDescriptionListGroup; diff --git a/ui/apps/platform/src/Components/Reports/View/ScheduleDescriptionListGroup.tsx b/ui/apps/platform/src/Components/Reports/View/ScheduleDescriptionListGroup.tsx new file mode 100644 index 0000000000000..cc74e0ae9930d --- /dev/null +++ b/ui/apps/platform/src/Components/Reports/View/ScheduleDescriptionListGroup.tsx @@ -0,0 +1,32 @@ +import type { ReactElement } from 'react'; +import { + DescriptionListDescription, + DescriptionListGroup, + DescriptionListTerm, +} from '@patternfly/react-core'; + +import type { Schedule } from 'types/schedule.proto'; +import { formatRecurringSchedule } from 'utils/dateUtils'; + +// Generic component for use cases: +// Parameters of compliance scan schedule configuration +// Delivery of vulnerability report configuration + +export type ScheduleDescriptionListGroupProps = { + schedule: Schedule | null; +}; + +function ScheduleDescriptionListGroup({ + schedule, +}: ScheduleDescriptionListGroupProps): ReactElement { + return ( + + Schedule + + {schedule ? formatRecurringSchedule(schedule) : '-'} + + + ); +} + +export default ScheduleDescriptionListGroup; diff --git a/ui/apps/platform/src/Components/SearchInput/SearchInput.jsx b/ui/apps/platform/src/Components/SearchInput/SearchInput.jsx index fc8373d45b82d..99fc6726f6590 100644 --- a/ui/apps/platform/src/Components/SearchInput/SearchInput.jsx +++ b/ui/apps/platform/src/Components/SearchInput/SearchInput.jsx @@ -32,7 +32,6 @@ export const searchInputPropTypes = { sendAutoCompleteRequest: PropTypes.func, clearAutoComplete: PropTypes.func, autoCompleteCategories: PropTypes.arrayOf(PropTypes.string), - setAllSearchOptions: PropTypes.func, isDisabled: PropTypes.bool, prependAutocompleteQuery: PropTypes.arrayOf( PropTypes.shape({ @@ -53,7 +52,6 @@ export const searchInputDefaultProps = { sendAutoCompleteRequest: null, clearAutoComplete: null, autoCompleteCategories: [], - setAllSearchOptions: () => {}, isDisabled: false, prependAutocompleteQuery: [], }; @@ -108,8 +106,6 @@ class SearchInput extends Component { } sendAutoCompleteRequest = (searchOptions, input) => { - this.props.setAllSearchOptions(searchOptions); - // Don't populate autocomplete if the text box is totally empty, // since we want people to see just the chips in that case. if (!searchOptions.length && !input.length) { diff --git a/ui/apps/platform/src/Components/URLSearchInputWithAutocomplete.jsx b/ui/apps/platform/src/Components/URLSearchInputWithAutocomplete.jsx index 642611d65ef5f..575335cd00c91 100644 --- a/ui/apps/platform/src/Components/URLSearchInputWithAutocomplete.jsx +++ b/ui/apps/platform/src/Components/URLSearchInputWithAutocomplete.jsx @@ -3,10 +3,8 @@ import { useLocation, useNavigate } from 'react-router-dom-v5-compat'; import PropTypes from 'prop-types'; import { components } from 'react-select'; import queryString from 'qs'; -import { connect } from 'react-redux'; import { Filter } from 'react-feather'; -import { actions as searchAutoCompleteActions } from 'reducers/searchAutocomplete'; import { Creatable } from 'Components/ReactSelect'; import searchOptionsToQuery from 'services/searchOptionsToQuery'; import searchContext from 'Containers/searchContext'; @@ -99,7 +97,6 @@ export const removeValuesForKey = (oldOptions, newOptions) => { const URLSearchInputWithAutocomplete = ({ autoCompleteResults, categoryOptions, - setAllSearchOptions, clearAutocomplete, fetchAutocomplete, placeholder, @@ -235,7 +232,6 @@ const URLSearchInputWithAutocomplete = ({ function updateAutocompleteState(searchOptions) { return (input) => { - setAllSearchOptions(searchOptions); if (searchOptions.length === 0) { if (clearAutocomplete) { clearAutocomplete(); @@ -311,7 +307,6 @@ URLSearchInputWithAutocomplete.propTypes = { autoCompleteResults: PropTypes.arrayOf(PropTypes.string), fetchAutocomplete: PropTypes.func, clearAutocomplete: PropTypes.func, - setAllSearchOptions: PropTypes.func.isRequired, prependAutocompleteQuery: PropTypes.arrayOf( PropTypes.shape({ value: PropTypes.string, @@ -328,8 +323,4 @@ URLSearchInputWithAutocomplete.defaultProps = { prependAutocompleteQuery: [], }; -const mapDispatchToProps = { - setAllSearchOptions: searchAutoCompleteActions.setAllSearchOptions, -}; - -export default connect(null, mapDispatchToProps)(URLSearchInputWithAutocomplete); +export default URLSearchInputWithAutocomplete; diff --git a/ui/apps/platform/src/Components/visuals/ArcSingle.jsx b/ui/apps/platform/src/Components/visuals/ArcSingle.jsx deleted file mode 100644 index 52571ec45bcf9..0000000000000 --- a/ui/apps/platform/src/Components/visuals/ArcSingle.jsx +++ /dev/null @@ -1,58 +0,0 @@ -import { ArcSeries, LabelSeries, XYPlot } from 'react-vis'; -import PropTypes from 'prop-types'; - -const RADIUS = 3; -const VALUE_THICKNESS = 0.2; -const FULL_ANGLE = 2 * Math.PI; - -function getDataFromValue(value) { - return [ - { - angle0: 0, - angle: (FULL_ANGLE * value) / 100, - radius0: RADIUS - VALUE_THICKNESS, - radius: RADIUS, - color: 'var(--success-500)', - }, - { - angle0: (FULL_ANGLE * value) / 100, - angle: FULL_ANGLE, - radius0: RADIUS - VALUE_THICKNESS * 0.8, - radius: RADIUS - VALUE_THICKNESS * 0.2, - color: 'var(--base-400)', - }, - ]; -} -const LABEL_STYLE = { - fontSize: '36px', - fill: 'var(--primary-800)', - fontWeight: 500, -}; - -const ArcSingle = ({ value }) => { - const data = getDataFromValue(value); - - return ( - - - - - - ); -}; - -ArcSingle.propTypes = { - value: PropTypes.number.isRequired, -}; - -export default ArcSingle; diff --git a/ui/apps/platform/src/Containers/AccessControl/AuthProviders/AuthProviderForm.tsx b/ui/apps/platform/src/Containers/AccessControl/AuthProviders/AuthProviderForm.tsx index 58a1e051e6a98..620d4ca201152 100644 --- a/ui/apps/platform/src/Containers/AccessControl/AuthProviders/AuthProviderForm.tsx +++ b/ui/apps/platform/src/Containers/AccessControl/AuthProviders/AuthProviderForm.tsx @@ -94,8 +94,7 @@ function testModeSupported(provider) { provider.type === 'oidc' || provider.type === 'saml' || provider.type === 'openshift' || - provider.type === 'openshift-with-acm-roles' || - provider.type === 'oidc-with-acm-roles' + provider.type === 'openshift-with-acm-roles' ); } @@ -168,7 +167,7 @@ function AuthProviderForm({ // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore .when('type', { - is: (type) => type === 'oidc' || type === 'oidc-with-acm-roles', + is: (type) => type === 'oidc', then: (configSchema) => configSchema.shape({ client_id: yup.string().required('A client ID is required.'), @@ -533,8 +532,7 @@ function AuthProviderForm({

- {(selectedAuthProvider.type === 'oidc' || - selectedAuthProvider.type === 'oidc-with-acm-roles') && ( + {selectedAuthProvider.type === 'oidc' && ( )} - {(selectedAuthProvider.type === 'oidc' || - selectedAuthProvider.type === 'oidc-with-acm-roles') && ( + {selectedAuthProvider.type === 'oidc' && ( )} - {selectedAuthProvider.type !== 'openshift-with-acm-roles' && - selectedAuthProvider.type !== 'oidc-with-acm-roles' && ( - - - - )} - {(selectedAuthProvider.type === 'openshift-with-acm-roles' || - selectedAuthProvider.type === 'oidc-with-acm-roles') && ( + {selectedAuthProvider.type !== 'openshift-with-acm-roles' && ( + + + + )} + {selectedAuthProvider.type === 'openshift-with-acm-roles' && (
)} - {(type === 'oidc' || type === 'oidc-with-acm-roles') && ( + {type === 'oidc' && ( <> diff --git a/ui/apps/platform/src/Containers/AccessControl/AuthProviders/authProviders.utils.ts b/ui/apps/platform/src/Containers/AccessControl/AuthProviders/authProviders.utils.ts index bce738d2ff708..d0112a639b1f9 100644 --- a/ui/apps/platform/src/Containers/AccessControl/AuthProviders/authProviders.utils.ts +++ b/ui/apps/platform/src/Containers/AccessControl/AuthProviders/authProviders.utils.ts @@ -19,7 +19,7 @@ export function transformInitialValues( // TODO-ivan: eventually logic for different auth provider type should live // with the form component that renders form for the corresponding auth provider // type, probably makes sense to refactor after moving away from redux-form - if (initialValues.type === 'oidc' || initialValues.type === 'oidc-with-acm-roles') { + if (initialValues.type === 'oidc') { const alteredConfig = { ...initialValues.config }; // backend doesn't return the exact value for the client secret for the security reasons, @@ -73,7 +73,7 @@ function populateDefaultValues(authProvider: AuthProvider): AuthProvider { const newInitialValues: DisplayedAuthProvider = { ...authProvider }; newInitialValues.uiEndpoint = window.location.host; newInitialValues.enabled = true; - if (authProvider.type === 'oidc' || authProvider.type === 'oidc-with-acm-roles') { + if (authProvider.type === 'oidc') { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore newInitialValues.config = { @@ -128,7 +128,7 @@ export function transformValuesBeforeSaving( | Group[] | undefined > { - if (values.type === 'oidc' || values.type === 'oidc-with-acm-roles') { + if (values.type === 'oidc') { const alteredConfig = { ...(values.config as AuthProviderConfig) }; // if client secret is stored on the backend and user didn't enter any value, diff --git a/ui/apps/platform/src/Containers/BaseImages/BaseImagesModal.cy.jsx b/ui/apps/platform/src/Containers/BaseImages/BaseImagesModal.cy.jsx index 524b31099b97d..f8dfb7e4f543c 100644 --- a/ui/apps/platform/src/Containers/BaseImages/BaseImagesModal.cy.jsx +++ b/ui/apps/platform/src/Containers/BaseImages/BaseImagesModal.cy.jsx @@ -49,9 +49,59 @@ describe('BaseImagesModal', () => { cy.get('input#baseImagePath').type('ubuntu'); cy.get('input#baseImagePath').blur(); - cy.contains( - 'Base image path must include both repository and tag separated by ":"' - ).should('be.visible'); + cy.contains('Base image path must include a tag pattern after ":"').should( + 'be.visible' + ); + cy.contains('example-registry.io/path/to/image:tag').should('be.visible'); + cy.contains('For registries with a port, use registry:port/repo:tag').should( + 'be.visible' + ); + }); + + it('should show error when the pattern is placed on the path of a registry with a port', () => { + const onClose = cy.stub(); + const onSuccess = cy.stub(); + + cy.mount( + + + + ); + + // Registry port colon must not be mistaken for the tag separator. + cy.get('input#baseImagePath').type('registry:5000/repo*'); + cy.get('input#baseImagePath').blur(); + cy.contains('Base image path must include a tag pattern after ":"').should( + 'be.visible' + ); + }); + + it('should reject invalid tag pattern characters', () => { + cy.mount( + + + + ); + + cy.get('input#baseImagePath').type('registry:5000/repo:1.@bad'); + cy.get('input#baseImagePath').blur(); + cy.contains('Tag pattern must not contain "/", ":", "@", or whitespace').should( + 'be.visible' + ); + cy.findByRole('button', { name: 'Save' }).should('be.disabled'); + }); + + it('should reject tag patterns longer than 128 bytes', () => { + cy.mount( + + + + ); + + cy.get('input#baseImagePath').type(`ubuntu:${'a'.repeat(129)}`); + cy.get('input#baseImagePath').blur(); + cy.contains('Tag pattern must be at most 128 bytes').should('be.visible'); + cy.findByRole('button', { name: 'Save' }).should('be.disabled'); }); it('should enable save button when form is valid', () => { diff --git a/ui/apps/platform/src/Containers/BaseImages/BaseImagesModal.tsx b/ui/apps/platform/src/Containers/BaseImages/BaseImagesModal.tsx index b6c16d64d39e1..626eec8fa38f6 100644 --- a/ui/apps/platform/src/Containers/BaseImages/BaseImagesModal.tsx +++ b/ui/apps/platform/src/Containers/BaseImages/BaseImagesModal.tsx @@ -60,35 +60,63 @@ const addValidationSchema = yup.object({ baseImagePath: yup .string() .required('Base image path is required') - .test( - 'has-colon', - 'Base image path must include both repository and tag separated by ":"', - (value) => { - if (!value?.includes(':')) { - return false; - } - const lastColonIndex = value.lastIndexOf(':'); - const tagPattern = value.substring(lastColonIndex + 1); - return tagPattern.length > 0; + .test('has-tag', 'Base image path must include a tag pattern after ":"', (value) => { + if (!value) { + return false; + } + const { tagPattern } = parseBaseImagePath(value); + return tagPattern.length > 0; + }) + .test('valid-tag-pattern', function (value) { + if (!value) { + return true; } - ), + const { tagPattern } = parseBaseImagePath(value); + const error = tagPattern && getTagPatternError(tagPattern); + return error ? this.createError({ message: error }) : true; + }), }); const editValidationSchema = yup.object({ - baseImageTagPattern: yup.string().required('Tag pattern is required'), + baseImageTagPattern: yup + .string() + .required('Tag pattern is required') + .test('valid-tag-pattern', function (value) { + const error = value && getTagPatternError(value); + return error ? this.createError({ message: error }) : true; + }), }); type AddFormData = yup.InferType; type EditFormData = yup.InferType; +export function getTagPatternError(tagPattern: string): string | undefined { + if (new TextEncoder().encode(tagPattern).length > 128) { + return 'Tag pattern must be at most 128 bytes'; + } + if (/[/:@\p{White_Space}]/u.test(tagPattern)) { + return 'Tag pattern must not contain "/", ":", "@", or whitespace'; + } + return undefined; +} + /** * Parses a base image path into repository path and tag pattern. - * Format: "docker.io/library/ubuntu:22.04" -> { repoPath: "docker.io/library/ubuntu", tagPattern: "22.04" } + * Only a colon in the final path segment separates the tag; a colon before the last + * "/" belongs to a registry port. Returns an empty tagPattern when no tag is present. + * Examples: + * "docker.io/library/ubuntu:22.04" -> { repoPath: "docker.io/library/ubuntu", tagPattern: "22.04" } + * "registry:5000/library/ubuntu:1.*" -> { repoPath: "registry:5000/library/ubuntu", tagPattern: "1.*" } + * "registry:5000/library/ubuntu" -> { repoPath: "registry:5000/library/ubuntu", tagPattern: "" } */ export function parseBaseImagePath(path: string): { repoPath: string; tagPattern: string } { - const lastColonIndex = path.lastIndexOf(':'); - const repoPath = path.substring(0, lastColonIndex); - const tagPattern = path.substring(lastColonIndex + 1); + const lastSlashIndex = path.lastIndexOf('/'); + const tagColonIndex = path.indexOf(':', lastSlashIndex + 1); + if (tagColonIndex === -1) { + return { repoPath: path, tagPattern: '' }; + } + const repoPath = path.substring(0, tagColonIndex); + const tagPattern = path.substring(tagColonIndex + 1); return { repoPath, tagPattern }; } @@ -298,8 +326,9 @@ function BaseImagesModal({ )} Include repository path and tag (e.g., - example-registry.io/path/to/image:tag). Tag can be a - pattern (e.g., 1.*) + example-registry.io/path/to/image:tag). The tag can be a + pattern such as 1.*. For registries with a port, use + registry:port/repo:tag (e.g., registry:5000/repo:1.*). diff --git a/ui/apps/platform/src/Containers/BaseImages/parseBaseImagePath.test.ts b/ui/apps/platform/src/Containers/BaseImages/parseBaseImagePath.test.ts index fa9243515bb4b..19845e80c91c9 100644 --- a/ui/apps/platform/src/Containers/BaseImages/parseBaseImagePath.test.ts +++ b/ui/apps/platform/src/Containers/BaseImages/parseBaseImagePath.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from 'vitest'; -import { parseBaseImagePath } from './BaseImagesModal'; +import { getTagPatternError, parseBaseImagePath } from './BaseImagesModal'; describe('parseBaseImagePath', () => { it('should parse simple image path with single colon', () => { @@ -29,4 +29,49 @@ describe('parseBaseImagePath', () => { tagPattern: '1.*', }); }); + + it('should keep the tag pattern separate for a registry with a port', () => { + const result = parseBaseImagePath('registry:5000/library/ubuntu:1.*'); + + expect(result).toEqual({ + repoPath: 'registry:5000/library/ubuntu', + tagPattern: '1.*', + }); + }); + + it('should return an empty tag when a registry with a port has no tag', () => { + const result = parseBaseImagePath('registry:5000/library/ubuntu'); + + expect(result).toEqual({ + repoPath: 'registry:5000/library/ubuntu', + tagPattern: '', + }); + }); + + it('should return an empty tag when the pattern is placed on the path instead of the tag', () => { + const result = parseBaseImagePath('registry:5000/library/ubuntu*'); + + expect(result).toEqual({ + repoPath: 'registry:5000/library/ubuntu*', + tagPattern: '', + }); + }); +}); + +describe('getTagPatternError', () => { + it('accepts a tag pattern at the length limit', () => { + expect(getTagPatternError('a'.repeat(128))).toBeUndefined(); + }); + + it('rejects tag patterns longer than 128 bytes', () => { + expect(getTagPatternError('a'.repeat(129))).toBe('Tag pattern must be at most 128 bytes'); + }); + + it('rejects repository separators and whitespace', () => { + ['repo/tag', 'port:tag', 'sha256@digest', '1. *', '1.\u00a0*'].forEach((pattern) => { + expect(getTagPatternError(pattern)).toBe( + 'Tag pattern must not contain "/", ":", "@", or whitespace' + ); + }); + }); }); diff --git a/ui/apps/platform/src/Containers/Clusters/ClusterRegistrationSecrets/SecureClusterModal.tsx b/ui/apps/platform/src/Containers/Clusters/ClusterRegistrationSecrets/SecureClusterModal.tsx index 8cde6f59163ed..8617becaec418 100644 --- a/ui/apps/platform/src/Containers/Clusters/ClusterRegistrationSecrets/SecureClusterModal.tsx +++ b/ui/apps/platform/src/Containers/Clusters/ClusterRegistrationSecrets/SecureClusterModal.tsx @@ -1,44 +1,21 @@ -import { useState } from 'react'; import type { ReactElement } from 'react'; -import { - Alert, - Button, - Divider, - Flex, - FlexItem, - Tab, - TabContent, - TabTitleText, - Tabs, -} from '@patternfly/react-core'; +import { Alert, Button, Flex } from '@patternfly/react-core'; import { Modal } from '@patternfly/react-core/deprecated'; -import SecureClusterUsingHelmChart from './SecureClusterUsingHelmChart'; import SecureClusterUsingOperator from './SecureClusterUsingOperator'; -type TabKey = 'Operator' | 'Helm'; - const headingLevel = 'h2'; -const idHelm = 'SecureClusterUsingHelm'; -const idOperator = 'SecureClusterUsingOperator'; - export type SecureClusterModalProps = { isModalOpen: boolean; setIsModalOpen: (isOpen: boolean) => void; }; function SecureClusterModal({ isModalOpen, setIsModalOpen }): ReactElement { - const [activeKey, setActiveKey] = useState('Operator'); - function onClose() { setIsModalOpen(false); } - function onSelect(_event, tabKey) { - setActiveKey(tabKey); - } - return ( - - - Operator} - /> - Helm chart (deprecated)} - /> - - - - {activeKey === 'Operator' && ( - - - - )} - {activeKey === 'Helm' && ( - - - - )} + @@ -42,28 +26,8 @@ function SecureClusterPage(): ReactElement { Secure a cluster with a cluster registration secret - - setActiveTabKey(tabKey)} - usePageInsets - mountOnEnter - unmountOnExit - > - {operatorTab}}> - - - - - Helm chart (deprecated)} - > - - - - - + + \\', - '--set clusterName= \\', - '--set centralEndpoint= \\', - '--set imagePullSecrets.username= \\', - '--set imagePullSecrets.password=', -].join('\n'); - -export type SecureClusterUsingHelmChartProps = { - headingLevel: 'h2' | 'h3'; -}; - -function SecureClusterUsingHelmChart({ - headingLevel, -}: SecureClusterUsingHelmChartProps): ReactElement { - const subHeadingLevel = headingLevel === 'h2' ? 'h3' : 'h4'; - const { wasCopied, copyToClipboard } = useClipboardCopy(); - - const actions = ( - - copyToClipboard(codeBlock)} - variant="plain" - > - {wasCopied ? 'Copied to clipboard' : 'Copy to clipboard'} - - - ); - - return ( - - - - The rhacs/secured-cluster-services Helm chart is - deprecated since version 4.11 and will be removed in 5.1. - - } - /> - - Prerequisites - - -

- You must have previously added the Helm chart repository, or add it using - the following command: -

- - helm repo add rhacs https://mirror.openshift.com/pub/rhacs/charts/ - -
- -

You must download the YAML file for a cluster registration secret.

-
- -

- You must have access to the Red Hat Container Registry and a pull secret for - authentication. -

-
- -

- You must have the address and the port number that you are exposing the - Central service on. -

-
- - -

Run a command similar to the following:

- - {codeBlock} - -
-
-
-
- ); -} - -export default SecureClusterUsingHelmChart; diff --git a/ui/apps/platform/src/Containers/Collections/CollectionsTablePage.tsx b/ui/apps/platform/src/Containers/Collections/CollectionsTablePage.tsx index ebc8a4e53437d..2bb533d8852f5 100644 --- a/ui/apps/platform/src/Containers/Collections/CollectionsTablePage.tsx +++ b/ui/apps/platform/src/Containers/Collections/CollectionsTablePage.tsx @@ -81,6 +81,16 @@ function CollectionsTablePage({ hasWriteAccessForCollections }: CollectionsTable return ( <> + + Collection scope is deprecated for scheduled image vulnerability reports. To prepare + for future updates, we recommend updating each scheduled report in Vulnerability + reporting to use Custom scope. + diff --git a/ui/apps/platform/src/Containers/Collections/errorUtils.test.ts b/ui/apps/platform/src/Containers/Collections/errorUtils.test.ts new file mode 100644 index 0000000000000..ad1a9737cf215 --- /dev/null +++ b/ui/apps/platform/src/Containers/Collections/errorUtils.test.ts @@ -0,0 +1,32 @@ +import { parseConfigError } from './errorUtils'; + +describe('parseConfigError', () => { + it('classifies a collection loop and extracts the loopId from a lower-case-leading message', () => { + const err = new Error( + "edge between 'aaaaaaaa-1111' and 'bbbbbbbb-2222' would create a loop" + ); + + const result = parseConfigError(err); + + expect(result.type).toBe('CollectionLoop'); + expect(result).toHaveProperty('loopId', 'bbbbbbbb-2222'); + }); + + it('classifies an invalid rule and preserves the backend message in details', () => { + const err = new Error('failed to compile regex "["'); + + const result = parseConfigError(err); + + expect(result.type).toBe('InvalidRule'); + expect(result.details).toBe('failed to compile regex "["'); + }); + + it('falls back to UnknownError for an unrecognized message', () => { + const err = new Error('something entirely unexpected happened'); + + const result = parseConfigError(err); + + expect(result.type).toBe('UnknownError'); + expect(result.details).toBe('something entirely unexpected happened'); + }); +}); diff --git a/ui/apps/platform/src/Containers/Compliance/ComplianceSearchInput.jsx b/ui/apps/platform/src/Containers/Compliance/ComplianceSearchInput.jsx deleted file mode 100644 index 259c6fb7f0ede..0000000000000 --- a/ui/apps/platform/src/Containers/Compliance/ComplianceSearchInput.jsx +++ /dev/null @@ -1,51 +0,0 @@ -import PropTypes from 'prop-types'; -import { CLIENT_SIDE_SEARCH_OPTIONS as SEARCH_OPTIONS } from 'constants/searchOptions'; - -import Query from 'Components/CacheFirstQuery'; -import URLSearchInput from 'Components/URLSearchInput'; - -import { SEARCH_OPTIONS_QUERY } from 'queries/search'; - -const addComplianceStateOption = (searchOptions) => { - let modifiedSearchOptions = []; - if (searchOptions) { - modifiedSearchOptions = [...searchOptions]; - modifiedSearchOptions.push(SEARCH_OPTIONS.COMPLIANCE.STATE); - } - return modifiedSearchOptions; -}; - -const ComplianceSearchInput = ({ placeholder, categories, shouldAddComplianceState }) => ( - - {({ data }) => { - if (!data) { - return null; - } - let { searchOptions } = data; - if (shouldAddComplianceState) { - searchOptions = addComplianceStateOption(searchOptions); - } - return ( - - ); - }} - -); - -ComplianceSearchInput.propTypes = { - placeholder: PropTypes.string.isRequired, - categories: PropTypes.arrayOf(PropTypes.string), - shouldAddComplianceState: PropTypes.bool, -}; - -ComplianceSearchInput.defaultProps = { - categories: [], - shouldAddComplianceState: false, -}; - -export default ComplianceSearchInput; diff --git a/ui/apps/platform/src/Containers/Compliance/Dashboard/ComplianceDashboardPage.tsx b/ui/apps/platform/src/Containers/Compliance/Dashboard/ComplianceDashboardPage.tsx deleted file mode 100644 index 7fa1e8d75fcc6..0000000000000 --- a/ui/apps/platform/src/Containers/Compliance/Dashboard/ComplianceDashboardPage.tsx +++ /dev/null @@ -1,240 +0,0 @@ -import { useState } from 'react'; -import type { ReactElement } from 'react'; -import { useApolloClient } from '@apollo/client'; -import { Alert } from '@patternfly/react-core'; - -import Button from 'Components/Button'; -import ComplianceUsageDisclaimer, { - COMPLIANCE_DISCLAIMER_KEY, -} from 'Components/ComplianceUsageDisclaimer'; -import ExportButton from 'Components/ExportButton'; -import PageHeader from 'Components/PageHeader'; -import { resourceTypes } from 'constants/entityTypes'; -import useCaseTypes from 'constants/useCaseTypes'; -import { useBooleanLocalStorage } from 'hooks/useLocalStorage'; -import usePermissions from 'hooks/usePermissions'; -import { fetchComplianceStandardsSortedByName } from 'services/ComplianceService'; -import type { ComplianceStandardMetadata } from 'services/ComplianceService'; -import { getAxiosErrorMessage } from 'utils/responseErrorUtils'; - -import { - AGGREGATED_RESULTS_ACROSS_ENTITY, - AGGREGATED_RESULTS_STANDARDS_BY_ENTITY, -} from 'queries/controls'; -import ScanButton from '../ScanButton'; -import StandardsByEntity from '../widgets/StandardsByEntity'; -import StandardsAcrossEntity from '../widgets/StandardsAcrossEntity'; - -import ManageStandardsError from './ManageStandardsError'; -import ManageStandardsModal from './ManageStandardsModal'; -import ComplianceDashboardTile, { - CLUSTERS_COUNT, - DEPLOYMENTS_COUNT, - NAMESPACES_COUNT, - NODES_COUNT, -} from './ComplianceDashboardTile'; -import ComplianceScanProgress from './ComplianceScanProgress'; -import { useComplianceRunStatuses } from './useComplianceRunStatuses'; -import { isComplianceRouteEnabled } from '../complianceRBAC'; - -const queriesToRefetchOnPollingComplete = [ - CLUSTERS_COUNT, - NODES_COUNT, - NAMESPACES_COUNT, - DEPLOYMENTS_COUNT, - AGGREGATED_RESULTS_STANDARDS_BY_ENTITY(resourceTypes.CLUSTER), - AGGREGATED_RESULTS_ACROSS_ENTITY(resourceTypes.CLUSTER), - AGGREGATED_RESULTS_ACROSS_ENTITY(resourceTypes.NAMESPACE), - AGGREGATED_RESULTS_ACROSS_ENTITY(resourceTypes.NODE), -]; - -function ComplianceDashboardPage(): ReactElement { - const [isDisclaimerAccepted, setIsDisclaimerAccepted] = useBooleanLocalStorage( - COMPLIANCE_DISCLAIMER_KEY, - false - ); - const { hasReadAccess, hasReadWriteAccess } = usePermissions(); - - // Counts and widgets (with one exception) have same conditional rendering as routes. - // Do not require for StandardsAcrossEntity cluster, so page has at least one widget. - // Do require for StandardsByEntity cluster, because it has links to clusters. - const isComplianceRouteEnabledForClusters = isComplianceRouteEnabled( - hasReadAccess, - 'compliance/clusters' - ); - const isComplianceRouteEnabledForDeployments = isComplianceRouteEnabled( - hasReadAccess, - 'compliance/deployments' - ); - const isComplianceRouteEnabledForNamespaces = isComplianceRouteEnabled( - hasReadAccess, - 'compliance/namespaces' - ); - const isComplianceRouteEnabledForNodes = isComplianceRouteEnabled( - hasReadAccess, - 'compliance/nodes' - ); - - const hasWriteAccessForCompliance = hasReadWriteAccess('Compliance'); - - const [isFetchingStandards, setIsFetchingStandards] = useState(false); - const [errorMessageFetching, setErrorMessageFetching] = useState(''); - const [standards, setStandards] = useState([]); - const [isManageStandardsModalOpen, setIsManageStandardsModalOpen] = useState(false); - - const client = useApolloClient(); - - const { runs, error, restartPolling, inProgressScanDetected, isCurrentScanIncomplete } = - useComplianceRunStatuses(queriesToRefetchOnPollingComplete); - - function clickManageStandardsButton() { - setIsFetchingStandards(true); - fetchComplianceStandardsSortedByName() - .then((standardsFetched) => { - setErrorMessageFetching(''); - setStandards(standardsFetched); - setIsManageStandardsModalOpen(true); - }) - .catch((error) => { - setErrorMessageFetching(getAxiosErrorMessage(error)); - setStandards([]); - }) - .finally(() => { - setIsFetchingStandards(false); - }); - } - - function onCloseManageStandardsError() { - setErrorMessageFetching(''); - } - - function onChangeManageStandardsModal() { - setIsManageStandardsModalOpen(false); - - /* - * Same method as for Scan button to clear store of any cached query data, - * so backend filters out standards in query data according to saved update - * to hideScanResults properties. - */ - return client.resetStore(); - } - - function onCancelManageStandardsModal() { - setIsManageStandardsModalOpen(false); - } - - return ( - <> - -
-
- {isComplianceRouteEnabledForClusters && ( - - )} - {isComplianceRouteEnabledForNamespaces && ( - - )} - {isComplianceRouteEnabledForNodes && ( - - )} - {isComplianceRouteEnabledForDeployments && ( - - )} - {hasWriteAccessForCompliance && ( - - )} - {hasWriteAccessForCompliance && ( -
-
- )} - -
-
-
-
- {!isDisclaimerAccepted && ( - setIsDisclaimerAccepted(true)} - className="pf-v6-u-mb-lg" - /> - )} - {(inProgressScanDetected || !!error) && ( -
- {error ? ( - - {getAxiosErrorMessage(error)} - - ) : ( - - )} -
- )} -
- - {isComplianceRouteEnabledForClusters && ( - - )} - {isComplianceRouteEnabledForNamespaces && ( - - )} - {isComplianceRouteEnabledForNodes && ( - - )} -
-
- {errorMessageFetching ? ( - - ) : isManageStandardsModalOpen ? ( - - ) : null} - - ); -} - -export default ComplianceDashboardPage; diff --git a/ui/apps/platform/src/Containers/Compliance/Dashboard/ComplianceDashboardTile.tsx b/ui/apps/platform/src/Containers/Compliance/Dashboard/ComplianceDashboardTile.tsx deleted file mode 100644 index c112b4ab707f0..0000000000000 --- a/ui/apps/platform/src/Containers/Compliance/Dashboard/ComplianceDashboardTile.tsx +++ /dev/null @@ -1,85 +0,0 @@ -import { Link } from 'react-router-dom-v5-compat'; -import { gql, useQuery } from '@apollo/client'; -import type { DocumentNode } from '@apollo/client'; - -import { complianceBasePath } from 'routePaths'; - -import { - entityCountNounOrdinaryCase, - entityNounOrdinaryCasePlural, -} from '../entitiesForCompliance'; - -export const CLUSTERS_COUNT = gql` - query clustersCount { - results: complianceClusterCount - } -`; - -export const NODES_COUNT = gql` - query nodesCount { - results: complianceNodeCount - } -`; - -export const NAMESPACES_COUNT = gql` - query namespacesCount { - results: complianceNamespaceCount - } -`; - -export const DEPLOYMENTS_COUNT = gql` - query deploymentsCount { - results: complianceDeploymentCount - } -`; - -// Subset of ComplianceEntityType -type DashboardTileEntityType = 'CLUSTER' | 'DEPLOYMENT' | 'NAMESPACE' | 'NODE'; - -const queryMap: Record = { - CLUSTER: CLUSTERS_COUNT, - DEPLOYMENT: DEPLOYMENTS_COUNT, - NAMESPACE: NAMESPACES_COUNT, - NODE: NODES_COUNT, -}; - -const entityPathSegmentMap: Record = { - CLUSTER: 'clusters', - DEPLOYMENT: 'deployments', - NAMESPACE: 'namespaces', - NODE: 'nodes', -}; - -export type ComplianceDashboardTileProps = { - entityType: DashboardTileEntityType; -}; - -function ComplianceDashboardTile({ entityType }: ComplianceDashboardTileProps) { - const QUERY = queryMap[entityType]; - const url = `${complianceBasePath}/${entityPathSegmentMap[entityType]}`; - - const { loading, data, error } = useQuery(QUERY); - - if (loading || error || !data) { - return ( -
-
-
{entityNounOrdinaryCasePlural[entityType]}
-
{error ? '(not scanned)' : 'scanned'}
-
-
- ); - } - - const count: number = typeof data?.results === 'number' ? data.results : 0; - return ( - -
-
{entityCountNounOrdinaryCase(count, entityType)}
-
(scanned)
-
- - ); -} - -export default ComplianceDashboardTile; diff --git a/ui/apps/platform/src/Containers/Compliance/Dashboard/ComplianceScanProgress.tsx b/ui/apps/platform/src/Containers/Compliance/Dashboard/ComplianceScanProgress.tsx deleted file mode 100644 index 5847135dc0929..0000000000000 --- a/ui/apps/platform/src/Containers/Compliance/Dashboard/ComplianceScanProgress.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import { Card, CardBody, CardTitle, Progress } from '@patternfly/react-core'; -import type { CardProps } from '@patternfly/react-core'; - -import type { ComplianceRunStatusResponse } from './useComplianceRunStatuses'; - -export type ComplianceScanProgressProps = { - runs: ComplianceRunStatusResponse['complianceRunStatuses']['runs']; -} & CardProps; - -function ComplianceScanProgress({ runs, ...props }: ComplianceScanProgressProps) { - const unfinishedRunCount = runs.filter((run) => run.state !== 'FINISHED').length; - const finishedRunCount = runs.length - unfinishedRunCount; - - const title = - unfinishedRunCount === 0 - ? 'Compliance scanning complete' - : 'Compliance scanning in progress'; - - return ( - - {title} - - - - - ); -} - -export default ComplianceScanProgress; diff --git a/ui/apps/platform/src/Containers/Compliance/Dashboard/ManageStandardsError.tsx b/ui/apps/platform/src/Containers/Compliance/Dashboard/ManageStandardsError.tsx deleted file mode 100644 index 305eb50003f9a..0000000000000 --- a/ui/apps/platform/src/Containers/Compliance/Dashboard/ManageStandardsError.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import type { ReactElement } from 'react'; -import { Alert } from '@patternfly/react-core'; -import { Modal } from '@patternfly/react-core/deprecated'; - -export type ManageStandardsErrorProps = { - onClose: () => void; - errorMessage: string; -}; - -function ManageStandardsError({ onClose, errorMessage }: ManageStandardsErrorProps): ReactElement { - return ( - - - {errorMessage} - - - ); -} - -export default ManageStandardsError; diff --git a/ui/apps/platform/src/Containers/Compliance/Dashboard/ManageStandardsModal.tsx b/ui/apps/platform/src/Containers/Compliance/Dashboard/ManageStandardsModal.tsx deleted file mode 100644 index 789620a0ea71b..0000000000000 --- a/ui/apps/platform/src/Containers/Compliance/Dashboard/ManageStandardsModal.tsx +++ /dev/null @@ -1,144 +0,0 @@ -import { useState } from 'react'; -import type { ReactElement } from 'react'; -import { Alert, Button, Checkbox, Form } from '@patternfly/react-core'; -import { Modal } from '@patternfly/react-core/deprecated'; -import { useFormik } from 'formik'; - -import { patchComplianceStandard } from 'services/ComplianceService'; -import type { ComplianceStandardMetadata } from 'services/ComplianceService'; -import { getAxiosErrorMessage } from 'utils/responseErrorUtils'; - -export type ManageStandardsModalProps = { - onCancel: () => void; - onChange: () => void; - standards: ComplianceStandardMetadata[]; -}; - -/* - * Formik values have standard id as key and showScanResults as value. - * Therefore, negate hideScanResults value here and - * showComplianceScanMap[id] value in onSubmit function below. - */ -function getShowScanResultsMap(standards: ComplianceStandardMetadata[]): Record { - return Object.fromEntries(standards.map(({ id, hideScanResults }) => [id, !hideScanResults])); -} - -function ManageStandardsModal({ - onCancel, - onChange, - standards, -}: ManageStandardsModalProps): ReactElement { - const [errorMessage, setErrorMessage] = useState(''); - const [countFulfilledWhenRejected, setCountFulfilledWhenRejected] = useState(0); - const { dirty, handleSubmit, isSubmitting, setFieldValue, setSubmitting, values } = useFormik< - Record - >({ - initialValues: getShowScanResultsMap(standards), - onSubmit: (showScanResultsMap) => { - setErrorMessage(''); - // Filter standards for which hideScanResults property has changed, - // and them map to promises for patch requests. - // Negate hideScanResults is correct even if property is absent. - const patchRequestPromises = standards - .filter(({ hideScanResults, id }) => !hideScanResults !== showScanResultsMap[id]) - .map(({ id }) => patchComplianceStandard(id, !showScanResultsMap[id])); - - Promise.allSettled(patchRequestPromises) - .then((results) => { - let numberOfRejectedPromises = 0; - let reasonMessage = ''; - results.forEach((result) => { - if (result.status === 'rejected') { - if (numberOfRejectedPromises === 0) { - reasonMessage = getAxiosErrorMessage(result.reason); - } - numberOfRejectedPromises += 1; - } - }); - setSubmitting(false); - - if (numberOfRejectedPromises === 0) { - onChange(); - } else { - setErrorMessage(reasonMessage); - setCountFulfilledWhenRejected(results.length - numberOfRejectedPromises); - } - }) - .catch((error) => { - setErrorMessage(getAxiosErrorMessage(error)); - setSubmitting(false); - }); - }, - }); - - return ( - { - handleSubmit(); - }} - isDisabled={!dirty || isSubmitting} - isLoading={isSubmitting} - > - Save - , - countFulfilledWhenRejected === 0 ? ( - - ) : ( - - ), - ]} - > -
- {standards.map(({ id, name }) => { - return ( - { - return setFieldValue(id, value); - }} - /> - ); - })} - - {errorMessage && ( - - {errorMessage} - - )} -
- ); -} - -export default ManageStandardsModal; diff --git a/ui/apps/platform/src/Containers/Compliance/Dashboard/useComplianceRunStatuses.ts b/ui/apps/platform/src/Containers/Compliance/Dashboard/useComplianceRunStatuses.ts deleted file mode 100644 index 9957b4538d728..0000000000000 --- a/ui/apps/platform/src/Containers/Compliance/Dashboard/useComplianceRunStatuses.ts +++ /dev/null @@ -1,90 +0,0 @@ -import { useState } from 'react'; -import { gql, useApolloClient, useQuery } from '@apollo/client'; -import type { DocumentNode } from '@apollo/client'; - -export type ComplianceRunStatusResponse = { - complianceRunStatuses: { - runs: { state: string }[]; - }; -}; - -function isCurrentScanIncomplete( - runs: ComplianceRunStatusResponse['complianceRunStatuses']['runs'] -) { - return runs.some((run) => run.state !== 'FINISHED'); -} - -const complianceRunStatusesQuery = gql` - query runStatuses($latest: Boolean) { - complianceRunStatuses(latest: $latest) { - runs { - state - } - } - } -`; - -const pollInterval = 10000; -const variables = { - latest: true, -}; - -export type UseComplianceRunStatusesResponse = { - /* The latest compliance scan runs */ - runs: ComplianceRunStatusResponse['complianceRunStatuses']['runs']; - error: unknown; - /* Fetches the latest compliance scan runs, and restarts polling, if necessary */ - restartPolling: () => void; - /* Whether or not an in progress scan was detected during the lifetime of this hook */ - inProgressScanDetected: boolean; - /* Whether or not the latest scan is incomplete */ - isCurrentScanIncomplete: boolean; -}; - -export function useComplianceRunStatuses( - queriesToRefetchOnPollingComplete: DocumentNode[] -): UseComplianceRunStatusesResponse { - const [inProgressScanDetected, setInProgressScanDetected] = useState(false); - - const client = useApolloClient(); - - const { startPolling, stopPolling, error, data, refetch } = useQuery< - ComplianceRunStatusResponse, - typeof variables - >(complianceRunStatusesQuery, { - variables, - pollInterval, - onCompleted, - onError, - errorPolicy: 'all', - notifyOnNetworkStatusChange: true, - }); - - function onCompleted(data: ComplianceRunStatusResponse) { - if (isCurrentScanIncomplete(data.complianceRunStatuses.runs)) { - setInProgressScanDetected(true); - } else { - stopPolling(); - } - - return client.refetchQueries({ include: queriesToRefetchOnPollingComplete }); - } - - function onError() { - stopPolling(); - } - - return { - error, - runs: data?.complianceRunStatuses.runs ?? [], - restartPolling: () => - refetch().then(({ data }) => { - if (isCurrentScanIncomplete(data.complianceRunStatuses.runs)) { - setInProgressScanDetected(true); - startPolling(pollInterval); - } - }), - inProgressScanDetected, - isCurrentScanIncomplete: isCurrentScanIncomplete(data?.complianceRunStatuses.runs ?? []), - }; -} diff --git a/ui/apps/platform/src/Containers/Compliance/Entity/Cluster.jsx b/ui/apps/platform/src/Containers/Compliance/Entity/Cluster.jsx deleted file mode 100644 index 00386c8b4cac7..0000000000000 --- a/ui/apps/platform/src/Containers/Compliance/Entity/Cluster.jsx +++ /dev/null @@ -1,215 +0,0 @@ -import { useContext } from 'react'; - -import entityTypes from 'constants/entityTypes'; -import EntityCompliance from 'Containers/Compliance/widgets/EntityCompliance'; -import ResourceCount from 'Containers/Compliance/widgets/ResourceCount'; -import ClusterVersion from 'Containers/Compliance/widgets/ClusterVersion'; -import Query from 'Components/CacheFirstQuery'; -import usePermissions from 'hooks/usePermissions'; -import { CLUSTER_NAME as QUERY } from 'queries/cluster'; -import ComplianceList from 'Containers/Compliance/List/List'; -import ComplianceByStandards from 'Containers/Compliance/widgets/ComplianceByStandards'; -import Loader from 'Components/Loader'; -import { entityPagePropTypes, entityPageDefaultProps } from 'constants/entityPageProps'; -import searchContext from 'Containers/searchContext'; -import isGQLLoading from 'utils/gqlLoading'; - -import Header from './Header'; -import ResourceTabs from './ResourceTabs'; -import { isComplianceRouteEnabled } from '../complianceRBAC'; - -function getResourceTabs({ - isComplianceRouteEnabledForDeployments, - isComplianceRouteEnabledForNamespaces, - isComplianceRouteEnabledForNodes, -}) { - const resourceTabs = [entityTypes.CONTROL]; - if (isComplianceRouteEnabledForNamespaces) { - resourceTabs.push(entityTypes.NAMESPACE); - } - if (isComplianceRouteEnabledForNodes) { - resourceTabs.push(entityTypes.NODE); - } - if (isComplianceRouteEnabledForDeployments) { - resourceTabs.push(entityTypes.DEPLOYMENT); - } - return resourceTabs; -} - -function processData(data) { - if (!data || !data.cluster) { - return {}; - } - return data.cluster; -} - -const ClusterPage = ({ - entityId, - listEntityType1, - entityId1, - entityType2, - entityListType2, - entityId2, - query, - sidePanelMode, -}) => { - const searchParam = useContext(searchContext); - - const { hasReadAccess } = usePermissions(); - const isComplianceRouteEnabledForDeployments = isComplianceRouteEnabled( - hasReadAccess, - 'compliance/deployments' - ); - const isComplianceRouteEnabledForNamespaces = isComplianceRouteEnabled( - hasReadAccess, - 'compliance/namespaces' - ); - const isComplianceRouteEnabledForNodes = isComplianceRouteEnabled( - hasReadAccess, - 'compliance/nodes' - ); - const isComplianceRouteEnabledForEntities = - isComplianceRouteEnabledForDeployments || - isComplianceRouteEnabledForNamespaces || - isComplianceRouteEnabledForNodes; - - const resourceTabs = getResourceTabs({ - isComplianceRouteEnabledForDeployments, - isComplianceRouteEnabledForNamespaces, - isComplianceRouteEnabledForNodes, - }); - - return ( - - {({ loading, data }) => { - if (isGQLLoading(loading, data)) { - return ; - } - const cluster = processData(data); - const { name, id } = cluster; - let contents; - - if (listEntityType1 && !sidePanelMode) { - const listQuery = { - groupBy: - listEntityType1 === entityTypes.CONTROL ? entityTypes.STANDARD : '', - 'Cluster Id': entityId, - ...query[searchParam], - }; - contents = ( -
- -
- ); - } else { - contents = ( -
-
-
-
- -
-
- -
-
- - - {sidePanelMode && isComplianceRouteEnabledForEntities && ( -
- {isComplianceRouteEnabledForNamespaces && ( -
- -
- )} - {isComplianceRouteEnabledForNodes && ( -
- -
- )} - {isComplianceRouteEnabledForDeployments && ( -
- -
- )} -
- )} -
-
- ); - } - - return ( -
- {!sidePanelMode && ( - <> -
- - - )} - {contents} -
- ); - }} -
- ); -}; - -ClusterPage.propTypes = entityPagePropTypes; -ClusterPage.defaultProps = entityPageDefaultProps; - -export default ClusterPage; diff --git a/ui/apps/platform/src/Containers/Compliance/Entity/Control.jsx b/ui/apps/platform/src/Containers/Compliance/Entity/Control.jsx deleted file mode 100644 index a1e8119ba59e0..0000000000000 --- a/ui/apps/platform/src/Containers/Compliance/Entity/Control.jsx +++ /dev/null @@ -1,166 +0,0 @@ -import { useContext } from 'react'; - -import entityTypes from 'constants/entityTypes'; -import Widget from 'Components/Widget'; -import Query from 'Components/CacheFirstQuery'; -import { CONTROL_QUERY as QUERY } from 'queries/controls'; -import ControlDetails from 'Components/ControlDetails'; -import ControlRelatedResourceList from 'Containers/Compliance/widgets/ControlRelatedResourceList'; -import { entityPagePropTypes, entityPageDefaultProps } from 'constants/entityPageProps'; -import useCases from 'constants/useCaseTypes'; -import ComplianceList from 'Containers/Compliance/List/List'; -import Loader from 'Components/Loader'; -import PageNotFound from 'Components/PageNotFound'; -import searchContext from 'Containers/searchContext'; -import isGQLLoading from 'utils/gqlLoading'; - -import Header from './Header'; -import ResourceTabs from './ResourceTabs'; - -const ControlPage = ({ - entityId, - listEntityType1, - entityId1, - entityType2, - entityListType2, - entityId2, - query, - sidePanelMode, -}) => { - const searchParam = useContext(searchContext); - - return ( - - {({ data, loading }) => { - if (isGQLLoading(loading, data)) { - return ; - } - - if (!data || !data.results) { - return ( - - ); - } - - const { results: control, complianceStandards: standards } = data; - const standard = standards.find((item) => item.id === control.standardId); - const { name, standardId, interpretationText, description } = control; - const standardName = standard ? standard.name : ''; - let contents; - - if (listEntityType1 && !sidePanelMode) { - const listQuery = { - control: name, - ...query[searchParam], - }; - - contents = ( -
- -
- ); - } else { - contents = ( -
-
- - {!!interpretationText.length && ( - -
- {interpretationText} -
-
- )} - {sidePanelMode && ( - <> - - - - - - )} -
-
- ); - } - - return ( -
- {!sidePanelMode && ( - <> -
- - - )} - {contents} -
- ); - }} -
- ); -}; -ControlPage.propTypes = entityPagePropTypes; -ControlPage.defaultProps = entityPageDefaultProps; - -export default ControlPage; diff --git a/ui/apps/platform/src/Containers/Compliance/Entity/Deployment.jsx b/ui/apps/platform/src/Containers/Compliance/Entity/Deployment.jsx deleted file mode 100644 index 7cfd73c681c39..0000000000000 --- a/ui/apps/platform/src/Containers/Compliance/Entity/Deployment.jsx +++ /dev/null @@ -1,194 +0,0 @@ -import { useContext } from 'react'; -import { useLocation } from 'react-router-dom-v5-compat'; -import { gql } from '@apollo/client'; -import pluralize from 'pluralize'; - -import entityTypes from 'constants/entityTypes'; -import Widget from 'Components/Widget'; -import Query from 'Components/CacheFirstQuery'; -import Loader from 'Components/Loader'; -import { entityPagePropTypes, entityPageDefaultProps } from 'constants/entityPageProps'; -import URLService from 'utils/URLService'; -import ComplianceList from 'Containers/Compliance/List/List'; -import EntityCompliance from 'Containers/Compliance/widgets/EntityCompliance'; -import Cluster from 'images/cluster.svg'; -import Namespace from 'images/ns-icon.svg'; -import IconWidget from 'Components/IconWidget'; -import Labels from 'Containers/Compliance/widgets/Labels'; -import ComplianceByStandards from 'Containers/Compliance/widgets/ComplianceByStandards'; -import isGQLLoading from 'utils/gqlLoading'; -import searchContext from 'Containers/searchContext'; -import useWorkflowMatch from 'hooks/useWorkflowMatch'; - -import Header from './Header'; -import ResourceTabs from './ResourceTabs'; - -export const DEPLOYMENT_QUERY = gql` - query getDeployment($id: ID!) { - deployment(id: $id) { - id - clusterId - clusterName - labels { - key - value - } - name - namespace - namespaceId - } - } -`; - -function processData(data) { - if (!data || !data.deployment) { - return {}; - } - - const result = { ...data.deployment }; - return result; -} - -const DeploymentPage = ({ - entityId, - listEntityType1, - entityId1, - entityType2, - entityListType2, - entityId2, - query, - sidePanelMode, -}) => { - const searchParam = useContext(searchContext); - const match = useWorkflowMatch(); - const location = useLocation(); - - return ( - - {({ loading, data }) => { - if (isGQLLoading(loading, data)) { - return ; - } - const deployment = processData(data); - const { name, id, labels, clusterName, namespace, clusterId, namespaceId } = - deployment; - let contents; - - if (listEntityType1 && !sidePanelMode) { - const listQuery = { - groupBy: - listEntityType1 === entityTypes.CONTROL ? entityTypes.STANDARD : '', - deployment: name, - ...query[searchParam], - }; - contents = ( -
- -
- ); - } else { - const clusterUrl = URLService.getURL(match, location) - .base(entityTypes.CLUSTER, clusterId) - .url(); - - const namespaceUrl = URLService.getURL(match, location) - .base(entityTypes.NAMESPACE, namespaceId) - .url(); - - contents = ( -
-
-
-
- -
-
- -
-
- -
-
- - - - - -
-
- ); - } - - return ( -
- {!sidePanelMode && ( - <> -
- - - )} - {contents} -
- ); - }} -
- ); -}; -DeploymentPage.propTypes = entityPagePropTypes; -DeploymentPage.defaultProps = entityPageDefaultProps; - -export default DeploymentPage; diff --git a/ui/apps/platform/src/Containers/Compliance/Entity/Header.jsx b/ui/apps/platform/src/Containers/Compliance/Entity/Header.jsx deleted file mode 100644 index 0b26de161dbf9..0000000000000 --- a/ui/apps/platform/src/Containers/Compliance/Entity/Header.jsx +++ /dev/null @@ -1,63 +0,0 @@ -import PropTypes from 'prop-types'; -import pluralize from 'pluralize'; - -import PageHeader from 'Components/PageHeader'; -import ScanButton from 'Containers/Compliance/ScanButton'; -import ExportButton from 'Components/ExportButton'; -import useCaseTypes from 'constants/useCaseTypes'; -import entityTypes from 'constants/entityTypes'; -import usePermissions from 'hooks/usePermissions'; - -import { entityNounSentenceCaseSingular } from '../entitiesForCompliance'; - -const EntityHeader = ({ entityType, listEntityType, entityName, entityId, searchComponent }) => { - const { hasReadWriteAccess } = usePermissions(); - const hasWriteAccessForCompliance = hasReadWriteAccess('Compliance'); - - const header = entityName || 'Loading...'; - const subHeader = entityNounSentenceCaseSingular[entityType]; - // Leave raw entity types in case customer depends on this convention for export file name. - let exportFilename = listEntityType - ? `${pluralize(listEntityType)} ACROSS ${entityType} "${entityName.toUpperCase()}"` - : `${entityType} "${entityName}"`; - exportFilename = `${exportFilename} Report`; - const scanCluster = entityType === entityTypes.CLUSTER ? entityId : '*'; - const scanStandard = entityType === entityTypes.STANDARD ? entityId : '*'; - - return ( - - {searchComponent} -
- {hasWriteAccessForCompliance && scanCluster && ( - - )} - {(entityType === entityTypes.CLUSTER || entityType === entityTypes.STANDARD) && ( - - )} -
-
- ); -}; - -EntityHeader.propTypes = { - entityType: PropTypes.string, - listEntityType: PropTypes.string, - entityName: PropTypes.string, - entityId: PropTypes.string, - searchComponent: PropTypes.node, -}; - -EntityHeader.defaultProps = { - entityType: '', - listEntityType: '', - entityName: '', - entityId: '', - searchComponent: null, -}; - -export default EntityHeader; diff --git a/ui/apps/platform/src/Containers/Compliance/Entity/Namespace.jsx b/ui/apps/platform/src/Containers/Compliance/Entity/Namespace.jsx deleted file mode 100644 index dd1f037fd3766..0000000000000 --- a/ui/apps/platform/src/Containers/Compliance/Entity/Namespace.jsx +++ /dev/null @@ -1,205 +0,0 @@ -import { useContext } from 'react'; -import pluralize from 'pluralize'; -import { gql } from '@apollo/client'; - -import ComplianceByStandards from 'Containers/Compliance/widgets/ComplianceByStandards'; -import Query from 'Components/CacheFirstQuery'; -import IconWidget from 'Components/IconWidget'; -import Cluster from 'images/cluster.svg'; -import Widget from 'Components/Widget'; -import ComplianceList from 'Containers/Compliance/List/List'; -import ResourceCount from 'Containers/Compliance/widgets/ResourceCount'; -import PageNotFound from 'Components/PageNotFound'; -import isGQLLoading from 'utils/gqlLoading'; -import Loader from 'Components/Loader'; -import Labels from 'Containers/Compliance/widgets/Labels'; -import EntityCompliance from 'Containers/Compliance/widgets/EntityCompliance'; -import entityTypes from 'constants/entityTypes'; -import useCases from 'constants/useCaseTypes'; -import { entityPagePropTypes, entityPageDefaultProps } from 'constants/entityPageProps'; -import searchContext from 'Containers/searchContext'; - -import Header from './Header'; -import ResourceTabs from './ResourceTabs'; - -export const QUERY = gql` - query getNamespace($id: ID!) { - results: namespace(id: $id) { - metadata { - clusterName - name - id - labels { - key - value - } - } - } - } -`; - -function processData(data, entityId) { - const defaultValue = { - labels: [], - name: '', - clusterName: '', - id: entityId, - }; - - if (!data || !data.results || !data.results.metadata) { - return defaultValue; - } - - const { metadata, ...rest } = data.results; - - return { - ...rest, - ...metadata, - }; -} - -const NamespacePage = ({ - entityId, - listEntityType1, - entityId1, - entityType2, - entityListType2, - entityId2, - query, - sidePanelMode, -}) => { - const searchParam = useContext(searchContext); - return ( - - {({ loading, data }) => { - if (isGQLLoading(loading, data)) { - return ; - } - if (!data.results) { - return ( - - ); - } - const namespace = processData(data); - const { name, id, clusterName, labels } = namespace; - let contents; - - if (listEntityType1 && !sidePanelMode) { - const listQuery = { - groupBy: - listEntityType1 === entityTypes.CONTROL ? entityTypes.STANDARD : '', - Namespace: namespace?.name, - ...query[searchParam], - }; - contents = ( -
- -
- ); - } else { - contents = ( -
-
-
-
- -
-
- -
-
- - - - - - {sidePanelMode && ( - <> -
-
- -
-
- - )} -
-
- ); - } - - return ( -
- {!sidePanelMode && ( - <> -
- - - )} - {contents} -
- ); - }} -
- ); -}; -NamespacePage.propTypes = entityPagePropTypes; -NamespacePage.defaultProps = entityPageDefaultProps; - -export default NamespacePage; diff --git a/ui/apps/platform/src/Containers/Compliance/Entity/Node.jsx b/ui/apps/platform/src/Containers/Compliance/Entity/Node.jsx deleted file mode 100644 index 8d033be499762..0000000000000 --- a/ui/apps/platform/src/Containers/Compliance/Entity/Node.jsx +++ /dev/null @@ -1,238 +0,0 @@ -import { useContext } from 'react'; -import pluralize from 'pluralize'; - -import entityTypes from 'constants/entityTypes'; -import { NODE_QUERY } from 'queries/node'; -import Cluster from 'images/cluster.svg'; -import IpAddress from 'images/ip-address.svg'; -import Hostname from 'images/hostname.svg'; -import ContainerRuntime from 'images/container-runtime.svg'; -import ComplianceByStandards from 'Containers/Compliance/widgets/ComplianceByStandards'; -import Widget from 'Components/Widget'; -import Query from 'Components/CacheFirstQuery'; -import IconWidget from 'Components/IconWidget'; -import InfoWidget from 'Components/InfoWidget'; -import Labels from 'Containers/Compliance/widgets/Labels'; -import EntityCompliance from 'Containers/Compliance/widgets/EntityCompliance'; -import Loader from 'Components/Loader'; -import ComplianceList from 'Containers/Compliance/List/List'; -import PageNotFound from 'Components/PageNotFound'; -import { entityPagePropTypes, entityPageDefaultProps } from 'constants/entityPageProps'; -import useCases from 'constants/useCaseTypes'; -import isGQLLoading from 'utils/gqlLoading'; -import { getDateTime, getDistanceStrictAsPhrase } from 'utils/dateUtils'; -import searchContext from 'Containers/searchContext'; - -import Header from './Header'; -import ResourceTabs from './ResourceTabs'; - -function processData(data) { - if (!data || !data.node) { - return { - name: '', - }; - } - - const result = { ...data.node }; - const [ipAddress] = result.internalIpAddresses; - result.ipAddress = ipAddress; - - return result; -} - -const NodePage = ({ - entityId, - listEntityType1, - entityId1, - entityType2, - entityListType2, - entityId2, - query, - sidePanelMode, -}) => { - const searchParam = useContext(searchContext); - return ( - - {({ loading, data }) => { - if (isGQLLoading(loading, data)) { - return ; - } - - if (!data.node) { - return ( - - ); - } - const node = processData(data); - const { - name, - id, - containerRuntimeVersion, - clusterName, - osImage, - ipAddress, - joinedAt, - kernelVersion, - labels, - } = node; - let contents; - - if (listEntityType1 && !sidePanelMode) { - const listQuery = { - groupBy: - listEntityType1 === entityTypes.CONTROL ? entityTypes.STANDARD : '', - node: name, - ...query[searchParam], - }; - contents = ( -
- -
- ); - } else { - contents = ( -
-
-
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- - - - - -
-
- ); - } - - return ( -
- {!sidePanelMode && ( - <> -
- - - )} - {contents} -
- ); - }} -
- ); -}; -NodePage.propTypes = entityPagePropTypes; -NodePage.defaultProps = entityPageDefaultProps; - -export default NodePage; diff --git a/ui/apps/platform/src/Containers/Compliance/Entity/Page.jsx b/ui/apps/platform/src/Containers/Compliance/Entity/Page.jsx deleted file mode 100644 index 385d0511f176a..0000000000000 --- a/ui/apps/platform/src/Containers/Compliance/Entity/Page.jsx +++ /dev/null @@ -1,56 +0,0 @@ -import PropTypes from 'prop-types'; -import { useLocation } from 'react-router-dom-v5-compat'; -import URLService from 'utils/URLService'; -import entityTypes from 'constants/entityTypes'; -import useWorkflowMatch from 'hooks/useWorkflowMatch'; - -import NodePage from './Node'; -import NamespacePage from './Namespace'; -import ClusterPage from './Cluster'; -import ControlPage from './Control'; -import DeploymentPage from './Deployment'; -import StandardPage from './Standard'; - -const ComplianceEntityPage = () => { - const location = useLocation(); - const match = useWorkflowMatch(); - - const params = URLService.getParams(match, location); - - const pageProps = { - entityId: params.pageEntityId, - listEntityType1: params.entityListType1, - entityType1: params.entityType1, - entityId1: params.entityId1, - entityType2: params.entityType2, - entityListType2: params.entityListType2, - entityId2: params.entityId2, - query: params.query, - }; - - const pageTypeMap = { - [entityTypes.CLUSTER]: , - [entityTypes.NODE]: , - [entityTypes.NAMESPACE]: , - [entityTypes.CONTROL]: , - [entityTypes.DEPLOYMENT]: , - [entityTypes.STANDARD]: , - }; - - return pageTypeMap[params.pageEntityType]; -}; - -ComplianceEntityPage.propTypes = { - params: PropTypes.shape({ - entityId: PropTypes.string, - entityType: PropTypes.string, - }), - sidePanelMode: PropTypes.bool, -}; - -ComplianceEntityPage.defaultProps = { - params: null, - sidePanelMode: false, -}; - -export default ComplianceEntityPage; diff --git a/ui/apps/platform/src/Containers/Compliance/Entity/ResourceTabs.jsx b/ui/apps/platform/src/Containers/Compliance/Entity/ResourceTabs.jsx deleted file mode 100644 index 0fdf5148715b0..0000000000000 --- a/ui/apps/platform/src/Containers/Compliance/Entity/ResourceTabs.jsx +++ /dev/null @@ -1,103 +0,0 @@ -import PropTypes from 'prop-types'; -import { Link, useLocation } from 'react-router-dom-v5-compat'; -import useWorkflowMatch from 'hooks/useWorkflowMatch'; -import { resourceLabels } from 'messages/common'; -import URLService from 'utils/URLService'; -import pluralize from 'pluralize'; -import Query from 'Components/ThrowingQuery'; -import { SEARCH_WITH_CONTROLS as QUERY } from 'queries/search'; -import queryService from 'utils/queryService'; -import { getResourceCountFromAggregatedResults } from '../complianceUtils'; - -const ResourceTabs = ({ entityType, entityId, resourceTabs, selectedType }) => { - const match = useWorkflowMatch(); - const location = useLocation(); - - function getLinkToListType(listEntityType) { - return URLService.getURL(match, location) - .base(entityType, entityId) - .push(listEntityType) - .query() - .url(); - } - - function processData(data) { - const tabData = [ - { - title: 'Overview', - link: getLinkToListType(), - type: null, - }, - ]; - - if (resourceTabs.length && data) { - resourceTabs.forEach((type) => { - const count = getResourceCountFromAggregatedResults(type, data); - if (count > 0) { - tabData.push({ - title: `${count} ${pluralize(resourceLabels[type], count)}`, - link: getLinkToListType(type), - type, - }); - } - }); - } - - return tabData; - } - - function getVariables() { - // entitytype.NODE and namespace don't play well in groupBy - return { - query: queryService.objectToWhereClause({ [`${entityType} ID`]: entityId }), - }; - } - - return ( - - {({ loading, data }) => { - if (loading) { - return null; - } - const tabData = processData(data); - return ( -
    - {tabData.map((datum, i) => { - const borderLeft = !i ? 'border-l' : ''; - const bgColor = - datum.type === selectedType || (!selectedType && !datum.type) - ? 'bg-primary-200' - : 'bg-base-100'; - const textColor = 'text-base-600'; - - return ( -
  • - - {datum.title} - -
  • - ); - })} -
- ); - }} -
- ); -}; - -ResourceTabs.propTypes = { - entityType: PropTypes.string.isRequired, - entityId: PropTypes.string.isRequired, - selectedType: PropTypes.string, - resourceTabs: PropTypes.arrayOf(PropTypes.string), -}; - -ResourceTabs.defaultProps = { - resourceTabs: PropTypes.arrayOf(PropTypes.string), - selectedType: null, -}; - -export default ResourceTabs; diff --git a/ui/apps/platform/src/Containers/Compliance/Entity/Standard.jsx b/ui/apps/platform/src/Containers/Compliance/Entity/Standard.jsx deleted file mode 100644 index 44c20dc5d966b..0000000000000 --- a/ui/apps/platform/src/Containers/Compliance/Entity/Standard.jsx +++ /dev/null @@ -1,45 +0,0 @@ -import entityTypes from 'constants/entityTypes'; -import ComplianceList from 'Containers/Compliance/List/List'; -import { entityPagePropTypes, entityPageDefaultProps } from 'constants/entityPageProps'; -import ComplianceSearchInput from '../ComplianceSearchInput'; -import Header from '../List/Header'; - -const StandardPage = ({ - entityId, - listEntityType1, - entityId1, - entityType2, - entityListType2, - entityId2, -}) => { - const listQuery = { - 'Standard Id': entityId, - }; - return ( -
-
- } - /> - -
- ); -}; - -StandardPage.propTypes = entityPagePropTypes; -StandardPage.defaultProps = entityPageDefaultProps; - -export default StandardPage; diff --git a/ui/apps/platform/src/Containers/Compliance/List/Header.jsx b/ui/apps/platform/src/Containers/Compliance/List/Header.jsx deleted file mode 100644 index 44f7ca980ce1b..0000000000000 --- a/ui/apps/platform/src/Containers/Compliance/List/Header.jsx +++ /dev/null @@ -1,61 +0,0 @@ -import PropTypes from 'prop-types'; -import lowerCase from 'lodash/lowerCase'; -import startCase from 'lodash/startCase'; -import findKey from 'lodash/findKey'; - -import PageHeader from 'Components/PageHeader'; -import ExportButton from 'Components/ExportButton'; -import ScanButton from 'Containers/Compliance/ScanButton'; -import { standardLabels } from 'messages/standards'; -import useCaseTypes from 'constants/useCaseTypes'; -import usePermissions from 'hooks/usePermissions'; - -// Disable to prevent merge conflict below if we need to cherry pick fix to previous release. -/* eslint-disable prettier/prettier */ -const ListHeader = ({ entityType, searchComponent, standard }) => { - const { hasReadWriteAccess } = usePermissions(); - const hasWriteAccessForCompliance = hasReadWriteAccess('Compliance'); - - const standardId = findKey(standardLabels, (key) => key === standard) || standard; - - // ROX-25189: Add nullish coalescing to include compliance operator standard id: - // in page header - // in file name - const headerText = standardId - ? standardLabels[standardId] ?? standardId - : `${startCase(lowerCase(entityType))}s`; - - // If standardId is truthy, then standard page entity is CONTROL for address controls?s[standard]=WHAT_EVER&s[groupBy]=CATEGORY - const subHeaderText = standardId ? 'Standard' : 'Resource list'; - return ( - -
{searchComponent}
-
- {hasWriteAccessForCompliance && standardId && ( - - )} - {standardId && ( - - )} -
-
- ); -}; -/* eslint-enable prettier/prettier */ -ListHeader.propTypes = { - searchComponent: PropTypes.element, - entityType: PropTypes.string.isRequired, - standard: PropTypes.string, -}; - -ListHeader.defaultProps = { - searchComponent: null, - standard: null, -}; - -export default ListHeader; diff --git a/ui/apps/platform/src/Containers/Compliance/List/List.jsx b/ui/apps/platform/src/Containers/Compliance/List/List.jsx deleted file mode 100644 index 586ef75dcdd82..0000000000000 --- a/ui/apps/platform/src/Containers/Compliance/List/List.jsx +++ /dev/null @@ -1,78 +0,0 @@ -import PropTypes from 'prop-types'; -import { useLocation, useNavigate } from 'react-router-dom-v5-compat'; -import lowerCase from 'lodash/lowerCase'; -import pluralize from 'pluralize'; - -import URLService from 'utils/URLService'; -import { PageBody } from 'Components/Panel'; -import { searchCategories as searchCategoryTypes } from 'constants/entityTypes'; -import searchContext from 'Containers/searchContext'; -import { searchParams } from 'constants/searchParams'; -import useWorkflowMatch from 'hooks/useWorkflowMatch'; -import ListTable from './Table'; -import SidePanel from './SidePanel'; -import SidePanelAdjacentArea from './SidePanelAdjacentArea'; -import ComplianceSearchInput from '../ComplianceSearchInput'; - -const ComplianceList = ({ entityType, query, selectedRowId, noSearch }) => { - const navigate = useNavigate(); - const location = useLocation(); - const match = useWorkflowMatch(); - function setSelectedRowId(row) { - const { id } = row; - const url = URLService.getURL(match, location) - .set('entityListType1', entityType) - .set('entityId1', id) - .url(); - navigate(url); - } - - const placeholder = `Filter ${pluralize(lowerCase(entityType))}`; - - const searchComponent = noSearch ? null : ( - - ); - - return ( - -
- -
- {selectedRowId && ( - - - - - - )} -
- ); -}; - -export default ComplianceList; - -ComplianceList.propTypes = { - entityType: PropTypes.string.isRequired, - query: PropTypes.shape({}), - selectedRowId: PropTypes.string, - // entityType2: PropTypes.string, - // entityId2: PropTypes.string, - noSearch: PropTypes.bool, -}; - -ComplianceList.defaultProps = { - query: null, - selectedRowId: null, - noSearch: false, - // entityType2: null, - // entityId2: null -}; diff --git a/ui/apps/platform/src/Containers/Compliance/List/Page.jsx b/ui/apps/platform/src/Containers/Compliance/List/Page.jsx deleted file mode 100644 index 6c3d6ba9f21a2..0000000000000 --- a/ui/apps/platform/src/Containers/Compliance/List/Page.jsx +++ /dev/null @@ -1,58 +0,0 @@ -import { useContext } from 'react'; -import PropTypes from 'prop-types'; -import { useLocation } from 'react-router-dom-v5-compat'; -import lowerCase from 'lodash/lowerCase'; -import pluralize from 'pluralize'; - -import URLService from 'utils/URLService'; -import ComplianceList from 'Containers/Compliance/List/List'; -import searchContext from 'Containers/searchContext'; -import useWorkflowMatch from 'hooks/useWorkflowMatch'; -import ComplianceSearchInput from '../ComplianceSearchInput'; -import Header from './Header'; - -const ComplianceListPage = () => { - const location = useLocation(); - const match = useWorkflowMatch(); - const params = URLService.getParams(match, location); - const searchParam = useContext(searchContext); - const query = { ...params.query[searchParam] }; - const { pageEntityListType, entityId1, entityType2, entityListType2, entityId2 } = params; - const placeholder = `Filter ${pluralize(lowerCase(pageEntityListType))}`; - return ( -
-
- } - standard={query.Standard || query.standard} - /> - -
- ); -}; - -ComplianceListPage.propTypes = { - params: PropTypes.shape({ - entityType: PropTypes.string.isRequired, - }), -}; - -ComplianceListPage.defaultProps = { - params: null, -}; - -export default ComplianceListPage; diff --git a/ui/apps/platform/src/Containers/Compliance/List/SidePanel.jsx b/ui/apps/platform/src/Containers/Compliance/List/SidePanel.jsx deleted file mode 100644 index 79d7566d93c3b..0000000000000 --- a/ui/apps/platform/src/Containers/Compliance/List/SidePanel.jsx +++ /dev/null @@ -1,102 +0,0 @@ -import PropTypes from 'prop-types'; -import { ExternalLinkAltIcon } from '@patternfly/react-icons'; -import { Link, useLocation, useNavigate } from 'react-router-dom-v5-compat'; - -import Query from 'Components/CacheFirstQuery'; -import CloseButton from 'Components/CloseButton'; -import { PanelNew, PanelBody, PanelHead, PanelHeadEnd } from 'Components/Panel'; -import { resourceTypes, standardEntityTypes } from 'constants/entityTypes'; -import ControlPage from 'Containers/Compliance/Entity/Control'; -import useWorkflowMatch from 'hooks/useWorkflowMatch'; -import URLService from 'utils/URLService'; -import getEntityName from 'utils/getEntityName'; -import { entityNameQueryMap } from 'utils/queryMap'; -import { truncate } from 'utils/textUtils'; -import NamespacePage from '../Entity/Namespace'; -import ClusterPage from '../Entity/Cluster'; -import NodePage from '../Entity/Node'; -import DeploymentPage from '../Entity/Deployment'; - -const MAX_CONTROL_TITLE = 120; - -const ComplianceListSidePanel = ({ entityType, entityId }) => { - const navigate = useNavigate(); - const location = useLocation(); - const match = useWorkflowMatch(); - - function getEntityPage() { - switch (entityType) { - case resourceTypes.NODE: - return ; - case resourceTypes.NAMESPACE: - return ; - case resourceTypes.CLUSTER: - return ; - case resourceTypes.DEPLOYMENT: - return ; - case standardEntityTypes.CONTROL: - return ; - default: - return null; - } - } - - function closeSidePanel() { - const baseURL = URLService.getURL(match, location).clearSidePanelParams().url(); - navigate(baseURL); - } - const headerUrl = URLService.getURL(match, location).base(entityType, entityId).url(); - - return ( - - {({ loading, data }) => { - let linkText = 'loading...'; - if (!loading && data) { - linkText = truncate(getEntityName(entityType, data), MAX_CONTROL_TITLE); - } - const headerTextComponent = ( -
-
- -
- {linkText} -
- - - - -
-
- ); - const entityPage = getEntityPage(); - return ( - - - {headerTextComponent} - - - - - {entityPage} - - ); - }} -
- ); -}; - -ComplianceListSidePanel.propTypes = { - entityType: PropTypes.string.isRequired, - entityId: PropTypes.string.isRequired, -}; - -export default ComplianceListSidePanel; diff --git a/ui/apps/platform/src/Containers/Compliance/List/SidePanelAdjacentArea.tsx b/ui/apps/platform/src/Containers/Compliance/List/SidePanelAdjacentArea.tsx deleted file mode 100644 index 9c00dbdcc6977..0000000000000 --- a/ui/apps/platform/src/Containers/Compliance/List/SidePanelAdjacentArea.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import type { ReactElement, ReactNode } from 'react'; - -type Width = '1/3' | '2/5' | '1/2' | '3/5'; - -export type SidePanelAdjacentAreaProps = { - children: ReactNode; - width?: Width; -}; - -const widthClassNames: Record = { - '1/3': 'md:w-1/3', // Compliance - '2/5': 'md:w-2/5 xl:w-1/3 xxl:w-1/4', // Violations - '1/2': 'md:w-1/2', // Integrations - '3/5': 'md:w-3/5 lg:w-1/2 xl:w-2/5 xxl:w-1/3', // Risk -}; - -/* - * Render an area (without animation nor overlay) that contains the content of a side panel. - * Assume its parent has position relative. - * Assume it follows its main panel sibling. - * - * If page width is less than medium, the side panel completely covers the main panel. - * If page width is at least medium, the side panel has a fraction of page width (not including side nav). - */ -function SidePanelAdjacentArea({ - children, - width = '1/2', -}: SidePanelAdjacentAreaProps): ReactElement { - return ( -
- {children} -
- ); -} - -export default SidePanelAdjacentArea; diff --git a/ui/apps/platform/src/Containers/Compliance/List/Table.jsx b/ui/apps/platform/src/Containers/Compliance/List/Table.jsx deleted file mode 100644 index a4fb72bdc44a6..0000000000000 --- a/ui/apps/platform/src/Containers/Compliance/List/Table.jsx +++ /dev/null @@ -1,388 +0,0 @@ -import { useState } from 'react'; -import PropTypes from 'prop-types'; -import pluralize from 'pluralize'; -import orderBy from 'lodash/orderBy'; -import { useQuery } from '@apollo/client'; -import { Alert } from '@patternfly/react-core'; - -import entityTypes, { standardTypes } from 'constants/entityTypes'; -import { standardLabels } from 'messages/standards'; -import { CLIENT_SIDE_SEARCH_OPTIONS as SEARCH_OPTIONS } from 'constants/searchOptions'; -import Table from 'Components/Table'; -import { PanelNew, PanelBody, PanelHead, PanelHeadEnd, PanelTitle } from 'Components/Panel'; -import Loader from 'Components/Loader'; -import TablePagination from 'Components/TablePagination'; -import Query from 'Components/CacheFirstQuery'; -import NoResultsMessage from 'Components/NoResultsMessage'; - -import { CLUSTERS_QUERY, NAMESPACES_QUERY, NODES_QUERY, DEPLOYMENTS_QUERY } from 'queries/table'; -import { LIST_STANDARD, STANDARDS_QUERY } from 'queries/standard'; -import queryService from 'utils/queryService'; - -import { complianceEntityTypes, entityCountNounOrdinaryCase } from '../entitiesForCompliance'; -import TableGroup from './TableGroup'; -import { getColumnsByEntity, getColumnsByStandard, getColumnsForControl } from './tableColumns'; - -function getQuery(entityType) { - switch (entityType) { - case entityTypes.CLUSTER: - return CLUSTERS_QUERY; - case entityTypes.NAMESPACE: - return NAMESPACES_QUERY; - case entityTypes.NODE: - return NODES_QUERY; - case entityTypes.DEPLOYMENT: - return DEPLOYMENTS_QUERY; - case entityTypes.CONTROL: - return LIST_STANDARD; - default: - return null; - } -} - -function getVariables(entityType, query) { - const groupBy = - entityType === entityTypes.CONTROL - ? ['CONTROL', 'CATEGORY', ...(query.groupBy ? [query.groupBy] : [])] - : null; - return { - where: queryService.objectToWhereClause(query), - groupBy, - }; -} - -function complianceRate(numPassing, numFailing) { - return numPassing + numFailing > 0 - ? `${Math.round((numPassing / (numPassing + numFailing)) * 100)}%` - : 'N/A'; -} - -function formatResourceData(data, resourceType) { - if (!data || !data.results || data.results.results.length === 0) { - return null; - } - const formattedData = { results: [] }; - const entityMap = {}; - let standardKeyIndex = 0; - let entityKeyIndex = 0; - data.results.results[0].aggregationKeys.forEach(({ scope }, idx) => { - if (scope === 'STANDARD') { - standardKeyIndex = idx; - } - if (scope === resourceType) { - entityKeyIndex = idx; - } - }); - data.results.results.forEach(({ aggregationKeys, keys, numPassing, numFailing }) => { - const curEntity = aggregationKeys[entityKeyIndex].id; - const curStandard = aggregationKeys[standardKeyIndex].id; - const entity = keys[entityKeyIndex]; - if (entity.__typename === '') { - return; - } - const entityMetaData = entity.metadata || {}; - - entityMap[curEntity] = entityMap[curEntity] || { - name: entity?.name || entity?.metadata?.name, - cluster: entity?.clusterName || entityMetaData?.clusterName || entity?.name, - namespace: entity?.namespace, - id: curEntity, - overall: { - numPassing: 0, - numFailing: 0, - average: 0, - }, - }; - - if (numPassing + numFailing > 0) { - entityMap[curEntity][curStandard] = complianceRate(numPassing, numFailing); - } - entityMap[curEntity].overall.numPassing += numPassing; - entityMap[curEntity].overall.numFailing += numFailing; - }); - - Object.keys(entityMap).forEach((cluster) => { - const overallCluster = { ...entityMap[cluster] }; - const { numPassing, numFailing } = overallCluster.overall; - overallCluster.overall.average = complianceRate(numPassing, numFailing); - formattedData.results.push(overallCluster); - }); - - return formattedData; -} - -function formatStandardData(data) { - if (!data.results || !data.results.results || data.results.results.length === 0) { - return null; - } - const formattedData = { results: [], totalRows: 0 }; - const groups = {}; - let controlKeyIndex = null; - let categoryKeyIndex = null; - let groupByKeyIndex = null; - data.results.results[0].aggregationKeys.forEach(({ scope }, idx) => { - if (scope === 'CONTROL') { - controlKeyIndex = idx; - } - if (scope === 'CATEGORY') { - categoryKeyIndex = idx; - } - if (scope !== 'CATEGORY' && scope !== 'CONTROL') { - groupByKeyIndex = idx; - } - }); - data.results.results.forEach(({ keys, numPassing, numFailing }) => { - const groupKey = groupByKeyIndex === null ? categoryKeyIndex : groupByKeyIndex; - const { - id: standard, - name, - clusterName, - description: groupDescription, - metadata, - __typename, - } = keys[groupKey]; - // the check below is to address ROX-1420 - if (__typename !== '') { - let groupName = name || standardLabels[standard] || standard; - if (__typename === 'Node') { - groupName = `${clusterName}/${name}`; - } else if (__typename === 'Namespace') { - groupName = `${metadata?.clusterName}/${metadata?.name}`; - } - if (!groups[groupName]) { - const groupId = parseInt(groupName, 10) || groupName; - groups[groupName] = { - groupId, - name: `${groupName} ${groupDescription ? `- ${groupDescription}` : ''}`, - rows: [], - }; - } - if (controlKeyIndex) { - const { id, name: controlName, description, standardId } = keys[controlKeyIndex]; - groups[groupName].rows.push({ - id, - description, - standardId, - standard: standardLabels[standardId], - control: controlName, - compliance: complianceRate(numPassing, numFailing), - group: groupName, - }); - } - } - }); - Object.keys(groups).forEach((group) => { - formattedData.results.push(groups[group]); - formattedData.totalRows += groups[group].rows.length; - }); - formattedData.results = orderBy(formattedData.results, ['groupId', 'name'], ['asc', 'asc']); - return formattedData; -} - -function canFilterByComplianceState(filterQuery, complianceStateKey) { - return ( - filterQuery[complianceStateKey] && - (!Array.isArray(filterQuery[complianceStateKey]) || - filterQuery[complianceStateKey].length <= 1) - ); -} - -const ListTable = ({ searchComponent, entityType, query, selectedRowId, updateSelectedRow }) => { - const [page, setPage] = useState(0); - // This is a client-side implementation of filtering by the "Compliance State" Search Option - function filterByComplianceState(data, filterQuery, isControlList) { - const complianceStateKey = SEARCH_OPTIONS.COMPLIANCE.STATE; - if (!canFilterByComplianceState(filterQuery, complianceStateKey)) { - return data.results; - } - const val = filterQuery[complianceStateKey].toLowerCase(); - const isPassing = val === 'pass'; - const isFailing = val === 'fail'; - const { results } = data; - if (isControlList) { - return results - .map((result) => { - const newResult = { ...result }; - newResult.rows = result.rows.filter((row) => { - const intValue = parseInt(row.compliance, 10); // strValue comes in the format "100.00%" - if (Number.isNaN(intValue)) { - return false; - } - if (isPassing) { - return intValue === 100; - } - if (isFailing) { - return intValue !== 100; - } - return true; - }); - return newResult; - }) - .filter((result) => result.rows.length); - } - - return results.filter((item) => - Object.values(standardTypes).reduce((acc, standardId) => { - if (!item[standardId]) { - return acc; - } - const intValue = parseInt(item[standardId], 10); - if (isPassing) { - if (acc === false) { - return acc; - } - return intValue === 100; - } - if (isFailing) { - if (acc === true) { - return acc; - } - return intValue !== 100; - } - return acc; - }, null) - ); - } - - function getTotalRows(data, isStandard) { - if (!isStandard) { - return data.length; - } - return data.reduce((acc, group) => acc + group.rows.length, 0); - } - - const { loading: loadingStandards, data: standardsData } = useQuery(STANDARDS_QUERY); - if (loadingStandards) { - return ; - } - const { standardId } = query; - const gqlQuery = getQuery(entityType); - const variables = getVariables(entityType, query); - const isControlList = entityType === entityTypes.CONTROL; - const formatData = isControlList ? formatStandardData : formatResourceData; - let tableColumns; - if (standardId) { - tableColumns = getColumnsByStandard(standardId); - } else if (isControlList) { - tableColumns = getColumnsForControl(query); - } else { - tableColumns = getColumnsByEntity(entityType, standardsData.results); - } - let tableData; - - return ( - - {({ loading, data }) => { - let contents = ; - let headerComponent; - let headerText; - let totalRows = 0; - - if (!loading || (data && data.results)) { - const formattedData = formatData(data, entityType); - if (!formattedData) { - headerText = entityCountNounOrdinaryCase(0, entityType); - contents = ; - } else { - tableData = filterByComplianceState(formattedData, query, isControlList); - totalRows = getTotalRows(tableData, isControlList); - const entityCountNoun = entityCountNounOrdinaryCase(totalRows, entityType); - const { groupBy } = query; - - // Resouces: CLUSTER, NAMESPACE, NODE, DEPLOYMENT. - // Or CATEGORY from View Standard link of sunburst graph on dashboard. - // Or STANDARD on Controls tab of resource single page. - // Otherwise undefined. - const { length } = tableData; - const groupedByText = groupBy - ? ` across ${ - complianceEntityTypes.includes(groupBy) - ? entityCountNounOrdinaryCase(length, groupBy) - : `${length} ${pluralize(groupBy.toLowerCase(), length)}` - }` - : ''; - headerText = `${entityCountNoun}${groupedByText}`; - - const tableElement = isControlList ? ( - - ) : ( - - ); - contents = ( - <> - {data.results.errorMessage && ( - - {data.results.errorMessage} - - )} - {tableElement} - - ); - } - headerComponent = isControlList ? null : ( - <> -
{searchComponent}
- - - ); - } - return ( - - - - {headerComponent} - - {contents} - - ); - }} - - ); -}; - -ListTable.propTypes = { - searchComponent: PropTypes.node, - entityType: PropTypes.string, - query: PropTypes.shape({ - standardId: PropTypes.string, - groupBy: PropTypes.string, - }), - selectedRowId: PropTypes.string, - updateSelectedRow: PropTypes.func.isRequired, -}; - -ListTable.defaultProps = { - searchComponent: null, - selectedRowId: null, - entityType: null, - query: null, -}; - -export default ListTable; diff --git a/ui/apps/platform/src/Containers/Compliance/List/TableGroup.jsx b/ui/apps/platform/src/Containers/Compliance/List/TableGroup.jsx deleted file mode 100644 index cac5d310637a4..0000000000000 --- a/ui/apps/platform/src/Containers/Compliance/List/TableGroup.jsx +++ /dev/null @@ -1,102 +0,0 @@ -import { Component } from 'react'; -import PropTypes from 'prop-types'; -import Table from 'Components/Table'; -import Collapsible from 'react-collapsible'; -import { ChevronDown, ChevronUp } from 'react-feather'; - -import { entityCountNounOrdinaryCase } from '../entitiesForCompliance'; - -const icons = { - opened: , - closed: , -}; - -class TableGroup extends Component { - static propTypes = { - groups: PropTypes.arrayOf( - PropTypes.shape({ - name: PropTypes.string.isRequired, - rows: PropTypes.arrayOf(PropTypes.shape()), - }) - ).isRequired, - totalRows: PropTypes.number.isRequired, - onRowClick: PropTypes.func.isRequired, - tableColumns: PropTypes.arrayOf(PropTypes.shape({})).isRequired, - idAttribute: PropTypes.string.isRequired, - entityType: PropTypes.string.isRequired, - selectedRowId: PropTypes.string, - }; - - static defaultProps = { - selectedRowId: null, - }; - - renderSubTable = ({ rows }) => { - const { tableColumns, onRowClick, selectedRowId, idAttribute } = this.props; - if (rows.length === 0) { - return null; - } - return ( -
- ); - }; - - renderGroupByCollapsible = (state, { name, rows }) => ( -
-
-
-
- {icons[state]} -
-

{name}

-
-
- {entityCountNounOrdinaryCase(rows.length, this.props.entityType)} -
-
-
- ); - - renderWhenOpened = (group) => this.renderGroupByCollapsible('opened', group); - - renderWhenClosed = (group) => this.renderGroupByCollapsible('closed', group); - - render() { - const { groups, totalRows } = this.props; - return ( -
- {groups.map((group, idx) => ( - - {this.renderSubTable(group)} - - ))} -
- ); - } -} - -export default TableGroup; diff --git a/ui/apps/platform/src/Containers/Compliance/List/tableColumns.jsx b/ui/apps/platform/src/Containers/Compliance/List/tableColumns.jsx deleted file mode 100644 index f32ff66ba3da8..0000000000000 --- a/ui/apps/platform/src/Containers/Compliance/List/tableColumns.jsx +++ /dev/null @@ -1,242 +0,0 @@ -import isEmpty from 'lodash/isEmpty'; -import qs from 'qs'; - -import { defaultHeaderClassName, defaultColumnClassName } from 'Components/Table'; -import TableCellLink from 'Components/TableCellLink'; -import { resourceTypes, standardBaseTypes } from 'constants/entityTypes'; -import { sortVersion } from 'sorters/sorters'; -import { complianceBasePath } from 'routePaths'; - -const getColumnValue = (row, accessor) => (row[accessor] ? row[accessor] : 'N/A'); - -const columnsForStandard = (function getColumnsForStandards() { - const ret = {}; - Object.entries(standardBaseTypes).forEach(([baseType, columnName]) => { - ret[baseType] = { - accessor: baseType, - Header: columnName, - Cell: ({ original }) => getColumnValue(original, baseType), - }; - }); - return ret; -})(); - -function getColumnForStandard(id) { - return { - accessor: id, - Header: standardBaseTypes[id] || id, - Cell: ({ original }) => getColumnValue(original, id), - }; -} - -const getClusterColumns = (standards) => [ - { - accessor: 'id', - Header: 'id', - headerClassName: 'hidden', - className: 'hidden', - }, - { - accessor: 'name', - Header: 'Cluster', - Cell: ({ original, pdf }) => { - const url = `${complianceBasePath}/clusters/${original.id}`; - return ( - - {original.name} - - ); - }, - }, - ...standards.map(({ id }) => getColumnForStandard(id)), - { - accessor: 'overall.average', - Header: 'Overall', - }, -]; - -// TODO verify that this is obsolete. -// If not obsolete, it might need query argument like getColumnsForControl function. -const getStandardColumns = (standard) => [ - { - accessor: 'id', - Header: 'id', - headerClassName: 'hidden', - className: 'hidden', - }, - { - accessor: 'control', - sortMethod: sortVersion, - Header: `${standard} Controls`, - headerClassName: `w-5/6 ${defaultHeaderClassName}`, - className: `w-5/6 ${defaultColumnClassName}`, - Cell: ({ original, pdf }) => { - const url = `${complianceBasePath}/controls/${original.id}`; - return ( - - {`${original.control} - ${original.description}`} - - ); - }, - }, - { - accessor: 'compliance', - Header: 'Compliance', - headerClassName: `w-1/8 flex justify-end pr-4 ${defaultHeaderClassName}`, - className: `w-1/8 justify-end pr-4 ${defaultColumnClassName}`, - }, -]; - -const getNodeColumns = (standards) => [ - { - accessor: 'id', - Header: 'id', - headerClassName: 'hidden', - className: 'hidden', - }, - { - accessor: 'name', - Header: 'Node', - Cell: ({ original, pdf }) => { - const url = `${complianceBasePath}/nodes/${original.id}`; - return ( - - {original.name} - - ); - }, - }, - { - accessor: 'cluster', - Header: 'Cluster', - }, - ...standards.map(({ id }) => columnsForStandard[id]), - { - accessor: 'overall.average', - Header: 'Overall', - }, -]; - -const getNamespaceColumns = (standards) => [ - { - accessor: 'id', - Header: 'id', - headerClassName: 'hidden', - className: 'hidden', - }, - { - accessor: 'name', - Header: 'Namespace', - Cell: ({ original, pdf }) => { - const url = `${complianceBasePath}/namespaces/${original.id}`; - return ( - - {original.name} - - ); - }, - }, - { - accessor: 'cluster', - Header: 'Cluster', - }, - ...standards.map(({ id }) => columnsForStandard[id]), - { - accessor: 'overall.average', - Header: 'Overall', - }, -]; - -const getDeploymentColumns = (standards) => [ - { - accessor: 'id', - Header: 'id', - headerClassName: 'hidden', - className: 'hidden', - }, - { - accessor: 'name', - Header: 'Name', - Cell: ({ original, pdf }) => { - const url = `${complianceBasePath}/deployments/${original.id}`; - return ( - - {original.name} - - ); - }, - }, - { - accessor: 'cluster', - Header: 'Cluster Name', - }, - { - accessor: 'namespace', - Header: 'Namespace', - }, - ...standards.map(({ id }) => columnsForStandard[id]), - { - accessor: 'overall.average', - Header: 'Overall', - }, -]; - -export function getColumnsForControl(query) { - return [ - { - accessor: 'id', - Header: 'id', - headerClassName: 'hidden', - className: 'hidden', - }, - { - accessor: 'control', - sortMethod: sortVersion, - Header: `Control`, - headerClassName: `w-5/6 ${defaultHeaderClassName}`, - className: `w-5/6 ${defaultColumnClassName}`, - Cell: ({ original, pdf }) => { - const search = isEmpty(query) - ? '' - : qs.stringify(query, { - addQueryPrefix: true, - arrayFormat: 'indices', - encodeValuesOnly: true, - }); - const url = `${complianceBasePath}/controls/${original.id}${search}`; - return ( - - {`${original.control} - ${original.description}`} - - ); - }, - }, - { - accessor: 'compliance', - Header: 'Compliance', - headerClassName: `w-1/8 flex justify-end pr-4 ${defaultHeaderClassName}`, - className: `w-1/8 justify-end pr-4 ${defaultColumnClassName}`, - }, - ]; -} - -export function getColumnsByEntity(entityType, standards) { - const filteredStandards = standards.filter(({ scopes }) => scopes.includes(entityType)); - switch (entityType) { - case resourceTypes.CLUSTER: - return getClusterColumns(filteredStandards); - case resourceTypes.NODE: - return getNodeColumns(filteredStandards); - case resourceTypes.NAMESPACE: - return getNamespaceColumns(filteredStandards); - case resourceTypes.DEPLOYMENT: - return getDeploymentColumns(filteredStandards); - default: - return []; - } -} - -// TODO verify that this is obsolete. -export function getColumnsByStandard(standardID) { - return getStandardColumns(standardBaseTypes[standardID]); -} diff --git a/ui/apps/platform/src/Containers/Compliance/List/tableColumns.test.js b/ui/apps/platform/src/Containers/Compliance/List/tableColumns.test.js deleted file mode 100644 index 717839b7a0a92..0000000000000 --- a/ui/apps/platform/src/Containers/Compliance/List/tableColumns.test.js +++ /dev/null @@ -1,68 +0,0 @@ -/* eslint vitest/expect-expect: ["error", { "assertFunctionNames": ["expectColumnsToContain", "expectColumnsNotToContain"] }] */ - -import { resourceTypes, standardTypes } from 'constants/entityTypes'; -import { getColumnsByEntity, getColumnsByStandard } from './tableColumns'; - -function expectColumnsToContain(columns, shouldContain) { - const accessors = columns.map((c) => c.accessor); - expect(accessors).toEqual(expect.arrayContaining(shouldContain)); -} - -function expectColumnsNotToContain(columns, shouldNotContain) { - const accessors = columns.map((c) => c.accessor); - expect(accessors).toEqual(expect.not.arrayContaining(shouldNotContain)); -} - -const standards = [ - { - id: 'CIS_Kubernetes_v1_5', - name: 'CIS Kubernetes v1.5', - scopes: ['CLUSTER', 'NODE'], - }, - { - id: 'HIPAA_164', - name: 'HIPAA 164', - scopes: ['CLUSTER', 'NAMESPACE', 'DEPLOYMENT'], - }, - { - id: 'NIST_800_190', - name: 'NIST SP 800-190', - scopes: ['CLUSTER', 'NAMESPACE', 'DEPLOYMENT', 'NODE'], - }, - { - id: 'NIST_SP_800_53_Rev_4', - name: 'NIST SP 800-53', - scopes: ['CLUSTER', 'NAMESPACE', 'DEPLOYMENT'], - }, - { - id: 'PCI_DSS_3_2', - name: 'PCI DSS 3.2.1', - scopes: ['CLUSTER', 'NAMESPACE', 'DEPLOYMENT'], - }, -]; - -describe('Get columns', () => { - it('can get columns by entity with exclusion', () => { - expectColumnsToContain(getColumnsByEntity(resourceTypes.CLUSTER, standards), [ - 'id', - standardTypes.NIST_800_190, - standardTypes.NIST_SP_800_53_Rev_4, - ]); - - expectColumnsToContain(getColumnsByEntity(resourceTypes.NODE, standards), [ - standardTypes.NIST_800_190, - ]); - - expectColumnsNotToContain(getColumnsByEntity(resourceTypes.NODE, standards), [ - standardTypes.NIST_SP_800_53_Rev_4, - ]); - }); - - it('can get columns by standard', () => { - expectColumnsToContain(getColumnsByStandard(standardTypes.NIST_SP_800_53_Rev_4), [ - 'id', - 'compliance', - 'control', - ]); - }); -}); diff --git a/ui/apps/platform/src/Containers/Compliance/Page.jsx b/ui/apps/platform/src/Containers/Compliance/Page.jsx deleted file mode 100644 index ea130f752c833..0000000000000 --- a/ui/apps/platform/src/Containers/Compliance/Page.jsx +++ /dev/null @@ -1,37 +0,0 @@ -import { memo } from 'react'; -import { Route, Routes } from 'react-router-dom-v5-compat'; -import isEqual from 'lodash/isEqual'; - -import PageNotFound from 'Components/PageNotFound'; -import searchContext from 'Containers/searchContext'; - -import Dashboard from './Dashboard/ComplianceDashboardPage'; -import Entity from './Entity/Page'; -import List from './List/Page'; - -const complianceListPath = `:entityId1?/:entityType2?/:entityId2?`; -const complianceEntityPath = `:pageEntityId?/:entityType1?/:entityId1?/:entityType2?/:entityId2?`; - -const Page = () => ( - - - } /> - } /> - } /> - } /> - } /> - } /> - - } /> - } /> - } /> - } /> - } /> - } /> - - } /> - - -); - -export default memo(Page, isEqual); diff --git a/ui/apps/platform/src/Containers/Compliance/ScanButton.jsx b/ui/apps/platform/src/Containers/Compliance/ScanButton.jsx deleted file mode 100644 index 235d4cd851752..0000000000000 --- a/ui/apps/platform/src/Containers/Compliance/ScanButton.jsx +++ /dev/null @@ -1,90 +0,0 @@ -import { Component } from 'react'; -import { connect } from 'react-redux'; -import PropTypes from 'prop-types'; -import { Mutation } from '@apollo/client/react/components'; -import { RefreshCcw } from 'react-feather'; -import { Spinner } from '@patternfly/react-core'; - -import { actions as notificationActions } from 'reducers/notifications'; -import { TRIGGER_SCAN } from 'queries/standard'; -import Button from 'Components/Button'; - -class ScanButton extends Component { - static propTypes = { - className: PropTypes.string, - text: PropTypes.string.isRequired, - textCondensed: PropTypes.string, - textClass: PropTypes.string, - clusterId: PropTypes.string, - standardId: PropTypes.string, - loaderSize: PropTypes.number, - addToast: PropTypes.func.isRequired, - removeToast: PropTypes.func.isRequired, - onScanTriggered: PropTypes.func, - scanInProgress: PropTypes.bool, - }; - - static defaultProps = { - className: 'btn btn-base h-10', - clusterId: '*', - textClass: null, - textCondensed: null, - standardId: '*', - loaderSize: 20, - onScanTriggered: () => {}, - }; - - onClick = (triggerScan) => () => { - const { clusterId, standardId } = this.props; - triggerScan({ variables: { clusterId, standardId } }) - .then(() => { - this.props.onScanTriggered(); - }) - .catch((e) => { - this.props.addToast(e.message); - setTimeout(this.props.removeToast, 2000); - }); - }; - - render() { - const { className, text, textCondensed, textClass, loaderSize, scanInProgress } = - this.props; - - return ( - - {(triggerScan, { loading }) => { - return ( - - - ); - - contents = ( - - ); - } else if ( - data?.checks?.results?.length === 0 && - data?.results?.results?.length === 0 - ) { - contents = ( -
- No data available. Please run a scan. -
- ); - } - - return ( - - {contents} - - ); - }} - - ); -}; - -ComplianceByStandard.propTypes = { - standardName: PropTypes.string.isRequired, - standardId: PropTypes.string.isRequired, - entityName: PropTypes.string, - entityType: PropTypes.string, - entityId: PropTypes.string, - className: PropTypes.string, -}; - -ComplianceByStandard.defaultProps = { - entityId: null, - entityType: null, - entityName: null, - className: '', -}; - -export default ComplianceByStandard; diff --git a/ui/apps/platform/src/Containers/Compliance/widgets/ComplianceByStandards.tsx b/ui/apps/platform/src/Containers/Compliance/widgets/ComplianceByStandards.tsx deleted file mode 100644 index 6bf3709fe269e..0000000000000 --- a/ui/apps/platform/src/Containers/Compliance/widgets/ComplianceByStandards.tsx +++ /dev/null @@ -1,66 +0,0 @@ -import type { ReactElement } from 'react'; -import { useQuery } from '@apollo/client'; - -import Loader from 'Components/Loader'; -import { STANDARDS_QUERY } from 'queries/standard'; -import type { ComplianceStandardScope } from 'services/ComplianceService'; - -import ComplianceByStandard from './ComplianceByStandard'; - -type StandardsQueryDataType = { - results: { - id: string; - name: string; - scopes: ComplianceStandardScope[]; - hidden: boolean; - }[]; -}; - -type ComplianceByStandardsProps = { - entityId: string; - entityName: string; - entityType: ComplianceStandardScope; -}; - -function ComplianceByStandards({ - entityId, - entityName, - entityType, -}: ComplianceByStandardsProps): ReactElement { - const { loading, data, error } = useQuery(STANDARDS_QUERY); - if (loading) { - return ; - } - - if (error) { - return ( -
- A database error has occurred. Please check that you have the correct permissions to - view this information. -
- ); - } - - const standards = !data?.results - ? [] - : !entityType - ? data.results - : data.results.filter(({ scopes }) => scopes.includes(entityType)); - - return ( - <> - {standards.map(({ name: standardName, id: standardId }) => ( - - ))} - - ); -} - -export default ComplianceByStandards; diff --git a/ui/apps/platform/src/Containers/Compliance/widgets/ControlRelatedResourceList.jsx b/ui/apps/platform/src/Containers/Compliance/widgets/ControlRelatedResourceList.jsx deleted file mode 100644 index 832a72e6040a3..0000000000000 --- a/ui/apps/platform/src/Containers/Compliance/widgets/ControlRelatedResourceList.jsx +++ /dev/null @@ -1,148 +0,0 @@ -import { useContext } from 'react'; -import PropTypes from 'prop-types'; -import URLService from 'utils/URLService'; -import entityTypes from 'constants/entityTypes'; -import useCases from 'constants/useCaseTypes'; -import useWorkflowMatch from 'hooks/useWorkflowMatch'; -import { AGGREGATED_RESULTS as QUERY } from 'queries/controls'; -import queryService from 'utils/queryService'; -import { useLocation, Link } from 'react-router-dom-v5-compat'; -import searchContext from 'Containers/searchContext'; - -import { entityNounOrdinaryCase } from '../entitiesForCompliance'; -import LinkListWidget from './LinkListWidget'; - -const ControlRelatedResourceList = ({ - listEntityType, - pageEntityType, - pageEntity, - limit, - standard, - className, -}) => { - const linkContext = useCases.COMPLIANCE; - const searchParam = useContext(searchContext); - const location = useLocation(); - const match = useWorkflowMatch(); - - function processData(data) { - if (!data || !data.results) { - return []; - } - - const { clusters } = data; - let options = clusters; - if (listEntityType === entityTypes.NAMESPACE) { - options = - clusters?.reduce( - (acc, cluster) => - acc.concat( - cluster.namespaces.map((ns) => ({ - ...ns.metadata, - name: `${cluster?.name}/${ns?.metadata?.name}`, - })) - ), - [] - ) || []; - } else if (listEntityType === entityTypes.NODE) { - options = - clusters?.reduce( - (acc, cluster) => - acc.concat( - cluster.nodes.map((node) => ({ - ...node, - name: `${cluster?.name}/${node?.name}`, - })) - ), - [] - ) || []; - } else if (listEntityType === entityTypes.DEPLOYMENT) { - options = data.deployments || []; - } - - function getEntityName(id) { - const found = options.find((item) => item.id === id); - return found ? found.name : null; - } - - const ids = data.results.results - .filter((item) => item.numPassing > 0 || item.numFailing > 0) - .map((item) => item.aggregationKeys.find((key) => key.scope === listEntityType).id); - - const filteredIds = []; - ids.forEach((id) => { - if (!filteredIds.includes(id)) { - filteredIds.push(id); - } - }); - - const result = filteredIds.map((id) => ({ - label: getEntityName(id), - link: URLService.getURL(match, location).base(listEntityType, id).url(), - })); - - return result; - } - - function getHeadline(items) { - if (!items) { - return 'Loading...'; - } - const count = typeof items.length !== 'undefined' ? items.length : 0; - return `${count} related ${entityNounOrdinaryCase(count, listEntityType)}`; - } - - const viewAllLink = - pageEntity && pageEntity.id && listEntityType !== entityTypes.SECRET ? ( - - - - ) : null; - - const variables = { - groupBy: [pageEntityType, listEntityType], - unit: entityTypes.CONTROL, - where: queryService.objectToWhereClause({ [`${pageEntityType} ID`]: pageEntity.id }), - }; - - return ( - - ); -}; - -ControlRelatedResourceList.propTypes = { - listEntityType: PropTypes.string.isRequired, - pageEntityType: PropTypes.string.isRequired, - pageEntity: PropTypes.shape({ - id: PropTypes.string, - name: PropTypes.string, - }), - limit: PropTypes.number, - standard: PropTypes.string.isRequired, - className: PropTypes.string, -}; - -ControlRelatedResourceList.defaultProps = { - pageEntity: null, - limit: 10, - className: '', -}; - -export default ControlRelatedResourceList; diff --git a/ui/apps/platform/src/Containers/Compliance/widgets/EntityCompliance.jsx b/ui/apps/platform/src/Containers/Compliance/widgets/EntityCompliance.jsx deleted file mode 100644 index 17713fdf7f18e..0000000000000 --- a/ui/apps/platform/src/Containers/Compliance/widgets/EntityCompliance.jsx +++ /dev/null @@ -1,131 +0,0 @@ -import { useContext } from 'react'; -import PropTypes from 'prop-types'; -import { useLocation, useNavigate } from 'react-router-dom-v5-compat'; - -import Widget from 'Components/Widget'; -import ArcSingle from 'Components/visuals/ArcSingle'; -import Query from 'Components/CacheFirstQuery'; -import Loader from 'Components/Loader'; -import entityTypes, { standardBaseTypes } from 'constants/entityTypes'; -import useWorkflowMatch from 'hooks/useWorkflowMatch'; -import URLService from 'utils/URLService'; -import { AGGREGATED_RESULTS } from 'queries/controls'; -import queryService from 'utils/queryService'; -import NoResultsMessage from 'Components/NoResultsMessage'; -import { standardLabels } from 'messages/standards'; -import searchContext from 'Containers/searchContext'; - -import { entityNounSentenceCaseSingular } from '../entitiesForCompliance'; -import VerticalBarChart from './VerticalBarChart'; - -const EntityCompliance = ({ entityId, entityType, entityName, clusterName }) => { - const entityTypeLabel = entityNounSentenceCaseSingular[entityType]; - const searchParam = useContext(searchContext); - const match = useWorkflowMatch(); - const location = useLocation(); - const navigate = useNavigate(); - - function getBarData(results) { - return results - .filter((item) => item.numPassing + item.numFailing) - .map((item) => ({ - x: standardBaseTypes[item.aggregationKeys[0].id] || item.aggregationKeys[0].id, - y: (item.numPassing / (item.numPassing + item.numFailing)) * 100, - standard: item.aggregationKeys[0].id, - })); - } - - function getTotals(results) { - return results.reduce( - (acc, curr) => { - acc.numPassing += curr.numPassing; - acc.total += curr.numPassing + curr.numFailing; - return acc; - }, - { numPassing: 0, total: 0 } - ); - } - function valueClick(datum) { - const URL = URLService.getURL(match, location) - .base(entityTypes.CONTROL) - .query({ - [searchParam]: { - [entityType]: entityName, - [entityTypes.CLUSTER]: clusterName, - standard: standardLabels[datum.standard] || datum.x, - }, - }) - .url(); - - navigate(URL); - } - - const whereClause = { [`${entityType} ID`]: entityId, [entityTypes.CLUSTER]: clusterName }; - const variables = { - unit: entityTypes.CHECK, - groupBy: [entityTypes.STANDARD, entityType], - where: queryService.objectToWhereClause(whereClause), - }; - return ( - - {({ loading, data }) => { - let contents = ; - if (!loading && data && data.controls) { - // Frontend filtering of control results. - const { complianceStandards } = data; - const results = data.controls.results.filter((result) => { - const standardId = result.aggregationKeys[0].id; - return complianceStandards.some(({ id }) => id === standardId); - }); - - if (!results.length) { - contents = ( - - ); - } else { - const barData = getBarData(results); - const totals = getTotals(results); - const pct = - totals.total > 0 - ? Math.round((totals.numPassing / totals.total) * 100) - : 0; - contents = ( - <> -
-
- -
-
- -
-
- - ); - } - } - return {contents}; - }} -
- ); -}; -EntityCompliance.propTypes = { - entityId: PropTypes.string.isRequired, - entityType: PropTypes.string.isRequired, - entityName: PropTypes.string, - clusterName: PropTypes.string, -}; - -EntityCompliance.defaultProps = { - entityName: null, - clusterName: null, -}; - -export default EntityCompliance; diff --git a/ui/apps/platform/src/Containers/Compliance/widgets/HorizontalBarChart.jsx b/ui/apps/platform/src/Containers/Compliance/widgets/HorizontalBarChart.jsx deleted file mode 100644 index 2f6d9b1b86f5f..0000000000000 --- a/ui/apps/platform/src/Containers/Compliance/widgets/HorizontalBarChart.jsx +++ /dev/null @@ -1,207 +0,0 @@ -import { - FlexibleWidthXYPlot, - XAxis, - YAxis, - VerticalGridLines, - HorizontalBarSeries, - LabelSeries, -} from 'react-vis'; -import { Link, useNavigate } from 'react-router-dom-v5-compat'; -import PropTypes from 'prop-types'; -import merge from 'deepmerge'; - -import { getColor } from './colorsForCompliance'; - -const minimalMargin = { top: -15, bottom: 0, left: 0, right: 0 }; - -const sortByYValue = (a, b) => { - if (a.y < b.y) { - return -1; - } - if (a.y > b.y) { - return 1; - } - return 0; -}; - -const HorizontalBarChart = ({ - data, - containerProps = {}, - plotProps = {}, - seriesProps = {}, - valueFormat = (x) => x, - tickValues = [0, 25, 50, 75, 100], - minimal = false, -}) => { - const navigate = useNavigate(); - - const showLabel = (value) => value >= 10; - - const getLabelData = () => - data.sort(sortByYValue).map((item) => { - let label = ''; - // This prevents overlap between the value label and the axis label - if (showLabel(item.x)) { - label = (valueFormat && valueFormat(item.x).toString()) || ''; - } - const val = { - x: item.x - 5, - y: item.y, - yOffset: minimal ? -6 : -3, - label, - }; - // x offset for label - val.x -= val.label.length; - return val; - }); - - const onValueClickHandler = (datum) => { - if (datum.link) { - navigate(datum.link); - } - }; - - const getContainerProps = () => { - const defaultContainerProps = { - className: 'relative chart-container w-full horizontal-bar-responsive', - }; - return merge(defaultContainerProps, containerProps); - }; - - const getPlotProps = () => { - const sortedData = data.sort(sortByYValue); - // This determines how far to push the bar graph to the right based on the longest axis label character's length - const maxLength = sortedData.reduce((acc, curr) => Math.max(curr.y.length, acc), 0); - - // Magic number that makes the horizontal bars a reasonable size if there are fewer than 6 - // but shrinks them if there are 6 or more. - const yRangeMultiplier = Math.min(41, 210 / sortedData.length); - const yRange = [...sortedData.map((item, i) => (i + 1) * yRangeMultiplier), 0]; - const defaultPlotProps = { - height: minimal ? 25 : 350, - xDomain: [0, 102], - yType: 'category', - yRange, - margin: minimal ? minimalMargin : { top: 33.3, left: Math.ceil(maxLength * 7.5) }, - stackBy: 'x', - }; - return merge(defaultPlotProps, plotProps); - }; - - const getSeriesProps = () => { - const defaultSeriesProps = { - style: { - height: minimal ? 15 : 20, - rx: '2px', - cursor: `${minimal ? '' : 'pointer'}`, - }, - onValueMouseOver: null, - onValueMouseOut: null, - onValueClick: onValueClickHandler, - }; - return merge(defaultSeriesProps, seriesProps); - }; - - const sortedData = data.sort(sortByYValue); - - // Generate y axis links - const axisLinks = sortedData.reduce((acc, curr) => { - if (curr.link) { - acc[curr.y] = curr.link; - } - return acc; - }, {}); - - const containerPropsMerged = getContainerProps(); - const plotPropsMerged = getPlotProps(); - const seriesPropsMerged = getSeriesProps(); - - function tickFormat(value) { - let inner = value; - if (axisLinks[value]) { - inner = ( - - {value} - - ); - } - - return {inner}; - } - - return ( -
- - {/* Empty area bar background */} - - {!minimal && } - - {!minimal && ( - - )} - - {/* Empty Background */} - ({ - x: 0, - x0: Math.ceil(sortedData[0].x / 5) * 5, - y: item.y, - link: item.link, - }))} - color="var(--pf-t--color--gray--20)" - style={{ - height: seriesPropsMerged.style.height, - rx: '2', - ry: '2', - cursor: `${minimal ? '' : 'pointer'}`, - }} - onValueClick={onValueClickHandler} - /> - - {/* Values */} - ({ ...item, color: getColor(item.x) }))} - {...seriesPropsMerged} - colorType="literal" - /> - - - {!minimal && ( - - )} - -
- ); -}; - -HorizontalBarChart.propTypes = { - data: PropTypes.arrayOf(PropTypes.shape({})).isRequired, - containerProps: PropTypes.shape({}), - plotProps: PropTypes.shape({}), - seriesProps: PropTypes.shape({}), - valueFormat: PropTypes.func, - tickValues: PropTypes.arrayOf(PropTypes.number), - minimal: PropTypes.bool, -}; - -export default HorizontalBarChart; diff --git a/ui/apps/platform/src/Containers/Compliance/widgets/Labels.jsx b/ui/apps/platform/src/Containers/Compliance/widgets/Labels.jsx deleted file mode 100644 index 304cbcf7c4b42..0000000000000 --- a/ui/apps/platform/src/Containers/Compliance/widgets/Labels.jsx +++ /dev/null @@ -1,35 +0,0 @@ -import PropTypes from 'prop-types'; -import { Tooltip } from '@patternfly/react-core'; - -const truncate = (key) => { - const index = key.indexOf('/'); - return index > 0 ? key.substr(index + 1) : key; -}; - -const Labels = ({ labels }) => ( -
    4 ? `columns-2` : ``} p-3 w-full leading-normal`}> - {labels.map((label) => ( -
  • - - - {`${truncate(label.key)}:`} - {label.value || '""'} - - -
  • - ))} -
-); - -Labels.propTypes = { - labels: PropTypes.arrayOf(PropTypes.object).isRequired, -}; - -export default Labels; diff --git a/ui/apps/platform/src/Containers/Compliance/widgets/LinkListWidget.jsx b/ui/apps/platform/src/Containers/Compliance/widgets/LinkListWidget.jsx deleted file mode 100644 index ce4da2029b7a8..0000000000000 --- a/ui/apps/platform/src/Containers/Compliance/widgets/LinkListWidget.jsx +++ /dev/null @@ -1,132 +0,0 @@ -import PropTypes from 'prop-types'; -import { Link } from 'react-router-dom-v5-compat'; -import { Alert } from '@patternfly/react-core'; - -import Widget from 'Components/Widget'; -import Loader from 'Components/Loader'; -import Query from 'Components/ThrowingQuery'; -import NoResultsMessage from 'Components/NoResultsMessage'; - -function getLI(item) { - if (!item) { - return null; - } - - const content = item.link ? ( - - {item.label} - - ) : ( - item.label - ); - return ( -
  • - {content} -
  • - ); -} - -const LinkListWidget = ({ - query, - variables, - processData, - getHeadline, - className, - headerComponents, - limit, - id, - showEmpty, -}) => ( - - {({ loading, data, error }) => { - let contents; - let headline = getHeadline(); - - if (loading) { - contents = ; - } else if (error) { - contents = ( - - {error} - - ); - } else if (data) { - const items = processData(data); - headline = getHeadline(items); - - if (items.length === 0) { - if (!showEmpty) { - return null; - } - contents = ; - } else { - contents = ( -
      5 ? `columns-2` : `columns-1` - } p-3 py-1 w-full leading-normal overflow-hidden`} - > - {items.slice(0, limit).map((item) => getLI(item))} -
    - ); - } - } - - return ( - - {contents} - - ); - }} -
    -); - -LinkListWidget.propTypes = { - query: PropTypes.shape({}).isRequired, - variables: PropTypes.shape({}), - processData: PropTypes.func, - getHeadline: PropTypes.func, - className: PropTypes.string, - headerComponents: PropTypes.node, - limit: PropTypes.number, - showEmpty: PropTypes.bool, - id: PropTypes.string, -}; - -LinkListWidget.defaultProps = { - variables: null, - processData(data) { - return data; - }, - getHeadline() { - return null; - }, - className: '', - headerComponents: null, - limit: 10, - showEmpty: false, - id: 'link-list-widget', -}; - -export default LinkListWidget; diff --git a/ui/apps/platform/src/Containers/Compliance/widgets/ResourceCount.jsx b/ui/apps/platform/src/Containers/Compliance/widgets/ResourceCount.jsx deleted file mode 100644 index 838b8f6795c71..0000000000000 --- a/ui/apps/platform/src/Containers/Compliance/widgets/ResourceCount.jsx +++ /dev/null @@ -1,100 +0,0 @@ -import { useContext } from 'react'; -import { useLocation } from 'react-router-dom-v5-compat'; -import PropTypes from 'prop-types'; -import capitalize from 'lodash/capitalize'; - -import entityTypes from 'constants/entityTypes'; -import URLService from 'utils/URLService'; -import Widget from 'Components/Widget'; -import Query from 'Components/CacheFirstQuery'; -import Loader from 'Components/Loader'; -import CountWidget from 'Components/CountWidget'; -import useWorkflowMatch from 'hooks/useWorkflowMatch'; -import { SEARCH_WITH_CONTROLS as QUERY } from 'queries/search'; -import queryService from 'utils/queryService'; -import useCases from 'constants/useCaseTypes'; -import searchContext from 'Containers/searchContext'; - -import { getResourceCountFromAggregatedResults } from '../complianceUtils'; -import { entityNounSentenceCaseSingular } from '../entitiesForCompliance'; - -const ResourceCount = ({ entityType, relatedToResourceType, relatedToResource }) => { - const searchParam = useContext(searchContext); - const match = useWorkflowMatch(); - const location = useLocation(); - - function getUrl() { - if (entityType === entityTypes.SECRET) { - return URLService.getURL(match, location) - .set('context', useCases.SECRET) - .query({ - [searchParam]: { - [`${capitalize(relatedToResourceType)}`]: relatedToResource?.name, - }, - }) - .url(); - } - - return URLService.getURL(match, location) - .base(relatedToResourceType, relatedToResource.id) - .push(entityType) - .url(); - } - - function getVariables() { - let query; - switch (relatedToResourceType) { - case entityTypes.NAMESPACE: - query = { - namespace: relatedToResource.name, - cluster: relatedToResource.clusterName, - }; - break; - default: - query = { [`${capitalize(relatedToResourceType)} ID`]: relatedToResource.id }; - } - - return { - query: queryService.objectToWhereClause(query), - categories: [], - }; - } - - const variables = getVariables(); - const headerText = `${entityNounSentenceCaseSingular[entityType]} Count`; - const url = getUrl(); - - return ( - - {({ loading, data }) => { - const contents = ; - if (!loading && data) { - const resourceCount = getResourceCountFromAggregatedResults(entityType, data); - - return ; - } - return ( - - {contents} - - ); - }} - - ); -}; - -ResourceCount.propTypes = { - entityType: PropTypes.string.isRequired, - relatedToResourceType: PropTypes.string.isRequired, - relatedToResource: PropTypes.shape({ - id: PropTypes.string, - name: PropTypes.string, - clusterName: PropTypes.string, - }), -}; - -ResourceCount.defaultProps = { - relatedToResource: null, -}; - -export default ResourceCount; diff --git a/ui/apps/platform/src/Containers/Compliance/widgets/StandardsAcrossEntity.jsx b/ui/apps/platform/src/Containers/Compliance/widgets/StandardsAcrossEntity.jsx deleted file mode 100644 index 0682497ca2e46..0000000000000 --- a/ui/apps/platform/src/Containers/Compliance/widgets/StandardsAcrossEntity.jsx +++ /dev/null @@ -1,148 +0,0 @@ -import { useContext } from 'react'; -import PropTypes from 'prop-types'; -import { useLocation } from 'react-router-dom-v5-compat'; -import { useQuery } from '@apollo/client'; -import merge from 'lodash/merge'; - -import entityTypes, { standardBaseTypes } from 'constants/entityTypes'; -import { standardLabels } from 'messages/standards'; -import URLService from 'utils/URLService'; -import Widget from 'Components/Widget'; -import Loader from 'Components/Loader'; -import NoResultsMessage from 'Components/NoResultsMessage'; -import useWorkflowMatch from 'hooks/useWorkflowMatch'; -import { AGGREGATED_RESULTS_ACROSS_ENTITY } from 'queries/controls'; -import searchContext from 'Containers/searchContext'; - -import { entityNounOrdinaryCasePlural } from '../entitiesForCompliance'; -import HorizontalBarChart from './HorizontalBarChart'; - -function formatAsPercent(x) { - return `${x}%`; -} - -function setStandardsMapping(data, key, type) { - const mapping = {}; - data[key].results.forEach((result) => { - const standardId = result.aggregationKeys[0].id; - if (!data.complianceStandards.some(({ id }) => id === standardId)) { - return; // because it implies standardId has hideScanResults: true - } - const { numPassing, numFailing } = result; - if (numPassing === 0 && numFailing === 0) { - return; - } - if (!mapping[standardId]) { - mapping[standardId] = {}; - mapping[standardId][type] = { - passing: numPassing, - total: numPassing + numFailing, - }; - } else { - const { passing, total } = mapping[standardId][type]; - mapping[standardId][type] = { - passing: passing + numPassing, - total: total + (numPassing + numFailing), - }; - } - }); - - return mapping; -} - -const StandardsAcrossEntity = ({ entityType, bodyClassName, className }) => { - const searchParam = useContext(searchContext); - const match = useWorkflowMatch(); - const location = useLocation(); - const headerText = `Passing standards across ${entityNounOrdinaryCasePlural[entityType]}`; - - function processData(data, type) { - if (!data || !data.controls || !data.controls.results.length) { - return []; - } - const standardsMapping = merge( - {}, - setStandardsMapping(data, 'results', 'checks'), - setStandardsMapping(data, 'controls', 'controls') - ); - - const barData = Object.keys(standardsMapping).map((standardId) => { - const { controls } = standardsMapping[standardId]; - const { passing: passingControls, total: totalControls } = controls; - const percentagePassing = Math.round((passingControls / totalControls) * 100) || 0; - const link = URLService.getURL(match, location) - .base(entityTypes.CONTROL) - .query({ - [searchParam]: { - groupBy: type, - standard: standardLabels[standardId] || standardId, - }, - }) - .url(); - const dataPoint = { - y: standardBaseTypes[standardId] || standardId, - x: percentagePassing, - link, - }; - return dataPoint; - }); - return barData; - } - - const variables = { - groupBy: [entityTypes.STANDARD, entityType], - unit: entityTypes.CHECK, - }; - const { loading, error, data } = useQuery(AGGREGATED_RESULTS_ACROSS_ENTITY(entityType), { - variables, - }); - - if (error) { - return ( - -
    - A database error has occurred. Please check that you have the correct - permissions to view this information. -
    -
    - ); - } - - let contents; - if (!loading && data && data.complianceStandards) { - const results = processData(data, entityType); - if (!results.length) { - contents = ; - } else { - contents = ; - } - } else { - contents = ; - } - return ( - - {contents} - - ); -}; - -StandardsAcrossEntity.propTypes = { - entityType: PropTypes.string.isRequired, - bodyClassName: PropTypes.string, - className: PropTypes.string, -}; - -StandardsAcrossEntity.defaultProps = { - bodyClassName: 'px-4 pt-1', - className: '', -}; - -export default StandardsAcrossEntity; diff --git a/ui/apps/platform/src/Containers/Compliance/widgets/StandardsByEntity.jsx b/ui/apps/platform/src/Containers/Compliance/widgets/StandardsByEntity.jsx deleted file mode 100644 index b500f36f0d675..0000000000000 --- a/ui/apps/platform/src/Containers/Compliance/widgets/StandardsByEntity.jsx +++ /dev/null @@ -1,179 +0,0 @@ -import { useContext } from 'react'; -import PropTypes from 'prop-types'; -import { useLocation } from 'react-router-dom-v5-compat'; -import { useQuery } from '@apollo/client'; -import capitalize from 'lodash/capitalize'; -import sortBy from 'lodash/sortBy'; -import chunk from 'lodash/chunk'; - -import entityTypes from 'constants/entityTypes'; -import URLService from 'utils/URLService'; -import Widget from 'Components/Widget'; -import Loader from 'Components/Loader'; -import NoResultsMessage from 'Components/NoResultsMessage'; -import useWorkflowMatch from 'hooks/useWorkflowMatch'; -import { standardLabels } from 'messages/standards'; -import { AGGREGATED_RESULTS_STANDARDS_BY_ENTITY } from 'queries/controls'; -import searchContext from 'Containers/searchContext'; - -import { entityNounOrdinaryCaseSingular } from '../entitiesForCompliance'; -import VerticalClusterBar from './VerticalClusterBar'; - -function processData(match, location, data, entityType, searchParam) { - if (!data || !data.controls.results.length || !data.entityList) { - return []; - } - const standardsGrouping = {}; - const { controls, entityList, complianceStandards } = data; - controls.results.forEach((result) => { - const entity = entityList.find( - (entityObject) => entityObject.id === result.aggregationKeys[1].id - ); - if (!entity) { - return; - } - const standard = complianceStandards.find((c) => c.id === result.aggregationKeys[0].id); - const { numPassing, numFailing } = result; - if (!standard || (numPassing === 0 && numFailing === 0)) { - return; - } - const percentagePassing = Math.round((numPassing / (numPassing + numFailing)) * 100); - - const link = URLService.getURL(match, location) - .base(entityTypes.CONTROL) - .query({ - [searchParam]: { - [`${capitalize(entityType)}`]: entity?.name, - standard: standardLabels[standard.id] || standard.id, - }, - }) - .url(); - const dataPoint = { - x: entity?.name, - y: percentagePassing, - link, - }; - const standardGroup = standardsGrouping[standard.id]; - if (standardGroup) { - standardGroup.push(dataPoint); - } else { - standardsGrouping[standard.id] = [dataPoint]; - } - }); - const sortedStandardsGrouping = {}; - const GRAPHS_PER_PAGE = 3; - const pagedStandardsGrouping = []; - - Object.keys(standardsGrouping).forEach((standard) => { - sortedStandardsGrouping[standard] = sortBy(standardsGrouping[standard], ['x']); - const pageArray = chunk(sortedStandardsGrouping[standard], GRAPHS_PER_PAGE); - pageArray.forEach((page, pageIdx) => { - if (!pagedStandardsGrouping[pageIdx]) { - pagedStandardsGrouping[pageIdx] = {}; - } - pagedStandardsGrouping[pageIdx][standard] = pageArray[pageIdx]; - }); - }); - return pagedStandardsGrouping; -} - -function getLabelLinks(match, location, data, entityType) { - if (!data) { - return null; - } - const { entityList } = data; - const labelLinks = {}; - entityList.forEach((entity) => { - labelLinks[entity?.name] = URLService.getURL(match, location) - .base(entityType, entity?.id) - .url(); - }); - return labelLinks; -} - -const StandardsByEntity = ({ entityType, bodyClassName, className }) => { - const searchParam = useContext(searchContext); - const match = useWorkflowMatch(); - const location = useLocation(); - const headerText = `Passing standards by ${entityNounOrdinaryCaseSingular[entityType]}`; - - const variables = { - groupBy: [entityTypes.STANDARD, entityType], - unit: entityTypes.CHECK, - }; - const { loading, error, data } = useQuery(AGGREGATED_RESULTS_STANDARDS_BY_ENTITY(entityType), { - variables, - }); - - if (error) { - return ( - -
    - A database error has occurred. Please check that you have the correct - permissions to view this information. -
    -
    - ); - } - - let contents = ; - let pages; - - if (!loading) { - if (!data || !data.results || data.results.length === 0) { - contents = ; - } else { - const formattedData = { - results: data && data.results, - controls: data && data.controls, - complianceStandards: data.complianceStandards, - entityList: data && data.clusters, - }; - const results = processData(match, location, formattedData, entityType, searchParam); - const labelLinks = getLabelLinks(match, location, formattedData, entityType); - pages = results.length; - - if (pages) { - const VerticalBarChartPaged = ({ currentPage }) => ( - - ); - VerticalBarChartPaged.propTypes = { currentPage: PropTypes.number }; - VerticalBarChartPaged.defaultProps = { currentPage: 0 }; - contents = ; - } else { - contents = ; - } - } - } - - return ( - - {contents} - - ); -}; -StandardsByEntity.propTypes = { - entityType: PropTypes.string.isRequired, - bodyClassName: PropTypes.string, - className: PropTypes.string, -}; - -StandardsByEntity.defaultProps = { - bodyClassName: 'p-4', - className: '', -}; - -export default StandardsByEntity; diff --git a/ui/apps/platform/src/Containers/Compliance/widgets/VerticalBarChart.jsx b/ui/apps/platform/src/Containers/Compliance/widgets/VerticalBarChart.jsx deleted file mode 100644 index 6ecbc9cbe44e1..0000000000000 --- a/ui/apps/platform/src/Containers/Compliance/widgets/VerticalBarChart.jsx +++ /dev/null @@ -1,112 +0,0 @@ -import { Component } from 'react'; -import { - FlexibleWidthXYPlot, - XAxis, - YAxis, - VerticalGridLines, - HorizontalGridLines, - VerticalBarSeries, -} from 'react-vis'; -import PropTypes from 'prop-types'; -import merge from 'deepmerge'; - -import { verticalBarColors } from './colorsForCompliance'; - -const sortByXValue = (a, b) => { - if (a.x < b.x) { - return -1; - } - if (a.x > b.x) { - return 1; - } - return 0; -}; - -// Component state was needed only for deleted HoverHint, but we will not rewrite. -class VerticalBarChart extends Component { - static propTypes = { - data: PropTypes.arrayOf(PropTypes.object).isRequired, - containerProps: PropTypes.shape({}), - plotProps: PropTypes.shape({}), - seriesProps: PropTypes.shape({}), - tickValues: PropTypes.arrayOf(PropTypes.number), - tickFormat: PropTypes.func, - onValueClick: PropTypes.func, - legend: PropTypes.bool, - }; - - static defaultProps = { - containerProps: {}, - plotProps: {}, - seriesProps: {}, - tickValues: [25, 50, 75, 100], - tickFormat: (x) => `${x}%`, - onValueClick: null, - legend: true, - }; - - render() { - const { tickValues, tickFormat, onValueClick } = this.props; - - const data = this.props.data.sort(sortByXValue); - - // Default props - const defaultPlotProps = { - xType: 'ordinal', - height: 250, - colorType: 'category', - yDomain: [0, 110], - }; - - const defaultContainerProps = { - className: 'relative chart-container w-full horizontal-bar-responsive', - }; - - const defaultSeriesProps = { - barWidth: 0.25, - style: { - opacity: '.8', - ry: '2px', - cursor: 'pointer', - }, - - colorDomain: data.map((datum) => datum.y), - colorRange: verticalBarColors, - onValueClick: (datum) => { - if (onValueClick) { - onValueClick(datum); - } - }, - }; - - // Merge props - const containerProps = merge(defaultContainerProps, this.props.containerProps); - const plotProps = merge(defaultPlotProps, this.props.plotProps); - const seriesProps = merge(defaultSeriesProps, this.props.seriesProps); - const styleProps = this.props.legend ? { top: '-16px' } : {}; - - // format data with colors: - const letDataWithColors = data.map((datum, i) => ({ - ...datum, - color: verticalBarColors[i % verticalBarColors.length], - })); - - function formatTicks(value) { - return {value}; - } - - return ( -
    - - - - - - - -
    - ); - } -} - -export default VerticalBarChart; diff --git a/ui/apps/platform/src/Containers/Compliance/widgets/VerticalClusterBar.jsx b/ui/apps/platform/src/Containers/Compliance/widgets/VerticalClusterBar.jsx deleted file mode 100644 index 094a7b81a0bf8..0000000000000 --- a/ui/apps/platform/src/Containers/Compliance/widgets/VerticalClusterBar.jsx +++ /dev/null @@ -1,152 +0,0 @@ -import { - FlexibleXYPlot, - XAxis, - YAxis, - VerticalGridLines, - HorizontalGridLines, - VerticalBarSeries, -} from 'react-vis'; -import PropTypes from 'prop-types'; -import { Link, useNavigate } from 'react-router-dom-v5-compat'; -import DiscreteColorLegend from 'react-vis/dist/legends/discrete-color-legend'; -import merge from 'deepmerge'; - -import { standardBaseTypes } from 'constants/entityTypes'; - -import { verticalBarColors } from './colorsForCompliance'; - -function VerticalClusterBar({ - id = '', - data, - containerProps = {}, - plotProps = {}, - seriesProps = {}, - tickValues = [25, 50, 75, 100], - tickFormat = (x) => `${x}%`, - labelLinks = {}, -}) { - const navigate = useNavigate(); - - const getLegendData = () => { - return Object.keys(data) - .sort() - .map((key, i) => ({ - title: standardBaseTypes[key] || key, - color: verticalBarColors[i % verticalBarColors.length], - })); - }; - - // Default props - const defaultPlotProps = { - xType: 'ordinal', - yDomain: [0, 100], - height: 270, - }; - - const defaultContainerProps = { - className: 'relative chart-container w-full horizontal-bar-responsive', - }; - - const defaultSeriesProps = { - // animation: true, //causes onValueMouseOut to fail https://github.com/uber/react-vis/issues/381 - barWidth: 0.5, - style: { - opacity: '.85', - width: '10px', - ry: '2px', - cursor: 'pointer', - }, - onValueClick: (datum) => { - if (datum.link) { - navigate(datum.link); - } - }, - }; - - // Merge props - const containerPropsMerged = merge(defaultContainerProps, containerProps); - const plotPropsMerged = merge(defaultPlotProps, plotProps); - const seriesPropsMerged = merge(defaultSeriesProps, seriesProps); - - function formatTicks(value) { - let inner = value; - if (labelLinks[value]) { - inner = ( - - {value} - - ); - } - - return {inner}; - } - - // Calculate unique cluster names - let clusterNames = new Set(); - Object.keys(data).forEach((dataSetKey) => { - const dataSet = data[dataSetKey]; - dataSet.forEach((datum) => { - clusterNames.add(datum.x); - }); - }); - clusterNames = Array.from(clusterNames); - - // Create Barseries for each data set - const series = []; - Object.keys(data) - .sort() - .forEach((key, i) => { - series.push( - - ); - }); - - return ( -
    -
    - - - - - {series} - - - -
    - -
    -
    -
    - ); -} - -VerticalClusterBar.propTypes = { - id: PropTypes.string, - data: PropTypes.shape({}).isRequired, - containerProps: PropTypes.shape({}), - plotProps: PropTypes.shape({}), - seriesProps: PropTypes.shape({}), - tickValues: PropTypes.arrayOf(PropTypes.number), - tickFormat: PropTypes.func, - labelLinks: PropTypes.shape({}), -}; - -export default VerticalClusterBar; diff --git a/ui/apps/platform/src/Containers/Compliance/widgets/colorsForCompliance.ts b/ui/apps/platform/src/Containers/Compliance/widgets/colorsForCompliance.ts deleted file mode 100644 index cdd9e12529b41..0000000000000 --- a/ui/apps/platform/src/Containers/Compliance/widgets/colorsForCompliance.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { - COMPLIANCE_PASS_COLOR, - CRITICAL_SEVERITY_COLOR, - IMPORTANT_HIGH_SEVERITY_COLOR, - MODERATE_MEDIUM_SEVERITY_COLOR, - noViolationsColor, -} from 'constants/severityColors'; - -export function getColor(value: number) { - if (value === 100) { - return COMPLIANCE_PASS_COLOR; - } - if (value >= 70) { - return MODERATE_MEDIUM_SEVERITY_COLOR; - } - if (value >= 50) { - return IMPORTANT_HIGH_SEVERITY_COLOR; - } - if (Number.isNaN(value)) { - return noViolationsColor; // skipped - } - return CRITICAL_SEVERITY_COLOR; -} - -// For example, Passing Standards by Clusters chart. -export const verticalBarColors = [ - 'var(--base-700)', - 'var(--primary-700)', - 'var(--secondary-700)', - 'var(--base-400)', - 'var(--primary-400)', - 'var(--secondary-400)', -]; diff --git a/ui/apps/platform/src/Containers/ComplianceEnhanced/Coverage/ClusterDetailsPage.tsx b/ui/apps/platform/src/Containers/ComplianceEnhanced/Coverage/ClusterDetailsPage.tsx index be117d5e6a811..a431bbf61140d 100644 --- a/ui/apps/platform/src/Containers/ComplianceEnhanced/Coverage/ClusterDetailsPage.tsx +++ b/ui/apps/platform/src/Containers/ComplianceEnhanced/Coverage/ClusterDetailsPage.tsx @@ -132,7 +132,7 @@ function ClusterDetailsPage() { return ( <> - + - )} - - - + + Scan schedules @@ -20,16 +20,10 @@ function CreateScanConfigPage(): ReactElement { Create scan schedule - - - - Create scan schedule - - - - - + + Create scan schedule + ); } diff --git a/ui/apps/platform/src/Containers/ComplianceEnhanced/Schedules/EditScanConfigDetail.tsx b/ui/apps/platform/src/Containers/ComplianceEnhanced/Schedules/EditScanConfigDetail.tsx index 6ed9bef795cf7..44b54dafe5190 100644 --- a/ui/apps/platform/src/Containers/ComplianceEnhanced/Schedules/EditScanConfigDetail.tsx +++ b/ui/apps/platform/src/Containers/ComplianceEnhanced/Schedules/EditScanConfigDetail.tsx @@ -4,9 +4,6 @@ import { Breadcrumb, BreadcrumbItem, Bullseye, - Divider, - Flex, - FlexItem, PageSection, Spinner, Title, @@ -17,7 +14,7 @@ import PageTitle from 'Components/PageTitle'; import BreadcrumbItemLink from 'Components/BreadcrumbItemLink'; import type { ComplianceScanConfigurationStatus } from 'services/ComplianceScanConfigurationService'; import { getAxiosErrorMessage } from 'utils/responseErrorUtils'; -import ScanConfigWizardForm from './Wizard/ScanConfigWizardForm'; +import ScanConfigWizardPageSection from './Wizard/ScanConfigWizardPageSection'; import { defaultScanConfigFormValues } from './Wizard/useFormikScanConfig'; import { convertScanConfigToFormik } from './compliance.scanConfigs.utils'; @@ -38,53 +35,50 @@ function EditScanConfigDetail({ return ( <> - + Scan schedules - {!isLoading && !error && scanConfig && ( + {scanConfig && ( Edit {scanConfig.scanName} )} - - {!isLoading && !error && scanConfig && ( - - - Edit {scanConfig.scanName} - - - )} - - - - {isLoading ? ( + {isLoading ? ( + - ) : ( - error && ( - - {getAxiosErrorMessage(error)} - - ) - )} - {!isLoading && scanConfig && ( - - - - )} - + + ) : ( + <> + {scanConfig && ( + + Edit {scanConfig.scanName} + + )} + {error && ( + + + {getAxiosErrorMessage(error)} + + + )} + {scanConfig && ( + + )} + + )} ); } diff --git a/ui/apps/platform/src/Containers/ComplianceEnhanced/Schedules/ScanConfigDetailPage.tsx b/ui/apps/platform/src/Containers/ComplianceEnhanced/Schedules/ScanConfigDetailPage.tsx index 9b2898d1beb44..e6f587d39f9b8 100644 --- a/ui/apps/platform/src/Containers/ComplianceEnhanced/Schedules/ScanConfigDetailPage.tsx +++ b/ui/apps/platform/src/Containers/ComplianceEnhanced/Schedules/ScanConfigDetailPage.tsx @@ -8,7 +8,7 @@ import useRestQuery from 'hooks/useRestQuery'; import { getComplianceScanConfiguration } from 'services/ComplianceScanConfigurationService'; import EditScanConfigDetail from './EditScanConfigDetail'; import ViewScanConfigDetail from './ViewScanConfigDetail'; -import type { PageActions } from './compliance.scanConfigs.utils'; +import type { SchedulePageAction } from './compliance.scanConfigs.utils'; type ScanConfigDetailPageProps = { hasWriteAccessForCompliance: boolean; @@ -18,7 +18,7 @@ function ScanConfigDetailPage({ hasWriteAccessForCompliance, }: ScanConfigDetailPageProps): ReactElement { const { scanConfigId } = useParams() as { scanConfigId: string }; - const { pageAction } = usePageAction(); + const { pageAction } = usePageAction(); const scanConfigFetcher = useCallback(() => { const { request, cancel } = getComplianceScanConfiguration(scanConfigId); diff --git a/ui/apps/platform/src/Containers/ComplianceEnhanced/Schedules/ScanConfigsPage.tsx b/ui/apps/platform/src/Containers/ComplianceEnhanced/Schedules/ScanConfigsPage.tsx index 6e98bdcfacc63..3b25225ef7acc 100644 --- a/ui/apps/platform/src/Containers/ComplianceEnhanced/Schedules/ScanConfigsPage.tsx +++ b/ui/apps/platform/src/Containers/ComplianceEnhanced/Schedules/ScanConfigsPage.tsx @@ -4,7 +4,7 @@ import { Banner } from '@patternfly/react-core'; import usePageAction from 'hooks/usePageAction'; import usePermissions from 'hooks/usePermissions'; import { complianceEnhancedSchedulesPath } from 'routePaths'; -import type { PageActions } from './compliance.scanConfigs.utils'; +import type { SchedulePageAction } from './compliance.scanConfigs.utils'; import CreateScanConfigPage from './CreateScanConfigPage'; import ComplianceNotFoundPage from '../ComplianceNotFoundPage'; import ScanConfigDetailPage from './ScanConfigDetailPage'; @@ -17,7 +17,7 @@ function ScanConfigsPage() { * /main/compliance-enhanced/scan-configs?action=create * /main/compliance-enhanced/scan-configs/configId */ - const { pageAction } = usePageAction(); + const { pageAction } = usePageAction(); const { hasReadWriteAccess } = usePermissions(); const hasWriteAccessForCompliance = hasReadWriteAccess('Compliance'); diff --git a/ui/apps/platform/src/Containers/ComplianceEnhanced/Schedules/ViewScanConfigDetail.tsx b/ui/apps/platform/src/Containers/ComplianceEnhanced/Schedules/ViewScanConfigDetail.tsx index 2eedb04bd92ba..097da5d7bd50b 100644 --- a/ui/apps/platform/src/Containers/ComplianceEnhanced/Schedules/ViewScanConfigDetail.tsx +++ b/ui/apps/platform/src/Containers/ComplianceEnhanced/Schedules/ViewScanConfigDetail.tsx @@ -5,8 +5,6 @@ import { AlertActionCloseButton, Breadcrumb, BreadcrumbItem, - Card, - CardBody, Flex, FlexItem, PageSection, @@ -211,15 +209,7 @@ function ViewScanConfigDetail({ {activeScanConfigTab === 'CONFIGURATION_DETAILS' && ( - - - - - + )} {activeScanConfigTab === 'ALL_REPORT_JOBS' && scanConfig?.id && ( diff --git a/ui/apps/platform/src/Containers/ComplianceEnhanced/Schedules/Wizard/ProfileSelection.tsx b/ui/apps/platform/src/Containers/ComplianceEnhanced/Schedules/Wizard/ProfileSelection.tsx deleted file mode 100644 index 2de996d4ed04a..0000000000000 --- a/ui/apps/platform/src/Containers/ComplianceEnhanced/Schedules/Wizard/ProfileSelection.tsx +++ /dev/null @@ -1,234 +0,0 @@ -import { useCallback, useState } from 'react'; -import type { FormEvent, ReactElement, RefObject } from 'react'; -import { useFormikContext } from 'formik'; -import type { FormikContextType } from 'formik'; -import { - Alert, - Content, - Divider, - Flex, - FlexItem, - Form, - PageSection, - Title, - Toolbar, - ToolbarContent, - ToolbarGroup, -} from '@patternfly/react-core'; -import { ExpandableRowContent, Table, Tbody, Td, Th, Thead, Tr } from '@patternfly/react-table'; - -import CompoundSearchFilter from 'Components/CompoundSearchFilter/components/CompoundSearchFilter'; -import CompoundSearchFilterLabels from 'Components/CompoundSearchFilter/components/CompoundSearchFilterLabels'; -import type { OnSearchCallback } from 'Components/CompoundSearchFilter/types'; -import { updateSearchFilter } from 'Components/CompoundSearchFilter/utils/utils'; -import TBodyUnified from 'Components/TableStateTemplates/TbodyUnified'; -import useRestQuery from 'hooks/useRestQuery'; -import useTableSelection from 'hooks/useTableSelection'; -import type { ComplianceProfileSummary } from 'services/ComplianceCommon'; -import { listProfileSummaries } from 'services/ComplianceProfileService'; -import type { SearchFilter } from 'types/search'; -import { getTableUIState } from 'utils/getTableUIState'; - -import { complianceProfileOperatorKindLabels } from '../../compliance.constants'; -import { profileSearchFilterConfig } from '../../searchFilterConfig'; -import type { ScanConfigFormValues } from '../compliance.scanConfigs.utils'; - -const searchFilterConfig = [profileSearchFilterConfig]; - -export type ProfileSelectionProps = { - alertRef: RefObject; - clusterIds: string[]; -}; - -function ProfileSelection({ alertRef, clusterIds }: ProfileSelectionProps): ReactElement { - const { - setFieldValue, - values: formikValues, - touched: formikTouched, - }: FormikContextType = useFormikContext(); - - const [searchFilter, setSearchFilter] = useState({}); - const [expandedProfileNames, setExpandedProfileNames] = useState([]); - const setProfileExpanded = (name: string, isExpanding = true) => - setExpandedProfileNames((prevExpanded) => { - const otherExpandedProfileNames = prevExpanded.filter( - (profileName) => profileName !== name - ); - return isExpanding ? [...otherExpandedProfileNames, name] : otherExpandedProfileNames; - }); - - const onSearch: OnSearchCallback = (payload) => { - setSearchFilter((prevSearchFilter) => updateSearchFilter(prevSearchFilter, payload)); - }; - - const listProfilesQuery = useCallback(() => { - if (clusterIds.length > 0) { - return listProfileSummaries(clusterIds, searchFilter); - } - return Promise.resolve([]); - }, [clusterIds, searchFilter]); - const { - data: profiles, - isLoading: isFetchingProfiles, - error: profilesFetchError, - } = useRestQuery(listProfilesQuery); - - const profileList = profiles ?? []; - - const profileIsPreSelected = useCallback( - (row) => formikValues.profiles.includes(row.name), - [formikValues.profiles] - ); - - const { selected, onSelect } = useTableSelection(profileList, profileIsPreSelected, 'name'); - - const handleSelect = ( - event: FormEvent, - isSelected: boolean, - rowId: number - ) => { - onSelect(event, isSelected, rowId); - - const visibleSelectedNames = profileList - .filter((_, index) => { - return index === rowId ? isSelected : selected[index]; - }) - .map((profile) => profile.name); - - const hiddenSelectedNames = formikValues.profiles.filter( - (name) => !profileList.some((p) => p.name === name) - ); - - setFieldValue('profiles', [...hiddenSelectedNames, ...visibleSelectedNames]); - }; - - const isProfileExpanded = (name: string) => expandedProfileNames.includes(name); - const totalColumns = 7; - - const tableState = getTableUIState({ - isLoading: isFetchingProfiles, - data: profiles, - error: profilesFetchError, - searchFilter, - }); - - return ( - <> - - - - Profiles - - Select profiles to be included in the scan - - - -
    - {formikTouched.profiles && formikValues.profiles.length === 0 && ( - - )} - - - - - - - - -
    - - - - - - - - - - - tableState={tableState} - colSpan={totalColumns} - filteredEmptyProps={{ onClearFilters: () => setSearchFilter({}) }} - renderer={({ data }) => - data.map( - ( - { - description, - name, - productType, - ruleCount, - title, - profileVersion, - operatorKind, - }, - rowIndex - ) => ( - - - - - - - - - - - - - ) - ) - } - /> -
    - - ProfileTypeRule setApplicabilityVersion
    - handleSelect(event, isSelected, rowIndex), - isSelected: selected[rowIndex], - }} - /> - - setProfileExpanded( - name, - !isProfileExpanded(name) - ), - }} - /> - {name} - {(operatorKind && - complianceProfileOperatorKindLabels[ - operatorKind - ]) ?? - '—'} - {ruleCount}{productType}{profileVersion || '-'}
    - - {title} - {description} - -
    - - - ); -} - -export default ProfileSelection; diff --git a/ui/apps/platform/src/Containers/ComplianceEnhanced/Schedules/Wizard/ReportConfiguration.tsx b/ui/apps/platform/src/Containers/ComplianceEnhanced/Schedules/Wizard/ReportConfiguration.tsx deleted file mode 100644 index 93093abad42ee..0000000000000 --- a/ui/apps/platform/src/Containers/ComplianceEnhanced/Schedules/Wizard/ReportConfiguration.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import type { ReactElement } from 'react'; -import { useFormikContext } from 'formik'; -import type { FormikContextType } from 'formik'; -import { Divider, Flex, FlexItem, Form, PageSection, Title } from '@patternfly/react-core'; - -import NotifierConfigurationForm from 'Components/NotifierConfiguration/NotifierConfigurationForm'; -import usePermissions from 'hooks/usePermissions'; - -// import { getBodyDefault, getSubjectDefault } from '../compliance.scanConfigs.utils'; -import type { ScanConfigFormValues } from '../compliance.scanConfigs.utils'; - -function ReportConfiguration(): ReactElement { - const formik: FormikContextType = useFormikContext(); - const { hasReadWriteAccess } = usePermissions(); - const hasWriteAccessForIntegration = hasReadWriteAccess('Integration'); - - return ( - <> - - - - Report - - - Optionally configure e-mail delivery destinations for reports - - - - -
    - - - - ); -} - -export default ReportConfiguration; diff --git a/ui/apps/platform/src/Containers/ComplianceEnhanced/Schedules/Wizard/ReviewConfig.tsx b/ui/apps/platform/src/Containers/ComplianceEnhanced/Schedules/Wizard/ReviewConfig.tsx deleted file mode 100644 index b4c551c4d825b..0000000000000 --- a/ui/apps/platform/src/Containers/ComplianceEnhanced/Schedules/Wizard/ReviewConfig.tsx +++ /dev/null @@ -1,118 +0,0 @@ -import { useFormikContext } from 'formik'; -import type { FormikContextType } from 'formik'; -import { - Alert, - Badge, - Divider, - Flex, - FlexItem, - List, - ListItem, - PageSection, - Title, -} from '@patternfly/react-core'; - -import NotifierConfigurationView from 'Components/NotifierConfiguration/NotifierConfigurationView'; -import type { ComplianceIntegration } from 'services/ComplianceIntegrationService'; - -import { - convertFormikParametersToSchedule, - getBodyDefault, - getSubjectDefault, -} from '../compliance.scanConfigs.utils'; -import type { ScanConfigFormValues } from '../compliance.scanConfigs.utils'; -import ScanConfigParametersView from '../components/ScanConfigParametersView'; -import ScanConfigProfilesView from '../components/ScanConfigProfilesView'; - -const headingLevel = 'h3'; - -export type ReviewConfigProps = { - clusters: ComplianceIntegration[]; - errorMessage: string; -}; - -function ReviewConfig({ clusters, errorMessage }: ReviewConfigProps) { - const { values: formikValues }: FormikContextType = useFormikContext(); - - const scanSchedule = convertFormikParametersToSchedule(formikValues.parameters); - - function findById(selectedIds: string[], items: T[], idKey: K): T[] { - return selectedIds - .map((id) => items.find((item) => String(item[idKey]) === id)) - .filter((item): item is T => item !== undefined); - } - - const selectedClusters = findById(formikValues.clusters, clusters, 'clusterId'); - - return ( - <> - - - - Review - - Review the scan schedule before you save changes - {errorMessage && ( - - {errorMessage} - - )} - - - - - - - - Clusters - {selectedClusters.length} - - - {selectedClusters.map((cluster) => ( - {cluster.clusterName} - ))} - - - - - - Compliance Operator runs a new scan schedule immediately upon creation, but does - not run until scheduled time when you save changes to an existing scan schedule. - - - - ); -} - -export default ReviewConfig; diff --git a/ui/apps/platform/src/Containers/ComplianceEnhanced/Schedules/Wizard/ClusterSelection.tsx b/ui/apps/platform/src/Containers/ComplianceEnhanced/Schedules/Wizard/ScanConfigClustersStep.tsx similarity index 69% rename from ui/apps/platform/src/Containers/ComplianceEnhanced/Schedules/Wizard/ClusterSelection.tsx rename to ui/apps/platform/src/Containers/ComplianceEnhanced/Schedules/Wizard/ScanConfigClustersStep.tsx index 9b0131e9e9afa..6a01dddfec7ae 100644 --- a/ui/apps/platform/src/Containers/ComplianceEnhanced/Schedules/Wizard/ClusterSelection.tsx +++ b/ui/apps/platform/src/Containers/ComplianceEnhanced/Schedules/Wizard/ScanConfigClustersStep.tsx @@ -7,7 +7,6 @@ import { Alert, Bullseye, Button, - Divider, Flex, FlexItem, Form, @@ -27,7 +26,7 @@ import type { ComplianceIntegration } from 'services/ComplianceIntegrationServic import type { ScanConfigFormValues } from '../compliance.scanConfigs.utils'; import ComplianceClusterStatus from '../components/ComplianceClusterStatus'; -export type ClusterSelectionProps = { +export type ScanConfigClustersStepProps = { alertRef: RefObject; clusters: ComplianceIntegration[]; isFetchingClusters: boolean; @@ -41,11 +40,11 @@ function InstallClustersButton() { ); } -function ClusterSelection({ +function ScanConfigClustersStep({ alertRef, clusters, isFetchingClusters, -}: ClusterSelectionProps): ReactElement { +}: ScanConfigClustersStepProps): ReactElement { const isRouteEnabled = useIsRouteEnabled(); const isRouteEnabledForClusters = isRouteEnabled('clusters'); const { @@ -151,55 +150,49 @@ function ClusterSelection({ } return ( - <> - - - - Clusters - - Select clusters to be included in the scan - - - -
    - -

    - Tip: The most common reason a cluster is marked Unhealthy is that the - Compliance Operator is either not installed or is below version 1.6. -

    -
    - {formikTouched.clusters && formikValues.clusters.length === 0 && ( + + + Clusters + - )} - - - - - - - - - {renderTableBodyContent()} -
    - NameOperator statusOperator version
    - - + > +

    + Tip: The most common reason a cluster is marked Unhealthy is that the + Compliance Operator is either not installed or is below version 1.6. +

    +
    + {formikTouched.clusters && formikValues.clusters.length === 0 && ( + + )} + + + + + + + + + {renderTableBodyContent()} +
    + NameOperator statusOperator version
    + +
    +
    ); } -export default ClusterSelection; +export default ScanConfigClustersStep; diff --git a/ui/apps/platform/src/Containers/ComplianceEnhanced/Schedules/Wizard/ScanConfigDeliveryStep.tsx b/ui/apps/platform/src/Containers/ComplianceEnhanced/Schedules/Wizard/ScanConfigDeliveryStep.tsx new file mode 100644 index 0000000000000..85f938cba0e56 --- /dev/null +++ b/ui/apps/platform/src/Containers/ComplianceEnhanced/Schedules/Wizard/ScanConfigDeliveryStep.tsx @@ -0,0 +1,34 @@ +import type { ReactElement } from 'react'; +import { useFormikContext } from 'formik'; +import type { FormikContextType } from 'formik'; +import { Flex, Form, PageSection, Title } from '@patternfly/react-core'; + +import NotifierConfigurationForm from 'Components/NotifierConfiguration/NotifierConfigurationForm'; +import usePermissions from 'hooks/usePermissions'; + +import type { ScanConfigFormValues } from '../compliance.scanConfigs.utils'; + +function ScanConfigDeliveryStep(): ReactElement { + const formik: FormikContextType = useFormikContext(); + const { hasReadWriteAccess } = usePermissions(); + const hasWriteAccessForIntegration = hasReadWriteAccess('Integration'); + + return ( + + + Delivery +
    + + +
    +
    + ); +} + +export default ScanConfigDeliveryStep; diff --git a/ui/apps/platform/src/Containers/ComplianceEnhanced/Schedules/Wizard/ScanConfigOptions.tsx b/ui/apps/platform/src/Containers/ComplianceEnhanced/Schedules/Wizard/ScanConfigOptions.tsx index 9e683163df5e2..4406d7374c661 100644 --- a/ui/apps/platform/src/Containers/ComplianceEnhanced/Schedules/Wizard/ScanConfigOptions.tsx +++ b/ui/apps/platform/src/Containers/ComplianceEnhanced/Schedules/Wizard/ScanConfigOptions.tsx @@ -2,13 +2,11 @@ import type { FormEvent, ReactElement } from 'react'; import { useFormikContext } from 'formik'; import type { FormikContextType } from 'formik'; import { - Divider, Flex, FlexItem, Form, + FormSection, PageSection, - Stack, - StackItem, TextArea, TextInput, TimePicker, @@ -20,7 +18,7 @@ import FormLabelGroup from 'Components/PatternFly/FormLabelGroup'; import RepeatScheduleDropdown from 'Components/PatternFly/RepeatScheduleDropdown'; import usePageAction from 'hooks/usePageAction'; -import type { PageActions, ScanConfigFormValues } from '../compliance.scanConfigs.utils'; +import type { ScanConfigFormValues, SchedulePageAction } from '../compliance.scanConfigs.utils'; import { helperTextForName, helperTextForNameEdit, helperTextForTime } from './useFormikScanConfig'; @@ -28,7 +26,7 @@ import './ScanConfigOptions.css'; function ScanConfigOptions(): ReactElement { const formik: FormikContextType = useFormikContext(); - const { pageAction } = usePageAction(); + const { pageAction } = usePageAction(); const isEditAction = pageAction === 'edit'; function handleSelectChange(id: string, value: string): void { @@ -46,187 +44,146 @@ function ScanConfigOptions(): ReactElement { } return ( - <> - - - - Parameters - - Set name and schedule to scan on a recurring basis - - - -
    - - - - - - + + Parameters + + + formik.handleChange(event)} + onBlur={formik.handleBlur} + /> + + +