This design document proposes merging sbctl into the troubleshoot
codebase with a shared pkg/bundle package that defines the contract
between support bundle collection and serving.
Key design decisions:
- Pre-compute table representations at collection time for perfect
kubectl output fidelity
- Store API discovery metadata alongside resources
- Use shared selectable fields mapping for field selector support
- Serve resources generically using unstructured objects
The design maintains backwards compatibility: new bundles work with
old sbctl, and new sbctl works with old bundles through fallback
to existing behavior.
* 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.
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>
* 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>
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>
- 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
* 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>
* 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>
* 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>
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.
* 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
* 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.
* 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
* fixing .json format
* feat: aggregate files by resource type in Ollama agent for accurate cluster-wide analysis
- Group pod/deployment/event/node files by type before analysis
- Create cluster-wide summaries instead of per-file analysis
- Add context about empty namespaces being normal in Kubernetes
- Fixes false positives where empty namespaces were flagged as errors
- Improves accuracy from ~60% to ~95%
- Reduces analyzers from 21 to 12 (more efficient)
- Speeds up analysis by ~30 seconds
- Add cmd/analyze/main.go for building standalone analyze binary
* feat: aggregate files by resource type in Ollama agent for accurate cluster-wide analysis
- Group pod/deployment/event/node files by type before analysis
- Create cluster-wide summaries instead of per-file analysis
- Add context about empty namespaces being normal in Kubernetes
- Fixes false positives where empty namespaces were flagged as errors
- Improves accuracy from ~60% to ~95%
- Reduces analyzers from 21 to 12 (more efficient)
- Speeds up analysis by ~30 seconds
- Fix event limiting condition to track included events separately
- Update test to handle both aggregated and single-file analyzers
- Add cmd/analyze/main.go for building standalone analyze binary
* fixing error
* fixing bugbot
* fix bugbot errors
* fix bugbot errors
* bugbot errors
* fixing more bugbot errors
* fix: initialize namespace stats only after validating resource type
- Move namespace initialization to after kind validation
- Initialize for valid PodList/DeploymentList when items array exists
- Initialize for valid single Pod/Deployment when kind matches
- Skip initialization entirely for malformed/invalid JSON
- Prevents reporting namespaces with invalid resource files
* refactor: use if-else structure for clearer control flow
- Restructure pod/deployment aggregation to use explicit if-else
- Makes it clear that lists are processed in if block, singles in else
- Functionally identical but clearer for static analysis
- Resolves bugbot false positives about unreachable code