Compare commits

...

41 Commits

Author SHA1 Message Date
github-actions[bot]
96d86d3eb0 chore(main): release 0.4.11 (#1451)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-04-15 11:24:06 +01:00
gossion
df17e3e728 fix: config ai provider in query (#1457)
Signed-off-by: Guoxun Wei <guwe@microsoft.com>
2025-04-15 11:11:40 +01:00
Alex Jones
80904e3063 feat: improved test coverage (#1455)
Signed-off-by: Alex Jones <alexsimonjones@gmail.com>
2025-04-14 14:15:26 +01:00
renovate[bot]
cf6f9289e1 fix(deps): update module gopkg.in/yaml.v2 to v3 (#1453)
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-14 13:50:15 +01:00
Yicheng
a79224e2bf feat: add verbose flag to enable detailed output (#1420)
* feat: add verbose flag to enable detailed output

Signed-off-by: Yicheng <36285652+zyc140345@users.noreply.github.com>

* test: add verbose output tests for analysis.go and root.go

Signed-off-by: Yicheng <36285652+zyc140345@users.noreply.github.com>

---------

Signed-off-by: Yicheng <36285652+zyc140345@users.noreply.github.com>
2025-04-14 13:06:24 +01:00
Pengfei Ni
9ce33469d8 docs: fix the slack invite link (#1450)
Signed-off-by: Pengfei Ni <feiskyer@gmail.com>
Co-authored-by: Alex Jones <alexsimonjones@gmail.com>
2025-04-14 11:48:35 +01:00
renovate[bot]
969fe99b33 fix(deps): update module gopkg.in/yaml.v2 to v3 (#1447)
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-11 09:53:59 +01:00
ju187
91d423b147 feat: call bedrock with inference profile (#1449)
* call bedrock with inference profile

Signed-off-by: Tony Chen <tony_chen@discovery.com>

* add validation and test

Signed-off-by: Tony Chen <tony_chen@discovery.com>

* update test

Signed-off-by: Tony Chen <tony_chen@discovery.com>

---------

Signed-off-by: Tony Chen <tony_chen@discovery.com>
2025-04-11 07:11:38 +01:00
github-actions[bot]
766b51cd3e chore(main): release 0.4.10 (#1441)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-04-10 21:45:59 +01:00
renovate[bot]
060a3b2a26 fix(deps): update module helm.sh/helm/v3 to v3.17.3 [security] (#1448)
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-10 18:59:22 +01:00
renovate[bot]
ce4b3c2e7d fix(deps): update module gopkg.in/yaml.v2 to v3 (#1417)
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-10 11:25:50 +01:00
ju187
78ffa5904a feat: add a naive support of bedrock inference profile (#1446)
* feat: add a naive support of bedrock inference profile

Signed-off-by: Tony Chen <tony_chen@discovery.com>

* feat: improving the tests

Signed-off-by: Alex Jones <alexsimonjones@gmail.com>

---------

Signed-off-by: Tony Chen <tony_chen@discovery.com>
Signed-off-by: Alex Jones <alexsimonjones@gmail.com>
Co-authored-by: Alex Jones <alexsimonjones@gmail.com>
2025-04-10 09:47:58 +01:00
gossion
dceda9a6a1 fix: pod analyzer catches errors when containers are in Terminated state (#1438)
Signed-off-by: Guoxun Wei <guwe@microsoft.com>
Co-authored-by: Alex Jones <alexsimonjones@gmail.com>
2025-04-08 10:49:53 +01:00
github-actions[bot]
e7783482ce chore(main): release 0.4.9 (#1439)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-04-08 09:17:34 +01:00
renovate[bot]
a5574ee49d chore(deps): pin dependencies (#1440)
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-08 09:08:25 +01:00
Alex Jones
f68ff0efee chore: fixing (#1437)
Signed-off-by: Alex Jones <alexsimonjones@gmail.com>
2025-04-08 08:36:39 +01:00
github-actions[bot]
0c63044254 chore(main): release 0.4.8 (#1435)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-04-07 20:31:33 +01:00
Alex Jones
39ae2aa635 chore: removed krew release (#1434)
Signed-off-by: Alex Jones <alexsimonjones@gmail.com>
2025-04-07 20:28:36 +01:00
github-actions[bot]
05040da188 chore(main): release 0.4.7 (#1432)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-04-07 17:32:40 +01:00
renovate[bot]
9bffc7cff7 chore(deps): update actions/upload-artifact digest to ea165f8 (#1425)
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-07 16:54:08 +01:00
Alex Jones
c5fe2c68d1 chore: fixing build (#1431)
Signed-off-by: Alex Jones <alexsimonjones@gmail.com>
2025-04-07 16:50:19 +01:00
github-actions[bot]
c1b267b818 chore(main): release 0.4.6 (#1427)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-04-07 15:22:49 +01:00
renovate[bot]
5086ccd659 chore(deps): pin docker/build-push-action action to 471d1dc (#1428)
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-07 15:16:26 +01:00
Alex Jones
b6261026f8 chore: updated actor for login (#1430)
Signed-off-by: Alex Jones <alexsimonjones@gmail.com>
2025-04-07 15:07:49 +01:00
Alex Jones
1681aadac1 chore: fixing docker build push action (#1426)
Signed-off-by: Alex Jones <alexsimonjones@gmail.com>
2025-04-07 07:37:25 +01:00
github-actions[bot]
9874cef8bf chore(main): release 0.4.5 (#1424)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-04-07 06:51:58 +01:00
Alex Jones
3dbc9e1a20 chore: fix workflows (#1423)
Signed-off-by: Alex Jones <alexsimonjones@gmail.com>
2025-04-07 06:50:46 +01:00
github-actions[bot]
e0d66f43f7 chore(main): release 0.4.4 (#1421)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-04-06 20:41:54 +01:00
renovate[bot]
d4de5d9e3f chore(deps): update docker/setup-buildx-action digest to b5ca514 (#1371)
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-06 20:34:35 +01:00
Alex Jones
5b7fb7e619 chore: updating deps (#1422)
Signed-off-by: Alex Jones <alexsimonjones@gmail.com>
2025-04-06 19:30:25 +01:00
renovate[bot]
68ddac0089 chore(deps): update module github.com/docker/docker to v28 (#1376)
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-06 16:47:40 +01:00
github-actions[bot]
d1a29e4001 chore(main): release 0.4.3 (#1412)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-04-04 11:49:09 +01:00
Sakshi Singh
ad2c90a129 chore: added new AmazonBedrock model (#1390)
* Update AI Bedrock region - Added mumbai region

Signed-off-by: Sakshi Singh <66963254+sakshirajput02@users.noreply.github.com>

* Update amazonbedrock.go

Signed-off-by: Sakshi Singh <66963254+sakshirajput02@users.noreply.github.com>

* Added new AI model to work for ap-south-1 region[that does not uses inference profile]

Signed-off-by: Sakshi Singh <66963254+sakshirajput02@users.noreply.github.com>

---------

Signed-off-by: Sakshi Singh <66963254+sakshirajput02@users.noreply.github.com>
Co-authored-by: Alex Jones <alexsimonjones@gmail.com>
2025-04-04 11:45:05 +01:00
renovate[bot]
e4861e9e2d fix(deps): update module gopkg.in/yaml.v2 to v3 (#1363)
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-02 16:19:03 +01:00
Kay Yan
3c353b0e93 fix: prometheus UTF8Validation (#1404)
Signed-off-by: Kay Yan <kay.yan@daocloud.io>
2025-04-02 16:07:32 +01:00
renovate[bot]
c823de12e6 chore(deps): update goreleaser/goreleaser-action digest to 9c156ee (#1411)
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-01 07:34:51 +01:00
renovate[bot]
e231032e1b chore(deps): pin golangci/golangci-lint-action action to 1481404 (#1415)
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-31 20:14:41 +01:00
Alex Jones
f0b18cfb1c chore: linter (#1414)
* chore: changing linter

Signed-off-by: Alex Jones <alexsimonjones@gmail.com>

* chore: changing linter

Signed-off-by: Alex Jones <alexsimonjones@gmail.com>

* chore: changing linter

Signed-off-by: Alex Jones <alexsimonjones@gmail.com>

---------

Signed-off-by: Alex Jones <alexsimonjones@gmail.com>
2025-03-31 19:17:55 +01:00
Hadi Azaddel
a31d07c802 docs: add table of contents and cleanup (#1413)
Signed-off-by: hadi2f244 <m.h.azaddel@gmail.com>
2025-03-31 19:04:59 +01:00
Eshaan Aggarwal
06d201ca5d test: add tests for k8sgpt/pkg/analyzer/events.go (#913)
* test: add tests for events_test.go

Signed-off-by: Eshaan Aggarwal <96648934+EshaanAgg@users.noreply.github.com>

* feat: fixed event tests

Signed-off-by: Alex Jones <alexsimonjones@gmail.com>

---------

Signed-off-by: Eshaan Aggarwal <96648934+EshaanAgg@users.noreply.github.com>
Signed-off-by: Alex Jones <alexsimonjones@gmail.com>
Co-authored-by: Alex Jones <alexsimonjones@gmail.com>
2025-03-31 14:33:02 +01:00
Qian_Xiao
a962741220 docs: remove extra dollar sign in README.md (#1410)
Signed-off-by: Qian_Xiao <heyheyco@gmail.com>
2025-03-31 14:09:41 +01:00
26 changed files with 2642 additions and 968 deletions

View File

@@ -8,13 +8,16 @@ on:
pull_request:
branches:
- 'main'
- fix/build-branch
- '[0-9]+.[1-9][0-9]*.x'
paths-ignore:
- "**.md"
env:
GO_VERSION: "~1.22"
GO_VERSION: "~1.23"
IMAGE_NAME: "k8sgpt"
REGISTRY_IMAGE: ghcr.io/k8sgpt-ai/k8sgpt
defaults:
run:
shell: bash
@@ -51,97 +54,61 @@ jobs:
id: get_run_type
run: |
NON_FORKED_AND_NON_ROBOT_RUN=${{ ( github.actor != 'renovate[bot]' && github.actor != 'dependabot[bot]' ) && ( github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository ) }}
echo "github.actor != 'renovate[bot]' = ${{ github.actor != 'renovate[bot]' }}"
echo "github.actor != 'dependabot[bot]' = ${{ github.actor != 'dependabot[bot]' }}"
echo "github.event_name == 'push' = ${{ github.event_name == 'push' }}"
echo "github.event.pull_request.head.repo.full_name == github.repository = ${{ github.event.pull_request.head.repo.full_name == github.repository }}"
echo "NON_FORKED_AND_NON_ROBOT_RUN = $NON_FORKED_AND_NON_ROBOT_RUN"
echo "NON_FORKED_AND_NON_ROBOT_RUN=$NON_FORKED_AND_NON_ROBOT_RUN" >> "$GITHUB_OUTPUT"
build_image:
name: Build Container Image
build-and-push:
name: Build and Push Multi-arch Image
needs: prepare_ci_run
runs-on: ubuntu-latest
if: ${{ needs.prepare_ci_run.outputs.NON_FORKED_AND_NON_ROBOT_RUN == 'true' }}
env:
BRANCH: ${{ needs.prepare_ci_run.outputs.BRANCH }}
DATETIME: ${{ needs.prepare_ci_run.outputs.DATETIME }}
BUILD_TIME: ${{ needs.prepare_ci_run.outputs.BUILD_TIME }}
GIT_SHA: ${{ needs.prepare_ci_run.outputs.GIT_SHA }}
RELEASE_REGISTRY: "localhost:5000/k8sgpt"
steps:
- name: Check out code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@6524bf65af31da8d45b59e8c27de4bd072b392f5 # v3
- name: Build Docker Image
uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v6
- name: Docker meta
id: meta
uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5
with:
context: .
platforms: linux/amd64
file: ./container/Dockerfile
target: production
images: ${{ env.REGISTRY_IMAGE }}
tags: |
${{ env.RELEASE_REGISTRY }}/${{ env.IMAGE_NAME }}:dev-${{ env.DATETIME }}
build-args: |
GIT_HASH=${{ env.GIT_SHA }}
RELEASE_VERSION=dev-${{ env.DATETIME }}
BUILD_TIME=${{ env.BUILD_TIME }}
builder: ${{ steps.buildx.outputs.name }}
push: false
cache-from: type=gha,scope=${{ github.ref_name }}-${{ env.IMAGE_NAME }}
cache-to: type=gha,scope=${{ github.ref_name }}-${{ env.IMAGE_NAME }}
outputs: type=docker,dest=/tmp/${{ env.IMAGE_NAME }}-image.tar
- name: Upload image as artifact
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: ${{ env.IMAGE_NAME }}-image.tar
path: /tmp/${{ env.IMAGE_NAME }}-image.tar
upload_images:
name: Upload images to ghcr registry
needs: [ prepare_ci_run, build_image ]
if: github.event_name == 'push' && needs.prepare_ci_run.outputs.NON_FORKED_AND_NON_ROBOT_RUN == 'true' # only run on push to main/maintenance branches
runs-on: ubuntu-latest
env:
DATETIME: ${{ needs.prepare_ci_run.outputs.DATETIME }}
BUILD_TIME: ${{ needs.prepare_ci_run.outputs.BUILD_TIME }}
GIT_SHA: ${{ needs.prepare_ci_run.outputs.GIT_SHA }}
permissions:
packages: write # Needed for pushing images to the registry
contents: read # Needed for checking out the repository
steps:
- name: Check out code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=raw,value=dev-${{ env.DATETIME }}
- name: Login to GitHub Container Registry
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3
with:
registry: "ghcr.io"
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
password: ${{ secrets.K8SGPT_BOT_SECRET }}
- name: Set up QEMU
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3
- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@6524bf65af31da8d45b59e8c27de4bd072b392f5 # v3
uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3
- name: Build Docker Image
- name: Build and push multi-arch image
uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v6
with:
context: .
file: ./container/Dockerfile
platforms: linux/amd64,linux/arm64
push: true
target: production
tags: |
ghcr.io/k8sgpt-ai/${{ env.IMAGE_NAME }}:dev-${{ env.DATETIME }}
build-args: |
GIT_HASH=${{ env.GIT_SHA }}
RELEASE_VERSION=dev-${{ env.DATETIME }}
BUILD_TIME=${{ env.BUILD_TIME }}
builder: ${{ steps.buildx.outputs.name }}
push: true
cache-from: type=gha,scope=${{ github.ref_name }}-${{ env.IMAGE_NAME }}
cache-to: type=gha,scope=${{ github.ref_name }}-${{ env.IMAGE_NAME }}
tags: |
${{ env.REGISTRY_IMAGE }}:${{ env.DATETIME }}
labels: ${{ steps.meta.outputs.labels }}
secrets: |
GIT_AUTH_TOKEN=${{ secrets.K8SGPT_BOT_SECRET }}

View File

@@ -12,9 +12,7 @@ jobs:
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- name: golangci-lint
uses: reviewdog/action-golangci-lint@7708105983c614f7a2725e2172908b7709d1c3e4 # v2
uses: golangci/golangci-lint-action@1481404843c368bc19ca9406f87d6e0fc97bdcfd # v7
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
reporter: github-pr-check
golangci_lint_flags: "--timeout=240s"
level: warning
version: v2.0
only-new-issues: true

View File

@@ -65,7 +65,7 @@ jobs:
- name: Download Syft
uses: anchore/sbom-action/download-syft@55dc4ee22412511ee8c3142cbea40418e6cec693 # v0.17.8
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@90a3faa9d0182683851fbfa97ca1a2cb983bfca3 # v6
uses: goreleaser/goreleaser-action@9c156ee8a17a598857849441385a2041ef570552 # v6
with:
# either 'goreleaser' (default) or 'goreleaser-pro'
distribution: goreleaser
@@ -73,8 +73,8 @@ jobs:
args: release --clean
env:
GITHUB_TOKEN: ${{ secrets.K8SGPT_BOT_SECRET }}
- name: Update new version in krew-index
uses: rajatjindal/krew-release-bot@3d9faef30a82761d610544f62afddca00993eef9 # v0.0.47
# - name: Update new version in krew-index
# uses: rajatjindal/krew-release-bot@3d9faef30a82761d610544f62afddca00993eef9 # v0.0.47
build-container:
if: needs.release-please.outputs.releases_created == 'true'
@@ -96,14 +96,14 @@ jobs:
- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@6524bf65af31da8d45b59e8c27de4bd072b392f5 # v3
uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3
- name: Login to GitHub Container Registry
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3
with:
registry: "ghcr.io"
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
password: ${{ secrets.K8SGPT_BOT_SECRET }}
- name: Build Docker Image
uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v6

View File

@@ -1 +1 @@
{".":"0.4.2"}
{".":"0.4.11"}

View File

@@ -1,5 +1,110 @@
# Changelog
## [0.4.11](https://github.com/k8sgpt-ai/k8sgpt/compare/v0.4.10...v0.4.11) (2025-04-15)
### Features
* add verbose flag to enable detailed output ([#1420](https://github.com/k8sgpt-ai/k8sgpt/issues/1420)) ([a79224e](https://github.com/k8sgpt-ai/k8sgpt/commit/a79224e2bf96f458dbc96404c8f4847970e8d2ef))
* call bedrock with inference profile ([#1449](https://github.com/k8sgpt-ai/k8sgpt/issues/1449)) ([91d423b](https://github.com/k8sgpt-ai/k8sgpt/commit/91d423b147ca18cda7d54ff19349938a894ecb85))
* improved test coverage ([#1455](https://github.com/k8sgpt-ai/k8sgpt/issues/1455)) ([80904e3](https://github.com/k8sgpt-ai/k8sgpt/commit/80904e3063b00b0536171b7b62b938938b20825a))
### Bug Fixes
* config ai provider in query ([#1457](https://github.com/k8sgpt-ai/k8sgpt/issues/1457)) ([df17e3e](https://github.com/k8sgpt-ai/k8sgpt/commit/df17e3e728591e974703527dff86de882af17790))
* **deps:** update module gopkg.in/yaml.v2 to v3 ([#1447](https://github.com/k8sgpt-ai/k8sgpt/issues/1447)) ([969fe99](https://github.com/k8sgpt-ai/k8sgpt/commit/969fe99b3320c313f1c97133cdffb668a00d5fb5))
* **deps:** update module gopkg.in/yaml.v2 to v3 ([#1453](https://github.com/k8sgpt-ai/k8sgpt/issues/1453)) ([cf6f928](https://github.com/k8sgpt-ai/k8sgpt/commit/cf6f9289e13ee729c24968fd771c901f412e8db7))
### Docs
* fix the slack invite link ([#1450](https://github.com/k8sgpt-ai/k8sgpt/issues/1450)) ([9ce3346](https://github.com/k8sgpt-ai/k8sgpt/commit/9ce33469d85aa0829e995e4b404ae85734124fb4))
## [0.4.10](https://github.com/k8sgpt-ai/k8sgpt/compare/v0.4.9...v0.4.10) (2025-04-10)
### Features
* add a naive support of bedrock inference profile ([#1446](https://github.com/k8sgpt-ai/k8sgpt/issues/1446)) ([78ffa59](https://github.com/k8sgpt-ai/k8sgpt/commit/78ffa5904addf71caf04554966437b14351f21e5))
### Bug Fixes
* **deps:** update module gopkg.in/yaml.v2 to v3 ([#1417](https://github.com/k8sgpt-ai/k8sgpt/issues/1417)) ([ce4b3c2](https://github.com/k8sgpt-ai/k8sgpt/commit/ce4b3c2e7d0762093506d9010eceb47a2dcdf5bc))
* **deps:** update module helm.sh/helm/v3 to v3.17.3 [security] ([#1448](https://github.com/k8sgpt-ai/k8sgpt/issues/1448)) ([060a3b2](https://github.com/k8sgpt-ai/k8sgpt/commit/060a3b2a26f117827090697eb599cd51a44125e6))
* pod analyzer catches errors when containers are in Terminated state ([#1438](https://github.com/k8sgpt-ai/k8sgpt/issues/1438)) ([dceda9a](https://github.com/k8sgpt-ai/k8sgpt/commit/dceda9a6a16a914b916c478ecd0b4c8ed0e19c40))
## [0.4.9](https://github.com/k8sgpt-ai/k8sgpt/compare/v0.4.8...v0.4.9) (2025-04-08)
### Other
* **deps:** pin dependencies ([#1440](https://github.com/k8sgpt-ai/k8sgpt/issues/1440)) ([a5574ee](https://github.com/k8sgpt-ai/k8sgpt/commit/a5574ee49d530960a515c419f4875cf02cb36fb3))
* fixing ([#1437](https://github.com/k8sgpt-ai/k8sgpt/issues/1437)) ([f68ff0e](https://github.com/k8sgpt-ai/k8sgpt/commit/f68ff0efee9bad5f8368c83800611fa9acbc53d7))
## [0.4.8](https://github.com/k8sgpt-ai/k8sgpt/compare/v0.4.7...v0.4.8) (2025-04-07)
### Other
* removed krew release ([#1434](https://github.com/k8sgpt-ai/k8sgpt/issues/1434)) ([39ae2aa](https://github.com/k8sgpt-ai/k8sgpt/commit/39ae2aa6351d6a77e0b45ad15b0d10b86a33f3be))
## [0.4.7](https://github.com/k8sgpt-ai/k8sgpt/compare/v0.4.6...v0.4.7) (2025-04-07)
### Other
* **deps:** update actions/upload-artifact digest to ea165f8 ([#1425](https://github.com/k8sgpt-ai/k8sgpt/issues/1425)) ([9bffc7c](https://github.com/k8sgpt-ai/k8sgpt/commit/9bffc7cff776733f6d05669e6c02f594ee2db261))
* fixing build ([#1431](https://github.com/k8sgpt-ai/k8sgpt/issues/1431)) ([c5fe2c6](https://github.com/k8sgpt-ai/k8sgpt/commit/c5fe2c68d18d4fd713b3e638066327ad586d1871))
## [0.4.6](https://github.com/k8sgpt-ai/k8sgpt/compare/v0.4.5...v0.4.6) (2025-04-07)
### Other
* **deps:** pin docker/build-push-action action to 471d1dc ([#1428](https://github.com/k8sgpt-ai/k8sgpt/issues/1428)) ([5086ccd](https://github.com/k8sgpt-ai/k8sgpt/commit/5086ccd65942ebb9a37bd2c3a48d16c4be99e8c1))
* fixing docker build push action ([#1426](https://github.com/k8sgpt-ai/k8sgpt/issues/1426)) ([1681aad](https://github.com/k8sgpt-ai/k8sgpt/commit/1681aadac106c608de9774ebfd7ea9df20eed482))
* updated actor for login ([#1430](https://github.com/k8sgpt-ai/k8sgpt/issues/1430)) ([b626102](https://github.com/k8sgpt-ai/k8sgpt/commit/b6261026f8b41e505359a52c18bebec7ef5079f9))
## [0.4.5](https://github.com/k8sgpt-ai/k8sgpt/compare/v0.4.4...v0.4.5) (2025-04-07)
### Other
* fix workflows ([#1423](https://github.com/k8sgpt-ai/k8sgpt/issues/1423)) ([3dbc9e1](https://github.com/k8sgpt-ai/k8sgpt/commit/3dbc9e1a20a3a55971733d990ecd39e798a804e9))
## [0.4.4](https://github.com/k8sgpt-ai/k8sgpt/compare/v0.4.3...v0.4.4) (2025-04-06)
### Other
* **deps:** update docker/setup-buildx-action digest to b5ca514 ([#1371](https://github.com/k8sgpt-ai/k8sgpt/issues/1371)) ([d4de5d9](https://github.com/k8sgpt-ai/k8sgpt/commit/d4de5d9e3fdd1cc4c7d6fc067a7426fef1d32c1d))
* **deps:** update module github.com/docker/docker to v28 ([#1376](https://github.com/k8sgpt-ai/k8sgpt/issues/1376)) ([68ddac0](https://github.com/k8sgpt-ai/k8sgpt/commit/68ddac008955933ffa27c2c4e46d286d9a26e100))
* updating deps ([#1422](https://github.com/k8sgpt-ai/k8sgpt/issues/1422)) ([5b7fb7e](https://github.com/k8sgpt-ai/k8sgpt/commit/5b7fb7e6199635e109c1bf7355bc11ff6f60071b))
## [0.4.3](https://github.com/k8sgpt-ai/k8sgpt/compare/v0.4.2...v0.4.3) (2025-04-04)
### Bug Fixes
* **deps:** update module gopkg.in/yaml.v2 to v3 ([#1363](https://github.com/k8sgpt-ai/k8sgpt/issues/1363)) ([e4861e9](https://github.com/k8sgpt-ai/k8sgpt/commit/e4861e9e2d631652b82768567afb9ba174114134))
* prometheus UTF8Validation ([#1404](https://github.com/k8sgpt-ai/k8sgpt/issues/1404)) ([3c353b0](https://github.com/k8sgpt-ai/k8sgpt/commit/3c353b0e931028f3be3b229518cf86d24422a29d))
### Other
* added new AmazonBedrock model ([#1390](https://github.com/k8sgpt-ai/k8sgpt/issues/1390)) ([ad2c90a](https://github.com/k8sgpt-ai/k8sgpt/commit/ad2c90a129074a13dac4fdd8e918d8e26159c7a1))
* **deps:** pin golangci/golangci-lint-action action to 1481404 ([#1415](https://github.com/k8sgpt-ai/k8sgpt/issues/1415)) ([e231032](https://github.com/k8sgpt-ai/k8sgpt/commit/e231032e1bec1d2d25cb03b35e701aa86a61d5ee))
* **deps:** update goreleaser/goreleaser-action digest to 9c156ee ([#1411](https://github.com/k8sgpt-ai/k8sgpt/issues/1411)) ([c823de1](https://github.com/k8sgpt-ai/k8sgpt/commit/c823de12e6b6efcf9f5639665aac602ed85ae31d))
* linter ([#1414](https://github.com/k8sgpt-ai/k8sgpt/issues/1414)) ([f0b18cf](https://github.com/k8sgpt-ai/k8sgpt/commit/f0b18cfb1cd418b94b448d3b9de43f03841c92bb))
### Docs
* add table of contents and cleanup ([#1413](https://github.com/k8sgpt-ai/k8sgpt/issues/1413)) ([a31d07c](https://github.com/k8sgpt-ai/k8sgpt/commit/a31d07c802694d3455b665382ff12a2abc3e0ef7))
* remove extra dollar sign in README.md ([#1410](https://github.com/k8sgpt-ai/k8sgpt/issues/1410)) ([a962741](https://github.com/k8sgpt-ai/k8sgpt/commit/a962741220bf98e159f14895d01cd596a7691f87))
## [0.4.2](https://github.com/k8sgpt-ai/k8sgpt/compare/v0.4.1...v0.4.2) (2025-03-28)

View File

@@ -24,14 +24,27 @@ _Out of the box integration with OpenAI, Azure, Cohere, Amazon Bedrock, Google G
<a href="https://www.producthunt.com/posts/k8sgpt?utm_source=badge-featured&utm_medium=badge&utm_souce=badge-k8sgpt" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=389489&theme=light" alt="K8sGPT - K8sGPT&#0032;gives&#0032;Kubernetes&#0032;Superpowers&#0032;to&#0032;everyone | Product Hunt" style="width: 250px; height: 54px;" width="250" height="54" /></a> <a href="https://hellogithub.com/repository/9dfe44c18dfb4d6fa0181baf8b2cf2e1" target="_blank"><img src="https://abroad.hellogithub.com/v1/widgets/recommend.svg?rid=9dfe44c18dfb4d6fa0181baf8b2cf2e1&claim_uid=gqG4wmzkMrP0eFy" alt="FeaturedHelloGitHub" style="width: 250px; height: 54px;" width="250" height="54" /></a>
<img src="images/demo4.gif" width=650px; />
<img src="images/demo4.gif" width="650px">
# Table of Contents
- [Overview](#k8sgpt)
- [Installation](#cli-installation)
- [Quick Start](#quick-start)
- [Analyzers](#analyzers)
- [Examples](#examples)
- [LLM AI Backends](#llm-ai-backends)
- [Key Features](#key-features)
- [Documentation](#documentation)
- [Contributing](#contributing)
- [Community](#community)
- [License](#license)
# CLI Installation
### Linux/Mac via brew
```sh
$ brew install k8sgpt
brew install k8sgpt
```
or
@@ -49,7 +62,7 @@ brew install k8sgpt
<!---x-release-please-start-version-->
```
sudo rpm -ivh https://github.com/k8sgpt-ai/k8sgpt/releases/download/v0.4.2/k8sgpt_386.rpm
sudo rpm -ivh https://github.com/k8sgpt-ai/k8sgpt/releases/download/v0.4.11/k8sgpt_386.rpm
```
<!---x-release-please-end-->
@@ -57,7 +70,7 @@ brew install k8sgpt
<!---x-release-please-start-version-->
```
sudo rpm -ivh https://github.com/k8sgpt-ai/k8sgpt/releases/download/v0.4.2/k8sgpt_amd64.rpm
sudo rpm -ivh https://github.com/k8sgpt-ai/k8sgpt/releases/download/v0.4.11/k8sgpt_amd64.rpm
```
<!---x-release-please-end-->
</details>
@@ -70,7 +83,7 @@ brew install k8sgpt
<!---x-release-please-start-version-->
```
curl -LO https://github.com/k8sgpt-ai/k8sgpt/releases/download/v0.4.2/k8sgpt_386.deb
curl -LO https://github.com/k8sgpt-ai/k8sgpt/releases/download/v0.4.11/k8sgpt_386.deb
sudo dpkg -i k8sgpt_386.deb
```
@@ -81,7 +94,7 @@ sudo dpkg -i k8sgpt_386.deb
<!---x-release-please-start-version-->
```
curl -LO https://github.com/k8sgpt-ai/k8sgpt/releases/download/v0.4.2/k8sgpt_amd64.deb
curl -LO https://github.com/k8sgpt-ai/k8sgpt/releases/download/v0.4.11/k8sgpt_amd64.deb
sudo dpkg -i k8sgpt_amd64.deb
```
@@ -96,7 +109,7 @@ sudo dpkg -i k8sgpt_amd64.deb
<!---x-release-please-start-version-->
```
wget https://github.com/k8sgpt-ai/k8sgpt/releases/download/v0.4.2/k8sgpt_386.apk
wget https://github.com/k8sgpt-ai/k8sgpt/releases/download/v0.4.11/k8sgpt_386.apk
apk add --allow-untrusted k8sgpt_386.apk
```
<!---x-release-please-end-->
@@ -105,7 +118,7 @@ sudo dpkg -i k8sgpt_amd64.deb
<!---x-release-please-start-version-->
```
wget https://github.com/k8sgpt-ai/k8sgpt/releases/download/v0.4.2/k8sgpt_amd64.apk
wget https://github.com/k8sgpt-ai/k8sgpt/releases/download/v0.4.11/k8sgpt_amd64.apk
apk add --allow-untrusted k8sgpt_amd64.apk
```
<!---x-release-please-end-->
@@ -133,7 +146,7 @@ If you install gcc as suggested, the problem will persist. Therefore, you need t
- Download the latest Windows binaries of **k8sgpt** from the [Release](https://github.com/k8sgpt-ai/k8sgpt/releases)
tab based on your system architecture.
- Extract the downloaded package to your desired location. Configure the system _path_ variable with the binary location
- Extract the downloaded package to your desired location. Configure the system _PATH_ environment variable with the binary location
## Operator Installation
@@ -324,14 +337,14 @@ _Print analysis stats_
```
k8sgpt analyze -s
The stats mode allows for debugging and understanding the time taken by an analysis by displaying the statistics of each analyzer.
- Analyzer Ingress took 47.125583ms
- Analyzer PersistentVolumeClaim took 53.009167ms
- Analyzer CronJob took 57.517792ms
- Analyzer Deployment took 156.6205ms
- Analyzer Node took 160.109833ms
- Analyzer ReplicaSet took 245.938333ms
- Analyzer StatefulSet took 448.0455ms
- Analyzer Pod took 5.662594708s
- Analyzer Ingress took 47.125583ms
- Analyzer PersistentVolumeClaim took 53.009167ms
- Analyzer CronJob took 57.517792ms
- Analyzer Deployment took 156.6205ms
- Analyzer Node took 160.109833ms
- Analyzer ReplicaSet took 245.938333ms
- Analyzer StatefulSet took 448.0455ms
- Analyzer Pod took 5.662594708s
- Analyzer Service took 38.583359166s
```
@@ -412,11 +425,9 @@ The Kubernetes system is trying to scale a StatefulSet named tGLcCRcHa1Ce5Rs usi
The Kubernetes system is trying to scale a StatefulSet named fake-deployment using the HorizontalPodAutoscaler, but it cannot find the StatefulSet. The solution is to verify that the StatefulSet name is spelled correctly and exists in the same namespace as the HorizontalPodAutoscaler.
```
Note: **Anonymization does not currently apply to events.**
### Further Details
**Anonymization does not currently apply to events.**
Note: **Anonymization does not currently apply to events.**
_In a few analysers like Pod, we feed to the AI backend the event messages which are not known beforehand thus we are not masking them for the **time being**._
@@ -434,7 +445,7 @@ _In a few analysers like Pod, we feed to the AI backend the event messages which
- The following is the list of analysers in which data is **not being masked**:-
- RepicaSet
- ReplicaSet
- PersistentVolumeClaim
- Pod
- Log
@@ -485,7 +496,7 @@ There may be scenarios where caching remotely is preferred.
In these scenarios K8sGPT supports AWS S3 or Azure Blob storage Integration.
<summary> Remote caching </summary>
<em>Note: You can only configure and use only one remote cache at a time</em>
<em>Note: You can configure and use only one remote cache at a time</em>
_Adding a remote cache_
@@ -581,7 +592,7 @@ Please read our [contributing guide](./CONTRIBUTING.md).
## Community
Find us on [Slack](https://join.slack.com/t/k8sgpt/shared_invite/zt-276pa9uyq-pxAUr4TCVHubFxEvLZuT1Q)
Find us on [Slack](https://join.slack.com/t/k8sgpt/shared_invite/zt-332vhyaxv-bfjJwHZLXWVCB3QaXafEYQ)
<a href="https://github.com/k8sgpt-ai/k8sgpt/graphs/contributors">
<img src="https://contrib.rocks/image?repo=k8sgpt-ai/k8sgpt" />

View File

@@ -23,6 +23,7 @@ import (
"github.com/k8sgpt-ai/k8sgpt/pkg/ai/interactive"
"github.com/k8sgpt-ai/k8sgpt/pkg/analysis"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
var (
@@ -67,25 +68,45 @@ var AnalyzeCmd = &cobra.Command{
withStats,
)
verbose := viper.GetBool("verbose")
if verbose {
fmt.Println("Debug: Checking analysis configuration.")
}
if err != nil {
color.Red("Error: %v", err)
os.Exit(1)
}
if verbose {
fmt.Println("Debug: Analysis initialized.")
}
defer config.Close()
if customAnalysis {
config.RunCustomAnalysis()
if verbose {
fmt.Println("Debug: All custom analyzers completed.")
}
}
config.RunAnalysis()
if verbose {
fmt.Println("Debug: All core analyzers completed.")
}
if explain {
if err := config.GetAIResults(output, anonymize); err != nil {
err := config.GetAIResults(output, anonymize)
if verbose {
fmt.Println("Debug: Checking AI results.")
}
if err != nil {
color.Red("Error: %v", err)
os.Exit(1)
}
}
// print results
output_data, err := config.PrintOutput(output)
if verbose {
fmt.Println("Debug: Checking output.")
}
if err != nil {
color.Red("Error: %v", err)
os.Exit(1)

View File

@@ -37,6 +37,7 @@ var (
cfgFile string
kubecontext string
kubeconfig string
verbose bool
Version string
Commit string
Date string
@@ -84,6 +85,7 @@ func init() {
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", fmt.Sprintf("Default config file (%s/k8sgpt/k8sgpt.yaml)", xdg.ConfigHome))
rootCmd.PersistentFlags().StringVar(&kubecontext, "kubecontext", "", "Kubernetes context to use. Only required if out-of-cluster.")
rootCmd.PersistentFlags().StringVar(&kubeconfig, "kubeconfig", "", "Path to a kubeconfig. Only required if out-of-cluster.")
rootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "Show detailed tool actions (e.g., API calls, checks).")
}
// initConfig reads in config file and ENV variables if set.
@@ -104,6 +106,7 @@ func initConfig() {
viper.Set("kubecontext", kubecontext)
viper.Set("kubeconfig", kubeconfig)
viper.Set("verbose", verbose)
viper.SetEnvPrefix("K8SGPT")
viper.AutomaticEnv() // read in environment variables that match

30
cmd/root_test.go Normal file
View File

@@ -0,0 +1,30 @@
/*
Copyright 2023 The K8sGPT Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package cmd
import (
"testing"
"github.com/spf13/viper"
)
// Test that verbose flag is correctly set in viper.
func TestInitConfig_VerboseFlag(t *testing.T) {
verbose = true
viper.Reset()
initConfig()
if !viper.GetBool("verbose") {
t.Error("Expected verbose flag to be true")
}
}

125
go.mod
View File

@@ -13,12 +13,12 @@ require (
github.com/spf13/cobra v1.8.1
github.com/spf13/viper v1.19.0
github.com/stretchr/testify v1.10.0
golang.org/x/term v0.29.0
helm.sh/helm/v3 v3.16.3
k8s.io/api v0.31.3
k8s.io/apimachinery v0.31.3
k8s.io/client-go v0.31.3
k8s.io/kubectl v0.31.1 // indirect
golang.org/x/term v0.30.0
helm.sh/helm/v3 v3.17.3
k8s.io/api v0.32.2
k8s.io/apimachinery v0.32.2
k8s.io/client-go v0.32.2
k8s.io/kubectl v0.32.2 // indirect
)
@@ -32,22 +32,24 @@ require (
buf.build/gen/go/k8sgpt-ai/k8sgpt/protocolbuffers/go v1.35.2-20241118152629-1379a5a1889d.1
cloud.google.com/go/storage v1.48.0
cloud.google.com/go/vertexai v0.13.2
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.1
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.5.0
github.com/IBM/watsonx-go v1.0.1
github.com/aws/aws-sdk-go v1.55.5
github.com/agiledragon/gomonkey/v2 v2.13.0
github.com/aws/aws-sdk-go v1.55.6
github.com/cohere-ai/cohere-go/v2 v2.12.2
github.com/go-logr/zapr v1.3.0
github.com/google/generative-ai-go v0.19.0
github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0
github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1
github.com/hupe1980/go-huggingface v0.0.15
github.com/kyverno/policy-reporter-kyverno-plugin v1.6.4
github.com/olekukonko/tablewriter v0.0.5
github.com/oracle/oci-go-sdk/v65 v65.79.0
github.com/prometheus/prometheus v0.300.1
github.com/prometheus/prometheus v0.302.1
github.com/pterm/pterm v0.12.80
google.golang.org/api v0.210.0
google.golang.org/api v0.218.0
gopkg.in/yaml.v2 v2.4.0
gopkg.in/yaml.v3 v3.0.1
sigs.k8s.io/controller-runtime v0.19.3
sigs.k8s.io/gateway-api v1.2.1
)
@@ -56,25 +58,25 @@ require (
atomicgo.dev/cursor v0.2.0 // indirect
atomicgo.dev/keyboard v0.2.9 // indirect
atomicgo.dev/schedule v0.1.0 // indirect
cel.dev/expr v0.16.1 // indirect
cel.dev/expr v0.19.0 // indirect
cloud.google.com/go v0.116.0 // indirect
cloud.google.com/go/ai v0.8.0 // indirect
cloud.google.com/go/aiplatform v1.69.0 // indirect
cloud.google.com/go/auth v0.11.0 // indirect
cloud.google.com/go/auth/oauth2adapt v0.2.6 // indirect
cloud.google.com/go/compute/metadata v0.5.2 // indirect
cloud.google.com/go/auth v0.14.0 // indirect
cloud.google.com/go/auth/oauth2adapt v0.2.7 // indirect
cloud.google.com/go/compute/metadata v0.6.0 // indirect
cloud.google.com/go/iam v1.2.2 // indirect
cloud.google.com/go/longrunning v0.6.2 // indirect
cloud.google.com/go/monitoring v1.21.2 // indirect
dario.cat/mergo v1.0.1 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.16.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.3 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.24.1 // indirect
github.com/AzureAD/microsoft-authentication-library-for-go v1.3.2 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.25.0 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.48.1 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.48.1 // indirect
github.com/Microsoft/hcsshim v0.12.4 // indirect
github.com/alecthomas/units v0.0.0-20240626203959-61d1e3462e30 // indirect
github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b // indirect
github.com/aws/aws-sdk-go-v2 v1.32.3 // indirect
github.com/aws/smithy-go v1.22.0 // indirect
github.com/blang/semver/v4 v4.0.0 // indirect
@@ -88,8 +90,8 @@ require (
github.com/creack/pty v1.1.21 // indirect
github.com/distribution/reference v0.6.0 // indirect
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 // indirect
github.com/envoyproxy/go-control-plane v0.13.0 // indirect
github.com/envoyproxy/protoc-gen-validate v1.1.0 // indirect
github.com/envoyproxy/go-control-plane v0.13.1 // indirect
github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect
github.com/evanphx/json-patch/v5 v5.9.0 // indirect
github.com/expr-lang/expr v1.16.9 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
@@ -98,9 +100,9 @@ require (
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/google/gnostic-models v0.6.9-0.20230804172637-c7be7c783f49 // indirect
github.com/google/s2a-go v0.1.8 // indirect
github.com/google/s2a-go v0.1.9 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect
github.com/googleapis/gax-go/v2 v2.14.0 // indirect
github.com/googleapis/gax-go/v2 v2.14.1 // indirect
github.com/gookit/color v1.5.4 // indirect
github.com/gorilla/websocket v1.5.1 // indirect
github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc // indirect
@@ -113,29 +115,29 @@ require (
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
github.com/prometheus/common/sigv4 v0.1.0 // indirect
github.com/prometheus/sigv4 v0.1.1 // indirect
github.com/sagikazarmark/locafero v0.6.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/segmentio/fasthash v1.0.3 // indirect
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
github.com/sony/gobreaker v0.5.0 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/x448/float16 v0.8.4 // indirect
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/contrib/detectors/gcp v1.29.0 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/contrib/detectors/gcp v1.32.0 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0 // indirect
go.opentelemetry.io/otel/metric v1.31.0 // indirect
go.opentelemetry.io/otel/sdk v1.31.0 // indirect
go.opentelemetry.io/otel/sdk/metric v1.31.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0 // indirect
go.opentelemetry.io/otel/metric v1.34.0 // indirect
go.opentelemetry.io/otel/sdk v1.34.0 // indirect
go.opentelemetry.io/otel/sdk/metric v1.32.0 // indirect
gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
google.golang.org/genproto v0.0.0-20241118233622-e639e219e697 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20241118233622-e639e219e697 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20241118233622-e639e219e697 // indirect
google.golang.org/grpc/stats/opentelemetry v0.0.0-20240907200651-3ffb98b2c93a // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250115164207-1a7da9e5054f // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f // indirect
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
knative.dev/pkg v0.0.0-20241026180704-25f6002b00f3 // indirect
)
@@ -152,19 +154,19 @@ require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/chai2010/gettext-go v1.0.3 // indirect
github.com/containerd/containerd v1.7.23 // indirect
github.com/cyphar/filepath-securejoin v0.3.4 // indirect
github.com/containerd/containerd v1.7.24 // indirect
github.com/cyphar/filepath-securejoin v0.3.6 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/docker/cli v26.1.4+incompatible // indirect
github.com/docker/distribution v2.8.3+incompatible // indirect
github.com/docker/docker v27.3.1+incompatible // indirect
github.com/docker/docker v27.4.1+incompatible // indirect
github.com/docker/docker-credential-helpers v0.8.2 // indirect
github.com/docker/go-connections v0.5.0 // indirect
github.com/docker/go-metrics v0.0.1 // indirect
github.com/emicklei/go-restful/v3 v3.12.1 // indirect
github.com/evanphx/json-patch v5.9.0+incompatible // indirect
github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/fsnotify/fsnotify v1.8.0 // indirect
github.com/go-errors/errors v1.5.1 // indirect
github.com/go-gorp/gorp/v3 v3.1.0 // indirect
github.com/go-logr/logr v1.4.2 // indirect
@@ -188,12 +190,11 @@ require (
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/huandu/xstrings v1.5.0 // indirect
github.com/imdario/mergo v0.3.16 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jmoiron/sqlx v1.4.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.17.10 // indirect
github.com/klauspost/compress v1.17.11 // indirect
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect
github.com/lib/pq v1.10.9 // indirect
@@ -208,7 +209,7 @@ require (
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/moby/locker v1.0.1 // indirect
github.com/moby/spdystream v0.4.0 // indirect
github.com/moby/spdystream v0.5.0 // indirect
github.com/moby/term v0.5.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
@@ -220,13 +221,13 @@ require (
github.com/peterbourgon/diskv v2.0.1+incompatible // 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.20.5
github.com/prometheus/client_golang v1.21.0-rc.0
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.60.1 // indirect
github.com/prometheus/common v0.62.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/robfig/cron/v3 v3.0.1
github.com/rubenv/sql-migrate v1.7.0 // indirect
github.com/rubenv/sql-migrate v1.7.1 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/shopspring/decimal v1.4.0 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
@@ -238,40 +239,40 @@ require (
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
github.com/xlab/treeprint v1.2.0 // indirect
go.opentelemetry.io/otel v1.31.0 // indirect
go.opentelemetry.io/otel/trace v1.31.0 // indirect
go.opentelemetry.io/otel v1.34.0 // indirect
go.opentelemetry.io/otel/trace v1.34.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0
golang.org/x/crypto v0.35.0 // indirect
golang.org/x/crypto v0.36.0 // indirect
golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 // indirect
golang.org/x/net v0.36.0
golang.org/x/oauth2 v0.24.0 // indirect
golang.org/x/sync v0.11.0 // indirect
golang.org/x/sys v0.30.0 // indirect
golang.org/x/text v0.22.0 // indirect
golang.org/x/time v0.8.0 // indirect
google.golang.org/grpc v1.68.1
google.golang.org/protobuf v1.35.2 // indirect
golang.org/x/net v0.37.0
golang.org/x/oauth2 v0.25.0 // indirect
golang.org/x/sync v0.12.0 // indirect
golang.org/x/sys v0.31.0 // indirect
golang.org/x/text v0.23.0 // indirect
golang.org/x/time v0.9.0 // indirect
google.golang.org/grpc v1.70.0
google.golang.org/protobuf v1.36.4 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
k8s.io/apiextensions-apiserver v0.31.3
k8s.io/apiserver v0.31.3 // indirect
k8s.io/cli-runtime v0.31.1 // indirect
k8s.io/component-base v0.31.3 // indirect
k8s.io/apiextensions-apiserver v0.32.2
k8s.io/apiserver v0.32.2 // indirect
k8s.io/cli-runtime v0.32.2 // indirect
k8s.io/component-base v0.32.2 // indirect
k8s.io/klog/v2 v2.130.1 // indirect
k8s.io/kube-openapi v0.0.0-20241009091222-67ed5848f094 // indirect
k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f // indirect
k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e
oras.land/oras-go v1.2.5 // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect
sigs.k8s.io/kustomize/api v0.18.0 // indirect
sigs.k8s.io/kustomize/kyaml v0.18.1 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.4.2 // indirect
sigs.k8s.io/yaml v1.4.0 // indirect
)
// v1.2.0 is taken from github.com/open-policy-agent/opa v0.42.0
// v1.2.0 incompatible with github.com/docker/docker v23.0.0-rc.1+incompatible
//replace oras.land/oras-go => oras.land/oras-go v1.2.4
replace github.com/docker/docker => github.com/docker/docker v27.4.0+incompatible
replace github.com/docker/docker => github.com/docker/docker v28.0.4+incompatible
replace dario.cat/mergo => github.com/imdario/mergo v1.0.1

332
go.sum
View File

@@ -16,8 +16,8 @@ buf.build/gen/go/k8sgpt-ai/k8sgpt/grpc/go v1.5.1-20241118152629-1379a5a1889d.1 h
buf.build/gen/go/k8sgpt-ai/k8sgpt/grpc/go v1.5.1-20241118152629-1379a5a1889d.1/go.mod h1:rlbkTkVN2P3aNR0U/7N5d9/uvNW8/dzHwtJDfPzh2vc=
buf.build/gen/go/k8sgpt-ai/k8sgpt/protocolbuffers/go v1.35.2-20241118152629-1379a5a1889d.1 h1:Z+fW0kWryP6LdjP+z+d1/WT4tObrq890aye4aPIh6hM=
buf.build/gen/go/k8sgpt-ai/k8sgpt/protocolbuffers/go v1.35.2-20241118152629-1379a5a1889d.1/go.mod h1:dqopmdpTDT6p9kPTxVCgR8WDnNb1SjZjwzaNj/kRbps=
cel.dev/expr v0.16.1 h1:NR0+oFYzR1CqLFhTAqg3ql59G9VfN8fKq1TCHJ6gq1g=
cel.dev/expr v0.16.1/go.mod h1:AsGA5zb3WruAEQeQng1RZdGEXmBj0jvMWh6l5SnNuC8=
cel.dev/expr v0.19.0 h1:lXuo+nDhpyJSpWxpPVi5cPUwzKb+dsdOiw6IreM5yt0=
cel.dev/expr v0.19.0/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw=
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=
@@ -123,10 +123,10 @@ cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVo
cloud.google.com/go/assuredworkloads v1.8.0/go.mod h1:AsX2cqyNCOvEQC8RMPnoc0yEarXQk6WEKkxYfL6kGIo=
cloud.google.com/go/assuredworkloads v1.9.0/go.mod h1:kFuI1P78bplYtT77Tb1hi0FMxM0vVpRC7VVoJC3ZoT0=
cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E=
cloud.google.com/go/auth v0.11.0 h1:Ic5SZz2lsvbYcWT5dfjNWgw6tTlGi2Wc8hyQSC9BstA=
cloud.google.com/go/auth v0.11.0/go.mod h1:xxA5AqpDrvS+Gkmo9RqrGGRh6WSNKKOXhY3zNOr38tI=
cloud.google.com/go/auth/oauth2adapt v0.2.6 h1:V6a6XDu2lTwPZWOawrAa9HUK+DB2zfJyTuciBG5hFkU=
cloud.google.com/go/auth/oauth2adapt v0.2.6/go.mod h1:AlmsELtlEBnaNTL7jCj8VQFLy6mbZv0s4Q7NGBeQ5E8=
cloud.google.com/go/auth v0.14.0 h1:A5C4dKV/Spdvxcl0ggWwWEzzP7AZMJSEIgrkngwhGYM=
cloud.google.com/go/auth v0.14.0/go.mod h1:CYsoRL1PdiDuqeQpZE0bP2pnPrGqFcOkI0nldEQis+A=
cloud.google.com/go/auth/oauth2adapt v0.2.7 h1:/Lc7xODdqcEw8IrZ9SvwnlLX6j9FHQM74z6cBk9Rw6M=
cloud.google.com/go/auth/oauth2adapt v0.2.7/go.mod h1:NTbTTzfvPl1Y3V1nPpOgl2w6d/FjO7NNUQaWSox6ZMc=
cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0=
cloud.google.com/go/automl v1.6.0/go.mod h1:ugf8a6Fx+zP0D59WLhqgTDsQI9w07o64uf/Is3Nh5p8=
cloud.google.com/go/automl v1.7.0/go.mod h1:RL9MYCCsJEOmt0Wf3z9uzG0a7adTT1fe+aObgSpkCt8=
@@ -205,8 +205,8 @@ cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZ
cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM=
cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
cloud.google.com/go/compute/metadata v0.5.2 h1:UxK4uu/Tn+I3p2dYWTfiX4wva7aYlKixAHn3fyqngqo=
cloud.google.com/go/compute/metadata v0.5.2/go.mod h1:C66sj2AluDcIqakBq/M8lw8/ybHgOZqin2obFxa/E5k=
cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I=
cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg=
cloud.google.com/go/contactcenterinsights v1.3.0/go.mod h1:Eu2oemoePuEFc/xKFPjbTuPSj0fYJcPls9TFlPNnHHY=
cloud.google.com/go/contactcenterinsights v1.4.0/go.mod h1:L2YzkGbPsv+vMQMCADxJoT9YiTTnSEd6fEvCeHTYVck=
cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w=
@@ -644,12 +644,12 @@ gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zum
git.sr.ht/~sbinet/gg v0.3.1/go.mod h1:KGYtlADtqsqANL9ueOFkWymvzUvLMQllU5Ixo+8v3pc=
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU=
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.16.0 h1:JZg6HRh6W6U4OLl6lk7BZ7BLisIzM9dG1R50zUk9C/M=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.16.0/go.mod h1:YL1xnZ6QejvQHWJrX/AvhFl4WW4rqHVoKspWNVwFk0M=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0 h1:B/dfvscEQtew9dVuoxqxrUKKv8Ih2f55PydknDamU+g=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0/go.mod h1:fiPSssYvltE08HJchL04dOy+RD4hgrjph0cwGGMntdI=
github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.0 h1:+m0M/LFxN43KvULkDNfdXOgrjtg6UYJPFBJyuEcRCAw=
github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.0/go.mod h1:PwOyop78lveYMRs6oCxjiVyBdyCgIYH6XHIVZO9/SFQ=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0 h1:g0EZJwz7xkXQiZAI5xi9f3WWFYBlX1CPTrR+NDToRkQ=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0/go.mod h1:XCW7KnZet0Opnr7HccfUw1PLc4CjHqpcaxW8DHklNkQ=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.1 h1:1mvYtZfWQAnwNah/C+Z+Jb9rQH95LPE2vlmMuWAHJk8=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.1/go.mod h1:75I/mXtme1JyWFtz8GocPHVFyH421IBoZErnO16dd0k=
github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.1 h1:Bk5uOhSAenHyR5P61D/NzeQCv+4fEVV8mOkJ82NqpWw=
github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.1/go.mod h1:QZ4pw3or1WPmRBxf0cHd1tknzrT54WPBOQoGutCPvSU=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 h1:ywEEhmNahHBihViHepv3xPBn1663uRv2t2q/ESv9seY=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0/go.mod h1:iZDifYGJTIgIIkYRNWPENUnqx6bJ2xnSDFI2tjwZNuY=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5 v5.7.0 h1:LkHbJbgF3YyvC53aqYGR+wWQDn2Rdp9AQdGndf9QvY4=
@@ -664,8 +664,8 @@ github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/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.2.3 h1:6LyjnnaLpcOKK0fbYisI+mb8CE7iNe7i89nMNQxFxs8=
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.3/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
github.com/AzureAD/microsoft-authentication-library-for-go v1.3.2 h1:kYRSnvJju5gYVyhkij+RTJ/VR6QIUaCfWeaFm2ycsjQ=
github.com/AzureAD/microsoft-authentication-library-for-go v1.3.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c h1:pxW6RcqyfI9/kWtOwnv/G+AzdKuy2ZrqINhenH4HyNs=
github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
@@ -674,8 +674,8 @@ github.com/Code-Hex/go-generics-cache v1.5.1 h1:6vhZGc5M7Y/YD8cIUcY8kcuQLB4cHR7U
github.com/Code-Hex/go-generics-cache v1.5.1/go.mod h1:qxcC9kRVrct9rHeiYpFWSoW1vxyillCVzX13KZG8dl4=
github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU=
github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.24.1 h1:pB2F2JKCj1Znmp2rwxxt1J0Fg0wezTMgWYk5Mpbi1kg=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.24.1/go.mod h1:itPGVDKf9cC/ov4MdvJ2QZ0khw4bfoo9jzwTJlaxy2k=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.25.0 h1:3c8yed4lgqTt+oTQ+JNMDo+F4xprBf+O/il4ZC0nRLw=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.25.0/go.mod h1:obipzmGjfSjam60XLwGfqUkJsfiheAl+TUjG+4yzyPM=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.48.1 h1:UQ0AhxogsIRZDkElkblfnwjc3IaltCm2HUMvezQaL7s=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.48.1/go.mod h1:jyqM3eLpJ3IbIFDTKVz2rF9T/xWGW0rIriGwnz8l9Tk=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.48.1 h1:oTX4vsorBZo/Zdum6OKPA4o7544hm6smoRv1QjpTwGo=
@@ -713,17 +713,16 @@ github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d h1:UrqY+r/O
github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ=
github.com/adrg/xdg v0.5.3 h1:xRnxJXne7+oWDatRhR1JLnvuccuIeCoBu2rtuLqQB78=
github.com/adrg/xdg v0.5.3/go.mod h1:nlTsY+NNiCBGCK2tpm09vRqfVzrc2fLmXGpBLF0zlTQ=
github.com/agiledragon/gomonkey/v2 v2.13.0 h1:B24Jg6wBI1iB8EFR1c+/aoTg7QN/Cum7YffG8KMIyYo=
github.com/agiledragon/gomonkey/v2 v2.13.0/go.mod h1:ap1AmDzcVOAz1YpeJ3TCzIgstoaWLA6jbbgxfB4w2iY=
github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY=
github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk=
github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b/go.mod h1:1KcenG0jGWcpt8ov532z81sp/kMMUG485J2InIOyADM=
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=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
github.com/alecthomas/units v0.0.0-20240626203959-61d1e3462e30 h1:t3eaIm0rUkzbrIewtiFmMK5RXHej2XnoXNhxVsAYUfg=
github.com/alecthomas/units v0.0.0-20240626203959-61d1e3462e30/go.mod h1:fvzegU4vN3H1qMT+8wDmzjAcDONcgo2/SZ/TyfdUOFs=
github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b h1:mimo19zliBX/vSQ6PWWSL9lK8qwHozUj03+zLoEB8O0=
github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b/go.mod h1:fvzegU4vN3H1qMT+8wDmzjAcDONcgo2/SZ/TyfdUOFs=
github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/apache/arrow/go/v10 v10.0.1/go.mod h1:YvhnlEePVnBS4+0z3fhPfUy7W1Ikj0Ih0vcRo/gZ1M0=
@@ -736,9 +735,8 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkY
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/atomicgo/cursor v0.0.1/go.mod h1:cBON2QmmrysudxNBFthvMtN32r3jxVRIvzkUiF/RuIk=
github.com/aws/aws-sdk-go v1.38.35/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
github.com/aws/aws-sdk-go v1.55.5 h1:KKUZBfBoyqy5d3swXyiC7Q76ic40rYcbqH7qjh59kzU=
github.com/aws/aws-sdk-go v1.55.5/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU=
github.com/aws/aws-sdk-go v1.55.6 h1:cSg4pvZ3m8dgYcgqB97MrcdjUmZ1BeMYKUxMMB89IPk=
github.com/aws/aws-sdk-go v1.55.6/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU=
github.com/aws/aws-sdk-go-v2 v1.32.3 h1:T0dRlFBKcdaUPGNtkBSwHZxrtis8CQU17UpNBZYd0wk=
github.com/aws/aws-sdk-go-v2 v1.32.3/go.mod h1:2SK5n0a2karNTv5tbP1SjsX0uhttou00v/HpXKM1ZUo=
github.com/aws/smithy-go v1.22.0 h1:uunKnWlcoL3zO7q+gG2Pk53joueEOsnNB28QdMsmiMM=
@@ -794,13 +792,13 @@ github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78/go.mod h1:W+zGtBO5Y1Ig
github.com/cohere-ai/cohere-go/v2 v2.12.2 h1:8WJqqcCe3q6TB1CdhgzJOgRO2ouno8xcYcOoeWtI8Pk=
github.com/cohere-ai/cohere-go/v2 v2.12.2/go.mod h1:MuiJkCxlR18BDV2qQPbz2Yb/OCVphT1y6nD2zYaKeR0=
github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM=
github.com/containerd/cgroups/v3 v3.0.3 h1:S5ByHZ/h9PMe5IOQoN7E+nMc2UcLEM/V48DGDJ9kip0=
github.com/containerd/cgroups/v3 v3.0.3/go.mod h1:8HBe7V3aWGLFPd/k03swSIsGjZhHI2WzJmticMgVuz0=
github.com/containerd/cgroups/v3 v3.0.2 h1:f5WFqIVSgo5IZmtTT3qVBo6TzI1ON6sycSBKkymb9L0=
github.com/containerd/cgroups/v3 v3.0.2/go.mod h1:JUgITrzdFqp42uI2ryGA+ge0ap/nxzYgkGmIcetmErE=
github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U=
github.com/containerd/console v1.0.4 h1:F2g4+oChYvBTsASRTz8NP6iIAi97J3TtSAsLbIFn4ro=
github.com/containerd/console v1.0.4/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk=
github.com/containerd/containerd v1.7.23 h1:H2CClyUkmpKAGlhQp95g2WXHfLYc7whAuvZGBNYOOwQ=
github.com/containerd/containerd v1.7.23/go.mod h1:7QUzfURqZWCZV7RLNEn1XjUCQLEf0bkaK4GjUaZehxw=
github.com/containerd/containerd v1.7.24 h1:zxszGrGjrra1yYJW/6rhm9cJ1ZQ8rkKBR48brqsa7nA=
github.com/containerd/containerd v1.7.24/go.mod h1:7QUzfURqZWCZV7RLNEn1XjUCQLEf0bkaK4GjUaZehxw=
github.com/containerd/continuity v0.4.3 h1:6HVkalIp+2u1ZLH1J/pYX2oBVXlJZvh1X1A7bEZ9Su8=
github.com/containerd/continuity v0.4.3/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ=
github.com/containerd/errdefs v0.3.0 h1:FSZgGOeK4yuT/+DnF07/Olde/q4KBoMsaamhXxIMDp4=
@@ -813,16 +811,16 @@ github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46t
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/creack/pty v1.1.21 h1:1/QdRyBaHHJP61QkWMXlOIBfsgdDeeKfK8SYVUWJKf0=
github.com/creack/pty v1.1.21/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
github.com/cyphar/filepath-securejoin v0.3.4 h1:VBWugsJh2ZxJmLFSM06/0qzQyiQX2Qs0ViKrUAcqdZ8=
github.com/cyphar/filepath-securejoin v0.3.4/go.mod h1:8s/MCNJREmFK0H02MF6Ihv1nakJe4L/w3WZLHNkvlYM=
github.com/cyphar/filepath-securejoin v0.3.6 h1:4d9N5ykBnSp5Xn2JkhocYDkOpURL/18CYMpo6xB9uWM=
github.com/cyphar/filepath-securejoin v0.3.6/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI=
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/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/digitalocean/godo v1.126.0 h1:+Znh7VMQj/E8ArbjWnc7OKGjWfzC+I8OCSRp7r1MdD8=
github.com/digitalocean/godo v1.126.0/go.mod h1:PU8JB6I1XYkQIdHFop8lLAY9ojp6M0XcU0TWaQSxbrc=
github.com/digitalocean/godo v1.132.0 h1:n0x6+ZkwbyQBtIU1wwBhv26EINqHg0wWQiBXlwYg/HQ=
github.com/digitalocean/godo v1.132.0/go.mod h1:PU8JB6I1XYkQIdHFop8lLAY9ojp6M0XcU0TWaQSxbrc=
github.com/distribution/distribution/v3 v3.0.0-20221208165359-362910506bc2 h1:aBfCb7iqHmDEIp6fBvC/hQUddQfg+3qdYjwzaiP9Hnc=
github.com/distribution/distribution/v3 v3.0.0-20221208165359-362910506bc2/go.mod h1:WHNsWjnIn2V1LYOrME7e8KxSeKunYHsxEm4am0BUtcI=
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
@@ -831,8 +829,8 @@ github.com/docker/cli v26.1.4+incompatible h1:I8PHdc0MtxEADqYJZvhBrW9bo8gawKwwen
github.com/docker/cli v26.1.4+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 v27.4.0+incompatible h1:I9z7sQ5qyzO0BfAb9IMOawRkAGxhYsidKiTMcm0DU+A=
github.com/docker/docker v27.4.0+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v28.0.4+incompatible h1:JNNkBctYKurkw6FrHfKqY0nKIDf5nrbxjVBtS+cdcok=
github.com/docker/docker v28.0.4+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker-credential-helpers v0.8.2 h1:bX3YxiGzFP5sOXWc3bTPEXdEaZSeVMrFgOr3T+zrFAo=
github.com/docker/docker-credential-helpers v0.8.2/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M=
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
@@ -859,13 +857,13 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.m
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE=
github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34=
github.com/envoyproxy/go-control-plane v0.13.0 h1:HzkeUz1Knt+3bK+8LG1bxOO/jzWZmdxpwC51i202les=
github.com/envoyproxy/go-control-plane v0.13.0/go.mod h1:GRaKG3dwvFoTg4nj7aXdZnvMg4d7nvT/wl9WgVXn3Q8=
github.com/envoyproxy/go-control-plane v0.13.1 h1:vPfJZCkob6yTMEgS+0TwfTUfbHjfy/6vOJ8hUWX/uXE=
github.com/envoyproxy/go-control-plane v0.13.1/go.mod h1:X45hY0mufo6Fd0KW3rqsGvQMw58jvjymeCzBU3mWyHw=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J6romD608Ba7Hij42vrOBCo=
github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w=
github.com/envoyproxy/protoc-gen-validate v1.1.0 h1:tntQDh69XqOCOZsDz0lVJQez/2L6Uu2PdjCQwWCJ3bM=
github.com/envoyproxy/protoc-gen-validate v1.1.0/go.mod h1:sXRDRVmzEbkM7CVcM06s9shE/m23dg3wzjl0UWqJ2q4=
github.com/envoyproxy/protoc-gen-validate v1.2.1 h1:DEo3O99U8j4hBFwbJfrz9VtgcDfUKS7KJ7spH3d86P8=
github.com/envoyproxy/protoc-gen-validate v1.2.1/go.mod h1:d/C80l/jxXLdfEIhX1W2TmLfsJ31lvEjwamM4DxlWXU=
github.com/evanphx/json-patch v5.9.0+incompatible h1:fBXyNpNMuTTDdquAq/uisOr2lShz4oaXpDTX2bLe7ls=
github.com/evanphx/json-patch v5.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg=
@@ -885,8 +883,8 @@ github.com/foxcpp/go-mockdns v1.1.0 h1:jI0rD8M0wuYAxL7r/ynTrCQQq0BVqfB99Vgk7Dlme
github.com/foxcpp/go-mockdns v1.1.0/go.mod h1:IhLeSFGed3mJIAXPH2aiRQB+kqz7oqu8ld2qVbOu7Wk=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
@@ -903,13 +901,10 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2
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-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.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U=
github.com/go-latex/latex v0.0.0-20210823091927-c0d11ff05a81/go.mod h1:SX0U8uGpxhq9o2S/CELCSUxEWWAuoCUcVCQWv7G2OCk=
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.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
@@ -925,8 +920,8 @@ github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+Gr
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
github.com/go-pdf/fpdf v0.5.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M=
github.com/go-pdf/fpdf v0.6.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M=
github.com/go-resty/resty/v2 v2.13.1 h1:x+LHXBI2nMB1vqndymf26quycC4aggYJ7DECYbiz03g=
github.com/go-resty/resty/v2 v2.13.1/go.mod h1:GznXlLxkq6Nh4sU59rPmUw3VtgpO3aS96ORAI6Q7d+0=
github.com/go-resty/resty/v2 v2.16.3 h1:zacNT7lt4b8M/io2Ahj6yPypL7bqx9n1iprfQuodV+E=
github.com/go-resty/resty/v2 v2.16.3/go.mod h1:hkJtXbA2iKHzJheXYvQ8snQES5ZLGKMwQ07xAwp/fiA=
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
@@ -1042,11 +1037,11 @@ github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/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-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo=
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg=
github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/s2a-go v0.1.8 h1:zZDs9gcbt9ZPLV0ndSyQk6Kacx2g/X+SKYovpnz3SMM=
github.com/google/s2a-go v0.1.8/go.mod h1:6iNWHTpQ+nfNRN5E00MSdfDwVesa8hhS32PhPO8deJA=
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/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.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@@ -1071,8 +1066,8 @@ github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqE
github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY=
github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8=
github.com/googleapis/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI=
github.com/googleapis/gax-go/v2 v2.14.0 h1:f+jMrjBPl+DL9nI4IQzLUxMq7XrAqFYB7hBPqMNIe8o=
github.com/googleapis/gax-go/v2 v2.14.0/go.mod h1:lhBCnjdLrWRaPvLWhmc8IS24m9mr07qSYnHncrgo+zk=
github.com/googleapis/gax-go/v2 v2.14.1 h1:hb0FFeiPaQskmvakKu5EbCbpntQn48jyHuvrkurSS/Q=
github.com/googleapis/gax-go/v2 v2.14.1/go.mod h1:Hb/NubMaVM88SrNkvl8X/o8XWwDJEPqouaLeN2IUxoA=
github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4=
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
github.com/gookit/color v1.4.2/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQHCoQ=
@@ -1080,7 +1075,9 @@ github.com/gookit/color v1.5.0/go.mod h1:43aQb+Zerm/BWh2GnrgOQm7ffz7tvQXEKV6BFMl
github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0=
github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w=
github.com/gophercloud/gophercloud v1.14.1 h1:DTCNaTVGl8/cFu58O1JwWgis9gtISAFONqpMKNg/Vpw=
github.com/gophercloud/gophercloud v1.14.1/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM=
github.com/gophercloud/gophercloud/v2 v2.4.0 h1:XhP5tVEH3ni66NSNK1+0iSO6kaGPH/6srtx6Cr+8eCg=
github.com/gophercloud/gophercloud/v2 v2.4.0/go.mod h1:uJWNpTgJPSl2gyzJqcU/pIAhFUWvIkp8eE8M15n9rs4=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4=
github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q=
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
@@ -1096,10 +1093,10 @@ github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:Fecb
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 h1:TmHmbvxPmaegwhDubVz0lICL0J5Ka2vwTzhoePEXsGE=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0/go.mod h1:qztMSjm835F2bXf+5HKAPIS5qsmQDqZna/PgVt4rWtI=
github.com/hashicorp/consul/api v1.29.4 h1:P6slzxDLBOxUSj3fWo2o65VuKtbtOXFi7TSSgtXutuE=
github.com/hashicorp/consul/api v1.29.4/go.mod h1:HUlfw+l2Zy68ceJavv2zAyArl2fqhGWnMycyt56sBgg=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 h1:VNqngBF40hVlDloBruUehVYC3ArSgIyScOAyMRqBxRg=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1/go.mod h1:RBRO7fro65R6tjKzYgLAFo0t1QEXY1Dp+i/bvpRiqiQ=
github.com/hashicorp/consul/api v1.31.0 h1:32BUNLembeSRek0G/ZAM6WNfdEwYdYo8oQ4+JoqGkNQ=
github.com/hashicorp/consul/api v1.31.0/go.mod h1:2ZGIiXM3A610NmDULmCHd/aqBJj8CkMfOhswhOafxRg=
github.com/hashicorp/cronexpr v1.1.2 h1:wG/ZYIKT+RT3QkOdgYc+xsKWVRgnxJ1OJtjjy84fJ9A=
github.com/hashicorp/cronexpr v1.1.2/go.mod h1:P4wA0KBl9C5q2hABiMO7cp6jcIg96CDh1Efb3g1PWA4=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
@@ -1123,12 +1120,12 @@ github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iP
github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hashicorp/nomad/api v0.0.0-20240717122358-3d93bd3778f3 h1:fgVfQ4AC1avVOnu2cfms8VAiD8lUq3vWI8mTocOXN/w=
github.com/hashicorp/nomad/api v0.0.0-20240717122358-3d93bd3778f3/go.mod h1:svtxn6QnrQ69P23VvIWMR34tg3vmwLz4UdUzm1dSCgE=
github.com/hashicorp/nomad/api v0.0.0-20241218080744-e3ac00f30eec h1:+YBzb977VrmffaCX/OBm17dEVJUcWn5dW+eqs3aIJ/A=
github.com/hashicorp/nomad/api v0.0.0-20241218080744-e3ac00f30eec/go.mod h1:svtxn6QnrQ69P23VvIWMR34tg3vmwLz4UdUzm1dSCgE=
github.com/hashicorp/serf v0.10.1 h1:Z1H2J60yRKvfDYAOZLd2MU0ND4AH/WDz7xYHDWQsIPY=
github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4=
github.com/hetznercloud/hcloud-go/v2 v2.13.1 h1:jq0GP4QaYE5d8xR/Zw17s9qoaESRJMXfGmtD1a/qckQ=
github.com/hetznercloud/hcloud-go/v2 v2.13.1/go.mod h1:dhix40Br3fDiBhwaSG/zgaYOFFddpfBm/6R1Zz0IiF0=
github.com/hetznercloud/hcloud-go/v2 v2.18.0 h1:BemrVGeWI8Kn/pvaC1jBsHZxQMnRqOydS7Ju4BERB4Q=
github.com/hetznercloud/hcloud-go/v2 v2.18.0/go.mod h1:r5RTzv+qi8IbLcDIskTzxkFIji7Ovc8yNgepQR9M+UA=
github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI=
github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/hupe1980/go-huggingface v0.0.15 h1:tTWmUGGunC/BYz4hrwS8SSVtMYVYjceG2uhL8HxeXvw=
@@ -1136,14 +1133,12 @@ github.com/hupe1980/go-huggingface v0.0.15/go.mod h1:IRvsik3+b9BJyw9hCfw1arI6gDO
github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4=
github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
github.com/imdario/mergo v1.0.1 h1:lFIgOs30GMaV/2+qQ+eEBLbUL6h1YosdohE3ODy4hTs=
github.com/imdario/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/ionos-cloud/sdk-go/v6 v6.2.1 h1:mxxN+frNVmbFrmmFfXnBC3g2USYJrl6mc1LW2iNYbFY=
github.com/ionos-cloud/sdk-go/v6 v6.2.1/go.mod h1:SXrO9OGyWjd2rZhAhEpdYN6VUAODzzqRdqA9BCviQtI=
github.com/ionos-cloud/sdk-go/v6 v6.3.2 h1:2mUmrZZz6cPyT9IRX0T8fBLc/7XU/eTxP2Y5tS7/09k=
github.com/ionos-cloud/sdk-go/v6 v6.3.2/go.mod h1:SXrO9OGyWjd2rZhAhEpdYN6VUAODzzqRdqA9BCviQtI=
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
@@ -1156,14 +1151,12 @@ github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2E
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
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/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
@@ -1175,8 +1168,8 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/asmfmt v1.3.2/go.mod h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j0HLHbNSE=
github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
github.com/klauspost/compress v1.17.10 h1:oXAz+Vh0PMUvJczoi+flxpnBEPxoER1IaAnU/NMPtT0=
github.com/klauspost/compress v1.17.10/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.0.10/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
@@ -1185,7 +1178,6 @@ github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZY
github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b h1:udzkj9S/zlT5X367kqJis0QP7YMxobob6zhzq6Yre00=
github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b/go.mod h1:pcaDhQK0/NJZEvtCO0qQPPropqV0sJOJ6YW7X+9kRwM=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
@@ -1209,8 +1201,8 @@ github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0=
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE=
github.com/linode/linodego v1.41.0 h1:GcP7JIBr9iLRJ9FwAtb9/WCT1DuPJS/xUApapfdjtiY=
github.com/linode/linodego v1.41.0/go.mod h1:Ow4/XZ0yvWBzt3iAHwchvhSx30AyLintsSMvvQ2/SJY=
github.com/linode/linodego v1.46.0 h1:+uOG4SD2MIrhbrLrvOD5HrbdLN3D19Wgn3MgdUNQjeU=
github.com/linode/linodego v1.46.0/go.mod h1:vyklQRzZUWhFVBZdYx4dcYJU/gG9yKB9VUcUs6ub0Lk=
github.com/lithammer/fuzzysearch v1.1.8 h1:/HIuJnjHuXS8bKaiTMeeDlW2/AyIWk2brx1V8LFgLN4=
github.com/lithammer/fuzzysearch v1.1.8/go.mod h1:IdqeyBClc3FFqSzYq/MXESsS4S0FsZ5ajtkr5xPLts4=
github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA=
@@ -1233,8 +1225,8 @@ github.com/mattn/go-sqlite3 v1.14.14/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/miekg/dns v1.1.62 h1:cN8OuEF1/x5Rq6Np+h1epln8OiyPWV+lROx9LxcGgIQ=
github.com/miekg/dns v1.1.62/go.mod h1:mvDlcItzm+br7MToIKqkglaGhlFMHJ9DTNNWONWXbNQ=
github.com/miekg/dns v1.1.63 h1:8M5aAw6OMZfFXTT7K5V0Eu5YiiL8l7nUAkyN6C9YwaY=
github.com/miekg/dns v1.1.63/go.mod h1:6NGHfjhpmr5lt3XPLuyfDJi5AXbNIPM9PY6H6sF1Nfs=
github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY=
github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3/go.mod h1:RagcQ7I8IeTMnF8JTXieKnO4Z6JCsikNEzj0DwauVzE=
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ=
@@ -1255,8 +1247,8 @@ github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3N
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg=
github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc=
github.com/moby/spdystream v0.4.0 h1:Vy79D6mHeJJjiPdFEL2yku1kl0chZpJfZcPpb16BRl8=
github.com/moby/spdystream v0.4.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI=
github.com/moby/spdystream v0.5.0 h1:7r0J1Si3QO/kjRitvSLVVFUjxMEb/YLj6S9FF62JBCU=
github.com/moby/spdystream v0.5.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI=
github.com/moby/sys/mountinfo v0.7.1 h1:/tTvQaSJRr2FshkhXiIpux6fQ2Zvc4j7tAhMTStAG2g=
github.com/moby/sys/mountinfo v0.7.1/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI=
github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g=
@@ -1324,10 +1316,8 @@ github.com/poy/onpar v1.1.2/go.mod h1:6X8FLNoxyr9kkmnlqpK6LSoiOtrO6MICtWwEuWkLjz
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=
github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y=
github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
github.com/prometheus/client_golang v1.21.0-rc.0 h1:bR+RxBlwcr4q8hXkgSOA/J18j6n0/qH0Gb0DH+8c+RY=
github.com/prometheus/client_golang v1.21.0-rc.0/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg=
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=
@@ -1336,22 +1326,17 @@ github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
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.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
github.com/prometheus/common v0.29.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
github.com/prometheus/common v0.60.1 h1:FUas6GcOw66yB/73KC+BOZoFJmbo/1pojoILArPAaSc=
github.com/prometheus/common v0.60.1/go.mod h1:h0LYf1R1deLSKtD4Vdg8gy4RuOvENW2J/h19V5NADQw=
github.com/prometheus/common/sigv4 v0.1.0 h1:qoVebwtwwEhS85Czm2dSROY5fTo2PAPEVdDeppTwGX4=
github.com/prometheus/common/sigv4 v0.1.0/go.mod h1:2Jkxxk9yYvCkE5G1sQT7GuEXm57JrvHu9k5YwTjsNtI=
github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io=
github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
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.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/prometheus/prometheus v0.300.1 h1:9KKcTTq80gkzmXW0Et/QCFSrBPgmwiS3Hlcxc6o8KlM=
github.com/prometheus/prometheus v0.300.1/go.mod h1:gtTPY/XVyCdqqnjA3NzDMb0/nc5H9hOu1RMame+gHyM=
github.com/prometheus/prometheus v0.302.1 h1:xqVdrwrB4WNpdgJqxsz5loqFWNUZitsK8myqLuSZ6Ag=
github.com/prometheus/prometheus v0.302.1/go.mod h1:YcyCoTbUR/TM8rY3Aoeqr0AWTu/pu1Ehh+trpX3eRzg=
github.com/prometheus/sigv4 v0.1.1 h1:UJxjOqVcXctZlwDjpUpZ2OiMWJdFijgSofwLzO1Xk0Q=
github.com/prometheus/sigv4 v0.1.1/go.mod h1:RAmWVKqx0bwi0Qm4lrKMXFM0nhpesBcenfCtz9qRyH8=
github.com/pterm/pterm v0.12.27/go.mod h1:PhQ89w4i95rhgE+xedAoqous6K9X+r6aSOI2eFF7DZI=
github.com/pterm/pterm v0.12.29/go.mod h1:WI3qxgvoQFFGKGjGnJR849gU0TsEOvKn5Q8LlY1U7lg=
github.com/pterm/pterm v0.12.30/go.mod h1:MOqLIyMOgmTDz9yorcYbcw+HsgoZo3BQfg2wtl3HEFE=
@@ -1373,10 +1358,10 @@ github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6L
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
github.com/rubenv/sql-migrate v1.7.0 h1:HtQq1xyTN2ISmQDggnh0c9U3JlP8apWh8YO2jzlXpTI=
github.com/rubenv/sql-migrate v1.7.0/go.mod h1:S4wtDEG1CKn+0ShpTtzWhFpHHI5PvCUtiGI+C+Z2THE=
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/rubenv/sql-migrate v1.7.1 h1:f/o0WgfO/GqNuVg+6801K/KW3WdDSupzSjDYODmiUq4=
github.com/rubenv/sql-migrate v1.7.1/go.mod h1:Ob2Psprc0/3ggbM6wCzyYVFFuc6FyZrb2AS+ezLDFb4=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w=
@@ -1399,10 +1384,10 @@ github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG
github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
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.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/sony/gobreaker v0.5.0 h1:dRCvqm0P490vZPmy7ppEk2qCnCieBooFJ+YoXGYB+yg=
github.com/sony/gobreaker v0.5.0/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
@@ -1483,24 +1468,26 @@ go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
go.opentelemetry.io/contrib/detectors/gcp v1.29.0 h1:TiaiXB4DpGD3sdzNlYQxruQngn5Apwzi1X0DRhuGvDQ=
go.opentelemetry.io/contrib/detectors/gcp v1.29.0/go.mod h1:GW2aWZNwR2ZxDLdv8OyC2G8zkRoQBuURgV7RPQgcPoU=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/contrib/detectors/gcp v1.32.0 h1:P78qWqkLSShicHmAzfECaTgvslqHxblNE9j62Ws1NK8=
go.opentelemetry.io/contrib/detectors/gcp v1.32.0/go.mod h1:TVqo0Sda4Cv8gCIixd7LuLwW4EylumVWfhjZJjDD4DU=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 h1:r6I7RJCN86bpD/FQwedZ0vSixDpwuWREjW9oRMsmqDc=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0/go.mod h1:B9yO6b04uB80CzjedvewuqDhxJxi11s7/GtiGa8bAjI=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0 h1:UP6IpuHFkUgOQL9FFQFrZ+5LiwhhYRbi7VZSIx6Nj5s=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0/go.mod h1:qxuZLtbq5QDtdeSHsS7bcf6EH6uO6jUAgk764zd3rhM=
go.opentelemetry.io/otel v1.31.0 h1:NsJcKPIW0D0H3NgzPDHmo0WW6SptzPdqg/L1zsIm2hY=
go.opentelemetry.io/otel v1.31.0/go.mod h1:O0C14Yl9FgkjqcCZAsE053C13OaddMYr/hz6clDkEJE=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0 h1:CV7UdSGJt/Ao6Gp4CXckLxVRRsRgDHoI8XjbL3PDl8s=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0/go.mod h1:FRmFuRJfag1IZ2dPkHnEoSFVgTVPUd2qf5Vi69hLb8I=
go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY=
go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI=
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.29.0 h1:WDdP9acbMYjbKIyJUhTvtzj601sVJOqgWdUxSdR/Ysc=
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.29.0/go.mod h1:BLbf7zbNIONBLPwvFnwNHGj4zge8uTCM/UPIVW1Mq2I=
go.opentelemetry.io/otel/metric v1.31.0 h1:FSErL0ATQAmYHUIzSezZibnyVlft1ybhy4ozRPcF2fE=
go.opentelemetry.io/otel/metric v1.31.0/go.mod h1:C3dEloVbLuYoX41KpmAhOqNriGbA+qqH6PQ5E5mUfnY=
go.opentelemetry.io/otel/sdk v1.31.0 h1:xLY3abVHYZ5HSfOg3l2E5LUj2Cwva5Y7yGxnSW9H5Gk=
go.opentelemetry.io/otel/sdk v1.31.0/go.mod h1:TfRbMdhvxIIr/B2N2LQW2S5v9m3gOQ/08KsbbO5BPT0=
go.opentelemetry.io/otel/sdk/metric v1.31.0 h1:i9hxxLJF/9kkvfHppyLL55aW7iIJz4JjxTeYusH7zMc=
go.opentelemetry.io/otel/sdk/metric v1.31.0/go.mod h1:CRInTMVvNhUKgSAMbKyTMxqOBC0zgyxzW55lZzX43Y8=
go.opentelemetry.io/otel/trace v1.31.0 h1:ffjsj1aRouKewfr85U2aGagJ46+MvodynlQ1HYdmJys=
go.opentelemetry.io/otel/trace v1.31.0/go.mod h1:TXZkRk7SM2ZQLtR6eoAWQFIHPvzQ06FJAsO1tJg480A=
go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ=
go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE=
go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A=
go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU=
go.opentelemetry.io/otel/sdk/metric v1.32.0 h1:rZvFnvmvawYb0alrYkjraqJq0Z4ZUJAiyYCU9snn1CU=
go.opentelemetry.io/otel/sdk/metric v1.32.0/go.mod h1:PWeZlq0zt9YkYAp3gjKZ0eicRYvOh1Gd+X99x6GHpCQ=
go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k=
go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
@@ -1521,8 +1508,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs=
golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ=
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@@ -1581,8 +1568,8 @@ golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
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=
@@ -1621,7 +1608,6 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
@@ -1642,8 +1628,8 @@ golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/net v0.36.0 h1:vWF2fRbw4qslQsQzgFqZff+BItCvGFQqKzKIzx1rmoA=
golang.org/x/net v0.36.0/go.mod h1:bFmbeoIPfrw4sMHNhb4J9f6+tPziuGjq7Jk/38fxi1I=
golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c=
golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
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=
@@ -1672,8 +1658,8 @@ golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri
golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec=
golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I=
golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw=
golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE=
golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/oauth2 v0.25.0 h1:CY4y7XT9v0cRI9oupztF8AgiIu99L/ksR/Xp/6jrZ70=
golang.org/x/oauth2 v0.25.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
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=
@@ -1690,15 +1676,14 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
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=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -1708,7 +1693,6 @@ golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -1722,8 +1706,6 @@ golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -1743,7 +1725,6 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -1781,8 +1762,8 @@ golang.org/x/sys v0.4.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.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@@ -1791,8 +1772,8 @@ golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU=
golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s=
golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y=
golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g=
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=
@@ -1809,16 +1790,16 @@ golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
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=
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg=
golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY=
golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
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=
@@ -1827,6 +1808,7 @@ golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
@@ -1881,8 +1863,8 @@ golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ=
golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
golang.org/x/tools v0.29.0 h1:Xx0h3TtM9rzQpQuR4dKLrdglAmCEN5Oi+P74JdhdzXE=
golang.org/x/tools v0.29.0/go.mod h1:KMQVMRsVxU6nHCFXrBPhDB8XncLNLM0lIy/F14RP588=
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=
@@ -1958,8 +1940,8 @@ google.golang.org/api v0.108.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/
google.golang.org/api v0.110.0/go.mod h1:7FC4Vvx1Mooxh8C5HWjzZHcavuS2f6pmJpZx60ca7iI=
google.golang.org/api v0.111.0/go.mod h1:qtFHvU9mhgTJegR31csQ+rwxyUTHOKFqCKWp1J0fdw0=
google.golang.org/api v0.114.0/go.mod h1:ifYI2ZsFK6/uGddGfAD5BMxlnkBqCmqHSDUVi45N5Yg=
google.golang.org/api v0.210.0 h1:HMNffZ57OoZCRYSbdWVRoqOa8V8NIHLL0CzdBPLztWk=
google.golang.org/api v0.210.0/go.mod h1:B9XDZGnx2NtyjzVkOVTGrFSAVZgPcbedzKg/gTLwqBs=
google.golang.org/api v0.218.0 h1:x6JCjEWeZ9PFCRe9z0FBrNwj7pB7DOAqT35N+IPnAUA=
google.golang.org/api v0.218.0/go.mod h1:5VGHBAkxrA/8EFjLVEYmMUJ8/8+gWWQ3s4cFH0FxG2M=
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=
@@ -2104,12 +2086,12 @@ google.golang.org/genproto v0.0.0-20241118233622-e639e219e697 h1:ToEetK57OidYuqD
google.golang.org/genproto v0.0.0-20241118233622-e639e219e697/go.mod h1:JJrvXBWRZaFMxBufik1a4RpFw4HhgVtBBWQeQgUj2cc=
google.golang.org/genproto/googleapis/api v0.0.0-20230525234020-1aefcd67740a/go.mod h1:ts19tUU+Z0ZShN1y3aPyq2+O3d5FUNNgT6FtOzmrNn8=
google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig=
google.golang.org/genproto/googleapis/api v0.0.0-20241118233622-e639e219e697 h1:pgr/4QbFyktUv9CtQ/Fq4gzEE6/Xs7iCXbktaGzLHbQ=
google.golang.org/genproto/googleapis/api v0.0.0-20241118233622-e639e219e697/go.mod h1:+D9ySVjN8nY8YCVjc5O7PZDIdZporIDY3KaGfJunh88=
google.golang.org/genproto/googleapis/api v0.0.0-20250115164207-1a7da9e5054f h1:gap6+3Gk41EItBuyi4XX/bp4oqJ3UwuIMl25yGinuAA=
google.golang.org/genproto/googleapis/api v0.0.0-20250115164207-1a7da9e5054f/go.mod h1:Ic02D47M+zbarjYYUlK57y316f2MoN0gjAwI3f2S95o=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234015-3fc162c6f38a/go.mod h1:xURIpW9ES5+/GZhnV6beoEtxQrnkRGIfP5VQG2tCBLc=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA=
google.golang.org/genproto/googleapis/rpc v0.0.0-20241118233622-e639e219e697 h1:LWZqQOEjDyONlF1H6afSWpAL/znlREo2tHfLoe+8LMA=
google.golang.org/genproto/googleapis/rpc v0.0.0-20241118233622-e639e219e697/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f h1:OxYkA3wjPsZyBylwymxSHa7ViiW1Sml4ToBrncvFehI=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f/go.mod h1:+2Yz8+CLJbIfL9z73EW45avw8Lmge3xVElCP9zEKi50=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
@@ -2149,11 +2131,9 @@ google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCD
google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww=
google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw=
google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g=
google.golang.org/grpc v1.68.1 h1:oI5oTa11+ng8r8XMMN7jAOmWfPZWbYpCFaMUTACxkM0=
google.golang.org/grpc v1.68.1/go.mod h1:+q1XYFJjShcqn0QZHvCyeR4CXPA+llXIeUIfIe00waw=
google.golang.org/grpc v1.70.0 h1:pWFv03aZoHzlRKHWicjsZytKAiYCtNS0dHbXnIdq7jQ=
google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
google.golang.org/grpc/stats/opentelemetry v0.0.0-20240907200651-3ffb98b2c93a h1:UIpYSuWdWHSzjwcAFRLjKcPXFZVVLXGEM23W+NWqipw=
google.golang.org/grpc/stats/opentelemetry v0.0.0-20240907200651-3ffb98b2c93a/go.mod h1:9i1T9n4ZinTUZGgzENMi8MDDgbGC5mqTS75JAv6xN3A=
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=
@@ -2171,8 +2151,8 @@ google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io=
google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
google.golang.org/protobuf v1.36.4 h1:6A3ZDJHn/eNqc1i+IdefRzy/9PokBTPvcqMySR7NNIM=
google.golang.org/protobuf v1.36.4/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
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=
@@ -2190,9 +2170,7 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
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=
@@ -2201,8 +2179,8 @@ 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.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o=
gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g=
helm.sh/helm/v3 v3.16.3 h1:kb8bSxMeRJ+knsK/ovvlaVPfdis0X3/ZhYCSFRP+YmY=
helm.sh/helm/v3 v3.16.3/go.mod h1:zeVWGDR4JJgiRbT3AnNsjYaX8OTJlIE9zC+Q7F7iUSU=
helm.sh/helm/v3 v3.17.3 h1:3n5rW3D0ArjFl0p4/oWO8IbY/HKaNNwJtOQFdH2AZHg=
helm.sh/helm/v3 v3.17.3/go.mod h1:+uJKMH/UiMzZQOALR3XUf3BLIoczI2RKKD6bMhPh4G8=
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=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
@@ -2211,26 +2189,26 @@ 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=
honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las=
k8s.io/api v0.31.3 h1:umzm5o8lFbdN/hIXbrK9oRpOproJO62CV1zqxXrLgk8=
k8s.io/api v0.31.3/go.mod h1:UJrkIp9pnMOI9K2nlL6vwpxRzzEX5sWgn8kGQe92kCE=
k8s.io/apiextensions-apiserver v0.31.3 h1:+GFGj2qFiU7rGCsA5o+p/rul1OQIq6oYpQw4+u+nciE=
k8s.io/apiextensions-apiserver v0.31.3/go.mod h1:2DSpFhUZZJmn/cr/RweH1cEVVbzFw9YBu4T+U3mf1e4=
k8s.io/apimachinery v0.31.3 h1:6l0WhcYgasZ/wk9ktLq5vLaoXJJr5ts6lkaQzgeYPq4=
k8s.io/apimachinery v0.31.3/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo=
k8s.io/apiserver v0.31.3 h1:+1oHTtCB+OheqFEz375D0IlzHZ5VeQKX1KGXnx+TTuY=
k8s.io/apiserver v0.31.3/go.mod h1:PrxVbebxrxQPFhJk4powDISIROkNMKHibTg9lTRQ0Qg=
k8s.io/cli-runtime v0.31.1 h1:/ZmKhmZ6hNqDM+yf9s3Y4KEYakNXUn5sod2LWGGwCuk=
k8s.io/cli-runtime v0.31.1/go.mod h1:pKv1cDIaq7ehWGuXQ+A//1OIF+7DI+xudXtExMCbe9U=
k8s.io/client-go v0.31.3 h1:CAlZuM+PH2cm+86LOBemaJI/lQ5linJ6UFxKX/SoG+4=
k8s.io/client-go v0.31.3/go.mod h1:2CgjPUTpv3fE5dNygAr2NcM8nhHzXvxB8KL5gYc3kJs=
k8s.io/component-base v0.31.3 h1:DMCXXVx546Rfvhj+3cOm2EUxhS+EyztH423j+8sOwhQ=
k8s.io/component-base v0.31.3/go.mod h1:xME6BHfUOafRgT0rGVBGl7TuSg8Z9/deT7qq6w7qjIU=
k8s.io/api v0.32.2 h1:bZrMLEkgizC24G9eViHGOPbW+aRo9duEISRIJKfdJuw=
k8s.io/api v0.32.2/go.mod h1:hKlhk4x1sJyYnHENsrdCWw31FEmCijNGPJO5WzHiJ6Y=
k8s.io/apiextensions-apiserver v0.32.2 h1:2YMk285jWMk2188V2AERy5yDwBYrjgWYggscghPCvV4=
k8s.io/apiextensions-apiserver v0.32.2/go.mod h1:GPwf8sph7YlJT3H6aKUWtd0E+oyShk/YHWQHf/OOgCA=
k8s.io/apimachinery v0.32.2 h1:yoQBR9ZGkA6Rgmhbp/yuT9/g+4lxtsGYwW6dR6BDPLQ=
k8s.io/apimachinery v0.32.2/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE=
k8s.io/apiserver v0.32.2 h1:WzyxAu4mvLkQxwD9hGa4ZfExo3yZZaYzoYvvVDlM6vw=
k8s.io/apiserver v0.32.2/go.mod h1:PEwREHiHNU2oFdte7BjzA1ZyjWjuckORLIK/wLV5goM=
k8s.io/cli-runtime v0.32.2 h1:aKQR4foh9qeyckKRkNXUccP9moxzffyndZAvr+IXMks=
k8s.io/cli-runtime v0.32.2/go.mod h1:a/JpeMztz3xDa7GCyyShcwe55p8pbcCVQxvqZnIwXN8=
k8s.io/client-go v0.32.2 h1:4dYCD4Nz+9RApM2b/3BtVvBHw54QjMFUl1OLcJG5yOA=
k8s.io/client-go v0.32.2/go.mod h1:fpZ4oJXclZ3r2nDOv+Ux3XcJutfrwjKTCHz2H3sww94=
k8s.io/component-base v0.32.2 h1:1aUL5Vdmu7qNo4ZsE+569PV5zFatM9hl+lb3dEea2zU=
k8s.io/component-base v0.32.2/go.mod h1:PXJ61Vx9Lg+P5mS8TLd7bCIr+eMJRQTyXe8KvkrvJq0=
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/kube-openapi v0.0.0-20241009091222-67ed5848f094 h1:MErs8YA0abvOqJ8gIupA1Tz6PKXYUw34XsGlA7uSL1k=
k8s.io/kube-openapi v0.0.0-20241009091222-67ed5848f094/go.mod h1:7ioBJr1A6igWjsR2fxq2EZ0mlMwYLejazSIc2bzMp2U=
k8s.io/kubectl v0.31.1 h1:ih4JQJHxsEggFqDJEHSOdJ69ZxZftgeZvYo7M/cpp24=
k8s.io/kubectl v0.31.1/go.mod h1:aNuQoR43W6MLAtXQ/Bu4GDmoHlbhHKuyD49lmTC8eJM=
k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f h1:GA7//TjRY9yWGy1poLzYYJJ4JRdzg3+O6e8I+e+8T5Y=
k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f/go.mod h1:R/HEjbvWI0qdfb8viZUeVZm0X6IZnxAydC7YU42CMw4=
k8s.io/kubectl v0.32.2 h1:TAkag6+XfSBgkqK9I7ZvwtF0WVtUAvK8ZqTt+5zi1Us=
k8s.io/kubectl v0.32.2/go.mod h1:+h/NQFSPxiDZYX/WZaWw9fwYezGLISP0ud8nQKg+3g8=
k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e h1:KqK5c/ghOm8xkHYhlodbp6i6+r+ChV2vuAuVRdFbLro=
k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
knative.dev/pkg v0.0.0-20241026180704-25f6002b00f3 h1:uUSDGlOIkdPT4svjlhi+JEnP2Ufw7AM/F5QDYiEL02U=
@@ -2279,13 +2257,13 @@ sigs.k8s.io/controller-runtime v0.19.3 h1:XO2GvC9OPftRst6xWCpTgBZO04S2cbp0Qqkj8b
sigs.k8s.io/controller-runtime v0.19.3/go.mod h1:j4j87DqtsThvwTv5/Tc5NFRyyF/RF0ip4+62tbTSIUM=
sigs.k8s.io/gateway-api v1.2.1 h1:fZZ/+RyRb+Y5tGkwxFKuYuSRQHu9dZtbjenblleOLHM=
sigs.k8s.io/gateway-api v1.2.1/go.mod h1:EpNfEXNjiYfUJypf0eZ0P5iXA9ekSGWaS1WgPaM42X0=
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/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8=
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo=
sigs.k8s.io/kustomize/api v0.18.0 h1:hTzp67k+3NEVInwz5BHyzc9rGxIauoXferXyjv5lWPo=
sigs.k8s.io/kustomize/api v0.18.0/go.mod h1:f8isXnX+8b+SGLHQ6yO4JG1rdkZlvhaCf/uZbLVMb0U=
sigs.k8s.io/kustomize/kyaml v0.18.1 h1:WvBo56Wzw3fjS+7vBjN6TeivvpbW9GmRaWZ9CIVmt4E=
sigs.k8s.io/kustomize/kyaml v0.18.1/go.mod h1:C3L2BFVU1jgcddNBE1TxuVLgS46TjObMwW5FT9FcjYo=
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4=
sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08=
sigs.k8s.io/structured-merge-diff/v4 v4.4.2 h1:MdmvkGuXi/8io6ixD5wud3vOLwc1rj0aNqRlpuvjmwA=
sigs.k8s.io/structured-merge-diff/v4 v4.4.2/go.mod h1:N8f93tFZh9U6vpxwRArLiikrE5/2tiu1w1AGfACIGE4=
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=

View File

@@ -3,8 +3,12 @@ package ai
import (
"context"
"errors"
"github.com/aws/aws-sdk-go/service/bedrockruntime/bedrockruntimeiface"
"fmt"
"os"
"regexp"
"strings"
"github.com/aws/aws-sdk-go/service/bedrockruntime/bedrockruntimeiface"
"github.com/k8sgpt-ai/k8sgpt/pkg/ai/bedrock_support"
@@ -24,6 +28,7 @@ type AmazonBedRockClient struct {
temperature float32
topP float32
maxTokens int
models []bedrock_support.BedrockModel
}
// AmazonCompletion BedRock support region list US East (N. Virginia),US West (Oregon),Asia Pacific (Singapore),Asia Pacific (Tokyo),Europe (Frankfurt)
@@ -48,181 +53,200 @@ var BEDROCKER_SUPPORTED_REGION = []string{
AP_South_1,
}
var (
models = []bedrock_support.BedrockModel{
{
Name: "anthropic.claude-3-5-sonnet-20240620-v1:0",
Completion: &bedrock_support.CohereMessagesCompletion{},
Response: &bedrock_support.CohereMessagesResponse{},
Config: bedrock_support.BedrockModelConfig{
// sensible defaults
MaxTokens: 100,
Temperature: 0.5,
TopP: 0.9,
ModelName: "anthropic.claude-3-5-sonnet-20240620-v1:0",
},
var defaultModels = []bedrock_support.BedrockModel{
{
Name: "anthropic.claude-3-5-sonnet-20240620-v1:0",
Completion: &bedrock_support.CohereMessagesCompletion{},
Response: &bedrock_support.CohereMessagesResponse{},
Config: bedrock_support.BedrockModelConfig{
// sensible defaults
MaxTokens: 100,
Temperature: 0.5,
TopP: 0.9,
ModelName: "anthropic.claude-3-5-sonnet-20240620-v1:0",
},
{
Name: "us.anthropic.claude-3-5-sonnet-20241022-v2:0",
Completion: &bedrock_support.CohereCompletion{},
Response: &bedrock_support.CohereResponse{},
Config: bedrock_support.BedrockModelConfig{
// sensible defaults
MaxTokens: 100,
Temperature: 0.5,
TopP: 0.9,
ModelName: "us.anthropic.claude-3-5-sonnet-20241022-v2:0",
},
},
{
Name: "us.anthropic.claude-3-5-sonnet-20241022-v2:0",
Completion: &bedrock_support.CohereCompletion{},
Response: &bedrock_support.CohereResponse{},
Config: bedrock_support.BedrockModelConfig{
// sensible defaults
MaxTokens: 100,
Temperature: 0.5,
TopP: 0.9,
ModelName: "us.anthropic.claude-3-5-sonnet-20241022-v2:0",
},
{
Name: "anthropic.claude-v2",
Completion: &bedrock_support.CohereCompletion{},
Response: &bedrock_support.CohereResponse{},
Config: bedrock_support.BedrockModelConfig{
// sensible defaults
MaxTokens: 100,
Temperature: 0.5,
TopP: 0.9,
ModelName: "anthropic.claude-v2",
},
},
{
Name: "anthropic.claude-v2",
Completion: &bedrock_support.CohereCompletion{},
Response: &bedrock_support.CohereResponse{},
Config: bedrock_support.BedrockModelConfig{
// sensible defaults
MaxTokens: 100,
Temperature: 0.5,
TopP: 0.9,
ModelName: "anthropic.claude-v2",
},
{
Name: "anthropic.claude-v1",
Completion: &bedrock_support.CohereCompletion{},
Response: &bedrock_support.CohereResponse{},
Config: bedrock_support.BedrockModelConfig{
// sensible defaults
MaxTokens: 100,
Temperature: 0.5,
TopP: 0.9,
ModelName: "anthropic.claude-v1",
},
},
{
Name: "anthropic.claude-v1",
Completion: &bedrock_support.CohereCompletion{},
Response: &bedrock_support.CohereResponse{},
Config: bedrock_support.BedrockModelConfig{
// sensible defaults
MaxTokens: 100,
Temperature: 0.5,
TopP: 0.9,
ModelName: "anthropic.claude-v1",
},
{
Name: "anthropic.claude-instant-v1",
Completion: &bedrock_support.CohereCompletion{},
Response: &bedrock_support.CohereResponse{},
Config: bedrock_support.BedrockModelConfig{
// sensible defaults
MaxTokens: 100,
Temperature: 0.5,
TopP: 0.9,
ModelName: "anthropic.claude-instant-v1",
},
},
{
Name: "anthropic.claude-instant-v1",
Completion: &bedrock_support.CohereCompletion{},
Response: &bedrock_support.CohereResponse{},
Config: bedrock_support.BedrockModelConfig{
// sensible defaults
MaxTokens: 100,
Temperature: 0.5,
TopP: 0.9,
ModelName: "anthropic.claude-instant-v1",
},
{
Name: "ai21.j2-ultra-v1",
Completion: &bedrock_support.AI21{},
Response: &bedrock_support.AI21Response{},
Config: bedrock_support.BedrockModelConfig{
// sensible defaults
MaxTokens: 100,
Temperature: 0.5,
TopP: 0.9,
ModelName: "ai21.j2-ultra-v1",
},
},
{
Name: "ai21.j2-ultra-v1",
Completion: &bedrock_support.AI21{},
Response: &bedrock_support.AI21Response{},
Config: bedrock_support.BedrockModelConfig{
// sensible defaults
MaxTokens: 100,
Temperature: 0.5,
TopP: 0.9,
ModelName: "ai21.j2-ultra-v1",
},
{
Name: "ai21.j2-jumbo-instruct",
Completion: &bedrock_support.AI21{},
Response: &bedrock_support.AI21Response{},
Config: bedrock_support.BedrockModelConfig{
// sensible defaults
MaxTokens: 100,
Temperature: 0.5,
TopP: 0.9,
ModelName: "ai21.j2-jumbo-instruct",
},
},
{
Name: "ai21.j2-jumbo-instruct",
Completion: &bedrock_support.AI21{},
Response: &bedrock_support.AI21Response{},
Config: bedrock_support.BedrockModelConfig{
// sensible defaults
MaxTokens: 100,
Temperature: 0.5,
TopP: 0.9,
ModelName: "ai21.j2-jumbo-instruct",
},
{
Name: "amazon.titan-text-express-v1",
Completion: &bedrock_support.AmazonCompletion{},
Response: &bedrock_support.AmazonResponse{},
Config: bedrock_support.BedrockModelConfig{
// sensible defaults
MaxTokens: 100,
Temperature: 0.5,
TopP: 0.9,
ModelName: "amazon.titan-text-express-v1",
},
},
{
Name: "amazon.titan-text-express-v1",
Completion: &bedrock_support.AmazonCompletion{},
Response: &bedrock_support.AmazonResponse{},
Config: bedrock_support.BedrockModelConfig{
// sensible defaults
MaxTokens: 100,
Temperature: 0.5,
TopP: 0.9,
ModelName: "amazon.titan-text-express-v1",
},
{
Name: "amazon.nova-pro-v1:0",
Completion: &bedrock_support.AmazonCompletion{},
Response: &bedrock_support.NovaResponse{},
Config: bedrock_support.BedrockModelConfig{
// sensible defaults
// https://docs.aws.amazon.com/nova/latest/userguide/getting-started-api.html
MaxTokens: 100, // max of 300k tokens
Temperature: 0.5,
TopP: 0.9,
ModelName: "amazon.nova-pro-v1:0",
},
},
{
Name: "amazon.nova-pro-v1:0",
Completion: &bedrock_support.AmazonCompletion{},
Response: &bedrock_support.NovaResponse{},
Config: bedrock_support.BedrockModelConfig{
// sensible defaults
// https://docs.aws.amazon.com/nova/latest/userguide/getting-started-api.html
MaxTokens: 100, // max of 300k tokens
Temperature: 0.5,
TopP: 0.9,
ModelName: "amazon.nova-pro-v1:0",
},
{
Name: "eu.amazon.nova-pro-v1:0",
Completion: &bedrock_support.AmazonCompletion{},
Response: &bedrock_support.NovaResponse{},
Config: bedrock_support.BedrockModelConfig{
// sensible defaults
// https://docs.aws.amazon.com/nova/latest/userguide/getting-started-api.html
MaxTokens: 100, // max of 300k tokens
Temperature: 0.5,
TopP: 0.9,
ModelName: "eu.wamazon.nova-pro-v1:0",
},
},
{
Name: "eu.amazon.nova-pro-v1:0",
Completion: &bedrock_support.AmazonCompletion{},
Response: &bedrock_support.NovaResponse{},
Config: bedrock_support.BedrockModelConfig{
// sensible defaults
// https://docs.aws.amazon.com/nova/latest/userguide/getting-started-api.html
MaxTokens: 100, // max of 300k tokens
Temperature: 0.5,
TopP: 0.9,
ModelName: "eu.amazon.nova-pro-v1:0",
},
{
Name: "us.amazon.nova-pro-v1:0",
Completion: &bedrock_support.AmazonCompletion{},
Response: &bedrock_support.NovaResponse{},
Config: bedrock_support.BedrockModelConfig{
// sensible defaults
// https://docs.aws.amazon.com/nova/latest/userguide/getting-started-api.html
MaxTokens: 100, // max of 300k tokens
Temperature: 0.5,
TopP: 0.9,
ModelName: "us.amazon.nova-pro-v1:0",
},
},
{
Name: "us.amazon.nova-pro-v1:0",
Completion: &bedrock_support.AmazonCompletion{},
Response: &bedrock_support.NovaResponse{},
Config: bedrock_support.BedrockModelConfig{
// sensible defaults
// https://docs.aws.amazon.com/nova/latest/userguide/getting-started-api.html
MaxTokens: 100, // max of 300k tokens
Temperature: 0.5,
TopP: 0.9,
ModelName: "us.amazon.nova-pro-v1:0",
},
{
Name: "amazon.nova-lite-v1:0",
Completion: &bedrock_support.AmazonCompletion{},
Response: &bedrock_support.NovaResponse{},
Config: bedrock_support.BedrockModelConfig{
// sensible defaults
MaxTokens: 100, // max of 300k tokens
Temperature: 0.5,
TopP: 0.9,
ModelName: "amazon.nova-lite-v1:0",
},
},
{
Name: "amazon.nova-lite-v1:0",
Completion: &bedrock_support.AmazonCompletion{},
Response: &bedrock_support.NovaResponse{},
Config: bedrock_support.BedrockModelConfig{
// sensible defaults
MaxTokens: 100, // max of 300k tokens
Temperature: 0.5,
TopP: 0.9,
ModelName: "amazon.nova-lite-v1:0",
},
{
Name: "eu.amazon.nova-lite-v1:0",
Completion: &bedrock_support.AmazonCompletion{},
Response: &bedrock_support.NovaResponse{},
Config: bedrock_support.BedrockModelConfig{
// sensible defaults
MaxTokens: 100, // max of 300k tokens
Temperature: 0.5,
TopP: 0.9,
ModelName: "eu.amazon.nova-lite-v1:0",
},
},
{
Name: "eu.amazon.nova-lite-v1:0",
Completion: &bedrock_support.AmazonCompletion{},
Response: &bedrock_support.NovaResponse{},
Config: bedrock_support.BedrockModelConfig{
// sensible defaults
MaxTokens: 100, // max of 300k tokens
Temperature: 0.5,
TopP: 0.9,
ModelName: "eu.amazon.nova-lite-v1:0",
},
{
Name: "us.amazon.nova-lite-v1:0",
Completion: &bedrock_support.AmazonCompletion{},
Response: &bedrock_support.NovaResponse{},
Config: bedrock_support.BedrockModelConfig{
// sensible defaults
MaxTokens: 100, // max of 300k tokens
Temperature: 0.5,
TopP: 0.9,
ModelName: "us.amazon.nova-lite-v1:0",
},
},
{
Name: "us.amazon.nova-lite-v1:0",
Completion: &bedrock_support.AmazonCompletion{},
Response: &bedrock_support.NovaResponse{},
Config: bedrock_support.BedrockModelConfig{
// sensible defaults
MaxTokens: 100, // max of 300k tokens
Temperature: 0.5,
TopP: 0.9,
ModelName: "us.amazon.nova-lite-v1:0",
},
},
{
Name: "anthropic.claude-3-haiku-20240307-v1:0",
Completion: &bedrock_support.CohereCompletion{},
Response: &bedrock_support.CohereResponse{},
Config: bedrock_support.BedrockModelConfig{
// sensible defaults
MaxTokens: 100,
Temperature: 0.5,
TopP: 0.9,
},
},
}
// NewAmazonBedRockClient creates a new AmazonBedRockClient with the given models
func NewAmazonBedRockClient(models []bedrock_support.BedrockModel) *AmazonBedRockClient {
if models == nil {
models = defaultModels // Use default models if none provided
}
)
return &AmazonBedRockClient{
models: models,
}
}
// GetModelOrDefault check config region
func GetRegionOrDefault(region string) string {
@@ -243,16 +267,56 @@ func GetRegionOrDefault(region string) string {
// Get model from string
func (a *AmazonBedRockClient) getModelFromString(model string) (*bedrock_support.BedrockModel, error) {
for _, m := range models {
if model == m.Name {
return &m, nil
if model == "" {
return nil, errors.New("model name cannot be empty")
}
// Trim spaces from the model name
model = strings.TrimSpace(model)
modelLower := strings.ToLower(model)
// Try to find an exact match first
for i := range a.models {
if strings.EqualFold(model, a.models[i].Name) || strings.EqualFold(model, a.models[i].Config.ModelName) {
// Create a copy to avoid returning a pointer to a loop variable
modelCopy := a.models[i]
return &modelCopy, nil
}
}
return nil, errors.New("model not found")
// If no exact match, try partial match
for i := range a.models {
modelNameLower := strings.ToLower(a.models[i].Name)
modelConfigNameLower := strings.ToLower(a.models[i].Config.ModelName)
// Check if the input string contains the model name or vice versa
if strings.Contains(modelNameLower, modelLower) || strings.Contains(modelLower, modelNameLower) ||
strings.Contains(modelConfigNameLower, modelLower) || strings.Contains(modelLower, modelConfigNameLower) {
// Create a copy to avoid returning a pointer to a loop variable
modelCopy := a.models[i]
// for partial match, set the model name to the input string if it is a valid ARN
if validateModelArn(modelLower) {
modelCopy.Config.ModelName = modelLower
}
return &modelCopy, nil
}
}
return nil, fmt.Errorf("model '%s' not found in supported models", model)
}
func validateModelArn(model string) bool {
var re = regexp.MustCompile(`(?m)^arn:(?P<Partition>[^:\n]*):bedrock:(?P<Region>[^:\n]*):(?P<AccountID>[^:\n]*):(?P<Ignore>(?P<ResourceType>[^:\/\n]*)[:\/])?(?P<Resource>.*)$`)
return re.MatchString(model)
}
// Configure configures the AmazonBedRockClient with the provided configuration.
func (a *AmazonBedRockClient) Configure(config IAIConfig) error {
// Initialize models if not already initialized
if a.models == nil {
a.models = defaultModels
}
// Create a new AWS session
providerRegion := GetRegionOrDefault(config.GetProviderRegion())
@@ -269,7 +333,6 @@ func (a *AmazonBedRockClient) Configure(config IAIConfig) error {
if err != nil {
return err
}
// TODO: Override the completion config somehow
// Create a new BedrockRuntime client
a.client = bedrockruntime.New(sess)

View File

@@ -0,0 +1,139 @@
package ai
import (
"testing"
"github.com/k8sgpt-ai/k8sgpt/pkg/ai/bedrock_support"
"github.com/stretchr/testify/assert"
)
// Test models for unit testing
var testModels = []bedrock_support.BedrockModel{
{
Name: "anthropic.claude-3-5-sonnet-20240620-v1:0",
Completion: &bedrock_support.CohereMessagesCompletion{},
Response: &bedrock_support.CohereMessagesResponse{},
Config: bedrock_support.BedrockModelConfig{
MaxTokens: 100,
Temperature: 0.5,
TopP: 0.9,
ModelName: "anthropic.claude-3-5-sonnet-20240620-v1:0",
},
},
{
Name: "anthropic.claude-3-5-sonnet-20241022-v2:0",
Completion: &bedrock_support.CohereCompletion{},
Response: &bedrock_support.CohereResponse{},
Config: bedrock_support.BedrockModelConfig{
MaxTokens: 100,
Temperature: 0.5,
TopP: 0.9,
ModelName: "anthropic.claude-3-5-sonnet-20241022-v2:0",
},
},
}
func TestBedrockModelConfig(t *testing.T) {
client := &AmazonBedRockClient{models: testModels}
foundModel, err := client.getModelFromString("arn:aws:bedrock:us-east-1:*:inference-policy/anthropic.claude-3-5-sonnet-20240620-v1:0")
assert.Nil(t, err, "Error should be nil")
assert.Equal(t, foundModel.Config.MaxTokens, 100)
assert.Equal(t, foundModel.Config.Temperature, float32(0.5))
assert.Equal(t, foundModel.Config.TopP, float32(0.9))
assert.Equal(t, foundModel.Config.ModelName, "arn:aws:bedrock:us-east-1:*:inference-policy/anthropic.claude-3-5-sonnet-20240620-v1:0")
}
func TestBedrockInvalidModel(t *testing.T) {
client := &AmazonBedRockClient{models: testModels}
foundModel, err := client.getModelFromString("arn:aws:s3:us-east-1:*:inference-policy/anthropic.claude-3-5-sonnet-20240620-v1:0")
assert.Nil(t, err, "Error should be nil")
assert.Equal(t, foundModel.Config.MaxTokens, 100)
}
func TestGetModelFromString(t *testing.T) {
client := &AmazonBedRockClient{models: testModels}
tests := []struct {
name string
model string
wantModel string
wantErr bool
}{
{
name: "exact model name match",
model: "anthropic.claude-3-5-sonnet-20240620-v1:0",
wantModel: "anthropic.claude-3-5-sonnet-20240620-v1:0",
wantErr: false,
},
{
name: "partial model name match",
model: "claude-3-5-sonnet",
wantModel: "anthropic.claude-3-5-sonnet-20240620-v1:0",
wantErr: false,
},
{
name: "model name with different version",
model: "anthropic.claude-3-5-sonnet-20241022-v2:0",
wantModel: "anthropic.claude-3-5-sonnet-20241022-v2:0",
wantErr: false,
},
{
name: "non-existent model",
model: "non-existent-model",
wantModel: "",
wantErr: true,
},
{
name: "empty model name",
model: "",
wantModel: "",
wantErr: true,
},
{
name: "model name with extra spaces",
model: " anthropic.claude-3-5-sonnet-20240620-v1:0 ",
wantModel: "anthropic.claude-3-5-sonnet-20240620-v1:0",
wantErr: false,
},
{
name: "case insensitive match",
model: "ANTHROPIC.CLAUDE-3-5-SONNET-20240620-V1:0",
wantModel: "anthropic.claude-3-5-sonnet-20240620-v1:0",
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gotModel, err := client.getModelFromString(tt.model)
if (err != nil) != tt.wantErr {
t.Errorf("getModelFromString() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !tt.wantErr && gotModel.Name != tt.wantModel {
t.Errorf("getModelFromString() = %v, want %v", gotModel.Name, tt.wantModel)
}
})
}
}
// TestDefaultModels tests that the client works with default models
func TestDefaultModels(t *testing.T) {
client := &AmazonBedRockClient{}
// Configure should initialize default models
err := client.Configure(&AIProvider{
Model: "anthropic.claude-v2",
})
assert.NoError(t, err, "Configure should not return an error")
assert.NotNil(t, client.models, "Models should be initialized")
assert.NotEmpty(t, client.models, "Models should not be empty")
// Test finding a default model
model, err := client.getModelFromString("anthropic.claude-v2")
assert.NoError(t, err, "Should find the model")
assert.Equal(t, "anthropic.claude-v2", model.Name, "Should find the correct model")
}

View File

@@ -17,7 +17,12 @@ var SUPPPORTED_BEDROCK_MODELS = []string{
"ai21.j2-jumbo-instruct",
"amazon.titan-text-express-v1",
"amazon.nova-pro-v1:0",
"eu.amazon.nova-pro-v1:0",
"us.amazon.nova-pro-v1:0",
"amazon.nova-lite-v1:0",
"eu.amazon.nova-lite-v1:0",
"us.amazon.nova-lite-v1:0",
"anthropic.claude-3-haiku-20240307-v1:0",
}
type ICompletion interface {
@@ -91,7 +96,7 @@ type AmazonCompletion struct {
func isModelSupported(modelName string) bool {
for _, supportedModel := range SUPPPORTED_BEDROCK_MODELS {
if modelName == supportedModel {
if strings.Contains(modelName, supportedModel) {
return true
}
}

87
pkg/ai/factory.go Normal file
View File

@@ -0,0 +1,87 @@
/*
Copyright 2023 The K8sGPT Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package ai
import (
"github.com/spf13/viper"
)
// AIClientFactory is an interface for creating AI clients
type AIClientFactory interface {
NewClient(provider string) IAI
}
// DefaultAIClientFactory is the default implementation of AIClientFactory
type DefaultAIClientFactory struct{}
// NewClient creates a new AI client using the default implementation
func (f *DefaultAIClientFactory) NewClient(provider string) IAI {
return NewClient(provider)
}
// ConfigProvider is an interface for accessing configuration
type ConfigProvider interface {
UnmarshalKey(key string, rawVal interface{}) error
}
// ViperConfigProvider is the default implementation of ConfigProvider using Viper
type ViperConfigProvider struct{}
// UnmarshalKey unmarshals a key from the configuration using Viper
func (p *ViperConfigProvider) UnmarshalKey(key string, rawVal interface{}) error {
return viper.UnmarshalKey(key, rawVal)
}
// Default instances to be used
var (
DefaultClientFactory = &DefaultAIClientFactory{}
DefaultConfigProvider = &ViperConfigProvider{}
)
// For testing - these variables can be overridden in tests
var (
testAIClientFactory AIClientFactory = nil
testConfigProvider ConfigProvider = nil
)
// GetAIClientFactory returns the test factory if set, otherwise the default
func GetAIClientFactory() AIClientFactory {
if testAIClientFactory != nil {
return testAIClientFactory
}
return DefaultClientFactory
}
// GetConfigProvider returns the test provider if set, otherwise the default
func GetConfigProvider() ConfigProvider {
if testConfigProvider != nil {
return testConfigProvider
}
return DefaultConfigProvider
}
// For testing - set the test implementations
func SetTestAIClientFactory(factory AIClientFactory) {
testAIClientFactory = factory
}
func SetTestConfigProvider(provider ConfigProvider) {
testConfigProvider = provider
}
// Reset test implementations
func ResetTestImplementations() {
testAIClientFactory = nil
testConfigProvider = nil
}

View File

@@ -18,6 +18,7 @@ import (
"encoding/base64"
"errors"
"fmt"
"reflect"
"strings"
"sync"
"time"
@@ -89,19 +90,35 @@ func NewAnalysis(
// Get kubernetes client from viper.
kubecontext := viper.GetString("kubecontext")
kubeconfig := viper.GetString("kubeconfig")
verbose := viper.GetBool("verbose")
client, err := kubernetes.NewClient(kubecontext, kubeconfig)
if verbose {
fmt.Println("Debug: Checking kubernetes client initialization.")
}
if err != nil {
return nil, fmt.Errorf("initialising kubernetes client: %w", err)
}
if verbose {
fmt.Printf("Debug: Kubernetes client initialized, server=%s.\n", client.Config.Host)
}
// Load remote cache if it is configured.
cache, err := cache.GetCacheConfiguration()
if verbose {
fmt.Println("Debug: Checking cache configuration.")
}
if err != nil {
return nil, err
}
if verbose {
fmt.Printf("Debug: Cache configuration loaded, type=%s.\n", cache.GetName())
}
if noCache {
cache.DisableCache()
if verbose {
fmt.Println("Debug: Cache disabled.")
}
}
a := &Analysis{
@@ -117,12 +134,31 @@ func NewAnalysis(
WithDoc: withDoc,
WithStats: withStats,
}
if verbose {
fmt.Print("Debug: Analysis configuration loaded, ")
fmt.Printf("filters=%v, language=%s, ", filters, language)
if namespace == "" {
fmt.Printf("namespace=none, ")
} else {
fmt.Printf("namespace=%s, ", namespace)
}
if labelSelector == "" {
fmt.Printf("labelSelector=none, ")
} else {
fmt.Printf("labelSelector=%s, ", labelSelector)
}
fmt.Printf("explain=%t, maxConcurrency=%d, ", explain, maxConcurrency)
fmt.Printf("withDoc=%t, withStats=%t.\n", withDoc, withStats)
}
if !explain {
// Return early if AI use was not requested.
return a, nil
}
var configAI ai.AIConfiguration
if verbose {
fmt.Println("Debug: Checking AI configuration.")
}
if err := viper.UnmarshalKey("ai", &configAI); err != nil {
return nil, err
}
@@ -135,10 +171,16 @@ func NewAnalysis(
// Hence, use the default provider only if the backend is not specified by the user.
if configAI.DefaultProvider != "" && backend == "" {
backend = configAI.DefaultProvider
if verbose {
fmt.Printf("Debug: Using default AI provider %s.\n", backend)
}
}
if backend == "" {
backend = "openai"
if verbose {
fmt.Printf("Debug: Using default AI provider %s.\n", backend)
}
}
var aiProvider ai.AIProvider
@@ -153,12 +195,23 @@ func NewAnalysis(
return nil, fmt.Errorf("AI provider %s not specified in configuration. Please run k8sgpt auth", backend)
}
if verbose {
fmt.Printf("Debug: AI configuration loaded, provider=%s, ", backend)
fmt.Printf("baseUrl=%s, model=%s.\n", aiProvider.BaseURL, aiProvider.Model)
}
aiClient := ai.NewClient(aiProvider.Name)
customHeaders := util.NewHeaders(httpHeaders)
aiProvider.CustomHeaders = customHeaders
if verbose {
fmt.Println("Debug: Checking AI client initialization.")
}
if err := aiClient.Configure(&aiProvider); err != nil {
return nil, err
}
if verbose {
fmt.Println("Debug: AI client initialized.")
}
a.AIClient = aiClient
a.AnalysisAIProvider = aiProvider.Name
return a, nil
@@ -182,6 +235,18 @@ func (a *Analysis) RunCustomAnalysis() {
semaphore := make(chan struct{}, a.MaxConcurrency)
var wg sync.WaitGroup
var mutex sync.Mutex
verbose := viper.GetBool("verbose")
if verbose {
if len(customAnalyzers) == 0 {
fmt.Println("Debug: No custom analyzers found.")
} else {
cAnalyzerNames := make([]string, len(customAnalyzers))
for i, cAnalyzer := range customAnalyzers {
cAnalyzerNames[i] = cAnalyzer.Name
}
fmt.Printf("Debug: Found custom analyzers %v.\n", cAnalyzerNames)
}
}
for _, cAnalyzer := range customAnalyzers {
wg.Add(1)
semaphore <- struct{}{}
@@ -194,6 +259,9 @@ func (a *Analysis) RunCustomAnalysis() {
mutex.Unlock()
return
}
if verbose {
fmt.Printf("Debug: %s launched.\n", cAnalyzer.Name)
}
result, err := canClient.Run()
if result.Kind == "" {
@@ -206,10 +274,16 @@ func (a *Analysis) RunCustomAnalysis() {
mutex.Lock()
a.Errors = append(a.Errors, fmt.Sprintf("[%s] %s", cAnalyzer.Name, err))
mutex.Unlock()
if verbose {
fmt.Printf("Debug: %s completed with errors.\n", cAnalyzer.Name)
}
} else {
mutex.Lock()
a.Results = append(a.Results, result)
mutex.Unlock()
if verbose {
fmt.Printf("Debug: %s completed without errors.\n", cAnalyzer.Name)
}
}
<-semaphore
}(cAnalyzer, &wg, semaphore)
@@ -219,6 +293,7 @@ func (a *Analysis) RunCustomAnalysis() {
func (a *Analysis) RunAnalysis() {
activeFilters := viper.GetStringSlice("active_filters")
verbose := viper.GetBool("verbose")
coreAnalyzerMap, analyzerMap := analyzer.GetAnalyzerMap()
@@ -227,7 +302,13 @@ func (a *Analysis) RunAnalysis() {
if a.WithDoc {
var openApiErr error
if verbose {
fmt.Println("Debug: Fetching Kubernetes docs.")
}
openapiSchema, openApiErr = a.Client.Client.Discovery().OpenAPISchema()
if verbose {
fmt.Println("Debug: Checking Kubernetes docs.")
}
if openApiErr != nil {
a.Errors = append(a.Errors, fmt.Sprintf("[KubernetesDoc] %s", openApiErr))
}
@@ -247,6 +328,9 @@ func (a *Analysis) RunAnalysis() {
var mutex sync.Mutex
// if there are no filters selected and no active_filters then run coreAnalyzer
if len(a.Filters) == 0 && len(activeFilters) == 0 {
if verbose {
fmt.Println("Debug: No filters selected and no active filters found, run all core analyzers.")
}
for name, analyzer := range coreAnalyzerMap {
wg.Add(1)
semaphore <- struct{}{}
@@ -258,6 +342,9 @@ func (a *Analysis) RunAnalysis() {
}
// if the filters flag is specified
if len(a.Filters) != 0 {
if verbose {
fmt.Printf("Debug: Filter flags %v specified, run selected core analyzers.\n", a.Filters)
}
for _, filter := range a.Filters {
if analyzer, ok := analyzerMap[filter]; ok {
semaphore <- struct{}{}
@@ -272,6 +359,9 @@ func (a *Analysis) RunAnalysis() {
}
// use active_filters
if len(activeFilters) > 0 && verbose {
fmt.Printf("Debug: Found active filters %v, run selected core analyzers.\n", activeFilters)
}
for _, filter := range activeFilters {
if analyzer, ok := analyzerMap[filter]; ok {
semaphore <- struct{}{}
@@ -294,6 +384,10 @@ func (a *Analysis) executeAnalyzer(analyzer common.IAnalyzer, filter string, ana
}
// Run the analyzer
verbose := viper.GetBool("verbose")
if verbose {
fmt.Printf("Debug: %s launched.\n", reflect.TypeOf(analyzer).Name())
}
results, err := analyzer.Analyze(analyzerConfig)
if err != nil {
fmt.Println(err)
@@ -315,11 +409,17 @@ func (a *Analysis) executeAnalyzer(analyzer common.IAnalyzer, filter string, ana
a.Stats = append(a.Stats, stat)
}
a.Errors = append(a.Errors, fmt.Sprintf("[%s] %s", filter, err))
if verbose {
fmt.Printf("Debug: %s completed with errors.\n", reflect.TypeOf(analyzer).Name())
}
} else {
if a.WithStats {
a.Stats = append(a.Stats, stat)
}
a.Results = append(a.Results, results...)
if verbose {
fmt.Printf("Debug: %s completed without errors.\n", reflect.TypeOf(analyzer).Name())
}
}
<-semaphore
}
@@ -329,6 +429,11 @@ func (a *Analysis) GetAIResults(output string, anonymize bool) error {
return nil
}
verbose := viper.GetBool("verbose")
if verbose {
fmt.Println("Debug: Generating AI analysis.")
}
var bar *progressbar.ProgressBar
if output != "json" {
bar = progressbar.Default(int64(len(a.Results)))
@@ -337,6 +442,10 @@ func (a *Analysis) GetAIResults(output string, anonymize bool) error {
for index, analysis := range a.Results {
var texts []string
if bar != nil && verbose {
bar.Describe(fmt.Sprintf("Analyzing %s", analysis.Kind))
}
for _, failure := range analysis.Error {
if anonymize {
for _, s := range failure.Sensitive {

View File

@@ -17,13 +17,17 @@ import (
"context"
"encoding/json"
"fmt"
"reflect"
"strings"
"testing"
"github.com/agiledragon/gomonkey/v2"
"github.com/k8sgpt-ai/k8sgpt/pkg/ai"
"github.com/k8sgpt-ai/k8sgpt/pkg/analyzer"
"github.com/k8sgpt-ai/k8sgpt/pkg/cache"
"github.com/k8sgpt-ai/k8sgpt/pkg/common"
"github.com/k8sgpt-ai/k8sgpt/pkg/kubernetes"
"github.com/k8sgpt-ai/k8sgpt/pkg/util"
"github.com/magiconair/properties/assert"
"github.com/spf13/viper"
"github.com/stretchr/testify/require"
@@ -31,9 +35,15 @@ import (
networkingv1 "k8s.io/api/networking/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes/fake"
"k8s.io/client-go/rest"
)
// sub-function
// helper function: get type name of an analyzer
func getTypeName(i interface{}) string {
return reflect.TypeOf(i).Name()
}
// helper function: run analysis with filter
func analysis_RunAnalysisFilterTester(t *testing.T, filterFlag string) []common.Result {
clientset := fake.NewSimpleClientset(
&v1.Pod{
@@ -404,3 +414,252 @@ func TestGetAIResultForSanitizedFailures(t *testing.T) {
})
}
}
// Test: Verbose output in NewAnalysis with explain=false
func TestVerbose_NewAnalysisWithoutExplain(t *testing.T) {
// Set viper config.
viper.Set("verbose", true)
viper.Set("kubecontext", "dummy")
viper.Set("kubeconfig", "dummy")
// Patch kubernetes.NewClient to return a dummy client.
patches := gomonkey.ApplyFunc(kubernetes.NewClient, func(kubecontext, kubeconfig string) (*kubernetes.Client, error) {
return &kubernetes.Client{
Config: &rest.Config{Host: "fake-server"},
}, nil
})
defer patches.Reset()
output := util.CaptureOutput(func() {
a, err := NewAnalysis(
"", "english", []string{"Pod"}, "default", "", true,
false, // explain
10, false, false, []string{}, false,
)
require.NoError(t, err)
a.Close()
})
expectedOutputs := []string{
"Debug: Checking kubernetes client initialization.",
"Debug: Kubernetes client initialized, server=fake-server.",
"Debug: Checking cache configuration.",
"Debug: Cache configuration loaded, type=file.",
"Debug: Cache disabled.",
"Debug: Analysis configuration loaded, filters=[Pod], language=english, namespace=default, labelSelector=none, explain=false, maxConcurrency=10, withDoc=false, withStats=false.",
}
for _, expected := range expectedOutputs {
if !util.Contains(output, expected) {
t.Errorf("Expected output to contain: '%s', but got output: '%s'", expected, output)
}
}
}
// Test: Verbose output in NewAnalysis with explain=true
func TestVerbose_NewAnalysisWithExplain(t *testing.T) {
// Set viper config.
viper.Set("verbose", true)
viper.Set("kubecontext", "dummy")
viper.Set("kubeconfig", "dummy")
// Set a dummy AI configuration.
dummyAIConfig := map[string]interface{}{
"defaultProvider": "dummy",
"providers": []map[string]interface{}{
{
"name": "dummy",
"baseUrl": "http://dummy",
"model": "dummy-model",
"customHeaders": map[string]string{},
},
},
}
viper.Set("ai", dummyAIConfig)
// Patch kubernetes.NewClient to return a dummy client.
patches := gomonkey.ApplyFunc(kubernetes.NewClient, func(kubecontext, kubeconfig string) (*kubernetes.Client, error) {
return &kubernetes.Client{
Config: &rest.Config{Host: "fake-server"},
}, nil
})
defer patches.Reset()
// Patch ai.NewClient to return a NoOp client.
patches2 := gomonkey.ApplyFunc(ai.NewClient, func(name string) ai.IAI {
return &ai.NoOpAIClient{}
})
defer patches2.Reset()
output := util.CaptureOutput(func() {
a, err := NewAnalysis(
"", "english", []string{"Pod"}, "default", "", true,
true, // explain
10, false, false, []string{}, false,
)
require.NoError(t, err)
a.Close()
})
expectedOutputs := []string{
"Debug: Checking AI configuration.",
"Debug: Using default AI provider dummy.",
"Debug: AI configuration loaded, provider=dummy, baseUrl=http://dummy, model=dummy-model.",
"Debug: Checking AI client initialization.",
"Debug: AI client initialized.",
}
for _, expected := range expectedOutputs {
if !util.Contains(output, expected) {
t.Errorf("Expected output to contain: '%s', but got output: '%s'", expected, output)
}
}
}
// Test: Verbose output in RunAnalysis with filter flag
func TestVerbose_RunAnalysisWithFilter(t *testing.T) {
viper.Set("verbose", true)
// Run analysis with a filter flag ("Pod") to trigger debug output.
output := util.CaptureOutput(func() {
_ = analysis_RunAnalysisFilterTester(t, "Pod")
})
expectedOutputs := []string{
"Debug: Filter flags [Pod] specified, run selected core analyzers.",
"Debug: PodAnalyzer launched.",
"Debug: PodAnalyzer completed without errors.",
}
for _, expected := range expectedOutputs {
if !util.Contains(output, expected) {
t.Errorf("Expected output to contain: '%s', but got output: '%s'", expected, output)
}
}
}
// Test: Verbose output in RunAnalysis with active filter
func TestVerbose_RunAnalysisWithActiveFilter(t *testing.T) {
viper.Set("verbose", true)
viper.SetDefault("active_filters", "Ingress")
output := util.CaptureOutput(func() {
_ = analysis_RunAnalysisFilterTester(t, "")
})
expectedOutputs := []string{
"Debug: Found active filters [Ingress], run selected core analyzers.",
"Debug: IngressAnalyzer launched.",
"Debug: IngressAnalyzer completed without errors.",
}
for _, expected := range expectedOutputs {
if !util.Contains(output, expected) {
t.Errorf("Expected output to contain: '%s', but got output: '%s'", expected, output)
}
}
}
// Test: Verbose output in RunAnalysis without any filter (run all core analyzers)
func TestVerbose_RunAnalysisWithoutFilter(t *testing.T) {
viper.Set("verbose", true)
// Clear filter flag and active_filters to run all core analyzers.
viper.SetDefault("active_filters", []string{})
output := util.CaptureOutput(func() {
_ = analysis_RunAnalysisFilterTester(t, "")
})
// Check for debug message indicating no filters.
expectedNoFilter := "Debug: No filters selected and no active filters found, run all core analyzers."
if !util.Contains(output, expectedNoFilter) {
t.Errorf("Expected output to contain: '%s', but got output: '%s'", expectedNoFilter, output)
}
// Get all core analyzers from analyzer.GetAnalyzerMap()
coreAnalyzerMap, _ := analyzer.GetAnalyzerMap()
for _, analyzerInstance := range coreAnalyzerMap {
analyzerType := getTypeName(analyzerInstance)
expectedLaunched := fmt.Sprintf("Debug: %s launched.", analyzerType)
expectedCompleted := fmt.Sprintf("Debug: %s completed without errors.", analyzerType)
if !util.Contains(output, expectedLaunched) {
t.Errorf("Expected output to contain: '%s', but got output: '%s'", expectedLaunched, output)
}
if !util.Contains(output, expectedCompleted) {
t.Errorf("Expected output to contain: '%s', but got output: '%s'", expectedCompleted, output)
}
}
}
// Test: Verbose output in RunCustomAnalysis without custom analyzer
func TestVerbose_RunCustomAnalysisWithoutCustomAnalyzer(t *testing.T) {
viper.Set("verbose", true)
// Set custom_analyzers to empty array to trigger "No custom analyzers" debug message.
viper.Set("custom_analyzers", []interface{}{})
analysisObj := &Analysis{
MaxConcurrency: 1,
}
output := util.CaptureOutput(func() {
analysisObj.RunCustomAnalysis()
})
expected := "Debug: No custom analyzers found."
if !util.Contains(output, "Debug: No custom analyzers found.") {
t.Errorf("Expected output to contain: '%s', but got output: '%s'", expected, output)
}
}
// Test: Verbose output in RunCustomAnalysis with custom analyzer
func TestVerbose_RunCustomAnalysisWithCustomAnalyzer(t *testing.T) {
viper.Set("verbose", true)
// Set custom_analyzers with one custom analyzer using "fake" connection.
viper.Set("custom_analyzers", []map[string]interface{}{
{
"name": "TestCustomAnalyzer",
"connection": map[string]interface{}{"url": "127.0.0.1", "port": "2333"},
},
})
analysisObj := &Analysis{
MaxConcurrency: 1,
}
output := util.CaptureOutput(func() {
analysisObj.RunCustomAnalysis()
})
assert.Equal(t, 1, len(analysisObj.Errors)) // connection error
expectedOutputs := []string{
"Debug: Found custom analyzers [TestCustomAnalyzer].",
"Debug: TestCustomAnalyzer launched.",
"Debug: TestCustomAnalyzer completed with errors.",
}
for _, expected := range expectedOutputs {
if !util.Contains(output, expected) {
t.Errorf("Expected output to contain: '%s', but got output: '%s'", expected, output)
}
}
}
// Test: Verbose output in GetAIResults
func TestVerbose_GetAIResults(t *testing.T) {
viper.Set("verbose", true)
disabledCache := cache.New("disabled-cache")
disabledCache.DisableCache()
aiClient := &ai.NoOpAIClient{}
analysisObj := Analysis{
AIClient: aiClient,
Cache: disabledCache,
Results: []common.Result{
{
Kind: "Deployment",
Name: "test-deployment",
Error: []common.Failure{{Text: "test-problem", Sensitive: []common.Sensitive{}}},
Details: "test-solution",
ParentObject: "parent-resource",
},
},
Namespace: "default",
}
output := util.CaptureOutput(func() {
_ = analysisObj.GetAIResults("json", false)
})
expected := "Debug: Generating AI analysis."
if !util.Contains(output, expected) {
t.Errorf("Expected output to contain: '%s', but got output: '%s'", expected, output)
}
}

View File

@@ -22,179 +22,283 @@ import (
"github.com/k8sgpt-ai/k8sgpt/pkg/kubernetes"
"github.com/stretchr/testify/require"
batchv1 "k8s.io/api/batch/v1"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes/fake"
)
func TestCronJobAnalyzer(t *testing.T) {
suspend := new(bool)
*suspend = true
invalidStartingDeadline := new(int64)
*invalidStartingDeadline = -7
validStartingDeadline := new(int64)
*validStartingDeadline = 7
config := common.Analyzer{
Client: &kubernetes.Client{
Client: fake.NewSimpleClientset(
&batchv1.CronJob{
ObjectMeta: metav1.ObjectMeta{
Name: "CJ1",
// This CronJob won't be list because of namespace filtering.
Namespace: "test",
},
},
&batchv1.CronJob{
ObjectMeta: metav1.ObjectMeta{
Name: "CJ2",
Namespace: "default",
},
// A suspended CronJob will contribute to failures.
Spec: batchv1.CronJobSpec{
Suspend: suspend,
},
},
&batchv1.CronJob{
ObjectMeta: metav1.ObjectMeta{
Name: "CJ3",
Namespace: "default",
},
Spec: batchv1.CronJobSpec{
// Valid schedule
Schedule: "*/1 * * * *",
// Negative starting deadline
StartingDeadlineSeconds: invalidStartingDeadline,
},
},
&batchv1.CronJob{
ObjectMeta: metav1.ObjectMeta{
Name: "CJ4",
Namespace: "default",
},
Spec: batchv1.CronJobSpec{
// Invalid schedule
Schedule: "*** * * * *",
},
},
&batchv1.CronJob{
ObjectMeta: metav1.ObjectMeta{
Name: "CJ5",
Namespace: "default",
},
Spec: batchv1.CronJobSpec{
// Valid schedule
Schedule: "*/1 * * * *",
// Positive starting deadline shouldn't be any problem.
StartingDeadlineSeconds: validStartingDeadline,
},
},
&batchv1.CronJob{
// This cronjob shouldn't contribute to any failures.
ObjectMeta: metav1.ObjectMeta{
Name: "successful-cronjob",
Namespace: "default",
Annotations: map[string]string{
"analysisDate": "2022-04-01",
},
Labels: map[string]string{
"app": "example-app",
},
},
Spec: batchv1.CronJobSpec{
Schedule: "*/1 * * * *",
ConcurrencyPolicy: "Allow",
JobTemplate: batchv1.JobTemplateSpec{
tests := []struct {
name string
config common.Analyzer
expectations []struct {
name string
failuresCount int
}
}{
{
name: "Suspended CronJob",
config: common.Analyzer{
Client: &kubernetes.Client{
Client: fake.NewSimpleClientset(
&batchv1.CronJob{
ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{
"app": "example-app",
},
Name: "suspended-job",
Namespace: "default",
},
Spec: batchv1.JobSpec{
Template: v1.PodTemplateSpec{
Spec: v1.PodSpec{
Containers: []v1.Container{
{
Name: "example-container",
Image: "nginx",
},
},
RestartPolicy: v1.RestartPolicyOnFailure,
},
},
Spec: batchv1.CronJobSpec{
Schedule: "*/5 * * * *",
Suspend: boolPtr(true),
},
},
},
),
},
),
Context: context.Background(),
Namespace: "default",
},
expectations: []struct {
name string
failuresCount int
}{
{
name: "default/suspended-job",
failuresCount: 1, // One failure for being suspended
},
},
},
{
name: "Invalid schedule format",
config: common.Analyzer{
Client: &kubernetes.Client{
Client: fake.NewSimpleClientset(
&batchv1.CronJob{
ObjectMeta: metav1.ObjectMeta{
Name: "invalid-schedule",
Namespace: "default",
},
Spec: batchv1.CronJobSpec{
Schedule: "invalid-cron", // Invalid cron format
},
},
),
},
Context: context.Background(),
Namespace: "default",
},
expectations: []struct {
name string
failuresCount int
}{
{
name: "default/invalid-schedule",
failuresCount: 1, // One failure for invalid schedule
},
},
},
{
name: "Negative starting deadline",
config: common.Analyzer{
Client: &kubernetes.Client{
Client: fake.NewSimpleClientset(
&batchv1.CronJob{
ObjectMeta: metav1.ObjectMeta{
Name: "negative-deadline",
Namespace: "default",
},
Spec: batchv1.CronJobSpec{
Schedule: "*/5 * * * *",
StartingDeadlineSeconds: int64Ptr(-60), // Negative deadline
},
},
),
},
Context: context.Background(),
Namespace: "default",
},
expectations: []struct {
name string
failuresCount int
}{
{
name: "default/negative-deadline",
failuresCount: 1, // One failure for negative deadline
},
},
},
{
name: "Valid CronJob",
config: common.Analyzer{
Client: &kubernetes.Client{
Client: fake.NewSimpleClientset(
&batchv1.CronJob{
ObjectMeta: metav1.ObjectMeta{
Name: "valid-job",
Namespace: "default",
},
Spec: batchv1.CronJobSpec{
Schedule: "*/5 * * * *", // Valid cron format
},
},
),
},
Context: context.Background(),
Namespace: "default",
},
expectations: []struct {
name string
failuresCount int
}{
// No expectations for valid job
},
},
{
name: "Multiple issues",
config: common.Analyzer{
Client: &kubernetes.Client{
Client: fake.NewSimpleClientset(
&batchv1.CronJob{
ObjectMeta: metav1.ObjectMeta{
Name: "multiple-issues",
Namespace: "default",
},
Spec: batchv1.CronJobSpec{
Schedule: "invalid-cron",
StartingDeadlineSeconds: int64Ptr(-60),
},
},
),
},
Context: context.Background(),
Namespace: "default",
},
expectations: []struct {
name string
failuresCount int
}{
{
name: "default/multiple-issues",
failuresCount: 2, // Two failures: invalid schedule and negative deadline
},
},
},
Context: context.Background(),
Namespace: "default",
}
cjAnalyzer := CronJobAnalyzer{}
results, err := cjAnalyzer.Analyze(config)
require.NoError(t, err)
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
analyzer := CronJobAnalyzer{}
results, err := analyzer.Analyze(tt.config)
require.NoError(t, err)
require.Len(t, results, len(tt.expectations))
sort.Slice(results, func(i, j int) bool {
return results[i].Name < results[j].Name
})
// Sort results by name for consistent comparison
sort.Slice(results, func(i, j int) bool {
return results[i].Name < results[j].Name
})
expectations := []string{
"default/CJ2",
"default/CJ3",
"default/CJ4",
}
require.Equal(t, len(expectations), len(results))
for i, result := range results {
require.Equal(t, expectations[i], result.Name)
for i, expectation := range tt.expectations {
require.Equal(t, expectation.name, results[i].Name)
require.Len(t, results[i].Error, expectation.failuresCount)
}
})
}
}
func TestCronJobAnalyzerLabelSelectorFiltering(t *testing.T) {
suspend := new(bool)
*suspend = true
invalidStartingDeadline := new(int64)
*invalidStartingDeadline = -7
validStartingDeadline := new(int64)
*validStartingDeadline = 7
func TestCronJobAnalyzerLabelSelector(t *testing.T) {
clientSet := fake.NewSimpleClientset(
&batchv1.CronJob{
ObjectMeta: metav1.ObjectMeta{
Name: "job-with-label",
Namespace: "default",
Labels: map[string]string{
"app": "test",
},
},
Spec: batchv1.CronJobSpec{
Schedule: "invalid-cron", // This should trigger a failure
},
},
&batchv1.CronJob{
ObjectMeta: metav1.ObjectMeta{
Name: "job-without-label",
Namespace: "default",
},
Spec: batchv1.CronJobSpec{
Schedule: "invalid-cron", // This should trigger a failure
},
},
)
// Test with label selector
config := common.Analyzer{
Client: &kubernetes.Client{
Client: fake.NewSimpleClientset(
&batchv1.CronJob{
ObjectMeta: metav1.ObjectMeta{
Name: "CJ1",
Namespace: "default",
Labels: map[string]string{
"app": "cronjob",
},
},
},
&batchv1.CronJob{
ObjectMeta: metav1.ObjectMeta{
Name: "CJ2",
Namespace: "default",
},
},
),
Client: clientSet,
},
Context: context.Background(),
Namespace: "default",
LabelSelector: "app=cronjob",
LabelSelector: "app=test",
}
cjAnalyzer := CronJobAnalyzer{}
results, err := cjAnalyzer.Analyze(config)
analyzer := CronJobAnalyzer{}
results, err := analyzer.Analyze(config)
require.NoError(t, err)
require.Equal(t, 1, len(results))
require.Equal(t, "default/CJ1", results[0].Name)
require.Equal(t, "default/job-with-label", results[0].Name)
}
func TestCheckCronScheduleIsValid(t *testing.T) {
tests := []struct {
name string
schedule string
wantErr bool
}{
{
name: "Valid schedule - every 5 minutes",
schedule: "*/5 * * * *",
wantErr: false,
},
{
name: "Valid schedule - specific time",
schedule: "0 2 * * *",
wantErr: false,
},
{
name: "Valid schedule - complex",
schedule: "0 0 1,15 * 3",
wantErr: false,
},
{
name: "Invalid schedule - wrong format",
schedule: "invalid-cron",
wantErr: true,
},
{
name: "Invalid schedule - too many fields",
schedule: "* * * * * *",
wantErr: true,
},
{
name: "Invalid schedule - empty string",
schedule: "",
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
_, err := CheckCronScheduleIsValid(tt.schedule)
if tt.wantErr {
require.Error(t, err)
} else {
require.NoError(t, err)
}
})
}
}
// Helper functions
func boolPtr(b bool) *bool {
return &b
}
func int64Ptr(i int64) *int64 {
return &i
}

137
pkg/analyzer/events_test.go Normal file
View File

@@ -0,0 +1,137 @@
package analyzer_test
import (
"context"
"errors"
"testing"
"time"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/kubernetes/fake"
)
func FetchLatestEvent(ctx context.Context, client kubernetes.Interface, namespace, eventName string) (*v1.Event, error) {
// List events in the specified namespace
events, err := client.CoreV1().Events(namespace).List(ctx, metav1.ListOptions{})
if err != nil {
return nil, err
}
var latestEvent *v1.Event
for _, event := range events.Items {
// Check if the event name matches the requested name (partial match)
if eventName == "" || event.Name == eventName {
if latestEvent == nil || event.LastTimestamp.Time.After(latestEvent.LastTimestamp.Time) {
latestEvent = &event
}
}
}
// If no matching event is found, return an error
if latestEvent == nil {
return nil, errors.New("no matching events found")
}
return latestEvent, nil
}
func TestFetchLatestEvent(t *testing.T) {
fakeClient := fake.NewSimpleClientset()
// Simulating events with different timestamps
event1 := &v1.Event{
ObjectMeta: metav1.ObjectMeta{
Name: "test-event-1",
Namespace: "default",
},
LastTimestamp: metav1.Time{Time: time.Now()},
}
event2 := &v1.Event{
ObjectMeta: metav1.ObjectMeta{
Name: "test-event-2",
Namespace: "default",
},
LastTimestamp: metav1.Time{Time: time.Now().Add(-time.Hour)}, // event1 should be fetched as it's newer
}
// ✅ Explicitly ensure namespace exists
_, err := fakeClient.CoreV1().Namespaces().Create(context.TODO(), &v1.Namespace{
ObjectMeta: metav1.ObjectMeta{Name: "default"},
}, metav1.CreateOptions{})
if err != nil {
t.Fatalf("Failed to create namespace: %v", err)
}
// ✅ Ensure events are properly created and stored in the fake client
_, err = fakeClient.CoreV1().Events("default").Create(context.TODO(), event1, metav1.CreateOptions{})
if err != nil {
t.Fatalf("Failed to create event1: %v", err)
}
_, err = fakeClient.CoreV1().Events("default").Create(context.TODO(), event2, metav1.CreateOptions{})
if err != nil {
t.Fatalf("Failed to create event2: %v", err)
}
// 🔍 Debug: Check if events exist before running FetchLatestEvent
storedEvents, _ := fakeClient.CoreV1().Events("default").List(context.TODO(), metav1.ListOptions{})
if len(storedEvents.Items) == 0 {
t.Fatal("No events were found in the fake client. Ensure event creation is working correctly.")
}
// Test cases
tests := []struct {
name string
namespace string
nameToFind string
expected *v1.Event
shouldFail bool
}{
{
name: "Valid case - fetch the latest event",
namespace: "default",
nameToFind: "test-event-1", // Match exact event name
expected: event1, // event1 has the latest timestamp
shouldFail: false,
},
{
name: "Nonexistent event",
namespace: "default",
nameToFind: "nonexistent-event", // Should not exist
expected: nil,
shouldFail: true,
},
{
name: "Nonexistent namespace",
namespace: "nonexistent-namespace", // Namespace doesn't exist
nameToFind: "test-event",
expected: nil,
shouldFail: true,
},
}
// Run tests
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Call the function to fetch the latest event
event, err := FetchLatestEvent(context.TODO(), fakeClient, tt.namespace, tt.nameToFind)
// Handle the expected outcomes based on the test case
if tt.shouldFail {
if err == nil {
t.Error("Expected an error, but got nil")
}
if event != nil {
t.Errorf("Expected nil event, but got event: %s", event.Name)
}
} else {
if err != nil {
t.Errorf("Expected no error, but got %v", err)
}
if event != nil && event.Name != tt.expected.Name {
t.Errorf("Expected event name %s, got %s", tt.expected.Name, event.Name)
}
}
})
}
}

View File

@@ -28,213 +28,334 @@ import (
)
func TestIngressAnalyzer(t *testing.T) {
validIgClassName := new(string)
*validIgClassName = "valid-ingress-class"
var igRule networkingv1.IngressRule
httpRule := networkingv1.HTTPIngressRuleValue{
Paths: []networkingv1.HTTPIngressPath{
{
Path: "/",
Backend: networkingv1.IngressBackend{
Service: &networkingv1.IngressServiceBackend{
// This service exists.
Name: "Service1",
},
},
},
{
Path: "/test1",
Backend: networkingv1.IngressBackend{
Service: &networkingv1.IngressServiceBackend{
// This service is in the test namespace
// Hence, it won't be discovered.
Name: "Service2",
},
},
},
{
Path: "/test2",
Backend: networkingv1.IngressBackend{
Service: &networkingv1.IngressServiceBackend{
// This service doesn't exist.
Name: "Service3",
},
},
},
},
}
igRule.IngressRuleValue.HTTP = &httpRule
config := common.Analyzer{
Client: &kubernetes.Client{
Client: fake.NewSimpleClientset(
&networkingv1.Ingress{
// Doesn't specify an ingress class.
ObjectMeta: metav1.ObjectMeta{
Name: "Ingress1",
Namespace: "default",
},
},
&networkingv1.Ingress{
ObjectMeta: metav1.ObjectMeta{
Name: "Ingress2",
Namespace: "default",
// Specify an invalid ingress class name using annotations.
Annotations: map[string]string{
"kubernetes.io/ingress.class": "invalid-class",
},
},
},
&networkingv1.Ingress{
// Namespace filtering.
ObjectMeta: metav1.ObjectMeta{
Name: "Ingress3",
Namespace: "test",
},
},
&networkingv1.IngressClass{
ObjectMeta: metav1.ObjectMeta{
Name: *validIgClassName,
},
},
&networkingv1.Ingress{
ObjectMeta: metav1.ObjectMeta{
Name: "Ingress4",
Namespace: "default",
// Specify valid ingress class name using annotations.
Annotations: map[string]string{
"kubernetes.io/ingress.class": *validIgClassName,
},
},
},
&v1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: "Service1",
Namespace: "default",
},
},
&v1.Service{
ObjectMeta: metav1.ObjectMeta{
// Namespace filtering.
Name: "Service2",
Namespace: "test",
},
},
&v1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "Secret1",
Namespace: "default",
},
},
&v1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "Secret2",
Namespace: "test",
},
},
&networkingv1.Ingress{
ObjectMeta: metav1.ObjectMeta{
Name: "Ingress5",
Namespace: "default",
},
// Specify valid ingress class name in spec.
Spec: networkingv1.IngressSpec{
IngressClassName: validIgClassName,
Rules: []networkingv1.IngressRule{
igRule,
},
TLS: []networkingv1.IngressTLS{
{
// This won't contribute to any failures.
SecretName: "Secret1",
},
{
// This secret won't be discovered because of namespace filtering.
SecretName: "Secret2",
},
{
// This secret doesn't exist.
SecretName: "Secret3",
},
},
},
},
),
},
Context: context.Background(),
Namespace: "default",
}
igAnalyzer := IngressAnalyzer{}
results, err := igAnalyzer.Analyze(config)
require.NoError(t, err)
sort.Slice(results, func(i, j int) bool {
return results[i].Name < results[j].Name
})
expectations := []struct {
name string
failuresCount int
tests := []struct {
name string
config common.Analyzer
expectations []struct {
name string
failuresCount int
}
}{
{
name: "default/Ingress1",
failuresCount: 1,
name: "Missing ingress class",
config: common.Analyzer{
Client: &kubernetes.Client{
Client: fake.NewSimpleClientset(
&networkingv1.Ingress{
ObjectMeta: metav1.ObjectMeta{
Name: "no-class",
Namespace: "default",
},
Spec: networkingv1.IngressSpec{
// No ingress class specified
},
},
),
},
Context: context.Background(),
Namespace: "default",
},
expectations: []struct {
name string
failuresCount int
}{
{
name: "default/no-class",
failuresCount: 1, // One failure for missing ingress class
},
},
},
{
name: "default/Ingress2",
failuresCount: 1,
name: "Non-existent ingress class",
config: common.Analyzer{
Client: &kubernetes.Client{
Client: fake.NewSimpleClientset(
&networkingv1.Ingress{
ObjectMeta: metav1.ObjectMeta{
Name: "bad-class",
Namespace: "default",
},
Spec: networkingv1.IngressSpec{
IngressClassName: strPtr("non-existent"),
},
},
),
},
Context: context.Background(),
Namespace: "default",
},
expectations: []struct {
name string
failuresCount int
}{
{
name: "default/bad-class",
failuresCount: 1, // One failure for non-existent ingress class
},
},
},
{
name: "default/Ingress5",
failuresCount: 4,
name: "Non-existent backend service",
config: common.Analyzer{
Client: &kubernetes.Client{
Client: fake.NewSimpleClientset(
&networkingv1.Ingress{
ObjectMeta: metav1.ObjectMeta{
Name: "bad-backend",
Namespace: "default",
Annotations: map[string]string{
"kubernetes.io/ingress.class": "nginx",
},
},
Spec: networkingv1.IngressSpec{
Rules: []networkingv1.IngressRule{
{
Host: "example.com",
IngressRuleValue: networkingv1.IngressRuleValue{
HTTP: &networkingv1.HTTPIngressRuleValue{
Paths: []networkingv1.HTTPIngressPath{
{
Path: "/",
PathType: pathTypePtr(networkingv1.PathTypePrefix),
Backend: networkingv1.IngressBackend{
Service: &networkingv1.IngressServiceBackend{
Name: "non-existent-service",
Port: networkingv1.ServiceBackendPort{
Number: 80,
},
},
},
},
},
},
},
},
},
},
},
),
},
Context: context.Background(),
Namespace: "default",
},
expectations: []struct {
name string
failuresCount int
}{
{
name: "default/bad-backend",
failuresCount: 2, // Two failures: non-existent ingress class and non-existent service
},
},
},
{
name: "Non-existent TLS secret",
config: common.Analyzer{
Client: &kubernetes.Client{
Client: fake.NewSimpleClientset(
&networkingv1.Ingress{
ObjectMeta: metav1.ObjectMeta{
Name: "bad-tls",
Namespace: "default",
Annotations: map[string]string{
"kubernetes.io/ingress.class": "nginx",
},
},
Spec: networkingv1.IngressSpec{
TLS: []networkingv1.IngressTLS{
{
Hosts: []string{"example.com"},
SecretName: "non-existent-secret",
},
},
},
},
),
},
Context: context.Background(),
Namespace: "default",
},
expectations: []struct {
name string
failuresCount int
}{
{
name: "default/bad-tls",
failuresCount: 2, // Two failures: non-existent ingress class and non-existent TLS secret
},
},
},
{
name: "Valid ingress with all components",
config: common.Analyzer{
Client: &kubernetes.Client{
Client: fake.NewSimpleClientset(
&networkingv1.Ingress{
ObjectMeta: metav1.ObjectMeta{
Name: "valid-ingress",
Namespace: "default",
},
Spec: networkingv1.IngressSpec{
IngressClassName: strPtr("nginx"),
},
},
&networkingv1.IngressClass{
ObjectMeta: metav1.ObjectMeta{
Name: "nginx",
},
},
&v1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: "backend-service",
Namespace: "default",
},
},
&v1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "tls-secret",
Namespace: "default",
},
Type: v1.SecretTypeTLS,
},
),
},
Context: context.Background(),
Namespace: "default",
},
expectations: []struct {
name string
failuresCount int
}{
// No expectations for valid ingress
},
},
{
name: "Multiple issues",
config: common.Analyzer{
Client: &kubernetes.Client{
Client: fake.NewSimpleClientset(
&networkingv1.Ingress{
ObjectMeta: metav1.ObjectMeta{
Name: "multiple-issues",
Namespace: "default",
},
Spec: networkingv1.IngressSpec{
IngressClassName: strPtr("non-existent"),
Rules: []networkingv1.IngressRule{
{
Host: "example.com",
IngressRuleValue: networkingv1.IngressRuleValue{
HTTP: &networkingv1.HTTPIngressRuleValue{
Paths: []networkingv1.HTTPIngressPath{
{
Path: "/",
PathType: pathTypePtr(networkingv1.PathTypePrefix),
Backend: networkingv1.IngressBackend{
Service: &networkingv1.IngressServiceBackend{
Name: "non-existent-service",
Port: networkingv1.ServiceBackendPort{
Number: 80,
},
},
},
},
},
},
},
},
},
TLS: []networkingv1.IngressTLS{
{
Hosts: []string{"example.com"},
SecretName: "non-existent-secret",
},
},
},
},
),
},
Context: context.Background(),
Namespace: "default",
},
expectations: []struct {
name string
failuresCount int
}{
{
name: "default/multiple-issues",
failuresCount: 3, // Three failures: ingress class, service, and TLS secret
},
},
},
}
require.Equal(t, len(expectations), len(results))
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
analyzer := IngressAnalyzer{}
results, err := analyzer.Analyze(tt.config)
require.NoError(t, err)
require.Len(t, results, len(tt.expectations))
for i, result := range results {
require.Equal(t, expectations[i].name, result.Name)
require.Equal(t, expectations[i].failuresCount, len(result.Error))
// Sort results by name for consistent comparison
sort.Slice(results, func(i, j int) bool {
return results[i].Name < results[j].Name
})
for i, expectation := range tt.expectations {
require.Equal(t, expectation.name, results[i].Name)
require.Len(t, results[i].Error, expectation.failuresCount)
}
})
}
}
func TestIngressAnalyzerLabelSelectorFiltering(t *testing.T) {
validIgClassName := new(string)
*validIgClassName = "valid-ingress-class"
func TestIngressAnalyzerLabelSelector(t *testing.T) {
clientSet := fake.NewSimpleClientset(
&networkingv1.Ingress{
ObjectMeta: metav1.ObjectMeta{
Name: "ingress-with-label",
Namespace: "default",
Labels: map[string]string{
"app": "test",
},
},
Spec: networkingv1.IngressSpec{
// Missing ingress class to trigger a failure
},
},
&networkingv1.Ingress{
ObjectMeta: metav1.ObjectMeta{
Name: "ingress-without-label",
Namespace: "default",
},
Spec: networkingv1.IngressSpec{
// Missing ingress class to trigger a failure
},
},
)
// Test with label selector
config := common.Analyzer{
Client: &kubernetes.Client{
Client: fake.NewSimpleClientset(
&networkingv1.Ingress{
ObjectMeta: metav1.ObjectMeta{
Name: "Ingress1",
Namespace: "default",
Labels: map[string]string{
"app": "ingress",
},
},
},
&networkingv1.Ingress{
ObjectMeta: metav1.ObjectMeta{
Name: "Ingress2",
Namespace: "default",
},
},
),
Client: clientSet,
},
Context: context.Background(),
Namespace: "default",
LabelSelector: "app=ingress",
LabelSelector: "app=test",
}
igAnalyzer := IngressAnalyzer{}
results, err := igAnalyzer.Analyze(config)
analyzer := IngressAnalyzer{}
results, err := analyzer.Analyze(config)
require.NoError(t, err)
require.Equal(t, 1, len(results))
require.Equal(t, "default/Ingress1", results[0].Name)
require.Equal(t, "default/ingress-with-label", results[0].Name)
}
// Helper functions
func strPtr(s string) *string {
return &s
}
func pathTypePtr(p networkingv1.PathType) *networkingv1.PathType {
return &p
}

View File

@@ -123,6 +123,20 @@ func analyzeContainerStatusFailures(a common.Analyzer, statuses []v1.ContainerSt
Sensitive: []common.Sensitive{},
})
}
} else if containerStatus.State.Terminated != nil {
if containerStatus.State.Terminated.ExitCode != 0 {
// This represents a container that is terminated abnormally
// https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#container-state-terminated
exitCode := containerStatus.State.Terminated.ExitCode
reason := containerStatus.State.Terminated.Reason
if reason == "" {
reason = "Unknown"
}
failures = append(failures, common.Failure{
Text: fmt.Sprintf("the termination reason is %s exitCode=%d container=%s pod=%s", reason, exitCode, containerStatus.Name, name),
Sensitive: []common.Sensitive{},
})
}
} else {
// when pod is Running but its ReadinessProbe fails
if !containerStatus.Ready && statusPhase == "Running" {

View File

@@ -343,6 +343,57 @@ func TestPodAnalyzer(t *testing.T) {
},
},
},
{
name: "Terminated container with non-zero exit code",
config: common.Analyzer{
Client: &kubernetes.Client{
Client: fake.NewSimpleClientset(
&v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "Pod1",
Namespace: "default",
},
Status: v1.PodStatus{
Phase: v1.PodFailed,
ContainerStatuses: []v1.ContainerStatus{
{
Name: "Container1",
Ready: false,
State: v1.ContainerState{
Terminated: &v1.ContainerStateTerminated{
ExitCode: 1,
Reason: "Error",
},
},
},
{
Name: "Container2",
Ready: false,
State: v1.ContainerState{
Terminated: &v1.ContainerStateTerminated{
ExitCode: 2,
Reason: "",
},
},
},
},
},
},
),
},
Context: context.Background(),
Namespace: "default",
},
expectations: []struct {
name string
failuresCount int
}{
{
name: "default/Pod1",
failuresCount: 2,
},
},
},
}
podAnalyzer := PodAnalyzer{}

View File

@@ -24,145 +24,232 @@ import (
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes/fake"
"k8s.io/client-go/tools/leaderelection/resourcelock"
)
func TestServiceAnalyzer(t *testing.T) {
config := common.Analyzer{
Client: &kubernetes.Client{
Client: fake.NewSimpleClientset(
&v1.Endpoints{
ObjectMeta: metav1.ObjectMeta{
Name: "Endpoint1",
Namespace: "test",
},
// Endpoint with non-zero subsets.
Subsets: []v1.EndpointSubset{
{
// These not ready end points will contribute to failures.
NotReadyAddresses: []v1.EndpointAddress{
{
TargetRef: &v1.ObjectReference{
Kind: "test-reference",
Name: "reference1",
},
},
{
TargetRef: &v1.ObjectReference{
Kind: "test-reference",
Name: "reference2",
},
},
},
},
{
// These not ready end points will contribute to failures.
NotReadyAddresses: []v1.EndpointAddress{
{
TargetRef: &v1.ObjectReference{
Kind: "test-reference",
Name: "reference3",
},
},
},
},
},
},
&v1.Endpoints{
ObjectMeta: metav1.ObjectMeta{
Name: "Endpoint2",
Namespace: "test",
Annotations: map[string]string{
// Leader election record annotation key defined.
resourcelock.LeaderElectionRecordAnnotationKey: "this is okay",
},
},
// Endpoint with zero subsets.
},
&v1.Endpoints{
ObjectMeta: metav1.ObjectMeta{
// This won't contribute to any failures.
Name: "non-existent-service",
Namespace: "test",
Annotations: map[string]string{},
},
// Endpoint with zero subsets.
},
&v1.Endpoints{
ObjectMeta: metav1.ObjectMeta{
Name: "Service1",
Namespace: "test",
Annotations: map[string]string{},
},
// Endpoint with zero subsets.
},
&v1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: "Service1",
Namespace: "test",
},
Spec: v1.ServiceSpec{
Selector: map[string]string{
"app1": "test-app1",
"app2": "test-app2",
},
},
},
&v1.Service{
ObjectMeta: metav1.ObjectMeta{
// This service won't be discovered.
Name: "Service2",
Namespace: "default",
},
Spec: v1.ServiceSpec{
Selector: map[string]string{
"app1": "test-app1",
"app2": "test-app2",
},
},
},
&v1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: "Service3",
Namespace: "test",
},
Spec: v1.ServiceSpec{
// No Spec Selector
},
},
),
},
Context: context.Background(),
Namespace: "test",
}
sAnalyzer := ServiceAnalyzer{}
results, err := sAnalyzer.Analyze(config)
require.NoError(t, err)
sort.Slice(results, func(i, j int) bool {
return results[i].Name < results[j].Name
})
expectations := []struct {
name string
failuresCount int
tests := []struct {
name string
config common.Analyzer
expectations []struct {
name string
failuresCount int
}
}{
{
name: "test/Endpoint1",
failuresCount: 1,
name: "Service with no endpoints",
config: common.Analyzer{
Client: &kubernetes.Client{
Client: fake.NewSimpleClientset(
&v1.Endpoints{
ObjectMeta: metav1.ObjectMeta{
Name: "test-service",
Namespace: "default",
},
Subsets: []v1.EndpointSubset{}, // Empty subsets
},
&v1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: "test-service",
Namespace: "default",
},
Spec: v1.ServiceSpec{
Selector: map[string]string{
"app": "test",
},
},
},
),
},
Namespace: "default",
},
expectations: []struct {
name string
failuresCount int
}{
{
name: "default/test-service",
failuresCount: 1, // One failure for no endpoints
},
},
},
{
name: "test/Service1",
failuresCount: 2,
name: "Service with not ready endpoints",
config: common.Analyzer{
Client: &kubernetes.Client{
Client: fake.NewSimpleClientset(
&v1.Endpoints{
ObjectMeta: metav1.ObjectMeta{
Name: "test-service",
Namespace: "default",
},
Subsets: []v1.EndpointSubset{
{
NotReadyAddresses: []v1.EndpointAddress{
{
TargetRef: &v1.ObjectReference{
Kind: "Pod",
Name: "test-pod",
},
},
},
},
},
},
&v1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: "test-service",
Namespace: "default",
},
Spec: v1.ServiceSpec{
Selector: map[string]string{
"app": "test",
},
},
},
),
},
Namespace: "default",
},
expectations: []struct {
name string
failuresCount int
}{
{
name: "default/test-service",
failuresCount: 1, // One failure for not ready endpoints
},
},
},
{
name: "Service with warning events",
config: common.Analyzer{
Client: &kubernetes.Client{
Client: fake.NewSimpleClientset(
&v1.Endpoints{
ObjectMeta: metav1.ObjectMeta{
Name: "test-service",
Namespace: "default",
},
Subsets: []v1.EndpointSubset{}, // Empty subsets
},
&v1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: "test-service",
Namespace: "default",
},
Spec: v1.ServiceSpec{
Selector: map[string]string{
"app": "test",
},
},
},
&v1.Event{
ObjectMeta: metav1.ObjectMeta{
Name: "test-event",
Namespace: "default",
},
InvolvedObject: v1.ObjectReference{
Kind: "Service",
Name: "test-service",
Namespace: "default",
},
Type: "Warning",
Reason: "TestReason",
Message: "Test warning message",
},
),
},
Namespace: "default",
},
expectations: []struct {
name string
failuresCount int
}{
{
name: "default/test-service",
failuresCount: 2, // One failure for no endpoints, one for warning event
},
},
},
{
name: "Service with leader election annotation",
config: common.Analyzer{
Client: &kubernetes.Client{
Client: fake.NewSimpleClientset(
&v1.Endpoints{
ObjectMeta: metav1.ObjectMeta{
Name: "test-service",
Namespace: "default",
Annotations: map[string]string{
"control-plane.alpha.kubernetes.io/leader": "test-leader",
},
},
Subsets: []v1.EndpointSubset{}, // Empty subsets
},
&v1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: "test-service",
Namespace: "default",
},
Spec: v1.ServiceSpec{
Selector: map[string]string{
"app": "test",
},
},
},
),
},
Namespace: "default",
},
expectations: []struct {
name string
failuresCount int
}{
// No expectations for leader election endpoints
},
},
{
name: "Service with non-existent service",
config: common.Analyzer{
Client: &kubernetes.Client{
Client: fake.NewSimpleClientset(
&v1.Endpoints{
ObjectMeta: metav1.ObjectMeta{
Name: "test-service",
Namespace: "default",
},
Subsets: []v1.EndpointSubset{}, // Empty subsets
},
),
},
Namespace: "default",
},
expectations: []struct {
name string
failuresCount int
}{
// No expectations for non-existent service
},
},
}
require.Equal(t, len(expectations), len(results))
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
analyzer := ServiceAnalyzer{}
results, err := analyzer.Analyze(tt.config)
require.NoError(t, err)
require.Len(t, results, len(tt.expectations))
for i, result := range results {
require.Equal(t, expectations[i].name, result.Name)
require.Equal(t, expectations[i].failuresCount, len(result.Error))
// Sort results by name for consistent comparison
sort.Slice(results, func(i, j int) bool {
return results[i].Name < results[j].Name
})
for i, expectation := range tt.expectations {
require.Equal(t, expectation.name, results[i].Name)
require.Len(t, results[i].Error, expectation.failuresCount)
}
})
}
}

View File

@@ -1,8 +1,10 @@
package query
import (
schemav1 "buf.build/gen/go/k8sgpt-ai/k8sgpt/protocolbuffers/go/schema/v1"
"context"
"fmt"
schemav1 "buf.build/gen/go/k8sgpt-ai/k8sgpt/protocolbuffers/go/schema/v1"
"github.com/k8sgpt-ai/k8sgpt/pkg/ai"
)
@@ -10,9 +12,50 @@ func (h *Handler) Query(ctx context.Context, i *schemav1.QueryRequest) (
*schemav1.QueryResponse,
error,
) {
aiClient := ai.NewClient(i.Backend)
// Create client factory and config provider
factory := ai.GetAIClientFactory()
configProvider := ai.GetConfigProvider()
// Use the factory to create the client
aiClient := factory.NewClient(i.Backend)
defer aiClient.Close()
var configAI ai.AIConfiguration
if err := configProvider.UnmarshalKey("ai", &configAI); err != nil {
return &schemav1.QueryResponse{
Response: "",
Error: &schemav1.QueryError{
Message: fmt.Sprintf("Failed to unmarshal AI configuration: %v", err),
},
}, nil
}
var aiProvider ai.AIProvider
for _, provider := range configAI.Providers {
if i.Backend == provider.Name {
aiProvider = provider
break
}
}
if aiProvider.Name == "" {
return &schemav1.QueryResponse{
Response: "",
Error: &schemav1.QueryError{
Message: fmt.Sprintf("AI provider %s not found in configuration", i.Backend),
},
}, nil
}
// Configure the AI client
if err := aiClient.Configure(&aiProvider); err != nil {
return &schemav1.QueryResponse{
Response: "",
Error: &schemav1.QueryError{
Message: fmt.Sprintf("Failed to configure AI client: %v", err),
},
}, nil
}
resp, err := aiClient.GetCompletion(ctx, i.Query)
var errMessage string = ""
if err != nil {

View File

@@ -0,0 +1,310 @@
package query
import (
"context"
"errors"
"testing"
schemav1 "buf.build/gen/go/k8sgpt-ai/k8sgpt/protocolbuffers/go/schema/v1"
"github.com/k8sgpt-ai/k8sgpt/pkg/ai"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
// MockAI is a mock implementation of the ai.IAI interface for testing
type MockAI struct {
mock.Mock
}
func (m *MockAI) Configure(config ai.IAIConfig) error {
args := m.Called(config)
return args.Error(0)
}
func (m *MockAI) GetCompletion(ctx context.Context, prompt string) (string, error) {
args := m.Called(ctx, prompt)
return args.String(0), args.Error(1)
}
func (m *MockAI) GetName() string {
args := m.Called()
return args.String(0)
}
func (m *MockAI) Close() {
m.Called()
}
// MockAIClientFactory is a mock implementation of AIClientFactory
type MockAIClientFactory struct {
mock.Mock
}
func (m *MockAIClientFactory) NewClient(provider string) ai.IAI {
args := m.Called(provider)
return args.Get(0).(ai.IAI)
}
// MockConfigProvider is a mock implementation of ConfigProvider
type MockConfigProvider struct {
mock.Mock
}
func (m *MockConfigProvider) UnmarshalKey(key string, rawVal interface{}) error {
args := m.Called(key, rawVal)
// If we want to set the rawVal (which is a pointer)
if fn, ok := args.Get(0).(func(interface{})); ok && fn != nil {
fn(rawVal)
}
// Return the error as the first return value
return args.Error(0)
}
func TestQuery_Success(t *testing.T) {
// Setup mocks
mockAI := new(MockAI)
mockFactory := new(MockAIClientFactory)
mockConfig := new(MockConfigProvider)
// Set test implementations
ai.SetTestAIClientFactory(mockFactory)
ai.SetTestConfigProvider(mockConfig)
defer ai.ResetTestImplementations()
// Define test data
testBackend := "test-backend"
testQuery := "test query"
testResponse := "test response"
// Setup expectations
mockFactory.On("NewClient", testBackend).Return(mockAI)
mockAI.On("Close").Return()
// Set up configuration with a valid provider
mockConfig.On("UnmarshalKey", "ai", mock.Anything).Run(func(args mock.Arguments) {
config := args.Get(1).(*ai.AIConfiguration)
*config = ai.AIConfiguration{
Providers: []ai.AIProvider{
{
Name: testBackend,
Password: "test-password",
Model: "test-model",
},
},
}
}).Return(nil)
mockAI.On("Configure", mock.AnythingOfType("*ai.AIProvider")).Return(nil)
mockAI.On("GetCompletion", mock.Anything, testQuery).Return(testResponse, nil)
// Create handler and call Query
handler := &Handler{}
response, err := handler.Query(context.Background(), &schemav1.QueryRequest{
Backend: testBackend,
Query: testQuery,
})
// Assertions
assert.NoError(t, err)
assert.NotNil(t, response)
assert.Equal(t, testResponse, response.Response)
assert.Equal(t, "", response.Error.Message)
// Verify mocks
mockAI.AssertExpectations(t)
mockFactory.AssertExpectations(t)
mockConfig.AssertExpectations(t)
}
func TestQuery_UnmarshalError(t *testing.T) {
// Setup mocks
mockAI := new(MockAI)
mockFactory := new(MockAIClientFactory)
mockConfig := new(MockConfigProvider)
// Set test implementations
ai.SetTestAIClientFactory(mockFactory)
ai.SetTestConfigProvider(mockConfig)
defer ai.ResetTestImplementations()
// Setup expectations
mockFactory.On("NewClient", "test-backend").Return(mockAI)
mockAI.On("Close").Return()
// Mock unmarshal error
mockConfig.On("UnmarshalKey", "ai", mock.Anything).Return(errors.New("unmarshal error"))
// Create handler and call Query
handler := &Handler{}
response, err := handler.Query(context.Background(), &schemav1.QueryRequest{
Backend: "test-backend",
Query: "test query",
})
// Assertions
assert.NoError(t, err)
assert.NotNil(t, response)
assert.Equal(t, "", response.Response)
assert.Contains(t, response.Error.Message, "Failed to unmarshal AI configuration")
// Verify mocks
mockAI.AssertExpectations(t)
mockFactory.AssertExpectations(t)
mockConfig.AssertExpectations(t)
}
func TestQuery_ProviderNotFound(t *testing.T) {
// Setup mocks
mockAI := new(MockAI)
mockFactory := new(MockAIClientFactory)
mockConfig := new(MockConfigProvider)
// Set test implementations
ai.SetTestAIClientFactory(mockFactory)
ai.SetTestConfigProvider(mockConfig)
defer ai.ResetTestImplementations()
// Define test data
testBackend := "test-backend"
// Setup expectations
mockFactory.On("NewClient", testBackend).Return(mockAI)
mockAI.On("Close").Return()
// Set up configuration with no matching provider
mockConfig.On("UnmarshalKey", "ai", mock.Anything).Run(func(args mock.Arguments) {
config := args.Get(1).(*ai.AIConfiguration)
*config = ai.AIConfiguration{
Providers: []ai.AIProvider{
{
Name: "other-backend",
},
},
}
}).Return(nil)
// Create handler and call Query
handler := &Handler{}
response, err := handler.Query(context.Background(), &schemav1.QueryRequest{
Backend: testBackend,
Query: "test query",
})
// Assertions
assert.NoError(t, err)
assert.NotNil(t, response)
assert.Equal(t, "", response.Response)
assert.Contains(t, response.Error.Message, "AI provider test-backend not found in configuration")
// Verify mocks
mockAI.AssertExpectations(t)
mockFactory.AssertExpectations(t)
mockConfig.AssertExpectations(t)
}
func TestQuery_ConfigureError(t *testing.T) {
// Setup mocks
mockAI := new(MockAI)
mockFactory := new(MockAIClientFactory)
mockConfig := new(MockConfigProvider)
// Set test implementations
ai.SetTestAIClientFactory(mockFactory)
ai.SetTestConfigProvider(mockConfig)
defer ai.ResetTestImplementations()
// Define test data
testBackend := "test-backend"
// Setup expectations
mockFactory.On("NewClient", testBackend).Return(mockAI)
mockAI.On("Close").Return()
// Set up configuration with a valid provider
mockConfig.On("UnmarshalKey", "ai", mock.Anything).Run(func(args mock.Arguments) {
config := args.Get(1).(*ai.AIConfiguration)
*config = ai.AIConfiguration{
Providers: []ai.AIProvider{
{
Name: testBackend,
},
},
}
}).Return(nil)
// Mock configure error
mockAI.On("Configure", mock.AnythingOfType("*ai.AIProvider")).Return(errors.New("configure error"))
// Create handler and call Query
handler := &Handler{}
response, err := handler.Query(context.Background(), &schemav1.QueryRequest{
Backend: testBackend,
Query: "test query",
})
// Assertions
assert.NoError(t, err)
assert.NotNil(t, response)
assert.Equal(t, "", response.Response)
assert.Contains(t, response.Error.Message, "Failed to configure AI client")
// Verify mocks
mockAI.AssertExpectations(t)
mockFactory.AssertExpectations(t)
mockConfig.AssertExpectations(t)
}
func TestQuery_GetCompletionError(t *testing.T) {
// Setup mocks
mockAI := new(MockAI)
mockFactory := new(MockAIClientFactory)
mockConfig := new(MockConfigProvider)
// Set test implementations
ai.SetTestAIClientFactory(mockFactory)
ai.SetTestConfigProvider(mockConfig)
defer ai.ResetTestImplementations()
// Define test data
testBackend := "test-backend"
testQuery := "test query"
// Setup expectations
mockFactory.On("NewClient", testBackend).Return(mockAI)
mockAI.On("Close").Return()
// Set up configuration with a valid provider
mockConfig.On("UnmarshalKey", "ai", mock.Anything).Run(func(args mock.Arguments) {
config := args.Get(1).(*ai.AIConfiguration)
*config = ai.AIConfiguration{
Providers: []ai.AIProvider{
{
Name: testBackend,
},
},
}
}).Return(nil)
mockAI.On("Configure", mock.AnythingOfType("*ai.AIProvider")).Return(nil)
mockAI.On("GetCompletion", mock.Anything, testQuery).Return("", errors.New("completion error"))
// Create handler and call Query
handler := &Handler{}
response, err := handler.Query(context.Background(), &schemav1.QueryRequest{
Backend: testBackend,
Query: testQuery,
})
// Assertions
assert.NoError(t, err)
assert.NotNil(t, response)
assert.Equal(t, "", response.Response)
assert.Equal(t, "completion error", response.Error.Message)
// Verify mocks
mockAI.AssertExpectations(t)
mockFactory.AssertExpectations(t)
mockConfig.AssertExpectations(t)
}

View File

@@ -14,6 +14,7 @@ limitations under the License.
package util
import (
"bytes"
"context"
"crypto/rand"
"crypto/sha256"
@@ -311,3 +312,33 @@ func LabelStrToSelector(labelStr string) labels.Selector {
}
return labels.SelectorFromSet(labels.Set(labelSelectorMap))
}
// CaptureOutput captures the output of a function that writes to stdout
func CaptureOutput(f func()) string {
old := os.Stdout
r, w, err := os.Pipe()
if err != nil {
panic(fmt.Sprintf("failed to create pipe: %v", err))
}
os.Stdout = w
// Ensure os.Stdout is restored even if panic occurs
defer func() {
os.Stdout = old
}()
f()
if err := w.Close(); err != nil {
panic(fmt.Sprintf("failed to close writer: %v", err))
}
var buf bytes.Buffer
if _, err := buf.ReadFrom(r); err != nil {
panic(fmt.Sprintf("failed to read from pipe: %v", err))
}
return buf.String()
}
// Contains checks if substr is present in s
func Contains(s, substr string) bool {
return bytes.Contains([]byte(s), []byte(substr))
}