Compare commits

...
157 Commits
Author SHA1 Message Date
Kris ColemanandClaude Opus 4.7 2192aecf40 fix(analyze/secret): guard nil deref when spec omits fail: outcome (#2053) (#2054)
* fix(analyze/secret): guard nil deref when spec omits fail: outcome (#2053)

When a Preflight spec defines only warn: and/or pass: outcomes and the
target Secret is missing, analyzeSecret dereferenced a nil failOutcome and
panicked. Reproduction from replicatedhq/troubleshoot#2053:

  outcomes:
    - warn:
        when: "notFound"
        message: "secret missing (warn)"
    - pass:
        message: "secret found"

This change:
- Collects fail, warn, and warn-when-notFound outcomes up front.
- Routes a missing secret (or missing key) through a single resolver:
  prefer warn(when=notFound), fall back to fail, then any warn,
  then synthesize a benign warn result. Never panics.
- Adds table-driven tests covering the three new shapes.

Same defect shape as #263 (imagePullSecret). The sibling analyzers
configmap.go and image.go have the same pattern but are out of scope
for this PR.

Refs: replicatedhq/troubleshoot#2053

* refactor(analyze/secret): drop warn handling per analyzer contract

Per review feedback (banjoh): the secret analyzer only supports fail
(not found) and pass (found) outcomes — `warn:` and `when:` are not
part of the analyzer's contract (https://troubleshoot.sh/docs/analyze/secrets).

Drop the warn / notFoundWarn branches added in the previous commit and
collapse the nil-fail fallback onto IsFail with a default message. The
core fix — guarding the nil deref at the previous secret.go:72 — stays
in place.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* refactor(analyze/secret): mirror image_pull_secret pattern; return nil when spec has neither outcome

Per banjoh review: collect failOutcome and passOutcome with non-nil
checks; when the spec contains neither, return nil and let the framework
surface the missing-outcome error rather than fabricating a result.

Structure now mirrors pkg/analyze/image_pull_secret.go: default to
IsFail with fail-outcome message (if set), flip to IsPass with
pass-outcome message when the secret/key check succeeds, fill default
messages at the end only when none were configured. Analyze() now
forwards a nil result through cleanly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(analyze/secret): assign outcome messages inside their own branch

Cursor bugbot caught: when the spec defined only a fail outcome and the
secret was found, the result showed IsPass=true with the fail outcome's
message. Pre-assigning the fail message at the top before flipping
IsPass meant the stale message leaked through whenever no pass outcome
was configured.

Move both message assignments into their respective branches so a pass
result never carries a fail message. Default messages still fill in
when no outcome is set on the active branch. Added a regression test
covering fail-only spec + secret found.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(analyze/secret): address Greptile P1s — combined outcome + empty configured messages

Two fixes flagged by review on #2054:

1. Combined pass outcome dropped: the outcome loop used 'else if' for pass, so a
   single outcome object containing both fail and pass silently dropped the pass.
   Capture fail and pass independently.

2. Empty configured messages overwritten: the default-message fallback fired
   whenever result.Message was empty, clobbering a configured outcome that
   intentionally has an empty message (e.g. URI-only). Track whether the matched
   branch had a configured outcome and only fall back to a default when none was
   supplied, preserving the configured message and URI verbatim.

Adds tests: combined fail+pass captured on both found/not-found paths, and
URI-only pass/fail outcomes preserved without default-message overwrite.

* fix(analyze/secret): drop fabricated default messages; error on missing outcome

Per maintainer review: analyzers do not fabricate default messages — an empty
outcome message is intentional (e.g. a URI-only outcome), so remove the default
message fallback and preserve the configured outcome verbatim. When a matched
branch has no configured outcome, the message stays empty.

Also address the missing-outcome case: when a spec defines neither a pass nor a
fail outcome, analyzeSecret returned (nil, nil), which the Analyze wrapper
swallowed into an empty result slice — the user saw neither a result nor a
config error. Return an explicit error so the framework surfaces the
misconfiguration.

Tests updated: the no-fail-outcome and only-fail-outcome cases now assert an
empty message rather than a fabricated one, and the neither-outcome case asserts
an error.

* fix(analyze/secret): default message only when no outcome is configured for the matched branch

Distinguish an absent matching outcome from an intentionally empty configured
message. A configured outcome with an empty message (e.g. a URI-only outcome) is
still preserved verbatim. But when the matched branch has no configured outcome at
all — a pass-only spec that took the fail path, or a fail-only spec that passed —
fall back to a default diagnostic instead of emitting an empty message.

Addresses the greptile P1 (endorsed by banjoh): dropping the default entirely
conflated the two cases and left users with a pass/fail result and no context.
Tests restore the default-message expectations for the no-configured-outcome
branches; URI-only (configured-empty) and neither-outcome (error) cases unchanged.

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-08-24 12:16:33 -04:00
Dmitriy Ivolgin 5bf008f7d2 Use all tags when building with securebuild (#2119) 2026-08-21 11:27:04 -07:00
Xav PaiceandElasticClaw Factory 0c6fb2177b fix(cluster-resources): stop emitting duplicate unredacted YAML copy (#2117)
* fix(cluster-resources): stop emitting duplicate unredacted YAML copy

storeCustomResource was writing both a JSON and a YAML file for every
custom resource. The built-in redactors are authored for JSON, so the
YAML copy was left unredacted. JSON is valid YAML, so analyzers that
expect YAML can still parse the JSON file.

Also convert the built-in kurl installer redactors from YAML-specific
paths to scoped JSON regex redactors so they continue to apply after the
YAML copy is removed.

* fix(cluster-resources): add YAML symlinks and cover cluster-scoped kurl installer

- Add a .yaml symlink for every custom-resource JSON file so existing
  analyzers that look for the old YAML copy keep working. The symlink
  points at the JSON file, so redaction of the JSON also redacts the YAML
  view.
- Fix the built-in kurl installer redactor to match both the cluster-scoped
  file (installers.cluster.kurl.sh.json) and the namespaced file pattern
  (installers.cluster.kurl.sh/*.json). The previous selector only matched
  the namespaced form.

---------

Co-authored-by: ElasticClaw Factory <factory@replicated.com>
2026-08-21 09:29:20 +12:00
replicated-software-factory[bot]andElasticClaw Factory bea9c2220d [deps] Dependency update: troubleshoot (#2112)
deps: update Go dependencies

- github.com/miekg/dns v1.1.72 => v1.1.73
- github.com/stretchr/testify v1.11.1 => v1.12.1
- github.com/stretchr/objx v0.5.2 => v0.5.3 (indirect)

Co-authored-by: ElasticClaw Factory <factory@replicated.com>
2026-08-20 13:16:18 +12:00
Xav PaiceandElasticClaw Factory 207cb90b53 feat(supportbundle): support secret/... redactor URIs (#2111)
Co-authored-by: ElasticClaw Factory <factory@replicated.com>
2026-08-20 08:40:11 +12:00
Dmitriy Ivolgin 0bb4a21f22 Remove dockerfile based release (#2115) 2026-08-19 12:07:36 -07:00
Dmitriy Ivolgin fb82fef6e0 Add securebuild release jobs (#2114) 2026-08-19 09:38:49 -07:00
Dmitriy Ivolgin 3f3906fea1 Use latest go 1.26 in release (#2113) 2026-08-19 08:33:17 -07:00
Dmitriy Ivolgin 1f1a21b3cf Fix SBOM generation (#2109) 2026-08-17 12:48:56 -07:00
Dmitriy Ivolgin e828c21545 Generate and sign SBOM (#2108) 2026-08-17 11:26:40 -07:00
replicated-software-factory[bot]andlnx01 b158f7d79f [deps] Dependency update: troubleshoot (#2107)
chore(deps): update go dependencies for troubleshoot

- helm.sh/helm/v3 v3.21.3 => v3.21.4
- github.com/aws/aws-sdk-go-v2 v1.43.5 => v1.43.6
- github.com/aws/aws-sdk-go-v2/credentials v1.19.35 => v1.19.36
- github.com/aws/aws-sdk-go-v2/service/s3 v1.107.1 => v1.107.2
- golang.org/x/mod v0.39.0 => v0.40.0
- golang.org/x/tools v0.48.0 => v0.49.0 (via tidy)
- golang.org/x/crypto v0.54.0 => v0.55.0 (sdk example)
- golang.org/x/net v0.57.0 => v0.58.0 (sdk example)
- golang.org/x/text v0.40.0 => v0.41.0 (sdk example)

Co-authored-by: replicated-software-factory[bot] <282391587+replicated-software-factory[bot]@users.noreply.github.com>
2026-08-17 08:42:30 +12:00
replicated-software-factory[bot]andDependency Update Bot 8be420c42e [deps] Dependency update: troubleshoot (#2106)
chore(deps): update go dependencies

Co-authored-by: Dependency Update Bot <deps@replicated.com>
2026-08-14 09:46:11 +12:00
Xav Paice 0e2e0cd0ab fix(runpod): strip pod spec before saving collected output (#2105) 2026-08-12 09:13:40 +12:00
Xav Paice 651ec1bfdb ci: remove unmaintained upgrade-go workflow (#2104) 2026-08-11 06:56:48 +12:00
Xav Paice b9faedfdb0 fix(preflight): add tracing span and align error handling for host collector redaction (#2102)
* fix(preflight): add tracing span and align error handling for host collector redaction

Follow-up to #2101.

Adds an OpenTelemetry span around host collector redaction and returns the
unredacted collectResult on redaction failure, matching the behavior of
remote host collectors and in-cluster support-bundle collectors.

* fix(preflight): assign collected data before redaction so errors preserve output
2026-08-10 16:17:10 +01:00
3db6a99d3a feat(analyze): add countDistinct() aggregate to nodeResources (#2079)
Add a countDistinct(<labelKey>) aggregate to the nodeResources analyzer
"when" expression language. It counts distinct values of a node label
across the filtered nodes and returns an int the existing comparison
operators evaluate.

Enables the AIR-238 3-AZ preflight: warn when Keeper-eligible nodes do
not span 3 availability zones, e.g.
"countDistinct(topology.kubernetes.io/zone) < 3".

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Xav Paice <xavpaice@users.noreply.github.com>
2026-08-10 12:54:33 +12:00
Benjamin Reed 3c5bf74750 fix(preflight): redact local host preflight collector output (#2101)
CollectHostWithContext was the only collection path (in-cluster support
bundle, remote/SSH host collectors) that never ran collected data through
the redaction engine. A `run` collector's captured environment in
particular can carry credentials verbatim -- e.g. HTTPS_PROXY with
embedded Basic Auth -- straight into the bundle's <collectorName>-info.json
with no redaction applied.

Wire it through collect.RedactResult the same way CollectRemoteWithContext
and pkg/supportbundle/collect.go already do, so the built-in default
redactors apply to local host preflight output too.

Fixes #2100
2026-08-10 12:09:22 +12:00
95a4a81bce [deps] Dependency update: troubleshoot (#2096)
* chore(deps): update Go dependencies for 2026-08-05

Updates:

- github.com/ClickHouse/clickhouse-go/v2 v2.47.0 -> v2.48.0

- github.com/aws/aws-sdk-go-v2/service/s3 v1.106.3 -> v1.106.4

- go.opentelemetry.io/otel v1.44.0 -> v1.45.0

- go.opentelemetry.io/otel/sdk v1.44.0 -> v1.45.0

* chore(deps): update Go dependencies for 2026-08-07

---------

Co-authored-by: ElasticClaw <elasticclaw@replicated.com>
Co-authored-by: OpenClaw Bot <elasticclaw@openclaw.ai>
2026-08-09 11:28:54 +12:00
replicated-software-factory[bot]andReplicated Developer 5767e9b516 chore(deps): update Go dependencies for 2026-08-02 (#2093)
Updates top-level go.mod/go.sum with latest patch-level dependency
releases. Also refreshes examples/sdk/helm-template go.mod/go.sum
while preserving the local replace directive for troubleshoot.

Validated with:
- make build
- make test
- go build ./... in examples/sdk/helm-template

Co-authored-by: Replicated Developer <dev@replicated.com>
2026-08-03 18:28:31 +12:00
replicated-software-factory[bot]andElasticClaw 102843b433 chore(deps): update Go dependencies (#2091)
* chore(deps): update Go dependencies for top-level and helm-template example

* ci: re-trigger preflight e2e after timeout

* ci: add compile-preflight dependency for validate-supportbundle-e2e-go

---------

Co-authored-by: ElasticClaw <elasticclaw@replicated.com>
2026-07-31 16:43:46 +12:00
dependabot[bot]andlnx01 5f09d49e12 chore(deps): bump github.com/go-logr/logr from 1.4.3 to 1.4.4 in the security group across 1 directory (#2087)
chore(deps): bump github.com/go-logr/logr

Bumps the security group with 1 update in the / directory: [github.com/go-logr/logr](https://github.com/go-logr/logr).


Updates `github.com/go-logr/logr` from 1.4.3 to 1.4.4
- [Release notes](https://github.com/go-logr/logr/releases)
- [Changelog](https://github.com/go-logr/logr/blob/master/CHANGELOG.md)
- [Commits](https://github.com/go-logr/logr/compare/v1.4.3...v1.4.4)

---
updated-dependencies:
- dependency-name: github.com/go-logr/logr
  dependency-version: 1.4.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-25 15:15:11 +12:00
replicated-software-factory[bot]andTroubleshoot Dependency Bot 28d098815b build(deps): automated Go dependency update (#2084)
build(deps): bump github.com/longhorn/go-common-libs

Co-authored-by: Troubleshoot Dependency Bot <troubleshoot-bot@replicated.com>
2026-07-21 16:50:32 +12:00
dependabot[bot]andlnx01 55479d963a chore(deps): bump actions/setup-python from 6 to 7 (#2085)
Bumps [actions/setup-python](https://github.com/actions/setup-python) from 6 to 7.
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](https://github.com/actions/setup-python/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/setup-python
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-21 16:50:05 +12:00
dependabot[bot]andlnx01 a75c227625 chore(deps): bump actions/setup-go from 6 to 7 (#2086)
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 6 to 7.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](https://github.com/actions/setup-go/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-21 16:49:41 +12:00
Xav Paice 80845c8733 Xp/factory update (#2072)
* Revert "use CLI rather than action for factory workflow push (#2067)"

This reverts commit 65bd747c50.

* enable Github action for workflow updates

* update workflow
2026-07-21 11:34:18 +12:00
replicated-software-factory[bot]andElasticClaw Bot 46cb1b2206 chore: bump Go dependencies (#2083)
Grouped patch/minor updates from go get -u ./... and go mod tidy:
- github.com/aws/aws-sdk-go-v2/service/s3 v1.105.1 => v1.105.2
- github.com/aws/smithy-go v1.27.3 => v1.27.4
- github.com/docker/cli v29.6.1 => v29.6.2
- github.com/longhorn/go-common-libs v0.0.0-20260712050051 => v0.0.0-20260716070930
- github.com/mattn/go-isatty v0.0.22 => v0.0.23
- google.golang.org/api v0.288.0 => v0.289.0

examples/sdk/helm-template had no net changes (local replace preserved).

Co-authored-by: ElasticClaw Bot <elasticclaw@openclaw.ai>
2026-07-17 16:03:59 +12:00
replicated-software-factory[bot]andTroubleshoot Bot f81e4fae5a chore(deps): grouped Go dependency updates (#2082)
chore(deps): bump Go dependencies

Bumps indirect Google Cloud/GRPC dependencies to latest patch versions:
- google.golang.org/grpc v1.82.0 => v1.82.1
- google.golang.org/genproto v0.0.0-20260713224248-f5fc221cf8c4 => v0.0.0-20260715232425-e75dac1f907d
- google.golang.org/genproto/googleapis/api v0.0.0-20260713224248-f5fc221cf8c4 => v0.0.0-20260715232425-e75dac1f907d
- google.golang.org/genproto/googleapis/rpc v0.0.0-20260713224248-f5fc221cf8c4 => v0.0.0-20260715232425-e75dac1f907d
- cloud.google.com/go/logging v1.18.0 => v1.19.0

Validated with:
- make build
- make test

Co-authored-by: Troubleshoot Bot <troubleshoot-bot@replicated.com>
2026-07-16 15:20:45 +12:00
replicated-software-factory[bot]andElasticClaw b0c4a23a56 chore(deps): update Go dependencies for top-level and helm-template example (#2081)
Updates indirect deps pulled in via the top-level go.mod (notably Google
Cloud, AWS, Sentry, and genproto modules) and refreshes the corresponding
helm-template example sums. Verified with make build and make test.

Co-authored-by: ElasticClaw <elasticclaw@openclaw.ai>
2026-07-15 20:12:21 +12:00
dependabot[bot]andlnx01 bce58cfe56 chore(deps): bump the security group across 1 directory with 2 updates (#2078)
Bumps the security group with 2 updates in the / directory: [github.com/aws/aws-sdk-go-v2/credentials](https://github.com/aws/aws-sdk-go-v2) and [github.com/aws/aws-sdk-go-v2/service/s3](https://github.com/aws/aws-sdk-go-v2).


Updates `github.com/aws/aws-sdk-go-v2/credentials` from 1.19.28 to 1.19.29
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/credentials/v1.19.28...credentials/v1.19.29)

Updates `github.com/aws/aws-sdk-go-v2/service/s3` from 1.105.0 to 1.105.1
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/service/s3/v1.105.0...service/s3/v1.105.1)

---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go-v2/credentials
  dependency-version: 1.19.29
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: github.com/aws/aws-sdk-go-v2/service/s3
  dependency-version: 1.105.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-14 17:12:47 +12:00
dependabot[bot]andlnx01 10a2a82d32 chore(deps): bump actions/checkout from 4 to 7 (#2075)
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 7.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4...v7)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-14 13:13:15 +12:00
replicated-software-factory[bot]andElasticClaw Bot 7fa4497b7f chore: update Go dependencies (#2074)
- github.com/longhorn/go-iscsi-helper: replaced by github.com/longhorn/go-common-libs
  and migrated pkg/longhorn/util/iscsi.go to the new namespace executor API
- helm.sh/helm/v3: v3.21.2 -> v3.21.3
- oras.land/oras-go/v2: v2.6.1 -> v2.6.2
- google.golang.org/api: v0.287.1 -> v0.288.0
- golang.org/x/tools: v0.47.0 -> v0.48.0
- github.com/GoogleCloudPlatform/opentelemetry-operations-go/*: v1.33.0/v0.57.0 -> v1.34.0/v0.58.0
- examples/sdk/helm-template: helm.sh/helm/v3 v3.21.2 -> v3.21.3

Fixes required by the update environment:
- Makefile: use $(shell go env GOPATH)/bin for controller-gen/client-gen so
  generate works when the tools are not on PATH
- pkg/collect/host_kernel_configs.go: only use /proc/config.gz when the
  requested kernel release matches the running kernel, making the collector
  robust to hosts that expose a generic /proc/config.gz

Co-authored-by: ElasticClaw Bot <elasticclaw@openclaw.ai>
2026-07-14 13:12:51 +12:00
Xav Paice b279b2bef9 chore: update Go to 1.26.5 (#2073) 2026-07-11 11:12:50 +12:00
replicated-software-factory[bot]andReplicated Dev 3c59305677 chore: update Go dependencies (#2070)
Updates:
- github.com/aws/aws-sdk-go-v2/credentials v1.19.27 => v1.19.28
- github.com/aws/aws-sdk-go-v2/config v1.32.28 => v1.32.29
- github.com/aws/aws-sdk-go-v2/service/signin v1.3.0 => v1.4.0
- golang.org/x/net v0.56.0 => v0.57.0
- examples/sdk/helm-template: various indirect dependency updates

Co-authored-by: Replicated Dev <dev@replicated.com>
2026-07-11 09:48:51 +12:00
Salah Al Saleh 2a87b280bf Add per-collector subcommands to the collect binary (#2071)
* Add per-collector subcommands to the collect binary

Add `collect http|postgres|mysql|mssql|redis` subcommands that run a single
collector and print its native result JSON to stdout, so a collector can run
inside a Pod via the troubleshoot image (e.g. as a runPod collector).

Each has its own flags mapping to the collector's spec fields and its own help.
The Kubernetes client (used only for TLS-from-Secret) is built to match the
production preflight/support-bundle path (QPS/Burst/UserAgent).

* Add clickhouse subcommand to the collect binary

Add `collect clickhouse`, matching the other per-collector subcommands, so the
clickhouse collector can run inside a Pod via the troubleshoot image (e.g. as a
runPod collector). Same flags as the other database collectors (--uri + --tls-*).

* Make global flags work on the collect subcommands

Register --debug and the Kubernetes flags (--kubeconfig, --context, etc.) as
persistent flags, and move the shared setup to PersistentPreRun/PersistentPostRun,
so the per-collector subcommands inherit the global flags and run the same
logger/profiling setup as `collect [url]`. Previously these were local flags with
setup in PreRun, so subcommands rejected --debug/--kubeconfig and ignored the setup.
2026-07-10 09:31:14 -07:00
replicated-software-factory[bot]andTroubleshoot Bot 5e6f3cdac1 chore: update Go dependencies (#2068)
Updated Go dependencies to latest patch/minor versions:
- cloud.google.com/go/auth v0.20.0 -> v0.21.0
- cloud.google.com/go/iam v1.5.3 -> v1.11.0
- cloud.google.com/go/monitoring v1.24.3 -> v1.29.0
- cloud.google.com/go/storage v1.61.3 -> v1.63.0
- github.com/andybalholm/brotli v1.2.1 -> v1.2.2
- github.com/aws/aws-sdk-go-v2/config v1.32.17 -> v1.32.28
- github.com/chai2010/gettext-go v1.0.2 -> v1.0.3
- github.com/cyphar/filepath-securejoin v0.6.1 -> v0.7.0
- github.com/docker/cli v29.5.3 -> v29.6.1
- github.com/fxamacker/cbor/v2 v2.9.0 -> v2.9.2
- github.com/go-viper/mapstructure/v2 v2.4.0 -> v2.5.0
- github.com/google/gnostic-models v0.7.0 -> v0.7.1
- github.com/googleapis/enterprise-certificate-proxy v0.3.16 -> v0.3.18
- github.com/hashicorp/aws-sdk-go-base/v2 v2.0.0-beta.72 -> v2.0.0-beta.73
- github.com/lufia/plan9stats v0.0.0-20260330125221 -> v0.0.0-20260627054121
- github.com/pelletier/go-toml/v2 v2.2.4 -> v2.4.3
- github.com/sagikazarmark/locafero v0.11.0 -> v0.12.0
- github.com/spiffe/go-spiffe/v2 v2.6.0 -> v2.8.1
- go.opentelemetry.io/contrib/detectors/gcp v1.42.0 -> v1.44.0
- go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.67.0 -> v0.69.0
- golang.org/x/crypto v0.53.0 -> v0.54.0
- golang.org/x/mod v0.37.0 -> v0.38.0
- golang.org/x/sync v0.21.0 -> v0.22.0
- golang.org/x/sys v0.46.0 -> v0.47.0
- golang.org/x/term v0.44.0 -> v0.45.0
- golang.org/x/text v0.39.0 -> v0.40.0
- google.golang.org/api v0.283.0 -> v0.287.1
- google.golang.org/genproto/googleapis/api v0.0.0-20260401024825 -> v0.0.0-20260706201446
- google.golang.org/genproto/googleapis/rpc v0.0.0-20260523011958 -> v0.0.0-20260706201446
- google.golang.org/grpc v1.81.1 -> v1.82.0
- k8s.io/kube-openapi v0.0.0-20260317180543 -> v0.0.0-20260706235625
- k8s.io/utils v0.0.0-20260210185600 -> v0.0.0-20260707023825
- sigs.k8s.io/structured-merge-diff/v6 v6.3.2 -> v6.4.2

Note: github.com/longhorn/go-iscsi-helper was kept at v0.0.0-20210330030558-49a327fb024e
due to breaking API changes in newer versions.

Build and tests pass successfully.

Co-authored-by: Troubleshoot Bot <troubleshoot-bot@replicated.com>
2026-07-09 09:36:56 +12:00
Xav Paice 65bd747c50 use CLI rather than action for factory workflow push (#2067)
* use CLI rather than action for factory workflow push

* update elasticclaw version

* replace inline elasticclaw token with env var
2026-07-09 07:45:29 +12:00
Xav Paice e0e45b0dc3 add factory workflow (#2066)
* add factory workflow

* add publish workflow for factory

* reduce duplication
2026-07-08 14:37:48 +12:00
dependabot[bot]andlnx01 eed103b6a5 chore(deps): bump the security group across 1 directory with 10 updates (#2065)
Bumps the security group with 10 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [github.com/ClickHouse/clickhouse-go/v2](https://github.com/ClickHouse/clickhouse-go) | `2.46.0` | `2.47.0` |
| [github.com/aws/aws-sdk-go-v2](https://github.com/aws/aws-sdk-go-v2) | `1.42.0` | `1.42.1` |
| [github.com/aws/aws-sdk-go-v2/credentials](https://github.com/aws/aws-sdk-go-v2) | `1.19.24` | `1.19.27` |
| [github.com/aws/aws-sdk-go-v2/service/s3](https://github.com/aws/aws-sdk-go-v2) | `1.103.3` | `1.105.0` |
| [github.com/cilium/ebpf](https://github.com/cilium/ebpf) | `0.21.0` | `0.22.0` |
| [github.com/google/go-containerregistry](https://github.com/google/go-containerregistry) | `0.21.6` | `0.21.7` |
| [github.com/shirou/gopsutil/v4](https://github.com/shirou/gopsutil) | `4.26.5` | `4.26.6` |
| [github.com/vmware-tanzu/velero](https://github.com/vmware-tanzu/velero) | `1.18.1` | `1.18.2` |
| [golang.org/x/text](https://github.com/golang/text) | `0.38.0` | `0.39.0` |
| [helm.sh/helm/v3](https://github.com/helm/helm) | `3.21.1` | `3.21.2` |



Updates `github.com/ClickHouse/clickhouse-go/v2` from 2.46.0 to 2.47.0
- [Release notes](https://github.com/ClickHouse/clickhouse-go/releases)
- [Changelog](https://github.com/ClickHouse/clickhouse-go/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ClickHouse/clickhouse-go/compare/v2.46.0...v2.47.0)

Updates `github.com/aws/aws-sdk-go-v2` from 1.42.0 to 1.42.1
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/v1.42.0...v1.42.1)

Updates `github.com/aws/aws-sdk-go-v2/credentials` from 1.19.24 to 1.19.27
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/credentials/v1.19.24...credentials/v1.19.27)

Updates `github.com/aws/aws-sdk-go-v2/service/s3` from 1.103.3 to 1.105.0
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/service/s3/v1.103.3...service/s3/v1.105.0)

Updates `github.com/cilium/ebpf` from 0.21.0 to 0.22.0
- [Release notes](https://github.com/cilium/ebpf/releases)
- [Commits](https://github.com/cilium/ebpf/compare/v0.21.0...v0.22.0)

Updates `github.com/google/go-containerregistry` from 0.21.6 to 0.21.7
- [Release notes](https://github.com/google/go-containerregistry/releases)
- [Commits](https://github.com/google/go-containerregistry/compare/v0.21.6...v0.21.7)

Updates `github.com/shirou/gopsutil/v4` from 4.26.5 to 4.26.6
- [Release notes](https://github.com/shirou/gopsutil/releases)
- [Commits](https://github.com/shirou/gopsutil/compare/v4.26.5...v4.26.6)

Updates `github.com/vmware-tanzu/velero` from 1.18.1 to 1.18.2
- [Release notes](https://github.com/vmware-tanzu/velero/releases)
- [Changelog](https://github.com/velero-io/velero/blob/main/CHANGELOG.md)
- [Commits](https://github.com/vmware-tanzu/velero/compare/v1.18.1...v1.18.2)

Updates `golang.org/x/text` from 0.38.0 to 0.39.0
- [Release notes](https://github.com/golang/text/releases)
- [Commits](https://github.com/golang/text/compare/v0.38.0...v0.39.0)

Updates `helm.sh/helm/v3` from 3.21.1 to 3.21.2
- [Release notes](https://github.com/helm/helm/releases)
- [Commits](https://github.com/helm/helm/compare/v3.21.1...v3.21.2)

---
updated-dependencies:
- dependency-name: github.com/ClickHouse/clickhouse-go/v2
  dependency-version: 2.47.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: github.com/aws/aws-sdk-go-v2
  dependency-version: 1.42.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: github.com/aws/aws-sdk-go-v2/credentials
  dependency-version: 1.19.27
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: github.com/aws/aws-sdk-go-v2/service/s3
  dependency-version: 1.105.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: github.com/cilium/ebpf
  dependency-version: 0.22.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: github.com/google/go-containerregistry
  dependency-version: 0.21.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: github.com/shirou/gopsutil/v4
  dependency-version: 4.26.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: github.com/vmware-tanzu/velero
  dependency-version: 1.18.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: golang.org/x/text
  dependency-version: 0.39.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: helm.sh/helm/v3
  dependency-version: 3.21.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-07 13:56:55 +12:00
dependabot[bot]andlnx01 d0c73d4723 chore(deps): bump actions/checkout from 6 to 7 (#2062)
Bumps [actions/checkout](https://github.com/actions/checkout) from 6 to 7.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-30 08:36:41 +12:00
dependabot[bot]andlnx01 19e7c9b9c8 chore(deps): bump helm.sh/helm/v3 from 3.21.0 to 3.21.2 in /examples/sdk/helm-template in the security group across 1 directory (#2059)
chore(deps): bump helm.sh/helm/v3

Bumps the security group with 1 update in the /examples/sdk/helm-template directory: [helm.sh/helm/v3](https://github.com/helm/helm).


Updates `helm.sh/helm/v3` from 3.21.0 to 3.21.2
- [Release notes](https://github.com/helm/helm/releases)
- [Commits](https://github.com/helm/helm/compare/v3.21.0...v3.21.2)

---
updated-dependencies:
- dependency-name: helm.sh/helm/v3
  dependency-version: 3.21.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-30 08:36:12 +12:00
dependabot[bot]andlnx01 0edd588c3e chore(deps): bump github.com/containerd/containerd from 1.7.32 to 1.7.33 (#2061)
Bumps [github.com/containerd/containerd](https://github.com/containerd/containerd) from 1.7.32 to 1.7.33.
- [Release notes](https://github.com/containerd/containerd/releases)
- [Changelog](https://github.com/containerd/containerd/blob/main/RELEASES.md)
- [Commits](https://github.com/containerd/containerd/compare/v1.7.32...v1.7.33)

---
updated-dependencies:
- dependency-name: github.com/containerd/containerd
  dependency-version: 1.7.33
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-23 09:10:09 +12:00
dependabot[bot]andlnx01 78ac8f7dc9 chore(deps): bump the security group across 1 directory with 19 updates (#2060)
Bumps the security group with 13 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [github.com/aws/aws-sdk-go-v2](https://github.com/aws/aws-sdk-go-v2) | `1.41.11` | `1.42.0` |
| [github.com/aws/aws-sdk-go-v2/credentials](https://github.com/aws/aws-sdk-go-v2) | `1.19.21` | `1.19.24` |
| [github.com/aws/aws-sdk-go-v2/service/s3](https://github.com/aws/aws-sdk-go-v2) | `1.103.1` | `1.103.3` |
| [golang.org/x/mod](https://github.com/golang/mod) | `0.36.0` | `0.37.0` |
| [golang.org/x/sync](https://github.com/golang/sync) | `0.20.0` | `0.21.0` |
| [k8s.io/api](https://github.com/kubernetes/api) | `0.36.1` | `0.36.2` |
| [k8s.io/apiextensions-apiserver](https://github.com/kubernetes/apiextensions-apiserver) | `0.36.1` | `0.36.2` |
| [k8s.io/cli-runtime](https://github.com/kubernetes/cli-runtime) | `0.36.1` | `0.36.2` |
| [oras.land/oras-go/v2](https://github.com/oras-project/oras-go) | `2.6.0` | `2.6.1` |
| [golang.org/x/net](https://github.com/golang/net) | `0.55.0` | `0.56.0` |
| [helm.sh/helm/v3](https://github.com/helm/helm) | `3.21.0` | `3.21.1` |
| [k8s.io/kubelet](https://github.com/kubernetes/kubelet) | `0.36.1` | `0.36.2` |
| [k8s.io/metrics](https://github.com/kubernetes/metrics) | `0.36.1` | `0.36.2` |



Updates `github.com/aws/aws-sdk-go-v2` from 1.41.11 to 1.42.0
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/v1.41.11...v1.42.0)

Updates `github.com/aws/aws-sdk-go-v2/credentials` from 1.19.21 to 1.19.24
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/credentials/v1.19.21...credentials/v1.19.24)

Updates `github.com/aws/aws-sdk-go-v2/service/s3` from 1.103.1 to 1.103.3
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/service/s3/v1.103.1...service/s3/v1.103.3)

Updates `golang.org/x/mod` from 0.36.0 to 0.37.0
- [Commits](https://github.com/golang/mod/compare/v0.36.0...v0.37.0)

Updates `golang.org/x/sync` from 0.20.0 to 0.21.0
- [Commits](https://github.com/golang/sync/compare/v0.20.0...v0.21.0)

Updates `k8s.io/api` from 0.36.1 to 0.36.2
- [Commits](https://github.com/kubernetes/api/compare/v0.36.1...v0.36.2)

Updates `k8s.io/apiextensions-apiserver` from 0.36.1 to 0.36.2
- [Release notes](https://github.com/kubernetes/apiextensions-apiserver/releases)
- [Commits](https://github.com/kubernetes/apiextensions-apiserver/compare/v0.36.1...v0.36.2)

Updates `k8s.io/apimachinery` from 0.36.1 to 0.36.2
- [Commits](https://github.com/kubernetes/apimachinery/compare/v0.36.1...v0.36.2)

Updates `k8s.io/apiserver` from 0.36.1 to 0.36.2
- [Commits](https://github.com/kubernetes/apiserver/compare/v0.36.1...v0.36.2)

Updates `k8s.io/cli-runtime` from 0.36.1 to 0.36.2
- [Commits](https://github.com/kubernetes/cli-runtime/compare/v0.36.1...v0.36.2)

Updates `k8s.io/client-go` from 0.36.1 to 0.36.2
- [Changelog](https://github.com/kubernetes/client-go/blob/master/CHANGELOG.md)
- [Commits](https://github.com/kubernetes/client-go/compare/v0.36.1...v0.36.2)

Updates `k8s.io/streaming` from 0.36.1 to 0.36.2
- [Commits](https://github.com/kubernetes/streaming/compare/v0.36.1...v0.36.2)

Updates `oras.land/oras-go/v2` from 2.6.0 to 2.6.1
- [Release notes](https://github.com/oras-project/oras-go/releases)
- [Commits](https://github.com/oras-project/oras-go/compare/v2.6.0...v2.6.1)

Updates `golang.org/x/net` from 0.55.0 to 0.56.0
- [Commits](https://github.com/golang/net/compare/v0.55.0...v0.56.0)

Updates `golang.org/x/sys` from 0.45.0 to 0.46.0
- [Commits](https://github.com/golang/sys/compare/v0.45.0...v0.46.0)

Updates `golang.org/x/text` from 0.37.0 to 0.38.0
- [Release notes](https://github.com/golang/text/releases)
- [Commits](https://github.com/golang/text/compare/v0.37.0...v0.38.0)

Updates `helm.sh/helm/v3` from 3.21.0 to 3.21.1
- [Release notes](https://github.com/helm/helm/releases)
- [Commits](https://github.com/helm/helm/compare/v3.21.0...v3.21.1)

Updates `k8s.io/kubelet` from 0.36.1 to 0.36.2
- [Commits](https://github.com/kubernetes/kubelet/compare/v0.36.1...v0.36.2)

Updates `k8s.io/metrics` from 0.36.1 to 0.36.2
- [Commits](https://github.com/kubernetes/metrics/compare/v0.36.1...v0.36.2)

---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go-v2
  dependency-version: 1.42.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: github.com/aws/aws-sdk-go-v2/credentials
  dependency-version: 1.19.24
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: github.com/aws/aws-sdk-go-v2/service/s3
  dependency-version: 1.103.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: golang.org/x/mod
  dependency-version: 0.37.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: golang.org/x/sync
  dependency-version: 0.21.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: k8s.io/api
  dependency-version: 0.36.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: k8s.io/apiextensions-apiserver
  dependency-version: 0.36.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: k8s.io/apimachinery
  dependency-version: 0.36.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: k8s.io/apiserver
  dependency-version: 0.36.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: k8s.io/cli-runtime
  dependency-version: 0.36.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: k8s.io/client-go
  dependency-version: 0.36.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: k8s.io/streaming
  dependency-version: 0.36.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: oras.land/oras-go/v2
  dependency-version: 2.6.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: golang.org/x/net
  dependency-version: 0.56.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: golang.org/x/sys
  dependency-version: 0.46.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: golang.org/x/text
  dependency-version: 0.38.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: helm.sh/helm/v3
  dependency-version: 3.21.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: k8s.io/kubelet
  dependency-version: 0.36.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: k8s.io/metrics
  dependency-version: 0.36.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-22 09:34:12 +12:00
Kris Coleman 22ab3cf551 feat(redact): make MAX_CONCURRENT_REDACTORS configurable via env var (sc-138321) (#2057)
Replace the hardcoded MAX_CONCURRENT_REDACTORS = 10 ceiling in
pkg/collect/redact.go with a runtime-resolved value driven by the
TROUBLESHOOT_MAX_CONCURRENT_REDACTORS env var. The default (10) is
unchanged, so behavior is identical unless an operator opts in.

- DefaultMaxConcurrentRedactors exported as the default
- MaxConcurrentRedactorsEnvVar exported as the env var name
- maxConcurrentRedactors() helper parses the env, logs on invalid input,
  and falls back to the default on missing/empty/non-numeric/<=0 values
- Table-driven tests in pkg/collect/redact_test.go cover unset, empty,
  positive override, default-equal, zero, negative, non-numeric, and
  whitespace-padded inputs

Unblocks Pixee's standalone support-bundle pipeline, which hits the
10-concurrent ceiling on large bundles.

Refs: sc-138321, replicated-collab/pixee-replicated#131
2026-06-10 16:07:27 -04:00
replicated-ciandlnx01 dcfddc78da Bump Go from 1.26.3 to 1.26.4 (#2055)
Bump Go to version from 1.26.3 to 1.26.4

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-08 16:38:50 +01:00
dependabot[bot]andlnx01 aad5f6ef06 chore(deps): bump the security group with 7 updates (#2052)
Bumps the security group with 7 updates:

| Package | From | To |
| --- | --- | --- |
| [github.com/aws/aws-sdk-go-v2](https://github.com/aws/aws-sdk-go-v2) | `1.41.7` | `1.41.11` |
| [github.com/aws/aws-sdk-go-v2/credentials](https://github.com/aws/aws-sdk-go-v2) | `1.19.17` | `1.19.21` |
| [github.com/aws/aws-sdk-go-v2/service/s3](https://github.com/aws/aws-sdk-go-v2) | `1.101.0` | `1.103.1` |
| [github.com/jackc/pgx/v5](https://github.com/jackc/pgx) | `5.9.2` | `5.10.0` |
| [github.com/shirou/gopsutil/v4](https://github.com/shirou/gopsutil) | `4.26.4` | `4.26.5` |
| [go.opentelemetry.io/otel](https://github.com/open-telemetry/opentelemetry-go) | `1.43.0` | `1.44.0` |
| [go.opentelemetry.io/otel/sdk](https://github.com/open-telemetry/opentelemetry-go) | `1.43.0` | `1.44.0` |


Updates `github.com/aws/aws-sdk-go-v2` from 1.41.7 to 1.41.11
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/v1.41.7...v1.41.11)

Updates `github.com/aws/aws-sdk-go-v2/credentials` from 1.19.17 to 1.19.21
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/credentials/v1.19.17...credentials/v1.19.21)

Updates `github.com/aws/aws-sdk-go-v2/service/s3` from 1.101.0 to 1.103.1
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/service/s3/v1.101.0...service/s3/v1.103.1)

Updates `github.com/jackc/pgx/v5` from 5.9.2 to 5.10.0
- [Changelog](https://github.com/jackc/pgx/blob/master/CHANGELOG.md)
- [Commits](https://github.com/jackc/pgx/compare/v5.9.2...v5.10.0)

Updates `github.com/shirou/gopsutil/v4` from 4.26.4 to 4.26.5
- [Release notes](https://github.com/shirou/gopsutil/releases)
- [Commits](https://github.com/shirou/gopsutil/compare/v4.26.4...v4.26.5)

Updates `go.opentelemetry.io/otel` from 1.43.0 to 1.44.0
- [Release notes](https://github.com/open-telemetry/opentelemetry-go/releases)
- [Changelog](https://github.com/open-telemetry/opentelemetry-go/blob/main/CHANGELOG.md)
- [Commits](https://github.com/open-telemetry/opentelemetry-go/compare/v1.43.0...v1.44.0)

Updates `go.opentelemetry.io/otel/sdk` from 1.43.0 to 1.44.0
- [Release notes](https://github.com/open-telemetry/opentelemetry-go/releases)
- [Changelog](https://github.com/open-telemetry/opentelemetry-go/blob/main/CHANGELOG.md)
- [Commits](https://github.com/open-telemetry/opentelemetry-go/compare/v1.43.0...v1.44.0)

---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go-v2
  dependency-version: 1.41.11
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: github.com/aws/aws-sdk-go-v2/credentials
  dependency-version: 1.19.21
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: github.com/aws/aws-sdk-go-v2/service/s3
  dependency-version: 1.103.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: github.com/jackc/pgx/v5
  dependency-version: 5.10.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: github.com/shirou/gopsutil/v4
  dependency-version: 4.26.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: go.opentelemetry.io/otel
  dependency-version: 1.44.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: go.opentelemetry.io/otel/sdk
  dependency-version: 1.44.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-04 17:46:47 +12:00
Kris Coleman 12b0e741d8 feat(ci): add Slack release notification via reusable workflow (#2051) 2026-05-29 14:25:15 -04:00
Kris ColemanandClaude Opus 4.6 baecd3c411 chore(deps): bump golang.org/x/net, x/crypto, containerd to patch CVEs (#2049) (#2050)
Bump golang.org/x/crypto v0.51.0 -> v0.52.0 in both root and examples modules.
Bump golang.org/x/net v0.54.0 -> v0.55.0 in examples module (root already at v0.55.0).
containerd already at v1.7.32 in root (no change needed).

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-29 13:39:20 -04:00
dependabot[bot]andlnx01 1cfa00ed9c chore(deps): bump the security group with 3 updates (#2048)
Bumps the security group with 3 updates: [github.com/aws/aws-sdk-go-v2/credentials](https://github.com/aws/aws-sdk-go-v2), [golang.org/x/net](https://github.com/golang/net) and [golang.org/x/sys](https://github.com/golang/sys).


Updates `github.com/aws/aws-sdk-go-v2/credentials` from 1.19.16 to 1.19.17
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/credentials/v1.19.16...credentials/v1.19.17)

Updates `golang.org/x/net` from 0.54.0 to 0.55.0
- [Commits](https://github.com/golang/net/compare/v0.54.0...v0.55.0)

Updates `golang.org/x/sys` from 0.44.0 to 0.45.0
- [Commits](https://github.com/golang/sys/compare/v0.44.0...v0.45.0)

---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go-v2/credentials
  dependency-version: 1.19.17
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: golang.org/x/net
  dependency-version: 0.55.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: golang.org/x/sys
  dependency-version: 0.45.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-29 12:33:42 -04:00
dependabot[bot]andlnx01 9600c17454 chore(deps): bump github.com/containerd/containerd from 1.7.30 to 1.7.32 (#2046)
Bumps [github.com/containerd/containerd](https://github.com/containerd/containerd) from 1.7.30 to 1.7.32.
- [Release notes](https://github.com/containerd/containerd/releases)
- [Changelog](https://github.com/containerd/containerd/blob/main/RELEASES.md)
- [Commits](https://github.com/containerd/containerd/compare/v1.7.30...v1.7.32)

---
updated-dependencies:
- dependency-name: github.com/containerd/containerd
  dependency-version: 1.7.32
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-22 15:36:48 +12:00
Gerard NguyenandChuck D'Antonio 61ef1e1036 fix: TLS support in MySQL connector (#2045)
* fix(mysql): respect TLS configuration in MySQL collector

The MySQL collector was ignoring the TLS field in the Database spec,
which caused TLS connections to fail even when properly configured.

This change mirrors the PostgreSQL collector pattern:
- Parse the MySQL DSN using mysql.ParseDSN
- When TLS is configured, create a tls.Config and set cfg.TLS
- Use sql.OpenDB with mysql.NewConnector when TLS is active
- Keep the existing sql.Open path for backward compatibility

Fixes: MySQL preflight fails over TLS connections

* fix(mysql): address review feedback

- Fix gofmt indentation in mysql_test.go
- Remove duplicate DSN parsing in createConnectConfig
- Add CA-cert-only TLS test case

---------

Co-authored-by: Chuck D'Antonio <chuck@replicated.com>
2026-05-22 12:35:15 +10:00
dependabot[bot]andlnx01 77e39bc5ed chore(deps): bump helm.sh/helm/v3 from 3.20.2 to 3.21.0 in /examples/sdk/helm-template in the security group across 1 directory (#2044)
chore(deps): bump helm.sh/helm/v3

Bumps the security group with 1 update in the /examples/sdk/helm-template directory: [helm.sh/helm/v3](https://github.com/helm/helm).


Updates `helm.sh/helm/v3` from 3.20.2 to 3.21.0
- [Release notes](https://github.com/helm/helm/releases)
- [Commits](https://github.com/helm/helm/compare/v3.20.2...v3.21.0)

---
updated-dependencies:
- dependency-name: helm.sh/helm/v3
  dependency-version: 3.21.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-20 16:13:24 +12:00
dependabot[bot]andlnx01 edba8f1ee0 chore(deps): bump the security group with 14 updates (#2043)
Bumps the security group with 14 updates:

| Package | From | To |
| --- | --- | --- |
| [github.com/ClickHouse/clickhouse-go/v2](https://github.com/ClickHouse/clickhouse-go) | `2.42.0` | `2.46.0` |
| [github.com/google/go-containerregistry](https://github.com/google/go-containerregistry) | `0.21.5` | `0.21.6` |
| [github.com/vmware-tanzu/velero](https://github.com/vmware-tanzu/velero) | `1.18.0` | `1.18.1` |
| [k8s.io/api](https://github.com/kubernetes/api) | `0.36.0` | `0.36.1` |
| [k8s.io/apiextensions-apiserver](https://github.com/kubernetes/apiextensions-apiserver) | `0.36.0` | `0.36.1` |
| [k8s.io/apimachinery](https://github.com/kubernetes/apimachinery) | `0.36.0` | `0.36.1` |
| [k8s.io/apiserver](https://github.com/kubernetes/apiserver) | `0.36.0` | `0.36.1` |
| [k8s.io/cli-runtime](https://github.com/kubernetes/cli-runtime) | `0.36.0` | `0.36.1` |
| [k8s.io/client-go](https://github.com/kubernetes/client-go) | `0.36.0` | `0.36.1` |
| [k8s.io/streaming](https://github.com/kubernetes/streaming) | `0.36.0` | `0.36.1` |
| [sigs.k8s.io/controller-runtime](https://github.com/kubernetes-sigs/controller-runtime) | `0.24.0` | `0.24.1` |
| [helm.sh/helm/v3](https://github.com/helm/helm) | `3.20.2` | `3.21.0` |
| [k8s.io/kubelet](https://github.com/kubernetes/kubelet) | `0.36.0` | `0.36.1` |
| [k8s.io/metrics](https://github.com/kubernetes/metrics) | `0.36.0` | `0.36.1` |


Updates `github.com/ClickHouse/clickhouse-go/v2` from 2.42.0 to 2.46.0
- [Release notes](https://github.com/ClickHouse/clickhouse-go/releases)
- [Changelog](https://github.com/ClickHouse/clickhouse-go/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ClickHouse/clickhouse-go/compare/v2.42.0...v2.46.0)

Updates `github.com/google/go-containerregistry` from 0.21.5 to 0.21.6
- [Release notes](https://github.com/google/go-containerregistry/releases)
- [Commits](https://github.com/google/go-containerregistry/compare/v0.21.5...v0.21.6)

Updates `github.com/vmware-tanzu/velero` from 1.18.0 to 1.18.1
- [Release notes](https://github.com/vmware-tanzu/velero/releases)
- [Changelog](https://github.com/velero-io/velero/blob/main/CHANGELOG.md)
- [Commits](https://github.com/vmware-tanzu/velero/compare/v1.18.0...v1.18.1)

Updates `k8s.io/api` from 0.36.0 to 0.36.1
- [Commits](https://github.com/kubernetes/api/compare/v0.36.0...v0.36.1)

Updates `k8s.io/apiextensions-apiserver` from 0.36.0 to 0.36.1
- [Release notes](https://github.com/kubernetes/apiextensions-apiserver/releases)
- [Commits](https://github.com/kubernetes/apiextensions-apiserver/compare/v0.36.0...v0.36.1)

Updates `k8s.io/apimachinery` from 0.36.0 to 0.36.1
- [Commits](https://github.com/kubernetes/apimachinery/compare/v0.36.0...v0.36.1)

Updates `k8s.io/apiserver` from 0.36.0 to 0.36.1
- [Commits](https://github.com/kubernetes/apiserver/compare/v0.36.0...v0.36.1)

Updates `k8s.io/cli-runtime` from 0.36.0 to 0.36.1
- [Commits](https://github.com/kubernetes/cli-runtime/compare/v0.36.0...v0.36.1)

Updates `k8s.io/client-go` from 0.36.0 to 0.36.1
- [Changelog](https://github.com/kubernetes/client-go/blob/master/CHANGELOG.md)
- [Commits](https://github.com/kubernetes/client-go/compare/v0.36.0...v0.36.1)

Updates `k8s.io/streaming` from 0.36.0 to 0.36.1
- [Commits](https://github.com/kubernetes/streaming/compare/v0.36.0...v0.36.1)

Updates `sigs.k8s.io/controller-runtime` from 0.24.0 to 0.24.1
- [Release notes](https://github.com/kubernetes-sigs/controller-runtime/releases)
- [Changelog](https://github.com/kubernetes-sigs/controller-runtime/blob/main/RELEASE.md)
- [Commits](https://github.com/kubernetes-sigs/controller-runtime/compare/v0.24.0...v0.24.1)

Updates `helm.sh/helm/v3` from 3.20.2 to 3.21.0
- [Release notes](https://github.com/helm/helm/releases)
- [Commits](https://github.com/helm/helm/compare/v3.20.2...v3.21.0)

Updates `k8s.io/kubelet` from 0.36.0 to 0.36.1
- [Commits](https://github.com/kubernetes/kubelet/compare/v0.36.0...v0.36.1)

Updates `k8s.io/metrics` from 0.36.0 to 0.36.1
- [Commits](https://github.com/kubernetes/metrics/compare/v0.36.0...v0.36.1)

---
updated-dependencies:
- dependency-name: github.com/ClickHouse/clickhouse-go/v2
  dependency-version: 2.46.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: github.com/google/go-containerregistry
  dependency-version: 0.21.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: github.com/vmware-tanzu/velero
  dependency-version: 1.18.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: k8s.io/api
  dependency-version: 0.36.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: k8s.io/apiextensions-apiserver
  dependency-version: 0.36.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: k8s.io/apimachinery
  dependency-version: 0.36.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: k8s.io/apiserver
  dependency-version: 0.36.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: k8s.io/cli-runtime
  dependency-version: 0.36.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: k8s.io/client-go
  dependency-version: 0.36.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: k8s.io/streaming
  dependency-version: 0.36.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: sigs.k8s.io/controller-runtime
  dependency-version: 0.24.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: helm.sh/helm/v3
  dependency-version: 3.21.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: k8s.io/kubelet
  dependency-version: 0.36.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: k8s.io/metrics
  dependency-version: 0.36.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-20 12:31:01 +12:00
replicated-ciandlnx01 894158779c Bump Go from 1.26.2 to 1.26.3 (#2040)
Bump Go to version from 1.26.2 to 1.26.3

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-05-15 08:19:00 -07:00
Lennard EijsackersandClaude Opus 4.6 1cd9b6103c feat: Add Clickhouse Support (#1967)
* feat: Add Clickhouse Support

* fix: missing case in GetCollector for ClickHouse

* chore: add analyzer

* fix; Findings

* fix: use go-version for ClickHouse version comparison

ClickHouse returns 4-part version numbers (e.g., 25.3.2.39) which
blang/semver.ParseTolerant cannot handle. Use hashicorp/go-version
(which supports arbitrary version parts) via a ClickHouse-specific
comparison function, matching the approach used by the MSSQL analyzer.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* change icon

* chore: Resolve comments

- Change icon value
- Update converter to support ClickHouse
- Update loader to support ClickHouse
- Ensure IsConnected behaviour is similar to other db collectors

* fmt 🤦

* chore: Add Clickhouse case to convertAnalyzerToSpec

* resolve CollectorName comment

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-13 22:57:16 +01:00
dependabot[bot]andlnx01 ba33b743d5 chore(deps): bump the security group with 5 updates (#2042)
Bumps the security group with 5 updates:

| Package | From | To |
| --- | --- | --- |
| [github.com/aws/aws-sdk-go-v2/service/s3](https://github.com/aws/aws-sdk-go-v2) | `1.100.1` | `1.101.0` |
| [golang.org/x/mod](https://github.com/golang/mod) | `0.35.0` | `0.36.0` |
| [golang.org/x/net](https://github.com/golang/net) | `0.53.0` | `0.54.0` |
| [golang.org/x/sys](https://github.com/golang/sys) | `0.43.0` | `0.44.0` |
| [golang.org/x/text](https://github.com/golang/text) | `0.36.0` | `0.37.0` |


Updates `github.com/aws/aws-sdk-go-v2/service/s3` from 1.100.1 to 1.101.0
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/service/s3/v1.100.1...service/s3/v1.101.0)

Updates `golang.org/x/mod` from 0.35.0 to 0.36.0
- [Commits](https://github.com/golang/mod/compare/v0.35.0...v0.36.0)

Updates `golang.org/x/net` from 0.53.0 to 0.54.0
- [Commits](https://github.com/golang/net/compare/v0.53.0...v0.54.0)

Updates `golang.org/x/sys` from 0.43.0 to 0.44.0
- [Commits](https://github.com/golang/sys/compare/v0.43.0...v0.44.0)

Updates `golang.org/x/text` from 0.36.0 to 0.37.0
- [Release notes](https://github.com/golang/text/releases)
- [Commits](https://github.com/golang/text/compare/v0.36.0...v0.37.0)

---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go-v2/service/s3
  dependency-version: 1.101.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: golang.org/x/mod
  dependency-version: 0.36.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: golang.org/x/net
  dependency-version: 0.54.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: golang.org/x/sys
  dependency-version: 0.44.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: golang.org/x/text
  dependency-version: 0.37.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-12 20:02:51 -07:00
dependabot[bot]andlnx01 f6c57607ea chore(deps): bump github.com/distribution/distribution/v3 from 3.1.0 to 3.1.1 (#2038)
chore(deps): bump github.com/distribution/distribution/v3

Bumps [github.com/distribution/distribution/v3](https://github.com/distribution/distribution) from 3.1.0 to 3.1.1.
- [Release notes](https://github.com/distribution/distribution/releases)
- [Commits](https://github.com/distribution/distribution/compare/v3.1.0...v3.1.1)

---
updated-dependencies:
- dependency-name: github.com/distribution/distribution/v3
  dependency-version: 3.1.1
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-05 16:06:49 -04:00
dependabot[bot]andlnx01 3779868880 chore(deps): bump the security group with 7 updates (#2039)
Bumps the security group with 7 updates:

| Package | From | To |
| --- | --- | --- |
| [github.com/aws/aws-sdk-go-v2](https://github.com/aws/aws-sdk-go-v2) | `1.41.6` | `1.41.7` |
| [github.com/aws/aws-sdk-go-v2/credentials](https://github.com/aws/aws-sdk-go-v2) | `1.19.15` | `1.19.16` |
| [github.com/aws/aws-sdk-go-v2/service/s3](https://github.com/aws/aws-sdk-go-v2) | `1.100.0` | `1.100.1` |
| [github.com/go-sql-driver/mysql](https://github.com/go-sql-driver/mysql) | `1.9.3` | `1.10.0` |
| [github.com/microsoft/go-mssqldb](https://github.com/microsoft/go-mssqldb) | `1.9.8` | `1.10.0` |
| [github.com/shirou/gopsutil/v4](https://github.com/shirou/gopsutil) | `4.26.3` | `4.26.4` |
| [sigs.k8s.io/controller-runtime](https://github.com/kubernetes-sigs/controller-runtime) | `0.23.3` | `0.24.0` |


Updates `github.com/aws/aws-sdk-go-v2` from 1.41.6 to 1.41.7
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/v1.41.6...v1.41.7)

Updates `github.com/aws/aws-sdk-go-v2/credentials` from 1.19.15 to 1.19.16
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/credentials/v1.19.15...credentials/v1.19.16)

Updates `github.com/aws/aws-sdk-go-v2/service/s3` from 1.100.0 to 1.100.1
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/service/s3/v1.100.0...service/s3/v1.100.1)

Updates `github.com/go-sql-driver/mysql` from 1.9.3 to 1.10.0
- [Release notes](https://github.com/go-sql-driver/mysql/releases)
- [Changelog](https://github.com/go-sql-driver/mysql/blob/master/CHANGELOG.md)
- [Commits](https://github.com/go-sql-driver/mysql/compare/v1.9.3...v1.10.0)

Updates `github.com/microsoft/go-mssqldb` from 1.9.8 to 1.10.0
- [Release notes](https://github.com/microsoft/go-mssqldb/releases)
- [Changelog](https://github.com/microsoft/go-mssqldb/blob/main/CHANGELOG.md)
- [Commits](https://github.com/microsoft/go-mssqldb/compare/v1.9.8...v1.10.0)

Updates `github.com/shirou/gopsutil/v4` from 4.26.3 to 4.26.4
- [Release notes](https://github.com/shirou/gopsutil/releases)
- [Commits](https://github.com/shirou/gopsutil/compare/v4.26.3...v4.26.4)

Updates `sigs.k8s.io/controller-runtime` from 0.23.3 to 0.24.0
- [Release notes](https://github.com/kubernetes-sigs/controller-runtime/releases)
- [Changelog](https://github.com/kubernetes-sigs/controller-runtime/blob/main/RELEASE.md)
- [Commits](https://github.com/kubernetes-sigs/controller-runtime/compare/v0.23.3...v0.24.0)

---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go-v2
  dependency-version: 1.41.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: github.com/aws/aws-sdk-go-v2/credentials
  dependency-version: 1.19.16
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: github.com/aws/aws-sdk-go-v2/service/s3
  dependency-version: 1.100.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: github.com/go-sql-driver/mysql
  dependency-version: 1.10.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: github.com/microsoft/go-mssqldb
  dependency-version: 1.10.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: github.com/shirou/gopsutil/v4
  dependency-version: 4.26.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: sigs.k8s.io/controller-runtime
  dependency-version: 0.24.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-05 10:01:29 -04:00
Ethan Mosbaugh 4c6af55e7c fix: correct RBAC verb for pods/exec from get to create (#2037)
fix: correct RBAC verb and WebSocket fallback for pods/exec

This commit fixes three related issues that prevented exec collectors from
working with minimal RBAC permissions:

1. RBAC preflight check used wrong verb for pods/exec
   Changed from "get" to "create" in v1beta1 and v1beta2 AccessReviewSpecs.
   The pods/exec subresource requires "create" to execute commands.

2. WebSocket fallback used wrong httpstream package import
   The fallback executor checked IsUpgradeFailure using the apimachinery
   httpstream package, but the roundtripper creates UpgradeFailureError using
   the streaming httpstream package. These are different Go types, so
   errors.As always returned false and fallback to SPDY never triggered.
   Changed import to k8s.io/streaming/pkg/httpstream.

3. Stdin mismatch caused SPDY fallback to hang
   PodExecOptions always set Stdin:true but StreamOptions always passed
   Stdin:nil. When WebSocket failed and fell back to SPDY, the server
   waited for stdin data that never arrived. Changed Stdin to false in
   PodExecOptions for exec, copy, and copy_from_host collectors.
2026-05-01 13:03:42 -07:00
Xav Paice a4ce199005 refactor(collect): replace go.podman.io/image with go-containerregistry (#2034)
* refactor(collect): replace go.podman.io/image with go-containerregistry

Migrate pkg/collect/registry.go off go.podman.io/image/v5 (containers/image)
onto github.com/google/go-containerregistry, eliminating the transitive
github.com/docker/docker +incompatible chain that blocks Docker v29 SDK
adoption.

The RegistryImages collector probes whether each requested image exists in
its registry by issuing a manifest HEAD. We replace alltransports.ParseImageName
+ imageRef.NewImage with name.ParseReference + remote.Head. Auth from a
kubernetes.io/dockerconfigjson Secret is converted to an authn.Authenticator;
error classification switches from errcode.Errors string matching to
transport.Error.StatusCode.

Add httptest.NewTLSServer-backed tests for imageExists covering the
found/not-found/unauthorized/EOF-retry paths to lock in protocol-level
behavior across the migration.

Promote go-containerregistry to a direct require at v0.21.5; go mod tidy
drops go.podman.io/image, distribution/distribution/v3, and the bare
docker/docker entry from the module graph.

Issue: tr-dit

* Removed the unreachable strings.Contains branch so we no longer pretend there is special “architecture mismatch → treat as exists” behavior.
Documented next to remote.Get that the check is manifest presence for the reference, not “runnable on this arch.”

* fix(collect): use DefaultKeychain when registry auth config is nil

Restore ambient credential behavior (~/.docker/config.json, credential
helpers) for registry image checks. Without WithAuthFromKeychain,
remote.Get defaulted to anonymous auth, diverging from containers/image
and from documented nil authConfig semantics.

Made-with: Cursor
2026-04-30 10:12:53 +01:00
Ethan MosbaughandClaude Sonnet 4.6 48c45d7b0a refactor: replace SPDY executor with WebSocket-first fallback executor (#2031)
* docs: add design spec for SPDY executor removal

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* docs: add implementation plan for SPDY executor removal

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(k8sutil): add NewFallbackExecutor helper

* fix(k8sutil): rename url param to u to avoid shadowing net/url

* refactor(collect): use fallback executor in exec collector

* refactor(collect): use fallback executor in copy collector

* refactor(collect): use fallback executor in copy_from_host collector

* refactor(collect): use fallback executor in sonobuoy_results collector

* refactor(collect): use fallback executor in etcd collector

* refactor(collect): use fallback executor in longhorn collector

* refactor(supportbundle): use fallback executor in collect

* chore(k8sutil): delete unused PortForward function

* fix(k8sutil): use GET for WebSocket executor and broaden fallback predicate

WebSocket upgrade requires GET per RFC 6455. Also add IsHTTPSProxyError to
the fallback predicate so HTTPS proxy environments fall back to SPDY correctly,
matching kubectl's implementation. Remove method param from NewFallbackExecutor
since the methods are now transport-specific and not caller-controlled.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* chore: remove superpowers docs artifacts

* fix(collect): enable stdout capture in exec collector

* fix(collect): enable stdout capture in copy collectors

PodExecOptions.Stdout: false causes the WebSocket API server to discard
stdout entirely, silently breaking tar output for file copy operations.
With SPDY this mismatch was harmless; WebSocket strictly respects the field.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-29 06:21:42 -07:00
Evans Mungai 2fdd21fca1 feat(analyze): warn when nodeResources has no node data, add ignoreIfNoFiles (#2035)
* feat(analyze): warn when nodeResources has no node data, add ignoreIfNoFiles

The nodeResources analyzer previously failed silently when
cluster-resources/nodes.json was not collected (e.g. when the
clusterResources collector was excluded or could not list nodes).
It now emits a warn outcome per nodeResources entry in the spec.

Add an ignoreIfNoFiles top-level field to nodeResources, mirroring
textAnalyze, so users can opt out of the new warning when the
analyzer is intentionally optional.

- Add IgnoreIfNoFiles to v1beta2.NodeResources
- Update CRDs and JSON schemas
- Unit test the warn / ignore paths
- Add an e2e fixture and test that excludes clusterResources and
asserts the analyze output

Signed-off-by: Evans Mungai <evans@replicated.com>

* Fix review comment

Signed-off-by: Evans Mungai <evans@replicated.com>

---------

Signed-off-by: Evans Mungai <evans@replicated.com>
2026-04-29 13:13:24 +01:00
572cb8e31d chore(deps): bump the security group across 1 directory with 12 updates (#2030)
* chore(deps): bump the security group across 1 directory with 12 updates

Bumps the security group with 8 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [github.com/apparentlymart/go-cidr](https://github.com/apparentlymart/go-cidr) | `1.1.0` | `1.1.1` |
| [github.com/aws/aws-sdk-go-v2/service/s3](https://github.com/aws/aws-sdk-go-v2) | `1.99.1` | `1.100.0` |
| [github.com/mattn/go-isatty](https://github.com/mattn/go-isatty) | `0.0.21` | `0.0.22` |
| [k8s.io/api](https://github.com/kubernetes/api) | `0.35.4` | `0.36.0` |
| [k8s.io/apiextensions-apiserver](https://github.com/kubernetes/apiextensions-apiserver) | `0.35.4` | `0.36.0` |
| [k8s.io/cli-runtime](https://github.com/kubernetes/cli-runtime) | `0.35.4` | `0.36.0` |
| [k8s.io/kubelet](https://github.com/kubernetes/kubelet) | `0.35.4` | `0.36.0` |
| [k8s.io/metrics](https://github.com/kubernetes/metrics) | `0.35.4` | `0.36.0` |



Updates `github.com/apparentlymart/go-cidr` from 1.1.0 to 1.1.1
- [Release notes](https://github.com/apparentlymart/go-cidr/releases)
- [Commits](https://github.com/apparentlymart/go-cidr/compare/v1.1.0...v1.1.1)

Updates `github.com/aws/aws-sdk-go-v2/service/s3` from 1.99.1 to 1.100.0
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/service/s3/v1.99.1...service/s3/v1.100.0)

Updates `github.com/mattn/go-isatty` from 0.0.21 to 0.0.22
- [Commits](https://github.com/mattn/go-isatty/compare/v0.0.21...v0.0.22)

Updates `k8s.io/api` from 0.35.4 to 0.36.0
- [Commits](https://github.com/kubernetes/api/compare/v0.35.4...v0.36.0)

Updates `k8s.io/apiextensions-apiserver` from 0.35.4 to 0.36.0
- [Release notes](https://github.com/kubernetes/apiextensions-apiserver/releases)
- [Commits](https://github.com/kubernetes/apiextensions-apiserver/compare/v0.35.4...v0.36.0)

Updates `k8s.io/apimachinery` from 0.35.4 to 0.36.0
- [Commits](https://github.com/kubernetes/apimachinery/compare/v0.35.4...v0.36.0)

Updates `k8s.io/apiserver` from 0.35.4 to 0.36.0
- [Commits](https://github.com/kubernetes/apiserver/compare/v0.35.4...v0.36.0)

Updates `k8s.io/cli-runtime` from 0.35.4 to 0.36.0
- [Commits](https://github.com/kubernetes/cli-runtime/compare/v0.35.4...v0.36.0)

Updates `k8s.io/client-go` from 0.35.4 to 0.36.0
- [Changelog](https://github.com/kubernetes/client-go/blob/master/CHANGELOG.md)
- [Commits](https://github.com/kubernetes/client-go/compare/v0.35.4...v0.36.0)

Updates `k8s.io/kubelet` from 0.35.4 to 0.36.0
- [Commits](https://github.com/kubernetes/kubelet/compare/v0.35.4...v0.36.0)

Updates `k8s.io/metrics` from 0.35.4 to 0.36.0
- [Commits](https://github.com/kubernetes/metrics/compare/v0.35.4...v0.36.0)

Updates `k8s.io/utils` from 0.0.0-20251002143259-bc988d571ff4 to 0.0.0-20260210185600-b8788abfbbc2
- [Commits](https://github.com/kubernetes/utils/commits)

---
updated-dependencies:
- dependency-name: github.com/apparentlymart/go-cidr
  dependency-version: 1.1.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: github.com/aws/aws-sdk-go-v2/service/s3
  dependency-version: 1.100.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: github.com/mattn/go-isatty
  dependency-version: 0.0.22
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: k8s.io/api
  dependency-version: 0.36.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: k8s.io/apiextensions-apiserver
  dependency-version: 0.36.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: k8s.io/apimachinery
  dependency-version: 0.36.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: k8s.io/apiserver
  dependency-version: 0.36.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: k8s.io/cli-runtime
  dependency-version: 0.36.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: k8s.io/client-go
  dependency-version: 0.36.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: k8s.io/kubelet
  dependency-version: 0.36.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: k8s.io/metrics
  dependency-version: 0.36.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: k8s.io/utils
  dependency-version: 0.0.0-20260210185600-b8788abfbbc2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
...

Signed-off-by: dependabot[bot] <support@github.com>

* k8s.io/kubectl v0.36.0

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Andrew Lavery <laverya@umich.edu>
2026-04-29 08:12:16 -04:00
Evans MungaiandClaude Opus 4.6 21948fe959 feat: add host registryImages collector and analyzer (#2029)
* feat: add host registryImages collector and analyzer

Adds a host-level registryImages collector and analyzer that can check
image existence in registries without requiring a Kubernetes cluster.
Supports inline username/password auth or ambient credentials from
~/.docker/config.json.

Refactors imageExistsWithAuth from the cluster-level registry collector
to share the core image existence check logic.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Fixes from manual tests

Signed-off-by: Evans Mungai <evans@replicated.com>

* Updates from manual tests

Signed-off-by: Evans Mungai <evans@replicated.com>

* Sort template lists

Signed-off-by: Evans Mungai <evans@replicated.com>

* More changes

Signed-off-by: Evans Mungai <evans@replicated.com>

---------

Signed-off-by: Evans Mungai <evans@replicated.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-29 10:26:18 +01:00
Xav Paice b56b98742e Revert "refactor(collect): replace go.podman.io/image with go-containerregistry" (#2033)
This reverts commit b105fa62c7.
2026-04-29 13:29:35 +12:00
furiosa b105fa62c7 refactor(collect): replace go.podman.io/image with go-containerregistry
Migrate pkg/collect/registry.go off go.podman.io/image/v5 (containers/image)
onto github.com/google/go-containerregistry, eliminating the transitive
github.com/docker/docker +incompatible chain that blocks Docker v29 SDK
adoption.

The RegistryImages collector probes whether each requested image exists in
its registry by issuing a manifest HEAD. We replace alltransports.ParseImageName
+ imageRef.NewImage with name.ParseReference + remote.Head. Auth from a
kubernetes.io/dockerconfigjson Secret is converted to an authn.Authenticator;
error classification switches from errcode.Errors string matching to
transport.Error.StatusCode.

Add httptest.NewTLSServer-backed tests for imageExists covering the
found/not-found/unauthorized/EOF-retry paths to lock in protocol-level
behavior across the migration.

Promote go-containerregistry to a direct require at v0.21.5; go mod tidy
drops go.podman.io/image, distribution/distribution/v3, and the bare
docker/docker entry from the module graph.

Issue: tr-dit
2026-04-28 16:14:55 +12:00
Xav PaiceandClaude Opus 4.7 558a8f5110 chore(deps): bump docker/docker to v28.5.2 and go-containerregistry to v0.21.5 (#2028)
Addresses vulnerabilities in github.com/docker/docker v28.5.1. Both are
indirect deps; no source imports them directly. Pulled v0.21.5 of
go-containerregistry via `go get ...@latest`, then forced docker/docker
to v28.5.2 since go.podman.io/image/v5 still pins v28.5.1 at its latest
release (v5.39.2).

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 13:59:37 +12:00
dependabot[bot]andlnx01 070fd9bab4 chore(deps): bump the security group across 1 directory with 12 updates (#2026)
Bumps the security group with 9 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [github.com/aws/aws-sdk-go-v2](https://github.com/aws/aws-sdk-go-v2) | `1.41.5` | `1.41.6` |
| [github.com/aws/aws-sdk-go-v2/credentials](https://github.com/aws/aws-sdk-go-v2) | `1.19.14` | `1.19.15` |
| [github.com/aws/aws-sdk-go-v2/service/s3](https://github.com/aws/aws-sdk-go-v2) | `1.99.0` | `1.99.1` |
| [k8s.io/api](https://github.com/kubernetes/api) | `0.35.3` | `0.35.4` |
| [k8s.io/apiextensions-apiserver](https://github.com/kubernetes/apiextensions-apiserver) | `0.35.3` | `0.35.4` |
| [k8s.io/cli-runtime](https://github.com/kubernetes/cli-runtime) | `0.35.3` | `0.35.4` |
| [sigs.k8s.io/e2e-framework](https://github.com/kubernetes-sigs/e2e-framework) | `0.6.0` | `0.7.0` |
| [k8s.io/kubelet](https://github.com/kubernetes/kubelet) | `0.35.3` | `0.35.4` |
| [k8s.io/metrics](https://github.com/kubernetes/metrics) | `0.35.3` | `0.35.4` |



Updates `github.com/aws/aws-sdk-go-v2` from 1.41.5 to 1.41.6
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/v1.41.5...v1.41.6)

Updates `github.com/aws/aws-sdk-go-v2/credentials` from 1.19.14 to 1.19.15
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/credentials/v1.19.14...credentials/v1.19.15)

Updates `github.com/aws/aws-sdk-go-v2/service/s3` from 1.99.0 to 1.99.1
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/service/s3/v1.99.0...service/s3/v1.99.1)

Updates `k8s.io/api` from 0.35.3 to 0.35.4
- [Commits](https://github.com/kubernetes/api/compare/v0.35.3...v0.35.4)

Updates `k8s.io/apiextensions-apiserver` from 0.35.3 to 0.35.4
- [Release notes](https://github.com/kubernetes/apiextensions-apiserver/releases)
- [Commits](https://github.com/kubernetes/apiextensions-apiserver/compare/v0.35.3...v0.35.4)

Updates `k8s.io/apimachinery` from 0.35.3 to 0.35.4
- [Commits](https://github.com/kubernetes/apimachinery/compare/v0.35.3...v0.35.4)

Updates `k8s.io/apiserver` from 0.35.3 to 0.35.4
- [Commits](https://github.com/kubernetes/apiserver/compare/v0.35.3...v0.35.4)

Updates `k8s.io/cli-runtime` from 0.35.3 to 0.35.4
- [Commits](https://github.com/kubernetes/cli-runtime/compare/v0.35.3...v0.35.4)

Updates `k8s.io/client-go` from 0.35.3 to 0.35.4
- [Changelog](https://github.com/kubernetes/client-go/blob/master/CHANGELOG.md)
- [Commits](https://github.com/kubernetes/client-go/compare/v0.35.3...v0.35.4)

Updates `sigs.k8s.io/e2e-framework` from 0.6.0 to 0.7.0
- [Release notes](https://github.com/kubernetes-sigs/e2e-framework/releases)
- [Changelog](https://github.com/kubernetes-sigs/e2e-framework/blob/main/RELEASE.md)
- [Commits](https://github.com/kubernetes-sigs/e2e-framework/compare/v0.6.0...v0.7.0)

Updates `k8s.io/kubelet` from 0.35.3 to 0.35.4
- [Commits](https://github.com/kubernetes/kubelet/compare/v0.35.3...v0.35.4)

Updates `k8s.io/metrics` from 0.35.3 to 0.35.4
- [Commits](https://github.com/kubernetes/metrics/compare/v0.35.3...v0.35.4)

---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go-v2
  dependency-version: 1.41.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: github.com/aws/aws-sdk-go-v2/credentials
  dependency-version: 1.19.15
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: github.com/aws/aws-sdk-go-v2/service/s3
  dependency-version: 1.99.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: k8s.io/api
  dependency-version: 0.35.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: k8s.io/apiextensions-apiserver
  dependency-version: 0.35.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: k8s.io/apimachinery
  dependency-version: 0.35.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: k8s.io/apiserver
  dependency-version: 0.35.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: k8s.io/cli-runtime
  dependency-version: 0.35.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: k8s.io/client-go
  dependency-version: 0.35.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: sigs.k8s.io/e2e-framework
  dependency-version: 0.7.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: k8s.io/kubelet
  dependency-version: 0.35.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: k8s.io/metrics
  dependency-version: 0.35.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-23 08:21:06 +12:00
dependabot[bot]andlnx01 e89c858bd2 chore(deps): bump docker/setup-qemu-action from 3 to 4 (#2023)
Bumps [docker/setup-qemu-action](https://github.com/docker/setup-qemu-action) from 3 to 4.
- [Release notes](https://github.com/docker/setup-qemu-action/releases)
- [Commits](https://github.com/docker/setup-qemu-action/compare/v3...v4)

---
updated-dependencies:
- dependency-name: docker/setup-qemu-action
  dependency-version: '4'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-22 13:37:56 +12:00
Evans Mungai 483467d8b9 chore: update preflight cli help text (#2027)
Signed-off-by: Evans Mungai <evans@replicated.com>
2026-04-21 17:38:16 +01:00
Ash 27903af638 [chore] bump pgx (#2025) 2026-04-21 11:40:02 +01:00
dependabot[bot]andlnx01 6eb09ee9d5 chore(deps): bump github.com/moby/spdystream from 0.5.0 to 0.5.1 (#2022)
Bumps [github.com/moby/spdystream](https://github.com/moby/spdystream) from 0.5.0 to 0.5.1.
- [Release notes](https://github.com/moby/spdystream/releases)
- [Commits](https://github.com/moby/spdystream/compare/v0.5.0...v0.5.1)

---
updated-dependencies:
- dependency-name: github.com/moby/spdystream
  dependency-version: 0.5.1
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-17 13:34:58 +01:00
Evans Mungai 845fdcc8c8 Move REVIEW.md to .cursor/BUGBOT.md (#2021)
* Move REVIEW.md to .cursor/BUGBOT.md

Signed-off-by: Evans Mungai <evans@replicated.com>

* Comment update

Signed-off-by: Evans Mungai <evans@replicated.com>

---------

Signed-off-by: Evans Mungai <evans@replicated.com>
2026-04-16 15:40:45 +01:00
Evans Mungai a3c453d1d6 fix: record skipped collectors in bundle and improve CLI warnings (#2019)
* fix: record skipped collectors in bundle and improve CLI warnings

- Write `skipped-collectors.json` to the support bundle and preflight bundle recording which collectors were skipped (RBAC permissions or spec exclusion), with reason, errors, and timestamp
- Surface RBAC errors and skipped-collector messages as `klog.Warningf` in non-interactive mode so they're visible without `-v` flags
- Exec collector file naming now falls back to the resolved container name (from the pod spec) when `collectorName` is not set, instead of only checking `containerName` from the spec

Signed-off-by: Evans Mungai <evans@replicated.com>

* Address comment

Signed-off-by: Evans Mungai <evans@replicated.com>

* fix bugbot comment

Signed-off-by: Evans Mungai <evans@replicated.com>

* Remove unused var

Signed-off-by: Evans Mungai <evans@replicated.com>

* Address comment

Signed-off-by: Evans Mungai <evans@replicated.com>

* Use results.SaveResult and add automated tests

Signed-off-by: Evans Mungai <evans@replicated.com>

* Improvements

Signed-off-by: Evans Mungai <evans@replicated.com>

* Fix bugbot

Signed-off-by: Evans Mungai <evans@replicated.com>

* Handle bugbot

Signed-off-by: Evans Mungai <evans@replicated.com>

---------

Signed-off-by: Evans Mungai <evans@replicated.com>
2026-04-15 22:29:35 +01:00
Evans Mungai 35d5ad17af feat: add CLAUDE.md and AGENTS.md to project (#2020)
* feat: add CLAUDE.md and AGENTS.md to project

Signed-off-by: Evans Mungai <evans@replicated.com>

* Add missed file

Signed-off-by: Evans Mungai <evans@replicated.com>

* Updates

Signed-off-by: Evans Mungai <evans@replicated.com>

---------

Signed-off-by: Evans Mungai <evans@replicated.com>
2026-04-15 18:46:07 +01:00
Evans MungaiandClaude Opus 4.6 daeab2dc20 fix: improve collector output discoverability (#2018)
* fix: document .tar.gz auto-append in --output flag help text

The --output flag silently appends .tar.gz to the provided path, which
was not mentioned in the help text, causing confusion for users who
expected the exact filename they specified.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: exec collector falls back to containerName for file naming

When collectorName is not set, the exec collector now uses containerName
as the output file prefix instead of producing bare -stdout.txt filenames.
This makes output files identifiable without requiring collectorName to
be explicitly set.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 18:42:30 +01:00
Andrew LaveryandDaniel Lipovetsky 5a611b3a6a feat: Collect validating and mutating webhook configurations (#2017)
* feat: Collect validating and mutating webhook configurations

* fixup! feat: Collect validating and mutating webhook configurations

Add metadata before marshaling

* explicitly test webhook configuration collection in TestClusterResources

---------

Co-authored-by: Daniel Lipovetsky <daniel.lipovetsky@nutanix.com>
2026-04-14 11:22:55 -04:00
Ludovic HenryandAndrew Lavery fc72539585 ci: Add releases for linux-riscv64 (#2010)
Add releases for linux-riscv64

This project is a dependency of `k0s` which is working on being built, tested and released on `linux-riscv64` [1].

RISC-V is gaining momentum especially in the embedded and edge world. 

[1] https://github.com/k0sproject/k0s/pull/7414

Co-authored-by: Andrew Lavery <laverya@umich.edu>
2026-04-14 11:03:26 -04:00
Andrew Lavery 69743729a3 smoke test all linux target architectures (#2016)
* smoke test all linux target architectures

* go mod update

* use 'real' target cluster

* better logging

* newer alpine
2026-04-14 07:30:26 -07:00
dependabot[bot]andlnx01 6d1b1eba49 chore(deps): bump golang.org/x/net from 0.52.0 to 0.53.0 in the security group (#2015)
chore(deps): bump golang.org/x/net in the security group

Bumps the security group with 1 update: [golang.org/x/net](https://github.com/golang/net).


Updates `golang.org/x/net` from 0.52.0 to 0.53.0
- [Commits](https://github.com/golang/net/compare/v0.52.0...v0.53.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-version: 0.53.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-14 06:02:54 -04:00
dependabot[bot]andlnx01 db137b1c33 chore(deps): bump helm.sh/helm/v3 from 3.20.1 to 3.20.2 in /examples/sdk/helm-template (#2012)
chore(deps): bump helm.sh/helm/v3 in /examples/sdk/helm-template

Bumps [helm.sh/helm/v3](https://github.com/helm/helm) from 3.20.1 to 3.20.2.
- [Release notes](https://github.com/helm/helm/releases)
- [Commits](https://github.com/helm/helm/compare/v3.20.1...v3.20.2)

---
updated-dependencies:
- dependency-name: helm.sh/helm/v3
  dependency-version: 3.20.2
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-13 09:48:28 -04:00
dependabot[bot]andlnx01 a6915eac63 chore(deps): bump helm.sh/helm/v3 from 3.20.1 to 3.20.2 (#2013)
Bumps [helm.sh/helm/v3](https://github.com/helm/helm) from 3.20.1 to 3.20.2.
- [Release notes](https://github.com/helm/helm/releases)
- [Commits](https://github.com/helm/helm/compare/v3.20.1...v3.20.2)

---
updated-dependencies:
- dependency-name: helm.sh/helm/v3
  dependency-version: 3.20.2
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-13 09:48:04 -04:00
replicated-ciandlnx01 95ef65b08d Bump Go from 1.26.1 to 1.26.2 (#2014)
Bump Go to version from 1.26.1 to 1.26.2

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-04-13 09:47:45 -04:00
Ethan MosbaughandClaude Sonnet 4.6 c096e5d075 fix(supportbundle): ExtractLicenseFromBundle prefers license.json regardless of tar order (#2011)
license.json was being ignored when configmaps containing a license ID
appeared earlier in the tar archive. The function now collects both
candidates in a single pass and returns the license.json result if
present, falling back to the configmap scan only when license.json is
absent.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 11:59:53 -07:00
dependabot[bot]andlnx01 e3903add9f chore(deps): bump the security group across 1 directory with 14 updates (#2009)
Bumps the security group with 14 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [github.com/aws/aws-sdk-go-v2](https://github.com/aws/aws-sdk-go-v2) | `1.41.1` | `1.41.5` |
| [github.com/aws/aws-sdk-go-v2/credentials](https://github.com/aws/aws-sdk-go-v2) | `1.19.9` | `1.19.14` |
| [github.com/aws/aws-sdk-go-v2/service/s3](https://github.com/aws/aws-sdk-go-v2) | `1.96.0` | `1.99.0` |
| [github.com/distribution/distribution/v3](https://github.com/distribution/distribution) | `3.0.0` | `3.1.0` |
| [github.com/hashicorp/go-getter](https://github.com/hashicorp/go-getter) | `1.8.5` | `1.8.6` |
| [github.com/mattn/go-isatty](https://github.com/mattn/go-isatty) | `0.0.20` | `0.0.21` |
| [github.com/shirou/gopsutil/v4](https://github.com/shirou/gopsutil) | `4.26.2` | `4.26.3` |
| [go.opentelemetry.io/otel](https://github.com/open-telemetry/opentelemetry-go) | `1.42.0` | `1.43.0` |
| [go.opentelemetry.io/otel/sdk](https://github.com/open-telemetry/opentelemetry-go) | `1.42.0` | `1.43.0` |
| [go.podman.io/image/v5](https://github.com/containers/container-libs) | `5.39.1` | `5.39.2` |
| [golang.org/x/mod](https://github.com/golang/mod) | `0.34.0` | `0.35.0` |
| [github.com/hashicorp/go-version](https://github.com/hashicorp/go-version) | `1.8.0` | `1.9.0` |
| [golang.org/x/sys](https://github.com/golang/sys) | `0.42.0` | `0.43.0` |
| [golang.org/x/text](https://github.com/golang/text) | `0.35.0` | `0.36.0` |



Updates `github.com/aws/aws-sdk-go-v2` from 1.41.1 to 1.41.5
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/v1.41.1...v1.41.5)

Updates `github.com/aws/aws-sdk-go-v2/credentials` from 1.19.9 to 1.19.14
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/service/m2/v1.19.9...credentials/v1.19.14)

Updates `github.com/aws/aws-sdk-go-v2/service/s3` from 1.96.0 to 1.99.0
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/service/s3/v1.96.0...service/s3/v1.99.0)

Updates `github.com/distribution/distribution/v3` from 3.0.0 to 3.1.0
- [Release notes](https://github.com/distribution/distribution/releases)
- [Commits](https://github.com/distribution/distribution/compare/v3.0.0...v3.1.0)

Updates `github.com/hashicorp/go-getter` from 1.8.5 to 1.8.6
- [Release notes](https://github.com/hashicorp/go-getter/releases)
- [Commits](https://github.com/hashicorp/go-getter/compare/v1.8.5...v1.8.6)

Updates `github.com/mattn/go-isatty` from 0.0.20 to 0.0.21
- [Commits](https://github.com/mattn/go-isatty/compare/v0.0.20...v0.0.21)

Updates `github.com/shirou/gopsutil/v4` from 4.26.2 to 4.26.3
- [Release notes](https://github.com/shirou/gopsutil/releases)
- [Commits](https://github.com/shirou/gopsutil/compare/v4.26.2...v4.26.3)

Updates `go.opentelemetry.io/otel` from 1.42.0 to 1.43.0
- [Release notes](https://github.com/open-telemetry/opentelemetry-go/releases)
- [Changelog](https://github.com/open-telemetry/opentelemetry-go/blob/main/CHANGELOG.md)
- [Commits](https://github.com/open-telemetry/opentelemetry-go/compare/v1.42.0...v1.43.0)

Updates `go.opentelemetry.io/otel/sdk` from 1.42.0 to 1.43.0
- [Release notes](https://github.com/open-telemetry/opentelemetry-go/releases)
- [Changelog](https://github.com/open-telemetry/opentelemetry-go/blob/main/CHANGELOG.md)
- [Commits](https://github.com/open-telemetry/opentelemetry-go/compare/v1.42.0...v1.43.0)

Updates `go.podman.io/image/v5` from 5.39.1 to 5.39.2
- [Release notes](https://github.com/containers/container-libs/releases)
- [Commits](https://github.com/containers/container-libs/compare/image/v5.39.1...image/v5.39.2)

Updates `golang.org/x/mod` from 0.34.0 to 0.35.0
- [Commits](https://github.com/golang/mod/compare/v0.34.0...v0.35.0)

Updates `github.com/hashicorp/go-version` from 1.8.0 to 1.9.0
- [Release notes](https://github.com/hashicorp/go-version/releases)
- [Changelog](https://github.com/hashicorp/go-version/blob/main/CHANGELOG.md)
- [Commits](https://github.com/hashicorp/go-version/compare/v1.8.0...v1.9.0)

Updates `golang.org/x/sys` from 0.42.0 to 0.43.0
- [Commits](https://github.com/golang/sys/compare/v0.42.0...v0.43.0)

Updates `golang.org/x/text` from 0.35.0 to 0.36.0
- [Release notes](https://github.com/golang/text/releases)
- [Commits](https://github.com/golang/text/compare/v0.35.0...v0.36.0)

---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go-v2
  dependency-version: 1.41.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: github.com/aws/aws-sdk-go-v2/credentials
  dependency-version: 1.19.14
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: github.com/aws/aws-sdk-go-v2/service/s3
  dependency-version: 1.99.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: github.com/distribution/distribution/v3
  dependency-version: 3.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: github.com/hashicorp/go-getter
  dependency-version: 1.8.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: github.com/mattn/go-isatty
  dependency-version: 0.0.21
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: github.com/shirou/gopsutil/v4
  dependency-version: 4.26.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: go.opentelemetry.io/otel
  dependency-version: 1.43.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: go.opentelemetry.io/otel/sdk
  dependency-version: 1.43.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: go.podman.io/image/v5
  dependency-version: 5.39.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: golang.org/x/mod
  dependency-version: 0.35.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: github.com/hashicorp/go-version
  dependency-version: 1.9.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: golang.org/x/sys
  dependency-version: 0.43.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: golang.org/x/text
  dependency-version: 0.36.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-09 14:32:09 -04:00
Andrew Lavery ad7d52f7e5 add a collector that checks s3 access (#2007)
* add a collector that checks s3 access

* testing and analyzer

* analyzer test

* fmt
2026-04-09 11:12:34 -07:00
Evans Mungai 670a510a2d feat(analyze): optional additionalDeviceTypes parameter for blockDevices (#2002)
feat(analyze): optional additionalDeviceTypes for blockDevices; refactor match config and tests

Allow preflights to count extra lsblk TYPE values (e.g. loop, lvm) by listing them in
blockDevices.additionalDeviceTypes on BlockDevicesAnalyze. Types in this list are
eligible whether or not includeUnmountedPartitions is set; disk and optional
partitions behave as before.

Refactor matching to use blockDevicesMatchConfig and document eligibility on that
type. Add host_block_devices_match_test.go for type-rule tables and preflight-style
integration cases; keep classic scenarios in host_block_devices_test.go with a
shared analyzeHostBlockDevicesOutput helper.
Regenerate CRDs and deepcopy for the new API field.

Signed-off-by: Evans Mungai <evans@replicated.com>
2026-03-31 20:29:51 +01:00
Andrew Lavery cb1e39cb61 run govulncheck and then grype (#2000)
* run govulncheck and then grype

* cleanup

* exclude bin/ from grype scans

* show path to file containing vuln in grype output
2026-03-24 13:29:12 -07:00
dependabot[bot]andlnx01 a697d59040 chore(deps): bump the security group with 10 updates (#1999)
Bumps the security group with 10 updates:

| Package | From | To |
| --- | --- | --- |
| [github.com/fatih/color](https://github.com/fatih/color) | `1.18.0` | `1.19.0` |
| [github.com/jackc/pgx/v5](https://github.com/jackc/pgx) | `5.8.0` | `5.9.1` |
| [k8s.io/api](https://github.com/kubernetes/api) | `0.35.2` | `0.35.3` |
| [k8s.io/apiextensions-apiserver](https://github.com/kubernetes/apiextensions-apiserver) | `0.35.2` | `0.35.3` |
| [k8s.io/apimachinery](https://github.com/kubernetes/apimachinery) | `0.35.2` | `0.35.3` |
| [k8s.io/apiserver](https://github.com/kubernetes/apiserver) | `0.35.2` | `0.35.3` |
| [k8s.io/cli-runtime](https://github.com/kubernetes/cli-runtime) | `0.35.2` | `0.35.3` |
| [k8s.io/client-go](https://github.com/kubernetes/client-go) | `0.35.2` | `0.35.3` |
| [k8s.io/kubelet](https://github.com/kubernetes/kubelet) | `0.35.2` | `0.35.3` |
| [k8s.io/metrics](https://github.com/kubernetes/metrics) | `0.35.2` | `0.35.3` |


Updates `github.com/fatih/color` from 1.18.0 to 1.19.0
- [Release notes](https://github.com/fatih/color/releases)
- [Commits](https://github.com/fatih/color/compare/v1.18.0...v1.19.0)

Updates `github.com/jackc/pgx/v5` from 5.8.0 to 5.9.1
- [Changelog](https://github.com/jackc/pgx/blob/master/CHANGELOG.md)
- [Commits](https://github.com/jackc/pgx/compare/v5.8.0...v5.9.1)

Updates `k8s.io/api` from 0.35.2 to 0.35.3
- [Commits](https://github.com/kubernetes/api/compare/v0.35.2...v0.35.3)

Updates `k8s.io/apiextensions-apiserver` from 0.35.2 to 0.35.3
- [Release notes](https://github.com/kubernetes/apiextensions-apiserver/releases)
- [Commits](https://github.com/kubernetes/apiextensions-apiserver/compare/v0.35.2...v0.35.3)

Updates `k8s.io/apimachinery` from 0.35.2 to 0.35.3
- [Commits](https://github.com/kubernetes/apimachinery/compare/v0.35.2...v0.35.3)

Updates `k8s.io/apiserver` from 0.35.2 to 0.35.3
- [Commits](https://github.com/kubernetes/apiserver/compare/v0.35.2...v0.35.3)

Updates `k8s.io/cli-runtime` from 0.35.2 to 0.35.3
- [Commits](https://github.com/kubernetes/cli-runtime/compare/v0.35.2...v0.35.3)

Updates `k8s.io/client-go` from 0.35.2 to 0.35.3
- [Changelog](https://github.com/kubernetes/client-go/blob/master/CHANGELOG.md)
- [Commits](https://github.com/kubernetes/client-go/compare/v0.35.2...v0.35.3)

Updates `k8s.io/kubelet` from 0.35.2 to 0.35.3
- [Commits](https://github.com/kubernetes/kubelet/compare/v0.35.2...v0.35.3)

Updates `k8s.io/metrics` from 0.35.2 to 0.35.3
- [Commits](https://github.com/kubernetes/metrics/compare/v0.35.2...v0.35.3)

---
updated-dependencies:
- dependency-name: github.com/fatih/color
  dependency-version: 1.19.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: github.com/jackc/pgx/v5
  dependency-version: 5.9.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: k8s.io/api
  dependency-version: 0.35.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: k8s.io/apiextensions-apiserver
  dependency-version: 0.35.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: k8s.io/apimachinery
  dependency-version: 0.35.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: k8s.io/apiserver
  dependency-version: 0.35.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: k8s.io/cli-runtime
  dependency-version: 0.35.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: k8s.io/client-go
  dependency-version: 0.35.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: k8s.io/kubelet
  dependency-version: 0.35.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: k8s.io/metrics
  dependency-version: 0.35.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-24 16:07:27 -04:00
dependabot[bot]andlnx01 b4fd76a5e1 chore(deps): bump helm.sh/helm/v3 from 3.20.0 to 3.20.1 in /examples/sdk/helm-template in the security group (#1996)
chore(deps): bump helm.sh/helm/v3

Bumps the security group in /examples/sdk/helm-template with 1 update: [helm.sh/helm/v3](https://github.com/helm/helm).


Updates `helm.sh/helm/v3` from 3.20.0 to 3.20.1
- [Release notes](https://github.com/helm/helm/releases)
- [Commits](https://github.com/helm/helm/compare/v3.20.0...v3.20.1)

---
updated-dependencies:
- dependency-name: helm.sh/helm/v3
  dependency-version: 3.20.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-20 12:36:28 -04:00
dependabot[bot]andlnx01 11e06c7b37 chore(deps): bump google.golang.org/grpc from 1.77.0 to 1.79.3 (#1998)
Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.77.0 to 1.79.3.
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](https://github.com/grpc/grpc-go/compare/v1.77.0...v1.79.3)

---
updated-dependencies:
- dependency-name: google.golang.org/grpc
  dependency-version: 1.79.3
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-20 12:33:32 -04:00
dependabot[bot]andlnx01 af3e5ab501 chore(deps): bump dorny/paths-filter from 3 to 4 (#1994)
Bumps [dorny/paths-filter](https://github.com/dorny/paths-filter) from 3 to 4.
- [Release notes](https://github.com/dorny/paths-filter/releases)
- [Changelog](https://github.com/dorny/paths-filter/blob/master/CHANGELOG.md)
- [Commits](https://github.com/dorny/paths-filter/compare/v3...v4)

---
updated-dependencies:
- dependency-name: dorny/paths-filter
  dependency-version: '4'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-20 12:29:37 -04:00
dependabot[bot]andlnx01 3ded294ae8 chore(deps): bump the security group with 5 updates (#1995)
Bumps the security group with 5 updates:

| Package | From | To |
| --- | --- | --- |
| [github.com/hashicorp/go-getter](https://github.com/hashicorp/go-getter) | `1.8.4` | `1.8.5` |
| [golang.org/x/mod](https://github.com/golang/mod) | `0.33.0` | `0.34.0` |
| [golang.org/x/net](https://github.com/golang/net) | `0.51.0` | `0.52.0` |
| [golang.org/x/text](https://github.com/golang/text) | `0.34.0` | `0.35.0` |
| [helm.sh/helm/v3](https://github.com/helm/helm) | `3.20.0` | `3.20.1` |


Updates `github.com/hashicorp/go-getter` from 1.8.4 to 1.8.5
- [Release notes](https://github.com/hashicorp/go-getter/releases)
- [Commits](https://github.com/hashicorp/go-getter/compare/v1.8.4...v1.8.5)

Updates `golang.org/x/mod` from 0.33.0 to 0.34.0
- [Commits](https://github.com/golang/mod/compare/v0.33.0...v0.34.0)

Updates `golang.org/x/net` from 0.51.0 to 0.52.0
- [Commits](https://github.com/golang/net/compare/v0.51.0...v0.52.0)

Updates `golang.org/x/text` from 0.34.0 to 0.35.0
- [Release notes](https://github.com/golang/text/releases)
- [Commits](https://github.com/golang/text/compare/v0.34.0...v0.35.0)

Updates `helm.sh/helm/v3` from 3.20.0 to 3.20.1
- [Release notes](https://github.com/helm/helm/releases)
- [Commits](https://github.com/helm/helm/compare/v3.20.0...v3.20.1)

---
updated-dependencies:
- dependency-name: github.com/hashicorp/go-getter
  dependency-version: 1.8.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: golang.org/x/mod
  dependency-version: 0.34.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: golang.org/x/net
  dependency-version: 0.52.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: golang.org/x/text
  dependency-version: 0.35.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: helm.sh/helm/v3
  dependency-version: 3.20.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-20 12:29:08 -04:00
Andrew Lavery e8bf6435e4 add a '--metadata' flag to support-bundle (#1993)
* add a '--metadata' flag to support-bundle

* test the metadata flag e2e
2026-03-12 13:30:28 -04:00
dependabot[bot]andlnx01 9293164e4a chore(deps): bump rajatjindal/krew-release-bot from 0.0.47 to 0.0.51 (#1988)
Bumps [rajatjindal/krew-release-bot](https://github.com/rajatjindal/krew-release-bot) from 0.0.47 to 0.0.51.
- [Release notes](https://github.com/rajatjindal/krew-release-bot/releases)
- [Commits](https://github.com/rajatjindal/krew-release-bot/compare/v0.0.47...v0.0.51)

---
updated-dependencies:
- dependency-name: rajatjindal/krew-release-bot
  dependency-version: 0.0.51
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-12 12:45:52 -04:00
dependabot[bot]andlnx01 8cc1ac5a53 chore(deps): bump actions/download-artifact from 7 to 8 (#1984)
Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 7 to 8.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/v7...v8)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-version: '8'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-12 12:45:31 -04:00
dependabot[bot]andlnx01 800e46a84c chore(deps): bump actions/upload-artifact from 6 to 7 (#1983)
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 6 to 7.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-12 12:45:18 -04:00
dependabot[bot]andlnx01 18dd879b9c chore(deps): bump goreleaser/goreleaser-action from 6 to 7 (#1978)
Bumps [goreleaser/goreleaser-action](https://github.com/goreleaser/goreleaser-action) from 6 to 7.
- [Release notes](https://github.com/goreleaser/goreleaser-action/releases)
- [Commits](https://github.com/goreleaser/goreleaser-action/compare/v6...v7)

---
updated-dependencies:
- dependency-name: goreleaser/goreleaser-action
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-12 12:45:07 -04:00
replicated-ciandlnx01 743cb07002 Bump Go from 1.26.0 to 1.26.1 (#1987)
Bump Go to version from 1.26.0 to 1.26.1

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-03-12 12:44:29 -04:00
dependabot[bot]andlnx01 f5f1910cc4 chore(deps): bump the security group across 1 directory with 19 updates (#1989)
Bumps the security group with 15 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [github.com/cilium/ebpf](https://github.com/cilium/ebpf) | `0.20.0` | `0.21.0` |
| [github.com/microsoft/go-mssqldb](https://github.com/microsoft/go-mssqldb) | `1.9.6` | `1.9.8` |
| [github.com/shirou/gopsutil/v4](https://github.com/shirou/gopsutil) | `4.26.1` | `4.26.2` |
| [github.com/vmware-tanzu/velero](https://github.com/vmware-tanzu/velero) | `1.17.2` | `1.18.0` |
| [go.opentelemetry.io/otel](https://github.com/open-telemetry/opentelemetry-go) | `1.40.0` | `1.42.0` |
| [go.opentelemetry.io/otel/sdk](https://github.com/open-telemetry/opentelemetry-go) | `1.40.0` | `1.42.0` |
| [golang.org/x/sync](https://github.com/golang/sync) | `0.19.0` | `0.20.0` |
| [k8s.io/api](https://github.com/kubernetes/api) | `0.35.1` | `0.35.2` |
| [k8s.io/apiextensions-apiserver](https://github.com/kubernetes/apiextensions-apiserver) | `0.35.1` | `0.35.2` |
| [k8s.io/cli-runtime](https://github.com/kubernetes/cli-runtime) | `0.35.1` | `0.35.2` |
| [k8s.io/klog/v2](https://github.com/kubernetes/klog) | `2.130.1` | `2.140.0` |
| [sigs.k8s.io/controller-runtime](https://github.com/kubernetes-sigs/controller-runtime) | `0.23.1` | `0.23.3` |
| [golang.org/x/sys](https://github.com/golang/sys) | `0.41.0` | `0.42.0` |
| [k8s.io/kubelet](https://github.com/kubernetes/kubelet) | `0.35.1` | `0.35.2` |
| [k8s.io/metrics](https://github.com/kubernetes/metrics) | `0.35.1` | `0.35.2` |



Updates `github.com/cilium/ebpf` from 0.20.0 to 0.21.0
- [Release notes](https://github.com/cilium/ebpf/releases)
- [Commits](https://github.com/cilium/ebpf/compare/v0.20.0...v0.21.0)

Updates `github.com/microsoft/go-mssqldb` from 1.9.6 to 1.9.8
- [Release notes](https://github.com/microsoft/go-mssqldb/releases)
- [Changelog](https://github.com/microsoft/go-mssqldb/blob/main/CHANGELOG.md)
- [Commits](https://github.com/microsoft/go-mssqldb/compare/v1.9.6...v1.9.8)

Updates `github.com/shirou/gopsutil/v4` from 4.26.1 to 4.26.2
- [Release notes](https://github.com/shirou/gopsutil/releases)
- [Commits](https://github.com/shirou/gopsutil/compare/v4.26.1...v4.26.2)

Updates `github.com/vmware-tanzu/velero` from 1.17.2 to 1.18.0
- [Release notes](https://github.com/vmware-tanzu/velero/releases)
- [Changelog](https://github.com/vmware-tanzu/velero/blob/main/CHANGELOG.md)
- [Commits](https://github.com/vmware-tanzu/velero/compare/v1.17.2...v1.18.0)

Updates `go.opentelemetry.io/otel` from 1.40.0 to 1.42.0
- [Release notes](https://github.com/open-telemetry/opentelemetry-go/releases)
- [Changelog](https://github.com/open-telemetry/opentelemetry-go/blob/main/CHANGELOG.md)
- [Commits](https://github.com/open-telemetry/opentelemetry-go/compare/v1.40.0...v1.42.0)

Updates `go.opentelemetry.io/otel/sdk` from 1.40.0 to 1.42.0
- [Release notes](https://github.com/open-telemetry/opentelemetry-go/releases)
- [Changelog](https://github.com/open-telemetry/opentelemetry-go/blob/main/CHANGELOG.md)
- [Commits](https://github.com/open-telemetry/opentelemetry-go/compare/v1.40.0...v1.42.0)

Updates `golang.org/x/sync` from 0.19.0 to 0.20.0
- [Commits](https://github.com/golang/sync/compare/v0.19.0...v0.20.0)

Updates `k8s.io/api` from 0.35.1 to 0.35.2
- [Commits](https://github.com/kubernetes/api/compare/v0.35.1...v0.35.2)

Updates `k8s.io/apiextensions-apiserver` from 0.35.1 to 0.35.2
- [Release notes](https://github.com/kubernetes/apiextensions-apiserver/releases)
- [Commits](https://github.com/kubernetes/apiextensions-apiserver/compare/v0.35.1...v0.35.2)

Updates `k8s.io/apimachinery` from 0.35.1 to 0.35.2
- [Commits](https://github.com/kubernetes/apimachinery/compare/v0.35.1...v0.35.2)

Updates `k8s.io/apiserver` from 0.35.1 to 0.35.2
- [Commits](https://github.com/kubernetes/apiserver/compare/v0.35.1...v0.35.2)

Updates `k8s.io/cli-runtime` from 0.35.1 to 0.35.2
- [Commits](https://github.com/kubernetes/cli-runtime/compare/v0.35.1...v0.35.2)

Updates `k8s.io/client-go` from 0.35.1 to 0.35.2
- [Changelog](https://github.com/kubernetes/client-go/blob/master/CHANGELOG.md)
- [Commits](https://github.com/kubernetes/client-go/compare/v0.35.1...v0.35.2)

Updates `k8s.io/klog/v2` from 2.130.1 to 2.140.0
- [Release notes](https://github.com/kubernetes/klog/releases)
- [Changelog](https://github.com/kubernetes/klog/blob/main/RELEASE.md)
- [Commits](https://github.com/kubernetes/klog/compare/v2.130.1...2.140.0)

Updates `sigs.k8s.io/controller-runtime` from 0.23.1 to 0.23.3
- [Release notes](https://github.com/kubernetes-sigs/controller-runtime/releases)
- [Changelog](https://github.com/kubernetes-sigs/controller-runtime/blob/main/RELEASE.md)
- [Commits](https://github.com/kubernetes-sigs/controller-runtime/compare/v0.23.1...v0.23.3)

Updates `golang.org/x/net` from 0.50.0 to 0.51.0
- [Commits](https://github.com/golang/net/compare/v0.50.0...v0.51.0)

Updates `golang.org/x/sys` from 0.41.0 to 0.42.0
- [Commits](https://github.com/golang/sys/compare/v0.41.0...v0.42.0)

Updates `k8s.io/kubelet` from 0.35.1 to 0.35.2
- [Commits](https://github.com/kubernetes/kubelet/compare/v0.35.1...v0.35.2)

Updates `k8s.io/metrics` from 0.35.1 to 0.35.2
- [Commits](https://github.com/kubernetes/metrics/compare/v0.35.1...v0.35.2)

---
updated-dependencies:
- dependency-name: github.com/cilium/ebpf
  dependency-version: 0.21.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: github.com/microsoft/go-mssqldb
  dependency-version: 1.9.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: github.com/shirou/gopsutil/v4
  dependency-version: 4.26.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: github.com/vmware-tanzu/velero
  dependency-version: 1.18.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: go.opentelemetry.io/otel
  dependency-version: 1.42.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: go.opentelemetry.io/otel/sdk
  dependency-version: 1.42.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: golang.org/x/sync
  dependency-version: 0.20.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: k8s.io/api
  dependency-version: 0.35.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: k8s.io/apiextensions-apiserver
  dependency-version: 0.35.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: k8s.io/apimachinery
  dependency-version: 0.35.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: k8s.io/apiserver
  dependency-version: 0.35.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: k8s.io/cli-runtime
  dependency-version: 0.35.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: k8s.io/client-go
  dependency-version: 0.35.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: k8s.io/klog/v2
  dependency-version: 2.140.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: sigs.k8s.io/controller-runtime
  dependency-version: 0.23.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: golang.org/x/net
  dependency-version: 0.51.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: golang.org/x/sys
  dependency-version: 0.42.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: k8s.io/kubelet
  dependency-version: 0.35.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: k8s.io/metrics
  dependency-version: 0.35.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-12 12:44:07 -04:00
Andrew Lavery 94db56d668 add a dedicated support bundle metadata collector (#1992)
* add support bundle metadata collector

* add e2e test for the new collector

* make fmt

* properly include v1beta3

* remove the ability to specify an arbitrary secret
2026-03-12 12:38:45 -04:00
Ethan Mosbaugh 596a1f21a6 fix: add back collect binray, release docker image (#1991) 2026-03-11 10:51:19 -07:00
Martin Wunderlich cfe3849bff Issue 1980: timeout for supportbundle collect too short (#1986)
* Issue 1980 - Timeout for supportbundle collect too short

- leave default timeout at 30 seconds
- but: make configurable with SupportBundleOpts
- add timeout parameter to CLI flags
- add unit tests

* Issue 1980 - Timeout for supportbundle collect too short

- fix formatting
2026-03-10 16:52:34 -07:00
ada mancini 9030fff9d0 Add IngressClass analyzer (#1981)
* Add CLUSTER_RESOURCES_INGRESS_CLASS constant

* Collect IngressClass resources in cluster resources

* Add IngressClass analyzer API type

* Regenerate deepcopy for IngressClass type

* Update client-gen output from make generate

* Add IngressClass analyzer tests

* Implement IngressClass analyzer

* Register IngressClass analyzer in dispatcher

* Restore v1beta3 import in clientset scheme registration

The v1beta3 import was accidentally removed during client-gen
regeneration, causing a compile error since the SchemeBuilder
still references troubleshootv1beta3.AddToScheme.
2026-02-27 13:01:36 -05:00
dependabot[bot]andlnx01 87169eeb4b chore(deps): bump filippo.io/edwards25519 from 1.1.0 to 1.1.1 (#1977)
Bumps [filippo.io/edwards25519](https://github.com/FiloSottile/edwards25519) from 1.1.0 to 1.1.1.
- [Commits](https://github.com/FiloSottile/edwards25519/compare/v1.1.0...v1.1.1)

---
updated-dependencies:
- dependency-name: filippo.io/edwards25519
  dependency-version: 1.1.1
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-19 09:09:49 -05:00
967c0ffc99 chore(deps): bump the security group with 2 updates (#1976)
* chore(deps): bump the security group with 2 updates

Bumps the security group with 2 updates: [github.com/containerd/cgroups/v3](https://github.com/containerd/cgroups) and [go.podman.io/image/v5](https://github.com/containers/container-libs).


Updates `github.com/containerd/cgroups/v3` from 3.1.2 to 3.1.3
- [Release notes](https://github.com/containerd/cgroups/releases)
- [Commits](https://github.com/containerd/cgroups/compare/v3.1.2...v3.1.3)

Updates `go.podman.io/image/v5` from 5.38.0 to 5.39.1
- [Release notes](https://github.com/containers/container-libs/releases)
- [Commits](https://github.com/containers/container-libs/compare/image/v5.38.0...image/v5.39.1)

---
updated-dependencies:
- dependency-name: github.com/containerd/cgroups/v3
  dependency-version: 3.1.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: go.podman.io/image/v5
  dependency-version: 5.39.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
...

Signed-off-by: dependabot[bot] <support@github.com>

* return to go.podman.io/storage@main

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Andrew Lavery <laverya@umich.edu>
2026-02-19 09:08:51 -05:00
replicated-ciandlnx01 f221e02c39 Bump Go from 1.25.7 to 1.26.0 (#1975)
Bump Go to version from 1.25.7 to 1.26.0

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-02-19 08:33:32 -05:00
26869d06f0 chore(deps): bump the security group across 1 directory with 16 updates (#1974)
* chore(deps): bump the security group across 1 directory with 16 updates

Bumps the security group with 11 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [github.com/shirou/gopsutil/v4](https://github.com/shirou/gopsutil) | `4.25.12` | `4.26.1` |
| [go.opentelemetry.io/otel](https://github.com/open-telemetry/opentelemetry-go) | `1.39.0` | `1.40.0` |
| [go.opentelemetry.io/otel/sdk](https://github.com/open-telemetry/opentelemetry-go) | `1.39.0` | `1.40.0` |
| [go.podman.io/image/v5](https://github.com/containers/container-libs) | `5.38.0` | `5.39.1` |
| [golang.org/x/mod](https://github.com/golang/mod) | `0.32.0` | `0.33.0` |
| [k8s.io/api](https://github.com/kubernetes/api) | `0.35.0` | `0.35.1` |
| [k8s.io/apiextensions-apiserver](https://github.com/kubernetes/apiextensions-apiserver) | `0.35.0` | `0.35.1` |
| [k8s.io/cli-runtime](https://github.com/kubernetes/cli-runtime) | `0.35.0` | `0.35.1` |
| [golang.org/x/net](https://github.com/golang/net) | `0.49.0` | `0.50.0` |
| [k8s.io/kubelet](https://github.com/kubernetes/kubelet) | `0.35.0` | `0.35.1` |
| [k8s.io/metrics](https://github.com/kubernetes/metrics) | `0.35.0` | `0.35.1` |



Updates `github.com/shirou/gopsutil/v4` from 4.25.12 to 4.26.1
- [Release notes](https://github.com/shirou/gopsutil/releases)
- [Commits](https://github.com/shirou/gopsutil/compare/v4.25.12...v4.26.1)

Updates `go.opentelemetry.io/otel` from 1.39.0 to 1.40.0
- [Release notes](https://github.com/open-telemetry/opentelemetry-go/releases)
- [Changelog](https://github.com/open-telemetry/opentelemetry-go/blob/main/CHANGELOG.md)
- [Commits](https://github.com/open-telemetry/opentelemetry-go/compare/v1.39.0...v1.40.0)

Updates `go.opentelemetry.io/otel/sdk` from 1.39.0 to 1.40.0
- [Release notes](https://github.com/open-telemetry/opentelemetry-go/releases)
- [Changelog](https://github.com/open-telemetry/opentelemetry-go/blob/main/CHANGELOG.md)
- [Commits](https://github.com/open-telemetry/opentelemetry-go/compare/v1.39.0...v1.40.0)

Updates `go.podman.io/image/v5` from 5.38.0 to 5.39.1
- [Release notes](https://github.com/containers/container-libs/releases)
- [Commits](https://github.com/containers/container-libs/compare/image/v5.38.0...image/v5.39.1)

Updates `golang.org/x/mod` from 0.32.0 to 0.33.0
- [Commits](https://github.com/golang/mod/compare/v0.32.0...v0.33.0)

Updates `k8s.io/api` from 0.35.0 to 0.35.1
- [Commits](https://github.com/kubernetes/api/compare/v0.35.0...v0.35.1)

Updates `k8s.io/apiextensions-apiserver` from 0.35.0 to 0.35.1
- [Release notes](https://github.com/kubernetes/apiextensions-apiserver/releases)
- [Commits](https://github.com/kubernetes/apiextensions-apiserver/compare/v0.35.0...v0.35.1)

Updates `k8s.io/apimachinery` from 0.35.0 to 0.35.1
- [Commits](https://github.com/kubernetes/apimachinery/compare/v0.35.0...v0.35.1)

Updates `k8s.io/apiserver` from 0.35.0 to 0.35.1
- [Commits](https://github.com/kubernetes/apiserver/compare/v0.35.0...v0.35.1)

Updates `k8s.io/cli-runtime` from 0.35.0 to 0.35.1
- [Commits](https://github.com/kubernetes/cli-runtime/compare/v0.35.0...v0.35.1)

Updates `k8s.io/client-go` from 0.35.0 to 0.35.1
- [Changelog](https://github.com/kubernetes/client-go/blob/master/CHANGELOG.md)
- [Commits](https://github.com/kubernetes/client-go/compare/v0.35.0...v0.35.1)

Updates `golang.org/x/net` from 0.49.0 to 0.50.0
- [Commits](https://github.com/golang/net/compare/v0.49.0...v0.50.0)

Updates `golang.org/x/sys` from 0.40.0 to 0.41.0
- [Commits](https://github.com/golang/sys/compare/v0.40.0...v0.41.0)

Updates `golang.org/x/text` from 0.33.0 to 0.34.0
- [Release notes](https://github.com/golang/text/releases)
- [Commits](https://github.com/golang/text/compare/v0.33.0...v0.34.0)

Updates `k8s.io/kubelet` from 0.35.0 to 0.35.1
- [Commits](https://github.com/kubernetes/kubelet/compare/v0.35.0...v0.35.1)

Updates `k8s.io/metrics` from 0.35.0 to 0.35.1
- [Commits](https://github.com/kubernetes/metrics/compare/v0.35.0...v0.35.1)

---
updated-dependencies:
- dependency-name: github.com/shirou/gopsutil/v4
  dependency-version: 4.26.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: go.opentelemetry.io/otel
  dependency-version: 1.40.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: go.opentelemetry.io/otel/sdk
  dependency-version: 1.40.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: go.podman.io/image/v5
  dependency-version: 5.39.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: golang.org/x/mod
  dependency-version: 0.33.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: k8s.io/api
  dependency-version: 0.35.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: k8s.io/apiextensions-apiserver
  dependency-version: 0.35.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: k8s.io/apimachinery
  dependency-version: 0.35.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: k8s.io/apiserver
  dependency-version: 0.35.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: k8s.io/cli-runtime
  dependency-version: 0.35.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: k8s.io/client-go
  dependency-version: 0.35.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: golang.org/x/net
  dependency-version: 0.50.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: golang.org/x/sys
  dependency-version: 0.41.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: golang.org/x/text
  dependency-version: 0.34.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: k8s.io/kubelet
  dependency-version: 0.35.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: k8s.io/metrics
  dependency-version: 0.35.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
...

Signed-off-by: dependabot[bot] <support@github.com>

* revert update to go.podman.io/storage

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Xav Paice <xav@replicated.com>
2026-02-13 18:22:52 +13:00
replicated-ciandlnx01 01b6240e2e Bump Go from 1.25.5 to 1.25.7 (#1970)
Bump Go to version from 1.25.5 to 1.25.7

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-02-13 15:24:03 +13:00
dependabot[bot]andlnx01 1c576cd5d8 chore(deps): bump the security group across 1 directory with 5 updates (#1965)
Bumps the security group with 5 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [github.com/microsoft/go-mssqldb](https://github.com/microsoft/go-mssqldb) | `1.9.5` | `1.9.6` |
| [github.com/miekg/dns](https://github.com/miekg/dns) | `1.1.70` | `1.1.72` |
| [github.com/vmware-tanzu/velero](https://github.com/vmware-tanzu/velero) | `1.17.1` | `1.17.2` |
| [sigs.k8s.io/controller-runtime](https://github.com/kubernetes-sigs/controller-runtime) | `0.22.4` | `0.23.1` |
| [helm.sh/helm/v3](https://github.com/helm/helm) | `3.19.4` | `3.20.0` |



Updates `github.com/microsoft/go-mssqldb` from 1.9.5 to 1.9.6
- [Release notes](https://github.com/microsoft/go-mssqldb/releases)
- [Changelog](https://github.com/microsoft/go-mssqldb/blob/main/CHANGELOG.md)
- [Commits](https://github.com/microsoft/go-mssqldb/compare/v1.9.5...v1.9.6)

Updates `github.com/miekg/dns` from 1.1.70 to 1.1.72
- [Commits](https://github.com/miekg/dns/compare/v1.1.70...v1.1.72)

Updates `github.com/vmware-tanzu/velero` from 1.17.1 to 1.17.2
- [Release notes](https://github.com/vmware-tanzu/velero/releases)
- [Changelog](https://github.com/vmware-tanzu/velero/blob/main/CHANGELOG.md)
- [Commits](https://github.com/vmware-tanzu/velero/compare/v1.17.1...v1.17.2)

Updates `sigs.k8s.io/controller-runtime` from 0.22.4 to 0.23.1
- [Release notes](https://github.com/kubernetes-sigs/controller-runtime/releases)
- [Changelog](https://github.com/kubernetes-sigs/controller-runtime/blob/main/RELEASE.md)
- [Commits](https://github.com/kubernetes-sigs/controller-runtime/compare/v0.22.4...v0.23.1)

Updates `helm.sh/helm/v3` from 3.19.4 to 3.20.0
- [Release notes](https://github.com/helm/helm/releases)
- [Commits](https://github.com/helm/helm/compare/v3.19.4...v3.20.0)

---
updated-dependencies:
- dependency-name: github.com/microsoft/go-mssqldb
  dependency-version: 1.9.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: github.com/miekg/dns
  dependency-version: 1.1.72
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: github.com/vmware-tanzu/velero
  dependency-version: 1.17.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: sigs.k8s.io/controller-runtime
  dependency-version: 0.23.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: helm.sh/helm/v3
  dependency-version: 3.20.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-29 11:53:53 -05:00
dependabot[bot]andlnx01 203f3fc167 chore(deps): bump helm.sh/helm/v3 from 3.19.4 to 3.19.5 in /examples/sdk/helm-template in the security group (#1963)
chore(deps): bump helm.sh/helm/v3

Bumps the security group in /examples/sdk/helm-template with 1 update: [helm.sh/helm/v3](https://github.com/helm/helm).


Updates `helm.sh/helm/v3` from 3.19.4 to 3.19.5
- [Release notes](https://github.com/helm/helm/releases)
- [Commits](https://github.com/helm/helm/compare/v3.19.4...v3.19.5)

---
updated-dependencies:
- dependency-name: helm.sh/helm/v3
  dependency-version: 3.19.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-29 11:53:14 -05:00
ada mancini 73017ec48e feat: collect CertificateSigningRequests in clusterResources collector (#1964)
* Add .worktrees to .gitignore

Prevent worktree directories from being tracked in the repository.

* feat: collect CertificateSigningRequests in clusterResources collector

Add support for collecting CertificateSigningRequests (CSRs) from the
certificates.k8s.io/v1 API in the clusterResources collector.

Changes:
- Added certificateSigningRequests() helper function in cluster_resources.go
  following the existing pattern for other cluster-scoped resources
- Integrated CSR collection into the Collect() method between
  volumeAttachments and configMaps
- Added CLUSTER_RESOURCES_CERTIFICATE_SIGNING_REQUESTS constant
- Implemented fail-safe error handling for permission denied scenarios
  (e.g., managed clusters like EKS that may deny CSR access)

Testing:
- Added Test_CertificateSigningRequests() with table-driven tests for
  single and multiple CSR collection scenarios
- Added Test_CertificateSigningRequests_PermissionDenied() to verify
  fail-safe behavior when API access is forbidden
- All existing tests pass with no regressions

CSRs are saved to: cluster-resources/certificatesigningrequests.json
Errors are saved to: cluster-resources/certificatesigningrequests-errors.json

* style: run make fmt to align constant declarations

Formatting changes only - realigned constant declarations for
consistent spacing.

* fix: add .worktrees as separate line in .gitignore

The /support-bundle directory should remain ignored (for built
binaries), and /.worktrees/ should be added as a separate line.
2026-01-21 14:18:53 -05:00
06a8692de5 chore(deps): bump helm.sh/helm/v3 from 3.19.2 to 3.19.4 in /examples/sdk/helm-template in the security group (#1951)
chore(deps): bump helm.sh/helm/v3

Bumps the security group in /examples/sdk/helm-template with 1 update: [helm.sh/helm/v3](https://github.com/helm/helm).


Updates `helm.sh/helm/v3` from 3.19.2 to 3.19.4
- [Release notes](https://github.com/helm/helm/releases)
- [Commits](https://github.com/helm/helm/compare/v3.19.2...v3.19.4)

---
updated-dependencies:
- dependency-name: helm.sh/helm/v3
  dependency-version: 3.19.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Andrew Lavery <laverya@umich.edu>
2026-01-14 15:36:39 -05:00
Andrew Lavery a50bd612e8 use oras.land/oras-go/v2 (#1957) 2026-01-14 14:36:04 -06:00
dependabot[bot]andlnx01 d5b591d6f1 chore(deps): bump the security group across 1 directory with 3 updates (#1960)
Bumps the security group with 2 updates in the / directory: [golang.org/x/mod](https://github.com/golang/mod) and [golang.org/x/net](https://github.com/golang/net).


Updates `golang.org/x/mod` from 0.31.0 to 0.32.0
- [Commits](https://github.com/golang/mod/compare/v0.31.0...v0.32.0)

Updates `golang.org/x/net` from 0.48.0 to 0.49.0
- [Commits](https://github.com/golang/net/compare/v0.48.0...v0.49.0)

Updates `golang.org/x/text` from 0.32.0 to 0.33.0
- [Release notes](https://github.com/golang/text/releases)
- [Commits](https://github.com/golang/text/compare/v0.32.0...v0.33.0)

---
updated-dependencies:
- dependency-name: golang.org/x/mod
  dependency-version: 0.32.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: golang.org/x/net
  dependency-version: 0.49.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: golang.org/x/text
  dependency-version: 0.33.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-14 15:15:17 -05:00
dependabot[bot]andlnx01 ad8ad1bf74 chore(deps): bump actions/download-artifact from 5 to 7 (#1950)
Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 5 to 7.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/v5...v7)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-14 15:08:07 -05:00
dependabot[bot]andlnx01 083ec78491 chore(deps): bump actions/upload-artifact from 5 to 6 (#1949)
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 5 to 6.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-14 15:07:41 -05:00
Andrew Laveryandlnx01 bd102623eb Update modules (#1959)
* chore(deps): bump the security group across 1 directory with 27 updates

Bumps the security group with 16 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [github.com/containerd/cgroups/v3](https://github.com/containerd/cgroups) | `3.1.1` | `3.1.2` |
| [github.com/godbus/dbus/v5](https://github.com/godbus/dbus) | `5.2.0` | `5.2.2` |
| [github.com/hashicorp/go-getter](https://github.com/hashicorp/go-getter) | `1.8.3` | `1.8.4` |
| [github.com/jackc/pgx/v5](https://github.com/jackc/pgx) | `5.7.6` | `5.8.0` |
| [github.com/microsoft/go-mssqldb](https://github.com/microsoft/go-mssqldb) | `1.9.4` | `1.9.5` |
| [github.com/miekg/dns](https://github.com/miekg/dns) | `1.1.68` | `1.1.69` |
| [github.com/shirou/gopsutil/v4](https://github.com/shirou/gopsutil) | `4.25.10` | `4.25.12` |
| [github.com/spf13/cobra](https://github.com/spf13/cobra) | `1.10.1` | `1.10.2` |
| [golang.org/x/mod](https://github.com/golang/mod) | `0.30.0` | `0.31.0` |
| [k8s.io/api](https://github.com/kubernetes/api) | `0.34.2` | `0.35.0` |
| [k8s.io/apiextensions-apiserver](https://github.com/kubernetes/apiextensions-apiserver) | `0.34.2` | `0.35.0` |
| [k8s.io/cli-runtime](https://github.com/kubernetes/cli-runtime) | `0.34.2` | `0.35.0` |
| [k8s.io/kubernetes](https://github.com/kubernetes/kubernetes) | `1.34.2` | `1.35.0` |
| [helm.sh/helm/v3](https://github.com/helm/helm) | `3.19.0` | `3.19.4` |
| [k8s.io/kubelet](https://github.com/kubernetes/kubelet) | `0.34.2` | `0.35.0` |
| [k8s.io/metrics](https://github.com/kubernetes/metrics) | `0.34.2` | `0.35.0` |



Updates `github.com/containerd/cgroups/v3` from 3.1.1 to 3.1.2
- [Release notes](https://github.com/containerd/cgroups/releases)
- [Commits](https://github.com/containerd/cgroups/compare/v3.1.1...v3.1.2)

Updates `github.com/godbus/dbus/v5` from 5.2.0 to 5.2.2
- [Release notes](https://github.com/godbus/dbus/releases)
- [Commits](https://github.com/godbus/dbus/compare/v5.2.0...v5.2.2)

Updates `github.com/hashicorp/go-getter` from 1.8.3 to 1.8.4
- [Release notes](https://github.com/hashicorp/go-getter/releases)
- [Commits](https://github.com/hashicorp/go-getter/compare/v1.8.3...v1.8.4)

Updates `github.com/jackc/pgx/v5` from 5.7.6 to 5.8.0
- [Changelog](https://github.com/jackc/pgx/blob/master/CHANGELOG.md)
- [Commits](https://github.com/jackc/pgx/compare/v5.7.6...v5.8.0)

Updates `github.com/microsoft/go-mssqldb` from 1.9.4 to 1.9.5
- [Release notes](https://github.com/microsoft/go-mssqldb/releases)
- [Changelog](https://github.com/microsoft/go-mssqldb/blob/main/CHANGELOG.md)
- [Commits](https://github.com/microsoft/go-mssqldb/compare/v1.9.4...v1.9.5)

Updates `github.com/miekg/dns` from 1.1.68 to 1.1.69
- [Commits](https://github.com/miekg/dns/compare/v1.1.68...v1.1.69)

Updates `github.com/shirou/gopsutil/v4` from 4.25.10 to 4.25.12
- [Release notes](https://github.com/shirou/gopsutil/releases)
- [Commits](https://github.com/shirou/gopsutil/compare/v4.25.10...v4.25.12)

Updates `github.com/spf13/cobra` from 1.10.1 to 1.10.2
- [Release notes](https://github.com/spf13/cobra/releases)
- [Commits](https://github.com/spf13/cobra/compare/v1.10.1...v1.10.2)

Updates `go.opentelemetry.io/otel` from 1.38.0 to 1.39.0
- [Release notes](https://github.com/open-telemetry/opentelemetry-go/releases)
- [Changelog](https://github.com/open-telemetry/opentelemetry-go/blob/main/CHANGELOG.md)
- [Commits](https://github.com/open-telemetry/opentelemetry-go/compare/v1.38.0...v1.39.0)

Updates `go.opentelemetry.io/otel/sdk` from 1.38.0 to 1.39.0
- [Release notes](https://github.com/open-telemetry/opentelemetry-go/releases)
- [Changelog](https://github.com/open-telemetry/opentelemetry-go/blob/main/CHANGELOG.md)
- [Commits](https://github.com/open-telemetry/opentelemetry-go/compare/v1.38.0...v1.39.0)

Updates `golang.org/x/mod` from 0.30.0 to 0.31.0
- [Commits](https://github.com/golang/mod/compare/v0.30.0...v0.31.0)

Updates `golang.org/x/sync` from 0.18.0 to 0.19.0
- [Commits](https://github.com/golang/sync/compare/v0.18.0...v0.19.0)

Updates `k8s.io/api` from 0.34.2 to 0.35.0
- [Commits](https://github.com/kubernetes/api/compare/v0.34.2...v0.35.0)

Updates `k8s.io/apiextensions-apiserver` from 0.34.2 to 0.35.0
- [Release notes](https://github.com/kubernetes/apiextensions-apiserver/releases)
- [Commits](https://github.com/kubernetes/apiextensions-apiserver/compare/v0.34.2...v0.35.0)

Updates `k8s.io/apimachinery` from 0.34.2 to 0.35.0
- [Commits](https://github.com/kubernetes/apimachinery/compare/v0.34.2...v0.35.0)

Updates `k8s.io/apiserver` from 0.34.2 to 0.35.0
- [Commits](https://github.com/kubernetes/apiserver/compare/v0.34.2...v0.35.0)

Updates `k8s.io/cli-runtime` from 0.34.2 to 0.35.0
- [Commits](https://github.com/kubernetes/cli-runtime/compare/v0.34.2...v0.35.0)

Updates `k8s.io/client-go` from 0.34.2 to 0.35.0
- [Changelog](https://github.com/kubernetes/client-go/blob/master/CHANGELOG.md)
- [Commits](https://github.com/kubernetes/client-go/compare/v0.34.2...v0.35.0)

Updates `k8s.io/kubernetes` from 1.34.2 to 1.35.0
- [Release notes](https://github.com/kubernetes/kubernetes/releases)
- [Commits](https://github.com/kubernetes/kubernetes/compare/v1.34.2...v1.35.0)

Updates `github.com/hashicorp/go-version` from 1.7.0 to 1.8.0
- [Release notes](https://github.com/hashicorp/go-version/releases)
- [Changelog](https://github.com/hashicorp/go-version/blob/main/CHANGELOG.md)
- [Commits](https://github.com/hashicorp/go-version/compare/v1.7.0...v1.8.0)

Updates `golang.org/x/net` from 0.47.0 to 0.48.0
- [Commits](https://github.com/golang/net/compare/v0.47.0...v0.48.0)

Updates `golang.org/x/sys` from 0.38.0 to 0.39.0
- [Commits](https://github.com/golang/sys/compare/v0.38.0...v0.39.0)

Updates `golang.org/x/text` from 0.31.0 to 0.32.0
- [Release notes](https://github.com/golang/text/releases)
- [Commits](https://github.com/golang/text/compare/v0.31.0...v0.32.0)

Updates `helm.sh/helm/v3` from 3.19.0 to 3.19.4
- [Release notes](https://github.com/helm/helm/releases)
- [Commits](https://github.com/helm/helm/compare/v3.19.0...v3.19.4)

Updates `k8s.io/kubelet` from 0.34.2 to 0.35.0
- [Commits](https://github.com/kubernetes/kubelet/compare/v0.34.2...v0.35.0)

Updates `k8s.io/metrics` from 0.34.2 to 0.35.0
- [Commits](https://github.com/kubernetes/metrics/compare/v0.34.2...v0.35.0)

Updates `k8s.io/utils` from 0.0.0-20250604170112-4c0f3b243397 to 0.0.0-20251002143259-bc988d571ff4
- [Commits](https://github.com/kubernetes/utils/commits)

---
updated-dependencies:
- dependency-name: github.com/containerd/cgroups/v3
  dependency-version: 3.1.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: github.com/godbus/dbus/v5
  dependency-version: 5.2.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: github.com/hashicorp/go-getter
  dependency-version: 1.8.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: github.com/jackc/pgx/v5
  dependency-version: 5.8.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: github.com/microsoft/go-mssqldb
  dependency-version: 1.9.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: github.com/miekg/dns
  dependency-version: 1.1.69
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: github.com/shirou/gopsutil/v4
  dependency-version: 4.25.12
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: github.com/spf13/cobra
  dependency-version: 1.10.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: go.opentelemetry.io/otel
  dependency-version: 1.39.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: go.opentelemetry.io/otel/sdk
  dependency-version: 1.39.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: golang.org/x/mod
  dependency-version: 0.31.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: golang.org/x/sync
  dependency-version: 0.19.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: k8s.io/api
  dependency-version: 0.35.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: k8s.io/apiextensions-apiserver
  dependency-version: 0.35.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: k8s.io/apimachinery
  dependency-version: 0.35.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: k8s.io/apiserver
  dependency-version: 0.35.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: k8s.io/cli-runtime
  dependency-version: 0.35.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: k8s.io/client-go
  dependency-version: 0.35.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: k8s.io/kubernetes
  dependency-version: 1.35.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: github.com/hashicorp/go-version
  dependency-version: 1.8.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: golang.org/x/net
  dependency-version: 0.48.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: golang.org/x/sys
  dependency-version: 0.39.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: golang.org/x/text
  dependency-version: 0.32.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: helm.sh/helm/v3
  dependency-version: 3.19.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: k8s.io/kubelet
  dependency-version: 0.35.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: k8s.io/metrics
  dependency-version: 0.35.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: k8s.io/utils
  dependency-version: 0.0.0-20251002143259-bc988d571ff4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
...

Signed-off-by: dependabot[bot] <support@github.com>

* go get go.podman.io/storage@main

* go mod tidy

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-14 13:59:56 -06:00
Adam Wolfe GordonandAndrew Lavery 985416f20c Copy TaintExists to pkg/k8sutil and stop importing k8s.io/kubernetes (#1952)
Importing k8s.io/kubernetes causes any go modules that depend on this one to
have some issues. For example, the following happens in a module that depends on
troubleshoot:

```shell
$ go list -modfile=./go.mod -m -json -mod=mod all
go: k8s.io/cloud-provider@v0.0.0: invalid version: unknown revision v0.0.0
go: k8s.io/cluster-bootstrap@v0.0.0: invalid version: unknown revision v0.0.0
go: k8s.io/controller-manager@v0.0.0: invalid version: unknown revision v0.0.0
go: k8s.io/cri-client@v0.0.0: invalid version: unknown revision v0.0.0
go: k8s.io/csi-translation-lib@v0.0.0: invalid version: unknown revision v0.0.0
go: k8s.io/dynamic-resource-allocation@v0.0.0: invalid version: unknown revision v0.0.0
go: k8s.io/endpointslice@v0.0.0: invalid version: unknown revision v0.0.0
go: k8s.io/externaljwt@v0.0.0: invalid version: unknown revision v0.0.0
go: k8s.io/kube-controller-manager@v0.0.0: invalid version: unknown revision v0.0.0
go: k8s.io/kube-proxy@v0.0.0: invalid version: unknown revision v0.0.0
go: k8s.io/kube-scheduler@v0.0.0: invalid version: unknown revision v0.0.0
go: k8s.io/mount-utils@v0.0.0: invalid version: unknown revision v0.0.0
go: k8s.io/pod-security-admission@v0.0.0: invalid version: unknown revision v0.0.0
go: k8s.io/sample-apiserver@v0.0.0: invalid version: unknown revision v0.0.0
```

The only thing being used from k8s.io/kubernetes is a simple utility function,
`TaintExists`. Copy it into pkg/k8sutil to eliminate the need for the import.

Signed-off-by: Adam Wolfe Gordon <awg@upbound.io>
Co-authored-by: Andrew Lavery <laverya@umich.edu>
2026-01-14 14:40:33 -05:00
Andrew Lavery 128f9311fe move to go.podman.io dependencies (#1956)
* move to go.podman.io dependencies

* go fmt
2026-01-09 10:40:47 -08:00
Benjamin Yangandhedge-sparrow a9d2180dd6 102 redactor newline corruption clean (#1947)
* fix: prevent redactors from corrupting binary files (#102)

Redactors were adding newlines to files without them, corrupting binary
files during support bundle collection (51 bytes → 53 bytes).

Created LineReader to track original newline state and only restore
newlines when they were present in the original file.

- Added pkg/redact/line_reader.go
- Refactored single_line.go, multi_line.go, literal.go
- Added 48 tests, all passing
- Verified: binary files now preserved byte-for-byte

Fixes #102


* fix: handle empty lines correctly in MultiLineRedactor

- Check line1 == nil instead of len(line1) == 0 for empty file detection
- Fixes edge case where file containing only '\n' would be dropped
- Addresses bugbot finding about empty line handling


* fix: handle empty lines correctly in MultiLineRedactor

- Check line1 != nil instead of len(line1) > 0 in both locations
- Fixes edge case where empty trailing lines would be dropped
- Fix test isolation in literal_test.go (move ResetRedactionList to parent)
- Addresses bugbot findings about empty line handling

* fmt

* chore: update regression baselines from run 20107431959

* adding defense

* fix: propagate non-EOF errors in all early return paths

Ensure non-EOF errors (like buffer overflow) are properly propagated
to caller in both pre-loop early returns. Addresses bugbot finding.

* fix: use unique test names to prevent redaction list pollution

Use t.Name() instead of hardcoded 'test' to ensure each test
has unique redactor name, preventing parallel test interference

---------

Co-authored-by: hedge-sparrow <sparrow@spooky.academy>
2025-12-10 16:55:54 -06:00
b69a8a9b8c Bump Go from 1.25.4 to 1.25.5 (#1943)
Bump Go to version from 1.25.4 to 1.25.5

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Andrew Lavery <laverya@umich.edu>
2025-12-10 17:15:39 -05:00
ada mancini cf816f8e26 fix(discovery): handle partial results from ServerGroupsAndResources (#1944) 2025-12-10 10:33:37 -05:00
Xav Paice 8ed6dbf581 update multiple packages (#1937) 2025-12-02 14:45:18 +13:00
Ethan Mosbaugh 8c0be8fd74 chore(ci): regression test cursor feedback (#1938) 2025-12-01 12:57:57 -08:00
dependabot[bot]andlnx01 d3655fa1ab chore(deps): bump actions/checkout from 5 to 6 (#1933)
Bumps [actions/checkout](https://github.com/actions/checkout) from 5 to 6.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-28 10:29:43 +13:00
Ethan Mosbaugh 9343b43e77 fix(collect): cluster resource errors json file has wrong name (#1936)
* fix(ci): regression test updates binary to latest release
* fix cluster resources collector
2025-11-28 10:17:03 +13:00
Xav Paice e45e2cadd3 Fix collector ordering: preserve order when grouping by type (#1935)
- Fix issue where EnsureClusterResourcesFirst ordering was lost when
  collectors were grouped by type into a map (Go maps have random
  iteration order)
- Preserve collector type order by tracking collectorTypeOrder slice
  as collectors are added to the map
- Apply fix to both pkg/preflight/collect.go and
  pkg/supportbundle/collect.go
- Add comprehensive tests to verify clusterResources runs first and
  relative order of other collectors is preserved
- Enhance EnsureClusterResourcesFirst tests with additional edge cases
2025-11-26 15:34:17 +13:00
da51c28767 chore(deps): bump github.com/opencontainers/selinux from 1.12.0 to 1.13.0 (#1919)
* chore(deps): bump github.com/opencontainers/selinux

Bumps [github.com/opencontainers/selinux](https://github.com/opencontainers/selinux) from 1.12.0 to 1.13.0.
- [Release notes](https://github.com/opencontainers/selinux/releases)
- [Commits](https://github.com/opencontainers/selinux/compare/v1.12.0...v1.13.0)

---
updated-dependencies:
- dependency-name: github.com/opencontainers/selinux
  dependency-version: 1.13.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

* Fix go vet failure in CI on Linux

- Add go mod download before make vet in CI to ensure modules are available
- Remove vendor directory (not needed, was causing vendoring inconsistencies)
- Remove cache: false from all workflow files (not needed, enables caching)
- Add replace directive for filepath-securejoin to fix containers/storage build
- Clean up go.mod formatting and workflow improvements

* downgrade filepath-securejoin

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Xav Paice <xav@replicated.com>
2025-11-25 11:09:45 +13:00
Xav Paice c76b0ab333 update cluster creation action in regression-test.yaml (#1932) 2025-11-24 19:06:11 +13:00
dependabot[bot]andlnx01 5aa11c0e4b chore(deps): bump helm.sh/helm/v3 from 3.19.0 to 3.19.2 in /examples/sdk/helm-template in the security group (#1922)
chore(deps): bump helm.sh/helm/v3

Bumps the security group in /examples/sdk/helm-template with 1 update: [helm.sh/helm/v3](https://github.com/helm/helm).


Updates `helm.sh/helm/v3` from 3.19.0 to 3.19.2
- [Release notes](https://github.com/helm/helm/releases)
- [Commits](https://github.com/helm/helm/compare/v3.19.0...v3.19.2)

---
updated-dependencies:
- dependency-name: helm.sh/helm/v3
  dependency-version: 3.19.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-24 16:51:58 +13:00
dependabot[bot]andlnx01 af5bae315e chore(deps): bump golang.org/x/crypto from 0.42.0 to 0.45.0 in /examples/sdk/helm-template (#1926)
chore(deps): bump golang.org/x/crypto in /examples/sdk/helm-template

Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.42.0 to 0.45.0.
- [Commits](https://github.com/golang/crypto/compare/v0.42.0...v0.45.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-version: 0.45.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-24 16:19:54 +13:00
73ac499d3e Bump Go from 1.24.6 to 1.25.4 (#1930)
* Bump Go to version from 1.24.6 to 1.25.4

* fix: use net.JoinHostPort for IPv6 compatibility

Fix IPv6 address formatting in namespace-pinger.go by replacing
fmt.Sprintf with net.JoinHostPort, which correctly handles both
IPv4 and IPv6 addresses.

Changes:
- PingTCP: Use net.JoinHostPort for client connections
- startTCPEchoServer: Use net.JoinHostPort for server listener

This fixes go vet errors introduced by Go 1.25's stricter checks:
  address format "%s:%d" does not work with IPv6

IPv4 example: 192.168.1.1:8080
IPv6 example: [::1]:8080 (brackets added automatically)

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Nicholas Mullen <nwmullen@gmail.com>
2025-11-21 11:54:22 -06:00
Nicholas FernandesandAndrew Lavery aa13c2e31e chore(ci): add workflow to automate Go version updates (#1924)
* chore(ci): add workflow to automate Go version updates

Add GitHub Actions workflow using StefMa/Upgrade-Go-Action to
automatically check for new Go releases and create PRs to update
the go directive in go.mod.

This addresses the limitation that Dependabot cannot update the
Go version itself (only module dependencies), which means stdlib
CVEs that are fixed in newer Go patch releases are not automatically
detected.

Workflow runs:
- Weekly on Mondays at 8am UTC
- Manually via workflow_dispatch

When a new Go version is available, the action will:
1. Update the go directive in go.mod
2. Run go mod tidy
3. Create a pull request with the changes

Related: https://github.com/replicated-collab/git-guardian-kots/issues/287
Dependabot limitation: https://github.com/dependabot/dependabot-core/issues/9527

* test: add push trigger to test workflow

* chore: remove temporary push trigger

* test: add custom token and push trigger for testing

* test: trigger workflow again after cleaning up old branch

* chore: remove temporary push trigger

---------

Co-authored-by: Andrew Lavery <laverya@umich.edu>
2025-11-20 17:34:48 -06:00
dependabot[bot]andlnx01 52d910f615 chore(deps): bump golang.org/x/crypto from 0.43.0 to 0.45.0 (#1927)
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.43.0 to 0.45.0.
- [Commits](https://github.com/golang/crypto/compare/v0.43.0...v0.45.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-version: 0.45.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-20 12:07:11 -05:00
dependabot[bot]andlnx01 e9111edd47 chore(deps): bump github.com/containerd/containerd from 1.7.28 to 1.7.29 (#1918)
Bumps [github.com/containerd/containerd](https://github.com/containerd/containerd) from 1.7.28 to 1.7.29.
- [Release notes](https://github.com/containerd/containerd/releases)
- [Changelog](https://github.com/containerd/containerd/blob/main/RELEASES.md)
- [Commits](https://github.com/containerd/containerd/compare/v1.7.28...v1.7.29)

---
updated-dependencies:
- dependency-name: github.com/containerd/containerd
  dependency-version: 1.7.29
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-12 14:28:58 -05:00
dependabot[bot]andlnx01 68f736b02c chore(deps): bump the security group across 1 directory with 10 updates (#1920)
Bumps the security group with 8 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [github.com/cilium/ebpf](https://github.com/cilium/ebpf) | `0.19.0` | `0.20.0` |
| [github.com/containerd/cgroups/v3](https://github.com/containerd/cgroups) | `3.1.0` | `3.1.1` |
| [github.com/hashicorp/go-getter](https://github.com/hashicorp/go-getter) | `1.8.2` | `1.8.3` |
| [github.com/shirou/gopsutil/v4](https://github.com/shirou/gopsutil) | `4.25.9` | `4.25.10` |
| [github.com/vmware-tanzu/velero](https://github.com/vmware-tanzu/velero) | `1.17.0` | `1.17.1` |
| [golang.org/x/sync](https://github.com/golang/sync) | `0.17.0` | `0.18.0` |
| [sigs.k8s.io/controller-runtime](https://github.com/kubernetes-sigs/controller-runtime) | `0.22.3` | `0.22.4` |
| [golang.org/x/sys](https://github.com/golang/sys) | `0.37.0` | `0.38.0` |



Updates `github.com/cilium/ebpf` from 0.19.0 to 0.20.0
- [Release notes](https://github.com/cilium/ebpf/releases)
- [Commits](https://github.com/cilium/ebpf/compare/v0.19.0...v0.20.0)

Updates `github.com/containerd/cgroups/v3` from 3.1.0 to 3.1.1
- [Release notes](https://github.com/containerd/cgroups/releases)
- [Commits](https://github.com/containerd/cgroups/compare/v3.1.0...v3.1.1)

Updates `github.com/hashicorp/go-getter` from 1.8.2 to 1.8.3
- [Release notes](https://github.com/hashicorp/go-getter/releases)
- [Changelog](https://github.com/hashicorp/go-getter/blob/main/.goreleaser.yml)
- [Commits](https://github.com/hashicorp/go-getter/compare/v1.8.2...v1.8.3)

Updates `github.com/shirou/gopsutil/v4` from 4.25.9 to 4.25.10
- [Release notes](https://github.com/shirou/gopsutil/releases)
- [Commits](https://github.com/shirou/gopsutil/compare/v4.25.9...v4.25.10)

Updates `github.com/vmware-tanzu/velero` from 1.17.0 to 1.17.1
- [Release notes](https://github.com/vmware-tanzu/velero/releases)
- [Changelog](https://github.com/vmware-tanzu/velero/blob/main/CHANGELOG.md)
- [Commits](https://github.com/vmware-tanzu/velero/compare/v1.17.0...v1.17.1)

Updates `golang.org/x/sync` from 0.17.0 to 0.18.0
- [Commits](https://github.com/golang/sync/compare/v0.17.0...v0.18.0)

Updates `sigs.k8s.io/controller-runtime` from 0.22.3 to 0.22.4
- [Release notes](https://github.com/kubernetes-sigs/controller-runtime/releases)
- [Changelog](https://github.com/kubernetes-sigs/controller-runtime/blob/main/RELEASE.md)
- [Commits](https://github.com/kubernetes-sigs/controller-runtime/compare/v0.22.3...v0.22.4)

Updates `github.com/opencontainers/runtime-spec` from 1.2.1 to 1.3.0
- [Release notes](https://github.com/opencontainers/runtime-spec/releases)
- [Changelog](https://github.com/opencontainers/runtime-spec/blob/main/ChangeLog)
- [Commits](https://github.com/opencontainers/runtime-spec/compare/v1.2.1...v1.3.0)

Updates `golang.org/x/net` from 0.45.0 to 0.46.0
- [Commits](https://github.com/golang/net/compare/v0.45.0...v0.46.0)

Updates `golang.org/x/sys` from 0.37.0 to 0.38.0
- [Commits](https://github.com/golang/sys/compare/v0.37.0...v0.38.0)

---
updated-dependencies:
- dependency-name: github.com/cilium/ebpf
  dependency-version: 0.20.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: github.com/containerd/cgroups/v3
  dependency-version: 3.1.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: github.com/hashicorp/go-getter
  dependency-version: 1.8.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: github.com/shirou/gopsutil/v4
  dependency-version: 4.25.10
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: github.com/vmware-tanzu/velero
  dependency-version: 1.17.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: golang.org/x/sync
  dependency-version: 0.18.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: sigs.k8s.io/controller-runtime
  dependency-version: 0.22.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: github.com/opencontainers/runtime-spec
  dependency-version: 1.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: golang.org/x/net
  dependency-version: 0.46.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: golang.org/x/sys
  dependency-version: 0.38.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-12 14:14:19 -05:00
Nicholas Fernandes 40bb2e3a2a Fix incorrect field names in nodeResources example files (#1917)
The nodeResources filter examples incorrectly used `allocatableMemory`
instead of `memoryAllocatable`. This causes YAML parsing to silently
ignore the field, resulting in empty filter values and unexpected
analyzer behavior.

Changed in 3 files (5 instances total):
- examples/preflight/node-resources.yaml (3 instances)
- examples/preflight/e2e.yaml (1 instance)
- examples/support-bundle/e2e.yaml (1 instance)

The correct field names according to pkg/apis/troubleshoot/v1beta2/analyzer_shared.go
are:
- memoryAllocatable (not allocatableMemory)
- cpuAllocatable (not allocatableCPU)
- memoryCapacity (not capacityMemory)
- cpuCapacity (not capacityCPU)

This bug caused users copying from these examples to experience false
failures in preflight checks, as documented in the bug report where
a GKE cluster with 85Gi memory failed a check requiring only 8Gi.
2025-11-06 15:30:27 -06:00
Benjamin Yang cf2db49f86 applied native sidecar fix (#1914) 2025-11-04 11:30:42 -06:00
dependabot[bot]andlnx01 05a7a2092e chore(deps): bump actions/download-artifact from 4 to 6 (#1908)
Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 4 to 6.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/v4...v6)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-29 11:35:11 -07:00
dependabot[bot]andlnx01 e28dc8e080 chore(deps): bump the security group across 1 directory with 7 updates (#1912)
Bumps the security group with 4 updates in the / directory: [github.com/containerd/cgroups/v3](https://github.com/containerd/cgroups), [golang.org/x/mod](https://github.com/golang/mod), [oras.land/oras-go](https://github.com/oras-project/oras-go) and [sigs.k8s.io/controller-runtime](https://github.com/kubernetes-sigs/controller-runtime).


Updates `github.com/containerd/cgroups/v3` from 3.0.5 to 3.1.0
- [Release notes](https://github.com/containerd/cgroups/releases)
- [Commits](https://github.com/containerd/cgroups/compare/v3.0.5...v3.1.0)

Updates `golang.org/x/mod` from 0.28.0 to 0.29.0
- [Commits](https://github.com/golang/mod/compare/v0.28.0...v0.29.0)

Updates `oras.land/oras-go` from 1.2.6 to 1.2.7
- [Release notes](https://github.com/oras-project/oras-go/releases)
- [Commits](https://github.com/oras-project/oras-go/compare/v1.2.6...v1.2.7)

Updates `sigs.k8s.io/controller-runtime` from 0.22.2 to 0.22.3
- [Release notes](https://github.com/kubernetes-sigs/controller-runtime/releases)
- [Changelog](https://github.com/kubernetes-sigs/controller-runtime/blob/main/RELEASE.md)
- [Commits](https://github.com/kubernetes-sigs/controller-runtime/compare/v0.22.2...v0.22.3)

Updates `golang.org/x/net` from 0.44.0 to 0.45.0
- [Commits](https://github.com/golang/net/compare/v0.44.0...v0.45.0)

Updates `golang.org/x/sys` from 0.36.0 to 0.37.0
- [Commits](https://github.com/golang/sys/compare/v0.36.0...v0.37.0)

Updates `golang.org/x/text` from 0.29.0 to 0.30.0
- [Release notes](https://github.com/golang/text/releases)
- [Commits](https://github.com/golang/text/compare/v0.29.0...v0.30.0)

---
updated-dependencies:
- dependency-name: github.com/containerd/cgroups/v3
  dependency-version: 3.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: golang.org/x/mod
  dependency-version: 0.29.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: oras.land/oras-go
  dependency-version: 1.2.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: sigs.k8s.io/controller-runtime
  dependency-version: 0.22.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: security
- dependency-name: golang.org/x/net
  dependency-version: 0.45.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: golang.org/x/sys
  dependency-version: 0.37.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
- dependency-name: golang.org/x/text
  dependency-version: 0.30.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: security
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-29 11:24:06 -07:00
dependabot[bot]andlnx01 b9da850d65 chore(deps): bump actions/setup-go from 5 to 6 (#1899)
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 5 to 6.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](https://github.com/actions/setup-go/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-29 11:23:46 -07:00
dependabot[bot]andlnx01 0ecc72e86f chore(deps): bump actions/checkout from 4 to 5 (#1900)
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 5.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-29 11:23:31 -07:00
dependabot[bot]andlnx01 6d3a1a004e chore(deps): bump actions/setup-python from 5 to 6 (#1901)
Bumps [actions/setup-python](https://github.com/actions/setup-python) from 5 to 6.
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](https://github.com/actions/setup-python/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/setup-python
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-29 11:23:10 -07:00
dependabot[bot]andlnx01 e90a18fe0f chore(deps): bump actions/upload-artifact from 4 to 5 (#1909)
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4 to 5.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-29 11:22:47 -07:00
Ethan Mosbaugh de1e3f4936 chore(ci): skip regression-test workflow if dependabot (#1911) 2025-10-29 10:53:21 -07:00
Noah Campbell 8197ddecfe added --values and --set flags to lint command (#1907)
* added --values and --set flags to lint command

* Update lint_test.go
2025-10-23 13:20:21 -05:00
Noah Campbell 1ff21d1e7a Add Windows build (#1905)
add windows to goreleaser
2025-10-16 12:04:23 -05:00
Noah Campbell 2cebe3d8f6 Support bundle upload functionality works for apps installed via Helm (#1904)
* Gets licenseid and app slug from cluster secrets

* Update upload.go

* Update cluster_resources.go
2025-10-15 13:12:36 -05:00
Noah Campbell 6ffc83dc43 Updated linter (#1903)
* moved linter to new branch

* reads each yaml file separately when given multiple

* split monolith lint file into more reasonably sized files

* github action linter fix

* lint error codes follow the rest of the codebase's standard
2025-10-14 16:25:50 -05:00
Benjamin Yang 21dc4e9b09 Fix ollama windows installer (#1894)
* Fix Windows filename issue in scheduled support bundles

* Fix: Close temp file before executing Ollama installer on Windows

Windows requires files to be closed before they can be executed. This fix
ensures the temporary installer file is properly closed before attempting
to run it, preventing file access errors on Windows systems.
2025-10-14 10:51:52 -05:00
Noah Campbell 5aa088b3b6 Revert unintended commits on main 2025-10-13 15:23:31 -05:00
Noah Campbell 3f5ab9c721 doesnt harcode apiVersion line when looking and figures out which apiVersion to give if none is there 2025-10-13 15:18:43 -05:00
Noah Campbell 0316bb2e12 improved --fix capabilities 2025-10-13 15:18:33 -05:00
Noah Campbell a5f4afb488 added lint subcommand 2025-10-13 15:18:04 -05:00
Noah Campbell b7f499c737 Arbitrary secret key refs and templating in collectors (#1895)
* Uses secrets from cluster

* updated gitignore to stop ignoring needed files

* Delete specs.go.bak

* make fmt

* added preflight to generic loader

* Tells user to run in cluster if using secretKeyRef

* Update loader.go

* Update loader.go
2025-10-13 12:19:37 -05:00
Noah Campbell deab5e49a5 readded auto upload flag for support bundle (#1893)
* readded auto upload flag for support bundle

* updated auto upload message
2025-10-10 10:12:10 -07:00
Benjamin Yang df40c661a2 Fix windows cronjob (#1891)
* Fix Windows filename issue in scheduled support bundles

* fix bugbot
2025-10-10 10:24:48 -05:00
217 changed files with 18164 additions and 1995 deletions
+22
View File
@@ -0,0 +1,22 @@
# Code Review Guidelines
## Basic Review
- **Breaking API changes** — Check for removed/renamed fields in `pkg/apis/`, changed function signatures in public packages, or modified CLI flags and output formats.
- **Pattern violations** — New code should follow existing patterns in the codebase (e.g., collector/analyzer structure, error handling conventions, interface usage).
- **Security** — Watch for command injection in exec-based collectors, path traversal in file operations, unsanitized user input in specs, and leaked credentials in collected data.
- **Go standards** — Issues that linters like `go vet`, `staticcheck`, and `modernize` would catch: deprecated API usage, unnecessary allocations, error shadowing, unchecked errors.
- **Test coverage** — New functionality should have tests. Changes to existing code should not reduce coverage compared to the last test run on `main`.
- **Error handling** — Errors should wrap context (`fmt.Errorf("... : %w", err)`), not be silently swallowed, and provide actionable messages for operator-facing output.
- **Concurrency safety** — Collectors run concurrently. Shared state must be protected. `CollectorResult` map writes from goroutines need synchronization.
- **Bundle storage** — Collectors must save data using `CollectorResult.SaveResult` and related methods (`SaveResults`, `SymLinkResult`). Never write files directly — `CollectorResult` handles dual-mode storage (in-memory for preflights, on-disk for support bundles). See `pkg/collect/result.go`.
## Advanced Review
- **Cross-feature impact** — Consider whether a change to one collector/analyzer could affect the broader collection pipeline, redaction, or output archive structure.
- **CLI vs SDK consumers** — This project is consumed both as CLI tools and as Go packages (SDK). Changes targeting a CLI use case must not break SDK consumers who import `pkg/collect`, `pkg/analyze`, or API types directly.
- **Documentation** — Does the change add, modify, or remove user-facing behavior? Check whether https://troubleshoot.sh needs updates. Use https://troubleshoot.sh/llms.txt or https://troubleshoot.sh/llms-full.txt to review current docs.
- **Dedicated documentation needs** — For large or complex changes, consider whether CLI users or SDK consumers need standalone documentation (migration guides, new feature walkthroughs, updated examples).
- **Backwards compatibility** — Spec changes must consider existing specs in the wild. New fields should have sensible zero-value defaults. Removed fields should not cause parse failures.
- **Downstream impact on sbctl** — Changes to public Go packages (`pkg/collect`, `pkg/analyze`, API types, etc.) may require follow-up changes in [replicatedhq/sbctl](https://github.com/replicatedhq/sbctl), which imports this project as a dependency. Flag any breaking or behavioral changes that could affect sbctl.
- **Repository docs** — If your changes affect build commands, architecture, project conventions, or review guidelines, update `CLAUDE.md`, `README.md`, and this file accordingly.
+180
View File
@@ -0,0 +1,180 @@
schema_version: v1
name: dependency-update-troubleshoot
enabled: true
trigger:
cron:
schedule: "0 21 * * *"
timezone: "America/Chicago"
overlap_policy: skip
timeout: 2h
enable_manual_trigger: true
tags: ["cron", "dependencies"]
color: cyan
stages:
- id: start
label: Start
entry: true
on_enter:
inject: |
Workflow task: run the Go dependency update maintenance workflow for Troubleshoot.
This is an unattended dependency maintenance workflow. Scope: Go
dependency updates for the top-level go.mod/go.sum plus examples/sdk/helm-template. After updates
are applied, you will review the changes, fix any compatibility issues,
validate with make build and make test, and open one grouped PR.
Do not ask for permission to start. Immediately say exactly [PROCEED]
to run the dependency updater. Detailed post-update instructions will
follow.
- id: working
label: Working
triggers:
- message_contains: "[PROCEED]"
on_enter:
run:
command: |
bash -lc '
set -euo pipefail
if ! command -v go >/dev/null 2>&1; then
nix profile install nixpkgs#go_1_26 || nix-env -iA nixpkgs.go_1_26
fi
go_path="$(command -v go)"
go_version="$(go version)"
printf "{\"status\":\"ready\",\"go_path\":\"%s\",\"go_version\":\"%s\"}\n" "$go_path" "$go_version"
'
output: go_toolchain
timeout: 10m
dependency_updates:
ecosystems: [go]
paths: ["."]
output: dependency_updates
timeout: 30m
inject: |
Dependency updates were applied for the root Go module.
Scope this workflow to Go dependency updates only. Focus on the
top-level go.mod/go.sum. Exclude Node dependencies and any non-Go
modules.
Treat compatibility fixes as part of this workflow. If an updated
dependency causes build, lint, type, or test failures, first attempt
reasonable scoped code changes within the affected Go module to support
the new version. Do not downgrade, pin, or skip an update just because
it has breaking API changes unless the required changes are broad,
risky, unrelated to this workflow's scope, or cannot be completed within
reasonable effort. If you defer an update, explain exactly why.
Review {{ .Outputs.dependency_updates.files_changed }}.
Before opening a PR, validate using the repo make targets in the Nix
development environment (nix develop -c). Do not run ad-hoc go
commands; use exactly these targets:
- make build
- make test
Note: make test-integration requires a Kubernetes cluster. Only add it
to the validation if the workflow environment provides one.
Fix any failures and open one grouped PR.
Say [DONE] with the PR URL only when the PR is open.
If {{ .Outputs.dependency_updates.files_changed }} is empty and no PR is
needed, say [NO_CHANGES] instead of [DONE].
- id: no-changes
label: No Changes
triggers:
- message_contains: "[NO_CHANGES]"
- message_contains: "[DONE] No changes"
terminal: true
- id: validate
label: Validate
triggers:
- message_contains: "[DONE]"
on_enter:
run:
command: |
nix develop -c bash -lc '
set +e
tmpdir="$(mktemp -d)"
make build >"$tmpdir/build.log" 2>&1
build_status=$?
make test >"$tmpdir/test.log" 2>&1
test_status=$?
python3 - "$tmpdir" "$build_status" "$test_status" <<PY
import json
import pathlib
import sys
tmpdir = pathlib.Path(sys.argv[1])
statuses = {
"build": int(sys.argv[2]),
"test": int(sys.argv[3]),
}
checks = []
for name, code in statuses.items():
log = (tmpdir / f"{name}.log").read_text(errors="replace")
checks.append({
"name": name,
"status": "passed" if code == 0 else "failed",
"exit_code": code,
"log_tail": log[-12000:],
})
failed = [check for check in checks if check["exit_code"] != 0]
print(json.dumps({
"status": "passed" if not failed else "failed",
"reason": "all validation checks passed" if not failed else "one or more validation checks failed",
"checks": checks,
}))
PY
'
output: validation
timeout: 45m
gate:
output: validation
pass:
path: status
values: [passed]
fail:
path: status
values: [failed, error]
required: true
- id: fix-validation
label: Fix Validation
triggers:
- gate_result:
stage: validate
verdict: fail
on_enter:
inject: |
Validation failed before completion.
Status: {{ .Outputs.validation.status }}
Reason: {{ .Outputs.validation.reason }}
Checks:
{{ .Outputs.validation.checks }}
Fix the failures above, commit the changes to the same PR branch, and
say [DONE] with the PR URL again when the PR is ready for validation.
- id: complete
label: Complete
triggers:
- gate_result:
stage: validate
verdict: pass
terminal: true
-39
View File
@@ -1,39 +0,0 @@
name: 'Setup Go Environment'
description: 'Setup Go with caching and common environment variables'
inputs:
go-version-file:
description: 'Path to go.mod file'
required: false
default: 'go.mod'
outputs:
go-version:
description: 'The Go version that was installed'
value: ${{ steps.setup-go.outputs.go-version }}
cache-hit:
description: 'Whether the Go cache was hit'
value: ${{ steps.setup-go.outputs.cache-hit }}
runs:
using: 'composite'
steps:
- name: Setup Go
id: setup-go
uses: actions/setup-go@v5
with:
go-version-file: ${{ inputs.go-version-file }}
cache: true
- name: Set Go environment variables
shell: bash
run: |
echo "GOMAXPROCS=2" >> $GITHUB_ENV
echo "GOCACHE=$(go env GOCACHE)" >> $GITHUB_ENV
echo "GOMODCACHE=$(go env GOMODCACHE)" >> $GITHUB_ENV
- name: Print Go environment
shell: bash
run: |
echo "Go version: $(go version)"
echo "GOOS: $(go env GOOS)"
echo "GOARCH: $(go env GOARCH)"
echo "Cache directory: $(go env GOCACHE)"
echo "Module cache: $(go env GOMODCACHE)"
+31 -18
View File
@@ -30,8 +30,8 @@ jobs:
tidy-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/setup-go@v6
- uses: actions/checkout@v7
- uses: actions/setup-go@v7
with:
go-version-file: 'go.mod'
- run: make tidy-diff
@@ -39,8 +39,8 @@ jobs:
test-integration:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/setup-go@v6
- uses: actions/checkout@v7
- uses: actions/setup-go@v7
with:
go-version-file: 'go.mod'
- uses: replicatedhq/action-k3s@main
@@ -54,12 +54,12 @@ jobs:
compile-preflight:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/setup-go@v6
- uses: actions/checkout@v7
- uses: actions/setup-go@v7
with:
go-version-file: 'go.mod'
- run: make generate preflight
- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@v7
with:
name: preflight
path: bin/preflight
@@ -68,13 +68,13 @@ jobs:
runs-on: ubuntu-latest
needs: compile-preflight
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v7
- uses: replicatedhq/action-k3s@main
id: k3s
with:
version: v1.31.2-k3s1
- name: Download preflight binary
uses: actions/download-artifact@v5
uses: actions/download-artifact@v8
with:
name: preflight
path: bin/
@@ -84,27 +84,40 @@ jobs:
compile-supportbundle:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/setup-go@v6
- uses: actions/checkout@v7
- uses: actions/setup-go@v7
with:
go-version-file: 'go.mod'
- run: make generate support-bundle
- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@v7
with:
name: support-bundle
path: bin/support-bundle
compile-collect:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-go@v7
with:
go-version-file: 'go.mod'
- run: make generate collect
- uses: actions/upload-artifact@v7
with:
name: collect
path: bin/collect
validate-supportbundle-e2e:
runs-on: ubuntu-latest
needs: compile-supportbundle
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v7
- uses: replicatedhq/action-k3s@main
id: k3s
with:
version: v1.31.2-k3s1
- name: Download support bundle binary
uses: actions/download-artifact@v5
uses: actions/download-artifact@v8
with:
name: support-bundle
path: bin/
@@ -114,17 +127,17 @@ jobs:
# Additional e2e tests for support bundle that run in Go, these create a Kind cluster
validate-supportbundle-e2e-go:
runs-on: ubuntu-latest
needs: compile-supportbundle
needs: [compile-supportbundle, compile-collect, compile-preflight]
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v7
- name: Download support bundle binary
uses: actions/download-artifact@v5
uses: actions/download-artifact@v8
with:
name: support-bundle
path: bin/
- run: chmod +x bin/support-bundle
- name: Download preflight binary
uses: actions/download-artifact@v5
uses: actions/download-artifact@v8
with:
name: preflight
path: bin/
+148 -12
View File
@@ -21,8 +21,8 @@ jobs:
support-bundle: ${{ steps.filter.outputs.support-bundle }}
examples: ${{ steps.filter.outputs.examples }}
steps:
- uses: actions/checkout@v5
- uses: dorny/paths-filter@v3
- uses: actions/checkout@v7
- uses: dorny/paths-filter@v4
id: filter
with:
filters: |
@@ -44,8 +44,10 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v5
- uses: ./.github/actions/setup-go
- uses: actions/checkout@v7
- uses: actions/setup-go@v7
with:
go-version-file: 'go.mod'
- name: Check go mod tidy
run: |
@@ -71,8 +73,10 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v5
- uses: ./.github/actions/setup-go
- uses: actions/checkout@v7
- uses: actions/setup-go@v7
with:
go-version-file: 'go.mod'
- name: Setup K3s
uses: replicatedhq/action-k3s@main
@@ -89,15 +93,145 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v5
- uses: ./.github/actions/setup-go
- uses: actions/checkout@v7
- uses: actions/setup-go@v7
with:
go-version-file: 'go.mod'
- run: make build
- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@v7
with:
name: binaries
path: bin/
retention-days: 1
# Minimal linux architecture smoke tests
linux-arch-smoke:
if: needs.changes.outputs.go-files == 'true'
needs: [changes, lint]
runs-on: ubuntu-latest
timeout-minutes: 15
strategy:
fail-fast: false
matrix:
include:
- goarch: amd64
docker_platform: linux/amd64
expected_machine: x86_64
- goarch: arm64
docker_platform: linux/arm64
expected_machine: aarch64
- goarch: arm
goarm: "7"
docker_platform: linux/arm/v7
expected_machine: armv7l
- goarch: riscv64
docker_platform: linux/riscv64
expected_machine: riscv64
steps:
- uses: actions/checkout@v7
- uses: actions/setup-go@v7
with:
go-version-file: 'go.mod'
- name: Setup K3s
uses: replicatedhq/action-k3s@main
with:
version: v1.31.2-k3s1
- uses: docker/setup-qemu-action@v4
with:
platforms: arm64,arm,riscv64
- name: Build linux/${{ matrix.goarch }} binaries
env:
CGO_ENABLED: "0"
GOOS: linux
GOARCH: ${{ matrix.goarch }}
GOARM: ${{ matrix.goarm }}
run: |
if [ -n "${GOARM}" ]; then
echo "Building for GOARCH=${GOARCH} GOARM=${GOARM}"
else
echo "Building for GOARCH=${GOARCH}"
fi
make build
- name: Collect a minimal support bundle on ${{ matrix.docker_platform }}
env:
PREFLIGHT_AUTO_UPDATE: "false"
TROUBLESHOOT_AUTO_UPDATE: "false"
run: |
set -euo pipefail
tmpdir="$(mktemp -d)"
trap 'rm -rf "$tmpdir"' EXIT
kubeconfig_path="${KUBECONFIG:-$HOME/.kube/config}"
assert_tar_member() {
local pattern="$1"
local label="$2"
local member
member="$(grep -m1 "$pattern" "$tmpdir/archive-members.txt" || true)"
if [ -z "$member" ]; then
echo "Expected ${label} was not found in ${archive}"
exit 1
fi
echo "Found ${label}: ${member}"
}
echo "Using kubeconfig at ${kubeconfig_path}"
test -f "${kubeconfig_path}"
cp "${kubeconfig_path}" "$tmpdir/kubeconfig"
echo "Verifying K3s cluster is reachable on the host"
kubectl --kubeconfig "$tmpdir/kubeconfig" get nodes -o wide
docker run --rm \
--platform ${{ matrix.docker_platform }} \
--network host \
-v "$PWD:/src" \
-v "$tmpdir:/tmp/linux-arch-smoke" \
-w /src \
alpine:3.23 \
sh -ec '
export PREFLIGHT_AUTO_UPDATE=false
export TROUBLESHOOT_AUTO_UPDATE=false
/src/bin/support-bundle \
--kubeconfig /tmp/linux-arch-smoke/kubeconfig \
--interactive=false \
/src/test/e2e/support-bundle/spec/linuxArchSmokeLocalHostCollectors.yaml \
--output /tmp/linux-arch-smoke/linux-arch-support-bundle.tar.gz
'
archive="$tmpdir/linux-arch-support-bundle.tar.gz"
test -f "$archive"
echo "Generated support bundle archive: $archive"
tar -tf "$archive" > "$tmpdir/archive-members.txt"
assert_tar_member '/host-collectors/system/cpu.json$' 'cpu.json'
assert_tar_member '/host-collectors/system/memory.json$' 'memory.json'
assert_tar_member '/host-collectors/run-host/uname.txt$' 'uname.txt'
assert_tar_member '/cluster-resources/nodes.json$' 'cluster-resources nodes.json'
assert_tar_member '/cluster-resources/resources.json$' 'cluster-resources resources.json'
assert_tar_member '/analysis.json$' 'analysis.json'
echo "Checking uname -m output"
uname_path="$(grep -m1 '/host-collectors/run-host/uname.txt$' "$tmpdir/archive-members.txt")"
uname_machine="$(tar -xOf "$archive" "$uname_path" | tr -d '\r\n')"
if [ "$uname_machine" != '${{ matrix.expected_machine }}' ]; then
echo "Unexpected uname -m output: ${uname_machine}"
exit 1
fi
echo "Analyzer input check passed: uname -m reported ${uname_machine}"
echo "Checking analysis.json"
analysis_path="$(grep -m1 '/analysis.json$' "$tmpdir/archive-members.txt")"
tar -xOf "$archive" "$analysis_path" > "$tmpdir/analysis.json"
jq -e '
.[]
| select(.insight.primary == "Linux arch smoke node count")
| select(.insight.detail == "This cluster has exactly 1 node")
| select(.severity == "debug")
' "$tmpdir/analysis.json" >/dev/null
echo "Found expected analyzer result: Linux arch smoke node count -> This cluster has exactly 1 node"
# E2E tests
e2e:
if: needs.changes.outputs.go-files == 'true' || github.event_name == 'push'
@@ -118,7 +252,7 @@ jobs:
target: support-bundle-e2e-go-test
needs-k3s: false
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v7
- name: Setup K3s
if: matrix.needs-k3s
@@ -126,7 +260,7 @@ jobs:
with:
version: v1.31.2-k3s1
- uses: actions/download-artifact@v4
- uses: actions/download-artifact@v8
with:
name: binaries
path: bin/
@@ -137,7 +271,7 @@ jobs:
# Success summary
success:
if: always()
needs: [lint, test, build, e2e]
needs: [lint, test, build, linux-arch-smoke, e2e]
runs-on: ubuntu-latest
steps:
- name: Check results
@@ -146,6 +280,7 @@ jobs:
if [[ "${{ needs.lint.result }}" == "failure" ]] || \
[[ "${{ needs.test.result }}" == "failure" ]] || \
[[ "${{ needs.build.result }}" == "failure" ]] || \
[[ "${{ needs.linux-arch-smoke.result }}" == "failure" ]] || \
[[ "${{ needs.e2e.result }}" == "failure" ]]; then
echo "::error::Some jobs failed or were cancelled"
exit 1
@@ -155,6 +290,7 @@ jobs:
if [[ "${{ needs.lint.result }}" == "cancelled" ]] || \
[[ "${{ needs.test.result }}" == "cancelled" ]] || \
[[ "${{ needs.build.result }}" == "cancelled" ]] || \
[[ "${{ needs.linux-arch-smoke.result }}" == "cancelled" ]] || \
[[ "${{ needs.e2e.result }}" == "cancelled" ]]; then
echo "::error::Some jobs failed or were cancelled"
exit 1
+31
View File
@@ -0,0 +1,31 @@
name: Publish ElasticClaw Workflow
on:
push:
branches:
- main
paths:
- ".factory-workflows/dependency-update.yaml"
workflow_dispatch:
jobs:
publish:
name: Publish workflow (${{ matrix.workflow }})
runs-on: ubuntu-latest
permissions:
contents: read
strategy:
fail-fast: false
matrix:
workflow:
- .factory-workflows/dependency-update.yaml
steps:
- uses: actions/checkout@v7
- name: Publish workflow (dependency-update)
uses: elasticclaw/actions/publish-workflow@main
with:
hub-endpoint: https://factory.repldev.com
token: ${{ secrets.ELASTICCLAW_TOKEN }}
workspace: replicated-troubleshoot
path: ${{ matrix.workflow }}
+101
View File
@@ -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"
+338 -133
View File
@@ -13,44 +13,22 @@ on:
default: false
jobs:
regression-test:
# Build binaries once (shared by all test jobs)
build-binaries:
if: github.actor != 'dependabot[bot]'
runs-on: ubuntu-22.04
timeout-minutes: 25
timeout-minutes: 5
steps:
# 1. SETUP
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@v7
with:
fetch-depth: 0 # Fetch all history for git describe to work
- name: Create output directory
run: mkdir -p test/output
- name: Create k3s cluster
id: create-cluster
uses: replicatedhq/compatibility-actions/create-cluster@v1
with:
api-token: ${{ secrets.REPLICATED_API_TOKEN }}
kubernetes-distribution: k3s
cluster-name: regression-${{ github.run_id }}-${{ github.run_attempt }}
ttl: 25m
timeout-minutes: 5
- name: Configure kubeconfig
run: |
echo "${{ steps.create-cluster.outputs.cluster-kubeconfig }}" > $GITHUB_WORKSPACE/kubeconfig.yaml
echo "KUBECONFIG=$GITHUB_WORKSPACE/kubeconfig.yaml" >> $GITHUB_ENV
- name: Verify cluster access
run: kubectl get nodes -o wide
fetch-depth: 0
- name: Setup Go
uses: actions/setup-go@v5
uses: actions/setup-go@v7
with:
go-version-file: go.mod
cache: true
cache-dependency-path: go.sum
go-version-file: 'go.mod'
- name: Build binaries
run: |
@@ -59,84 +37,83 @@ jobs:
./bin/preflight version
./bin/support-bundle version
- name: Upload binaries
uses: actions/upload-artifact@v7
with:
name: binaries-${{ github.run_id }}
path: |
bin/preflight
bin/support-bundle
retention-days: 1
# Preflight v1beta3 test (parallel job 1)
test-preflight-v1beta3:
needs: [build-binaries]
if: github.actor != 'dependabot[bot]'
runs-on: ubuntu-22.04
timeout-minutes: 15
steps:
- name: Checkout code
uses: actions/checkout@v7
- name: Create output directory
run: mkdir -p test/output
- name: Create k3s cluster
uses: replicatedhq/action-k3s@main
with:
version: v1.31.2-k3s1
- name: Verify cluster access
run: kubectl get nodes -o wide
- name: Wait for all pods to be ready
run: |
echo "Waiting for all pods to be running..."
kubectl get pods --all-namespaces
kubectl wait --for=condition=Ready pods --all --all-namespaces --timeout=300s || true
kubectl get pods --all-namespaces
- name: Download binaries
uses: actions/download-artifact@v8
with:
name: binaries-${{ github.run_id }}
path: bin/
- name: Make binaries executable
run: |
chmod +x bin/preflight bin/support-bundle
./bin/preflight version
- name: Setup Python for comparison
uses: actions/setup-python@v5
uses: actions/setup-python@v7
with:
python-version: '3.11'
- name: Install Python dependencies
run: |
pip install pyyaml deepdiff
run: pip install pyyaml deepdiff
# 2. EXECUTE SPECS (in parallel)
- name: Run all specs in parallel
- name: Run preflight v1beta3
continue-on-error: true
run: |
echo "Running all 3 specs in parallel..."
echo "Running preflight v1beta3..."
./bin/preflight \
examples/preflight/complex-v1beta3.yaml \
--values examples/preflight/values-complex-full.yaml \
--interactive=false \
--format=json \
--auto-update=false \
--output=test/output/preflight-results-v1beta3.json 2>&1 | tee test/output/v1beta3.log || true
# Run v1beta3 in background
(
echo "Starting preflight v1beta3..."
./bin/preflight \
examples/preflight/complex-v1beta3.yaml \
--values examples/preflight/values-complex-full.yaml \
--interactive=false \
--format=json \
--output=test/output/preflight-results-v1beta3.json 2>&1 | tee test/output/v1beta3.log || true
BUNDLE=$(ls -t preflightbundle-*.tar.gz 2>/dev/null | head -1)
if [ -n "$BUNDLE" ]; then
mv "$BUNDLE" test/output/preflight-v1beta3-bundle.tar.gz
echo "✓ v1beta3 bundle saved"
fi
BUNDLE=$(ls -t preflightbundle-*.tar.gz 2>/dev/null | head -1)
if [ -n "$BUNDLE" ]; then
mv "$BUNDLE" test/output/preflight-v1beta3-bundle.tar.gz
echo "✓ v1beta3 bundle saved"
fi
) &
PID_V1BETA3=$!
# Run v1beta2 in background
(
echo "Starting preflight v1beta2..."
./bin/preflight \
examples/preflight/all-analyzers-v1beta2.yaml \
--interactive=false \
--format=json \
--output=test/output/preflight-results-v1beta2.json 2>&1 | tee test/output/v1beta2.log || true
BUNDLE=$(ls -t preflightbundle-*.tar.gz 2>/dev/null | head -1)
if [ -n "$BUNDLE" ]; then
mv "$BUNDLE" test/output/preflight-v1beta2-bundle.tar.gz
echo "✓ v1beta2 bundle saved"
fi
) &
PID_V1BETA2=$!
# Run support bundle in background
(
echo "Starting support bundle..."
./bin/support-bundle \
examples/collect/host/all-kubernetes-collectors.yaml \
--interactive=false \
--output=test/output/supportbundle.tar.gz 2>&1 | tee test/output/supportbundle.log || true
if [ -f test/output/supportbundle.tar.gz ]; then
echo "✓ Support bundle saved"
fi
) &
PID_SUPPORTBUNDLE=$!
# Wait for all to complete
echo "Waiting for all specs to complete..."
wait $PID_V1BETA3
wait $PID_V1BETA2
wait $PID_SUPPORTBUNDLE
echo "All specs completed!"
# Verify bundles exist
ls -lh test/output/*.tar.gz || echo "Warning: Some bundles may be missing"
# 3. COMPARE BUNDLES
- name: Compare preflight v1beta3 bundle
id: compare-v1beta3
id: compare
continue-on-error: true
run: |
echo "Comparing v1beta3 preflight bundle against baseline..."
@@ -153,8 +130,93 @@ jobs:
--report test/output/diff-report-v1beta3.json \
--spec-type preflight
- name: Upload test artifacts
if: ${{ !cancelled() }}
uses: actions/upload-artifact@v7
with:
name: test-results-v1beta3-${{ github.run_id }}-${{ github.run_attempt }}
path: |
test/output/preflight-v1beta3-bundle.tar.gz
test/output/preflight-results-v1beta3.json
test/output/diff-report-v1beta3.json
test/output/v1beta3.log
retention-days: 30
- name: Set job outcome
if: ${{ !cancelled() }}
run: |
if [ "${{ steps.compare.outcome }}" == "failure" ] && [ "${{ steps.compare.outputs.baseline_missing }}" != "true" ]; then
echo "comparison_failed=true" >> $GITHUB_OUTPUT
exit 1
fi
# Preflight v1beta2 test (parallel job 2)
test-preflight-v1beta2:
needs: [build-binaries]
if: github.actor != 'dependabot[bot]'
runs-on: ubuntu-22.04
timeout-minutes: 15
steps:
- name: Checkout code
uses: actions/checkout@v7
- name: Create output directory
run: mkdir -p test/output
- name: Create k3s cluster
uses: replicatedhq/action-k3s@main
with:
version: v1.31.2-k3s1
- name: Verify cluster access
run: kubectl get nodes -o wide
- name: Wait for all pods to be ready
run: |
echo "Waiting for all pods to be running..."
kubectl get pods --all-namespaces
kubectl wait --for=condition=Ready pods --all --all-namespaces --timeout=300s || true
kubectl get pods --all-namespaces
- name: Download binaries
uses: actions/download-artifact@v8
with:
name: binaries-${{ github.run_id }}
path: bin/
- name: Make binaries executable
run: |
chmod +x bin/preflight bin/support-bundle
./bin/preflight version
- name: Setup Python for comparison
uses: actions/setup-python@v7
with:
python-version: '3.11'
- name: Install Python dependencies
run: pip install pyyaml deepdiff
- name: Run preflight v1beta2
continue-on-error: true
run: |
echo "Running preflight v1beta2..."
./bin/preflight \
examples/preflight/all-analyzers-v1beta2.yaml \
--interactive=false \
--format=json \
--auto-update=false \
--output=test/output/preflight-results-v1beta2.json 2>&1 | tee test/output/v1beta2.log || true
BUNDLE=$(ls -t preflightbundle-*.tar.gz 2>/dev/null | head -1)
if [ -n "$BUNDLE" ]; then
mv "$BUNDLE" test/output/preflight-v1beta2-bundle.tar.gz
echo "✓ v1beta2 bundle saved"
fi
- name: Compare preflight v1beta2 bundle
id: compare-v1beta2
id: compare
continue-on-error: true
run: |
echo "Comparing v1beta2 preflight bundle against baseline..."
@@ -171,8 +233,90 @@ jobs:
--report test/output/diff-report-v1beta2.json \
--spec-type preflight
- name: Upload test artifacts
if: ${{ !cancelled() }}
uses: actions/upload-artifact@v7
with:
name: test-results-v1beta2-${{ github.run_id }}-${{ github.run_attempt }}
path: |
test/output/preflight-v1beta2-bundle.tar.gz
test/output/preflight-results-v1beta2.json
test/output/diff-report-v1beta2.json
test/output/v1beta2.log
retention-days: 30
- name: Set job outcome
if: ${{ !cancelled() }}
run: |
if [ "${{ steps.compare.outcome }}" == "failure" ] && [ "${{ steps.compare.outputs.baseline_missing }}" != "true" ]; then
echo "comparison_failed=true" >> $GITHUB_OUTPUT
exit 1
fi
# Support bundle test (parallel job 3)
test-supportbundle:
needs: [build-binaries]
if: github.actor != 'dependabot[bot]'
runs-on: ubuntu-22.04
timeout-minutes: 15
steps:
- name: Checkout code
uses: actions/checkout@v7
- name: Create output directory
run: mkdir -p test/output
- name: Create k3s cluster
uses: replicatedhq/action-k3s@main
with:
version: v1.31.2-k3s1
- name: Verify cluster access
run: kubectl get nodes -o wide
- name: Wait for all pods to be ready
run: |
echo "Waiting for all pods to be running..."
kubectl get pods --all-namespaces
kubectl wait --for=condition=Ready pods --all --all-namespaces --timeout=300s || true
kubectl get pods --all-namespaces
- name: Download binaries
uses: actions/download-artifact@v8
with:
name: binaries-${{ github.run_id }}
path: bin/
- name: Make binaries executable
run: |
chmod +x bin/preflight bin/support-bundle
./bin/support-bundle version
- name: Setup Python for comparison
uses: actions/setup-python@v7
with:
python-version: '3.11'
- name: Install Python dependencies
run: pip install pyyaml deepdiff
- name: Run support bundle
continue-on-error: true
run: |
echo "Running support bundle..."
./bin/support-bundle \
examples/collect/host/all-kubernetes-collectors.yaml \
--interactive=false \
--auto-update=false \
--output=test/output/supportbundle.tar.gz 2>&1 | tee test/output/supportbundle.log || true
if [ -f test/output/supportbundle.tar.gz ]; then
echo "✓ Support bundle saved"
fi
- name: Compare support bundle
id: compare-supportbundle
id: compare
continue-on-error: true
run: |
echo "Comparing support bundle against baseline..."
@@ -189,45 +333,116 @@ jobs:
--report test/output/diff-report-supportbundle.json \
--spec-type supportbundle
# 4. REPORT RESULTS
- name: Generate summary report
if: always()
run: |
python3 scripts/generate_summary.py \
--reports test/output/diff-report-*.json \
--output-file $GITHUB_STEP_SUMMARY \
--output-console
- name: Upload test artifacts
if: always()
uses: actions/upload-artifact@v4
if: ${{ !cancelled() }}
uses: actions/upload-artifact@v7
with:
name: regression-test-results-${{ github.run_id }}-${{ github.run_attempt }}
name: test-results-supportbundle-${{ github.run_id }}-${{ github.run_attempt }}
path: |
test/output/*.tar.gz
test/output/*.json
test/output/supportbundle.tar.gz
test/output/diff-report-supportbundle.json
test/output/supportbundle.log
retention-days: 30
- name: Set job outcome
if: ${{ !cancelled() }}
run: |
if [ "${{ steps.compare.outcome }}" == "failure" ] && [ "${{ steps.compare.outputs.baseline_missing }}" != "true" ]; then
echo "comparison_failed=true" >> $GITHUB_OUTPUT
exit 1
fi
# Report results (runs after all tests complete)
report-results:
needs: [test-preflight-v1beta3, test-preflight-v1beta2, test-supportbundle]
if: ${{ !cancelled() && github.actor != 'dependabot[bot]' }}
runs-on: ubuntu-22.04
timeout-minutes: 5
steps:
- name: Checkout code
uses: actions/checkout@v7
- name: Setup Python
uses: actions/setup-python@v7
with:
python-version: '3.11'
- name: Install Python dependencies
run: pip install pyyaml deepdiff
- name: Download all test artifacts
uses: actions/download-artifact@v8
with:
path: test/output
pattern: test-results-*
- name: Reorganize artifacts
run: |
# Move artifacts from nested directories to test/output
# Use shopt to handle glob patterns that don't match
shopt -s nullglob
for dir in test/output/test-results-*; do
if [ -d "$dir" ]; then
find "$dir" -type f -exec mv {} test/output/ \;
fi
done
# Clean up empty directories
for dir in test/output/test-results-*; do
if [ -d "$dir" ]; then
find "$dir" -type d -empty -delete || true
fi
done
shopt -u nullglob
- name: Generate summary report
run: |
# Handle case where no reports exist
shopt -s nullglob
REPORTS=(test/output/diff-report-*.json)
shopt -u nullglob
if [ ${#REPORTS[@]} -eq 0 ]; then
echo "⚠ No comparison reports found - test jobs may have failed before generating reports"
echo "## Summary Report" >> $GITHUB_STEP_SUMMARY
echo "No comparison reports available. Check individual test job results." >> $GITHUB_STEP_SUMMARY
else
python3 scripts/generate_summary.py \
--reports test/output/diff-report-*.json \
--output-file $GITHUB_STEP_SUMMARY \
--output-console
fi
- name: Check for regressions
if: always()
run: |
echo "Checking comparison results..."
# Check if any comparisons failed
FAILURES=0
if [ "${{ steps.compare-v1beta3.outcome }}" == "failure" ] && [ "${{ steps.compare-v1beta3.outputs.baseline_missing }}" != "true" ]; then
echo "❌ v1beta3 comparison failed"
if [ "${{ needs.test-preflight-v1beta3.result }}" == "failure" ] || [ "${{ needs.test-preflight-v1beta3.result }}" == "skipped" ]; then
if [ "${{ needs.test-preflight-v1beta3.result }}" == "skipped" ]; then
echo "❌ v1beta3 test was skipped (likely due to build failure)"
else
echo "❌ v1beta3 comparison failed"
fi
FAILURES=$((FAILURES + 1))
fi
if [ "${{ steps.compare-v1beta2.outcome }}" == "failure" ] && [ "${{ steps.compare-v1beta2.outputs.baseline_missing }}" != "true" ]; then
echo "❌ v1beta2 comparison failed"
if [ "${{ needs.test-preflight-v1beta2.result }}" == "failure" ] || [ "${{ needs.test-preflight-v1beta2.result }}" == "skipped" ]; then
if [ "${{ needs.test-preflight-v1beta2.result }}" == "skipped" ]; then
echo "❌ v1beta2 test was skipped (likely due to build failure)"
else
echo "❌ v1beta2 comparison failed"
fi
FAILURES=$((FAILURES + 1))
fi
if [ "${{ steps.compare-supportbundle.outcome }}" == "failure" ] && [ "${{ steps.compare-supportbundle.outputs.baseline_missing }}" != "true" ]; then
echo "❌ Support bundle comparison failed"
if [ "${{ needs.test-supportbundle.result }}" == "failure" ] || [ "${{ needs.test-supportbundle.result }}" == "skipped" ]; then
if [ "${{ needs.test-supportbundle.result }}" == "skipped" ]; then
echo "❌ Support bundle test was skipped (likely due to build failure)"
else
echo "❌ Support bundle comparison failed"
fi
FAILURES=$((FAILURES + 1))
fi
@@ -240,9 +455,8 @@ jobs:
echo "✅ All comparisons passed or skipped (no baseline)"
fi
# 5. UPDATE BASELINES (optional, manual trigger only)
- name: Update baselines
if: github.event.inputs.update_baselines == 'true' && github.event_name == 'workflow_dispatch'
if: ${{ !cancelled() && github.event.inputs.update_baselines == 'true' && github.event_name == 'workflow_dispatch' }}
run: |
echo "Updating baselines with current bundles..."
@@ -270,7 +484,7 @@ jobs:
{
"updated_at": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
"git_sha": "${{ github.sha }}",
"k8s_version": "v1.28.3",
"k8s_version": "v1.31.2-k3s1",
"workflow_run": "${{ github.run_id }}"
}
EOF
@@ -281,12 +495,3 @@ jobs:
git add test/baselines/
git commit -m "chore: update regression test baselines from run ${{ github.run_id }}"
git push
# 6. CLEANUP
- name: Remove cluster
if: always()
uses: replicatedhq/compatibility-actions/remove-cluster@v1
continue-on-error: true
with:
api-token: ${{ secrets.REPLICATED_API_TOKEN }}
cluster-id: ${{ steps.create-cluster.outputs.cluster-id }}
+32 -9
View File
@@ -14,21 +14,28 @@ jobs:
runs-on: troubleshoot_release
steps:
- name: Checkout
uses: actions/checkout@v5
uses: actions/checkout@v7
with:
fetch-depth: 0
- uses: azure/docker-login@v2
- uses: actions/setup-go@v7
with:
username: ${{ secrets.DOCKERHUB_USER }}
password: ${{ secrets.DOCKERHUB_PASSWORD }}
go-version: '1.26'
check-latest: true
- uses: actions/setup-go@v6
- name: Install Cosign
uses: sigstore/cosign-installer@v4.1.2
with:
go-version-file: 'go.mod'
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@v6
uses: goreleaser/goreleaser-action@v7
with:
version: "v2.12.3"
args: release --clean --config deploy/.goreleaser.yaml
@@ -37,12 +44,28 @@ jobs:
- name: Update new preflight version in krew-index
if: ${{ !contains(github.ref_name, '-') }}
uses: rajatjindal/krew-release-bot@v0.0.47
uses: rajatjindal/krew-release-bot@v0.0.51
with:
krew_template_file: deploy/krew/preflight.yaml
- name: Update new support-bundle version in krew-index
if: ${{ !contains(github.ref_name, '-') }}
uses: rajatjindal/krew-release-bot@v0.0.47
uses: rajatjindal/krew-release-bot@v0.0.51
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
with:
tag: ${{ github.ref_name }}
secrets:
slack_webhook: ${{ secrets.RELEASE_SLACK_WEBHOOK }}
+9 -4
View File
@@ -50,9 +50,14 @@ sbom/
!testdata/supportbundle/*.tar.gz
!test/baselines/**/baseline.tar.gz
# Ignore built binaries
troubleshoot
troubleshoot-test
# Ignore built binaries (use / prefix to avoid catching source files)
/troubleshoot
/troubleshoot-test
cmd/troubleshoot/troubleshoot
cmd/*/troubleshoot
support-bundle
/support-bundle
/.worktrees/
# IDEs
## IntelliJ / GoLand
/troubleshoot.iml
+4
View File
@@ -0,0 +1,4 @@
NAME INSTALLED FIXED-IN TYPE VULNERABILITY SEVERITY EPSS RISK PATH
{{- range .Matches}}
{{.Artifact.Name}} {{.Artifact.Version}} {{join .Vulnerability.Fix.Versions ","}} {{.Artifact.Type}} {{.Vulnerability.ID}} {{.Vulnerability.Severity}} {{.Vulnerability.EPSS}} {{.Vulnerability.Risk}} {{range .Artifact.Locations}}{{.AccessPath}}{{end}}
{{- end}}
+3
View File
@@ -0,0 +1,3 @@
exclude:
- ./examples/**
- ./bin/**
+3
View File
@@ -0,0 +1,3 @@
# AGENTS.md
ALWAYS read and follow the instructions in CLAUDE.md before starting any work in this repository.
+30
View File
@@ -0,0 +1,30 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Project Overview
Replicated Troubleshoot is a Kubernetes diagnostic framework providing two kubectl plugins: `preflight` (pre-installation cluster validation) and `support-bundle` (post-installation diagnostics with log collection, redaction, and analysis). Specs use the Kubernetes custom resource format (as a serialization convention, not installed in-cluster) and are defined by application vendors and executed by cluster operators.
## Build & Test Commands
```bash
make build # Build bin/support-bundle and bin/preflight
make test # Unit tests (includes generate, fmt, vet)
make test RUN=TestMyFunction # Run a single test
make test-integration # Integration tests (requires k8s cluster)
make e2e # All e2e tests
make generate # Regenerate types/clients after modifying pkg/apis/
```
## Architecture
The core data flow is: **Spec loading → Collection → Redaction → Analysis → Results**. The two main workflows are orchestrated by `pkg/supportbundle/` and `pkg/preflight/`.
Three API versions coexist in `pkg/apis/troubleshoot/`: v1beta1, v1beta2 (primary, all types defined here), and v1beta3 (in-progress, adds `StringOrValueFrom` for Secret/ConfigMap references, converts to v1beta2 at runtime).
Collectors live in `pkg/collect/`, analyzers in `pkg/analyze/`. When adding either, follow the pattern of existing implementations and run `make generate` after modifying API types.
## Code Review
See [.cursor/BUGBOT.md](.cursor/BUGBOT.md) for the full review checklist covering basic checks (API breaks, pattern violations, security, test coverage) and advanced checks (cross-feature impact, CLI vs SDK consumers, documentation needs).
+22 -35
View File
@@ -61,6 +61,9 @@ test: generate fmt vet
test-integration: generate fmt vet
go test -v --tags="integration exclude_graphdriver_devicemapper exclude_graphdriver_btrfs" ${BUILDPATHS}
.PHONY: e2e
e2e: preflight-e2e-test support-bundle-e2e-test support-bundle-e2e-go-test
.PHONY: preflight-e2e-test
preflight-e2e-test:
./test/validate-preflight-e2e.sh
@@ -149,16 +152,8 @@ vet:
.PHONY: generate
generate: controller-gen client-gen
$(CONTROLLER_GEN) \
object:headerFile=./hack/boilerplate.go.txt paths=./pkg/apis/...
$(CLIENT_GEN) \
--output-dir=. \
--output-pkg=github.com/replicatedhq/troubleshoot/pkg/client \
--clientset-name troubleshootclientset \
--input-base github.com/replicatedhq/troubleshoot/pkg/apis \
--input troubleshoot/v1beta1 \
--input troubleshoot/v1beta2 \
--go-header-file ./hack/boilerplate.go.txt
$(CONTROLLER_GEN) object:headerFile=./hack/boilerplate.go.txt paths=./pkg/apis/...
$(CLIENT_GEN) --output-dir=. --output-pkg=github.com/replicatedhq/troubleshoot/pkg/client --clientset-name troubleshootclientset --input-base github.com/replicatedhq/troubleshoot/pkg/apis --input troubleshoot/v1beta1 --input troubleshoot/v1beta2 --input troubleshoot/v1beta3 --go-header-file ./hack/boilerplate.go.txt
cp -r troubleshootclientset pkg/client
rm -rf troubleshootclientset
@@ -190,32 +185,18 @@ bin/docsgen:
controller-gen:
go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.19.0
CONTROLLER_GEN=$(shell which controller-gen)
CONTROLLER_GEN=$(shell go env GOPATH)/bin/controller-gen
.PHONY: client-gen
client-gen:
go install k8s.io/code-generator/cmd/client-gen@v0.34.0
CLIENT_GEN=$(shell which client-gen)
CLIENT_GEN=$(shell go env GOPATH)/bin/client-gen
.PHONY: release
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
@@ -251,17 +232,23 @@ 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
get-govulncheck:
@command -v govulncheck >/dev/null 2>&1 || go install golang.org/x/vuln/cmd/govulncheck@latest
.PHONY: get-grype
get-grype:
@command -v grype >/dev/null 2>&1 || curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b $(GOPATH)/bin
.PHONY: scan
scan:
trivy fs \
--scanners vuln \
--exit-code=1 \
--severity="HIGH,CRITICAL" \
--ignore-unfixed \
./
scan: get-govulncheck get-grype
govulncheck ./...
grype db update
grype dir:. --only-fixed --fail-on high -o template -t .grype.tmpl
.PHONY: watch
watch: npm-install
@@ -295,4 +282,4 @@ longhorn:
find pkg/longhorn -type f | xargs sed -i "s/github.com\/longhorn\/longhorn-manager\/k8s\/pkg/github.com\/replicatedhq\/troubleshoot\/pkg\/longhorn/g"
find pkg/longhorn -type f | xargs sed -i "s/github.com\/longhorn\/longhorn-manager\/types/github.com\/replicatedhq\/troubleshoot\/pkg\/longhorn\/types/g"
find pkg/longhorn -type f | xargs sed -i "s/github.com\/longhorn\/longhorn-manager\/util/github.com\/replicatedhq\/troubleshoot\/pkg\/longhorn\/util/g"
rm -rf longhorn-manager
rm -rf longhorn-manager
+3 -10
View File
@@ -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
```
+21
View File
@@ -0,0 +1,21 @@
package cli
import (
"errors"
"syscall"
"github.com/replicatedhq/troubleshoot/internal/util"
)
func checkAndSetChroot(newroot string) error {
if newroot == "" {
return nil
}
if !util.IsRunningAsRoot() {
return errors.New("Can only chroot when run as root")
}
if err := syscall.Chroot(newroot); err != nil {
return err
}
return nil
}
+21
View File
@@ -0,0 +1,21 @@
package cli
import (
"errors"
"syscall"
"github.com/replicatedhq/troubleshoot/internal/util"
)
func checkAndSetChroot(newroot string) error {
if newroot == "" {
return nil
}
if !util.IsRunningAsRoot() {
return errors.New("Can only chroot when run as root")
}
if err := syscall.Chroot(newroot); err != nil {
return err
}
return nil
}
+9
View File
@@ -0,0 +1,9 @@
package cli
import (
"errors"
)
func checkAndSetChroot(newroot string) error {
return errors.New("chroot is only implimented in linux/darwin")
}
+88
View File
@@ -0,0 +1,88 @@
package cli
import (
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
"github.com/replicatedhq/troubleshoot/pkg/collect"
"github.com/spf13/cobra"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
)
// ClickhouseCmd runs the clickhouse collector against a single database and
// prints the native result JSON ({"isConnected":..,"version":..,"error":..}).
func ClickhouseCmd() *cobra.Command {
var (
uri string
skipVerify bool
caCert string
clientCert string
clientKey string
secretName string
secretNamespace string
)
cmd := &cobra.Command{
Use: "clickhouse",
Short: "Run the clickhouse collector against a database",
Long: `Run the clickhouse collector: connect to a ClickHouse server, run "SELECT version()",
and print the collector result as JSON.
--uri is a clickhouse-go DSN:
clickhouse://user:password@host:9000/dbname
TLS material may be provided inline / by file path (--tls-cacert, --tls-client-cert,
--tls-client-key) or sourced from a Secret (--tls-secret-name), which requires
cluster access.
Example:
collect clickhouse --uri "clickhouse://default:@ch.default.svc:9000/default"`,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
db := &troubleshootv1beta2.Database{
CollectorMeta: troubleshootv1beta2.CollectorMeta{CollectorName: "clickhouse"},
URI: uri,
}
var (
client kubernetes.Interface
cfg *rest.Config
)
if skipVerify || caCert != "" || clientCert != "" || clientKey != "" || secretName != "" {
tls := &troubleshootv1beta2.TLSParams{
SkipVerify: skipVerify,
CACert: caCert,
ClientCert: clientCert,
ClientKey: clientKey,
}
if secretName != "" {
tls.Secret = &troubleshootv1beta2.TLSSecret{Name: secretName, Namespace: secretNamespace}
var err error
client, cfg, err = k8sClientForCollectors()
if err != nil {
return err
}
}
db.TLS = tls
}
c := &collect.CollectClickhouse{Collector: db, ClientConfig: cfg, Client: client, Context: cmd.Context()}
res, err := c.Collect(nil)
if err != nil {
return err
}
return printCollectorResult(res)
},
}
f := cmd.Flags()
f.StringVar(&uri, "uri", "", "ClickHouse connection DSN, e.g. clickhouse://user:pass@host:9000/db (required)")
cmd.MarkFlagRequired("uri")
f.BoolVar(&skipVerify, "tls-skip-verify", false, "skip TLS certificate verification")
f.StringVar(&caCert, "tls-cacert", "", "CA certificate (PEM contents or a file path)")
f.StringVar(&clientCert, "tls-client-cert", "", "client certificate (PEM contents or a file path)")
f.StringVar(&clientKey, "tls-client-key", "", "client key (PEM contents or a file path)")
f.StringVar(&secretName, "tls-secret-name", "", "name of a Secret holding TLS material (requires cluster access)")
f.StringVar(&secretNamespace, "tls-secret-namespace", "default", "namespace of the TLS Secret")
return cmd
}
+47
View File
@@ -0,0 +1,47 @@
// Package cli implements the `collect` command and its subcommands.
//
// The per-collector subcommands (http, postgres, mysql, mssql, redis) run a
// single collector and print its native result JSON to stdout. This lets a
// collector run inside a Pod using the troubleshoot image — e.g. as a runPod
// collector — so the check executes from within the cluster instead of from
// wherever the CLI happens to be invoked.
package cli
import (
"fmt"
"github.com/replicatedhq/troubleshoot/pkg/collect"
"github.com/replicatedhq/troubleshoot/pkg/constants"
"github.com/replicatedhq/troubleshoot/pkg/k8sutil"
"github.com/replicatedhq/troubleshoot/pkg/version"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
)
// printCollectorResult writes the native collector result JSON to stdout.
// The single-collector subcommands run with an empty BundlePath, so the result
// is held in memory (map value = the JSON bytes) rather than written to disk.
func printCollectorResult(res collect.CollectorResult) error {
for _, b := range res {
fmt.Println(string(b))
}
return nil
}
// k8sClientForCollectors builds a Kubernetes client from the ambient kubeconfig
// or in-cluster config. Only the collectors that resolve TLS material from a
// Secret need this; plain connections and inline/file TLS do not.
func k8sClientForCollectors() (kubernetes.Interface, *rest.Config, error) {
cfg, err := k8sutil.GetRESTConfig()
if err != nil {
return nil, nil, err
}
cfg.QPS = constants.DEFAULT_CLIENT_QPS
cfg.Burst = constants.DEFAULT_CLIENT_BURST
cfg.UserAgent = fmt.Sprintf("%s/%s", constants.DEFAULT_CLIENT_USER_AGENT, version.Version())
client, err := kubernetes.NewForConfig(cfg)
if err != nil {
return nil, nil, err
}
return client, cfg, nil
}
+79
View File
@@ -0,0 +1,79 @@
package cli
import (
"fmt"
"strings"
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
"github.com/replicatedhq/troubleshoot/pkg/collect"
"github.com/spf13/cobra"
)
// HTTPCmd runs the http collector against a single endpoint and prints the
// native result JSON ({"response":{"status":...}} or {"error":{...}}).
func HTTPCmd() *cobra.Command {
var (
method string
url string
headers map[string]string
body string
timeout string
proxy string
insecure bool
caCert string
)
cmd := &cobra.Command{
Use: "http",
Short: "Run the http collector against an endpoint",
Long: `Run the http collector: issue an HTTP request and print the collector result as JSON.
The result contains the response status, body and headers, or an error object.
Examples:
collect http --url http://myapp.default.svc:8080/healthz
collect http --method POST --url https://api.internal/ping \
--header 'Content-Type=application/json' --body '{"ping":true}'`,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
var tls *troubleshootv1beta2.TLSParams
if caCert != "" {
tls = &troubleshootv1beta2.TLSParams{CACert: caCert}
}
spec := &troubleshootv1beta2.HTTP{
CollectorMeta: troubleshootv1beta2.CollectorMeta{CollectorName: "http"},
}
switch strings.ToUpper(method) {
case "GET":
spec.Get = &troubleshootv1beta2.Get{URL: url, Headers: headers, Timeout: timeout, Proxy: proxy, InsecureSkipVerify: insecure, TLS: tls}
case "POST":
spec.Post = &troubleshootv1beta2.Post{URL: url, Headers: headers, Body: body, Timeout: timeout, Proxy: proxy, InsecureSkipVerify: insecure, TLS: tls}
case "PUT":
spec.Put = &troubleshootv1beta2.Put{URL: url, Headers: headers, Body: body, Timeout: timeout, Proxy: proxy, InsecureSkipVerify: insecure, TLS: tls}
default:
return fmt.Errorf("unsupported --method %q (use GET, POST, or PUT)", method)
}
c := &collect.CollectHTTP{Collector: spec}
res, err := c.Collect(nil)
if err != nil {
return err
}
return printCollectorResult(res)
},
}
f := cmd.Flags()
f.StringVar(&url, "url", "", "request URL (required)")
cmd.MarkFlagRequired("url")
f.StringVar(&method, "method", "GET", "HTTP method: GET, POST, or PUT")
f.StringToStringVar(&headers, "header", nil, "request header as key=value (repeatable)")
f.StringVar(&body, "body", "", "request body (POST/PUT only)")
f.StringVar(&timeout, "timeout", "", "request timeout, e.g. 15s (empty = no timeout)")
f.StringVar(&proxy, "proxy", "", "proxy URL to use for the request")
f.BoolVar(&insecure, "insecure-skip-verify", false, "do not verify the server's TLS certificate")
f.StringVar(&caCert, "tls-cacert", "", "CA certificate to trust (PEM contents or a file path)")
return cmd
}
+49
View File
@@ -0,0 +1,49 @@
package cli
import (
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
"github.com/replicatedhq/troubleshoot/pkg/collect"
"github.com/spf13/cobra"
)
// MssqlCmd runs the mssql collector against a single database and prints the
// native result JSON ({"isConnected":..,"version":..,"error":..}).
//
// Unlike the other database collectors, the mssql collector does not honor a
// separate TLS field — TLS is configured through the connection URI query
// parameters (e.g. encrypt=true) — so this subcommand only takes --uri.
func MssqlCmd() *cobra.Command {
var uri string
cmd := &cobra.Command{
Use: "mssql",
Short: "Run the mssql collector against a database",
Long: `Run the mssql collector: connect to a Microsoft SQL Server, run "select @@VERSION",
and print the collector result as JSON.
--uri is a go-mssqldb connection URL; TLS options are passed as query parameters:
sqlserver://user:password@host:1433?database=app&encrypt=true
Example:
collect mssql --uri "sqlserver://sa:pass@mssql.default.svc:1433?encrypt=true"`,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
db := &troubleshootv1beta2.Database{
CollectorMeta: troubleshootv1beta2.CollectorMeta{CollectorName: "mssql"},
URI: uri,
}
c := &collect.CollectMssql{Collector: db, Context: cmd.Context()}
res, err := c.Collect(nil)
if err != nil {
return err
}
return printCollectorResult(res)
},
}
cmd.Flags().StringVar(&uri, "uri", "", "SQL Server connection URI, e.g. sqlserver://user:pass@host:1433 (required)")
cmd.MarkFlagRequired("uri")
return cmd
}
+90
View File
@@ -0,0 +1,90 @@
package cli
import (
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
"github.com/replicatedhq/troubleshoot/pkg/collect"
"github.com/spf13/cobra"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
)
// MysqlCmd runs the mysql collector against a single database and prints the
// native result JSON ({"isConnected":..,"version":..,"variables":..,"error":..}).
func MysqlCmd() *cobra.Command {
var (
uri string
parameters []string
skipVerify bool
caCert string
clientCert string
clientKey string
secretName string
secretNamespace string
)
cmd := &cobra.Command{
Use: "mysql",
Short: "Run the mysql collector against a database",
Long: `Run the mysql collector: connect to a MySQL server, run "select version()",
optionally collect server variables, and print the collector result as JSON.
--uri is a go-sql-driver DSN (note: not a URL):
user:password@tcp(host:3306)/dbname
--parameters names server variables to collect via "SHOW VARIABLES"; the matching
values are returned under "variables" in the result. This flag is unique to mysql.
Example:
collect mysql --uri "root:pass@tcp(mysql.default.svc:3306)/" --parameters max_connections,version`,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
db := &troubleshootv1beta2.Database{
CollectorMeta: troubleshootv1beta2.CollectorMeta{CollectorName: "mysql"},
URI: uri,
Parameters: parameters,
}
var (
client kubernetes.Interface
cfg *rest.Config
)
if skipVerify || caCert != "" || clientCert != "" || clientKey != "" || secretName != "" {
tls := &troubleshootv1beta2.TLSParams{
SkipVerify: skipVerify,
CACert: caCert,
ClientCert: clientCert,
ClientKey: clientKey,
}
if secretName != "" {
tls.Secret = &troubleshootv1beta2.TLSSecret{Name: secretName, Namespace: secretNamespace}
var err error
client, cfg, err = k8sClientForCollectors()
if err != nil {
return err
}
}
db.TLS = tls
}
c := &collect.CollectMysql{Collector: db, ClientConfig: cfg, Client: client, Context: cmd.Context()}
res, err := c.Collect(nil)
if err != nil {
return err
}
return printCollectorResult(res)
},
}
f := cmd.Flags()
f.StringVar(&uri, "uri", "", "MySQL connection DSN, e.g. user:pass@tcp(host:3306)/db (required)")
cmd.MarkFlagRequired("uri")
f.StringSliceVar(&parameters, "parameters", nil, "server variables to collect via SHOW VARIABLES (comma-separated or repeatable)")
f.BoolVar(&skipVerify, "tls-skip-verify", false, "skip TLS certificate verification")
f.StringVar(&caCert, "tls-cacert", "", "CA certificate (PEM contents or a file path)")
f.StringVar(&clientCert, "tls-client-cert", "", "client certificate (PEM contents or a file path)")
f.StringVar(&clientKey, "tls-client-key", "", "client key (PEM contents or a file path)")
f.StringVar(&secretName, "tls-secret-name", "", "name of a Secret holding TLS material (requires cluster access)")
f.StringVar(&secretNamespace, "tls-secret-namespace", "default", "namespace of the TLS Secret")
return cmd
}
+88
View File
@@ -0,0 +1,88 @@
package cli
import (
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
"github.com/replicatedhq/troubleshoot/pkg/collect"
"github.com/spf13/cobra"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
)
// PostgresCmd runs the postgres collector against a single database and prints
// the native result JSON ({"isConnected":..,"version":..,"error":..}).
func PostgresCmd() *cobra.Command {
var (
uri string
skipVerify bool
caCert string
clientCert string
clientKey string
secretName string
secretNamespace string
)
cmd := &cobra.Command{
Use: "postgres",
Short: "Run the postgres collector against a database",
Long: `Run the postgres collector: connect to a PostgreSQL server, run "select version()",
and print the collector result as JSON.
--uri is a libpq/pgx connection URI:
postgres://user:password@host:5432/dbname?sslmode=disable
TLS material may be provided inline / by file path (--tls-cacert, --tls-client-cert,
--tls-client-key) or sourced from a Secret (--tls-secret-name), which requires
cluster access.
Example:
collect postgres --uri "postgres://user:pass@pg.default.svc:5432/app?sslmode=disable"`,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
db := &troubleshootv1beta2.Database{
CollectorMeta: troubleshootv1beta2.CollectorMeta{CollectorName: "postgres"},
URI: uri,
}
var (
client kubernetes.Interface
cfg *rest.Config
)
if skipVerify || caCert != "" || clientCert != "" || clientKey != "" || secretName != "" {
tls := &troubleshootv1beta2.TLSParams{
SkipVerify: skipVerify,
CACert: caCert,
ClientCert: clientCert,
ClientKey: clientKey,
}
if secretName != "" {
tls.Secret = &troubleshootv1beta2.TLSSecret{Name: secretName, Namespace: secretNamespace}
var err error
client, cfg, err = k8sClientForCollectors()
if err != nil {
return err
}
}
db.TLS = tls
}
c := &collect.CollectPostgres{Collector: db, ClientConfig: cfg, Client: client, Context: cmd.Context()}
res, err := c.Collect(nil)
if err != nil {
return err
}
return printCollectorResult(res)
},
}
f := cmd.Flags()
f.StringVar(&uri, "uri", "", "PostgreSQL connection URI (required)")
cmd.MarkFlagRequired("uri")
f.BoolVar(&skipVerify, "tls-skip-verify", false, "skip TLS certificate verification")
f.StringVar(&caCert, "tls-cacert", "", "CA certificate (PEM contents or a file path)")
f.StringVar(&clientCert, "tls-client-cert", "", "client certificate (PEM contents or a file path)")
f.StringVar(&clientKey, "tls-client-key", "", "client key (PEM contents or a file path)")
f.StringVar(&secretName, "tls-secret-name", "", "name of a Secret holding TLS material (requires cluster access)")
f.StringVar(&secretNamespace, "tls-secret-namespace", "default", "namespace of the TLS Secret")
return cmd
}
+89
View File
@@ -0,0 +1,89 @@
package cli
import (
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
"github.com/replicatedhq/troubleshoot/pkg/collect"
"github.com/spf13/cobra"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
)
// RedisCmd runs the redis collector against a single instance and prints the
// native result JSON ({"isConnected":..,"version":..,"error":..}).
func RedisCmd() *cobra.Command {
var (
uri string
skipVerify bool
caCert string
clientCert string
clientKey string
secretName string
secretNamespace string
)
cmd := &cobra.Command{
Use: "redis",
Short: "Run the redis collector against an instance",
Long: `Run the redis collector: connect to a Redis server, read "INFO server" (server
version), and print the collector result as JSON.
--uri is a go-redis connection URL:
redis://host:6379 (plaintext)
rediss://user:pass@host:6379 (TLS)
TLS material may be provided inline / by file path (--tls-cacert, --tls-client-cert,
--tls-client-key) or sourced from a Secret (--tls-secret-name), which requires
cluster access.
Example:
collect redis --uri "redis://redis.default.svc:6379"`,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
db := &troubleshootv1beta2.Database{
CollectorMeta: troubleshootv1beta2.CollectorMeta{CollectorName: "redis"},
URI: uri,
}
var (
client kubernetes.Interface
cfg *rest.Config
)
if skipVerify || caCert != "" || clientCert != "" || clientKey != "" || secretName != "" {
tls := &troubleshootv1beta2.TLSParams{
SkipVerify: skipVerify,
CACert: caCert,
ClientCert: clientCert,
ClientKey: clientKey,
}
if secretName != "" {
tls.Secret = &troubleshootv1beta2.TLSSecret{Name: secretName, Namespace: secretNamespace}
var err error
client, cfg, err = k8sClientForCollectors()
if err != nil {
return err
}
}
db.TLS = tls
}
c := &collect.CollectRedis{Collector: db, ClientConfig: cfg, Client: client, Context: cmd.Context()}
res, err := c.Collect(nil)
if err != nil {
return err
}
return printCollectorResult(res)
},
}
f := cmd.Flags()
f.StringVar(&uri, "uri", "", "Redis connection URL, e.g. redis://host:6379 (required)")
cmd.MarkFlagRequired("uri")
f.BoolVar(&skipVerify, "tls-skip-verify", false, "skip TLS certificate verification")
f.StringVar(&caCert, "tls-cacert", "", "CA certificate (PEM contents or a file path)")
f.StringVar(&clientCert, "tls-client-cert", "", "client certificate (PEM contents or a file path)")
f.StringVar(&clientKey, "tls-client-key", "", "client key (PEM contents or a file path)")
f.StringVar(&secretName, "tls-secret-name", "", "name of a Secret holding TLS material (requires cluster access)")
f.StringVar(&secretNamespace, "tls-secret-namespace", "default", "namespace of the TLS Secret")
return cmd
}
+103
View File
@@ -0,0 +1,103 @@
package cli
import (
"os"
"strings"
"github.com/replicatedhq/troubleshoot/cmd/internal/util"
"github.com/replicatedhq/troubleshoot/pkg/k8sutil"
"github.com/replicatedhq/troubleshoot/pkg/logger"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"k8s.io/klog/v2"
)
func RootCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "collect [url]",
Args: cobra.MinimumNArgs(1),
Short: "Run a collector",
Long: `Run a collector and output the results.`,
SilenceUsage: true,
// PersistentPreRun/PersistentPostRun (rather than PreRun/PostRun) so this
// setup also runs for the per-collector subcommands, not just `collect [url]`.
PersistentPreRun: func(cmd *cobra.Command, args []string) {
v := viper.GetViper()
v.BindPFlags(cmd.Flags())
logger.SetupLogger(v)
if err := util.StartProfiling(); err != nil {
klog.Errorf("Failed to start profiling: %v", err)
}
},
RunE: func(cmd *cobra.Command, args []string) error {
v := viper.GetViper()
if err := checkAndSetChroot(v.GetString("chroot")); err != nil {
return err
}
return runCollect(v, args[0])
},
PersistentPostRun: func(cmd *cobra.Command, args []string) {
if err := util.StopProfiling(); err != nil {
klog.Errorf("Failed to stop profiling: %v", err)
}
},
}
cobra.OnInitialize(initConfig)
cmd.AddCommand(util.VersionCmd())
// Per-collector subcommands: run a single collector and print its native
// result JSON. Each has its own flags and help. These let a collector run
// inside a Pod via the troubleshoot image (e.g. as a runPod collector), so
// the check executes from within the cluster rather than wherever the CLI runs.
cmd.AddCommand(HTTPCmd())
cmd.AddCommand(PostgresCmd())
cmd.AddCommand(MysqlCmd())
cmd.AddCommand(MssqlCmd())
cmd.AddCommand(RedisCmd())
cmd.AddCommand(ClickhouseCmd())
cmd.Flags().StringSlice("redactors", []string{}, "names of the additional redactors to use")
cmd.Flags().Bool("redact", true, "enable/disable default redactions")
cmd.Flags().String("format", "json", "output format, one of json or raw.")
cmd.Flags().String("collector-image", "", "the full name of the collector image to use")
cmd.Flags().String("collector-pull-policy", "", "the pull policy of the collector image")
cmd.Flags().String("selector", "", "selector (label query) to filter remote collection nodes on.")
cmd.Flags().Bool("collect-without-permissions", false, "always generate a support bundle, even if it some require additional permissions")
cmd.PersistentFlags().Bool("debug", false, "enable debug logging")
cmd.Flags().String("chroot", "", "Chroot to path")
// hidden in favor of the `insecure-skip-tls-verify` flag
cmd.Flags().Bool("allow-insecure-connections", false, "when set, do not verify TLS certs when retrieving spec and reporting results")
cmd.Flags().MarkHidden("allow-insecure-connections")
viper.BindPFlags(cmd.Flags())
viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_"))
k8sutil.AddFlags(cmd.PersistentFlags())
// Initialize klog flags
logger.InitKlogFlags(cmd)
// CPU and memory profiling flags
util.AddProfilingFlags(cmd)
return cmd
}
func InitAndExecute() {
if err := RootCmd().Execute(); err != nil {
os.Exit(1)
}
}
func initConfig() {
viper.SetEnvPrefix("TROUBLESHOOT")
viper.AutomaticEnv()
}
+189
View File
@@ -0,0 +1,189 @@
package cli
import (
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"os/signal"
"strings"
"time"
"github.com/pkg/errors"
"github.com/replicatedhq/troubleshoot/internal/util"
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
"github.com/replicatedhq/troubleshoot/pkg/client/troubleshootclientset/scheme"
"github.com/replicatedhq/troubleshoot/pkg/collect"
"github.com/replicatedhq/troubleshoot/pkg/docrewrite"
"github.com/replicatedhq/troubleshoot/pkg/k8sutil"
"github.com/replicatedhq/troubleshoot/pkg/specs"
"github.com/replicatedhq/troubleshoot/pkg/supportbundle"
"github.com/spf13/viper"
"k8s.io/apimachinery/pkg/labels"
)
const (
defaultTimeout = 30 * time.Second
)
func runCollect(v *viper.Viper, arg string) error {
go func() {
signalChan := make(chan os.Signal, 1)
signal.Notify(signalChan, os.Interrupt)
<-signalChan
os.Exit(0)
}()
var collectorContent []byte
var err error
if strings.HasPrefix(arg, "secret/") {
// format secret/namespace-name/secret-name
pathParts := strings.Split(arg, "/")
if len(pathParts) != 3 {
return errors.Errorf("path %s must have 3 components", arg)
}
spec, err := specs.LoadFromSecret(pathParts[1], pathParts[2], "collect-spec")
if err != nil {
return errors.Wrap(err, "failed to get spec from secret")
}
collectorContent = spec
} else if arg == "-" {
b, err := io.ReadAll(os.Stdin)
if err != nil {
return err
}
collectorContent = b
} else if _, err = os.Stat(arg); err == nil {
b, err := os.ReadFile(arg)
if err != nil {
return err
}
collectorContent = b
} else {
if !util.IsURL(arg) {
return fmt.Errorf("%s is not a URL and was not found", arg)
}
req, err := http.NewRequest("GET", arg, nil)
if err != nil {
return err
}
req.Header.Set("User-Agent", "Replicated_Collect/v1beta2")
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
collectorContent = body
}
collectorContent, err = docrewrite.ConvertToV1Beta2(collectorContent)
if err != nil {
return errors.Wrap(err, "failed to convert to v1beta2")
}
multidocs := strings.Split(string(collectorContent), "\n---\n")
decode := scheme.Codecs.UniversalDeserializer().Decode
redactors, err := supportbundle.GetRedactorsFromURIs(v.GetStringSlice("redactors"))
if err != nil {
return errors.Wrap(err, "failed to get redactors")
}
additionalRedactors := &troubleshootv1beta2.Redactor{
Spec: troubleshootv1beta2.RedactorSpec{
Redactors: redactors,
},
}
for i, additionalDoc := range multidocs {
if i == 0 {
continue
}
additionalDoc, err := docrewrite.ConvertToV1Beta2([]byte(additionalDoc))
if err != nil {
return errors.Wrap(err, "failed to convert to v1beta2")
}
obj, _, err := decode(additionalDoc, nil, nil)
if err != nil {
return errors.Wrapf(err, "failed to parse additional doc %d", i)
}
multidocRedactors, ok := obj.(*troubleshootv1beta2.Redactor)
if !ok {
continue
}
additionalRedactors.Spec.Redactors = append(additionalRedactors.Spec.Redactors, multidocRedactors.Spec.Redactors...)
}
// make sure we don't block any senders
progressCh := make(chan interface{})
defer close(progressCh)
go func() {
for range progressCh {
}
}()
restConfig, err := k8sutil.GetRESTConfig()
if err != nil {
return errors.Wrap(err, "failed to convert kube flags to rest config")
}
labelSelector, err := labels.Parse(v.GetString("selector"))
if err != nil {
return errors.Wrap(err, "unable to parse selector")
}
namespace := v.GetString("namespace")
if namespace == "" {
namespace = "default"
}
timeout := v.GetDuration("request-timeout")
if timeout == 0 {
timeout = defaultTimeout
}
createOpts := collect.CollectorRunOpts{
CollectWithoutPermissions: v.GetBool("collect-without-permissions"),
KubernetesRestConfig: restConfig,
Image: v.GetString("collector-image"),
PullPolicy: v.GetString("collector-pullpolicy"),
LabelSelector: labelSelector.String(),
Namespace: namespace,
Timeout: timeout,
ProgressChan: progressCh,
}
// we only support HostCollector or RemoteCollector kinds.
hostCollector, err := collect.ParseHostCollectorFromDoc([]byte(multidocs[0]))
if err == nil {
results, err := collect.CollectHost(hostCollector, additionalRedactors, createOpts)
if err != nil {
return errors.Wrap(err, "failed to collect from host")
}
return showHostStdoutResults(v.GetString("format"), hostCollector.Name, results)
}
remoteCollector, err := collect.ParseRemoteCollectorFromDoc([]byte(multidocs[0]))
if err == nil {
results, err := collect.CollectRemote(remoteCollector, additionalRedactors, createOpts)
if err != nil {
return errors.Wrap(err, "failed to collect from remote host(s)")
}
return showRemoteStdoutResults(v.GetString("format"), remoteCollector.Name, results)
}
return errors.New("failed to parse hostCollector or remoteCollector")
}
+103
View File
@@ -0,0 +1,103 @@
package cli
import (
"encoding/json"
"fmt"
"github.com/pkg/errors"
"github.com/replicatedhq/troubleshoot/pkg/collect"
)
const (
// FormatJSON is intended for CLI output.
FormatJSON = "json"
// FormatRaw is intended for consumption by a remote collector. Output is a
// string of quoted JSON.
FormatRaw = "raw"
)
func showHostStdoutResults(format string, collectName string, results *collect.HostCollectResult) error {
switch format {
case FormatJSON:
return showHostStdoutResultsJSON(collectName, results.AllCollectedData)
case FormatRaw:
return showHostStdoutResultsRaw(collectName, results.AllCollectedData)
default:
return errors.Errorf("unknown output format: %q", format)
}
}
func showRemoteStdoutResults(format string, collectName string, results *collect.RemoteCollectResult) error {
switch format {
case FormatJSON:
return showRemoteStdoutResultsJSON(collectName, results.AllCollectedData)
case FormatRaw:
return errors.Errorf("raw format not supported for remote collectors")
default:
return errors.Errorf("unknown output format: %q", format)
}
}
func showHostStdoutResultsJSON(collectName string, results map[string][]byte) error {
output := make(map[string]interface{})
for file, collectorResult := range results {
var collectedItems map[string]interface{}
if err := json.Unmarshal([]byte(collectorResult), &collectedItems); err != nil {
return errors.Wrap(err, "failed to marshal collector results")
}
output[file] = collectedItems
}
formatted, err := json.MarshalIndent(output, "", " ")
if err != nil {
return errors.Wrap(err, "failed to convert output to json")
}
fmt.Print(string(formatted))
return nil
}
// showHostStdoutResultsRaw outputs the collector output as a string of quoted json.
func showHostStdoutResultsRaw(collectName string, results map[string][]byte) error {
strData := map[string]string{}
for k, v := range results {
strData[k] = string(v)
}
formatted, err := json.MarshalIndent(strData, "", " ")
if err != nil {
return errors.Wrap(err, "failed to convert output to json")
}
fmt.Print(string(formatted))
return nil
}
func showRemoteStdoutResultsJSON(collectName string, results map[string][]byte) error {
type CollectorResult map[string]interface{}
type NodeResult map[string]CollectorResult
var output = make(map[string]NodeResult)
for node, result := range results {
var nodeResult map[string]string
if err := json.Unmarshal(result, &nodeResult); err != nil {
return errors.Wrap(err, "failed to marshal node results")
}
nr := make(NodeResult)
for file, collectorResult := range nodeResult {
var collectedItems map[string]interface{}
if err := json.Unmarshal([]byte(collectorResult), &collectedItems); err != nil {
return errors.Wrap(err, "failed to marshal collector results")
}
nr[file] = collectedItems
}
output[node] = nr
}
formatted, err := json.MarshalIndent(output, "", " ")
if err != nil {
return errors.Wrap(err, "failed to convert output to json")
}
fmt.Print(string(formatted))
return nil
}
+10
View File
@@ -0,0 +1,10 @@
package main
import (
"github.com/replicatedhq/troubleshoot/cmd/collect/cli"
_ "k8s.io/client-go/plugin/pkg/client/auth"
)
func main() {
cli.InitAndExecute()
}
+1 -20
View File
@@ -88,7 +88,7 @@ func extractDocs(templateFiles []string, valuesFiles []string, setValues []strin
if err != nil {
return errors.Wrapf(err, "failed to load values file %s", valuesFile)
}
values = mergeMaps(values, fileValues)
values = preflight.MergeMaps(values, fileValues)
}
// Normalize maps for Helm set merging
@@ -331,25 +331,6 @@ func setNestedValue(m map[string]interface{}, keys []string, value interface{})
}
}
func mergeMaps(base, overlay map[string]interface{}) map[string]interface{} {
result := make(map[string]interface{})
for k, v := range base {
result[k] = v
}
for k, v := range overlay {
if baseVal, exists := result[k]; exists {
if baseMap, ok := baseVal.(map[string]interface{}); ok {
if overlayMap, ok := v.(map[string]interface{}); ok {
result[k] = mergeMaps(baseMap, overlayMap)
continue
}
}
}
result[k] = v
}
return result
}
func renderTemplate(templateContent string, values map[string]interface{}) (string, error) {
tmpl := template.New("preflight").Funcs(sprig.FuncMap())
tmpl, err := tmpl.Parse(templateContent)
+100
View File
@@ -0,0 +1,100 @@
package cli
import (
"fmt"
"os"
"github.com/pkg/errors"
"github.com/replicatedhq/troubleshoot/pkg/constants"
"github.com/replicatedhq/troubleshoot/pkg/lint"
"github.com/replicatedhq/troubleshoot/pkg/types"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
func LintCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "lint [spec-files...]",
Args: cobra.MinimumNArgs(1),
Short: "Lint v1beta2/v1beta3 preflight specs for syntax and structural errors",
Long: `Lint v1beta2/v1beta3 preflight specs for syntax and structural errors.
This command validates v1beta2/v1beta3 preflight specs and checks for:
- YAML syntax errors
- Missing required fields (apiVersion, kind, metadata, spec)
- Invalid template syntax ({{ .Values.* }})
- Missing analyzers or collectors
- Common structural issues
- Missing docStrings (warning)
Examples:
# Lint a single spec file
preflight lint my-preflight.yaml
# Lint multiple spec files
preflight lint spec1.yaml spec2.yaml spec3.yaml
# Lint with automatic fixes
preflight lint --fix my-preflight.yaml
# Lint and output as JSON for CI/CD integration
preflight lint --format json my-preflight.yaml
Notes:
- v1beta2 does not support templating; template syntax in v1beta2 files will be flagged as errors.
- v1beta3 supports templating and is linted with template-awareness.
Exit codes:
0 - No errors found
2 - Validation errors found`,
PreRun: func(cmd *cobra.Command, args []string) {
viper.BindPFlags(cmd.Flags())
},
RunE: func(cmd *cobra.Command, args []string) error {
v := viper.GetViper()
opts := lint.LintOptions{
FilePaths: args,
Fix: v.GetBool("fix"),
Format: v.GetString("format"),
ValuesFiles: v.GetStringSlice("values"),
SetValues: v.GetStringSlice("set"),
}
return runLint(opts)
},
}
cmd.Flags().Bool("fix", false, "Automatically fix issues where possible")
cmd.Flags().String("format", "text", "Output format: text or json")
cmd.Flags().StringSlice("values", []string{}, "Path to YAML files with template values (required for v1beta3 specs)")
cmd.Flags().StringSlice("set", []string{}, "Set template values via command line (e.g., --set key=value)")
return cmd
}
func runLint(opts lint.LintOptions) error {
// Validate file paths exist
for _, filePath := range opts.FilePaths {
if _, err := os.Stat(filePath); err != nil {
return errors.Wrapf(err, "file not found: %s", filePath)
}
}
// Run linting
results, err := lint.LintFiles(opts)
if err != nil {
return errors.Wrap(err, "failed to lint files")
}
// Format and print results
output := lint.FormatResults(results, opts.Format)
fmt.Print(output)
// Return appropriate exit code
if lint.HasErrors(results) {
return types.NewExitCodeError(constants.EXIT_CODE_SPEC_ISSUES, nil)
}
return nil
}
+8 -1
View File
@@ -25,7 +25,13 @@ func RootCmd() *cobra.Command {
Args: cobra.MinimumNArgs(1),
Short: "Run and retrieve preflight checks in a cluster",
Long: `A preflight check is a set of validations that can and should be run to ensure
that a cluster meets the requirements to run an application.`,
that a cluster meets the requirements to run an application.
Unlike support-bundle, preflight does not support --load-cluster-specs because
preflight checks are designed to run before an application is installed or
upgraded. Since no deployment has occurred yet, there are no in-cluster specs
to discover. Preflight specs must be provided via a URL, local file path, or
stdin (e.g. "helm template ... | kubectl preflight -").`,
SilenceUsage: true,
SilenceErrors: true,
PreRun: func(cmd *cobra.Command, args []string) {
@@ -89,6 +95,7 @@ that a cluster meets the requirements to run an application.`,
cmd.AddCommand(TemplateCmd())
cmd.AddCommand(DocsCmd())
cmd.AddCommand(ConvertCmd())
cmd.AddCommand(LintCmd())
preflight.AddFlags(cmd.PersistentFlags())
+100
View File
@@ -0,0 +1,100 @@
package cli
import (
"fmt"
"os"
"github.com/pkg/errors"
"github.com/replicatedhq/troubleshoot/pkg/constants"
"github.com/replicatedhq/troubleshoot/pkg/lint"
"github.com/replicatedhq/troubleshoot/pkg/types"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
func LintCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "lint [spec-files...]",
Args: cobra.MinimumNArgs(1),
Short: "Lint v1beta2/v1beta3 troubleshoot specs for syntax and structural errors",
Long: `Lint v1beta2/v1beta3 troubleshoot specs (both preflight and support-bundle) for syntax and structural errors.
This command validates v1beta2/v1beta3 troubleshoot specs and checks for:
- YAML syntax errors
- Missing required fields (apiVersion, kind, metadata, spec)
- Invalid template syntax ({{ .Values.* }})
- Missing collectors or hostCollectors
- Common structural issues
- Missing docStrings (warning)
Examples:
# Lint a single spec file
support-bundle lint my-spec.yaml
# Lint multiple spec files
support-bundle lint spec1.yaml spec2.yaml spec3.yaml
# Lint with automatic fixes
support-bundle lint --fix my-spec.yaml
# Lint and output as JSON for CI/CD integration
support-bundle lint --format json my-spec.yaml
Notes:
- v1beta2 does not support templating; template syntax in v1beta2 files will be flagged as errors.
- v1beta3 supports templating and is linted with template-awareness.
Exit codes:
0 - No errors found
2 - Validation errors found`,
PreRun: func(cmd *cobra.Command, args []string) {
viper.BindPFlags(cmd.Flags())
},
RunE: func(cmd *cobra.Command, args []string) error {
v := viper.GetViper()
opts := lint.LintOptions{
FilePaths: args,
Fix: v.GetBool("fix"),
Format: v.GetString("format"),
ValuesFiles: v.GetStringSlice("values"),
SetValues: v.GetStringSlice("set"),
}
return runLint(opts)
},
}
cmd.Flags().Bool("fix", false, "Automatically fix issues where possible")
cmd.Flags().String("format", "text", "Output format: text or json")
cmd.Flags().StringSlice("values", []string{}, "Path to YAML files with template values (required for v1beta3 specs)")
cmd.Flags().StringSlice("set", []string{}, "Set template values via command line (e.g., --set key=value)")
return cmd
}
func runLint(opts lint.LintOptions) error {
// Validate file paths exist
for _, filePath := range opts.FilePaths {
if _, err := os.Stat(filePath); err != nil {
return errors.Wrapf(err, "file not found: %s", filePath)
}
}
// Run linting
results, err := lint.LintFiles(opts)
if err != nil {
return errors.Wrap(err, "failed to lint files")
}
// Format and print results
output := lint.FormatResults(results, opts.Format)
fmt.Print(output)
// Return appropriate exit code
if lint.HasErrors(results) {
return types.NewExitCodeError(constants.EXIT_CODE_SPEC_ISSUES, nil)
}
return nil
}
+24 -2
View File
@@ -5,10 +5,14 @@ import (
"os"
"strings"
"errors"
"github.com/replicatedhq/troubleshoot/cmd/internal/util"
"github.com/replicatedhq/troubleshoot/internal/traces"
"github.com/replicatedhq/troubleshoot/pkg/constants"
"github.com/replicatedhq/troubleshoot/pkg/k8sutil"
"github.com/replicatedhq/troubleshoot/pkg/logger"
"github.com/replicatedhq/troubleshoot/pkg/types"
"github.com/replicatedhq/troubleshoot/pkg/updater"
"github.com/spf13/cobra"
"github.com/spf13/viper"
@@ -108,6 +112,7 @@ If no arguments are provided, specs are automatically loaded from the cluster by
cmd.AddCommand(Diff())
cmd.AddCommand(Schedule())
cmd.AddCommand(UploadCmd())
cmd.AddCommand(LintCmd())
cmd.AddCommand(util.VersionCmd())
cmd.Flags().StringSlice("redactors", []string{}, "names of the additional redactors to use")
@@ -127,10 +132,18 @@ If no arguments are provided, specs are automatically loaded from the cluster by
cmd.Flags().Bool("load-cluster-specs", false, "enable/disable loading additional troubleshoot specs found within the cluster. Do not load by default unless no specs are provided in the cli args")
cmd.Flags().String("since-time", "", "force pod logs collectors to return logs after a specific date (RFC3339)")
cmd.Flags().String("since", "", "force pod logs collectors to return logs newer than a relative duration like 5s, 2m, or 3h.")
cmd.Flags().StringP("output", "o", "", "specify the output file path for the support bundle")
cmd.Flags().Int("remote-host-collect-timeout", 30, "timeout in seconds for remote host collect operations (e.g. waiting for pods/daemonsets)")
cmd.Flags().StringP("output", "o", "", "specify the output file path for the support bundle (.tar.gz extension is added automatically)")
cmd.Flags().Bool("debug", false, "enable debug logging. This is equivalent to --v=0")
cmd.Flags().Bool("dry-run", false, "print support bundle spec without collecting anything")
cmd.Flags().Bool("auto-update", true, "enable automatic binary self-update check and install")
cmd.Flags().StringSlice("metadata", []string{}, "user-provided metadata key=value pairs to include in the bundle (can be specified multiple times)")
// Upload flags
cmd.Flags().Bool("auto-upload", false, "automatically upload resulting bundle to replicated.app")
cmd.Flags().String("license-id", "", "license ID for authentication when uploading (auto-detected from bundle if not provided)")
cmd.Flags().String("app-slug", "", "application slug when uploading (auto-detected from bundle if not provided)")
cmd.Flags().String("upload-domain", "", "custom domain for upload (default: replicated.app)")
// Auto-discovery flags
cmd.Flags().Bool("auto", false, "enable auto-discovery of foundational collectors. When used with YAML specs, adds foundational collectors to YAML collectors. When used alone, collects only foundational data")
@@ -161,7 +174,16 @@ If no arguments are provided, specs are automatically loaded from the cluster by
}
func InitAndExecute() {
if err := RootCmd().Execute(); err != nil {
cmd := RootCmd()
if err := cmd.Execute(); err != nil {
var exitErr types.ExitError
if errors.As(err, &exitErr) {
if exitErr.ExitStatus() != constants.EXIT_CODE_FAIL && exitErr.ExitStatus() != constants.EXIT_CODE_WARN {
cmd.PrintErrln("Error:", err.Error())
}
os.Exit(exitErr.ExitStatus())
}
cmd.PrintErrln("Error:", err.Error())
os.Exit(1)
}
}
+67 -13
View File
@@ -166,7 +166,18 @@ func runTroubleshoot(v *viper.Viper, args []string) error {
go func() {
defer wg.Done()
for msg := range progressChan {
klog.Infof("Collecting support bundle: %v", msg)
switch msg := msg.(type) {
case error:
klog.Warningf("Collecting support bundle: %v", msg)
case string:
if strings.Contains(msg, "skipping collector") {
klog.Warningf("Collecting support bundle: %s", msg)
} else {
klog.Infof("Collecting support bundle: %s", msg)
}
default:
klog.Infof("Collecting support bundle: %v", msg)
}
}
}()
} else {
@@ -200,17 +211,23 @@ func runTroubleshoot(v *viper.Viper, args []string) error {
}()
}
userMetadata, err := parseMetadataFlag(v.GetStringSlice("metadata"))
if err != nil {
return errors.Wrap(err, "invalid metadata flag")
}
createOpts := supportbundle.SupportBundleCreateOpts{
CollectorProgressCallback: collectorCB,
CollectWithoutPermissions: v.GetBool("collect-without-permissions"),
KubernetesRestConfig: restConfig,
Namespace: v.GetString("namespace"),
ProgressChan: progressChan,
SinceTime: sinceTime,
OutputPath: v.GetString("output"),
Redact: v.GetBool("redact"),
FromCLI: true,
RunHostCollectorsInPod: mainBundle.Spec.RunHostCollectorsInPod,
CollectorProgressCallback: collectorCB,
CollectWithoutPermissions: v.GetBool("collect-without-permissions"),
RemoteHostCollectTimeoutSeconds: v.GetInt("remote-host-collect-timeout"),
KubernetesRestConfig: restConfig,
Namespace: v.GetString("namespace"),
ProgressChan: progressChan,
SinceTime: sinceTime,
OutputPath: v.GetString("output"),
Redact: v.GetBool("redact"),
FromCLI: true,
RunHostCollectorsInPod: mainBundle.Spec.RunHostCollectorsInPod,
// Phase 4: Tokenization options
Tokenize: v.GetBool("tokenize"),
@@ -220,6 +237,7 @@ func runTroubleshoot(v *viper.Viper, args []string) error {
VerifyTokenization: v.GetBool("verify-tokenization"),
BundleID: v.GetString("bundle-id"),
TokenizationStats: v.GetBool("tokenization-stats"),
UserMetadata: userMetadata,
}
nonInteractiveOutput := analysisOutput{}
@@ -242,6 +260,26 @@ func runTroubleshoot(v *viper.Viper, args []string) error {
}
}
// Attempt auto-upload before any early returns
if v.GetBool("auto-upload") && !response.FileUploaded {
licenseID := v.GetString("license-id")
appSlug := v.GetString("app-slug")
uploadDomain := v.GetString("upload-domain")
targetDomain := uploadDomain
if targetDomain == "" {
targetDomain = "replicated.app"
}
fmt.Fprintf(os.Stderr, "Auto-uploading bundle to %s...\n", targetDomain)
if err := supportbundle.UploadBundleAutoDetect(response.ArchivePath, licenseID, appSlug, uploadDomain); err != nil {
fmt.Fprintf(os.Stderr, "Auto-upload failed: %v\n", err)
fmt.Fprintf(os.Stderr, "You can manually upload the bundle using: support-bundle upload %s\n", response.ArchivePath)
} else {
response.FileUploaded = true
}
}
if !response.FileUploaded {
if appName := mainBundle.Labels["applicationName"]; appName != "" {
f := `A support bundle for %s has been created in this directory
@@ -269,11 +307,12 @@ the %s Admin Console to begin analysis.`
fmt.Printf("\r%s\r", cursor.ClearEntireLine())
}
if response.FileUploaded {
fmt.Printf("A support bundle has been created and uploaded to your cluster for analysis. Please visit the Troubleshoot page to continue.\n")
fmt.Printf("A support bundle has been created and uploaded to replicated.app for analysis.\n")
fmt.Printf("A copy of this support bundle was written to the current directory, named %q\n", response.ArchivePath)
} else {
fmt.Printf("A support bundle has been created in the current directory named %q\n", response.ArchivePath)
}
return nil
}
@@ -497,7 +536,7 @@ func (a *analysisOutput) FormattedAnalysisOutput() (outputJson string, err error
formatted, err := json.MarshalIndent(o, "", " ")
if err != nil {
return "", fmt.Errorf("\r * Failed to format analysis: %v\n", err)
return "", fmt.Errorf("\r * Failed to format analysis: %v", err)
}
return string(formatted), nil
}
@@ -604,3 +643,18 @@ func VerifyTokenizationSetup(v *viper.Viper) error {
return nil
}
func parseMetadataFlag(values []string) (map[string]string, error) {
if len(values) == 0 {
return nil, nil
}
metadata := make(map[string]string, len(values))
for _, v := range values {
k, val, ok := strings.Cut(v, "=")
if !ok {
return nil, fmt.Errorf("invalid metadata format %q, expected key=value", v)
}
metadata[k] = val
}
return metadata, nil
}
+79
View File
@@ -13,6 +13,7 @@ import (
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
"github.com/replicatedhq/troubleshoot/pkg/httputil"
"github.com/replicatedhq/troubleshoot/pkg/loader"
"github.com/spf13/viper"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
testclient "k8s.io/client-go/kubernetes/fake"
@@ -436,3 +437,81 @@ func Test_loadInvalidURISpec(t *testing.T) {
assert.Len(t, sb.Spec.Collectors, 3) // default + clusterInfo + clusterResources
assert.NotNil(t, sb.Spec.Collectors[0].ConfigMap) // come from the original spec
}
func TestCollectTimeoutFlag(t *testing.T) {
const defaultCollectTimeout = 30
// Parse flags and bind to viper without running the full command (avoids k8s connection).
// This verifies the flag is defined and viper receives the correct value.
bindFlagsFromArgs := func(t *testing.T, args []string) {
t.Helper()
cmd := RootCmd()
require.NoError(t, cmd.Flags().Parse(args))
if cmd.PersistentPreRun != nil {
cmd.PersistentPreRun(cmd, nil)
}
}
t.Run("default value when flag not set", func(t *testing.T) {
bindFlagsFromArgs(t, []string{})
actualTimeout := viper.GetInt("remote-host-collect-timeout")
assert.Equal(t, defaultCollectTimeout, actualTimeout, "remote-host-collect-timeout should default to 30 seconds")
})
t.Run("custom value when flag set", func(t *testing.T) {
bindFlagsFromArgs(t, []string{"--remote-host-collect-timeout=90"})
actualTimeout := viper.GetInt("remote-host-collect-timeout")
assert.Equal(t, 90, actualTimeout, "remote-host-collect-timeout should be 90 when --remote-host-collect-timeout=90 is passed")
})
}
func TestParseMetadataFlag(t *testing.T) {
tests := []struct {
name string
values []string
want map[string]string
wantErr bool
}{
{
name: "nil input",
values: nil,
want: nil,
},
{
name: "empty input",
values: []string{},
want: nil,
},
{
name: "single pair",
values: []string{"env=staging"},
want: map[string]string{"env": "staging"},
},
{
name: "multiple pairs",
values: []string{"env=staging", "version=1.2.3"},
want: map[string]string{"env": "staging", "version": "1.2.3"},
},
{
name: "value contains equals",
values: []string{"config=key=value"},
want: map[string]string{"config": "key=value"},
},
{
name: "missing equals",
values: []string{"noequals"},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := parseMetadataFlag(tt.values)
if tt.wantErr {
assert.Error(t, err)
} else {
require.NoError(t, err)
assert.Equal(t, tt.want, got)
}
})
}
}
+7 -2
View File
@@ -26,7 +26,10 @@ Examples:
support-bundle upload bundle.tar.gz --license-id YOUR_LICENSE_ID
# Specify both license and app
support-bundle upload bundle.tar.gz --license-id YOUR_LICENSE_ID --app-slug my-app`,
support-bundle upload bundle.tar.gz --license-id YOUR_LICENSE_ID --app-slug my-app
# Upload to a custom domain (e.g., development environment)
support-bundle upload bundle.tar.gz --upload-domain replicated-app-dev.example.com`,
RunE: func(cmd *cobra.Command, args []string) error {
v := viper.GetViper()
bundlePath := args[0]
@@ -39,9 +42,10 @@ Examples:
// Get upload parameters
licenseID := v.GetString("license-id")
appSlug := v.GetString("app-slug")
uploadDomain := v.GetString("upload-domain")
// Use auto-detection for uploads
if err := supportbundle.UploadBundleAutoDetect(bundlePath, licenseID, appSlug); err != nil {
if err := supportbundle.UploadBundleAutoDetect(bundlePath, licenseID, appSlug, uploadDomain); err != nil {
return errors.Wrap(err, "upload failed")
}
@@ -51,6 +55,7 @@ Examples:
cmd.Flags().String("license-id", "", "license ID for authentication (auto-detected from bundle if not provided)")
cmd.Flags().String("app-slug", "", "application slug (auto-detected from bundle if not provided)")
cmd.Flags().String("upload-domain", "", "custom domain for upload (default: replicated.app)")
return cmd
}
+161
View File
@@ -880,6 +880,55 @@ spec:
- namespace
- outcomes
type: object
ingressClass:
properties:
annotations:
additionalProperties:
type: string
type: object
checkName:
type: string
exclude:
type: BoolString
ingressClassName:
type: string
outcomes:
items:
properties:
fail:
properties:
message:
type: string
uri:
type: string
when:
type: string
type: object
pass:
properties:
message:
type: string
uri:
type: string
when:
type: string
type: object
warn:
properties:
message:
type: string
uri:
type: string
when:
type: string
type: object
type: object
type: array
strict:
type: BoolString
required:
- outcomes
type: object
jobStatus:
properties:
annotations:
@@ -1311,6 +1360,8 @@ spec:
- key
type: object
type: object
ignoreIfNoFiles:
type: boolean
outcomes:
items:
properties:
@@ -1563,6 +1614,58 @@ spec:
- outcomes
- selector
type: object
s3Status:
properties:
annotations:
additionalProperties:
type: string
type: object
checkName:
type: string
collectorName:
type: string
exclude:
type: BoolString
fileName:
type: string
outcomes:
items:
properties:
fail:
properties:
message:
type: string
uri:
type: string
when:
type: string
type: object
pass:
properties:
message:
type: string
uri:
type: string
when:
type: string
type: object
warn:
properties:
message:
type: string
uri:
type: string
when:
type: string
type: object
type: object
type: array
strict:
type: BoolString
required:
- collectorName
- outcomes
type: object
secret:
properties:
annotations:
@@ -1922,7 +2025,16 @@ spec:
items:
properties:
blockDevices:
description: BlockDevicesAnalyze evaluates host-collected block
device listings (lsblk-based).
properties:
additionalDeviceTypes:
description: |-
AdditionalDeviceTypes are extra lsblk TYPE values (e.g. loop, lvm) that may count toward outcomes,
in addition to whole disks and (when IncludeUnmountedPartitions is set) partitions.
items:
type: string
type: array
annotations:
additionalProperties:
type: string
@@ -2725,6 +2837,55 @@ spec:
required:
- outcomes
type: object
registryImages:
properties:
annotations:
additionalProperties:
type: string
type: object
checkName:
type: string
collectorName:
type: string
exclude:
type: BoolString
outcomes:
items:
properties:
fail:
properties:
message:
type: string
uri:
type: string
when:
type: string
type: object
pass:
properties:
message:
type: string
uri:
type: string
when:
type: string
type: object
warn:
properties:
message:
type: string
uri:
type: string
when:
type: string
type: object
type: object
type: array
strict:
type: BoolString
required:
- outcomes
type: object
subnetAvailable:
properties:
annotations:
+185 -12
View File
@@ -2674,7 +2674,9 @@ spec:
type: integer
type: object
resizePolicy:
description: Resources resize policy for the container.
description: |-
Resources resize policy for the container.
This field cannot be set on ephemeral containers.
items:
description: ContainerResizePolicy represents
resource resize policy for the container.
@@ -5933,7 +5935,9 @@ spec:
type: integer
type: object
resizePolicy:
description: Resources resize policy for the container.
description: |-
Resources resize policy for the container.
This field cannot be set on ephemeral containers.
items:
description: ContainerResizePolicy represents
resource resize policy for the container.
@@ -6723,8 +6727,8 @@ spec:
will be made available to those containers which consume them
by name.
This is an alpha field and requires enabling the
DynamicResourceAllocation feature gate.
This is a stable field but requires that the
DynamicResourceAllocation feature gate is enabled.
This field is immutable.
items:
@@ -7184,9 +7188,10 @@ spec:
operator:
description: |-
Operator represents a key's relationship to the value.
Valid operators are Exists and Equal. Defaults to Equal.
Valid operators are Exists, Equal, Lt, and Gt. Defaults to Equal.
Exists is equivalent to wildcard for value, so that a pod can
tolerate all taints of a particular category.
Lt and Gt perform numeric comparisons (requires feature gate TaintTolerationComparisonOperators).
type: string
tolerationSeconds:
description: |-
@@ -7987,7 +7992,7 @@ spec:
resources:
description: |-
resources represents the minimum resources the volume should have.
If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements
Users are allowed to specify resource requirements
that are lower than previous value but must still be higher than capacity recorded in the
status field of the claim.
More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources
@@ -8888,6 +8893,24 @@ spec:
CSRs will be addressed to this
signer.
type: string
userAnnotations:
additionalProperties:
type: string
description: |-
userAnnotations allow pod authors to pass additional information to
the signer implementation. Kubernetes does not restrict or validate this
metadata in any way.
These values are copied verbatim into the `spec.unverifiedUserAnnotations` field of
the PodCertificateRequest objects that Kubelet creates.
Entries are subject to the same validation as object metadata annotations,
with the addition that all keys must be domain-prefixed. No restrictions
are placed on values, except an overall size limitation on the entire field.
Signers should document the keys and values they support. Signers should
deny requests that contain keys they do not recognize.
type: object
required:
- keyType
- signerName
@@ -9318,6 +9341,42 @@ spec:
x-kubernetes-list-map-keys:
- name
x-kubernetes-list-type: map
workloadRef:
description: |-
WorkloadRef provides a reference to the Workload object that this Pod belongs to.
This field is used by the scheduler to identify the PodGroup and apply the
correct group scheduling policies. The Workload object referenced
by this field may not exist at the time the Pod is created.
This field is immutable, but a Workload object with the same name
may be recreated with different policies. Doing this during pod scheduling
may result in the placement not conforming to the expected policies.
properties:
name:
description: |-
Name defines the name of the Workload object this Pod belongs to.
Workload must be in the same namespace as the Pod.
If it doesn't match any existing Workload, the Pod will remain unschedulable
until a Workload object is created and observed by the kube-scheduler.
It must be a DNS subdomain.
type: string
podGroup:
description: |-
PodGroup is the name of the PodGroup within the Workload that this Pod
belongs to. If it doesn't match any existing PodGroup within the Workload,
the Pod will remain unschedulable until the Workload object is recreated
and observed by the kube-scheduler. It must be a DNS label.
type: string
podGroupReplicaKey:
description: |-
PodGroupReplicaKey specifies the replica key of the PodGroup to which this
Pod belongs. It is used to distinguish pods belonging to different replicas
of the same pod group. The pod group policy is applied separately to each replica.
When set, it must be a DNS label.
type: string
required:
- name
- podGroup
type: object
required:
- containers
type: object
@@ -11199,7 +11258,9 @@ spec:
type: integer
type: object
resizePolicy:
description: Resources resize policy for the container.
description: |-
Resources resize policy for the container.
This field cannot be set on ephemeral containers.
items:
description: ContainerResizePolicy represents
resource resize policy for the container.
@@ -14458,7 +14519,9 @@ spec:
type: integer
type: object
resizePolicy:
description: Resources resize policy for the container.
description: |-
Resources resize policy for the container.
This field cannot be set on ephemeral containers.
items:
description: ContainerResizePolicy represents
resource resize policy for the container.
@@ -15248,8 +15311,8 @@ spec:
will be made available to those containers which consume them
by name.
This is an alpha field and requires enabling the
DynamicResourceAllocation feature gate.
This is a stable field but requires that the
DynamicResourceAllocation feature gate is enabled.
This field is immutable.
items:
@@ -15709,9 +15772,10 @@ spec:
operator:
description: |-
Operator represents a key's relationship to the value.
Valid operators are Exists and Equal. Defaults to Equal.
Valid operators are Exists, Equal, Lt, and Gt. Defaults to Equal.
Exists is equivalent to wildcard for value, so that a pod can
tolerate all taints of a particular category.
Lt and Gt perform numeric comparisons (requires feature gate TaintTolerationComparisonOperators).
type: string
tolerationSeconds:
description: |-
@@ -16512,7 +16576,7 @@ spec:
resources:
description: |-
resources represents the minimum resources the volume should have.
If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements
Users are allowed to specify resource requirements
that are lower than previous value but must still be higher than capacity recorded in the
status field of the claim.
More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources
@@ -17413,6 +17477,24 @@ spec:
CSRs will be addressed to this
signer.
type: string
userAnnotations:
additionalProperties:
type: string
description: |-
userAnnotations allow pod authors to pass additional information to
the signer implementation. Kubernetes does not restrict or validate this
metadata in any way.
These values are copied verbatim into the `spec.unverifiedUserAnnotations` field of
the PodCertificateRequest objects that Kubelet creates.
Entries are subject to the same validation as object metadata annotations,
with the addition that all keys must be domain-prefixed. No restrictions
are placed on values, except an overall size limitation on the entire field.
Signers should document the keys and values they support. Signers should
deny requests that contain keys they do not recognize.
type: object
required:
- keyType
- signerName
@@ -17843,6 +17925,42 @@ spec:
x-kubernetes-list-map-keys:
- name
x-kubernetes-list-type: map
workloadRef:
description: |-
WorkloadRef provides a reference to the Workload object that this Pod belongs to.
This field is used by the scheduler to identify the PodGroup and apply the
correct group scheduling policies. The Workload object referenced
by this field may not exist at the time the Pod is created.
This field is immutable, but a Workload object with the same name
may be recreated with different policies. Doing this during pod scheduling
may result in the placement not conforming to the expected policies.
properties:
name:
description: |-
Name defines the name of the Workload object this Pod belongs to.
Workload must be in the same namespace as the Pod.
If it doesn't match any existing Workload, the Pod will remain unschedulable
until a Workload object is created and observed by the kube-scheduler.
It must be a DNS subdomain.
type: string
podGroup:
description: |-
PodGroup is the name of the PodGroup within the Workload that this Pod
belongs to. If it doesn't match any existing PodGroup within the Workload,
the Pod will remain unschedulable until the Workload object is recreated
and observed by the kube-scheduler. It must be a DNS label.
type: string
podGroupReplicaKey:
description: |-
PodGroupReplicaKey specifies the replica key of the PodGroup to which this
Pod belongs. It is used to distinguish pods belonging to different replicas
of the same pod group. The pod group policy is applied separately to each replica.
When set, it must be a DNS label.
type: string
required:
- name
- podGroup
type: object
required:
- containers
type: object
@@ -17851,6 +17969,29 @@ spec:
required:
- namespace
type: object
s3Status:
properties:
accessKeyID:
type: string
bucketName:
type: string
collectorName:
type: string
endpoint:
type: string
exclude:
type: BoolString
insecure:
type: boolean
region:
type: string
secretAccessKey:
type: string
usePathStyle:
type: boolean
required:
- bucketName
type: object
secret:
properties:
collectorName:
@@ -17881,6 +18022,17 @@ spec:
namespace:
type: string
type: object
supportBundleMetadata:
properties:
collectorName:
type: string
exclude:
type: BoolString
namespace:
type: string
required:
- namespace
type: object
sysctl:
properties:
collectorName:
@@ -18333,6 +18485,27 @@ spec:
- port
- toCIDR
type: object
registryImages:
description: |-
HostRegistryImages checks whether images are accessible from the host,
without requiring a Kubernetes cluster. Auth can be supplied inline via
Username/Password or omitted to rely on ambient credentials (e.g. ~/.docker/config.json).
properties:
collectorName:
type: string
exclude:
type: BoolString
images:
items:
type: string
type: array
password:
type: string
username:
type: string
required:
- images
type: object
run:
properties:
args:
@@ -43,7 +43,16 @@ spec:
items:
properties:
blockDevices:
description: BlockDevicesAnalyze evaluates host-collected block
device listings (lsblk-based).
properties:
additionalDeviceTypes:
description: |-
AdditionalDeviceTypes are extra lsblk TYPE values (e.g. loop, lvm) that may count toward outcomes,
in addition to whole disks and (when IncludeUnmountedPartitions is set) partitions.
items:
type: string
type: array
annotations:
additionalProperties:
type: string
@@ -846,6 +855,55 @@ spec:
required:
- outcomes
type: object
registryImages:
properties:
annotations:
additionalProperties:
type: string
type: object
checkName:
type: string
collectorName:
type: string
exclude:
type: BoolString
outcomes:
items:
properties:
fail:
properties:
message:
type: string
uri:
type: string
when:
type: string
type: object
pass:
properties:
message:
type: string
uri:
type: string
when:
type: string
type: object
warn:
properties:
message:
type: string
uri:
type: string
when:
type: string
type: object
type: object
type: array
strict:
type: BoolString
required:
- outcomes
type: object
subnetAvailable:
properties:
annotations:
@@ -1775,6 +1833,27 @@ spec:
- port
- toCIDR
type: object
registryImages:
description: |-
HostRegistryImages checks whether images are accessible from the host,
without requiring a Kubernetes cluster. Auth can be supplied inline via
Username/Password or omitted to rely on ambient credentials (e.g. ~/.docker/config.json).
properties:
collectorName:
type: string
exclude:
type: BoolString
images:
items:
type: string
type: array
password:
type: string
username:
type: string
required:
- images
type: object
run:
properties:
args:
@@ -43,7 +43,16 @@ spec:
items:
properties:
blockDevices:
description: BlockDevicesAnalyze evaluates host-collected block
device listings (lsblk-based).
properties:
additionalDeviceTypes:
description: |-
AdditionalDeviceTypes are extra lsblk TYPE values (e.g. loop, lvm) that may count toward outcomes,
in addition to whole disks and (when IncludeUnmountedPartitions is set) partitions.
items:
type: string
type: array
annotations:
additionalProperties:
type: string
@@ -846,6 +855,55 @@ spec:
required:
- outcomes
type: object
registryImages:
properties:
annotations:
additionalProperties:
type: string
type: object
checkName:
type: string
collectorName:
type: string
exclude:
type: BoolString
outcomes:
items:
properties:
fail:
properties:
message:
type: string
uri:
type: string
when:
type: string
type: object
pass:
properties:
message:
type: string
uri:
type: string
when:
type: string
type: object
warn:
properties:
message:
type: string
uri:
type: string
when:
type: string
type: object
type: object
type: array
strict:
type: BoolString
required:
- outcomes
type: object
subnetAvailable:
properties:
annotations:
@@ -1775,6 +1833,27 @@ spec:
- port
- toCIDR
type: object
registryImages:
description: |-
HostRegistryImages checks whether images are accessible from the host,
without requiring a Kubernetes cluster. Auth can be supplied inline via
Username/Password or omitted to rely on ambient credentials (e.g. ~/.docker/config.json).
properties:
collectorName:
type: string
exclude:
type: BoolString
images:
items:
type: string
type: array
password:
type: string
username:
type: string
required:
- images
type: object
run:
properties:
args:
+267 -12
View File
@@ -880,6 +880,55 @@ spec:
- namespace
- outcomes
type: object
ingressClass:
properties:
annotations:
additionalProperties:
type: string
type: object
checkName:
type: string
exclude:
type: BoolString
ingressClassName:
type: string
outcomes:
items:
properties:
fail:
properties:
message:
type: string
uri:
type: string
when:
type: string
type: object
pass:
properties:
message:
type: string
uri:
type: string
when:
type: string
type: object
warn:
properties:
message:
type: string
uri:
type: string
when:
type: string
type: object
type: object
type: array
strict:
type: BoolString
required:
- outcomes
type: object
jobStatus:
properties:
annotations:
@@ -1311,6 +1360,8 @@ spec:
- key
type: object
type: object
ignoreIfNoFiles:
type: boolean
outcomes:
items:
properties:
@@ -1563,6 +1614,58 @@ spec:
- outcomes
- selector
type: object
s3Status:
properties:
annotations:
additionalProperties:
type: string
type: object
checkName:
type: string
collectorName:
type: string
exclude:
type: BoolString
fileName:
type: string
outcomes:
items:
properties:
fail:
properties:
message:
type: string
uri:
type: string
when:
type: string
type: object
pass:
properties:
message:
type: string
uri:
type: string
when:
type: string
type: object
warn:
properties:
message:
type: string
uri:
type: string
when:
type: string
type: object
type: object
type: array
strict:
type: BoolString
required:
- collectorName
- outcomes
type: object
secret:
properties:
annotations:
@@ -4522,7 +4625,9 @@ spec:
type: integer
type: object
resizePolicy:
description: Resources resize policy for the container.
description: |-
Resources resize policy for the container.
This field cannot be set on ephemeral containers.
items:
description: ContainerResizePolicy represents
resource resize policy for the container.
@@ -7781,7 +7886,9 @@ spec:
type: integer
type: object
resizePolicy:
description: Resources resize policy for the container.
description: |-
Resources resize policy for the container.
This field cannot be set on ephemeral containers.
items:
description: ContainerResizePolicy represents
resource resize policy for the container.
@@ -8571,8 +8678,8 @@ spec:
will be made available to those containers which consume them
by name.
This is an alpha field and requires enabling the
DynamicResourceAllocation feature gate.
This is a stable field but requires that the
DynamicResourceAllocation feature gate is enabled.
This field is immutable.
items:
@@ -9032,9 +9139,10 @@ spec:
operator:
description: |-
Operator represents a key's relationship to the value.
Valid operators are Exists and Equal. Defaults to Equal.
Valid operators are Exists, Equal, Lt, and Gt. Defaults to Equal.
Exists is equivalent to wildcard for value, so that a pod can
tolerate all taints of a particular category.
Lt and Gt perform numeric comparisons (requires feature gate TaintTolerationComparisonOperators).
type: string
tolerationSeconds:
description: |-
@@ -9835,7 +9943,7 @@ spec:
resources:
description: |-
resources represents the minimum resources the volume should have.
If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements
Users are allowed to specify resource requirements
that are lower than previous value but must still be higher than capacity recorded in the
status field of the claim.
More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources
@@ -10736,6 +10844,24 @@ spec:
CSRs will be addressed to this
signer.
type: string
userAnnotations:
additionalProperties:
type: string
description: |-
userAnnotations allow pod authors to pass additional information to
the signer implementation. Kubernetes does not restrict or validate this
metadata in any way.
These values are copied verbatim into the `spec.unverifiedUserAnnotations` field of
the PodCertificateRequest objects that Kubelet creates.
Entries are subject to the same validation as object metadata annotations,
with the addition that all keys must be domain-prefixed. No restrictions
are placed on values, except an overall size limitation on the entire field.
Signers should document the keys and values they support. Signers should
deny requests that contain keys they do not recognize.
type: object
required:
- keyType
- signerName
@@ -11166,6 +11292,42 @@ spec:
x-kubernetes-list-map-keys:
- name
x-kubernetes-list-type: map
workloadRef:
description: |-
WorkloadRef provides a reference to the Workload object that this Pod belongs to.
This field is used by the scheduler to identify the PodGroup and apply the
correct group scheduling policies. The Workload object referenced
by this field may not exist at the time the Pod is created.
This field is immutable, but a Workload object with the same name
may be recreated with different policies. Doing this during pod scheduling
may result in the placement not conforming to the expected policies.
properties:
name:
description: |-
Name defines the name of the Workload object this Pod belongs to.
Workload must be in the same namespace as the Pod.
If it doesn't match any existing Workload, the Pod will remain unschedulable
until a Workload object is created and observed by the kube-scheduler.
It must be a DNS subdomain.
type: string
podGroup:
description: |-
PodGroup is the name of the PodGroup within the Workload that this Pod
belongs to. If it doesn't match any existing PodGroup within the Workload,
the Pod will remain unschedulable until the Workload object is recreated
and observed by the kube-scheduler. It must be a DNS label.
type: string
podGroupReplicaKey:
description: |-
PodGroupReplicaKey specifies the replica key of the PodGroup to which this
Pod belongs. It is used to distinguish pods belonging to different replicas
of the same pod group. The pod group policy is applied separately to each replica.
When set, it must be a DNS label.
type: string
required:
- name
- podGroup
type: object
required:
- containers
type: object
@@ -13047,7 +13209,9 @@ spec:
type: integer
type: object
resizePolicy:
description: Resources resize policy for the container.
description: |-
Resources resize policy for the container.
This field cannot be set on ephemeral containers.
items:
description: ContainerResizePolicy represents
resource resize policy for the container.
@@ -16306,7 +16470,9 @@ spec:
type: integer
type: object
resizePolicy:
description: Resources resize policy for the container.
description: |-
Resources resize policy for the container.
This field cannot be set on ephemeral containers.
items:
description: ContainerResizePolicy represents
resource resize policy for the container.
@@ -17096,8 +17262,8 @@ spec:
will be made available to those containers which consume them
by name.
This is an alpha field and requires enabling the
DynamicResourceAllocation feature gate.
This is a stable field but requires that the
DynamicResourceAllocation feature gate is enabled.
This field is immutable.
items:
@@ -17557,9 +17723,10 @@ spec:
operator:
description: |-
Operator represents a key's relationship to the value.
Valid operators are Exists and Equal. Defaults to Equal.
Valid operators are Exists, Equal, Lt, and Gt. Defaults to Equal.
Exists is equivalent to wildcard for value, so that a pod can
tolerate all taints of a particular category.
Lt and Gt perform numeric comparisons (requires feature gate TaintTolerationComparisonOperators).
type: string
tolerationSeconds:
description: |-
@@ -18360,7 +18527,7 @@ spec:
resources:
description: |-
resources represents the minimum resources the volume should have.
If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements
Users are allowed to specify resource requirements
that are lower than previous value but must still be higher than capacity recorded in the
status field of the claim.
More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources
@@ -19261,6 +19428,24 @@ spec:
CSRs will be addressed to this
signer.
type: string
userAnnotations:
additionalProperties:
type: string
description: |-
userAnnotations allow pod authors to pass additional information to
the signer implementation. Kubernetes does not restrict or validate this
metadata in any way.
These values are copied verbatim into the `spec.unverifiedUserAnnotations` field of
the PodCertificateRequest objects that Kubelet creates.
Entries are subject to the same validation as object metadata annotations,
with the addition that all keys must be domain-prefixed. No restrictions
are placed on values, except an overall size limitation on the entire field.
Signers should document the keys and values they support. Signers should
deny requests that contain keys they do not recognize.
type: object
required:
- keyType
- signerName
@@ -19691,6 +19876,42 @@ spec:
x-kubernetes-list-map-keys:
- name
x-kubernetes-list-type: map
workloadRef:
description: |-
WorkloadRef provides a reference to the Workload object that this Pod belongs to.
This field is used by the scheduler to identify the PodGroup and apply the
correct group scheduling policies. The Workload object referenced
by this field may not exist at the time the Pod is created.
This field is immutable, but a Workload object with the same name
may be recreated with different policies. Doing this during pod scheduling
may result in the placement not conforming to the expected policies.
properties:
name:
description: |-
Name defines the name of the Workload object this Pod belongs to.
Workload must be in the same namespace as the Pod.
If it doesn't match any existing Workload, the Pod will remain unschedulable
until a Workload object is created and observed by the kube-scheduler.
It must be a DNS subdomain.
type: string
podGroup:
description: |-
PodGroup is the name of the PodGroup within the Workload that this Pod
belongs to. If it doesn't match any existing PodGroup within the Workload,
the Pod will remain unschedulable until the Workload object is recreated
and observed by the kube-scheduler. It must be a DNS label.
type: string
podGroupReplicaKey:
description: |-
PodGroupReplicaKey specifies the replica key of the PodGroup to which this
Pod belongs. It is used to distinguish pods belonging to different replicas
of the same pod group. The pod group policy is applied separately to each replica.
When set, it must be a DNS label.
type: string
required:
- name
- podGroup
type: object
required:
- containers
type: object
@@ -19699,6 +19920,29 @@ spec:
required:
- namespace
type: object
s3Status:
properties:
accessKeyID:
type: string
bucketName:
type: string
collectorName:
type: string
endpoint:
type: string
exclude:
type: BoolString
insecure:
type: boolean
region:
type: string
secretAccessKey:
type: string
usePathStyle:
type: boolean
required:
- bucketName
type: object
secret:
properties:
collectorName:
@@ -19729,6 +19973,17 @@ spec:
namespace:
type: string
type: object
supportBundleMetadata:
properties:
collectorName:
type: string
exclude:
type: BoolString
namespace:
type: string
required:
- namespace
type: object
sysctl:
properties:
collectorName:
+346 -12
View File
@@ -911,6 +911,55 @@ spec:
- namespace
- outcomes
type: object
ingressClass:
properties:
annotations:
additionalProperties:
type: string
type: object
checkName:
type: string
exclude:
type: BoolString
ingressClassName:
type: string
outcomes:
items:
properties:
fail:
properties:
message:
type: string
uri:
type: string
when:
type: string
type: object
pass:
properties:
message:
type: string
uri:
type: string
when:
type: string
type: object
warn:
properties:
message:
type: string
uri:
type: string
when:
type: string
type: object
type: object
type: array
strict:
type: BoolString
required:
- outcomes
type: object
jobStatus:
properties:
annotations:
@@ -1342,6 +1391,8 @@ spec:
- key
type: object
type: object
ignoreIfNoFiles:
type: boolean
outcomes:
items:
properties:
@@ -1594,6 +1645,58 @@ spec:
- outcomes
- selector
type: object
s3Status:
properties:
annotations:
additionalProperties:
type: string
type: object
checkName:
type: string
collectorName:
type: string
exclude:
type: BoolString
fileName:
type: string
outcomes:
items:
properties:
fail:
properties:
message:
type: string
uri:
type: string
when:
type: string
type: object
pass:
properties:
message:
type: string
uri:
type: string
when:
type: string
type: object
warn:
properties:
message:
type: string
uri:
type: string
when:
type: string
type: object
type: object
type: array
strict:
type: BoolString
required:
- collectorName
- outcomes
type: object
secret:
properties:
annotations:
@@ -4553,7 +4656,9 @@ spec:
type: integer
type: object
resizePolicy:
description: Resources resize policy for the container.
description: |-
Resources resize policy for the container.
This field cannot be set on ephemeral containers.
items:
description: ContainerResizePolicy represents
resource resize policy for the container.
@@ -7812,7 +7917,9 @@ spec:
type: integer
type: object
resizePolicy:
description: Resources resize policy for the container.
description: |-
Resources resize policy for the container.
This field cannot be set on ephemeral containers.
items:
description: ContainerResizePolicy represents
resource resize policy for the container.
@@ -8602,8 +8709,8 @@ spec:
will be made available to those containers which consume them
by name.
This is an alpha field and requires enabling the
DynamicResourceAllocation feature gate.
This is a stable field but requires that the
DynamicResourceAllocation feature gate is enabled.
This field is immutable.
items:
@@ -9063,9 +9170,10 @@ spec:
operator:
description: |-
Operator represents a key's relationship to the value.
Valid operators are Exists and Equal. Defaults to Equal.
Valid operators are Exists, Equal, Lt, and Gt. Defaults to Equal.
Exists is equivalent to wildcard for value, so that a pod can
tolerate all taints of a particular category.
Lt and Gt perform numeric comparisons (requires feature gate TaintTolerationComparisonOperators).
type: string
tolerationSeconds:
description: |-
@@ -9866,7 +9974,7 @@ spec:
resources:
description: |-
resources represents the minimum resources the volume should have.
If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements
Users are allowed to specify resource requirements
that are lower than previous value but must still be higher than capacity recorded in the
status field of the claim.
More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources
@@ -10767,6 +10875,24 @@ spec:
CSRs will be addressed to this
signer.
type: string
userAnnotations:
additionalProperties:
type: string
description: |-
userAnnotations allow pod authors to pass additional information to
the signer implementation. Kubernetes does not restrict or validate this
metadata in any way.
These values are copied verbatim into the `spec.unverifiedUserAnnotations` field of
the PodCertificateRequest objects that Kubelet creates.
Entries are subject to the same validation as object metadata annotations,
with the addition that all keys must be domain-prefixed. No restrictions
are placed on values, except an overall size limitation on the entire field.
Signers should document the keys and values they support. Signers should
deny requests that contain keys they do not recognize.
type: object
required:
- keyType
- signerName
@@ -11197,6 +11323,42 @@ spec:
x-kubernetes-list-map-keys:
- name
x-kubernetes-list-type: map
workloadRef:
description: |-
WorkloadRef provides a reference to the Workload object that this Pod belongs to.
This field is used by the scheduler to identify the PodGroup and apply the
correct group scheduling policies. The Workload object referenced
by this field may not exist at the time the Pod is created.
This field is immutable, but a Workload object with the same name
may be recreated with different policies. Doing this during pod scheduling
may result in the placement not conforming to the expected policies.
properties:
name:
description: |-
Name defines the name of the Workload object this Pod belongs to.
Workload must be in the same namespace as the Pod.
If it doesn't match any existing Workload, the Pod will remain unschedulable
until a Workload object is created and observed by the kube-scheduler.
It must be a DNS subdomain.
type: string
podGroup:
description: |-
PodGroup is the name of the PodGroup within the Workload that this Pod
belongs to. If it doesn't match any existing PodGroup within the Workload,
the Pod will remain unschedulable until the Workload object is recreated
and observed by the kube-scheduler. It must be a DNS label.
type: string
podGroupReplicaKey:
description: |-
PodGroupReplicaKey specifies the replica key of the PodGroup to which this
Pod belongs. It is used to distinguish pods belonging to different replicas
of the same pod group. The pod group policy is applied separately to each replica.
When set, it must be a DNS label.
type: string
required:
- name
- podGroup
type: object
required:
- containers
type: object
@@ -13078,7 +13240,9 @@ spec:
type: integer
type: object
resizePolicy:
description: Resources resize policy for the container.
description: |-
Resources resize policy for the container.
This field cannot be set on ephemeral containers.
items:
description: ContainerResizePolicy represents
resource resize policy for the container.
@@ -16337,7 +16501,9 @@ spec:
type: integer
type: object
resizePolicy:
description: Resources resize policy for the container.
description: |-
Resources resize policy for the container.
This field cannot be set on ephemeral containers.
items:
description: ContainerResizePolicy represents
resource resize policy for the container.
@@ -17127,8 +17293,8 @@ spec:
will be made available to those containers which consume them
by name.
This is an alpha field and requires enabling the
DynamicResourceAllocation feature gate.
This is a stable field but requires that the
DynamicResourceAllocation feature gate is enabled.
This field is immutable.
items:
@@ -17588,9 +17754,10 @@ spec:
operator:
description: |-
Operator represents a key's relationship to the value.
Valid operators are Exists and Equal. Defaults to Equal.
Valid operators are Exists, Equal, Lt, and Gt. Defaults to Equal.
Exists is equivalent to wildcard for value, so that a pod can
tolerate all taints of a particular category.
Lt and Gt perform numeric comparisons (requires feature gate TaintTolerationComparisonOperators).
type: string
tolerationSeconds:
description: |-
@@ -18391,7 +18558,7 @@ spec:
resources:
description: |-
resources represents the minimum resources the volume should have.
If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements
Users are allowed to specify resource requirements
that are lower than previous value but must still be higher than capacity recorded in the
status field of the claim.
More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources
@@ -19292,6 +19459,24 @@ spec:
CSRs will be addressed to this
signer.
type: string
userAnnotations:
additionalProperties:
type: string
description: |-
userAnnotations allow pod authors to pass additional information to
the signer implementation. Kubernetes does not restrict or validate this
metadata in any way.
These values are copied verbatim into the `spec.unverifiedUserAnnotations` field of
the PodCertificateRequest objects that Kubelet creates.
Entries are subject to the same validation as object metadata annotations,
with the addition that all keys must be domain-prefixed. No restrictions
are placed on values, except an overall size limitation on the entire field.
Signers should document the keys and values they support. Signers should
deny requests that contain keys they do not recognize.
type: object
required:
- keyType
- signerName
@@ -19722,6 +19907,42 @@ spec:
x-kubernetes-list-map-keys:
- name
x-kubernetes-list-type: map
workloadRef:
description: |-
WorkloadRef provides a reference to the Workload object that this Pod belongs to.
This field is used by the scheduler to identify the PodGroup and apply the
correct group scheduling policies. The Workload object referenced
by this field may not exist at the time the Pod is created.
This field is immutable, but a Workload object with the same name
may be recreated with different policies. Doing this during pod scheduling
may result in the placement not conforming to the expected policies.
properties:
name:
description: |-
Name defines the name of the Workload object this Pod belongs to.
Workload must be in the same namespace as the Pod.
If it doesn't match any existing Workload, the Pod will remain unschedulable
until a Workload object is created and observed by the kube-scheduler.
It must be a DNS subdomain.
type: string
podGroup:
description: |-
PodGroup is the name of the PodGroup within the Workload that this Pod
belongs to. If it doesn't match any existing PodGroup within the Workload,
the Pod will remain unschedulable until the Workload object is recreated
and observed by the kube-scheduler. It must be a DNS label.
type: string
podGroupReplicaKey:
description: |-
PodGroupReplicaKey specifies the replica key of the PodGroup to which this
Pod belongs. It is used to distinguish pods belonging to different replicas
of the same pod group. The pod group policy is applied separately to each replica.
When set, it must be a DNS label.
type: string
required:
- name
- podGroup
type: object
required:
- containers
type: object
@@ -19730,6 +19951,29 @@ spec:
required:
- namespace
type: object
s3Status:
properties:
accessKeyID:
type: string
bucketName:
type: string
collectorName:
type: string
endpoint:
type: string
exclude:
type: BoolString
insecure:
type: boolean
region:
type: string
secretAccessKey:
type: string
usePathStyle:
type: boolean
required:
- bucketName
type: object
secret:
properties:
collectorName:
@@ -19760,6 +20004,17 @@ spec:
namespace:
type: string
type: object
supportBundleMetadata:
properties:
collectorName:
type: string
exclude:
type: BoolString
namespace:
type: string
required:
- namespace
type: object
sysctl:
properties:
collectorName:
@@ -19797,7 +20052,16 @@ spec:
items:
properties:
blockDevices:
description: BlockDevicesAnalyze evaluates host-collected block
device listings (lsblk-based).
properties:
additionalDeviceTypes:
description: |-
AdditionalDeviceTypes are extra lsblk TYPE values (e.g. loop, lvm) that may count toward outcomes,
in addition to whole disks and (when IncludeUnmountedPartitions is set) partitions.
items:
type: string
type: array
annotations:
additionalProperties:
type: string
@@ -20600,6 +20864,55 @@ spec:
required:
- outcomes
type: object
registryImages:
properties:
annotations:
additionalProperties:
type: string
type: object
checkName:
type: string
collectorName:
type: string
exclude:
type: BoolString
outcomes:
items:
properties:
fail:
properties:
message:
type: string
uri:
type: string
when:
type: string
type: object
pass:
properties:
message:
type: string
uri:
type: string
when:
type: string
type: object
warn:
properties:
message:
type: string
uri:
type: string
when:
type: string
type: object
type: object
type: array
strict:
type: BoolString
required:
- outcomes
type: object
subnetAvailable:
properties:
annotations:
@@ -21529,6 +21842,27 @@ spec:
- port
- toCIDR
type: object
registryImages:
description: |-
HostRegistryImages checks whether images are accessible from the host,
without requiring a Kubernetes cluster. Auth can be supplied inline via
Username/Password or omitted to rely on ambient credentials (e.g. ~/.docker/config.json).
properties:
collectorName:
type: string
exclude:
type: BoolString
images:
items:
type: string
type: array
password:
type: string
username:
type: string
required:
- images
type: object
run:
properties:
args:
+12 -26
View File
@@ -8,11 +8,15 @@ builds:
- id: preflight
main: ./cmd/preflight/main.go
env: [CGO_ENABLED=0]
goos: [linux, darwin]
goarch: [amd64, arm, arm64]
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 }}
@@ -31,11 +35,15 @@ builds:
- id: support-bundle
main: ./cmd/troubleshoot/main.go
env: [CGO_ENABLED=0]
goos: [linux, darwin]
goarch: [amd64, arm, arm64]
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 }}
@@ -125,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
skip_push: true
- 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
skip_push: true
universal_binaries:
- id: preflight-universal
ids: [preflight] # refers to the build id above
-12
View File
@@ -1,12 +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
ENV PATH="/troubleshoot:${PATH}"
@@ -0,0 +1,59 @@
apiVersion: troubleshoot.sh/v1beta3
kind: SupportBundle
metadata:
name: test-v1beta3-secretref
spec:
collectors:
# Test 1: PostgreSQL with URI from secret
- postgres:
collectorName: postgres-with-secret
uri:
valueFrom:
secretKeyRef:
name: test-database-credentials
key: postgres-uri
# This will fail to connect (fake server) but that's OK -
# we're testing secret resolution, not actual DB connectivity
# Test 2: PostgreSQL with TLS certs from secret
- postgres:
collectorName: postgres-with-tls
uri:
value: "postgresql://testuser:testpass@localhost:5432/testdb"
tls:
cacert:
valueFrom:
secretKeyRef:
name: test-database-credentials
key: ca.crt
clientCert:
valueFrom:
secretKeyRef:
name: test-database-credentials
key: client.crt
clientKey:
valueFrom:
secretKeyRef:
name: test-database-credentials
key: client.key
# Test 3: MySQL with URI from secret
- mysql:
collectorName: mysql-with-secret
uri:
valueFrom:
secretKeyRef:
name: test-database-credentials
key: mysql-uri
# Test 4: Redis with URI from secret
- redis:
collectorName: redis-with-secret
uri:
valueFrom:
secretKeyRef:
name: test-database-credentials
key: redis-uri
# Test 5: Literal value (no secret) for comparison
- clusterInfo: {}
+39
View File
@@ -0,0 +1,39 @@
---
# Secret containing database credentials
apiVersion: v1
kind: Secret
metadata:
name: test-database-credentials
namespace: default
type: Opaque
stringData:
# PostgreSQL connection URI
postgres-uri: "postgresql://testuser:supersecret@postgres.example.com:5432/testdb?sslmode=require"
# MySQL connection URI
mysql-uri: "mysql://testuser:supersecret@mysql.example.com:3306/testdb"
# Redis connection URI
redis-uri: "redis://:supersecret@redis.example.com:6379"
# TLS certificates (example data)
ca.crt: |
-----BEGIN CERTIFICATE-----
MIICpDCCAYwCCQDU+pQ3ZUD30jANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDDAls
b2NhbGhvc3QwHhcNMjQwMTAxMDAwMDAwWhcNMjUwMTAxMDAwMDAwWjAUMRIwEAYD
VQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC7
VJTUt9Us8cKjMzEfYyjiWA4R4/M2bS1+fWIcPm15A8IgC0qC1J3xGhE=
-----END CERTIFICATE-----
client.crt: |
-----BEGIN CERTIFICATE-----
MIICpDCCAYwCCQDU+pQ3ZUD30jANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDDAls
b2NhbGhvc3QwHhcNMjQwMTAxMDAwMDAwWhcNMjUwMTAxMDAwMDAwWjAUMRIwEAYD
VQQDDA5jbGllbnQtY2VydA==
-----END CERTIFICATE-----
client.key: |
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC7VJTUt9Us8cKj
MzEfYyjiWA4R4/M2bS1+fWIcPm15A8IgC0qC1J3xGhE=
-----END PRIVATE KEY-----
+1 -1
View File
@@ -92,7 +92,7 @@ spec:
- nodeResources:
checkName: Must have 1 node with 2Gi (available) memory and at least 2 cores (on a single node)
filters:
allocatableMemory: 2Gi
memoryAllocatable: 2Gi
cpuCapacity: "2"
outcomes:
- pass:
+3 -3
View File
@@ -28,7 +28,7 @@ spec:
- nodeResources:
checkName: Must have 1 node with 16 GB (available) memory and 10 cores (on a single node)
filters:
allocatableMemory: 16Gi
memoryAllocatable: 16Gi
cpuCapacity: "10"
outcomes:
- fail:
@@ -39,7 +39,7 @@ spec:
- nodeResources:
checkName: Must have 1 node with 16 GB (available) memory and 4 cores of amd64 arch (on a single node)
filters:
allocatableMemory: 16Gi
memoryAllocatable: 16Gi
cpuArchitecture: amd64
cpuCapacity: "4"
outcomes:
@@ -54,7 +54,7 @@ spec:
selector:
matchLabel:
node-role.kubernetes.io/master: ""
allocatableMemory: 16Gi
memoryAllocatable: 16Gi
cpuArchitecture: amd64
cpuCapacity: "6"
outcomes:
+44 -36
View File
@@ -1,6 +1,6 @@
module helm-template
go 1.24.6
go 1.26.5
// Always use the local version of troubleshoot so as to build using
// the latest version of the library. This will ensure the example
@@ -9,33 +9,41 @@ replace github.com/replicatedhq/troubleshoot v0.0.0 => ../../../
require (
github.com/replicatedhq/troubleshoot v0.0.0
helm.sh/helm/v3 v3.19.0
helm.sh/helm/v3 v3.21.4
sigs.k8s.io/yaml v1.6.0
)
require (
dario.cat/mergo v1.0.2 // indirect
github.com/BurntSushi/toml v1.5.0 // indirect
github.com/BurntSushi/toml v1.6.0 // indirect
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver/v3 v3.4.0 // indirect
github.com/Masterminds/semver/v3 v3.5.0 // indirect
github.com/Masterminds/sprig/v3 v3.3.0 // indirect
github.com/cyphar/filepath-securejoin v0.4.1 // indirect
github.com/cyphar/filepath-securejoin v0.7.0 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/emicklei/go-restful/v3 v3.12.2 // indirect
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-openapi/jsonpointer v0.21.0 // indirect
github.com/go-openapi/jsonreference v0.21.0 // indirect
github.com/go-openapi/swag v0.23.1 // indirect
github.com/emicklei/go-restful/v3 v3.13.0 // indirect
github.com/fxamacker/cbor/v2 v2.9.2 // indirect
github.com/go-logr/logr v1.4.4 // indirect
github.com/go-openapi/jsonpointer v1.0.0 // indirect
github.com/go-openapi/jsonreference v1.0.0 // indirect
github.com/go-openapi/swag v0.28.0 // indirect
github.com/go-openapi/swag/cmdutils v0.28.0 // indirect
github.com/go-openapi/swag/conv v0.28.0 // indirect
github.com/go-openapi/swag/fileutils v0.28.0 // indirect
github.com/go-openapi/swag/jsonutils v0.28.0 // indirect
github.com/go-openapi/swag/loading v0.28.0 // indirect
github.com/go-openapi/swag/mangling v0.28.0 // indirect
github.com/go-openapi/swag/netutils v0.28.0 // indirect
github.com/go-openapi/swag/pools v0.28.0 // indirect
github.com/go-openapi/swag/stringutils v0.28.0 // indirect
github.com/go-openapi/swag/typeutils v0.28.0 // indirect
github.com/go-openapi/swag/yamlutils v0.28.0 // indirect
github.com/gobwas/glob v0.2.3 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/google/gnostic-models v0.7.0 // indirect
github.com/google/gnostic-models v0.7.1 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/huandu/xstrings v1.5.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/mailru/easyjson v0.9.0 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
@@ -46,28 +54,28 @@ require (
github.com/shopspring/decimal v1.4.0 // indirect
github.com/spf13/cast v1.10.0 // indirect
github.com/x448/float16 v0.8.4 // indirect
go.yaml.in/yaml/v2 v2.4.2 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/crypto v0.42.0 // indirect
golang.org/x/net v0.44.0 // indirect
golang.org/x/oauth2 v0.30.0 // indirect
golang.org/x/sys v0.36.0 // indirect
golang.org/x/term v0.35.0 // indirect
golang.org/x/text v0.29.0 // indirect
golang.org/x/time v0.12.0 // indirect
google.golang.org/protobuf v1.36.6 // indirect
go.yaml.in/yaml/v2 v2.4.4 // indirect
go.yaml.in/yaml/v3 v3.0.5 // 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.41.0 // indirect
golang.org/x/time v0.15.0 // indirect
google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af // indirect
gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/api v0.34.1 // indirect
k8s.io/apiextensions-apiserver v0.34.1 // indirect
k8s.io/apimachinery v0.34.1 // indirect
k8s.io/client-go v0.34.1 // indirect
k8s.io/klog/v2 v2.130.1 // indirect
k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b // indirect
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 // indirect
sigs.k8s.io/controller-runtime v0.22.1 // indirect
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
k8s.io/api v0.36.3 // indirect
k8s.io/apiextensions-apiserver v0.36.3 // indirect
k8s.io/apimachinery v0.36.3 // indirect
k8s.io/client-go v0.36.3 // indirect
k8s.io/klog/v2 v2.140.0 // indirect
k8s.io/kube-openapi v0.0.0-20260721132016-d427ff9ee9ad // indirect
k8s.io/utils v0.0.0-20260707023825-cf1189d6abe3 // indirect
sigs.k8s.io/controller-runtime v0.24.1 // indirect
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect
sigs.k8s.io/randfill v1.0.0 // indirect
sigs.k8s.io/structured-merge-diff/v6 v6.3.0 // indirect
sigs.k8s.io/structured-merge-diff/v6 v6.4.2 // indirect
)
+106 -109
View File
@@ -2,67 +2,87 @@ dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8=
dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA=
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/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk=
github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0=
github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
github.com/Masterminds/semver/v3 v3.5.0 h1:kQceYJfbupGfZOKZQg0kou0DgAKhzDg2NZPAwZ/2OOE=
github.com/Masterminds/semver/v3 v3.5.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
github.com/Masterminds/sprig/v3 v3.3.0 h1:mQh0Yrg1XPo6vjYXgtf5OtijNAKJRNcTdOOGZe3tPhs=
github.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSCzdgBfDb35Lz0=
github.com/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s=
github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI=
github.com/cyphar/filepath-securejoin v0.7.0 h1:s0Y3ITPy6sQn5xt54DuYvTF8hu134ooYLUb58DX/HjE=
github.com/cyphar/filepath-securejoin v0.7.0/go.mod h1:ymLGms/u3BYaviIiuKFnUx8EkQEZeK6cInNoAPJA3o4=
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/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI=
github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/emicklei/go-restful/v3 v3.12.2 h1:DhwDP0vY3k8ZzE0RunuJy8GhNpPL6zqLkDf9B/a0/xU=
github.com/emicklei/go-restful/v3 v3.12.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/emicklei/go-restful/v3 v3.13.0 h1:C4Bl2xDndpU6nJ4bc1jXd+uTmYPVUwkD6bFY/oTyCes=
github.com/emicklei/go-restful/v3 v3.13.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
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/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM=
github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ=
github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4=
github.com/go-openapi/swag v0.23.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU=
github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0=
github.com/fxamacker/cbor/v2 v2.9.2 h1:X4Ksno9+x3cz0TZv69ec1hxP/+tymuR8PXQJyDwfh78=
github.com/fxamacker/cbor/v2 v2.9.2/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
github.com/go-logr/logr v1.4.4 h1:tG4xh9yMsRCAiodLVTxyrkzSZ9+o0L1Kg/+cPVcbP/8=
github.com/go-logr/logr v1.4.4/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-openapi/jsonpointer v1.0.0 h1:kR9tHqY0CtZaOPVFm622dPVNhrvYpwr4uCxgL3h1H8s=
github.com/go-openapi/jsonpointer v1.0.0/go.mod h1:Z3rw7dWu1p9IgitXCFamSlA5lmDiklEB6vkaxcNZW5Y=
github.com/go-openapi/jsonreference v1.0.0 h1:jlmTr6torcd1YgDQvSfNmRtKzYDO4FGBkrAdlAVWnpY=
github.com/go-openapi/jsonreference v1.0.0/go.mod h1:jtwdyGbJk0Xhe5Y+rwtglQP6Sb1WZST4rT32LWB+sv0=
github.com/go-openapi/swag v0.28.0 h1:xkgbOSKj6DZziNpyqRRAOt3GJGtgjgsd2RoyT30VWuw=
github.com/go-openapi/swag v0.28.0/go.mod h1:4qYnT3Cqr1p1VknOdPo70evN4rgQnAg6jwApHyxSGIg=
github.com/go-openapi/swag/cmdutils v0.28.0 h1:7TOeNtkYru1SG8Y34tDh9WBbLsMqGnptuxWiHREPZ4Q=
github.com/go-openapi/swag/cmdutils v0.28.0/go.mod h1:Sm1MVFMkF6guJJ+pQqHnQA3N0j9qALV3NxzDSv6bETM=
github.com/go-openapi/swag/conv v0.28.0 h1:GtqqbyFe7vR5Y7ehxG9W6/OvrSFdf1OLeTGp40TqxH8=
github.com/go-openapi/swag/conv v0.28.0/go.mod h1:mbUE+mzctnhxi864m0Q07SpN8OowD9JhxmxuYvZZD/k=
github.com/go-openapi/swag/fileutils v0.28.0 h1:Z04XWQD7R8Eq+7GnOrjovBxPPmZzsS4gt2H2GPGIViU=
github.com/go-openapi/swag/fileutils v0.28.0/go.mod h1:VvJFZLTZS0AI854gEQz5tk7dBESdLjiNUMSZ/th2ry8=
github.com/go-openapi/swag/jsonutils v0.28.0 h1:YIch6FwO7RXzeAnbO8Tu7dWBZeUEH+4nA0HXltVTnv4=
github.com/go-openapi/swag/jsonutils v0.28.0/go.mod h1:CYM3WlTUcagR2ZoHdz54di/cbBqt82tuxuXgAjxw+mg=
github.com/go-openapi/swag/jsonutils/fixtures_test v0.28.0 h1:qV+VVUAx5Oro8WjVWpZeql7YReTKhT4smR4zhcOQZr0=
github.com/go-openapi/swag/jsonutils/fixtures_test v0.28.0/go.mod h1:mofwUWx70wvskwESqRJ//k/9kURmCgyJl5m5Ppoh5kY=
github.com/go-openapi/swag/loading v0.28.0 h1:td8QZdZC9MIYGGSnSPKShKiK22I2tU5UQvuUhIBPRLU=
github.com/go-openapi/swag/loading v0.28.0/go.mod h1:rXB0QiQX5mMveXEA7ouM4KiiM9jVJe4K6BVbwhD1M4k=
github.com/go-openapi/swag/mangling v0.28.0 h1:pH8eyeNO9SLYsTMWJrurnNfKmDa28XrlA+HePVD53VM=
github.com/go-openapi/swag/mangling v0.28.0/go.mod h1:jtBE2+V+3pILxOR7Vgce+Cwp6A2PgZbvVqfNntbVs0w=
github.com/go-openapi/swag/netutils v0.28.0 h1:YXN6TALEi2pzts8/8GNm6T61HTAZsieukGZidap989k=
github.com/go-openapi/swag/netutils v0.28.0/go.mod h1:J+WYyFMLtvtCGqa6jLv+YNUmIKI3ZRQRrvfNDMoQoEQ=
github.com/go-openapi/swag/pools v0.28.0 h1:HPMZWSAfce3rdVTFcjFiCIBtDg9h4x2QlRrHipwhxeU=
github.com/go-openapi/swag/pools v0.28.0/go.mod h1:kVQefhSK5RWuRe7BXsL8htgBPAMpN7HDGpGEknqugeE=
github.com/go-openapi/swag/stringutils v0.28.0 h1:ixsc9iYgDPubHL/8nSkbnryEHpD2VRlBMLKpQyPXcDU=
github.com/go-openapi/swag/stringutils v0.28.0/go.mod h1:lzRN95CxXmA03XcDWHLOb6nOMcxCqR5rGY0lOgsfRoM=
github.com/go-openapi/swag/typeutils v0.28.0 h1:nRBKSBXjDgf01VDPB3fWeD9nQuhCOVeIYAkUx2tbkyY=
github.com/go-openapi/swag/typeutils v0.28.0/go.mod h1:Srm0xFNRZ1Y+vCxJclo5qzx8aj+1pAKda/YfFPrG0dQ=
github.com/go-openapi/swag/yamlutils v0.28.0 h1:TV3JXH6DS46KUroDtMLAYHGkdWf5VDq3wVWFirmzROY=
github.com/go-openapi/swag/yamlutils v0.28.0/go.mod h1:x0q/yndZHEgk9Rx3DyDqzFUmHy55KTvIZldvF2dTJXs=
github.com/go-openapi/testify/enable/yaml/v2 v2.6.0 h1:gGHwAJ0R/5jU8BEGDbfRNR3hL68dAVi84WuOApp29B0=
github.com/go-openapi/testify/enable/yaml/v2 v2.6.0/go.mod h1:tY+St1SGq4NFl0QIqdTY4aEdbChAHxhyB77XQi9iJCo=
github.com/go-openapi/testify/v2 v2.6.0 h1:5PKH2HE7YJ/LuRPQGvSxBRlFXNQhSetBLlGAgUEu3ug=
github.com/go-openapi/testify/v2 v2.6.0/go.mod h1:SgsVHtfooshd0tublTtJ50FPKhujf47YRqauXXOUxfw=
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/google/gnostic-models v0.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo=
github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ=
github.com/google/gnostic-models v0.7.1 h1:SisTfuFKJSKM5CPZkffwi6coztzzeYUhc3v4yxLWH8c=
github.com/google/gnostic-models v0.7.1/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo=
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J0b1vyeLSOYI8bm5wbJM/8yDe8=
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
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/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/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/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4=
github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
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/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
@@ -75,17 +95,17 @@ github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFd
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/onsi/ginkgo/v2 v2.22.0 h1:Yed107/8DjTr0lKCNt7Dn8yQ6ybuDRQoMGrNFKzMfHg=
github.com/onsi/ginkgo/v2 v2.22.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo=
github.com/onsi/gomega v1.36.1 h1:bJDPBO7ibjxcbHMgSCoo4Yj18UWbKDlLwX1x9sybDcw=
github.com/onsi/gomega v1.36.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog=
github.com/onsi/ginkgo/v2 v2.27.4 h1:fcEcQW/A++6aZAZQNUmNjvA9PSOzefMJBerHJ4t8v8Y=
github.com/onsi/ginkgo/v2 v2.27.4/go.mod h1:ArE1D/XhNXBXCBkKOLkbsb2c81dQHCRcF5zwn/ykDRo=
github.com/onsi/gomega v1.39.0 h1:y2ROC3hKFmQZJNFeGAMeHZKkjBL65mIZcvrLQBF9k6Q=
github.com/onsi/gomega v1.39.0/go.mod h1:ZCU1pkQcXDO5Sl9/VVEGlDyp+zm0m1cmeG5TOzLgdh4=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/rogpeppe/go-internal v1.15.0 h1:D0RCU5rMAp+SpgkiNdrjfJ+LX4J1M32V2NeCY7EJ6hc=
github.com/rogpeppe/go-internal v1.15.0/go.mod h1:DrUVZyrJU+txYW5/1kwtXQSMFio52ZOxX7yM1VHvnxs=
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ=
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU=
github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
@@ -102,89 +122,66 @@ github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI=
go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU=
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
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.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI=
golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8=
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/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-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.44.0 h1:evd8IRDyfNBMBTTY5XRF1vaZlD+EmWx6x8PkhR04H/I=
golang.org/x/net v0.44.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ=
golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk=
golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4=
golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
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.36.0 h1:kWS0uv/zsvHEle1LbV5LE8QujrxB3wfQyxHfhOk0Qkg=
golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s=
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=
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
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.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=
golang.org/x/sync v0.22.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs=
golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/term v0.45.0 h1:NwWyBmoJCbfTHpxrWoZ9C6/VxOf7ic219I8xZZFdrf0=
golang.org/x/term v0.45.0/go.mod h1:9aqxs0blBcrm/n0L9QW0aRVD+ktan8ssZromtqJC43w=
golang.org/x/text v0.41.0 h1:vz/seA0lnX87Othu2f/0L24RcgrXD9/YFTSuGjj3rH8=
golang.org/x/text v0.41.0/go.mod h1:jvf1O8ajNzZqhSrQBPbutR/EB83Cc0CFrezNQIwbb5M=
golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
golang.org/x/tools v0.48.0 h1:3+hClM1aLL5mjMKm5ovokw9epgRXPuu2tILgismM6RE=
golang.org/x/tools v0.48.0/go.mod h1:08xX0orndb/F7jJxGDicx061tyd5pcMto75YMAXr6lk=
google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af h1:+5/Sw3GsDNlEmu7TfklWKPdQ0Ykja5VEmq2i817+jbI=
google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4=
gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M=
gopkg.in/evanphx/json-patch.v4 v4.13.0 h1:czT3CmqEaQ1aanPc5SdlgQrrEIb8w/wwCvWWnfEbYzo=
gopkg.in/evanphx/json-patch.v4 v4.13.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M=
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
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.19.0 h1:krVyCGa8fa/wzTZgqw0DUiXuRT5BPdeqE/sQXujQ22k=
helm.sh/helm/v3 v3.19.0/go.mod h1:Lk/SfzN0w3a3C3o+TdAKrLwJ0wcZ//t1/SDXAvfgDdc=
k8s.io/api v0.34.1 h1:jC+153630BMdlFukegoEL8E/yT7aLyQkIVuwhmwDgJM=
k8s.io/api v0.34.1/go.mod h1:SB80FxFtXn5/gwzCoN6QCtPD7Vbu5w2n1S0J5gFfTYk=
k8s.io/apiextensions-apiserver v0.34.1 h1:NNPBva8FNAPt1iSVwIE0FsdrVriRXMsaWFMqJbII2CI=
k8s.io/apiextensions-apiserver v0.34.1/go.mod h1:hP9Rld3zF5Ay2Of3BeEpLAToP+l4s5UlxiHfqRaRcMc=
k8s.io/apimachinery v0.34.1 h1:dTlxFls/eikpJxmAC7MVE8oOeP1zryV7iRyIjB0gky4=
k8s.io/apimachinery v0.34.1/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw=
k8s.io/client-go v0.34.1 h1:ZUPJKgXsnKwVwmKKdPfw4tB58+7/Ik3CrjOEhsiZ7mY=
k8s.io/client-go v0.34.1/go.mod h1:kA8v0FP+tk6sZA0yKLRG67LWjqufAoSHA2xVGKw9Of8=
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-20250710124328-f3f2b991d03b h1:MloQ9/bdJyIu9lb1PzujOPolHyvO06MXG5TUIj2mNAA=
k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b/go.mod h1:UZ2yyWbFTpuhSbFhv24aGNOdoRdJZgsIObGBUaYVsts=
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 h1:hwvWFiBzdWw1FhfY1FooPn3kzWuJ8tmbZBHi4zVsl1Y=
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
sigs.k8s.io/controller-runtime v0.22.1 h1:Ah1T7I+0A7ize291nJZdS1CabF/lB4E++WizgV24Eqg=
sigs.k8s.io/controller-runtime v0.22.1/go.mod h1:FwiwRjkRPbiN+zp2QRp7wlTCzbUXxZ/D4OzuQUDwBHY=
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE=
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=
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=
k8s.io/apiextensions-apiserver v0.36.3/go.mod h1:KTXFqgXiuw2pRoL+Wpmttqc+up9Xt/GohadPWeLLOa4=
k8s.io/apimachinery v0.36.3 h1:PkzMRBRG8joFD8EhCuQAtNPvJlxb82FwplP26HIzvAM=
k8s.io/apimachinery v0.36.3/go.mod h1:cTSjBWgPe/6CQyBKzY/hDIRWCQQQeK0mfLbml0UYFHE=
k8s.io/client-go v0.36.3 h1:M4JdVzXxYcZk4fGpfDdYnxSwhLKWCFoQsHW6t+z8Hfg=
k8s.io/client-go v0.36.3/go.mod h1:gcPwr0c87vjjG6HB6pWEqOeuYVoXSsREjzux2j6GF30=
k8s.io/klog/v2 v2.140.0 h1:Tf+J3AH7xnUzZyVVXhTgGhEKnFqye14aadWv7bzXdzc=
k8s.io/klog/v2 v2.140.0/go.mod h1:o+/RWfJ6PwpnFn7OyAG3QnO47BFsymfEfrz6XyYSSp0=
k8s.io/kube-openapi v0.0.0-20260721132016-d427ff9ee9ad h1:oXImqH8mQNk7PmvzKhmN3ddJoY6OnyM225MXwGHPm0A=
k8s.io/kube-openapi v0.0.0-20260721132016-d427ff9ee9ad/go.mod h1:0/mqHCVhlumdJ3BhCfnjSZQE037nAhNodh1/hK0T8/I=
k8s.io/utils v0.0.0-20260707023825-cf1189d6abe3 h1:jVkFFVfXdXP74B/zbO3hM3hpSFD0xvhQ5U686DPurkE=
k8s.io/utils v0.0.0-20260707023825-cf1189d6abe3/go.mod h1:M2s5JB1lIYP3jzZdorPLHXIPJzt9vv2muW5a6L9DtNM=
sigs.k8s.io/controller-runtime v0.24.1 h1:miPEwrmirImAvgME1L9qebGHrOnGJoVmVdtOU9fRfo4=
sigs.k8s.io/controller-runtime v0.24.1/go.mod h1:vFkfY5fGt5xAC/sKb8IBFKgWPNKG9OUG29dR8Y2wImw=
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg=
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=
sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=
sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
sigs.k8s.io/structured-merge-diff/v6 v6.3.0 h1:jTijUJbW353oVOd9oTlifJqOGEkUw2jB/fXCbTiQEco=
sigs.k8s.io/structured-merge-diff/v6 v6.3.0/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE=
sigs.k8s.io/structured-merge-diff/v6 v6.4.2 h1:qdOxHwrl2Kaag1aQEarlYcOA9vSyGCp3CIki3aW8c4Q=
sigs.k8s.io/structured-merge-diff/v6 v6.4.2/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE=
sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs=
sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4=
+1 -1
View File
@@ -77,7 +77,7 @@ spec:
- nodeResources:
checkName: Must have 1 node with 2Gi (available) memory and at least 2 cores (on a single node)
filters:
allocatableMemory: 2Gi
memoryAllocatable: 2Gi
cpuCapacity: "2"
outcomes:
- pass:
+236
View File
@@ -0,0 +1,236 @@
# v1beta3 Support Bundle Examples
This directory contains example Support Bundle specs using the v1beta3 API, which introduces `StringOrValueFrom` support for securely referencing Kubernetes Secrets and ConfigMaps in collector fields.
## Features
### StringOrValueFrom Pattern
The v1beta3 API introduces a Kubernetes-native pattern for referencing sensitive values:
```yaml
uri:
valueFrom:
secretKeyRef:
name: my-secret
key: connection-uri
```
or
```yaml
uri: "postgresql://localhost:5432/db" # Literal value
```
### Supported Collectors
Currently, v1beta3 supports `StringOrValueFrom` for:
- **Database collectors**: `postgres`, `mysql`, `redis`, `mssql`
- `uri` field - Connection strings from secrets
- `tls` fields - CA cert, client cert, and client key from secrets
## Examples
### 1. postgres-with-secret.yaml
Basic PostgreSQL collector with connection URI from a secret.
**Use case**: Securely store database credentials without hardcoding them in the spec.
```bash
kubectl apply -f postgres-with-secret.yaml
```
### 2. postgres-with-tls.yaml
PostgreSQL with TLS configuration from secrets.
**Use case**: Secure database connections with mutual TLS, storing certificates in secrets.
```bash
kubectl apply -f postgres-with-tls.yaml
```
### 3. multiple-databases.yaml
Multiple database collectors (PostgreSQL, MySQL, Redis, MSSQL) with various configurations.
**Use case**: Collect diagnostics from multiple databases in your application stack.
```bash
kubectl apply -f multiple-databases.yaml
```
### 4. cross-namespace-secrets.yaml
Accessing secrets from different namespaces.
**Use case**: Centralized credential management in a shared namespace.
```bash
kubectl apply -f cross-namespace-secrets.yaml
```
**RBAC Requirements**: The support bundle service account needs `get` permission on secrets in the referenced namespaces.
### 5. optional-secrets.yaml
Using the `optional` field for graceful degradation.
**Use case**: Collect diagnostics even when some credentials are unavailable (e.g., optional secondary databases).
```bash
kubectl apply -f optional-secrets.yaml
```
### 6. configmap-example.yaml
Using ConfigMaps for non-sensitive configuration.
**Use case**: Store non-sensitive connection strings (e.g., development databases) in ConfigMaps.
```bash
kubectl apply -f configmap-example.yaml
```
## Key Concepts
### Secret vs ConfigMap
- **Secrets**: Use for sensitive data (passwords, tokens, certificates)
- **ConfigMaps**: Use for non-sensitive configuration (development endpoints, feature flags)
### Optional Field
```yaml
uri:
valueFrom:
secretKeyRef:
name: my-secret
key: uri
optional: true # Returns empty string if secret/key doesn't exist
```
- `optional: false` (default): Collection fails if secret is missing
- `optional: true`: Returns empty string if secret/key is missing
### Cross-Namespace Access
```yaml
uri:
valueFrom:
secretKeyRef:
name: shared-secret
key: uri
namespace: other-namespace # Access secrets in different namespaces
```
If `namespace` is not specified, uses the support bundle's namespace.
### Backward Compatibility
v1beta3 maintains backward compatibility with v1beta2 TLS configuration:
```yaml
tls:
secret: # v1beta2 style
name: tls-secret
namespace: default
```
## RBAC Configuration
Support bundles need appropriate RBAC permissions to read secrets:
```yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: troubleshoot-secret-reader
rules:
- apiGroups: [""]
resources: ["secrets"]
resourceNames: ["postgres-connection", "redis-creds"] # Restrict to specific secrets
verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: troubleshoot-secret-reader-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: troubleshoot-secret-reader
subjects:
- kind: ServiceAccount
name: troubleshoot
namespace: default
```
## Migration from v1beta2
### Before (v1beta2):
```yaml
apiVersion: troubleshoot.sh/v1beta2
kind: SupportBundle
spec:
collectors:
- postgres:
uri: "postgresql://user:password@host:5432/db" # Hardcoded
```
### After (v1beta3):
```yaml
apiVersion: troubleshoot.sh/v1beta3
kind: SupportBundle
spec:
collectors:
- postgres:
uri:
valueFrom:
secretKeyRef:
name: postgres-connection
key: connection-uri
```
## Limitations
1. **No value composition**: Cannot combine multiple secrets into a single value
```yaml
# NOT SUPPORTED
uri: "postgresql://$(USERNAME):$(PASSWORD)@host:5432/db"
```
Store the complete connection string in a single secret key.
2. **Collector scope**: Only database collectors support `StringOrValueFrom` initially
- Future versions will extend to HTTP, Data, and other collectors
3. **No templating**: The entire field value comes from one source
## Security Best Practices
1. **Use resourceNames in RBAC**: Restrict access to specific secrets
2. **Separate secrets**: Don't reuse secrets across applications
3. **Rotate credentials**: Update secrets regularly
4. **Audit access**: Monitor secret access logs
5. **Redact output**: Ensure connection strings are redacted in bundle output
## Troubleshooting
### Error: "failed to get secret default/my-secret"
- **Cause**: Secret doesn't exist or RBAC denied access
- **Solution**: Verify secret exists: `kubectl get secret my-secret`
- **Solution**: Check RBAC: `kubectl auth can-i get secret/my-secret`
### Error: "key 'uri' not found in secret"
- **Cause**: Secret exists but doesn't contain the specified key
- **Solution**: Check secret keys: `kubectl get secret my-secret -o jsonpath='{.data}'`
### Error: "cannot specify both 'value' and 'valueFrom'"
- **Cause**: Both literal value and secret reference provided
- **Solution**: Use only one: either `value: "string"` or `valueFrom: {...}`
## Additional Resources
- [Troubleshoot Documentation](https://troubleshoot.sh)
- [v1beta3 API Reference](https://troubleshoot.sh/docs/v1beta3/)
- [Kubernetes Secrets](https://kubernetes.io/docs/concepts/configuration/secret/)
- [RBAC Authorization](https://kubernetes.io/docs/reference/access-authn-authz/rbac/)
@@ -0,0 +1,57 @@
apiVersion: troubleshoot.sh/v1beta3
kind: SupportBundle
metadata:
name: configmap-example
spec:
collectors:
# Database URI from ConfigMap (non-sensitive connection string)
- postgres:
collectorName: dev-database
uri:
valueFrom:
configMapKeyRef:
name: database-config
key: dev-connection-uri
# Redis URI from ConfigMap
- redis:
collectorName: dev-redis
uri:
valueFrom:
configMapKeyRef:
name: cache-config
key: redis-uri
# Mixed: URI from ConfigMap, password from Secret
# Note: This shows the limitation - you can't compose values from multiple sources
# The full connection string must be in one place
- mysql:
collectorName: staging-mysql
uri:
valueFrom:
secretKeyRef:
name: mysql-secret
key: complete-connection-string
---
apiVersion: v1
kind: ConfigMap
metadata:
name: database-config
data:
dev-connection-uri: "postgresql://devuser@dev-postgres.default.svc:5432/devdb"
---
apiVersion: v1
kind: ConfigMap
metadata:
name: cache-config
data:
redis-uri: "redis://dev-redis.default.svc:6379/0"
---
apiVersion: v1
kind: Secret
metadata:
name: mysql-secret
type: Opaque
stringData:
# Complete connection string with password included
complete-connection-string: "mysql://staging:stagingpass@staging-mysql:3306/stagingdb"
@@ -0,0 +1,45 @@
apiVersion: troubleshoot.sh/v1beta3
kind: SupportBundle
metadata:
name: cross-namespace-example
spec:
collectors:
# Database in one namespace, secret in another
- postgres:
collectorName: shared-database
uri:
valueFrom:
secretKeyRef:
name: shared-postgres-connection
key: uri
namespace: shared-services # Secret is in a different namespace
# Redis accessing centralized credentials
- redis:
collectorName: shared-cache
uri:
valueFrom:
secretKeyRef:
name: shared-redis-creds
key: uri
namespace: platform-credentials
---
# This secret would be in the 'shared-services' namespace
apiVersion: v1
kind: Secret
metadata:
name: shared-postgres-connection
namespace: shared-services
type: Opaque
stringData:
uri: "postgresql://shared:password@shared-postgres.shared-services.svc:5432/shared_db"
---
# This secret would be in the 'platform-credentials' namespace
apiVersion: v1
kind: Secret
metadata:
name: shared-redis-creds
namespace: platform-credentials
type: Opaque
stringData:
uri: "redis://shared-redis.shared-services.svc:6379/0"
@@ -0,0 +1,78 @@
apiVersion: troubleshoot.sh/v1beta3
kind: SupportBundle
metadata:
name: multi-database-support-bundle
spec:
collectors:
# PostgreSQL with secret reference
- postgres:
collectorName: primary-db
uri:
valueFrom:
secretKeyRef:
name: postgres-primary
key: connection-uri
# PostgreSQL replica with secret reference
- postgres:
collectorName: replica-db
uri:
valueFrom:
secretKeyRef:
name: postgres-replica
key: connection-uri
# Redis cache with secret reference
- redis:
collectorName: cache
uri:
valueFrom:
secretKeyRef:
name: redis-creds
key: uri
# MySQL with literal value (for development/testing)
- mysql:
collectorName: local-mysql
uri: "mysql://root:password@localhost:3306/testdb"
# MSSQL with secret reference
- mssql:
collectorName: legacy-db
uri:
valueFrom:
secretKeyRef:
name: mssql-connection
key: dsn
---
apiVersion: v1
kind: Secret
metadata:
name: postgres-primary
type: Opaque
stringData:
connection-uri: "postgresql://app:secret123@postgres-primary.default.svc:5432/appdb"
---
apiVersion: v1
kind: Secret
metadata:
name: postgres-replica
type: Opaque
stringData:
connection-uri: "postgresql://app:secret123@postgres-replica.default.svc:5432/appdb"
---
apiVersion: v1
kind: Secret
metadata:
name: redis-creds
type: Opaque
stringData:
uri: "redis://:cachesecret@redis.default.svc:6379/0"
---
apiVersion: v1
kind: Secret
metadata:
name: mssql-connection
type: Opaque
stringData:
dsn: "sqlserver://sa:Str0ngP@ssw0rd@mssql.default.svc:1433?database=legacy"
@@ -0,0 +1,58 @@
apiVersion: troubleshoot.sh/v1beta3
kind: SupportBundle
metadata:
name: optional-secrets-example
spec:
collectors:
# Required database - collection will fail if secret doesn't exist
- postgres:
collectorName: required-db
uri:
valueFrom:
secretKeyRef:
name: required-postgres
key: uri
optional: false # Default behavior - secret must exist
# Optional database - collection continues if secret doesn't exist
- postgres:
collectorName: optional-db
uri:
valueFrom:
secretKeyRef:
name: optional-postgres
key: uri
optional: true # Gracefully degrades if secret is missing
# Mixed required and optional TLS
- postgres:
collectorName: partially-optional
uri: "postgresql://localhost:5432/db"
tls:
cacert:
valueFrom:
secretKeyRef:
name: tls-certs
key: ca.crt
optional: false # CA cert is required
clientCert:
valueFrom:
secretKeyRef:
name: tls-certs
key: client.crt
optional: true # Client cert is optional (cert-only TLS)
clientKey:
valueFrom:
secretKeyRef:
name: tls-certs
key: client.key
optional: true # Client key is optional
---
apiVersion: v1
kind: Secret
metadata:
name: required-postgres
type: Opaque
stringData:
uri: "postgresql://user:pass@required-postgres:5432/db"
# Note: optional-postgres secret intentionally not created
@@ -0,0 +1,21 @@
apiVersion: troubleshoot.sh/v1beta3
kind: SupportBundle
metadata:
name: postgres-support-bundle
spec:
collectors:
- postgres:
collectorName: main-database
uri:
valueFrom:
secretKeyRef:
name: postgres-connection
key: connection-uri
---
apiVersion: v1
kind: Secret
metadata:
name: postgres-connection
type: Opaque
stringData:
connection-uri: "postgresql://myuser:mypassword@postgres.default.svc:5432/mydb?sslmode=require"
@@ -0,0 +1,47 @@
apiVersion: troubleshoot.sh/v1beta3
kind: SupportBundle
metadata:
name: postgres-tls-support-bundle
spec:
collectors:
- postgres:
collectorName: secure-database
uri:
valueFrom:
secretKeyRef:
name: postgres-connection
key: connection-uri
tls:
cacert:
valueFrom:
secretKeyRef:
name: postgres-tls
key: ca.crt
clientCert:
valueFrom:
secretKeyRef:
name: postgres-tls
key: tls.crt
clientKey:
valueFrom:
secretKeyRef:
name: postgres-tls
key: tls.key
---
apiVersion: v1
kind: Secret
metadata:
name: postgres-connection
type: Opaque
stringData:
connection-uri: "postgresql://myuser:mypassword@postgres.default.svc:5432/mydb?sslmode=verify-full"
---
apiVersion: v1
kind: Secret
metadata:
name: postgres-tls
type: kubernetes.io/tls
data:
ca.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCi4uLgotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0t
tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCi4uLgotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0t
tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCi4uLgotLS0tLUVORCBQUklWQVRFIEtFWS0tLS0t
@@ -0,0 +1,33 @@
apiVersion: troubleshoot.sh/v1beta3
kind: Preflight
metadata:
name: helm-builtins-example
labels:
release: {{ .Release.Name }}
spec:
analyzers:
- docString: |
Title: Example using Helm builtin objects
Requirement: Demonstrates .Values, .Release, .Chart, etc.
Supported Helm builtin objects:
- .Values.* - User-provided values
- .Release.Name - Release name (default: "preflight")
- .Release.Namespace - Release namespace (default: "default")
- .Release.IsInstall - Whether this is an install (true)
- .Release.IsUpgrade - Whether this is an upgrade (false)
- .Release.Revision - Release revision (1)
- .Chart.Name - Chart name
- .Chart.Version - Chart version
- .Capabilities.KubeVersion - Kubernetes version capabilities
clusterVersion:
checkName: Kubernetes version check in {{ .Release.Namespace }}
outcomes:
- fail:
when: '< {{ .Values.minVersion | default "1.19.0" }}'
message: |
Release {{ .Release.Name }} requires Kubernetes {{ .Values.minVersion | default "1.19.0" }} or later.
Chart: {{ .Chart.Name }}
- pass:
when: '>= {{ .Values.minVersion | default "1.19.0" }}'
message: Kubernetes version is supported for release {{ .Release.Name }}
@@ -0,0 +1,19 @@
apiVersion: troubleshoot.sh/v1beta3
kind: SupportBundle
metadata:
name: invalid-collectors
spec:
collectors:
# Unknown collector type
- notACollector: {}
# Known collector but missing required fields (e.g., ceph requires namespace)
- ceph: {}
# Field exists but wrong type (should be a list)
hostCollectors: "not-a-list"
analyzers:
# Unknown analyzer type
- notAnAnalyzer: {}
# Known analyzer missing required 'outcomes'
- cephStatus:
namespace: default
@@ -0,0 +1,8 @@
apiVersion: troubleshoot.sh/v1beta3
kind: Preflight
metadata
name: invalid-yaml
spec:
analyzers:
- clusterVersion:
checkName: Kubernetes version
@@ -0,0 +1,11 @@
kind: Preflight
metadata:
name: missing-apiversion
spec:
analyzers:
- clusterVersion:
checkName: Kubernetes version
outcomes:
- pass:
when: '>= 1.19.0'
message: Kubernetes version is supported
@@ -0,0 +1,10 @@
apiVersion: troubleshoot.sh/v1beta3
kind: Preflight
spec:
analyzers:
- clusterVersion:
checkName: Kubernetes version
outcomes:
- pass:
when: '>= 1.19.0'
message: Kubernetes version is supported
@@ -0,0 +1,7 @@
apiVersion: troubleshoot.sh/v1beta3
kind: Preflight
metadata:
name: no-analyzers
spec:
collectors:
- clusterInfo: {}
@@ -0,0 +1,18 @@
apiVersion: troubleshoot.sh/v1beta3
kind: Preflight
metadata:
name: simple-no-template
spec:
analyzers:
- docString: |
Title: Kubernetes Version Check
Requirement: Kubernetes 1.19.0 or later
clusterVersion:
checkName: Kubernetes version
outcomes:
- fail:
when: '< 1.19.0'
message: Kubernetes version must be at least 1.19.0
- pass:
when: '>= 1.19.0'
message: Kubernetes version is supported
@@ -0,0 +1,12 @@
apiVersion: troubleshoot.sh/v1beta3
kind: SupportBundle
metadata:
name: no-collectors
spec:
analyzers:
- clusterVersion:
checkName: Kubernetes version
outcomes:
- pass:
when: '>= 1.19.0'
message: Kubernetes version is supported
@@ -0,0 +1,15 @@
apiVersion: troubleshoot.sh/v1beta3
kind: SupportBundle
metadata:
name: valid-support-bundle
spec:
collectors:
- clusterInfo: {}
- clusterResources: {}
analyzers:
- clusterVersion:
checkName: Kubernetes version
outcomes:
- pass:
when: '>= 1.19.0'
message: Kubernetes version is supported
@@ -0,0 +1,15 @@
apiVersion: troubleshoot.sh/v1beta3
kind: Preflight
metadata:
name: valid-preflight
spec:
analyzers:
- docString: |
Title: Test Analyzer
Requirement: Test requirement
clusterVersion:
checkName: Kubernetes version
outcomes:
- pass:
when: '>= 1.19.0'
message: Kubernetes version is supported
@@ -0,0 +1,2 @@
# Empty values file for v1beta3 specs without templates
{}
@@ -0,0 +1 @@
minVersion: "1.19.0"
@@ -0,0 +1,12 @@
apiVersion: troubleshoot.sh/v1beta2
kind: Preflight
metadata:
name: wrong-version
spec:
analyzers:
- clusterVersion:
checkName: Kubernetes version
outcomes:
- pass:
when: '>= 1.19.0'
message: Kubernetes version is supported
Generated
+61
View File
@@ -0,0 +1,61 @@
{
"nodes": {
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1783224372,
"narHash": "sha256-8i/87eeoqiGE4yOTjwSA3Eh/ziJRQEmd/unYU+K27sk=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "d407951447dcd00442e97087bf374aad70c04cea",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
"version": 7
}
+26
View File
@@ -0,0 +1,26 @@
{
description = "Troubleshoot development environment";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
};
outputs = { self, nixpkgs, flake-utils }:
flake-utils.lib.eachDefaultSystem (system:
let
pkgs = nixpkgs.legacyPackages.${system};
in {
devShells.default = pkgs.mkShell {
buildInputs = with pkgs; [
go_1_26
git # required for go VCS stamping during build
python3 # required by the dependency-update validation stage
];
shellHook = ''
echo "Troubleshoot dev $(go version)" # go 1.26.x required
'';
};
});
}
+181 -192
View File
@@ -1,290 +1,279 @@
module github.com/replicatedhq/troubleshoot
go 1.24.6
go 1.26.5
require (
github.com/ClickHouse/clickhouse-go/v2 v2.48.0
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.0
github.com/apparentlymart/go-cidr v1.1.1
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.19.0
github.com/containerd/cgroups/v3 v3.0.5
github.com/containers/image/v5 v5.36.2
github.com/distribution/distribution/v3 v3.0.0
github.com/fatih/color v1.18.0
github.com/go-logr/logr v1.4.3
github.com/cilium/ebpf v0.22.0
github.com/containerd/cgroups/v3 v3.1.3
github.com/fatih/color v1.19.0
github.com/go-logr/logr v1.4.4
github.com/go-redis/redis/v7 v7.4.1
github.com/go-sql-driver/mysql v1.9.3
github.com/go-sql-driver/mysql v1.10.0
github.com/gobwas/glob v0.2.3
github.com/godbus/dbus/v5 v5.1.0
github.com/godbus/dbus/v5 v5.2.2
github.com/google/go-containerregistry v0.21.9
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.2
github.com/hashicorp/go-getter v1.8.8
github.com/hashicorp/go-multierror v1.1.1
github.com/jackc/pgx/v5 v5.7.6
github.com/longhorn/go-iscsi-helper v0.0.0-20210330030558-49a327fb024e
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.20
github.com/microsoft/go-mssqldb v1.9.3
github.com/miekg/dns v1.1.68
github.com/mattn/go-isatty v0.0.24
github.com/microsoft/go-mssqldb v1.10.0
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
github.com/segmentio/ksuid v1.0.4
github.com/shirou/gopsutil/v4 v4.25.9
github.com/spf13/cobra v1.10.1
github.com/shirou/gopsutil/v4 v4.26.7
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
github.com/vmware-tanzu/velero v1.17.0
go.opentelemetry.io/otel v1.38.0
go.opentelemetry.io/otel/sdk v1.38.0
golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67
golang.org/x/mod v0.28.0
golang.org/x/sync v0.17.0
github.com/vmware-tanzu/velero v1.18.2
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.40.0
golang.org/x/sync v0.22.0
gopkg.in/yaml.v2 v2.4.0
k8s.io/api v0.34.1
k8s.io/apiextensions-apiserver v0.34.1
k8s.io/apimachinery v0.34.1
k8s.io/apiserver v0.34.1
k8s.io/cli-runtime v0.34.1
k8s.io/client-go v0.34.1
k8s.io/klog/v2 v2.130.1
k8s.io/kubernetes v1.34.1
oras.land/oras-go v1.2.6
sigs.k8s.io/controller-runtime v0.22.2
sigs.k8s.io/e2e-framework v0.6.0
k8s.io/api v0.36.3
k8s.io/apiextensions-apiserver v0.36.3
k8s.io/apimachinery v0.36.3
k8s.io/apiserver v0.36.3
k8s.io/cli-runtime v0.36.3
k8s.io/client-go v0.36.3
k8s.io/klog/v2 v2.140.0
k8s.io/streaming v0.36.3
oras.land/oras-go/v2 v2.6.2
sigs.k8s.io/controller-runtime v0.24.1
sigs.k8s.io/e2e-framework v0.7.0
)
require (
cel.dev/expr v0.24.0 // indirect
cloud.google.com/go/auth v0.16.2 // indirect
cel.dev/expr v0.25.2 // indirect
cloud.google.com/go/auth v0.22.0 // indirect
cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
cloud.google.com/go/compute/metadata v0.7.0 // indirect
cloud.google.com/go/monitoring v1.24.2 // indirect
cloud.google.com/go/compute/metadata v0.9.0 // indirect
cloud.google.com/go/monitoring v1.30.0 // indirect
dario.cat/mergo v1.0.2 // indirect
filippo.io/edwards25519 v1.1.0 // indirect
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.27.0 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.51.0 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.51.0 // indirect
filippo.io/edwards25519 v1.2.0 // indirect
github.com/ClickHouse/ch-go v0.74.0 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.35.0 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.59.0 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.59.0 // indirect
github.com/MakeNowJust/heredoc v1.0.0 // indirect
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver/v3 v3.4.0 // 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/aws/aws-sdk-go-v2 v1.36.3 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.10 // indirect
github.com/aws/aws-sdk-go-v2/config v1.29.15 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.17.68 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.34 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.2 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.15 // indirect
github.com/aws/aws-sdk-go-v2/service/s3 v1.80.1 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.25.3 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.1 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.33.20 // indirect
github.com/aws/smithy-go v1.22.3 // indirect
github.com/chai2010/gettext-go v1.0.2 // indirect
github.com/cncf/xds/go v0.0.0-20250326154945-ae57f3c0d45f // indirect
github.com/containerd/errdefs v1.0.0 // indirect
github.com/containerd/errdefs/pkg v0.3.0 // indirect
github.com/avast/retry-go/v4 v4.7.0 // 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
github.com/cockroachdb/redact v1.1.8 // indirect
github.com/containerd/log v0.1.0 // indirect
github.com/containerd/platforms v0.2.1 // indirect
github.com/containerd/typeurl/v2 v2.2.3 // indirect
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
github.com/distribution/reference v0.6.0 // indirect
github.com/docker/distribution v2.8.3+incompatible // indirect
github.com/ebitengine/purego v0.9.0 // indirect
github.com/emicklei/go-restful/v3 v3.12.2 // indirect
github.com/envoyproxy/go-control-plane/envoy v1.32.4 // indirect
github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect
github.com/coreos/go-systemd/v22 v22.7.0 // indirect
github.com/cyphar/filepath-securejoin v0.7.0 // indirect
github.com/docker/cli v29.7.1+incompatible // indirect
github.com/ebitengine/purego v0.10.2 // indirect
github.com/emicklei/go-restful/v3 v3.13.0 // indirect
github.com/envoyproxy/go-control-plane/envoy v1.37.0 // indirect
github.com/envoyproxy/protoc-gen-validate v1.3.3 // indirect
github.com/evanphx/json-patch/v5 v5.9.11 // indirect
github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f // indirect
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
github.com/fxamacker/cbor/v2 v2.9.2 // indirect
github.com/getsentry/sentry-go v0.48.0 // indirect
github.com/go-faster/city v1.0.1 // indirect
github.com/go-faster/errors v0.8.0 // indirect
github.com/go-gorp/gorp/v3 v3.1.0 // indirect
github.com/go-jose/go-jose/v4 v4.0.5 // indirect
github.com/go-jose/go-jose/v4 v4.1.4 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
github.com/go-openapi/swag/cmdutils v0.28.0 // indirect
github.com/go-openapi/swag/conv v0.28.0 // indirect
github.com/go-openapi/swag/fileutils v0.28.0 // indirect
github.com/go-openapi/swag/jsonutils v0.28.0 // indirect
github.com/go-openapi/swag/loading v0.28.0 // indirect
github.com/go-openapi/swag/mangling v0.28.0 // indirect
github.com/go-openapi/swag/netutils v0.28.0 // indirect
github.com/go-openapi/swag/pools v0.28.0 // indirect
github.com/go-openapi/swag/stringutils v0.28.0 // indirect
github.com/go-openapi/swag/typeutils v0.28.0 // indirect
github.com/go-openapi/swag/yamlutils v0.28.0 // indirect
github.com/go-viper/mapstructure/v2 v2.5.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect
github.com/golang-sql/sqlexp v0.1.0 // indirect
github.com/google/gnostic-models v0.7.0 // indirect
github.com/google/go-containerregistry v0.20.3 // indirect
github.com/google/gnostic-models v0.7.1 // indirect
github.com/google/s2a-go v0.1.9 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.19 // indirect
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect
github.com/gosuri/uitable v0.0.4 // indirect
github.com/hashicorp/aws-sdk-go-base/v2 v2.0.0-beta.65 // indirect
github.com/hashicorp/aws-sdk-go-base/v2 v2.0.0-beta.74 // indirect
github.com/huandu/xstrings v1.5.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
github.com/jmoiron/sqlx v1.4.0 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/kr/text v0.2.0 // 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
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
github.com/mistifyio/go-zfs/v3 v3.0.1 // indirect
github.com/lib/pq v1.12.3 // indirect
github.com/lufia/plan9stats v0.0.0-20260801144041-2fc331e7910f // indirect
github.com/mattn/go-sqlite3 v1.14.32 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/go-ps v1.0.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/moby/docker-image-spec v1.3.1 // indirect
github.com/moby/sys/capability v0.4.0 // indirect
github.com/moby/sys/user v0.4.0 // indirect
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
github.com/paulmach/orb v0.13.0 // indirect
github.com/pierrec/lz4/v4 v4.1.27 // indirect
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
github.com/rubenv/sql-migrate v1.8.0 // indirect
github.com/rogpeppe/go-internal v1.15.0 // indirect
github.com/rubenv/sql-migrate v1.8.1 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/sagikazarmark/locafero v0.11.0 // indirect
github.com/sagikazarmark/locafero v0.12.0 // indirect
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 // indirect
github.com/segmentio/asm v1.2.1 // indirect
github.com/shirou/gopsutil/v3 v3.24.5 // indirect
github.com/shopspring/decimal v1.4.0 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect
github.com/spiffe/go-spiffe/v2 v2.5.0 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/sylabs/sif/v2 v2.21.1 // indirect
github.com/tchap/go-patricia/v2 v2.3.3 // indirect
github.com/ulikunitz/xz v0.5.15 // indirect
github.com/vladimirvivien/gexe v0.4.1 // 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.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
github.com/zeebo/errs v1.4.0 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/contrib/detectors/gcp v1.36.0 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect
go.opentelemetry.io/otel/metric v1.38.0 // indirect
go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect
go.opentelemetry.io/otel/trace v1.38.0 // indirect
go.yaml.in/yaml/v2 v2.4.2 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/tools v0.36.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
k8s.io/component-base v0.34.1 // indirect
k8s.io/kubectl v0.34.0 // indirect
oras.land/oras-go/v2 v2.6.0 // indirect
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
go.opentelemetry.io/contrib/detectors/gcp v1.44.0 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.69.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0 // indirect
go.opentelemetry.io/otel/metric v1.45.0 // indirect
go.opentelemetry.io/otel/sdk/metric v1.45.0 // indirect
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
google.golang.org/genproto/googleapis/api 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
k8s.io/kubectl v0.36.3 // indirect
sigs.k8s.io/randfill v1.0.0 // indirect
sigs.k8s.io/structured-merge-diff/v6 v6.3.0 // indirect
sigs.k8s.io/structured-merge-diff/v6 v6.4.2 // indirect
)
require (
cloud.google.com/go v0.121.1 // indirect
cloud.google.com/go/iam v1.5.2 // indirect
cloud.google.com/go/storage v1.55.0 // indirect
cloud.google.com/go v0.123.0 // indirect
cloud.google.com/go/iam v1.12.0 // indirect
cloud.google.com/go/storage v1.64.0 // indirect
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect
github.com/BurntSushi/toml v1.5.0 // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/Microsoft/hcsshim v0.13.0 // indirect
github.com/BurntSushi/toml v1.6.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect
github.com/c9s/goprocinfo v0.0.0-20170724085704-0010a05ce49f // indirect
github.com/c9s/goprocinfo v0.0.0-20210130143923-c95fcf8c64a8 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/chzyer/readline v1.5.1 // indirect
github.com/containerd/containerd v1.7.28 // indirect
github.com/containerd/stargz-snapshotter/estargz v0.16.3 // indirect
github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01 // indirect
github.com/containers/ocicrypt v1.2.1 // indirect
github.com/containers/storage v1.59.1 // indirect
github.com/cyphar/filepath-securejoin v0.4.1 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/docker/cli v28.3.2+incompatible // indirect
github.com/docker/docker v28.3.3+incompatible // indirect
github.com/docker/docker-credential-helpers v0.9.3 // indirect
github.com/docker/go-connections v0.5.0 // indirect
github.com/docker/go-metrics v0.0.1 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/docker/docker-credential-helpers v0.9.8 // indirect
github.com/evanphx/json-patch v5.9.11+incompatible // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fsnotify/fsnotify v1.9.0 // indirect
github.com/go-errors/errors v1.4.2 // indirect
github.com/felixge/httpsnoop v1.1.0 // indirect
github.com/fsnotify/fsnotify v1.10.1 // indirect
github.com/go-errors/errors v1.5.1 // indirect
github.com/go-ole/go-ole v1.3.0 // indirect
github.com/go-openapi/jsonpointer v0.21.0 // indirect
github.com/go-openapi/jsonreference v0.21.0 // indirect
github.com/go-openapi/swag v0.23.1 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
github.com/go-openapi/jsonpointer v1.0.0 // indirect
github.com/go-openapi/jsonreference v1.0.0 // indirect
github.com/go-openapi/swag v0.28.0 // indirect
github.com/google/btree v1.1.3 // indirect
github.com/google/go-cmp v0.7.0 // indirect
github.com/google/go-intervals v0.0.2 // indirect
github.com/googleapis/gax-go/v2 v2.14.2 // indirect
github.com/gorilla/mux v1.8.1 // indirect
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
github.com/googleapis/gax-go/v2 v2.23.0 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-version v1.7.0
github.com/hashicorp/go-version v1.9.0
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.18.0 // indirect
github.com/klauspost/pgzip v1.2.6 // indirect
github.com/klauspost/compress v1.19.2 // indirect
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
github.com/mailru/easyjson v0.9.0 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/mattn/go-colorable v0.1.15 // indirect
github.com/mattn/go-runewidth v0.0.27 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/go-wordwrap v1.0.1
github.com/moby/locker v1.0.1 // indirect
github.com/moby/spdystream v0.5.0 // indirect
github.com/moby/sys/mountinfo v0.7.2 // indirect
github.com/moby/spdystream v0.5.1 // indirect
github.com/moby/term v0.5.2 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/nsf/termbox-go v0.0.0-20190121233118-02980233997d // indirect
github.com/nsf/termbox-go v1.1.1 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/runtime-spec v1.2.1
github.com/opencontainers/selinux v1.12.0 // indirect
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
github.com/opencontainers/runtime-spec v1.3.0
github.com/pelletier/go-toml/v2 v2.4.3 // indirect
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2
github.com/prometheus/client_golang v1.22.0 // indirect
github.com/prometheus/client_golang v1.23.2 // indirect
github.com/prometheus/client_model v0.6.2 // indirect
github.com/prometheus/common v0.65.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/prometheus/common v0.67.5 // indirect
github.com/prometheus/procfs v0.20.1 // indirect
github.com/spf13/afero v1.15.0 // indirect
github.com/spf13/cast v1.10.0 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/tklauser/go-sysconf v0.3.15 // indirect
github.com/tklauser/numcpus v0.10.0 // indirect
github.com/vbatts/tar-split v0.12.1 // indirect
github.com/tklauser/go-sysconf v0.4.0 // indirect
github.com/tklauser/numcpus v0.12.0 // indirect
github.com/xlab/treeprint v1.2.0 // indirect
github.com/yusufpapurcu/wmi v1.2.4 // indirect
go.opencensus.io v0.24.0 // indirect
golang.org/x/crypto v0.42.0 // indirect
golang.org/x/net v0.44.0
golang.org/x/oauth2 v0.30.0 // indirect
golang.org/x/sys v0.36.0
golang.org/x/term v0.35.0 // indirect
golang.org/x/text v0.29.0
golang.org/x/time v0.12.0 // indirect
google.golang.org/api v0.241.0 // indirect
google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2 // indirect
google.golang.org/grpc v1.73.0 // indirect
google.golang.org/protobuf v1.36.6 // indirect
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.41.0
golang.org/x/time v0.15.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.19.0
k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b // indirect
k8s.io/kubelet v0.34.1
k8s.io/metrics v0.34.1
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397
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
k8s.io/utils v0.0.0-20260707023825-cf1189d6abe3
periph.io/x/host/v3 v3.8.5
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
sigs.k8s.io/kustomize/api v0.20.1 // indirect
sigs.k8s.io/kustomize/kyaml v0.20.1 // indirect
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect
sigs.k8s.io/kustomize/api v0.21.1 // indirect
sigs.k8s.io/kustomize/kyaml v0.21.1 // indirect
sigs.k8s.io/yaml v1.6.0
)
+454 -582
View File
File diff suppressed because it is too large Load Diff
+9 -3
View File
@@ -191,7 +191,9 @@ func LoadFromCLIArgs(ctx context.Context, client kubernetes.Interface, args []st
// load URL spec first to remove URI key from the spec
urlSpec, err := loader.LoadSpecs(ctx, loader.LoadOptions{
RawSpec: rawURLSpec,
RawSpec: rawURLSpec,
Client: client,
Namespace: vp.GetString("namespace"),
})
if err != nil {
fmt.Println(color.YellowString("failed to load spec from URI %q: %v\n", v, err))
@@ -209,7 +211,9 @@ func LoadFromCLIArgs(ctx context.Context, client kubernetes.Interface, args []st
}
kinds, err := loader.LoadSpecs(ctx, loader.LoadOptions{
RawSpecs: rawSpecs,
RawSpecs: rawSpecs,
Client: client,
Namespace: vp.GetString("namespace"),
})
if err != nil {
return nil, err
@@ -363,7 +367,9 @@ func LoadFromCluster(ctx context.Context, client kubernetes.Interface, selectors
// Load troubleshoot specs from the raw specs
return loader.LoadSpecs(ctx, loader.LoadOptions{
RawSpecs: rawSpecs,
RawSpecs: rawSpecs,
Client: client,
Namespace: ns,
})
}
+6
View File
@@ -194,6 +194,8 @@ func GetAnalyzer(analyzer *troubleshootv1beta2.Analyze) Analyzer {
return &AnalyzeClusterVersion{analyzer: analyzer.ClusterVersion}
case analyzer.StorageClass != nil:
return &AnalyzeStorageClass{analyzer: analyzer.StorageClass}
case analyzer.IngressClass != nil:
return &AnalyzeIngressClass{analyzer: analyzer.IngressClass}
case analyzer.CustomResourceDefinition != nil:
return &AnalyzeCustomResourceDefinition{analyzer: analyzer.CustomResourceDefinition}
case analyzer.Ingress != nil:
@@ -236,6 +238,8 @@ func GetAnalyzer(analyzer *troubleshootv1beta2.Analyze) Analyzer {
return &AnalyzeMssql{analyzer: analyzer.Mssql}
case analyzer.Redis != nil:
return &AnalyzeRedis{analyzer: analyzer.Redis}
case analyzer.ClickHouse != nil:
return &AnalyzeClickhouse{analyzer: analyzer.ClickHouse}
case analyzer.CephStatus != nil:
return &AnalyzeCephStatus{analyzer: analyzer.CephStatus}
case analyzer.Velero != nil:
@@ -260,6 +264,8 @@ func GetAnalyzer(analyzer *troubleshootv1beta2.Analyze) Analyzer {
return &AnalyzeNodeMetrics{analyzer: analyzer.NodeMetrics}
case analyzer.HTTP != nil:
return &AnalyzeHTTPAnalyze{analyzer: analyzer.HTTP}
case analyzer.S3Status != nil:
return &AnalyzeS3Status{analyzer: analyzer.S3Status}
default:
return nil
}
+193
View File
@@ -0,0 +1,193 @@
package analyzer
import (
"encoding/json"
"fmt"
"path"
"strconv"
"strings"
"github.com/hashicorp/go-version"
"github.com/pkg/errors"
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
"github.com/replicatedhq/troubleshoot/pkg/collect"
)
type AnalyzeClickhouse struct {
analyzer *troubleshootv1beta2.DatabaseAnalyze
}
func (a *AnalyzeClickhouse) Title() string {
title := a.analyzer.CheckName
if title == "" {
title = a.collectorName()
}
return title
}
func (a *AnalyzeClickhouse) IsExcluded() (bool, error) {
return isExcluded(a.analyzer.Exclude)
}
func (a *AnalyzeClickhouse) Analyze(getFile getCollectedFileContents, findFiles getChildCollectedFileContents) ([]*AnalyzeResult, error) {
result, err := a.analyze(a.analyzer, getFile)
if err != nil {
return nil, err
}
result.Strict = a.analyzer.Strict.BoolOrDefaultFalse()
return []*AnalyzeResult{result}, nil
}
func (a *AnalyzeClickhouse) collectorName() string {
if a.analyzer.CollectorName != "" {
return a.analyzer.CollectorName
}
return "clickhouse"
}
func compareClickhouseConditionalToActual(conditional string, result *collect.DatabaseConnection) (bool, error) {
parts := strings.Split(strings.TrimSpace(conditional), " ")
if len(parts) != 3 {
return false, errors.New("unable to parse conditional")
}
switch parts[0] {
case "connected":
expected, err := strconv.ParseBool(parts[2])
if err != nil {
return false, errors.Wrap(err, "failed to parse bool")
}
switch parts[1] {
case "=", "==", "===":
return expected == result.IsConnected, nil
case "!=", "!==":
return expected != result.IsConnected, nil
}
return false, errors.New("unable to parse ClickHouse connected analyzer")
case "version":
expected, err := version.NewVersion(strings.ReplaceAll(parts[2], "x", "0"))
if err != nil {
return false, errors.Wrap(err, "failed to parse expected version")
}
operation := parts[1]
switch operation {
case "=", "==", "===":
operation = "="
case "!=", "!==":
operation = "!="
}
actual, err := version.NewVersion(strings.ReplaceAll(result.Version, "x", "0"))
if err != nil {
return false, errors.Wrap(err, "failed to parse ClickHouse db actual version")
}
constraints, err := version.NewConstraint(fmt.Sprintf("%s %s", operation, expected))
if err != nil {
return false, errors.Wrap(err, "failed to create constraint")
}
return constraints.Check(actual), nil
}
return false, nil
}
func (a *AnalyzeClickhouse) analyze(analyzer *troubleshootv1beta2.DatabaseAnalyze, getCollectedFileContents func(string) ([]byte, error)) (*AnalyzeResult, error) {
fullPath := path.Join("", fmt.Sprintf("clickhouse/%s.json", a.collectorName()))
collected, err := getCollectedFileContents(fullPath)
if err != nil {
return nil, errors.Wrapf(err, "failed to read collected file name: %s", fullPath)
}
databaseConnection := collect.DatabaseConnection{}
if err := json.Unmarshal(collected, &databaseConnection); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal database connection result")
}
result := &AnalyzeResult{
Title: a.Title(),
IconKey: "kubernetes_clickhouse_analyze",
IconURI: "https://troubleshoot.sh/images/analyzer-icons/clickhouse-analyze.svg",
}
for _, outcome := range analyzer.Outcomes {
if outcome.Fail != nil {
if outcome.Fail.When == "" {
result.IsFail = true
result.Message = outcome.Fail.Message
result.URI = outcome.Fail.URI
return result, nil
}
isMatch, err := compareClickhouseConditionalToActual(outcome.Fail.When, &databaseConnection)
if err != nil {
return result, errors.Wrap(err, "failed to compare ClickHouse database conditional")
}
if isMatch {
if databaseConnection.Error != "" {
result.Message = outcome.Fail.Message + " " + databaseConnection.Error
} else {
result.Message = outcome.Fail.Message
}
result.IsFail = true
result.URI = outcome.Fail.URI
return result, nil
}
} else if outcome.Warn != nil {
if outcome.Warn.When == "" {
result.IsWarn = true
result.Message = outcome.Warn.Message
result.URI = outcome.Warn.URI
return result, nil
}
isMatch, err := compareClickhouseConditionalToActual(outcome.Warn.When, &databaseConnection)
if err != nil {
return result, errors.Wrap(err, "failed to compare ClickHouse database conditional")
}
if isMatch {
result.IsWarn = true
result.Message = outcome.Warn.Message
result.URI = outcome.Warn.URI
return result, nil
}
} else if outcome.Pass != nil {
if outcome.Pass.When == "" {
result.IsPass = true
result.Message = outcome.Pass.Message
result.URI = outcome.Pass.URI
return result, nil
}
isMatch, err := compareClickhouseConditionalToActual(outcome.Pass.When, &databaseConnection)
if err != nil {
return result, errors.Wrap(err, "failed to compare ClickHouse database conditional")
}
if isMatch {
result.IsPass = true
result.Message = outcome.Pass.Message
result.URI = outcome.Pass.URI
return result, nil
}
}
}
return result, nil
}
+4
View File
@@ -699,6 +699,10 @@ func (e *DefaultAnalysisEngine) convertAnalyzerToSpec(analyzer *troubleshootv1be
spec.Name = "redis"
spec.Type = "database"
spec.Config["analyzer"] = analyzer.Redis
case analyzer.ClickHouse != nil:
spec.Name = "clickhouse"
spec.Type = "database"
spec.Config["analyzer"] = analyzer.ClickHouse
// ✅ Storage analyzers
case analyzer.CephStatus != nil:
+2
View File
@@ -67,6 +67,8 @@ func GetHostAnalyzer(analyzer *troubleshootv1beta2.HostAnalyze) (HostAnalyzer, b
return &AnalyzeHostNetworkNamespaceConnectivity{analyzer.NetworkNamespaceConnectivity}, true
case analyzer.Sysctl != nil:
return &AnalyzeHostSysctl{analyzer.Sysctl}, true
case analyzer.RegistryImages != nil:
return &AnalyzeHostRegistryImages{analyzer.RegistryImages}, true
default:
return nil, false
}
+40 -18
View File
@@ -4,6 +4,7 @@ import (
"encoding/json"
"fmt"
"regexp"
"slices"
"strconv"
"strings"
@@ -16,6 +17,25 @@ type AnalyzeHostBlockDevices struct {
hostAnalyzer *troubleshootv1beta2.BlockDevicesAnalyze
}
// blockDevicesMatchConfig carries analyzer settings for counting devices toward a blockDevices when-clause
// ("<name-regex> <op> <count>" against host block_devices.json). A device is eligible when its name matches
// the regex; its type is "disk", or "part" if includeUnmountedPartitions, or listed in additionalDeviceTypes;
// size >= minimumAcceptableSize when that is non-zero; it has no mountpoint or filesystem; it is not
// read-only or removable; and no other row has ParentKernelName equal to its KernelName.
type blockDevicesMatchConfig struct {
minimumAcceptableSize uint64
includeUnmountedPartitions bool
additionalDeviceTypes []string
}
func matchConfigFromAnalyzer(a *troubleshootv1beta2.BlockDevicesAnalyze) blockDevicesMatchConfig {
return blockDevicesMatchConfig{
minimumAcceptableSize: a.MinimumAcceptableSize,
includeUnmountedPartitions: a.IncludeUnmountedPartitions,
additionalDeviceTypes: a.AdditionalDeviceTypes,
}
}
func (a *AnalyzeHostBlockDevices) Title() string {
return hostAnalyzerTitleOrDefault(a.hostAnalyzer.AnalyzeMeta, "Block Devices")
}
@@ -49,7 +69,7 @@ func (a *AnalyzeHostBlockDevices) Analyze(
// <regexp> <op> <count>
// example: sdb > 0
func compareHostBlockDevicesConditionalToActual(conditional string, minimumAcceptableSize uint64, includeUnmountedPartitions bool, devices []collect.BlockDeviceInfo) (res bool, err error) {
func compareHostBlockDevicesConditionalToActual(conditional string, cfg blockDevicesMatchConfig, devices []collect.BlockDeviceInfo) (res bool, err error) {
parts := strings.Split(conditional, " ")
if len(parts) != 3 {
return false, fmt.Errorf("Expected exactly 3 parts, got %d", len(parts))
@@ -59,7 +79,7 @@ func compareHostBlockDevicesConditionalToActual(conditional string, minimumAccep
if err != nil {
return false, errors.Wrapf(err, "failed to compile regex %q", parts[0])
}
count := countEligibleBlockDevices(rx, minimumAcceptableSize, includeUnmountedPartitions, devices)
count := countEligibleBlockDevices(rx, cfg, devices)
desiredInt, err := strconv.Atoi(parts[2])
if err != nil {
@@ -82,11 +102,11 @@ func compareHostBlockDevicesConditionalToActual(conditional string, minimumAccep
return false, fmt.Errorf("Unexpected operator %q", parts[1])
}
func countEligibleBlockDevices(rx *regexp.Regexp, minimumAcceptableSize uint64, includeUnmountedPartitions bool, devices []collect.BlockDeviceInfo) int {
func countEligibleBlockDevices(rx *regexp.Regexp, cfg blockDevicesMatchConfig, devices []collect.BlockDeviceInfo) int {
count := 0
for _, device := range devices {
if isEligibleBlockDevice(rx, minimumAcceptableSize, includeUnmountedPartitions, device, devices) {
if isEligibleBlockDevice(rx, cfg, device, devices) {
count++
}
}
@@ -94,23 +114,27 @@ func countEligibleBlockDevices(rx *regexp.Regexp, minimumAcceptableSize uint64,
return count
}
func isEligibleBlockDevice(rx *regexp.Regexp, minimumAcceptableSize uint64, includeUnmountedPartitions bool, device collect.BlockDeviceInfo, devices []collect.BlockDeviceInfo) bool {
func isEligibleDeviceType(deviceType string, cfg blockDevicesMatchConfig) bool {
if deviceType == "disk" {
return true
}
if cfg.includeUnmountedPartitions && deviceType == "part" {
return true
}
return slices.Contains(cfg.additionalDeviceTypes, deviceType)
}
func isEligibleBlockDevice(rx *regexp.Regexp, cfg blockDevicesMatchConfig, device collect.BlockDeviceInfo, devices []collect.BlockDeviceInfo) bool {
if !rx.MatchString(device.Name) {
return false
}
if includeUnmountedPartitions {
if device.Type != "disk" && device.Type != "part" {
return false
}
} else {
if device.Type != "disk" {
return false
}
if !isEligibleDeviceType(device.Type, cfg) {
return false
}
if minimumAcceptableSize != 0 {
if device.Size < minimumAcceptableSize {
if cfg.minimumAcceptableSize != 0 {
if device.Size < cfg.minimumAcceptableSize {
return false
}
}
@@ -141,12 +165,10 @@ func isEligibleBlockDevice(rx *regexp.Regexp, minimumAcceptableSize uint64, incl
}
func (a *AnalyzeHostBlockDevices) CheckCondition(when string, data []byte) (bool, error) {
var devices []collect.BlockDeviceInfo
if err := json.Unmarshal(data, &devices); err != nil {
return false, errors.Wrap(err, "failed to unmarshal block devices info")
}
return compareHostBlockDevicesConditionalToActual(when, a.hostAnalyzer.MinimumAcceptableSize, a.hostAnalyzer.IncludeUnmountedPartitions, devices)
return compareHostBlockDevicesConditionalToActual(when, matchConfigFromAnalyzer(a.hostAnalyzer), devices)
}
@@ -0,0 +1,102 @@
package analyzer
import (
"testing"
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
"github.com/replicatedhq/troubleshoot/pkg/collect"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// TestHostBlockDevices_deviceTypeEligibility documents type rules in isolation (see blockDevicesMatchConfig in host_block_devices.go).
func TestHostBlockDevices_deviceTypeEligibility(t *testing.T) {
tests := []struct {
name string
cfg blockDevicesMatchConfig
devType string
want bool
}{
{name: "disk always", cfg: blockDevicesMatchConfig{}, devType: "disk", want: true},
{name: "part without flag", cfg: blockDevicesMatchConfig{}, devType: "part", want: false},
{name: "part with flag", cfg: blockDevicesMatchConfig{includeUnmountedPartitions: true}, devType: "part", want: true},
{name: "loop without additional", cfg: blockDevicesMatchConfig{}, devType: "loop", want: false},
{name: "loop with additional", cfg: blockDevicesMatchConfig{additionalDeviceTypes: []string{"loop"}}, devType: "loop", want: true},
{name: "lvm with additional", cfg: blockDevicesMatchConfig{additionalDeviceTypes: []string{"lvm"}}, devType: "lvm", want: true},
{name: "crypt with additional", cfg: blockDevicesMatchConfig{additionalDeviceTypes: []string{"crypt"}}, devType: "crypt", want: true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := isEligibleDeviceType(tt.devType, tt.cfg)
assert.Equal(t, tt.want, got)
})
}
}
// TestHostBlockDevices_additionalDeviceTypes covers end-to-end analyze behavior for AdditionalDeviceTypes and representative preflights.
func TestHostBlockDevices_additionalDeviceTypes(t *testing.T) {
const rawStoragePass = "At least one raw block device is available for storage."
const rawStorageFail = "No raw block devices found. At least one unformatted, unmounted disk is required for storage. Attach a raw disk and ensure it has no filesystem or mount point."
rawStorageOutcomes := []*troubleshootv1beta2.Outcome{
{Fail: &troubleshootv1beta2.SingleOutcome{When: ".* == 0", Message: rawStorageFail}},
{Pass: &troubleshootv1beta2.SingleOutcome{When: ".* >= 1", Message: rawStoragePass}},
}
tests := []struct {
name string
devices []collect.BlockDeviceInfo
hostAnalyzer *troubleshootv1beta2.BlockDevicesAnalyze
want []*AnalyzeResult
}{
{
name: "preflight-style 10GiB loop0 with includeUnmountedPartitions + additionalDeviceTypes loop",
devices: []collect.BlockDeviceInfo{{
Name: "loop0", KernelName: "loop0", Type: "loop", Major: 7, Minor: 0,
Size: 10737418240, ReadOnly: false, Removable: false,
}},
hostAnalyzer: &troubleshootv1beta2.BlockDevicesAnalyze{
IncludeUnmountedPartitions: true,
MinimumAcceptableSize: 10737418240,
AdditionalDeviceTypes: []string{"loop"},
Outcomes: rawStorageOutcomes,
},
want: []*AnalyzeResult{{Title: "Block Devices", IsPass: true, Message: rawStoragePass}},
},
{
name: "preflight-style 10GiB LVM with includeUnmountedPartitions + additionalDeviceTypes lvm",
devices: []collect.BlockDeviceInfo{{
Name: "ceph--vg-lv--osd0", KernelName: "dm-0", Type: "lvm", Major: 252, Minor: 0,
Size: 10737418240, ReadOnly: false, Removable: false,
}},
hostAnalyzer: &troubleshootv1beta2.BlockDevicesAnalyze{
IncludeUnmountedPartitions: true,
MinimumAcceptableSize: 10737418240,
AdditionalDeviceTypes: []string{"lvm"},
Outcomes: rawStorageOutcomes,
},
want: []*AnalyzeResult{{Title: "Block Devices", IsPass: true, Message: rawStoragePass}},
},
{
name: "loop counts with only additionalDeviceTypes (includeUnmountedPartitions false)",
devices: []collect.BlockDeviceInfo{{
Name: "loop0", KernelName: "loop0", Type: "loop", Major: 7,
}},
hostAnalyzer: &troubleshootv1beta2.BlockDevicesAnalyze{
AdditionalDeviceTypes: []string{"loop"},
Outcomes: []*troubleshootv1beta2.Outcome{
{Pass: &troubleshootv1beta2.SingleOutcome{When: ".* > 0", Message: "Block device available"}},
{Fail: &troubleshootv1beta2.SingleOutcome{Message: "No block device available"}},
},
},
want: []*AnalyzeResult{{Title: "Block Devices", IsPass: true, Message: "Block device available"}},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := analyzeHostBlockDevicesOutput(t, tt.devices, tt.hostAnalyzer)
require.NoError(t, err)
assert.Equal(t, tt.want, got)
})
}
}
+10 -11
View File
@@ -256,23 +256,22 @@ func TestAnalyzeBlockDevices(t *testing.T) {
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
req := require.New(t)
b, err := json.Marshal(test.devices)
if err != nil {
t.Fatal(err)
}
getCollectedFileContents := func(filename string) ([]byte, error) {
return b, nil
}
result, err := (&AnalyzeHostBlockDevices{test.hostAnalyzer}).Analyze(getCollectedFileContents, nil)
result, err := analyzeHostBlockDevicesOutput(t, test.devices, test.hostAnalyzer)
if test.expectErr {
req.Error(err)
} else {
req.NoError(err)
}
assert.Equal(t, test.result, result)
})
}
}
// analyzeHostBlockDevicesOutput runs the host block device analyzer on marshaled fixture data (shared by match tests).
func analyzeHostBlockDevicesOutput(t *testing.T, devices []collect.BlockDeviceInfo, hostAnalyzer *troubleshootv1beta2.BlockDevicesAnalyze) ([]*AnalyzeResult, error) {
t.Helper()
b, err := json.Marshal(devices)
require.NoError(t, err)
getCollectedFileContents := func(string) ([]byte, error) { return b, nil }
return (&AnalyzeHostBlockDevices{hostAnalyzer}).Analyze(getCollectedFileContents, nil)
}
+199
View File
@@ -0,0 +1,199 @@
package analyzer
import (
"encoding/json"
"fmt"
"slices"
"github.com/pkg/errors"
"github.com/replicatedhq/troubleshoot/internal/util"
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
"github.com/replicatedhq/troubleshoot/pkg/collect"
"k8s.io/klog/v2"
)
// RegistryImagesSummary is passed as template data when rendering outcome messages.
// Fields are exported so Go templates can reference them.
//
// - Verified: images confirmed to exist in the registry.
// - Missing: images confirmed not to exist in the registry.
// - Errors: images that could not be checked (parse failures, timeouts, auth errors, etc).
// - UnverifiedReasons: map of image name to reason string for every unverified image
// (union of Missing and Errors).
//
// The `when` conditions follow the existing registry images analyzer nomenclature:
// "verified", "missing", and "errors" (see https://troubleshoot.sh/docs/analyze/registry-images).
type RegistryImagesSummary struct {
Verified []string
Missing []string
Errors []string
UnverifiedReasons map[string]string
}
type AnalyzeHostRegistryImages struct {
hostAnalyzer *troubleshootv1beta2.HostRegistryImagesAnalyze
}
func (a *AnalyzeHostRegistryImages) Title() string {
return hostAnalyzerTitleOrDefault(a.hostAnalyzer.AnalyzeMeta, "Registry Images")
}
func (a *AnalyzeHostRegistryImages) IsExcluded() (bool, error) {
return isExcluded(a.hostAnalyzer.Exclude)
}
func (a *AnalyzeHostRegistryImages) Analyze(
getCollectedFileContents func(string) ([]byte, error), findFiles getChildCollectedFileContents,
) ([]*AnalyzeResult, error) {
collectorName := a.hostAnalyzer.CollectorName
if collectorName == "" {
collectorName = "images"
}
const nodeBaseDir = "host-collectors/registry-images"
localPath := fmt.Sprintf("%s/%s.json", nodeBaseDir, collectorName)
fileName := fmt.Sprintf("%s.json", collectorName)
collectedContents, err := retrieveCollectedContents(
getCollectedFileContents,
localPath,
nodeBaseDir,
fileName,
)
if err != nil {
return []*AnalyzeResult{{Title: a.Title()}}, err
}
var results []*AnalyzeResult
for _, content := range collectedContents {
currentTitle := a.Title()
if content.NodeName != "" {
currentTitle = fmt.Sprintf("%s - Node %s", a.Title(), content.NodeName)
}
result, err := a.evaluateOutcomesWithTemplate(content.Data, currentTitle)
if err != nil {
return nil, errors.Wrap(err, "failed to analyze host registry images")
}
if result != nil {
klog.V(2).Infof("registry images analysis result: title=%q pass=%t warn=%t fail=%t message=%q",
result.Title, result.IsPass, result.IsWarn, result.IsFail, result.Message)
results = append(results, result)
}
}
return results, nil
}
func (a *AnalyzeHostRegistryImages) evaluateOutcomesWithTemplate(data []byte, title string) (*AnalyzeResult, error) {
summary, err := buildRegistryImagesSummary(data)
if err != nil {
return nil, err
}
for _, outcome := range a.hostAnalyzer.Outcomes {
result := &AnalyzeResult{Title: title}
switch {
case outcome.Fail != nil:
if outcome.Fail.When == "" {
result.IsFail = true
result.Message = renderRegistryMessage(outcome.Fail.Message, summary)
result.URI = outcome.Fail.URI
return result, nil
}
isMatch, err := compareRegistryConditionalToActual(outcome.Fail.When, len(summary.Verified), len(summary.Missing), len(summary.Errors))
if err != nil {
return result, errors.Wrapf(err, "failed to compare %s", outcome.Fail.When)
}
if isMatch {
result.IsFail = true
result.Message = renderRegistryMessage(outcome.Fail.Message, summary)
result.URI = outcome.Fail.URI
return result, nil
}
case outcome.Warn != nil:
if outcome.Warn.When == "" {
result.IsWarn = true
result.Message = renderRegistryMessage(outcome.Warn.Message, summary)
result.URI = outcome.Warn.URI
return result, nil
}
isMatch, err := compareRegistryConditionalToActual(outcome.Warn.When, len(summary.Verified), len(summary.Missing), len(summary.Errors))
if err != nil {
return result, errors.Wrapf(err, "failed to compare %s", outcome.Warn.When)
}
if isMatch {
result.IsWarn = true
result.Message = renderRegistryMessage(outcome.Warn.Message, summary)
result.URI = outcome.Warn.URI
return result, nil
}
case outcome.Pass != nil:
if outcome.Pass.When == "" {
result.IsPass = true
result.Message = renderRegistryMessage(outcome.Pass.Message, summary)
result.URI = outcome.Pass.URI
return result, nil
}
isMatch, err := compareRegistryConditionalToActual(outcome.Pass.When, len(summary.Verified), len(summary.Missing), len(summary.Errors))
if err != nil {
return result, errors.Wrapf(err, "failed to compare %s", outcome.Pass.When)
}
if isMatch {
result.IsPass = true
result.Message = renderRegistryMessage(outcome.Pass.Message, summary)
result.URI = outcome.Pass.URI
return result, nil
}
}
}
return nil, nil
}
func buildRegistryImagesSummary(data []byte) (*RegistryImagesSummary, error) {
var registryInfo collect.RegistryInfo
if err := json.Unmarshal(data, &registryInfo); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal registry info")
}
summary := &RegistryImagesSummary{
UnverifiedReasons: map[string]string{},
}
for image, info := range registryInfo.Images {
if info.Error != "" {
summary.Errors = append(summary.Errors, image)
summary.UnverifiedReasons[image] = info.Error
} else if !info.Exists {
summary.Missing = append(summary.Missing, image)
summary.UnverifiedReasons[image] = "image not found in registry"
} else {
summary.Verified = append(summary.Verified, image)
}
}
slices.Sort(summary.Verified)
slices.Sort(summary.Missing)
slices.Sort(summary.Errors)
return summary, nil
}
func renderRegistryMessage(message string, summary *RegistryImagesSummary) string {
rendered, err := util.RenderTemplate(message, summary)
if err != nil {
klog.V(2).Infof("Failed to render registry message template: %v", err)
return message
}
return rendered
}
func (a *AnalyzeHostRegistryImages) CheckCondition(when string, data []byte) (bool, error) {
summary, err := buildRegistryImagesSummary(data)
if err != nil {
return false, err
}
return compareRegistryConditionalToActual(when, len(summary.Verified), len(summary.Missing), len(summary.Errors))
}
+412
View File
@@ -0,0 +1,412 @@
package analyzer
import (
"encoding/json"
"testing"
"github.com/pkg/errors"
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
"github.com/replicatedhq/troubleshoot/pkg/collect"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestAnalyzeHostRegistryImagesCheckCondition(t *testing.T) {
tests := []struct {
name string
conditional string
data collect.RegistryInfo
expected bool
expectErr string
}{
{
name: "all images found",
conditional: "missing == 0",
data: collect.RegistryInfo{
Images: map[string]collect.RegistryImage{
"registry.example.com/app:v1": {Exists: true},
"registry.example.com/app:v2": {Exists: true},
},
},
expected: true,
},
{
name: "some images not found",
conditional: "missing > 0",
data: collect.RegistryInfo{
Images: map[string]collect.RegistryImage{
"registry.example.com/app:v1": {Exists: true},
"registry.example.com/app:v2": {Exists: false},
},
},
expected: true,
},
{
name: "verified count matches found",
conditional: "verified == 2",
data: collect.RegistryInfo{
Images: map[string]collect.RegistryImage{
"registry.example.com/app:v1": {Exists: true},
"registry.example.com/app:v2": {Exists: true},
},
},
expected: true,
},
{
name: "errored images counted under errors",
conditional: "errors > 0",
data: collect.RegistryInfo{
Images: map[string]collect.RegistryImage{
"registry.example.com/app:v1": {Error: "connection refused"},
},
},
expected: true,
},
{
name: "no errors when all found",
conditional: "missing == 0",
data: collect.RegistryInfo{
Images: map[string]collect.RegistryImage{
"registry.example.com/app:v1": {Exists: true},
},
},
expected: true,
},
{
name: "mixed results - missing and errors counted separately",
conditional: "missing == 1",
data: collect.RegistryInfo{
Images: map[string]collect.RegistryImage{
"registry.example.com/app:v1": {Exists: true},
"registry.example.com/app:v2": {Exists: false},
"registry.example.com/app:v3": {Error: "timeout"},
},
},
expected: true,
},
{
name: "invalid conditional format",
conditional: "missing",
data: collect.RegistryInfo{
Images: map[string]collect.RegistryImage{},
},
expected: false,
expectErr: "unable to parse conditional",
},
{
name: "unmarshal error",
conditional: "missing == 0",
expected: false,
expectErr: "failed to unmarshal registry info",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
req := require.New(t)
a := &AnalyzeHostRegistryImages{}
var data []byte
if test.expectErr == "failed to unmarshal registry info" {
data = []byte(`{not valid json}`)
} else {
var err error
data, err = json.Marshal(test.data)
req.NoError(err)
}
result, err := a.CheckCondition(test.conditional, data)
if test.expectErr != "" {
req.ErrorContains(err, test.expectErr)
} else {
req.NoError(err)
}
assert.Equal(t, test.expected, result)
})
}
}
func TestAnalyzeHostRegistryImages(t *testing.T) {
tests := []struct {
name string
hostAnalyzer *troubleshootv1beta2.HostRegistryImagesAnalyze
getCollectedFileContents func(string) ([]byte, error)
expectedResults []*AnalyzeResult
expectedError string
}{
{
name: "pass when all images found",
hostAnalyzer: &troubleshootv1beta2.HostRegistryImagesAnalyze{
Outcomes: []*troubleshootv1beta2.Outcome{
{
Pass: &troubleshootv1beta2.SingleOutcome{
When: "missing == 0",
Message: "All images are available",
},
},
},
},
getCollectedFileContents: func(path string) ([]byte, error) {
if path == "host-collectors/registry-images/images.json" {
return json.Marshal(collect.RegistryInfo{
Images: map[string]collect.RegistryImage{
"registry.example.com/app:v1": {Exists: true},
},
})
}
return nil, errors.New("file not found")
},
expectedResults: []*AnalyzeResult{
{
Title: "Registry Images",
IsPass: true,
Message: "All images are available",
},
},
},
{
name: "fail when images not found",
hostAnalyzer: &troubleshootv1beta2.HostRegistryImagesAnalyze{
Outcomes: []*troubleshootv1beta2.Outcome{
{
Fail: &troubleshootv1beta2.SingleOutcome{
When: "missing > 0",
Message: "Some images are not available",
},
},
},
},
getCollectedFileContents: func(path string) ([]byte, error) {
if path == "host-collectors/registry-images/images.json" {
return json.Marshal(collect.RegistryInfo{
Images: map[string]collect.RegistryImage{
"registry.example.com/app:v1": {Exists: false},
},
})
}
return nil, errors.New("file not found")
},
expectedResults: []*AnalyzeResult{
{
Title: "Registry Images",
IsFail: true,
Message: "Some images are not available",
},
},
},
{
name: "errored images matched by errors condition",
hostAnalyzer: &troubleshootv1beta2.HostRegistryImagesAnalyze{
Outcomes: []*troubleshootv1beta2.Outcome{
{
Fail: &troubleshootv1beta2.SingleOutcome{
When: "errors > 0",
Message: "Some images are not available",
},
},
},
},
getCollectedFileContents: func(path string) ([]byte, error) {
if path == "host-collectors/registry-images/images.json" {
return json.Marshal(collect.RegistryInfo{
Images: map[string]collect.RegistryImage{
"registry.example.com/app:v1": {Error: "connection refused"},
},
})
}
return nil, errors.New("file not found")
},
expectedResults: []*AnalyzeResult{
{
Title: "Registry Images",
IsFail: true,
Message: "Some images are not available",
},
},
},
{
name: "custom collector name used in path",
hostAnalyzer: &troubleshootv1beta2.HostRegistryImagesAnalyze{
CollectorName: "my-registry",
Outcomes: []*troubleshootv1beta2.Outcome{
{
Pass: &troubleshootv1beta2.SingleOutcome{
When: "missing == 0",
Message: "All images are available",
},
},
},
},
getCollectedFileContents: func(path string) ([]byte, error) {
if path == "host-collectors/registry-images/my-registry.json" {
return json.Marshal(collect.RegistryInfo{
Images: map[string]collect.RegistryImage{
"registry.example.com/app:v1": {Exists: true},
},
})
}
return nil, errors.New("file not found")
},
expectedResults: []*AnalyzeResult{
{
Title: "Registry Images",
IsPass: true,
Message: "All images are available",
},
},
},
{
name: "return error when collection data missing",
hostAnalyzer: &troubleshootv1beta2.HostRegistryImagesAnalyze{
Outcomes: []*troubleshootv1beta2.Outcome{
{
Pass: &troubleshootv1beta2.SingleOutcome{
When: "missing == 0",
Message: "All images are available",
},
},
},
},
getCollectedFileContents: func(path string) ([]byte, error) {
return nil, errors.New("file not found")
},
expectedResults: []*AnalyzeResult{
{
Title: "Registry Images",
},
},
expectedError: "file not found",
},
{
name: "template rendering with NotFound list",
hostAnalyzer: &troubleshootv1beta2.HostRegistryImagesAnalyze{
Outcomes: []*troubleshootv1beta2.Outcome{
{
Fail: &troubleshootv1beta2.SingleOutcome{
When: "missing > 0",
Message: "Missing: {{ .Missing | join \", \" }}",
},
},
},
},
getCollectedFileContents: func(path string) ([]byte, error) {
if path == "host-collectors/registry-images/images.json" {
return json.Marshal(collect.RegistryInfo{
Images: map[string]collect.RegistryImage{
"registry.example.com/app:v1": {Exists: false},
"registry.example.com/app:v2": {Exists: true},
},
})
}
return nil, errors.New("file not found")
},
expectedResults: []*AnalyzeResult{
{
Title: "Registry Images",
IsFail: true,
Message: "Missing: registry.example.com/app:v1",
},
},
},
{
name: "template rendering with NotFoundReasons map",
hostAnalyzer: &troubleshootv1beta2.HostRegistryImagesAnalyze{
Outcomes: []*troubleshootv1beta2.Outcome{
{
Fail: &troubleshootv1beta2.SingleOutcome{
When: "errors > 0",
Message: `{{ range $image, $reason := .UnverifiedReasons }}{{ $image }}: {{ $reason }}; {{ end }}`,
},
},
},
},
getCollectedFileContents: func(path string) ([]byte, error) {
if path == "host-collectors/registry-images/images.json" {
return json.Marshal(collect.RegistryInfo{
Images: map[string]collect.RegistryImage{
"registry.example.com/app:v1": {Error: "connection refused"},
},
})
}
return nil, errors.New("file not found")
},
expectedResults: []*AnalyzeResult{
{
Title: "Registry Images",
IsFail: true,
Message: "registry.example.com/app:v1: connection refused; ",
},
},
},
{
name: "template rendering with Found count",
hostAnalyzer: &troubleshootv1beta2.HostRegistryImagesAnalyze{
Outcomes: []*troubleshootv1beta2.Outcome{
{
Pass: &troubleshootv1beta2.SingleOutcome{
When: "missing == 0",
Message: "All {{ len .Verified }} images are available",
},
},
},
},
getCollectedFileContents: func(path string) ([]byte, error) {
if path == "host-collectors/registry-images/images.json" {
return json.Marshal(collect.RegistryInfo{
Images: map[string]collect.RegistryImage{
"registry.example.com/app:v1": {Exists: true},
"registry.example.com/app:v2": {Exists: true},
},
})
}
return nil, errors.New("file not found")
},
expectedResults: []*AnalyzeResult{
{
Title: "Registry Images",
IsPass: true,
Message: "All 2 images are available",
},
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
req := require.New(t)
a := &AnalyzeHostRegistryImages{
hostAnalyzer: test.hostAnalyzer,
}
results, err := a.Analyze(test.getCollectedFileContents, nil)
if test.expectedError != "" {
req.ErrorContains(err, test.expectedError)
} else {
req.NoError(err)
}
req.Equal(test.expectedResults, results)
})
}
}
func TestAnalyzeHostRegistryImagesTitle(t *testing.T) {
t.Run("default title", func(t *testing.T) {
a := &AnalyzeHostRegistryImages{
hostAnalyzer: &troubleshootv1beta2.HostRegistryImagesAnalyze{},
}
assert.Equal(t, "Registry Images", a.Title())
})
t.Run("custom title", func(t *testing.T) {
a := &AnalyzeHostRegistryImages{
hostAnalyzer: &troubleshootv1beta2.HostRegistryImagesAnalyze{
AnalyzeMeta: troubleshootv1beta2.AnalyzeMeta{
CheckName: "My Registry Check",
},
},
}
assert.Equal(t, "My Registry Check", a.Title())
})
}
+87
View File
@@ -0,0 +1,87 @@
package analyzer
import (
"encoding/json"
"fmt"
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
"github.com/replicatedhq/troubleshoot/pkg/constants"
networkingv1 "k8s.io/api/networking/v1"
)
type AnalyzeIngressClass struct {
analyzer *troubleshootv1beta2.IngressClass
}
func (a *AnalyzeIngressClass) Title() string {
title := a.analyzer.CheckName
if title == "" {
if a.analyzer.IngressClassName != "" {
title = fmt.Sprintf("Ingress class %s", a.analyzer.IngressClassName)
} else {
title = "Default Ingress Class"
}
}
return title
}
func (a *AnalyzeIngressClass) IsExcluded() (bool, error) {
return isExcluded(a.analyzer.Exclude)
}
func (a *AnalyzeIngressClass) Analyze(getFile getCollectedFileContents, findFiles getChildCollectedFileContents) ([]*AnalyzeResult, error) {
result, err := a.analyzeIngressClass(a.analyzer, getFile)
if err != nil {
return nil, err
}
result.Strict = a.analyzer.Strict.BoolOrDefaultFalse()
return []*AnalyzeResult{result}, nil
}
func (a *AnalyzeIngressClass) analyzeIngressClass(analyzer *troubleshootv1beta2.IngressClass, getCollectedFileContents func(string) ([]byte, error)) (*AnalyzeResult, error) {
ingressClassesData, err := getCollectedFileContents(fmt.Sprintf("%s/%s.json", constants.CLUSTER_RESOURCES_DIR, constants.CLUSTER_RESOURCES_INGRESS_CLASS))
if err != nil {
return nil, err
}
var ingressClasses networkingv1.IngressClassList
if err := json.Unmarshal(ingressClassesData, &ingressClasses); err != nil {
return nil, err
}
result := AnalyzeResult{
Title: a.Title(),
IconKey: "kubernetes_ingress_class",
IconURI: "https://troubleshoot.sh/images/analyzer-icons/ingress-class.svg?w=12&h=12",
}
for _, ingressClass := range ingressClasses.Items {
val := ingressClass.Annotations["ingressclass.kubernetes.io/is-default-class"]
if (ingressClass.Name == analyzer.IngressClassName) || (analyzer.IngressClassName == "" && val == "true") {
result.IsPass = true
for _, outcome := range analyzer.Outcomes {
if outcome.Pass != nil {
result.Message = outcome.Pass.Message
result.URI = outcome.Pass.URI
}
}
if analyzer.IngressClassName == "" && result.Message == "" {
result.Message = "Default Ingress Class found"
}
return &result, nil
}
}
result.IsFail = true
for _, outcome := range analyzer.Outcomes {
if outcome.Fail != nil {
result.Message = outcome.Fail.Message
result.URI = outcome.Fail.URI
}
}
if analyzer.IngressClassName == "" && result.Message == "" {
result.Message = "No Default Ingress Class found"
}
return &result, nil
}
+202
View File
@@ -0,0 +1,202 @@
package analyzer
import (
"encoding/json"
"testing"
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
networkingv1 "k8s.io/api/networking/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
func TestAnalyzeIngressClass(t *testing.T) {
tests := []struct {
name string
analyzer *troubleshootv1beta2.IngressClass
ingressList *networkingv1.IngressClassList
expectResult AnalyzeResult
}{
{
name: "named ingress class found",
analyzer: &troubleshootv1beta2.IngressClass{
IngressClassName: "nginx",
Outcomes: []*troubleshootv1beta2.Outcome{
{
Pass: &troubleshootv1beta2.SingleOutcome{
Message: "nginx ingress class found",
},
},
{
Fail: &troubleshootv1beta2.SingleOutcome{
Message: "nginx ingress class not found",
},
},
},
},
ingressList: &networkingv1.IngressClassList{
Items: []networkingv1.IngressClass{
{ObjectMeta: metav1.ObjectMeta{Name: "nginx"}},
},
},
expectResult: AnalyzeResult{
IsPass: true,
Title: "Ingress class nginx",
Message: "nginx ingress class found",
IconKey: "kubernetes_ingress_class",
IconURI: "https://troubleshoot.sh/images/analyzer-icons/ingress-class.svg?w=12&h=12",
},
},
{
name: "named ingress class not found",
analyzer: &troubleshootv1beta2.IngressClass{
IngressClassName: "nginx",
Outcomes: []*troubleshootv1beta2.Outcome{
{
Pass: &troubleshootv1beta2.SingleOutcome{
Message: "nginx ingress class found",
},
},
{
Fail: &troubleshootv1beta2.SingleOutcome{
Message: "nginx ingress class not found",
},
},
},
},
ingressList: &networkingv1.IngressClassList{
Items: []networkingv1.IngressClass{
{ObjectMeta: metav1.ObjectMeta{Name: "traefik"}},
},
},
expectResult: AnalyzeResult{
IsFail: true,
Title: "Ingress class nginx",
Message: "nginx ingress class not found",
IconKey: "kubernetes_ingress_class",
IconURI: "https://troubleshoot.sh/images/analyzer-icons/ingress-class.svg?w=12&h=12",
},
},
{
name: "default ingress class found",
analyzer: &troubleshootv1beta2.IngressClass{
Outcomes: []*troubleshootv1beta2.Outcome{
{
Pass: &troubleshootv1beta2.SingleOutcome{
Message: "default ingress class exists",
},
},
{
Fail: &troubleshootv1beta2.SingleOutcome{
Message: "no default ingress class",
},
},
},
},
ingressList: &networkingv1.IngressClassList{
Items: []networkingv1.IngressClass{
{
ObjectMeta: metav1.ObjectMeta{
Name: "nginx",
Annotations: map[string]string{
"ingressclass.kubernetes.io/is-default-class": "true",
},
},
},
},
},
expectResult: AnalyzeResult{
IsPass: true,
Title: "Default Ingress Class",
Message: "default ingress class exists",
IconKey: "kubernetes_ingress_class",
IconURI: "https://troubleshoot.sh/images/analyzer-icons/ingress-class.svg?w=12&h=12",
},
},
{
name: "default ingress class not found",
analyzer: &troubleshootv1beta2.IngressClass{
Outcomes: []*troubleshootv1beta2.Outcome{
{
Pass: &troubleshootv1beta2.SingleOutcome{
Message: "default ingress class exists",
},
},
{
Fail: &troubleshootv1beta2.SingleOutcome{
Message: "no default ingress class",
},
},
},
},
ingressList: &networkingv1.IngressClassList{
Items: []networkingv1.IngressClass{
{ObjectMeta: metav1.ObjectMeta{Name: "nginx"}},
},
},
expectResult: AnalyzeResult{
IsFail: true,
Title: "Default Ingress Class",
Message: "no default ingress class",
IconKey: "kubernetes_ingress_class",
IconURI: "https://troubleshoot.sh/images/analyzer-icons/ingress-class.svg?w=12&h=12",
},
},
{
name: "default ingress class not found with default message",
analyzer: &troubleshootv1beta2.IngressClass{
Outcomes: []*troubleshootv1beta2.Outcome{},
},
ingressList: &networkingv1.IngressClassList{},
expectResult: AnalyzeResult{
IsFail: true,
Title: "Default Ingress Class",
Message: "No Default Ingress Class found",
IconKey: "kubernetes_ingress_class",
IconURI: "https://troubleshoot.sh/images/analyzer-icons/ingress-class.svg?w=12&h=12",
},
},
{
name: "default ingress class found with default message",
analyzer: &troubleshootv1beta2.IngressClass{
Outcomes: []*troubleshootv1beta2.Outcome{},
},
ingressList: &networkingv1.IngressClassList{
Items: []networkingv1.IngressClass{
{
ObjectMeta: metav1.ObjectMeta{
Name: "nginx",
Annotations: map[string]string{
"ingressclass.kubernetes.io/is-default-class": "true",
},
},
},
},
},
expectResult: AnalyzeResult{
IsPass: true,
Title: "Default Ingress Class",
Message: "Default Ingress Class found",
IconKey: "kubernetes_ingress_class",
IconURI: "https://troubleshoot.sh/images/analyzer-icons/ingress-class.svg?w=12&h=12",
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
b, err := json.Marshal(tt.ingressList)
require.NoError(t, err)
getFile := func(_ string) ([]byte, error) {
return b, nil
}
a := AnalyzeIngressClass{analyzer: tt.analyzer}
result, err := a.analyzeIngressClass(tt.analyzer, getFile)
require.NoError(t, err)
assert.Equal(t, tt.expectResult, *result)
})
}
}
+20 -18
View File
@@ -17,24 +17,26 @@ import (
)
var Filemap = map[string]string{
"deployment": constants.CLUSTER_RESOURCES_DEPLOYMENTS,
"daemonset": constants.CLUSTER_RESOURCES_DAEMONSETS,
"statefulset": constants.CLUSTER_RESOURCES_STATEFULSETS,
"networkpolicy": constants.CLUSTER_RESOURCES_NETWORK_POLICY,
"pod": constants.CLUSTER_RESOURCES_PODS,
"ingress": constants.CLUSTER_RESOURCES_INGRESS,
"service": constants.CLUSTER_RESOURCES_SERVICES,
"resourcequota": constants.CLUSTER_RESOURCES_RESOURCE_QUOTA,
"job": constants.CLUSTER_RESOURCES_JOBS,
"persistentvolumeclaim": constants.CLUSTER_RESOURCES_PVCS,
"pvc": constants.CLUSTER_RESOURCES_PVCS,
"replicaset": constants.CLUSTER_RESOURCES_REPLICASETS,
"configmap": constants.CLUSTER_RESOURCES_CONFIGMAPS,
"namespace": fmt.Sprintf("%s.json", constants.CLUSTER_RESOURCES_NAMESPACES),
"persistentvolume": fmt.Sprintf("%s.json", constants.CLUSTER_RESOURCES_PVS),
"pv": fmt.Sprintf("%s.json", constants.CLUSTER_RESOURCES_PVS),
"node": fmt.Sprintf("%s.json", constants.CLUSTER_RESOURCES_NODES),
"storageclass": fmt.Sprintf("%s.json", constants.CLUSTER_RESOURCES_STORAGE_CLASS),
"deployment": constants.CLUSTER_RESOURCES_DEPLOYMENTS,
"daemonset": constants.CLUSTER_RESOURCES_DAEMONSETS,
"statefulset": constants.CLUSTER_RESOURCES_STATEFULSETS,
"networkpolicy": constants.CLUSTER_RESOURCES_NETWORK_POLICY,
"pod": constants.CLUSTER_RESOURCES_PODS,
"ingress": constants.CLUSTER_RESOURCES_INGRESS,
"service": constants.CLUSTER_RESOURCES_SERVICES,
"resourcequota": constants.CLUSTER_RESOURCES_RESOURCE_QUOTA,
"job": constants.CLUSTER_RESOURCES_JOBS,
"persistentvolumeclaim": constants.CLUSTER_RESOURCES_PVCS,
"pvc": constants.CLUSTER_RESOURCES_PVCS,
"replicaset": constants.CLUSTER_RESOURCES_REPLICASETS,
"configmap": constants.CLUSTER_RESOURCES_CONFIGMAPS,
"validatingwebhookconfiguration": fmt.Sprintf("%s.json", constants.CLUSTER_RESOURCES_VALIDATING_WEBHOOK_CONFIGURATIONS),
"mutatingwebhookconfiguration": fmt.Sprintf("%s.json", constants.CLUSTER_RESOURCES_MUTATING_WEBHOOK_CONFIGURATIONS),
"namespace": fmt.Sprintf("%s.json", constants.CLUSTER_RESOURCES_NAMESPACES),
"persistentvolume": fmt.Sprintf("%s.json", constants.CLUSTER_RESOURCES_PVS),
"pv": fmt.Sprintf("%s.json", constants.CLUSTER_RESOURCES_PVS),
"node": fmt.Sprintf("%s.json", constants.CLUSTER_RESOURCES_NODES),
"storageclass": fmt.Sprintf("%s.json", constants.CLUSTER_RESOURCES_STORAGE_CLASS),
}
type AnalyzeClusterResource struct {
+34 -3
View File
@@ -12,11 +12,12 @@ import (
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/kubernetes/pkg/util/taints"
"github.com/replicatedhq/troubleshoot/internal/util"
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
"github.com/replicatedhq/troubleshoot/pkg/constants"
"github.com/replicatedhq/troubleshoot/pkg/k8sutil"
"github.com/replicatedhq/troubleshoot/pkg/types"
)
type AnalyzeNodeResources struct {
@@ -45,6 +46,9 @@ func (a *AnalyzeNodeResources) Analyze(getFile getCollectedFileContents, findFil
if err != nil {
return nil, err
}
if result == nil {
return nil, nil
}
result.Strict = a.analyzer.Strict.BoolOrDefaultFalse()
return []*AnalyzeResult{result}, nil
}
@@ -53,7 +57,19 @@ func (a *AnalyzeNodeResources) analyzeNodeResources(analyzer *troubleshootv1beta
collected, err := getCollectedFileContents(fmt.Sprintf("%s/%s.json", constants.CLUSTER_RESOURCES_DIR, constants.CLUSTER_RESOURCES_NODES))
if err != nil {
return nil, errors.Wrap(err, "failed to get contents of nodes.json")
if _, ok := err.(*types.NotFoundError); !ok {
return nil, errors.Wrap(err, "failed to get contents of nodes.json")
}
if analyzer.IgnoreIfNoFiles {
return nil, nil
}
return &AnalyzeResult{
Title: a.Title(),
IconKey: "kubernetes_node_resources",
IconURI: "https://troubleshoot.sh/images/analyzer-icons/node-resources.svg?w=16&h=18",
IsWarn: true,
Message: "No node resources were collected, unable to analyze node resources",
}, nil
}
var nodes corev1.NodeList
@@ -203,6 +219,8 @@ func compareNodeResourceConditionalToActual(conditional string, matchingNodes []
switch function {
case "count":
actualValue = len(matchingNodes)
case "countDistinct":
actualValue = countDistinctLabelValues(matchingNodes, property)
case "min":
actualValue = findMin(matchingNodes, property, resourceName)
case "max":
@@ -352,6 +370,19 @@ func getQuantity(node corev1.Node, property string, resourceName string) *resour
return nil
}
// countDistinctLabelValues returns the number of distinct values of labelKey
// across the given nodes. Nodes missing the label are ignored, so an absent
// label yields 0.
func countDistinctLabelValues(nodes []corev1.Node, labelKey string) int {
seen := map[string]struct{}{}
for _, node := range nodes {
if v, ok := node.Labels[labelKey]; ok {
seen[v] = struct{}{}
}
}
return len(seen)
}
func findSum(nodes []corev1.Node, property string, resourceName string) *resource.Quantity {
sum := resource.Quantity{}
@@ -453,7 +484,7 @@ func nodeMatchesFilters(node corev1.Node, filters *troubleshootv1beta2.NodeResou
}
if filters.Taint != nil {
return taints.TaintExists(node.Spec.Taints, filters.Taint), nil
return k8sutil.TaintExists(node.Spec.Taints, filters.Taint), nil
}
if filters.CPUArchitecture != "" {
+165
View File
@@ -1,6 +1,7 @@
package analyzer
import (
"fmt"
"testing"
"github.com/stretchr/testify/assert"
@@ -10,6 +11,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
"github.com/replicatedhq/troubleshoot/pkg/types"
)
func Test_compareNodeResourceConditionalToActual(t *testing.T) {
@@ -1664,6 +1666,116 @@ func Test_analyzeNodeResources(t *testing.T) {
IconURI: "https://troubleshoot.sh/images/analyzer-icons/node-resources.svg?w=16&h=18",
},
},
{
name: "countDistinct spans at least 3 instance types", // countDistinct pass path across all nodes
analyzer: &troubleshootv1beta2.NodeResources{
AnalyzeMeta: troubleshootv1beta2.AnalyzeMeta{
CheckName: "instance-type spread",
},
Outcomes: []*troubleshootv1beta2.Outcome{
{
Warn: &troubleshootv1beta2.SingleOutcome{
When: "countDistinct(node.kubernetes.io/instance-type) < 3",
Message: "Fewer than 3 distinct instance types.",
URI: "",
},
},
{
Pass: &troubleshootv1beta2.SingleOutcome{
Message: "At least 3 distinct instance types.",
URI: "",
},
},
},
},
want: &AnalyzeResult{
IsPass: true,
IsFail: false,
IsWarn: false,
Title: "instance-type spread",
Message: "At least 3 distinct instance types.",
URI: "",
IconKey: "kubernetes_node_resources",
IconURI: "https://troubleshoot.sh/images/analyzer-icons/node-resources.svg?w=16&h=18",
},
},
{
name: "countDistinct only counts filtered nodes", // filtering to one pool leaves a single distinct value
analyzer: &troubleshootv1beta2.NodeResources{
AnalyzeMeta: troubleshootv1beta2.AnalyzeMeta{
CheckName: "filtered instance-type spread",
},
Outcomes: []*troubleshootv1beta2.Outcome{
{
Warn: &troubleshootv1beta2.SingleOutcome{
When: "countDistinct(node.kubernetes.io/instance-type) < 3",
Message: "Fewer than 3 distinct instance types.",
URI: "",
},
},
{
Pass: &troubleshootv1beta2.SingleOutcome{
Message: "At least 3 distinct instance types.",
URI: "",
},
},
},
Filters: &troubleshootv1beta2.NodeResourceFilters{
Selector: &troubleshootv1beta2.NodeResourceSelectors{
MatchExpressions: []metav1.LabelSelectorRequirement{
{
Key: "node.kubernetes.io/instance-type",
Operator: metav1.LabelSelectorOpIn,
Values: []string{"s-2vcpu-4gb"},
},
},
},
},
},
want: &AnalyzeResult{
IsPass: false,
IsFail: false,
IsWarn: true,
Title: "filtered instance-type spread",
Message: "Fewer than 3 distinct instance types.",
URI: "",
IconKey: "kubernetes_node_resources",
IconURI: "https://troubleshoot.sh/images/analyzer-icons/node-resources.svg?w=16&h=18",
},
},
{
name: "countDistinct is 0 when the label is absent", // AIR-238 zone syntax; fixture nodes carry no zone label
analyzer: &troubleshootv1beta2.NodeResources{
AnalyzeMeta: troubleshootv1beta2.AnalyzeMeta{
CheckName: "zone spread",
},
Outcomes: []*troubleshootv1beta2.Outcome{
{
Warn: &troubleshootv1beta2.SingleOutcome{
When: "countDistinct(topology.kubernetes.io/zone) < 3",
Message: "Nodes span fewer than 3 availability zones.",
URI: "",
},
},
{
Pass: &troubleshootv1beta2.SingleOutcome{
Message: "Nodes span at least 3 availability zones.",
URI: "",
},
},
},
},
want: &AnalyzeResult{
IsPass: false,
IsFail: false,
IsWarn: true,
Title: "zone spread",
Message: "Nodes span fewer than 3 availability zones.",
URI: "",
IconKey: "kubernetes_node_resources",
IconURI: "https://troubleshoot.sh/images/analyzer-icons/node-resources.svg?w=16&h=18",
},
},
}
getExampleNodeContents := func(nodeName string) ([]byte, error) {
@@ -1684,3 +1796,56 @@ func Test_analyzeNodeResources(t *testing.T) {
})
}
}
func Test_analyzeNodeResources_NoFiles(t *testing.T) {
missingFile := func(name string) ([]byte, error) {
return nil, &types.NotFoundError{Name: name}
}
t.Run("emits warning when nodes.json is not collected", func(t *testing.T) {
req := require.New(t)
analyzer := &troubleshootv1beta2.NodeResources{
Outcomes: []*troubleshootv1beta2.Outcome{
{Pass: &troubleshootv1beta2.SingleOutcome{Message: "ok"}},
},
}
a := AnalyzeNodeResources{analyzer: analyzer}
got, err := a.Analyze(missingFile, nil)
req.NoError(err)
req.Len(got, 1)
req.True(got[0].IsWarn)
req.Equal("Node Resources", got[0].Title)
})
t.Run("ignoreIfNoFiles suppresses the warning", func(t *testing.T) {
req := require.New(t)
analyzer := &troubleshootv1beta2.NodeResources{
IgnoreIfNoFiles: true,
Outcomes: []*troubleshootv1beta2.Outcome{
{Pass: &troubleshootv1beta2.SingleOutcome{Message: "ok"}},
},
}
a := AnalyzeNodeResources{analyzer: analyzer}
got, err := a.Analyze(missingFile, nil)
req.NoError(err)
req.Empty(got)
})
t.Run("non-NotFound errors are propagated", func(t *testing.T) {
req := require.New(t)
analyzer := &troubleshootv1beta2.NodeResources{
IgnoreIfNoFiles: true,
Outcomes: []*troubleshootv1beta2.Outcome{
{Pass: &troubleshootv1beta2.SingleOutcome{Message: "ok"}},
},
}
ioErr := func(string) ([]byte, error) {
return nil, fmt.Errorf("permission denied")
}
a := AnalyzeNodeResources{analyzer: analyzer}
got, err := a.Analyze(ioErr, nil)
req.Error(err)
req.Nil(got)
req.Contains(err.Error(), "permission denied")
})
}
+8 -1
View File
@@ -146,7 +146,7 @@ func (h *OllamaHelper) downloadAndInstallWindows() error {
return errors.Wrap(err, "failed to create temporary file")
}
defer os.Remove(tmpFile.Name())
defer tmpFile.Close()
defer tmpFile.Close() // Ensures file is closed in error paths
// Download installer
resp, err := http.Get(h.downloadURL)
@@ -165,6 +165,13 @@ func (h *OllamaHelper) downloadAndInstallWindows() error {
return errors.Wrap(err, "failed to write installer")
}
// Close the file before executing it (required on Windows)
// Note: This will be called twice (here and via defer), but that's safe
// The defer ensures cleanup on error paths, this ensures closure before execution
if err := tmpFile.Close(); err != nil {
return errors.Wrap(err, "failed to close installer file")
}
// Run installer
klog.Info("Running Ollama installer...")
cmd := exec.Command(tmpFile.Name())
+139
View File
@@ -0,0 +1,139 @@
package analyzer
import (
"encoding/json"
"fmt"
"path"
"github.com/pkg/errors"
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
"github.com/replicatedhq/troubleshoot/pkg/collect"
)
type AnalyzeS3Status struct {
analyzer *troubleshootv1beta2.DatabaseAnalyze
}
func (a *AnalyzeS3Status) Title() string {
title := a.analyzer.CheckName
if title == "" {
title = a.collectorName()
}
return title
}
func (a *AnalyzeS3Status) IsExcluded() (bool, error) {
return isExcluded(a.analyzer.Exclude)
}
func (a *AnalyzeS3Status) Analyze(getFile getCollectedFileContents, findFiles getChildCollectedFileContents) ([]*AnalyzeResult, error) {
result, err := a.analyzeS3Status(a.analyzer, getFile)
if err != nil {
return nil, err
}
result.Strict = a.analyzer.Strict.BoolOrDefaultFalse()
return []*AnalyzeResult{result}, nil
}
func (a *AnalyzeS3Status) collectorName() string {
collectorName := a.analyzer.CollectorName
if collectorName == "" {
collectorName = "s3Status"
}
return collectorName
}
func (a *AnalyzeS3Status) analyzeS3Status(analyzer *troubleshootv1beta2.DatabaseAnalyze, getCollectedFileContents func(string) ([]byte, error)) (*AnalyzeResult, error) {
fullPath := path.Join("s3Status", fmt.Sprintf("%s.json", a.collectorName()))
collected, err := getCollectedFileContents(fullPath)
if err != nil {
return nil, errors.Wrapf(err, "failed to read collected file name: %s", fullPath)
}
databaseConnection := collect.DatabaseConnection{}
if err := json.Unmarshal(collected, &databaseConnection); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal s3 status result")
}
result := &AnalyzeResult{
Title: a.Title(),
IconKey: "kubernetes_s3_analyze",
IconURI: "https://troubleshoot.sh/images/analyzer-icons/s3-analyze.svg",
}
for _, outcome := range analyzer.Outcomes {
if outcome.Fail != nil {
if outcome.Fail.When == "" {
result.IsFail = true
result.Message = outcome.Fail.Message
result.URI = outcome.Fail.URI
return result, nil
}
isMatch, err := compareDatabaseConditionalToActual(outcome.Fail.When, &databaseConnection)
if err != nil {
return result, errors.Wrap(err, "failed to compare s3 status conditional")
}
if isMatch {
result.IsFail = true
if databaseConnection.Error != "" {
result.Message = outcome.Fail.Message + " " + databaseConnection.Error
} else {
result.Message = outcome.Fail.Message
}
result.URI = outcome.Fail.URI
return result, nil
}
} else if outcome.Warn != nil {
if outcome.Warn.When == "" {
result.IsWarn = true
result.Message = outcome.Warn.Message
result.URI = outcome.Warn.URI
return result, nil
}
isMatch, err := compareDatabaseConditionalToActual(outcome.Warn.When, &databaseConnection)
if err != nil {
return result, errors.Wrap(err, "failed to compare s3 status conditional")
}
if isMatch {
result.IsWarn = true
result.Message = outcome.Warn.Message
result.URI = outcome.Warn.URI
return result, nil
}
} else if outcome.Pass != nil {
if outcome.Pass.When == "" {
result.IsPass = true
result.Message = outcome.Pass.Message
result.URI = outcome.Pass.URI
return result, nil
}
isMatch, err := compareDatabaseConditionalToActual(outcome.Pass.When, &databaseConnection)
if err != nil {
return result, errors.Wrap(err, "failed to compare s3 status conditional")
}
if isMatch {
result.IsPass = true
result.Message = outcome.Pass.Message
result.URI = outcome.Pass.URI
return result, nil
}
}
}
return result, nil
}
+175
View File
@@ -0,0 +1,175 @@
package analyzer
import (
"encoding/json"
"testing"
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
"github.com/replicatedhq/troubleshoot/pkg/collect"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestAnalyzeS3Status(t *testing.T) {
tests := []struct {
name string
analyzer *troubleshootv1beta2.DatabaseAnalyze
collected *collect.DatabaseConnection
wantPass bool
wantFail bool
wantWarn bool
wantMessage string
}{
{
name: "connected, pass",
analyzer: &troubleshootv1beta2.DatabaseAnalyze{
Outcomes: []*troubleshootv1beta2.Outcome{
{
Fail: &troubleshootv1beta2.SingleOutcome{
When: "connected == false",
Message: "Cannot access the S3 bucket.",
},
},
{
Pass: &troubleshootv1beta2.SingleOutcome{
When: "connected == true",
Message: "S3 bucket is accessible.",
},
},
},
},
collected: &collect.DatabaseConnection{
IsConnected: true,
},
wantPass: true,
wantMessage: "S3 bucket is accessible.",
},
{
name: "not connected, fail with error appended",
analyzer: &troubleshootv1beta2.DatabaseAnalyze{
Outcomes: []*troubleshootv1beta2.Outcome{
{
Fail: &troubleshootv1beta2.SingleOutcome{
When: "connected == false",
Message: "Cannot access the S3 bucket.",
},
},
{
Pass: &troubleshootv1beta2.SingleOutcome{
When: "connected == true",
Message: "S3 bucket is accessible.",
},
},
},
},
collected: &collect.DatabaseConnection{
IsConnected: false,
Error: "operation error S3: HeadBucket, StatusCode: 403",
},
wantFail: true,
wantMessage: "Cannot access the S3 bucket. operation error S3: HeadBucket, StatusCode: 403",
},
{
name: "not connected, fail without error",
analyzer: &troubleshootv1beta2.DatabaseAnalyze{
Outcomes: []*troubleshootv1beta2.Outcome{
{
Fail: &troubleshootv1beta2.SingleOutcome{
When: "connected == false",
Message: "Cannot access the S3 bucket.",
},
},
},
},
collected: &collect.DatabaseConnection{
IsConnected: false,
},
wantFail: true,
wantMessage: "Cannot access the S3 bucket.",
},
{
name: "warn outcome",
analyzer: &troubleshootv1beta2.DatabaseAnalyze{
Outcomes: []*troubleshootv1beta2.Outcome{
{
Warn: &troubleshootv1beta2.SingleOutcome{
When: "connected == false",
Message: "S3 bucket may be inaccessible.",
},
},
},
},
collected: &collect.DatabaseConnection{
IsConnected: false,
},
wantWarn: true,
wantMessage: "S3 bucket may be inaccessible.",
},
{
name: "unconditional fail",
analyzer: &troubleshootv1beta2.DatabaseAnalyze{
Outcomes: []*troubleshootv1beta2.Outcome{
{
Fail: &troubleshootv1beta2.SingleOutcome{
Message: "Always fails.",
},
},
},
},
collected: &collect.DatabaseConnection{
IsConnected: true,
},
wantFail: true,
wantMessage: "Always fails.",
},
{
name: "custom collector name",
analyzer: &troubleshootv1beta2.DatabaseAnalyze{
AnalyzeMeta: troubleshootv1beta2.AnalyzeMeta{
CheckName: "My S3 Check",
},
CollectorName: "my-bucket",
Outcomes: []*troubleshootv1beta2.Outcome{
{
Pass: &troubleshootv1beta2.SingleOutcome{
When: "connected == true",
Message: "Bucket OK.",
},
},
},
},
collected: &collect.DatabaseConnection{
IsConnected: true,
},
wantPass: true,
wantMessage: "Bucket OK.",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
collectedData, err := json.Marshal(tt.collected)
require.NoError(t, err)
a := &AnalyzeS3Status{analyzer: tt.analyzer}
getFile := func(path string) ([]byte, error) {
return collectedData, nil
}
results, err := a.Analyze(getFile, nil)
require.NoError(t, err)
require.Len(t, results, 1)
result := results[0]
assert.Equal(t, tt.wantPass, result.IsPass)
assert.Equal(t, tt.wantFail, result.IsFail)
assert.Equal(t, tt.wantWarn, result.IsWarn)
assert.Equal(t, tt.wantMessage, result.Message)
if tt.analyzer.CheckName != "" {
assert.Equal(t, tt.analyzer.CheckName, result.Title)
}
})
}
}
+54 -25
View File
@@ -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)
}
}
+234
View File
@@ -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) {
@@ -261,7 +261,7 @@ func (c *Collect) AccessReviewSpecs(overrideNS string) []authorizationv1.SelfSub
result = append(result, authorizationv1.SelfSubjectAccessReviewSpec{
ResourceAttributes: &authorizationv1.ResourceAttributes{
Namespace: pickNamespaceOrDefault(c.Exec.Namespace, overrideNS),
Verb: "get",
Verb: "create",
Group: "",
Version: "",
Resource: "pods",
@@ -286,7 +286,7 @@ func (c *Collect) AccessReviewSpecs(overrideNS string) []authorizationv1.SelfSub
result = append(result, authorizationv1.SelfSubjectAccessReviewSpec{
ResourceAttributes: &authorizationv1.ResourceAttributes{
Namespace: pickNamespaceOrDefault(c.Copy.Namespace, overrideNS),
Verb: "get",
Verb: "create",
Group: "",
Version: "",
Resource: "pods",
@@ -18,6 +18,12 @@ type StorageClass struct {
StorageClassName string `json:"storageClassName,omitempty" yaml:"storageClassName,omitempty"`
}
type IngressClass struct {
AnalyzeMeta `json:",inline" yaml:",inline"`
Outcomes []*Outcome `json:"outcomes" yaml:"outcomes"`
IngressClassName string `json:"ingressClassName,omitempty" yaml:"ingressClassName,omitempty"`
}
type CustomResourceDefinition struct {
AnalyzeMeta `json:",inline" yaml:",inline"`
Outcomes []*Outcome `json:"outcomes" yaml:"outcomes"`
@@ -124,9 +130,10 @@ type Distribution struct {
}
type NodeResources struct {
AnalyzeMeta `json:",inline" yaml:",inline"`
Outcomes []*Outcome `json:"outcomes" yaml:"outcomes"`
Filters *NodeResourceFilters `json:"filters,omitempty" yaml:"filters,omitempty"`
AnalyzeMeta `json:",inline" yaml:",inline"`
Outcomes []*Outcome `json:"outcomes" yaml:"outcomes"`
Filters *NodeResourceFilters `json:"filters,omitempty" yaml:"filters,omitempty"`
IgnoreIfNoFiles bool `json:"ignoreIfNoFiles,omitempty" yaml:"ignoreIfNoFiles,omitempty"`
}
type NodeResourceFilters struct {
@@ -276,6 +283,7 @@ type PVCRef struct {
type Analyze struct {
ClusterVersion *ClusterVersion `json:"clusterVersion,omitempty" yaml:"clusterVersion,omitempty"`
StorageClass *StorageClass `json:"storageClass,omitempty" yaml:"storageClass,omitempty"`
IngressClass *IngressClass `json:"ingressClass,omitempty" yaml:"ingressClass,omitempty"`
CustomResourceDefinition *CustomResourceDefinition `json:"customResourceDefinition,omitempty" yaml:"customResourceDefinition,omitempty"`
Ingress *Ingress `json:"ingress,omitempty" yaml:"ingress,omitempty"`
Secret *AnalyzeSecret `json:"secret,omitempty" yaml:"secret,omitempty"`
@@ -297,6 +305,7 @@ type Analyze struct {
Mssql *DatabaseAnalyze `json:"mssql,omitempty" yaml:"mssql,omitempty"`
Mysql *DatabaseAnalyze `json:"mysql,omitempty" yaml:"mysql,omitempty"`
Redis *DatabaseAnalyze `json:"redis,omitempty" yaml:"redis,omitempty"`
ClickHouse *DatabaseAnalyze `json:"clickhouse,omitempty" yaml:"clickhouse,omitempty"`
CephStatus *CephStatusAnalyze `json:"cephStatus,omitempty" yaml:"cephStatus,omitempty"`
Velero *VeleroAnalyze `json:"velero,omitempty" yaml:"velero,omitempty"`
Longhorn *LonghornAnalyze `json:"longhorn,omitempty" yaml:"longhorn,omitempty"`
@@ -309,4 +318,5 @@ type Analyze struct {
Event *EventAnalyze `json:"event,omitempty" yaml:"event,omitempty"`
NodeMetrics *NodeMetricsAnalyze `json:"nodeMetrics,omitempty" yaml:"nodeMetrics,omitempty"`
HTTP *HTTPAnalyze `json:"http,omitempty" yaml:"http,omitempty"`
S3Status *DatabaseAnalyze `json:"s3Status,omitempty" yaml:"s3Status,omitempty"`
}
@@ -318,37 +318,56 @@ type Etcd struct {
Image string `json:"image" yaml:"image"`
}
type SupportBundleMetadata struct {
CollectorMeta `json:",inline" yaml:",inline"`
Namespace string `json:"namespace" yaml:"namespace"`
}
type S3Status struct {
CollectorMeta `json:",inline" yaml:",inline"`
BucketName string `json:"bucketName" yaml:"bucketName"`
Region string `json:"region,omitempty" yaml:"region,omitempty"`
Endpoint string `json:"endpoint,omitempty" yaml:"endpoint,omitempty"`
AccessKeyID string `json:"accessKeyID,omitempty" yaml:"accessKeyID,omitempty"`
SecretAccessKey string `json:"secretAccessKey,omitempty" yaml:"secretAccessKey,omitempty"`
UsePathStyle bool `json:"usePathStyle,omitempty" yaml:"usePathStyle,omitempty"`
Insecure bool `json:"insecure,omitempty" yaml:"insecure,omitempty"`
}
type Collect struct {
ClusterInfo *ClusterInfo `json:"clusterInfo,omitempty" yaml:"clusterInfo,omitempty"`
ClusterResources *ClusterResources `json:"clusterResources,omitempty" yaml:"clusterResources,omitempty"`
Secret *Secret `json:"secret,omitempty" yaml:"secret,omitempty"`
CustomMetrics *CustomMetrics `json:"customMetrics,omitempty" yaml:"customMetrics,omitempty"`
ConfigMap *ConfigMap `json:"configMap,omitempty" yaml:"configMap,omitempty"`
Logs *Logs `json:"logs,omitempty" yaml:"logs,omitempty"`
Run *Run `json:"run,omitempty" yaml:"run,omitempty"`
RunPod *RunPod `json:"runPod,omitempty" yaml:"runPod,omitempty"`
RunDaemonSet *RunDaemonSet `json:"runDaemonSet,omitempty" yaml:"runDaemonSet,omitempty"`
Exec *Exec `json:"exec,omitempty" yaml:"exec,omitempty"`
Data *Data `json:"data,omitempty" yaml:"data,omitempty"`
Copy *Copy `json:"copy,omitempty" yaml:"copy,omitempty"`
CopyFromHost *CopyFromHost `json:"copyFromHost,omitempty" yaml:"copyFromHost,omitempty"`
HTTP *HTTP `json:"http,omitempty" yaml:"http,omitempty"`
Postgres *Database `json:"postgres,omitempty" yaml:"postgres,omitempty"`
Mssql *Database `json:"mssql,omitempty" yaml:"mssql,omitempty"`
Mysql *Database `json:"mysql,omitempty" yaml:"mysql,omitempty"`
Redis *Database `json:"redis,omitempty" yaml:"redis,omitempty"`
Collectd *Collectd `json:"collectd,omitempty" yaml:"collectd,omitempty"`
Ceph *Ceph `json:"ceph,omitempty" yaml:"ceph,omitempty"`
Longhorn *Longhorn `json:"longhorn,omitempty" yaml:"longhorn,omitempty"`
RegistryImages *RegistryImages `json:"registryImages,omitempty" yaml:"registryImages,omitempty"`
Sysctl *Sysctl `json:"sysctl,omitempty" yaml:"sysctl,omitempty"`
Certificates *Certificates `json:"certificates,omitempty" yaml:"certificates,omitempty"`
Helm *Helm `json:"helm,omitempty" yaml:"helm,omitempty"`
Goldpinger *Goldpinger `json:"goldpinger,omitempty" yaml:"goldpinger,omitempty"`
Sonobuoy *Sonobuoy `json:"sonobuoy,omitempty" yaml:"sonobuoy,omitempty"`
NodeMetrics *NodeMetrics `json:"nodeMetrics,omitempty" yaml:"nodeMetrics,omitempty"`
DNS *DNS `json:"dns,omitempty" yaml:"dns,omitempty"`
Etcd *Etcd `json:"etcd,omitempty" yaml:"etcd,omitempty"`
ClusterInfo *ClusterInfo `json:"clusterInfo,omitempty" yaml:"clusterInfo,omitempty"`
ClusterResources *ClusterResources `json:"clusterResources,omitempty" yaml:"clusterResources,omitempty"`
Secret *Secret `json:"secret,omitempty" yaml:"secret,omitempty"`
CustomMetrics *CustomMetrics `json:"customMetrics,omitempty" yaml:"customMetrics,omitempty"`
ConfigMap *ConfigMap `json:"configMap,omitempty" yaml:"configMap,omitempty"`
Logs *Logs `json:"logs,omitempty" yaml:"logs,omitempty"`
Run *Run `json:"run,omitempty" yaml:"run,omitempty"`
RunPod *RunPod `json:"runPod,omitempty" yaml:"runPod,omitempty"`
RunDaemonSet *RunDaemonSet `json:"runDaemonSet,omitempty" yaml:"runDaemonSet,omitempty"`
Exec *Exec `json:"exec,omitempty" yaml:"exec,omitempty"`
Data *Data `json:"data,omitempty" yaml:"data,omitempty"`
Copy *Copy `json:"copy,omitempty" yaml:"copy,omitempty"`
CopyFromHost *CopyFromHost `json:"copyFromHost,omitempty" yaml:"copyFromHost,omitempty"`
HTTP *HTTP `json:"http,omitempty" yaml:"http,omitempty"`
Postgres *Database `json:"postgres,omitempty" yaml:"postgres,omitempty"`
Mssql *Database `json:"mssql,omitempty" yaml:"mssql,omitempty"`
Mysql *Database `json:"mysql,omitempty" yaml:"mysql,omitempty"`
Redis *Database `json:"redis,omitempty" yaml:"redis,omitempty"`
ClickHouse *Database `json:"clickhouse,omitempty" yaml:"clickhouse,omitempty"`
Collectd *Collectd `json:"collectd,omitempty" yaml:"collectd,omitempty"`
Ceph *Ceph `json:"ceph,omitempty" yaml:"ceph,omitempty"`
Longhorn *Longhorn `json:"longhorn,omitempty" yaml:"longhorn,omitempty"`
RegistryImages *RegistryImages `json:"registryImages,omitempty" yaml:"registryImages,omitempty"`
Sysctl *Sysctl `json:"sysctl,omitempty" yaml:"sysctl,omitempty"`
Certificates *Certificates `json:"certificates,omitempty" yaml:"certificates,omitempty"`
Helm *Helm `json:"helm,omitempty" yaml:"helm,omitempty"`
Goldpinger *Goldpinger `json:"goldpinger,omitempty" yaml:"goldpinger,omitempty"`
Sonobuoy *Sonobuoy `json:"sonobuoy,omitempty" yaml:"sonobuoy,omitempty"`
NodeMetrics *NodeMetrics `json:"nodeMetrics,omitempty" yaml:"nodeMetrics,omitempty"`
DNS *DNS `json:"dns,omitempty" yaml:"dns,omitempty"`
Etcd *Etcd `json:"etcd,omitempty" yaml:"etcd,omitempty"`
SupportBundleMetadata *SupportBundleMetadata `json:"supportBundleMetadata,omitempty" yaml:"supportBundleMetadata,omitempty"`
S3Status *S3Status `json:"s3Status,omitempty" yaml:"s3Status,omitempty"`
}
func (c *Collect) AccessReviewSpecs(overrideNS string) []authorizationv1.SelfSubjectAccessReviewSpec {
@@ -511,7 +530,7 @@ func (c *Collect) AccessReviewSpecs(overrideNS string) []authorizationv1.SelfSub
result = append(result, authorizationv1.SelfSubjectAccessReviewSpec{
ResourceAttributes: &authorizationv1.ResourceAttributes{
Namespace: pickNamespaceOrDefault(c.Exec.Namespace, overrideNS),
Verb: "get",
Verb: "create",
Group: "",
Version: "",
Resource: "pods",
@@ -536,7 +555,7 @@ func (c *Collect) AccessReviewSpecs(overrideNS string) []authorizationv1.SelfSub
result = append(result, authorizationv1.SelfSubjectAccessReviewSpec{
ResourceAttributes: &authorizationv1.ResourceAttributes{
Namespace: pickNamespaceOrDefault(c.Copy.Namespace, overrideNS),
Verb: "get",
Verb: "create",
Group: "",
Version: "",
Resource: "pods",
@@ -568,6 +587,21 @@ func (c *Collect) AccessReviewSpecs(overrideNS string) []authorizationv1.SelfSub
})
} else if c.Sysctl != nil {
// TODO
} else if c.SupportBundleMetadata != nil {
result = append(result, authorizationv1.SelfSubjectAccessReviewSpec{
ResourceAttributes: &authorizationv1.ResourceAttributes{
Namespace: pickNamespaceOrDefault(c.SupportBundleMetadata.Namespace, overrideNS),
Verb: "get",
Group: "",
Version: "",
Resource: "secrets",
Subresource: "",
Name: "replicated-support-metadata",
},
NonResourceAttributes: nil,
})
} else if c.S3Status != nil {
// NOOP
}
return result
@@ -647,6 +681,10 @@ func (c *Collect) GetName() string {
collector = "redis"
name = c.Redis.CollectorName
}
if c.ClickHouse != nil {
collector = "clickhouse"
name = c.ClickHouse.CollectorName
}
if c.Collectd != nil {
collector = "collectd"
name = c.Collectd.CollectorName
@@ -671,6 +709,14 @@ func (c *Collect) GetName() string {
collector = "certificates"
name = c.Certificates.CollectorName
}
if c.SupportBundleMetadata != nil {
collector = "support-bundle-metadata"
name = c.SupportBundleMetadata.CollectorName
}
if c.S3Status != nil {
collector = "s3Status"
name = c.S3Status.CollectorName
}
if collector == "" {
return "<none>"

Some files were not shown because too many files have changed in this diff Show More