mirror of
https://github.com/replicatedhq/troubleshoot.git
synced 2026-08-27 00:37:20 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2192aecf40 | ||
|
|
5bf008f7d2 | ||
|
|
0c6fb2177b | ||
|
|
bea9c2220d | ||
|
|
207cb90b53 | ||
|
|
0bb4a21f22 | ||
|
|
fb82fef6e0 | ||
|
|
3f3906fea1 | ||
|
|
1f1a21b3cf | ||
|
|
e828c21545 | ||
|
|
b158f7d79f | ||
|
|
8be420c42e |
@@ -0,0 +1,101 @@
|
||||
name: publish-securebuild
|
||||
|
||||
env:
|
||||
SECUREBUILD_CLI_VERSION: v0.0.498
|
||||
SECUREBUILD_CLI_SHA256: d259aa99d85aef957fe1e40c6f26e1983cc7fd72277e08599a82adc6681d3b37
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
version:
|
||||
description: Stable version tag to build (for example, v0.130.0)
|
||||
required: true
|
||||
type: string
|
||||
secrets:
|
||||
SECUREBUILD_API_TOKEN:
|
||||
required: true
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
description: Stable version tag to build (for example, v0.130.0)
|
||||
required: true
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
validate-version:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Require a stable release version
|
||||
env:
|
||||
VERSION: ${{ inputs.version }}
|
||||
run: |
|
||||
if ! [[ "$VERSION" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||||
echo "SecureBuild only supports stable release versions (for example, v0.130.0): $VERSION"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
build-package:
|
||||
needs: validate-version
|
||||
runs-on: ubuntu-22.04
|
||||
outputs:
|
||||
version: ${{ steps.version.outputs.version }}
|
||||
steps:
|
||||
- name: Set version
|
||||
id: version
|
||||
env:
|
||||
VERSION: ${{ inputs.version }}
|
||||
run: echo "version=$VERSION" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Install SecureBuild CLI
|
||||
run: |
|
||||
curl --fail --silent --show-error --location \
|
||||
"https://github.com/securebuildhq/securebuild/releases/download/${SECUREBUILD_CLI_VERSION}/securebuild-cli-linux-amd64" \
|
||||
--output securebuild
|
||||
echo "${SECUREBUILD_CLI_SHA256} securebuild" | sha256sum --check --strict
|
||||
chmod +x securebuild
|
||||
|
||||
- name: Build package
|
||||
env:
|
||||
SECUREBUILD_API_TOKEN: ${{ secrets.SECUREBUILD_API_TOKEN }}
|
||||
VERSION: ${{ steps.version.outputs.version }}
|
||||
run: |
|
||||
./securebuild build package \
|
||||
--package-family-name troubleshoot \
|
||||
--tag "$VERSION" \
|
||||
--api-token "$SECUREBUILD_API_TOKEN"
|
||||
|
||||
build-image:
|
||||
needs: build-package
|
||||
if: ${{ !cancelled() && needs.build-package.result == 'success' }}
|
||||
runs-on: ubuntu-22.04
|
||||
strategy:
|
||||
matrix:
|
||||
image-name:
|
||||
- troubleshoot
|
||||
- preflight
|
||||
steps:
|
||||
- name: Install SecureBuild CLI
|
||||
run: |
|
||||
curl --fail --silent --show-error --location \
|
||||
"https://github.com/securebuildhq/securebuild/releases/download/${SECUREBUILD_CLI_VERSION}/securebuild-cli-linux-amd64" \
|
||||
--output securebuild
|
||||
echo "${SECUREBUILD_CLI_SHA256} securebuild" | sha256sum --check --strict
|
||||
chmod +x securebuild
|
||||
|
||||
- name: Build image
|
||||
env:
|
||||
IMAGE_NAME: ${{ matrix.image-name }}
|
||||
SECUREBUILD_API_TOKEN: ${{ secrets.SECUREBUILD_API_TOKEN }}
|
||||
VERSION: ${{ needs.build-package.outputs.version }}
|
||||
run: |
|
||||
IMAGE_VERSION="${VERSION#v}"
|
||||
MAJOR_MINOR_VERSION="${IMAGE_VERSION%.*}"
|
||||
MAJOR_VERSION="${IMAGE_VERSION%%.*}"
|
||||
|
||||
./securebuild build image \
|
||||
--image-name "$IMAGE_NAME" \
|
||||
--tag "$VERSION" \
|
||||
--image-tag "$MAJOR_MINOR_VERSION" \
|
||||
--image-tag "$MAJOR_VERSION" \
|
||||
--image-tag latest \
|
||||
--api-token "$SECUREBUILD_API_TOKEN"
|
||||
@@ -18,14 +18,21 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: azure/docker-login@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USER }}
|
||||
password: ${{ secrets.DOCKERHUB_PASSWORD }}
|
||||
|
||||
- uses: actions/setup-go@v7
|
||||
with:
|
||||
go-version-file: 'go.mod'
|
||||
go-version: '1.26'
|
||||
check-latest: true
|
||||
|
||||
- name: Install Cosign
|
||||
uses: sigstore/cosign-installer@v4.1.2
|
||||
with:
|
||||
cosign-release: 'v3.1.3'
|
||||
|
||||
- name: Generate and sign SBOM
|
||||
run: make sbom
|
||||
env:
|
||||
COSIGN_KEY: ${{ secrets.COSIGN_KEY }}
|
||||
COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }}
|
||||
|
||||
- name: Run GoReleaser
|
||||
uses: goreleaser/goreleaser-action@v7
|
||||
@@ -47,6 +54,14 @@ jobs:
|
||||
with:
|
||||
krew_template_file: deploy/krew/support-bundle.yaml
|
||||
|
||||
securebuild:
|
||||
if: ${{ !contains(github.ref_name, '-') }}
|
||||
uses: ./.github/workflows/publish-securebuild.yml
|
||||
with:
|
||||
version: ${{ github.ref_name }}
|
||||
secrets:
|
||||
SECUREBUILD_API_TOKEN: ${{ secrets.SECUREBUILD_API_TOKEN }}
|
||||
|
||||
notify:
|
||||
if: ${{ !contains(github.ref_name, '-') }}
|
||||
uses: replicatedhq/reusable-workflows/.github/workflows/notify-release.yml@0432fb838fc83852b78be97a150b35991a85d56f
|
||||
|
||||
@@ -197,20 +197,6 @@ release: export GITHUB_TOKEN = $(shell echo ${GITHUB_TOKEN_TROUBLESHOOT})
|
||||
release:
|
||||
curl -sL https://git.io/goreleaser | bash -s -- --rm-dist --config deploy/.goreleaser.yml
|
||||
|
||||
.PHONY: snapshot-release
|
||||
snapshot-release:
|
||||
curl -sL https://git.io/goreleaser | bash -s -- --rm-dist --snapshot --config deploy/.goreleaser.snapshot.yml
|
||||
docker push replicated/troubleshoot:alpha
|
||||
docker push replicated/preflight:alpha
|
||||
|
||||
.PHONY: local-release
|
||||
local-release:
|
||||
curl -sL https://git.io/goreleaser | bash -s -- --rm-dist --snapshot --config deploy/.goreleaser.yaml
|
||||
docker tag replicated/troubleshoot:alpha localhost:32000/troubleshoot:alpha
|
||||
docker tag replicated/preflight:alpha localhost:32000/preflight:alpha
|
||||
docker push localhost:32000/troubleshoot:alpha
|
||||
docker push localhost:32000/preflight:alpha
|
||||
|
||||
.PHONY: run-preflight
|
||||
run-preflight: bin/preflight
|
||||
./bin/preflight ./examples/preflight/sample-preflight.yaml
|
||||
@@ -246,7 +232,8 @@ sbom: sbom/assets/troubleshoot-sbom.tgz
|
||||
--tlog-upload \
|
||||
--yes \
|
||||
--rekor-url=https://rekor.sigstore.dev \
|
||||
sbom/assets/troubleshoot-sbom.tgz > sbom/assets/troubleshoot-sbom.tgz.sig
|
||||
--bundle sbom/assets/troubleshoot-sbom.tgz.bundle \
|
||||
sbom/assets/troubleshoot-sbom.tgz
|
||||
cosign public-key --key cosign.key --outfile sbom/assets/key.pub
|
||||
|
||||
.PHONY: get-govulncheck
|
||||
|
||||
@@ -56,19 +56,12 @@ For questions about using Troubleshoot, how to contribute and engaging with the
|
||||
# Software Bill of Materials
|
||||
A signed SBOM that includes Troubleshoot dependencies is included in each release.
|
||||
- **troubleshoot-sbom.tgz** contains a software bill of materials for Troubleshoot.
|
||||
- **troubleshoot-sbom.tgz.sig** is the digital signature for troubleshoot-sbom.tgz
|
||||
- **troubleshoot-sbom.tgz.bundle** contains the signature and transparency log material used by Cosign.
|
||||
- **key.pub** is the public key from the key pair used to sign troubleshoot-sbom.tgz
|
||||
|
||||
The following example illustrates using [cosign](https://github.com/sigstore/cosign) to verify that **troubleshoot-sbom.tgz** has
|
||||
not been tampered with.
|
||||
not been tampered with. Install [Cosign v3](https://github.com/sigstore/cosign/releases).
|
||||
```sh
|
||||
$ cosign verify-blob --key key.pub --signature troubleshoot-sbom.tgz.sig troubleshoot-sbom.tgz
|
||||
Verified OK
|
||||
```
|
||||
|
||||
If you were to get an error similar to the one below, it means you are verifying an SBOM signed using cosign `v1` using a newer `v2` of the binary. This version introduced [breaking changes](https://github.com/sigstore/cosign/blob/main/CHANGELOG.md#breaking-changes) which require an additional flag `--insecure-ignore-tlog=true` to successfully verify SBOMs like so.
|
||||
```sh
|
||||
$ cosign verify-blob --key key.pub --signature troubleshoot-sbom.tgz.sig troubleshoot-sbom.tgz --insecure-ignore-tlog=true
|
||||
WARNING: Skipping tlog verification is an insecure practice that lacks of transparency and auditability verification for the blob.
|
||||
$ cosign verify-blob --key key.pub --bundle troubleshoot-sbom.tgz.bundle troubleshoot-sbom.tgz
|
||||
Verified OK
|
||||
```
|
||||
|
||||
@@ -59,33 +59,6 @@ builds:
|
||||
- -installsuffix=netgo
|
||||
binary: support-bundle
|
||||
|
||||
- id: collect
|
||||
main: ./cmd/collect/main.go
|
||||
env: [CGO_ENABLED=0]
|
||||
goos: [linux, darwin, windows]
|
||||
goarch: [amd64, arm, arm64, riscv64]
|
||||
ignore:
|
||||
- goos: windows
|
||||
goarch: arm
|
||||
- goos: windows
|
||||
goarch: riscv64
|
||||
- goos: darwin
|
||||
goarch: riscv64
|
||||
ldflags:
|
||||
- -s -w
|
||||
- -X github.com/replicatedhq/troubleshoot/pkg/version.version={{ .Version }}
|
||||
- -X github.com/replicatedhq/troubleshoot/pkg/version.gitSHA={{ .Commit }}
|
||||
- -X github.com/replicatedhq/troubleshoot/pkg/version.buildTime={{ .Date }}
|
||||
- -extldflags "-static"
|
||||
flags:
|
||||
- -tags=netgo
|
||||
- -tags=containers_image_ostree_stub
|
||||
- -tags=exclude_graphdriver_devicemapper
|
||||
- -tags=exclude_graphdriver_btrfs
|
||||
- -tags=containers_image_openpgp
|
||||
- -installsuffix=netgo
|
||||
binary: collect
|
||||
|
||||
archives:
|
||||
- id: preflight
|
||||
ids: [preflight]
|
||||
@@ -160,28 +133,6 @@ archives:
|
||||
dst: .
|
||||
strip_parent: true
|
||||
|
||||
dockers:
|
||||
- dockerfile: ./deploy/Dockerfile.troubleshoot
|
||||
image_templates:
|
||||
- "replicated/troubleshoot:latest"
|
||||
- "replicated/troubleshoot:{{ .Major }}"
|
||||
- "replicated/troubleshoot:{{ .Major }}.{{ .Minor }}"
|
||||
- "replicated/troubleshoot:{{ .Major }}.{{ .Minor }}.{{ .Patch }}"
|
||||
ids:
|
||||
- support-bundle
|
||||
- preflight
|
||||
- collect
|
||||
- dockerfile: ./deploy/Dockerfile.troubleshoot
|
||||
image_templates:
|
||||
- "replicated/preflight:latest"
|
||||
- "replicated/preflight:{{ .Major }}"
|
||||
- "replicated/preflight:{{ .Major }}.{{ .Minor }}"
|
||||
- "replicated/preflight:{{ .Major }}.{{ .Minor }}.{{ .Patch }}"
|
||||
ids:
|
||||
- support-bundle
|
||||
- preflight
|
||||
- collect
|
||||
|
||||
universal_binaries:
|
||||
- id: preflight-universal
|
||||
ids: [preflight] # refers to the build id above
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
FROM debian:bookworm
|
||||
WORKDIR /
|
||||
|
||||
RUN apt-get -qq update \
|
||||
&& apt-get -qq -y install \
|
||||
ca-certificates kmod
|
||||
|
||||
COPY support-bundle /troubleshoot/support-bundle
|
||||
COPY preflight /troubleshoot/preflight
|
||||
COPY collect /troubleshoot/collect
|
||||
|
||||
ENV PATH="/troubleshoot:${PATH}"
|
||||
|
||||
@@ -9,7 +9,7 @@ replace github.com/replicatedhq/troubleshoot v0.0.0 => ../../../
|
||||
|
||||
require (
|
||||
github.com/replicatedhq/troubleshoot v0.0.0
|
||||
helm.sh/helm/v3 v3.21.3
|
||||
helm.sh/helm/v3 v3.21.4
|
||||
sigs.k8s.io/yaml v1.6.0
|
||||
)
|
||||
|
||||
@@ -56,12 +56,12 @@ require (
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
go.yaml.in/yaml/v2 v2.4.4 // indirect
|
||||
go.yaml.in/yaml/v3 v3.0.5 // indirect
|
||||
golang.org/x/crypto v0.54.0 // indirect
|
||||
golang.org/x/net v0.57.0 // indirect
|
||||
golang.org/x/crypto v0.55.0 // indirect
|
||||
golang.org/x/net v0.58.0 // indirect
|
||||
golang.org/x/oauth2 v0.36.0 // indirect
|
||||
golang.org/x/sys v0.47.0 // indirect
|
||||
golang.org/x/term v0.45.0 // indirect
|
||||
golang.org/x/text v0.40.0 // indirect
|
||||
golang.org/x/text v0.41.0 // indirect
|
||||
golang.org/x/time v0.15.0 // indirect
|
||||
google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af // indirect
|
||||
gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect
|
||||
|
||||
@@ -126,12 +126,12 @@ go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ=
|
||||
go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ=
|
||||
go.yaml.in/yaml/v3 v3.0.5 h1:N6y/pJk8buWs9NY5ERU2HSMfm+IuD/OtfdAnq6kESPw=
|
||||
go.yaml.in/yaml/v3 v3.0.5/go.mod h1:HVTZu1O7/Vkt2N+BFy8Zza+lnLsABggaTM2ZpNIGuKg=
|
||||
golang.org/x/crypto v0.54.0 h1:YLIA59K4fiNzHzjnZt2tUJQjQtUWfWbeHBqKtk3eScw=
|
||||
golang.org/x/crypto v0.54.0/go.mod h1:KWL8ny2AZdGR2cWmzeHrp2azQPGogOv+HeQaVEXC2dk=
|
||||
golang.org/x/mod v0.38.0 h1:MECBjubtXD7yj4HrhIUcywNaGeNVUdfVnxmPajOk4yk=
|
||||
golang.org/x/mod v0.38.0/go.mod h1:V6Xz0pq8TQ3dGqVQ1FVHuelZpAL0uNhSkk9ogYP3c40=
|
||||
golang.org/x/net v0.57.0 h1:K5+3DljvIuDG9/Jv9rvyMywYNFCQ9RSUY6OOTTkT+tE=
|
||||
golang.org/x/net v0.57.0/go.mod h1:KpXc8iv+r3XplLAG/f7Jsf9RPszJzdR0f58q9vGOuEU=
|
||||
golang.org/x/crypto v0.55.0 h1:+KWHjbgOaAQ66dh/YlkZKHlz9ZUlq61AFirAR9ntP8M=
|
||||
golang.org/x/crypto v0.55.0/go.mod h1:uq0V9dE/fzQuJtbnL+2EhWOE63vo164FY8xqEnV9xis=
|
||||
golang.org/x/mod v0.39.0 h1:UF5zwQdCRRUpHfyPwr7d4UrGiVeldIsogtzWVnczL74=
|
||||
golang.org/x/mod v0.39.0/go.mod h1:bvIbwjQ0HUFFf5AKukeeYQG4ZBUG9yxQbR9aEweIwYY=
|
||||
golang.org/x/net v0.58.0 h1:ynWG7rqYi4ccpTEuPZ2QGWHktVEM9DMCj9yzDE0Q7To=
|
||||
golang.org/x/net v0.58.0/go.mod h1:YwCddHnFlT7eLQqVprV19OnhLGtc5xOKgE0RyqgfWAU=
|
||||
golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs=
|
||||
golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q=
|
||||
golang.org/x/sync v0.22.0 h1:SZjpbeLmrCk4xhRSZFNZW5gFUeCeFgjekvI/+gfScek=
|
||||
@@ -140,8 +140,8 @@ golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs=
|
||||
golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
golang.org/x/term v0.45.0 h1:NwWyBmoJCbfTHpxrWoZ9C6/VxOf7ic219I8xZZFdrf0=
|
||||
golang.org/x/term v0.45.0/go.mod h1:9aqxs0blBcrm/n0L9QW0aRVD+ktan8ssZromtqJC43w=
|
||||
golang.org/x/text v0.40.0 h1:Ub2Z6/xjgF1WrYQz2nuITOEegKFtiIy+rieRJ5lHZKs=
|
||||
golang.org/x/text v0.40.0/go.mod h1:hpnzDAfGV753zIKo+wk3u1bVKCGPbrnF7+7LBF/UHVY=
|
||||
golang.org/x/text v0.41.0 h1:vz/seA0lnX87Othu2f/0L24RcgrXD9/YFTSuGjj3rH8=
|
||||
golang.org/x/text v0.41.0/go.mod h1:jvf1O8ajNzZqhSrQBPbutR/EB83Cc0CFrezNQIwbb5M=
|
||||
golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
|
||||
golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
|
||||
golang.org/x/tools v0.48.0 h1:3+hClM1aLL5mjMKm5ovokw9epgRXPuu2tILgismM6RE=
|
||||
@@ -159,8 +159,8 @@ 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.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
helm.sh/helm/v3 v3.21.3 h1:wkamdwI3liEkW6wI1l9aGqQZGxcTKyt8kx0qJLPcmCg=
|
||||
helm.sh/helm/v3 v3.21.3/go.mod h1:iaJ0iNsPoTZl++7h6vzQFyT0VEVtLYJiyRBDkPOOBTs=
|
||||
helm.sh/helm/v3 v3.21.4 h1:T/GcIEXU/gNjJnkITlIZ3e9xqkZjhFTmISuStTZ6+Qg=
|
||||
helm.sh/helm/v3 v3.21.4/go.mod h1:cS2FBb+xfLuaSqvEmbqIeKUVFgHdHVHtVeXb2epof3M=
|
||||
k8s.io/api v0.36.3 h1:NxB+05W2UGqXWFXcLO0RB5cnqnUPP5v5sVlaOH0Iz4w=
|
||||
k8s.io/api v0.36.3/go.mod h1:JzLQKqRHC5+I8RVj/lS3lCg0mg6nWI9Fo/Sk3ElxHzg=
|
||||
k8s.io/apiextensions-apiserver v0.36.3 h1:dPmOAPhwTtqb1bTxbFPsy18KHPhktQeO3WUPXunZIB0=
|
||||
|
||||
@@ -7,9 +7,9 @@ require (
|
||||
github.com/Masterminds/sprig/v3 v3.3.0
|
||||
github.com/ahmetalpbalkan/go-cursor v0.0.0-20131010032410-8136607ea412
|
||||
github.com/apparentlymart/go-cidr v1.1.1
|
||||
github.com/aws/aws-sdk-go-v2 v1.43.4
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.34
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.107.0
|
||||
github.com/aws/aws-sdk-go-v2 v1.43.6
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.36
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.107.2
|
||||
github.com/blang/semver/v4 v4.0.0
|
||||
github.com/casbin/govaluate v1.10.0
|
||||
github.com/cilium/ebpf v0.22.0
|
||||
@@ -24,14 +24,14 @@ require (
|
||||
github.com/google/gofuzz v1.2.0
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/gorilla/handlers v1.5.2
|
||||
github.com/hashicorp/go-getter v1.8.6
|
||||
github.com/hashicorp/go-getter v1.8.8
|
||||
github.com/hashicorp/go-multierror v1.1.1
|
||||
github.com/jackc/pgx/v5 v5.10.0
|
||||
github.com/longhorn/go-common-libs v0.0.0-20260730002911-add09e6eb92c
|
||||
github.com/manifoldco/promptui v0.9.0
|
||||
github.com/mattn/go-isatty v0.0.24
|
||||
github.com/microsoft/go-mssqldb v1.10.0
|
||||
github.com/miekg/dns v1.1.72
|
||||
github.com/miekg/dns v1.1.73
|
||||
github.com/opencontainers/image-spec v1.1.1
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/replicatedhq/termui/v3 v3.1.1-0.20200811145416-f40076d26851
|
||||
@@ -40,7 +40,7 @@ require (
|
||||
github.com/spf13/cobra v1.10.2
|
||||
github.com/spf13/pflag v1.0.10
|
||||
github.com/spf13/viper v1.21.0
|
||||
github.com/stretchr/testify v1.11.1
|
||||
github.com/stretchr/testify v1.12.1
|
||||
github.com/tj/go-spin v1.1.0
|
||||
github.com/vishvananda/netlink v1.3.1
|
||||
github.com/vishvananda/netns v0.0.5
|
||||
@@ -48,7 +48,7 @@ require (
|
||||
go.opentelemetry.io/otel v1.45.0
|
||||
go.opentelemetry.io/otel/sdk v1.45.0
|
||||
golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f
|
||||
golang.org/x/mod v0.38.0
|
||||
golang.org/x/mod v0.40.0
|
||||
golang.org/x/sync v0.22.0
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
k8s.io/api v0.36.3
|
||||
@@ -80,26 +80,28 @@ require (
|
||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||
github.com/Masterminds/semver/v3 v3.5.0 // indirect
|
||||
github.com/Masterminds/squirrel v1.5.4 // indirect
|
||||
github.com/ProtonMail/go-crypto v1.4.1 // indirect
|
||||
github.com/andybalholm/brotli v1.2.2 // indirect
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
|
||||
github.com/avast/retry-go/v4 v4.7.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.16 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.34 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.35 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.35 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.35 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.36 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.15 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.28 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.35 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.36 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/signin v1.5.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.33.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.38.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.45.4 // indirect
|
||||
github.com/aws/smithy-go v1.27.6 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.18 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.35 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.37 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.37 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.37 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.38 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.17 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.30 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.37 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.38 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/signin v1.5.6 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.33.6 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.38.6 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.45.6 // indirect
|
||||
github.com/aws/smithy-go v1.27.8 // indirect
|
||||
github.com/chai2010/gettext-go v1.0.3 // indirect
|
||||
github.com/clipperhouse/uax29/v2 v2.7.0 // indirect
|
||||
github.com/cloudflare/circl v1.6.3 // indirect
|
||||
github.com/cncf/xds/go v0.0.0-20260202195803-dba9d589def2 // indirect
|
||||
github.com/cockroachdb/errors v1.14.0 // indirect
|
||||
github.com/cockroachdb/logtags v0.0.0-20241215232642-bb51bb14a506 // indirect
|
||||
@@ -170,7 +172,7 @@ require (
|
||||
github.com/shopspring/decimal v1.4.0 // indirect
|
||||
github.com/sirupsen/logrus v1.9.4 // indirect
|
||||
github.com/spiffe/go-spiffe/v2 v2.8.1 // indirect
|
||||
github.com/stretchr/objx v0.5.2 // indirect
|
||||
github.com/stretchr/objx v0.5.3 // indirect
|
||||
github.com/ulikunitz/xz v0.5.16 // indirect
|
||||
github.com/vladimirvivien/gexe v0.5.0 // indirect
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
@@ -183,9 +185,8 @@ require (
|
||||
go.opentelemetry.io/otel/trace v1.45.0 // indirect
|
||||
go.yaml.in/yaml/v2 v2.4.4 // indirect
|
||||
go.yaml.in/yaml/v3 v3.0.5 // indirect
|
||||
golang.org/x/tools v0.48.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20260729162451-8efbd57d26e0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260729162451-8efbd57d26e0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260803160001-6ac0973c030d // indirect
|
||||
gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect
|
||||
gotest.tools/v3 v3.5.2 // indirect
|
||||
k8s.io/component-base v0.36.3 // indirect
|
||||
@@ -222,7 +223,7 @@ require (
|
||||
github.com/hashicorp/go-version v1.9.0
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/compress v1.19.1 // indirect
|
||||
github.com/klauspost/compress v1.19.2 // indirect
|
||||
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
|
||||
github.com/mattn/go-colorable v0.1.15 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.27 // indirect
|
||||
@@ -251,20 +252,20 @@ require (
|
||||
github.com/tklauser/numcpus v0.12.0 // indirect
|
||||
github.com/xlab/treeprint v1.2.0 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
||||
golang.org/x/crypto v0.54.0 // indirect
|
||||
golang.org/x/net v0.57.0
|
||||
golang.org/x/crypto v0.55.0 // indirect
|
||||
golang.org/x/net v0.58.0
|
||||
golang.org/x/oauth2 v0.36.0 // indirect
|
||||
golang.org/x/sys v0.47.0
|
||||
golang.org/x/term v0.45.0 // indirect
|
||||
golang.org/x/text v0.40.0
|
||||
golang.org/x/text v0.41.0
|
||||
golang.org/x/time v0.15.0 // indirect
|
||||
google.golang.org/api v0.291.0 // indirect
|
||||
google.golang.org/api v0.292.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20260729162451-8efbd57d26e0 // indirect
|
||||
google.golang.org/grpc v1.83.0 // indirect
|
||||
google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
helm.sh/helm/v3 v3.21.3
|
||||
helm.sh/helm/v3 v3.21.4
|
||||
k8s.io/kube-openapi v0.0.0-20260721132016-d427ff9ee9ad // indirect
|
||||
k8s.io/kubelet v0.36.3
|
||||
k8s.io/metrics v0.36.3
|
||||
|
||||
@@ -67,6 +67,8 @@ github.com/Masterminds/sprig/v3 v3.3.0 h1:mQh0Yrg1XPo6vjYXgtf5OtijNAKJRNcTdOOGZe
|
||||
github.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSCzdgBfDb35Lz0=
|
||||
github.com/Masterminds/squirrel v1.5.4 h1:uUcX/aBc8O7Fg9kaISIUsHXdKuqehiXAMQTYX8afzqM=
|
||||
github.com/Masterminds/squirrel v1.5.4/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10=
|
||||
github.com/ProtonMail/go-crypto v1.4.1 h1:9RfcZHqEQUvP8RzecWEUafnZVtEvrBVL9BiF67IQOfM=
|
||||
github.com/ProtonMail/go-crypto v1.4.1/go.mod h1:e1OaTyu5SYVrO9gKOEhTc+5UcXtTUa+P3uLudwcgPqo=
|
||||
github.com/ahmetalpbalkan/go-cursor v0.0.0-20131010032410-8136607ea412 h1:vOVO0ypMfTt6tZacyI0kp+iCZb1XSNiYDqnzBWYgfe4=
|
||||
github.com/ahmetalpbalkan/go-cursor v0.0.0-20131010032410-8136607ea412/go.mod h1:AI9hp1tkp10pAlK5TCwL+7yWbRgtDm9jhToq6qij2xs=
|
||||
github.com/andybalholm/brotli v1.2.2 h1:HzTuoo2ErYQqf5qvcJInB8uvqSVxRttzkFexPWtnceM=
|
||||
@@ -79,42 +81,42 @@ github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3d
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
|
||||
github.com/avast/retry-go/v4 v4.7.0 h1:yjDs35SlGvKwRNSykujfjdMxMhMQQM0TnIjJaHB+Zio=
|
||||
github.com/avast/retry-go/v4 v4.7.0/go.mod h1:ZMPDa3sY2bKgpLtap9JRUgk2yTAba7cgiFhqxY2Sg6Q=
|
||||
github.com/aws/aws-sdk-go-v2 v1.43.4 h1:b9FTvbRwy+JCsfp2Wp6wV/KbOx3Aj7nkoFb2cRX0IhE=
|
||||
github.com/aws/aws-sdk-go-v2 v1.43.4/go.mod h1:70vwSy16txshwG+g55WkpgPKDIByzHI8ccBsOteo3bQ=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.16 h1:aiuaKlDweRC5qExJondpWjOgyzMHpofpwspGXUtwn4c=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.16/go.mod h1:nG/LOlmox9BDe9HvQnXWzgcK8uKbgBMZ/Hp5pVt/21I=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.34 h1:o+YAizrX562nEZXaB38uYTK8RvIsvW0uuRP+e5e0Pfk=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.34/go.mod h1:wc0zYRChOniiufvdWiRVf3jgXSgbkvaD683IHHHc2ZQ=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.34 h1:y6GkSmcv5myd1ngrYbGmiLlwQqB6TQhOuN/tbSSuWDY=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.34/go.mod h1:w3dTcnDVoQIewjo7JG45hduAToikiIFLC4FIO7fndvw=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.35 h1:+S7kbJoLDDQ5tE+lHrUBgMkzC8NLgsaioS2F3dVoFAE=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.35/go.mod h1:Ak7xXviIARfFdNUJ9Etb0bdVDt/KAvKjMGJVLWXDzik=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.35 h1:kzVuGlatQtYinwBJEEyLAbggepCoavosiaHHX9+fD+c=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.35/go.mod h1:0yLx0yEI+SfqeJMPvOtIEFoZbiQYXMGszBueiutQyaI=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.35 h1:WK6CjihTuLisCjSKKbildJ79sGZZgbBz3iNa7VsKIhU=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.35/go.mod h1:KYleN57luLoe97R7vTnx8PMcVrr9gAcRECtOjl91DNg=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.36 h1:jbGY4CXLzZElOXgGsexlC3Hi+3YM0rSmk4opFXKqg/k=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.36/go.mod h1:uBu/9aKsS/UQGc72RAt3y54kjgYQxmhut8ZD2dXCDNE=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.15 h1:JJLBQxwY+AFwuPAi5ivGc1ChnTdUt4cXMv7e76m2c/Y=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.15/go.mod h1:lQknBIe78MVL0cQOQDlag8KGflMbMEVFx9mB6O8ENvk=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.28 h1:Q1TF1J9jVD+vFo0LzNnmNdQ9EAt52TS+MQlq9Ir+Yxo=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.28/go.mod h1:4KqXXC/p1hrotmouDFbrRoWaLy962b9PMUReCG6+uWo=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.35 h1:BBEElKh4a+rKshvjrfpajTe9CbpZvrbb4Jkg2PB7RzA=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.35/go.mod h1:zaZk983w//8beSruBVec/mr4CmDwgZitW/qzGhAAX0g=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.36 h1:EUIwBoN+q7UmhAejxgD27APiRjh1vwCFo53gSqdT0BM=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.36/go.mod h1:6u00gmlTGR6W0b2k9NBrld7MnOEmf1Spqx0VVt6AqyE=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.107.0 h1:OkYV+1171za+ab9otU1tGxMXhx6uZvwVEtVddjLuYTg=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.107.0/go.mod h1:5FTZoQxhmLEiCAtYVk6V+t0iS/B5yGZVLZ3Wq5FDJZI=
|
||||
github.com/aws/aws-sdk-go-v2/service/signin v1.5.4 h1:cOJELVNrq5Q3Udry2GLuHUM7MhwpeaQRdYaoa6GI/yI=
|
||||
github.com/aws/aws-sdk-go-v2/service/signin v1.5.4/go.mod h1:f4LxzKBtaTxD7xh3PiVg3CE1tchQemfmghaJr+NbK2c=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.33.4 h1:AMW7a7S8iQaHjBYZdU3PCq4GKRPijTPRAc7e6XtEThY=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.33.4/go.mod h1:QQNsFV1DVXoXcZt18FS8lI8rtUrlDyAuWZLQ5shunv4=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.38.4 h1:AsbZcJAQPRmHDJG8K1N0pof/1zPWjVT8TFlTWuGLSvo=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.38.4/go.mod h1:6imqztH0//t0mKbl6yWl7swSEl7F/w32oAmqB3vP1ag=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.45.4 h1:w/AryDYMjSUANSQ2uoZxJovUsMTwWJNTv3IMex30Y+4=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.45.4/go.mod h1:WeBiAa67azG7Su9Vf+ChGDBLiAozJCXzdjXiPBUwtbc=
|
||||
github.com/aws/smithy-go v1.27.6 h1:0zjT8jgK3jbrTT7JJ3EE6JsMhX8JTrZ+f1sEndYDXrA=
|
||||
github.com/aws/smithy-go v1.27.6/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc=
|
||||
github.com/aws/aws-sdk-go-v2 v1.43.6 h1:RrmFcqCBxkJuf7g1axVo5krB4jM/AO8r5e5oujrgdoQ=
|
||||
github.com/aws/aws-sdk-go-v2 v1.43.6/go.mod h1:tXpPM+v0D1lndmga+HqqLDIzUFJlEeR21aspVklHF00=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.18 h1:LAfOuhAH331fmOjTQpAaOlH+Ftn7RzSDJ2VFwjdMMy4=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.18/go.mod h1:4e5xhuXHx1e4U9EthvbPP1r/DIMp5c2823OL8karzcM=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.35 h1:UEzXuET8E42lxBPijuACu/tEK7v5lFPlk0Q+GT5WD9E=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.35/go.mod h1:KaMtJpFa2JlL2BStjjHQVwQpzZEmw+ND/EgVrfFoo2g=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.36 h1:84s5xMme6ENYEdKG8rsbSFFg/8+lbHBeM9QYSO0gnDk=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.36/go.mod h1:c46BLdagDLIswjgt+GeQOslXgeS0E6wCacs5yZbxPGk=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.37 h1:b5tb+CZItBkydC7r3hTNdSO3pszG1R2EtnA+7TePQPk=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.37/go.mod h1:ZQ+6SU9X0oz6+7MUCSswv9Mjci4eaqZr21HI2RVy/yA=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.37 h1:lznzIOvvbqjfe8UAaciCRJgBgJsxuTROKlhZuXQWfv8=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.37/go.mod h1:otfkzyfQeMMLZAqX59GSXTL3o22BR/l6HFaRzzbWSqA=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.37 h1:zCEORWo0eU0gDjG+IyApE/2B+ZGG1m+GU7B263XV8ds=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.37/go.mod h1:i6c0PEl3TNOWxRbQ++KQcVenPWS/GoQeiklKhNuqzJ8=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.38 h1:A3UAuCmx7LyUcrixBTzKJYYIUZ2yTvn6ZhT8PB+7APk=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.38/go.mod h1:1PDUYG9Z+JrbbsobsAZHjWOm9QBT/djiK3QbykTL5Z4=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.17 h1:OvYZOB3qA6zvfdRFiRFRzVSiElMYrz3GdntkXZxlp1o=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.17/go.mod h1:JgR/2Ew50ACfIWau1oeMRX59tMtC0kM+PYQGEaT04cY=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.30 h1:5437eMoOwqqQpZn2XJy74mlDCuPYL81texMT3mXqgtU=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.30/go.mod h1:xfu2m3dOpvW8lj98wQYa8V9ku/Rta59hsbireGzhh3A=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.37 h1:a3D4AjrOrTrP8+d9ILBthqrElf0z1JNol09Xvnwcys8=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.37/go.mod h1:ky0gTu+ukvUTuUKFIpp6Wid4oninrkCyvbFkVs0kpHM=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.38 h1:gX8B8y3Ho30B1LPxefDKMi/HZqWEb47U9ogs3DtSG0M=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.38/go.mod h1:l5WblZlcmGPe4/O7JY2HO25Z+xqTBvyfTyFbRMf8gYw=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.107.2 h1:GNU0/xtPEXMKilJZ/a8BedeuQnvu+Usi6qVm9EFfncc=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.107.2/go.mod h1:4jYWUecEsQtE73jPl7p3jrbYXH5ffcR4gegyCygagfg=
|
||||
github.com/aws/aws-sdk-go-v2/service/signin v1.5.6 h1:i68sFvXidKlkiSvI7d7Ilc1/UvW4CtBOaivH7jhG4fs=
|
||||
github.com/aws/aws-sdk-go-v2/service/signin v1.5.6/go.mod h1:/h7Obr9WTtzbjTHGASRQwLN7Bupw+TC3x8x7fyx39hE=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.33.6 h1:tpfGChmjUmv3W9WlRvy+stwKDTbFFdq8Zk9DbFPrfMU=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.33.6/go.mod h1:CSjiDzmG/lsKkTOYjbkM+duLmRlW+LOxD64Na44ijnI=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.38.6 h1:49BBtY68A+KJCQ3a2F3eUe6ROsKucxUdfHKoqorc0wI=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.38.6/go.mod h1:ptG2hbs7QltE1GcQY0MpS4bfrc51KCnBXUr7OT1EEfE=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.45.6 h1:JvExZWabChDM0qJAirQYGfOYo0ndT3edXj+fqSPNjkE=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.45.6/go.mod h1:XZcaQkV2cItp6yEkrwljyaPOf22RuX7T43jxap/FOmM=
|
||||
github.com/aws/smithy-go v1.27.8 h1:FR0dxZfIlV7Z8eh2iHfIofdunw382XsDV3Mxt9nUvRY=
|
||||
github.com/aws/smithy-go v1.27.8/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas=
|
||||
@@ -146,6 +148,8 @@ github.com/cilium/ebpf v0.22.0 h1:v2ktp0roffpMOj2MMf3idtCQZOsAoC4BJbAJN+ke2bY=
|
||||
github.com/cilium/ebpf v0.22.0/go.mod h1:CDzZbe2hC5JjlDC+CY3KFCzlYwN4gbxppYM+Z10bQt4=
|
||||
github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJv2v7Vk=
|
||||
github.com/clipperhouse/uax29/v2 v2.7.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM=
|
||||
github.com/cloudflare/circl v1.6.3 h1:9GPOhQGF9MCYUeXyMYlqTR6a5gTrgR/fBLXvUgtVcg8=
|
||||
github.com/cloudflare/circl v1.6.3/go.mod h1:2eXP6Qfat4O/Yhh8BznvKnJ+uzEoTQ6jVKJRn81BiS4=
|
||||
github.com/cncf/xds/go v0.0.0-20260202195803-dba9d589def2 h1:aBangftG7EVZoUb69Os8IaYg++6uMOdKK83QtkkvJik=
|
||||
github.com/cncf/xds/go v0.0.0-20260202195803-dba9d589def2/go.mod h1:qwXFYgsP6T7XnJtbKlf1HP8AjxZZyzxMmc+Lq5GjlU4=
|
||||
github.com/cockroachdb/errors v1.14.0 h1:EfdVEJpN3z8rPMo43Yit59LxoiIa470fSXpZXuEs+ZI=
|
||||
@@ -339,8 +343,8 @@ github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY
|
||||
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
|
||||
github.com/hashicorp/go-getter v1.8.6 h1:9sQboWULaydVphxc4S64oAI4YqpuCk7nPmvbk131ebY=
|
||||
github.com/hashicorp/go-getter v1.8.6/go.mod h1:nVH12eOV2P58dIiL3rsU6Fh3wLeJEKBOJzhMmzlSWoo=
|
||||
github.com/hashicorp/go-getter v1.8.8 h1:sRakhf+EH6s0LZLO2IgBwZ6hAFp+fZOZMNREwVELV80=
|
||||
github.com/hashicorp/go-getter v1.8.8/go.mod h1:fqFlibKpwfns/s4oljLB3upJspyfFLQhS7031PlfUDc=
|
||||
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
|
||||
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
||||
github.com/hashicorp/go-version v1.9.0 h1:CeOIz6k+LoN3qX9Z0tyQrPtiB1DFYRPfCIBtaXPSCnA=
|
||||
@@ -373,8 +377,8 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.19.1 h1:VsB4HPswih7mmZ8WleSFQ75c/Ui1M4trX5oAsJnhSlk=
|
||||
github.com/klauspost/compress v1.19.1/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
|
||||
github.com/klauspost/compress v1.19.2 h1:hMRETovs/pu/dVWN7zIT1PGG8t509MwT6bO7XSi26R8=
|
||||
github.com/klauspost/compress v1.19.2/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
@@ -416,8 +420,8 @@ github.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos
|
||||
github.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ=
|
||||
github.com/microsoft/go-mssqldb v1.10.0 h1:pHEt+Qz6YFPWqREq10mqSE524QQo+/QremwTCQht7TY=
|
||||
github.com/microsoft/go-mssqldb v1.10.0/go.mod h1:mnG7lGa9iYJbzJqGCXyuQCegStKMr3kogDLD6+bmggg=
|
||||
github.com/miekg/dns v1.1.72 h1:vhmr+TF2A3tuoGNkLDFK9zi36F2LS+hKTRW0Uf8kbzI=
|
||||
github.com/miekg/dns v1.1.72/go.mod h1:+EuEPhdHOsfk6Wk5TT2CzssZdqkmFhf8r+aVyDEToIs=
|
||||
github.com/miekg/dns v1.1.73 h1:uhT8nJxmTrPJYClxVxTCX+CVn6qnzSiybRk72Z6DgrE=
|
||||
github.com/miekg/dns v1.1.73/go.mod h1:RW2Obtfd5NZHvOFe3zYG0W8koWOQtAzyHaLo8vASBuQ=
|
||||
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
|
||||
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
@@ -543,14 +547,14 @@ github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjb
|
||||
github.com/spiffe/go-spiffe/v2 v2.8.1 h1:eXZMLsu+3MLEPJyGJkolqtVrteZfQdUpOWj6LTiDl/E=
|
||||
github.com/spiffe/go-spiffe/v2 v2.8.1/go.mod h1:47Q0Q9/AqGha8QLHp+kxpH4Wca7X7EnOtlIJy3mxZ3U=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
|
||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||
github.com/stretchr/objx v0.5.3 h1:jmXUvGomnU1o3W/V5h2VEradbpJDwGrzugQQvL0POH4=
|
||||
github.com/stretchr/objx v0.5.3/go.mod h1:rDQraq+vQZU7Fde9LOZLr8Tax6zZvy4kuNKF+QYS+U0=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
github.com/stretchr/testify v1.12.1 h1:EuwCh5fleGS7H32xRwO3wRGT7DxrDhLAT6FF8MpWDWE=
|
||||
github.com/stretchr/testify v1.12.1/go.mod h1:MDEgiDPPsNp5cuIrHPPCyornHKgEVbtFUmoNlxoYthg=
|
||||
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
||||
github.com/tj/go-spin v1.1.0 h1:lhdWZsvImxvZ3q1C5OIB7d72DuOwP4O2NdBg9PyzNds=
|
||||
@@ -645,22 +649,22 @@ go.yaml.in/yaml/v3 v3.0.5/go.mod h1:HVTZu1O7/Vkt2N+BFy8Zza+lnLsABggaTM2ZpNIGuKg=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.54.0 h1:YLIA59K4fiNzHzjnZt2tUJQjQtUWfWbeHBqKtk3eScw=
|
||||
golang.org/x/crypto v0.54.0/go.mod h1:KWL8ny2AZdGR2cWmzeHrp2azQPGogOv+HeQaVEXC2dk=
|
||||
golang.org/x/crypto v0.55.0 h1:+KWHjbgOaAQ66dh/YlkZKHlz9ZUlq61AFirAR9ntP8M=
|
||||
golang.org/x/crypto v0.55.0/go.mod h1:uq0V9dE/fzQuJtbnL+2EhWOE63vo164FY8xqEnV9xis=
|
||||
golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f h1:W3F4c+6OLc6H2lb//N1q4WpJkhzJCK5J6kUi1NTVXfM=
|
||||
golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f/go.mod h1:J1xhfL/vlindoeF/aINzNzt2Bket5bjo9sdOYzOsU80=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.38.0 h1:MECBjubtXD7yj4HrhIUcywNaGeNVUdfVnxmPajOk4yk=
|
||||
golang.org/x/mod v0.38.0/go.mod h1:V6Xz0pq8TQ3dGqVQ1FVHuelZpAL0uNhSkk9ogYP3c40=
|
||||
golang.org/x/mod v0.40.0 h1:hUv+3cXcdRHz08UmSiOob7sadHig73uo5bkXxQ/tvUs=
|
||||
golang.org/x/mod v0.40.0/go.mod h1:0/weTWkPWGBikyTWAX3dkjVztMmBA5hM0DH6BElSupE=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.57.0 h1:K5+3DljvIuDG9/Jv9rvyMywYNFCQ9RSUY6OOTTkT+tE=
|
||||
golang.org/x/net v0.57.0/go.mod h1:KpXc8iv+r3XplLAG/f7Jsf9RPszJzdR0f58q9vGOuEU=
|
||||
golang.org/x/net v0.58.0 h1:ynWG7rqYi4ccpTEuPZ2QGWHktVEM9DMCj9yzDE0Q7To=
|
||||
golang.org/x/net v0.58.0/go.mod h1:YwCddHnFlT7eLQqVprV19OnhLGtc5xOKgE0RyqgfWAU=
|
||||
golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs=
|
||||
golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -688,30 +692,30 @@ golang.org/x/term v0.45.0/go.mod h1:9aqxs0blBcrm/n0L9QW0aRVD+ktan8ssZromtqJC43w=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.40.0 h1:Ub2Z6/xjgF1WrYQz2nuITOEegKFtiIy+rieRJ5lHZKs=
|
||||
golang.org/x/text v0.40.0/go.mod h1:hpnzDAfGV753zIKo+wk3u1bVKCGPbrnF7+7LBF/UHVY=
|
||||
golang.org/x/text v0.41.0 h1:vz/seA0lnX87Othu2f/0L24RcgrXD9/YFTSuGjj3rH8=
|
||||
golang.org/x/text v0.41.0/go.mod h1:jvf1O8ajNzZqhSrQBPbutR/EB83Cc0CFrezNQIwbb5M=
|
||||
golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
|
||||
golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.48.0 h1:3+hClM1aLL5mjMKm5ovokw9epgRXPuu2tILgismM6RE=
|
||||
golang.org/x/tools v0.48.0/go.mod h1:08xX0orndb/F7jJxGDicx061tyd5pcMto75YMAXr6lk=
|
||||
golang.org/x/tools v0.49.0 h1:3NI7VXzL9+1WZD52Dx2ttoPwD5DWrFGpl9mFZDlmisI=
|
||||
golang.org/x/tools v0.49.0/go.mod h1:SJNXV9DBKT0UbdttsQjbfJlAE/q+y36++zo3uL3N0Oo=
|
||||
golang.org/x/xerrors v0.0.0-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=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=
|
||||
gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E=
|
||||
google.golang.org/api v0.291.0 h1:wfPbbY+mr9c7wZLqqzrHJLft/q8iFKREd6IgTBUene0=
|
||||
google.golang.org/api v0.291.0/go.mod h1:at7kwWbuonglBFEBoeMDAV1bguHqL3qf0BHFsv3coa0=
|
||||
google.golang.org/api v0.292.0 h1:Ewiwo/GTtiaPZSNAZQUcWLh8AYDEoPmIXyJfeoTSMHU=
|
||||
google.golang.org/api v0.292.0/go.mod h1:07kjmMnFGm2RQuCza2EZM/5N68G/fVvFb1xKjWqoFA0=
|
||||
google.golang.org/genproto v0.0.0-20260729162451-8efbd57d26e0 h1:xJf8e9ReUqiexuIT3OWJkvA4RdgR8K4Hfheq8gaKxIM=
|
||||
google.golang.org/genproto v0.0.0-20260729162451-8efbd57d26e0/go.mod h1:0MNk3ibJAyOwDZVlp18knQe3jRyFxpcU06xjxhgjx0M=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20260729162451-8efbd57d26e0 h1:ybvH/ZpOcpCrjtkb7oW/fdlzbEmRVeumw19SRQmNFKU=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20260729162451-8efbd57d26e0/go.mod h1:HJ9MpJLeDSstBkx1LILTpd5f41ADSMZcTPypw02qEGw=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260729162451-8efbd57d26e0 h1:mJiOtnGp0k/BcSgdu03G2NwnscCfCH+h2QKUBZr18KI=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260729162451-8efbd57d26e0/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260803160001-6ac0973c030d h1:IL4hdHzcUv2l/gcg98/Rj3FbtE6axwqslOW8SW0C+S0=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260803160001-6ac0973c030d/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
||||
google.golang.org/grpc v1.83.0 h1:JeNZEKJFbQxArAMl+hiytHauacDNqJUllNfmIMmpqnQ=
|
||||
google.golang.org/grpc v1.83.0/go.mod h1:kDyl6SKsiHKt0uylY5gtn5cEjkrIOhQOGDgIc4JGwzQ=
|
||||
google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af h1:+5/Sw3GsDNlEmu7TfklWKPdQ0Ykja5VEmq2i817+jbI=
|
||||
@@ -737,8 +741,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.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q=
|
||||
gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA=
|
||||
helm.sh/helm/v3 v3.21.3 h1:wkamdwI3liEkW6wI1l9aGqQZGxcTKyt8kx0qJLPcmCg=
|
||||
helm.sh/helm/v3 v3.21.3/go.mod h1:iaJ0iNsPoTZl++7h6vzQFyT0VEVtLYJiyRBDkPOOBTs=
|
||||
helm.sh/helm/v3 v3.21.4 h1:T/GcIEXU/gNjJnkITlIZ3e9xqkZjhFTmISuStTZ6+Qg=
|
||||
helm.sh/helm/v3 v3.21.4/go.mod h1:cS2FBb+xfLuaSqvEmbqIeKUVFgHdHVHtVeXb2epof3M=
|
||||
k8s.io/api v0.36.3 h1:NxB+05W2UGqXWFXcLO0RB5cnqnUPP5v5sVlaOH0Iz4w=
|
||||
k8s.io/api v0.36.3/go.mod h1:JzLQKqRHC5+I8RVj/lS3lCg0mg6nWI9Fo/Sk3ElxHzg=
|
||||
k8s.io/apiextensions-apiserver v0.36.3 h1:dPmOAPhwTtqb1bTxbFPsy18KHPhktQeO3WUPXunZIB0=
|
||||
|
||||
+54
-25
@@ -30,6 +30,9 @@ func (a *AnalyzeSecret) Analyze(getFile getCollectedFileContents, findFiles getC
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if result == nil {
|
||||
return nil, nil
|
||||
}
|
||||
result.Strict = a.analyzer.Strict.BoolOrDefaultFalse()
|
||||
return []*AnalyzeResult{result}, nil
|
||||
}
|
||||
@@ -54,42 +57,68 @@ func (a *AnalyzeSecret) analyzeSecret(analyzer *troubleshootv1beta2.AnalyzeSecre
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// The secret analyzer only supports fail (not found) and pass (found) outcomes
|
||||
// per https://troubleshoot.sh/docs/analyze/secrets. If the spec contains
|
||||
// neither, return an explicit error: returning (nil, nil) is swallowed by the
|
||||
// Analyze wrapper into an empty result slice, so the misconfiguration would
|
||||
// surface as neither a result nor an error.
|
||||
// Capture fail and pass independently: a single outcome object may set both,
|
||||
// so an else-if here would silently drop the second one.
|
||||
var failOutcome, passOutcome *troubleshootv1beta2.SingleOutcome
|
||||
for _, outcome := range analyzer.Outcomes {
|
||||
if outcome.Fail != nil {
|
||||
failOutcome = outcome.Fail
|
||||
}
|
||||
if outcome.Pass != nil {
|
||||
passOutcome = outcome.Pass
|
||||
}
|
||||
}
|
||||
if failOutcome == nil && passOutcome == nil {
|
||||
return nil, fmt.Errorf("secret analyzer %s/%s must define at least one pass or fail outcome", analyzer.Namespace, analyzer.SecretName)
|
||||
}
|
||||
|
||||
result := AnalyzeResult{
|
||||
Title: a.Title(),
|
||||
IconKey: "kubernetes_analyze_secret",
|
||||
IconURI: "https://troubleshoot.sh/images/analyzer-icons/secret.svg?w=13&h=16",
|
||||
}
|
||||
|
||||
var failOutcome *troubleshootv1beta2.Outcome
|
||||
for _, outcome := range analyzer.Outcomes {
|
||||
if outcome.Fail != nil {
|
||||
failOutcome = outcome
|
||||
}
|
||||
secretFound := foundSecret.SecretExists
|
||||
if secretFound && analyzer.Key != "" {
|
||||
secretFound = foundSecret.Key == analyzer.Key && foundSecret.KeyExists
|
||||
}
|
||||
|
||||
if !foundSecret.SecretExists {
|
||||
// Use the matched branch's configured outcome verbatim, tracking whether one
|
||||
// was actually present. A configured outcome with an intentionally empty
|
||||
// message (e.g. a URI-only outcome) is preserved as-is. But when the matched
|
||||
// branch has NO configured outcome at all — e.g. a pass-only spec that took
|
||||
// the fail path, or a fail-only spec that passed — the empty message is not
|
||||
// an intentional choice, so fall back to a default diagnostic. An absent
|
||||
// outcome is not the same as an intentionally empty one.
|
||||
outcomeConfigured := false
|
||||
if secretFound {
|
||||
result.IsPass = true
|
||||
if passOutcome != nil {
|
||||
result.Message = passOutcome.Message
|
||||
result.URI = passOutcome.URI
|
||||
outcomeConfigured = true
|
||||
}
|
||||
} else {
|
||||
result.IsFail = true
|
||||
result.Message = failOutcome.Fail.Message
|
||||
result.URI = failOutcome.Fail.URI
|
||||
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
if analyzer.Key != "" {
|
||||
if foundSecret.Key != analyzer.Key || !foundSecret.KeyExists {
|
||||
result.IsFail = true
|
||||
result.Message = failOutcome.Fail.Message
|
||||
result.URI = failOutcome.Fail.URI
|
||||
|
||||
return &result, nil
|
||||
if failOutcome != nil {
|
||||
result.Message = failOutcome.Message
|
||||
result.URI = failOutcome.URI
|
||||
outcomeConfigured = true
|
||||
}
|
||||
}
|
||||
|
||||
result.IsPass = true
|
||||
for _, outcome := range analyzer.Outcomes {
|
||||
if outcome.Pass != nil {
|
||||
result.Message = outcome.Pass.Message
|
||||
result.URI = outcome.Pass.URI
|
||||
if !outcomeConfigured {
|
||||
switch {
|
||||
case result.IsPass:
|
||||
result.Message = fmt.Sprintf("Secret %s was found in namespace %s", analyzer.SecretName, analyzer.Namespace)
|
||||
case analyzer.Key != "" && foundSecret.SecretExists:
|
||||
result.Message = fmt.Sprintf("Key %s was not found in secret %s/%s", analyzer.Key, analyzer.Namespace, analyzer.SecretName)
|
||||
default:
|
||||
result.Message = fmt.Sprintf("Secret %s was not found in namespace %s", analyzer.SecretName, analyzer.Namespace)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -166,6 +166,118 @@ func Test_analyzeSecret(t *testing.T) {
|
||||
IconURI: "https://troubleshoot.sh/images/analyzer-icons/secret.svg?w=13&h=16",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "not found with no fail outcome falls back to a default message (no configured outcome for this branch)",
|
||||
analyzer: &troubleshootv1beta2.AnalyzeSecret{
|
||||
AnalyzeMeta: troubleshootv1beta2.AnalyzeMeta{
|
||||
CheckName: "Optional Secret",
|
||||
},
|
||||
Namespace: "default",
|
||||
SecretName: "does-not-exist",
|
||||
Outcomes: []*troubleshootv1beta2.Outcome{
|
||||
{
|
||||
Pass: &troubleshootv1beta2.SingleOutcome{
|
||||
Message: "secret found",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
mockFiles: map[string][]byte{
|
||||
"secrets/default/does-not-exist.json": mustJSONMarshalIndent(t, collect.SecretOutput{
|
||||
Namespace: "default",
|
||||
Name: "does-not-exist",
|
||||
SecretExists: false,
|
||||
}),
|
||||
},
|
||||
want: &AnalyzeResult{
|
||||
IsFail: true,
|
||||
Message: "Secret does-not-exist was not found in namespace default",
|
||||
Title: "Optional Secret",
|
||||
IconKey: "kubernetes_analyze_secret",
|
||||
IconURI: "https://troubleshoot.sh/images/analyzer-icons/secret.svg?w=13&h=16",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "key not found with no fail outcome falls back to a default message (no configured outcome for this branch)",
|
||||
analyzer: &troubleshootv1beta2.AnalyzeSecret{
|
||||
AnalyzeMeta: troubleshootv1beta2.AnalyzeMeta{
|
||||
CheckName: "Optional Secret Key",
|
||||
},
|
||||
Namespace: "test-namespace",
|
||||
SecretName: "test-secret",
|
||||
Key: "missing-key",
|
||||
Outcomes: []*troubleshootv1beta2.Outcome{
|
||||
{
|
||||
Pass: &troubleshootv1beta2.SingleOutcome{
|
||||
Message: "key found",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
mockFiles: map[string][]byte{
|
||||
"secrets/test-namespace/test-secret/missing-key.json": mustJSONMarshalIndent(t, collect.SecretOutput{
|
||||
Namespace: "test-namespace",
|
||||
Name: "test-secret",
|
||||
Key: "missing-key",
|
||||
SecretExists: true,
|
||||
KeyExists: false,
|
||||
}),
|
||||
},
|
||||
want: &AnalyzeResult{
|
||||
IsFail: true,
|
||||
Message: "Key missing-key was not found in secret test-namespace/test-secret",
|
||||
Title: "Optional Secret Key",
|
||||
IconKey: "kubernetes_analyze_secret",
|
||||
IconURI: "https://troubleshoot.sh/images/analyzer-icons/secret.svg?w=13&h=16",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "found with only fail outcome configured falls back to the default pass message, not the fail outcome's message",
|
||||
analyzer: &troubleshootv1beta2.AnalyzeSecret{
|
||||
Namespace: "test-namespace",
|
||||
SecretName: "test-secret",
|
||||
Outcomes: []*troubleshootv1beta2.Outcome{
|
||||
{
|
||||
Fail: &troubleshootv1beta2.SingleOutcome{
|
||||
Message: "Not found",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
mockFiles: map[string][]byte{
|
||||
"secrets/test-namespace/test-secret.json": mustJSONMarshalIndent(t, collect.SecretOutput{
|
||||
Namespace: "test-namespace",
|
||||
Name: "test-secret",
|
||||
SecretExists: true,
|
||||
}),
|
||||
},
|
||||
want: &AnalyzeResult{
|
||||
IsPass: true,
|
||||
Message: "Secret test-secret was found in namespace test-namespace",
|
||||
Title: "Secret test-secret",
|
||||
IconKey: "kubernetes_analyze_secret",
|
||||
IconURI: "https://troubleshoot.sh/images/analyzer-icons/secret.svg?w=13&h=16",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "spec with neither fail nor pass outcome returns an error so the framework surfaces the misconfiguration",
|
||||
analyzer: &troubleshootv1beta2.AnalyzeSecret{
|
||||
AnalyzeMeta: troubleshootv1beta2.AnalyzeMeta{
|
||||
CheckName: "Misconfigured",
|
||||
},
|
||||
Namespace: "default",
|
||||
SecretName: "does-not-exist",
|
||||
Outcomes: []*troubleshootv1beta2.Outcome{},
|
||||
},
|
||||
mockFiles: map[string][]byte{
|
||||
"secrets/default/does-not-exist.json": mustJSONMarshalIndent(t, collect.SecretOutput{
|
||||
Namespace: "default",
|
||||
Name: "does-not-exist",
|
||||
SecretExists: false,
|
||||
}),
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "key not found secret not found",
|
||||
analyzer: &troubleshootv1beta2.AnalyzeSecret{
|
||||
@@ -190,6 +302,128 @@ func Test_analyzeSecret(t *testing.T) {
|
||||
},
|
||||
wantErr: true, // TODO: should this be a not found error? This will not work with selectors.
|
||||
},
|
||||
{
|
||||
name: "combined fail and pass in a single outcome, secret found uses the pass outcome",
|
||||
analyzer: &troubleshootv1beta2.AnalyzeSecret{
|
||||
Namespace: "test-namespace",
|
||||
SecretName: "test-secret",
|
||||
Outcomes: []*troubleshootv1beta2.Outcome{
|
||||
{
|
||||
Fail: &troubleshootv1beta2.SingleOutcome{
|
||||
Message: "Not found",
|
||||
},
|
||||
Pass: &troubleshootv1beta2.SingleOutcome{
|
||||
Message: "Found",
|
||||
URI: "https://example.com/found",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
mockFiles: map[string][]byte{
|
||||
"secrets/test-namespace/test-secret.json": mustJSONMarshalIndent(t, collect.SecretOutput{
|
||||
Namespace: "test-namespace",
|
||||
Name: "test-secret",
|
||||
SecretExists: true,
|
||||
}),
|
||||
},
|
||||
want: &AnalyzeResult{
|
||||
IsPass: true,
|
||||
Message: "Found",
|
||||
URI: "https://example.com/found",
|
||||
Title: "Secret test-secret",
|
||||
IconKey: "kubernetes_analyze_secret",
|
||||
IconURI: "https://troubleshoot.sh/images/analyzer-icons/secret.svg?w=13&h=16",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "combined fail and pass in a single outcome, secret not found uses the fail outcome",
|
||||
analyzer: &troubleshootv1beta2.AnalyzeSecret{
|
||||
Namespace: "test-namespace",
|
||||
SecretName: "test-secret",
|
||||
Outcomes: []*troubleshootv1beta2.Outcome{
|
||||
{
|
||||
Fail: &troubleshootv1beta2.SingleOutcome{
|
||||
Message: "Not found",
|
||||
},
|
||||
Pass: &troubleshootv1beta2.SingleOutcome{
|
||||
Message: "Found",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
mockFiles: map[string][]byte{
|
||||
"secrets/test-namespace/test-secret.json": mustJSONMarshalIndent(t, collect.SecretOutput{
|
||||
Namespace: "test-namespace",
|
||||
Name: "test-secret",
|
||||
SecretExists: false,
|
||||
}),
|
||||
},
|
||||
want: &AnalyzeResult{
|
||||
IsFail: true,
|
||||
Message: "Not found",
|
||||
Title: "Secret test-secret",
|
||||
IconKey: "kubernetes_analyze_secret",
|
||||
IconURI: "https://troubleshoot.sh/images/analyzer-icons/secret.svg?w=13&h=16",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "secret found with URI-only pass outcome preserves the empty message and URI",
|
||||
analyzer: &troubleshootv1beta2.AnalyzeSecret{
|
||||
Namespace: "test-namespace",
|
||||
SecretName: "test-secret",
|
||||
Outcomes: []*troubleshootv1beta2.Outcome{
|
||||
{
|
||||
Pass: &troubleshootv1beta2.SingleOutcome{
|
||||
URI: "https://example.com/pass",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
mockFiles: map[string][]byte{
|
||||
"secrets/test-namespace/test-secret.json": mustJSONMarshalIndent(t, collect.SecretOutput{
|
||||
Namespace: "test-namespace",
|
||||
Name: "test-secret",
|
||||
SecretExists: true,
|
||||
}),
|
||||
},
|
||||
want: &AnalyzeResult{
|
||||
IsPass: true,
|
||||
Message: "",
|
||||
URI: "https://example.com/pass",
|
||||
Title: "Secret test-secret",
|
||||
IconKey: "kubernetes_analyze_secret",
|
||||
IconURI: "https://troubleshoot.sh/images/analyzer-icons/secret.svg?w=13&h=16",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "secret not found with URI-only fail outcome preserves the empty message and URI",
|
||||
analyzer: &troubleshootv1beta2.AnalyzeSecret{
|
||||
Namespace: "test-namespace",
|
||||
SecretName: "test-secret",
|
||||
Outcomes: []*troubleshootv1beta2.Outcome{
|
||||
{
|
||||
Fail: &troubleshootv1beta2.SingleOutcome{
|
||||
URI: "https://example.com/fail",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
mockFiles: map[string][]byte{
|
||||
"secrets/test-namespace/test-secret.json": mustJSONMarshalIndent(t, collect.SecretOutput{
|
||||
Namespace: "test-namespace",
|
||||
Name: "test-secret",
|
||||
SecretExists: false,
|
||||
}),
|
||||
},
|
||||
want: &AnalyzeResult{
|
||||
IsFail: true,
|
||||
Message: "",
|
||||
URI: "https://example.com/fail",
|
||||
Title: "Secret test-secret",
|
||||
IconKey: "kubernetes_analyze_secret",
|
||||
IconURI: "https://troubleshoot.sh/images/analyzer-icons/secret.svg?w=13&h=16",
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
||||
@@ -294,7 +294,18 @@ func (c *CollectClusterResources) Collect(progressChan chan<- interface{}) (Coll
|
||||
// crs
|
||||
customResources, crErrors := crs(ctx, dynamicClient, client, c.ClientConfig, namespaceNames)
|
||||
for k, v := range customResources {
|
||||
output.SaveResult(c.BundlePath, path.Join(constants.CLUSTER_RESOURCES_DIR, constants.CLUSTER_RESOURCES_CUSTOM_RESOURCES, k), bytes.NewBuffer(v))
|
||||
jsonPath := path.Join(constants.CLUSTER_RESOURCES_DIR, constants.CLUSTER_RESOURCES_CUSTOM_RESOURCES, k)
|
||||
output.SaveResult(c.BundlePath, jsonPath, bytes.NewBuffer(v))
|
||||
|
||||
// Keep a YAML symlink for backward compatibility. It points at the JSON
|
||||
// file, so any analyzer that expects YAML can still read it, and the
|
||||
// content is redacted through the JSON copy.
|
||||
if strings.HasSuffix(k, ".json") {
|
||||
yamlPath := path.Join(constants.CLUSTER_RESOURCES_DIR, constants.CLUSTER_RESOURCES_CUSTOM_RESOURCES, strings.TrimSuffix(k, ".json")+".yaml")
|
||||
if err := output.SymLinkResult(c.BundlePath, yamlPath, jsonPath); err != nil {
|
||||
klog.V(2).Infof("failed to create YAML symlink for %s: %v", jsonPath, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
output.SaveResult(c.BundlePath, path.Join(constants.CLUSTER_RESOURCES_DIR, constants.CLUSTER_RESOURCES_CUSTOM_RESOURCES, fmt.Sprintf("%s-errors.json", constants.CLUSTER_RESOURCES_CUSTOM_RESOURCES)), marshalErrors(crErrors))
|
||||
|
||||
@@ -2294,23 +2305,18 @@ func mutatingWebhookConfigurations(ctx context.Context, client kubernetes.Interf
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// storeCustomResource stores a custom resource as JSON and YAML
|
||||
// We use both formats for backwards compatibility. This way we
|
||||
// avoid breaking existing tools and analysers that already rely on
|
||||
// the YAML format.
|
||||
// storeCustomResource stores a custom resource as JSON only.
|
||||
// JSON is valid YAML, so any analyzer expecting YAML can consume the JSON
|
||||
// file directly. We no longer write a separate YAML file because the
|
||||
// built-in redactors are authored for JSON, and the duplicate YAML copy
|
||||
// would otherwise be left unredacted.
|
||||
func storeCustomResource(name string, objects any, m map[string][]byte) error {
|
||||
j, err := json.MarshalIndent(objects, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
y, err := yaml.Marshal(objects)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
m[fmt.Sprintf("%s.json", name)] = j
|
||||
m[fmt.Sprintf("%s.yaml", name)] = y
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,6 @@ import (
|
||||
"k8s.io/client-go/kubernetes"
|
||||
testclient "k8s.io/client-go/kubernetes/fake"
|
||||
k8stesting "k8s.io/client-go/testing"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -512,17 +511,8 @@ func TestCollectClusterResources_CustomResource(t *testing.T) {
|
||||
// Fetch the CR from cluster
|
||||
res, errs := crsV1(ctx, dynamicClient, apixClient.ApiextensionsV1(), []string{"default"})
|
||||
assert.Empty(t, errs)
|
||||
require.Equal(t, 2, len(res))
|
||||
require.Equal(t, 1, len(res))
|
||||
assert.Equal(t, fromJSON(t, res["supportbundles.troubleshoot.sh/default.json"]), sbObject)
|
||||
assert.Equal(t, fromYAML(t, res["supportbundles.troubleshoot.sh/default.yaml"]), sbObject)
|
||||
}
|
||||
|
||||
func fromYAML(t *testing.T, dat []byte) troubleshootv1beta2.SupportBundle {
|
||||
sb := []troubleshootv1beta2.SupportBundle{}
|
||||
err := yaml.Unmarshal(dat, &sb)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(sb))
|
||||
return sb[0]
|
||||
}
|
||||
|
||||
func fromJSON(t *testing.T, dat []byte) troubleshootv1beta2.SupportBundle {
|
||||
|
||||
+31
-32
@@ -35,6 +35,32 @@ func init() {
|
||||
}
|
||||
}
|
||||
|
||||
// kurlInstallerRedactors are built-in redactors scoped to the kurl installer
|
||||
// custom resource. They previously applied only to the YAML copy of custom
|
||||
// resources; now they target the JSON file (and the YAML symlink that points to it).
|
||||
// The installer CRD can be either cluster-scoped (installers.cluster.kurl.sh.json)
|
||||
// or namespaced (installers.cluster.kurl.sh/<namespace>.json), so both patterns are
|
||||
// included.
|
||||
var kurlInstallerRedactors = []*troubleshootv1beta2.Redact{
|
||||
{
|
||||
Name: "Redact kurl installer fields",
|
||||
FileSelector: troubleshootv1beta2.FileSelector{
|
||||
Files: []string{
|
||||
fmt.Sprintf("%s/%s/%s.json", constants.CLUSTER_RESOURCES_DIR, constants.CLUSTER_RESOURCES_CUSTOM_RESOURCES, "installers.cluster.kurl.sh"),
|
||||
fmt.Sprintf("%s/%s/%s/*.json", constants.CLUSTER_RESOURCES_DIR, constants.CLUSTER_RESOURCES_CUSTOM_RESOURCES, "installers.cluster.kurl.sh"),
|
||||
},
|
||||
},
|
||||
Removals: troubleshootv1beta2.Removals{
|
||||
Regex: []troubleshootv1beta2.Regex{
|
||||
{Redactor: `(?i)("bootstrapToken"\s*:\s*")(?P<mask>[^"]*)(")`},
|
||||
{Redactor: `(?i)("certKey"\s*:\s*")(?P<mask>[^"]*)(")`},
|
||||
{Redactor: `(?i)("kubeadmToken"\s*:\s*")(?P<mask>[^"]*)(")`},
|
||||
{Redactor: `(?i)("kubectl\.kubernetes\.io/last-applied-configuration"\s*:\s*")(?P<mask>(?:\\.|[^"\\])*)(")`},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// A regex cache to avoid recompiling the same regexes over and over
|
||||
func compileRegex(pattern string) (*regexp.Regexp, error) {
|
||||
regexCacheLock.Lock()
|
||||
@@ -440,39 +466,12 @@ func getRedactors(path string) ([]Redactor, error) {
|
||||
redactors = append(redactors, r)
|
||||
}
|
||||
|
||||
customResources := []struct {
|
||||
resource string
|
||||
yamlPath string
|
||||
}{
|
||||
{
|
||||
resource: "installers.cluster.kurl.sh",
|
||||
yamlPath: "*.spec.kubernetes.bootstrapToken",
|
||||
},
|
||||
{
|
||||
resource: "installers.cluster.kurl.sh",
|
||||
yamlPath: "*.spec.kubernetes.certKey",
|
||||
},
|
||||
{
|
||||
resource: "installers.cluster.kurl.sh",
|
||||
yamlPath: "*.spec.kubernetes.kubeadmToken",
|
||||
},
|
||||
}
|
||||
|
||||
uniqueCRs := map[string]bool{}
|
||||
for _, cr := range customResources {
|
||||
fileglob := fmt.Sprintf("%s/%s/%s/*.yaml", constants.CLUSTER_RESOURCES_DIR, constants.CLUSTER_RESOURCES_CUSTOM_RESOURCES, cr.resource)
|
||||
redactors = append(redactors, NewYamlRedactor(cr.yamlPath, fileglob, ""))
|
||||
|
||||
// redact kubectl last applied annotation once for each resource since it contains copies of
|
||||
// redacted fields
|
||||
if !uniqueCRs[cr.resource] {
|
||||
uniqueCRs[cr.resource] = true
|
||||
redactors = append(redactors, &YamlRedactor{
|
||||
filePath: fileglob,
|
||||
maskPath: []string{"*", "metadata", "annotations", "kubectl.kubernetes.io/last-applied-configuration"},
|
||||
})
|
||||
}
|
||||
// Add built-in redactors that are scoped to specific custom resource files.
|
||||
scopedRedactors, err := buildAdditionalRedactors(path, kurlInstallerRedactors)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
redactors = append(redactors, scopedRedactors...)
|
||||
|
||||
return redactors, nil
|
||||
}
|
||||
|
||||
@@ -1874,3 +1874,49 @@ func Test_redactMatchesPath(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_RedactKurlInstallerJSON(t *testing.T) {
|
||||
input := `[
|
||||
{
|
||||
"metadata": {
|
||||
"name": "kurl",
|
||||
"annotations": {
|
||||
"kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"cluster.kurl.sh/v1beta1\",\"kind\":\"Installer\",\"spec\":{\"kubernetes\":{\"bootstrapToken\":\"abc\",\"certKey\":\"def\",\"kubeadmToken\":\"ghi\"}}}"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"kubernetes": {
|
||||
"bootstrapToken": "abc",
|
||||
"certKey": "def",
|
||||
"kubeadmToken": "ghi"
|
||||
}
|
||||
}
|
||||
}
|
||||
]`
|
||||
|
||||
cases := []string{
|
||||
// Cluster-scoped installer (file directly under custom-resources)
|
||||
"cluster-resources/custom-resources/installers.cluster.kurl.sh.json",
|
||||
// Namespaced installer (file under a per-CRD directory)
|
||||
"cluster-resources/custom-resources/installers.cluster.kurl.sh/default.json",
|
||||
}
|
||||
|
||||
for _, path := range cases {
|
||||
t.Run(path, func(t *testing.T) {
|
||||
r, err := Redact(strings.NewReader(input), path, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
out, err := ioutil.ReadAll(r)
|
||||
require.NoError(t, err)
|
||||
|
||||
outStr := string(out)
|
||||
require.NotContains(t, outStr, `"abc"`)
|
||||
require.NotContains(t, outStr, `"def"`)
|
||||
require.NotContains(t, outStr, `"ghi"`)
|
||||
require.Contains(t, outStr, `"bootstrapToken": "***HIDDEN***"`)
|
||||
require.Contains(t, outStr, `"certKey": "***HIDDEN***"`)
|
||||
require.Contains(t, outStr, `"kubeadmToken": "***HIDDEN***"`)
|
||||
require.Contains(t, outStr, `"kubectl.kubernetes.io/last-applied-configuration": "***HIDDEN***"`)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,9 @@ import (
|
||||
"k8s.io/klog/v2"
|
||||
)
|
||||
|
||||
// loadFromSecret is a package-level hook so tests can stub out cluster access.
|
||||
var loadFromSecret = specs.LoadFromSecret
|
||||
|
||||
// GetSupportBundleFromURI downloads and parses a support bundle from a URI and returns a SupportBundle object
|
||||
func GetSupportBundleFromURI(bundleURI string) (*troubleshootv1beta2.SupportBundle, error) {
|
||||
collectorContent, err := LoadSupportBundleSpec(bundleURI)
|
||||
@@ -165,6 +168,29 @@ func LoadSupportBundleSpec(arg string) ([]byte, error) {
|
||||
}
|
||||
|
||||
func LoadRedactorSpec(arg string) ([]byte, error) {
|
||||
if strings.HasPrefix(arg, "secret/") {
|
||||
// format secret/namespace-name/secret-name[/data-key]
|
||||
pathParts := strings.Split(arg, "/")
|
||||
if len(pathParts) > 4 {
|
||||
return nil, errors.Errorf("secret path %s must have at most 4 components", arg)
|
||||
}
|
||||
if len(pathParts) < 3 {
|
||||
return nil, errors.Errorf("secret path %s must have at least 3 components", arg)
|
||||
}
|
||||
|
||||
dataKey := "redactor-spec"
|
||||
if len(pathParts) == 4 {
|
||||
dataKey = pathParts[3]
|
||||
}
|
||||
|
||||
spec, err := loadFromSecret(pathParts[1], pathParts[2], dataKey)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to get spec from secret")
|
||||
}
|
||||
|
||||
return spec, nil
|
||||
}
|
||||
|
||||
if strings.HasPrefix(arg, "configmap/") {
|
||||
// format configmap/namespace-name/configmap-name[/data-key]
|
||||
pathParts := strings.Split(arg, "/")
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package supportbundle
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
|
||||
@@ -92,3 +94,61 @@ spec:
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadRedactorSpec(t *testing.T) {
|
||||
origLoadFromSecret := loadFromSecret
|
||||
defer func() { loadFromSecret = origLoadFromSecret }()
|
||||
|
||||
loadFromSecret = func(namespace, secretName, key string) ([]byte, error) {
|
||||
return []byte(fmt.Sprintf("namespace=%s,secret=%s,key=%s", namespace, secretName, key)), nil
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
uri string
|
||||
wantContent string
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
name: "secret URI with default key",
|
||||
uri: "secret/default/my-redactor",
|
||||
wantContent: "namespace=default,secret=my-redactor,key=redactor-spec",
|
||||
},
|
||||
{
|
||||
name: "secret URI with custom key",
|
||||
uri: "secret/default/my-redactor/custom-key",
|
||||
wantContent: "namespace=default,secret=my-redactor,key=custom-key",
|
||||
},
|
||||
{
|
||||
name: "secret URI with too few components",
|
||||
uri: "secret/default",
|
||||
wantErr: "must have at least 3 components",
|
||||
},
|
||||
{
|
||||
name: "secret URI with too many components",
|
||||
uri: "secret/default/my-redactor/custom-key/extra",
|
||||
wantErr: "must have at most 4 components",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := LoadRedactorSpec(tt.uri)
|
||||
if tt.wantErr != "" {
|
||||
if err == nil {
|
||||
t.Fatalf("LoadRedactorSpec() expected error, got nil")
|
||||
}
|
||||
if !strings.Contains(err.Error(), tt.wantErr) {
|
||||
t.Errorf("LoadRedactorSpec() error = %q, want containing %q", err.Error(), tt.wantErr)
|
||||
}
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("LoadRedactorSpec() unexpected error = %v", err)
|
||||
}
|
||||
if string(got) != tt.wantContent {
|
||||
t.Errorf("LoadRedactorSpec() = %q, want %q", string(got), tt.wantContent)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
contents:
|
||||
repositories:
|
||||
- https://apk.cve0.io
|
||||
keyring:
|
||||
- https://apk.cve0.io/key/cve0-signing.rsa.pub
|
||||
packages:
|
||||
- troubleshoot
|
||||
- bash
|
||||
- kmod
|
||||
- ca-certificates-bundle
|
||||
- securebuild-baselayout
|
||||
- busybox
|
||||
|
||||
cmd: bash
|
||||
|
||||
work-dir: /
|
||||
|
||||
archs:
|
||||
- x86_64
|
||||
- aarch64
|
||||
|
||||
environment:
|
||||
PATH: /troubleshoot:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
||||
|
||||
paths:
|
||||
- path: /troubleshoot
|
||||
type: directory
|
||||
uid: 0
|
||||
gid: 0
|
||||
permissions: 0o755
|
||||
|
||||
- path: /troubleshoot/support-bundle
|
||||
type: symlink
|
||||
source: /usr/bin/support-bundle
|
||||
permissions: 0o755
|
||||
|
||||
- path: /troubleshoot/preflight
|
||||
type: symlink
|
||||
source: /usr/bin/preflight
|
||||
permissions: 0o755
|
||||
|
||||
- path: /troubleshoot/collect
|
||||
type: symlink
|
||||
source: /usr/bin/collect
|
||||
permissions: 0o755
|
||||
|
||||
annotations:
|
||||
org.opencontainers.image.title: Troubleshoot (SecureBuild)
|
||||
org.opencontainers.image.description: Troubleshoot tools for collecting and analyzing Kubernetes cluster diagnostics
|
||||
org.opencontainers.image.source: https://github.com/replicatedhq/troubleshoot
|
||||
org.opencontainers.image.vendor: SecureBuild
|
||||
@@ -0,0 +1,106 @@
|
||||
package:
|
||||
name: troubleshoot-head
|
||||
version: "1000.0.0"
|
||||
epoch: 0
|
||||
description: Troubleshoot tools for collecting and analyzing Kubernetes cluster diagnostics
|
||||
copyright:
|
||||
- license: Apache-2.0
|
||||
attestation: "SecureBuild (https://securebuild.com)"
|
||||
dependencies:
|
||||
runtime:
|
||||
- ${{package.name}}-support-bundle=${{package.full-version}}
|
||||
- ${{package.name}}-preflight=${{package.full-version}}
|
||||
- ${{package.name}}-collect=${{package.full-version}}
|
||||
provides:
|
||||
- troubleshoot=${{package.full-version}}
|
||||
|
||||
var-transforms:
|
||||
- from: ${{package.version}}
|
||||
match: ^(\d+\.\d+)\.\d+$
|
||||
replace: "$1"
|
||||
to: major-minor-version
|
||||
|
||||
environment:
|
||||
contents:
|
||||
repositories:
|
||||
- https://apk.cve0.io
|
||||
keyring:
|
||||
- https://apk.cve0.io/key/cve0-signing.rsa.pub
|
||||
packages:
|
||||
- busybox
|
||||
- build-base
|
||||
- ca-certificates-bundle
|
||||
- go
|
||||
- git
|
||||
- bash
|
||||
environment:
|
||||
CGO_ENABLED: "0"
|
||||
GOPROXY: https://proxy.golang.org,direct
|
||||
GOSUMDB: sum.golang.org
|
||||
|
||||
pipeline:
|
||||
- uses: git-checkout
|
||||
with:
|
||||
repository: https://github.com/replicatedhq/troubleshoot
|
||||
tag: v${{package.version}}
|
||||
depth: 1
|
||||
|
||||
- name: Build troubleshoot binaries
|
||||
runs: |
|
||||
export PATH="/usr/bin:$PATH"
|
||||
export VERSION="v${{package.version}}"
|
||||
make -j bin/support-bundle bin/preflight bin/collect
|
||||
|
||||
subpackages:
|
||||
- name: ${{package.name}}-support-bundle
|
||||
description: Support bundle collector for Kubernetes cluster diagnostics
|
||||
dependencies:
|
||||
provides:
|
||||
- troubleshoot-support-bundle=${{package.full-version}}
|
||||
pipeline:
|
||||
- runs: |
|
||||
mkdir -p ${{targets.subpkgdir}}/usr/bin
|
||||
cp bin/support-bundle ${{targets.subpkgdir}}/usr/bin/support-bundle
|
||||
- uses: strip
|
||||
test:
|
||||
pipeline:
|
||||
- runs: /usr/bin/support-bundle --help
|
||||
|
||||
- name: ${{package.name}}-preflight
|
||||
description: Preflight checker for Kubernetes cluster requirements
|
||||
dependencies:
|
||||
provides:
|
||||
- troubleshoot-preflight=${{package.full-version}}
|
||||
pipeline:
|
||||
- runs: |
|
||||
mkdir -p ${{targets.subpkgdir}}/usr/bin
|
||||
cp bin/preflight ${{targets.subpkgdir}}/usr/bin/preflight
|
||||
- uses: strip
|
||||
test:
|
||||
pipeline:
|
||||
- runs: /usr/bin/preflight --help
|
||||
|
||||
- name: ${{package.name}}-collect
|
||||
description: Collector for Kubernetes cluster data
|
||||
dependencies:
|
||||
provides:
|
||||
- troubleshoot-collect=${{package.full-version}}
|
||||
pipeline:
|
||||
- runs: |
|
||||
mkdir -p ${{targets.subpkgdir}}/usr/bin
|
||||
cp bin/collect ${{targets.subpkgdir}}/usr/bin/collect
|
||||
- uses: strip
|
||||
test:
|
||||
pipeline:
|
||||
- runs: /usr/bin/collect --help
|
||||
|
||||
test:
|
||||
environment:
|
||||
contents:
|
||||
packages:
|
||||
- ${{package.name}}=${{package.full-version}}
|
||||
pipeline:
|
||||
- runs: |
|
||||
/usr/bin/support-bundle --help
|
||||
/usr/bin/preflight --help
|
||||
/usr/bin/collect --help
|
||||
Reference in New Issue
Block a user