Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:Factory:Rebuild
kubeshark-cli
kubeshark-cli-52.3.90.obscpio
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File kubeshark-cli-52.3.90.obscpio of Package kubeshark-cli
07070100000000000041ED000000000000000000000002673DBE2800000000000000000000000000000000000000000000001E00000000kubeshark-cli-52.3.90/.github07070100000001000041ED000000000000000000000002673DBE2800000000000000000000000000000000000000000000002D00000000kubeshark-cli-52.3.90/.github/ISSUE_TEMPLATE07070100000002000081A4000000000000000000000001673DBE280000042C000000000000000000000000000000000000003B00000000kubeshark-cli-52.3.90/.github/ISSUE_TEMPLATE/bug_report.md--- name: Bug report about: Create a report to help us improve title: '' labels: '' assignees: '' --- **Describe the bug** A clear and concise description of what the bug is. **Provide more information** Running on EKS, AKS, GKE, Minikube, Rancher, OpenShift? Number of Nodes? CNI? **To Reproduce** Steps to reproduce the behavior: 1. Run `kubeshark <command> ...` 2. Click on '...' 3. Scroll down to '...' 4. See error **Expected behavior** A clear and concise description of what you expected to happen. **Logs** Upload logs: 1. Run the kubeshark command with `--set dump-logs=true` (e.g `kubeshark tap --set dump-logs=true`) 2. Try to reproduce the issue 3. <kbd>CTRL</kbd>+<kbd>C</kbd> on terminal tab which runs `kubeshark` 4. Upload the logs zip file from `~/.kubeshark/kubeshark_logs_**.zip` **Screenshots** If applicable, add screenshots to help explain your problem. **Desktop (please complete the following information):** - OS: [e.g. macOS] - Web Browser: [e.g. Google Chrome] **Additional context** Add any other context about the problem here. 07070100000003000081A4000000000000000000000001673DBE28000006F0000000000000000000000000000000000000004100000000kubeshark-cli-52.3.90/.github/ISSUE_TEMPLATE/feature_request.ymlname: Feature request description: Request a new feature or an improvement to an existing one title: "[Feature Request:]" labels: ["enhancement"] assignees: - alongir body: - type: markdown attributes: value: | Thanks for taking the time to request a new feature! - type: input id: contact attributes: label: Contact Details description: How can we get in touch with you if we need more info? placeholder: ex. email@example.com validations: required: false - type: textarea id: the-problem attributes: label: Is your feature request related to a problem? Please describe. description: Please describe the problem you are trying to solve validations: required: true - type: input id: original-thread attributes: label: Original Thread description: A link to the original discussion thread (e.g. Slack, Discord, Email, Verbal) validations: required: false - type: textarea id: the-solution attributes: label: Describe the solution you'd like to see description: A clear and concise description of what you want to happen. validations: required: false - type: textarea id: the-context attributes: label: Provide additional context description: Add any other context or screenshots about the feature request here. validations: required: false - type: checkboxes id: terms attributes: label: Code of Conduct description: By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/kubeshark/kubeshark/blob/master/docs/CODE_OF_CONDUCT.md) options: - label: I agree to follow this project's Code of Conduct required: true 07070100000004000041ED000000000000000000000002673DBE2800000000000000000000000000000000000000000000002500000000kubeshark-cli-52.3.90/.github/static07070100000005000081A4000000000000000000000001673DBE280000051F000000000000000000000000000000000000003700000000kubeshark-cli-52.3.90/.github/static/kubeshark.rb.tmpl# typed: false # frozen_string_literal: true class Kubeshark < Formula desc "" homepage "https://github.com/kubeshark/kubeshark" version "${CLEAN_VERSION}" on_macos do if Hardware::CPU.arm? url "https://github.com/kubeshark/kubeshark/releases/download/${FULL_VERSION}/kubeshark_darwin_arm64" sha256 "${DARWIN_ARM64_SHA256}" def install bin.install "kubeshark_darwin_arm64" => "kubeshark" end end if Hardware::CPU.intel? url "https://github.com/kubeshark/kubeshark/releases/download/${FULL_VERSION}/kubeshark_darwin_amd64" sha256 "${DARWIN_AMD64_SHA256}" def install bin.install "kubeshark_darwin_amd64" => "kubeshark" end end end on_linux do if Hardware::CPU.intel? url "https://github.com/kubeshark/kubeshark/releases/download/${FULL_VERSION}/kubeshark_linux_amd64" sha256 "${LINUX_AMD64_SHA256}" def install bin.install "kubeshark_linux_amd64" => "kubeshark" end end if Hardware::CPU.arm? && Hardware::CPU.is_64_bit? url "https://github.com/kubeshark/kubeshark/releases/download/${FULL_VERSION}/kubeshark_linux_arm64" sha256 "${LINUX_ARM64_SHA256}" def install bin.install "kubeshark_linux_arm64" => "kubeshark" end end end end 07070100000006000041ED000000000000000000000002673DBE2800000000000000000000000000000000000000000000002800000000kubeshark-cli-52.3.90/.github/workflows07070100000007000081A4000000000000000000000001673DBE280000045C000000000000000000000000000000000000003100000000kubeshark-cli-52.3.90/.github/workflows/helm.ymlon: push: # Sequence of patterns matched against refs/tags tags: - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10 name: Release Helm Charts jobs: release: # depending on default permission settings for your org (contents being read-only or read-write for workloads), you will have to add permissions # see: https://docs.github.com/en/actions/security-guides/automatic-token-authentication#modifying-the-permissions-for-the-github_token permissions: contents: write runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v3 with: fetch-depth: 0 - name: Configure Git run: | git config user.name "$GITHUB_ACTOR" git config user.email "$GITHUB_ACTOR@users.noreply.github.com" - name: Install Helm uses: azure/setup-helm@v3 - name: Run chart-releaser uses: helm/chart-releaser-action@v1.5.0 with: charts_dir: . charts_repo_url: https://kubeshark.github.io/kubeshark env: CR_TOKEN: "${{ secrets.HELM_TOKEN }}" 07070100000008000081A4000000000000000000000001673DBE2800000224000000000000000000000000000000000000003300000000kubeshark-cli-52.3.90/.github/workflows/linter.ymlon: push: branches: - master pull_request: branches: - master name: Linter permissions: contents: read jobs: golint: name: Golint runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v3 with: fetch-depth: 2 - name: Set up Go uses: actions/setup-go@v4 with: go-version-file: 'go.mod' - name: Go lint uses: golangci/golangci-lint-action@v3 with: version: latest args: --timeout=10m 07070100000009000081A4000000000000000000000001673DBE2800000747000000000000000000000000000000000000003400000000kubeshark-cli-52.3.90/.github/workflows/release.ymlon: push: # Sequence of patterns matched against refs/tags tags: - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10 name: Release concurrency: group: kubeshark-publish-${{ github.ref }} cancel-in-progress: true jobs: release: name: Build and publish a new release runs-on: ubuntu-latest outputs: version: ${{ steps.version.outputs.tag }} steps: - name: Check out the repo uses: actions/checkout@v3 - name: Set up Go uses: actions/setup-go@v4 with: go-version-file: 'go.mod' - name: Version id: version shell: bash run: | { echo "tag=${GITHUB_REF#refs/*/}" echo "build_timestamp=$(date +%s)" echo "branch=${GITHUB_REF#refs/heads/}" } >> "$GITHUB_OUTPUT" - name: Build run: make build-all VER='${{ steps.version.outputs.tag }}' BUILD_TIMESTAMP='${{ steps.version.outputs.build_timestamp }}' - name: Log the version into a .txt file shell: bash run: | echo '${{ steps.version.outputs.tag }}' >> bin/version.txt - name: Release uses: ncipollo/release-action@v1 with: token: ${{ secrets.GITHUB_TOKEN }} artifacts: "bin/*" tag: ${{ steps.version.outputs.tag }} prerelease: false bodyFile: 'bin/README.md' brew: name: Publish a new Homebrew formulae needs: [release] runs-on: ubuntu-latest steps: - name: Bump core homebrew formula uses: mislav/bump-homebrew-formula-action@v3 with: # A PR will be sent to github.com/Homebrew/homebrew-core to update this formula: formula-name: kubeshark push-to: kubeshark/homebrew-core env: COMMITTER_TOKEN: ${{ secrets.COMMITTER_TOKEN }} 0707010000000A000081A4000000000000000000000001673DBE280000023B000000000000000000000000000000000000003100000000kubeshark-cli-52.3.90/.github/workflows/test.ymlon: push: branches: - master pull_request: branches: - master name: Test jobs: run-unit-tests: name: Unit Tests runs-on: ubuntu-latest timeout-minutes: 20 steps: - name: Check out code into the Go module directory uses: actions/checkout@v3 with: fetch-depth: 2 - name: Set up Go uses: actions/setup-go@v4 with: go-version-file: 'go.mod' - name: Test run: make test - name: Upload coverage to Codecov uses: codecov/codecov-action@v3 0707010000000B000081A4000000000000000000000001673DBE280000035C000000000000000000000000000000000000002100000000kubeshark-cli-52.3.90/.gitignore# Binaries for programs and plugins *.exe *.exe~ *.dll *.so *.dylib # Test binary, built with `go test -c` *.test # Output of the go coverage tool, specifically when used with LiteIDE *.out # Dependency directories (remove the comment below to include it) # vendor/ .idea/ build # Mac OS .DS_Store .vscode/ # Ignore the scripts that are created for development *dev.* # Environment variables .env # pprof pprof/* # Database Files *.db *.gob # Nohup Files - https://man7.org/linux/man-pages/man1/nohup.1p.html nohup.* # Cypress tests cypress.env.json */cypress/downloads */cypress/fixtures */cypress/plugins */cypress/screenshots */cypress/videos */cypress/support # UI folders to ignore **/node_modules/** **/dist/** *.editorconfig # Ignore *.log files *.log # Object files *.o # Binaries bin # Scripts scripts/ # CWD config YAML kubeshark.yaml0707010000000C000081A4000000000000000000000001673DBE28000000DC000000000000000000000000000000000000002600000000kubeshark-cli-52.3.90/.goreleaser.ymlbrews: - name: kubeshark homepage: https://github.com/kubeshark/kubeshark tap: owner: kubeshark name: homebrew-kubeshark commit_author: name: mertyildiran email: me@mertyildiran.com 0707010000000D000081A4000000000000000000000001673DBE2800000D00000000000000000000000000000000000000002900000000kubeshark-cli-52.3.90/CODE_OF_CONDUCT.md# Contributor Covenant Code of Conduct ## Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards Examples of behavior that contributes to creating a positive environment include: * Using welcoming and inclusive language * Being respectful of differing viewpoints and experiences * Gracefully accepting constructive criticism * Focusing on what is best for the community * Showing empathy towards other community members Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery and unwelcome sexual attention or advances * Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or electronic address, without explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html [homepage]: https://www.contributor-covenant.org For answers to common questions about this code of conduct, see https://www.contributor-covenant.org/faq 0707010000000E000081A4000000000000000000000001673DBE28000005C0000000000000000000000000000000000000002600000000kubeshark-cli-52.3.90/CONTRIBUTING.md![Kubeshark: The API Traffic Analyzer for Kubernetes](https://raw.githubusercontent.com/kubeshark/assets/master/svg/kubeshark-logo.svg) # Contributing to Kubeshark We welcome code contributions from the community. Please read and follow the guidelines below. ## Communication * Before starting work on a major feature, please reach out to us via [GitHub](https://github.com/kubeshark/kubeshark), [Discord](https://discord.gg/WkvRGMUcx7), [Slack](https://join.slack.com/t/kubeshark/shared_invite/zt-1k3sybpq9-uAhFkuPJiJftKniqrGHGhg), [email](mailto:info@kubeshark.co), etc. We will make sure no one else is already working on it. A _major feature_ is defined as any change that is > 100 LOC altered (not including tests), or changes any user-facing behavior * Small patches and bug fixes don't need prior communication. ## Contribution Requirements * Code style - most of the code is written in Go, please follow [these guidelines](https://golang.org/doc/effective_go) * Go-tools compatible (`go get`, `go test`, etc.) * Code coverage for unit tests must not decrease. * Code must be usefully commented. Not only for developers on the project, but also for external users of these packages * When reviewing PRs, you are encouraged to use Golang's [code review comments page](https://github.com/golang/go/wiki/CodeReviewComments) * Project follows [Google JSON Style Guide](https://google.github.io/styleguide/jsoncstyleguide.xml) for the REST APIs that are provided. 0707010000000F000081A4000000000000000000000001673DBE2800002A05000000000000000000000000000000000000001E00000000kubeshark-cli-52.3.90/LICENSE Apache License Version 2.0, January 2004 https://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS Copyright 2022 Kubeshark Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. 07070100000010000081A4000000000000000000000001673DBE2800002129000000000000000000000000000000000000001F00000000kubeshark-cli-52.3.90/MakefileSHELL=/bin/bash .PHONY: help .DEFAULT_GOAL := build .ONESHELL: SUFFIX=$(GOOS)_$(GOARCH) COMMIT_HASH=$(shell git rev-parse HEAD) GIT_BRANCH=$(shell git branch --show-current | tr '[:upper:]' '[:lower:]') GIT_VERSION=$(shell git branch --show-current | tr '[:upper:]' '[:lower:]') BUILD_TIMESTAMP=$(shell date +%s) export VER?=0.0.0 help: ## Print this help message. @awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST) build-debug: ## Build for debugging. export CGO_ENABLED=1 export GCLFAGS='-gcflags="all=-N -l"' ${MAKE} build-base build: ## Build. export CGO_ENABLED=0 export LDFLAGS_EXT='-extldflags=-static -s -w' ${MAKE} build-base build-race: ## Build with -race flag. export CGO_ENABLED=1 export GCLFAGS='-race' export LDFLAGS_EXT='-extldflags=-static -s -w' ${MAKE} build-base build-base: ## Build binary (select the platform via GOOS / GOARCH env variables). go build ${GCLFAGS} -ldflags="${LDFLAGS_EXT} \ -X 'github.com/kubeshark/kubeshark/misc.GitCommitHash=$(COMMIT_HASH)' \ -X 'github.com/kubeshark/kubeshark/misc.Branch=$(GIT_BRANCH)' \ -X 'github.com/kubeshark/kubeshark/misc.BuildTimestamp=$(BUILD_TIMESTAMP)' \ -X 'github.com/kubeshark/kubeshark/misc.Platform=$(SUFFIX)' \ -X 'github.com/kubeshark/kubeshark/misc.Ver=$(VER)'" \ -o bin/kubeshark_$(SUFFIX) kubeshark.go && \ cd bin && shasum -a 256 kubeshark_${SUFFIX} > kubeshark_${SUFFIX}.sha256 build-brew: ## Build binary for brew/core CI go build ${GCLFAGS} -ldflags="${LDFLAGS_EXT} \ -X 'github.com/kubeshark/kubeshark/misc.GitCommitHash=$(COMMIT_HASH)' \ -X 'github.com/kubeshark/kubeshark/misc.Branch=$(GIT_BRANCH)' \ -X 'github.com/kubeshark/kubeshark/misc.BuildTimestamp=$(BUILD_TIMESTAMP)' \ -X 'github.com/kubeshark/kubeshark/misc.Platform=$(SUFFIX)' \ -X 'github.com/kubeshark/kubeshark/misc.Ver=$(VER)'" \ -o kubeshark kubeshark.go build-windows-amd64: $(MAKE) build GOOS=windows GOARCH=amd64 && \ mv ./bin/kubeshark_windows_amd64 ./bin/kubeshark.exe && \ rm bin/kubeshark_windows_amd64.sha256 && \ cd bin && shasum -a 256 kubeshark.exe > kubeshark.exe.sha256 build-all: ## Build for all supported platforms. export CGO_ENABLED=0 echo "Compiling for every OS and Platform" && \ mkdir -p bin && sed s/_VER_/$(VER)/g RELEASE.md.TEMPLATE > bin/README.md && \ $(MAKE) build GOOS=linux GOARCH=amd64 && \ $(MAKE) build GOOS=linux GOARCH=arm64 && \ $(MAKE) build GOOS=darwin GOARCH=amd64 && \ $(MAKE) build GOOS=darwin GOARCH=arm64 && \ $(MAKE) build-windows-amd64 && \ echo "---------" && \ find ./bin -ls clean: ## Clean all build artifacts. go clean rm -rf ./bin/* test: ## Run cli tests. @go test ./... -coverpkg=./... -race -coverprofile=coverage.out -covermode=atomic lint: ## Lint the source code. golangci-lint run kubectl-view-all-resources: ## This command outputs all Kubernetes resources using YAML format and pipes it to VS Code ./kubectl.sh view-all-resources kubectl-view-kubeshark-resources: ## This command outputs all Kubernetes resources in "kubeshark" namespace using YAML format and pipes it to VS Code ./kubectl.sh view-kubeshark-resources generate-helm-values: ## Generate the Helm values from config.yaml mv ~/.kubeshark/config.yaml ~/.kubeshark/config.yaml.old; bin/kubeshark__ config>helm-chart/values.yaml;mv ~/.kubeshark/config.yaml.old ~/.kubeshark/config.yaml sed -i 's/^license:.*/license: ""/' helm-chart/values.yaml && sed -i '1i # find a detailed description here: https://github.com/kubeshark/kubeshark/blob/master/helm-chart/README.md' helm-chart/values.yaml generate-manifests: ## Generate the manifests from the Helm chart using default configuration helm template kubeshark -n default ./helm-chart > ./manifests/complete.yaml logs-sniffer: export LOGS_POD_PREFIX=kubeshark-worker- export LOGS_CONTAINER='-c sniffer' export LOGS_FOLLOW= ${MAKE} logs logs-sniffer-follow: export LOGS_POD_PREFIX=kubeshark-worker- export LOGS_CONTAINER='-c sniffer' export LOGS_FOLLOW=--follow ${MAKE} logs logs-tracer: export LOGS_POD_PREFIX=kubeshark-worker- export LOGS_CONTAINER='-c tracer' export LOGS_FOLLOW= ${MAKE} logs logs-tracer-follow: export LOGS_POD_PREFIX=kubeshark-worker- export LOGS_CONTAINER='-c tracer' export LOGS_FOLLOW=--follow ${MAKE} logs logs-worker: logs-sniffer logs-worker-follow: logs-sniffer-follow logs-hub: export LOGS_POD_PREFIX=kubeshark-hub export LOGS_FOLLOW= ${MAKE} logs logs-hub-follow: export LOGS_POD_PREFIX=kubeshark-hub export LOGS_FOLLOW=--follow ${MAKE} logs logs-front: export LOGS_POD_PREFIX=kubeshark-front export LOGS_FOLLOW= ${MAKE} logs logs-front-follow: export LOGS_POD_PREFIX=kubeshark-front export LOGS_FOLLOW=--follow ${MAKE} logs logs: kubectl logs $$(kubectl get pods | awk '$$1 ~ /^$(LOGS_POD_PREFIX)/' | awk 'END {print $$1}') $(LOGS_CONTAINER) $(LOGS_FOLLOW) ssh-node: kubectl ssh node $$(kubectl get nodes | awk 'END {print $$1}') exec-worker: export EXEC_POD_PREFIX=kubeshark-worker- ${MAKE} exec exec-hub: export EXEC_POD_PREFIX=kubeshark-hub ${MAKE} exec exec-front: export EXEC_POD_PREFIX=kubeshark-front ${MAKE} exec exec: kubectl exec --stdin --tty $$(kubectl get pods | awk '$$1 ~ /^$(EXEC_POD_PREFIX)/' | awk 'END {print $$1}') -- /bin/sh helm-install: cd helm-chart && helm install kubeshark . --set tap.docker.tag=$(TAG) && cd .. helm-install-debug: cd helm-chart && helm install kubeshark . --set tap.docker.tag=$(TAG) --set tap.debug=true && cd .. helm-install-profile: cd helm-chart && helm install kubeshark . --set tap.docker.tag=$(TAG) --set tap.pprof.enabled=true && cd .. helm-uninstall: helm uninstall kubeshark proxy: kubeshark proxy port-forward: kubectl port-forward $$(kubectl get pods | awk '$$1 ~ /^$(POD_PREFIX)/' | awk 'END {print $$1}') $(SRC_PORT):$(DST_PORT) release: @cd ../worker && git checkout master && git pull && git tag -d v$(VERSION); git tag v$(VERSION) && git push origin --tags @cd ../tracer && git checkout master && git pull && git tag -d v$(VERSION); git tag v$(VERSION) && git push origin --tags @cd ../hub && git checkout master && git pull && git tag -d v$(VERSION); git tag v$(VERSION) && git push origin --tags @cd ../front && git checkout master && git pull && git tag -d v$(VERSION); git tag v$(VERSION) && git push origin --tags @cd ../kubeshark && git checkout master && git pull && sed -i 's/^version:.*/version: "$(VERSION)"/' helm-chart/Chart.yaml && make && make generate-helm-values && make generate-manifests @git add -A . && git commit -m ":bookmark: Bump the Helm chart version to $(VERSION)" && git push @git tag -d v$(VERSION); git tag v$(VERSION) && git push origin --tags @cd helm-chart && cp -r . ../../kubeshark.github.io/charts/chart @cd ../kubeshark.github.io/ && git add -A . && git commit -m ":sparkles: Update the Helm chart" && git push @cd ../kubeshark soft-release: @cd ../worker && git checkout master && git pull && git tag -d v$(VERSION); git tag v$(VERSION) && git push origin --tags @cd ../tracer && git checkout master && git pull && git tag -d v$(VERSION); git tag v$(VERSION) && git push origin --tags @cd ../hub && git checkout master && git pull && git tag -d v$(VERSION); git tag v$(VERSION) && git push origin --tags @cd ../front && git checkout master && git pull && git tag -d v$(VERSION); git tag v$(VERSION) && git push origin --tags @cd ../kubeshark && git checkout master && git pull && sed -i 's/^version:.*/version: "$(VERSION)"/' helm-chart/Chart.yaml && make && make generate-helm-values && make generate-manifests @git add -A . && git commit -m ":bookmark: Bump the Helm chart version to $(VERSION)" && git push # @git tag -d v$(VERSION); git tag v$(VERSION) && git push origin --tags # @cd helm-chart && cp -r . ../../kubeshark.github.io/charts/chart # @cd ../kubeshark.github.io/ && git add -A . && git commit -m ":sparkles: Update the Helm chart" && git push # @cd ../kubeshark branch: @cd ../worker && git checkout master && git pull && git checkout -b $(name); git push --set-upstream origin $(name) @cd ../hub && git checkout master && git pull && git checkout -b $(name); git push --set-upstream origin $(name) @cd ../front && git checkout master && git pull && git checkout -b $(name); git push --set-upstream origin $(name) switch-to-branch: @cd ../worker && git checkout $(name) @cd ../hub && git checkout $(name) @cd ../front && git checkout $(name) 07070100000011000081A4000000000000000000000001673DBE2800000C6D000000000000000000000000000000000000002000000000kubeshark-cli-52.3.90/README.md<p align="center"> <img src="https://raw.githubusercontent.com/kubeshark/assets/master/svg/kubeshark-logo.svg" alt="Kubeshark: Traffic analyzer for Kubernetes." height="128px"/> </p> <p align="center"> <a href="https://github.com/kubeshark/kubeshark/releases/latest"> <img alt="GitHub Latest Release" src="https://img.shields.io/github/v/release/kubeshark/kubeshark?logo=GitHub&style=flat-square"> </a> <a href="https://hub.docker.com/r/kubeshark/worker"> <img alt="Docker pulls" src="https://img.shields.io/docker/pulls/kubeshark/worker?color=%23099cec&logo=Docker&style=flat-square"> </a> <a href="https://hub.docker.com/r/kubeshark/worker"> <img alt="Image size" src="https://img.shields.io/docker/image-size/kubeshark/kubeshark/latest?logo=Docker&style=flat-square"> </a> <a href="https://discord.gg/WkvRGMUcx7"> <img alt="Discord" src="https://img.shields.io/discord/1042559155224973352?logo=Discord&style=flat-square&label=discord"> </a> <a href="https://join.slack.com/t/kubeshark/shared_invite/zt-1m90td3n7-VHxN_~V5kVp80SfQW3SfpA"> <img alt="Slack" src="https://img.shields.io/badge/slack-join_chat-green?logo=Slack&style=flat-square&label=slack"> </a> </p> <p align="center"> <b> Want to see Kubeshark in action, right now? Visit this <a href="https://demo.kubeshark.co/">live demo deployment</a> of Kubeshark. </b> </p> **Kubeshark** is an API Traffic Analyzer for [**Kubernetes**](https://kubernetes.io/) providing real-time, protocol-level visibility into Kubernetes’ internal network, capturing and monitoring all traffic and payloads going in, out and across containers, pods, nodes and clusters. ![Simple UI](https://github.com/kubeshark/assets/raw/master/png/kubeshark-ui.png) Think [TCPDump](https://en.wikipedia.org/wiki/Tcpdump) and [Wireshark](https://www.wireshark.org/) re-invented for Kubernetes ## Getting Started Download **Kubeshark**'s binary distribution [latest release](https://github.com/kubeshark/kubeshark/releases/latest) and run following one of these examples: ```shell kubeshark tap ``` ```shell kubeshark tap -n sock-shop "(catalo*|front-end*)" ``` Running any of the :point_up: above commands will open the [Web UI](https://docs.kubeshark.co/en/ui) in your browser which streams the traffic in your Kubernetes cluster in real-time. ### Homebrew [Homebrew](https://brew.sh/) :beer: users install Kubeshark CLI with: ```shell brew install kubeshark ``` ### Helm Add the helm repository and install the chart: ```shell helm repo add kubeshark https://helm.kubeshark.co helm install kubeshark kubeshark/kubeshark ``` ## Building From Source Clone this repository and run `make` command to build it. After the build is complete, the executable can be found at `./bin/kubeshark__`. ## Documentation To learn more, read the [documentation](https://docs.kubeshark.co). ## Contributing We :heart: pull requests! See [CONTRIBUTING.md](CONTRIBUTING.md) for the contribution guide. ## Code of Conduct This project is for everyone. We ask that our users and contributors take a few minutes to review our [Code of Conduct](CODE_OF_CONDUCT.md). 07070100000012000081A4000000000000000000000001673DBE28000003E8000000000000000000000000000000000000002A00000000kubeshark-cli-52.3.90/RELEASE.md.TEMPLATE# Kubeshark release _VER_ Release notes coming soon .. ## Download Kubeshark for your platform **Mac** (x86-64/Intel) ``` curl -Lo kubeshark https://github.com/kubeshark/kubeshark/releases/download/_VER_/kubeshark_darwin_amd64 && chmod 755 kubeshark ``` **Mac** (AArch64/Apple M1 silicon) ``` rm -f kubeshark && curl -Lo kubeshark https://github.com/kubeshark/kubeshark/releases/download/_VER_/kubeshark_darwin_arm64 && chmod 755 kubeshark ``` **Linux** (x86-64) ``` curl -Lo kubeshark https://github.com/kubeshark/kubeshark/releases/download/_VER_/kubeshark_linux_amd64 && chmod 755 kubeshark ``` **Linux** (AArch64) ``` curl -Lo kubeshark https://github.com/kubeshark/kubeshark/releases/download/_VER_/kubeshark_linux_arm64 && chmod 755 kubeshark ``` **Windows** (x86-64) ``` curl -LO https://github.com/kubeshark/kubeshark/releases/download/_VER_/kubeshark.exe ``` ### Checksums SHA256 checksums available for compiled binaries. Run `shasum -a 256 -c kubeshark_OS_ARCH.sha256` to verify. 07070100000013000041ED000000000000000000000002673DBE2800000000000000000000000000000000000000000000001A00000000kubeshark-cli-52.3.90/cmd07070100000014000081A4000000000000000000000001673DBE2800000453000000000000000000000000000000000000002300000000kubeshark-cli-52.3.90/cmd/clean.gopackage cmd import ( "fmt" "github.com/creasty/defaults" "github.com/kubeshark/kubeshark/config" "github.com/kubeshark/kubeshark/config/configStructs" "github.com/kubeshark/kubeshark/kubernetes/helm" "github.com/kubeshark/kubeshark/misc" "github.com/rs/zerolog/log" "github.com/spf13/cobra" ) var cleanCmd = &cobra.Command{ Use: "clean", Short: fmt.Sprintf("Removes all %s resources", misc.Software), RunE: func(cmd *cobra.Command, args []string) error { resp, err := helm.NewHelm( config.Config.Tap.Release.Repo, config.Config.Tap.Release.Name, config.Config.Tap.Release.Namespace, ).Uninstall() if err != nil { log.Error().Err(err).Send() } else { log.Info().Msgf("Uninstalled the Helm release: %s", resp.Release.Name) } return nil }, } func init() { rootCmd.AddCommand(cleanCmd) defaultTapConfig := configStructs.TapConfig{} if err := defaults.Set(&defaultTapConfig); err != nil { log.Debug().Err(err).Send() } cleanCmd.Flags().StringP(configStructs.ReleaseNamespaceLabel, "s", defaultTapConfig.Release.Namespace, "Release namespace of Kubeshark") } 07070100000015000081A4000000000000000000000001673DBE2800001077000000000000000000000000000000000000002400000000kubeshark-cli-52.3.90/cmd/common.gopackage cmd import ( "context" "errors" "fmt" "path" "regexp" "time" "github.com/kubeshark/kubeshark/config" "github.com/kubeshark/kubeshark/errormessage" "github.com/kubeshark/kubeshark/internal/connect" "github.com/kubeshark/kubeshark/kubernetes" "github.com/kubeshark/kubeshark/misc" "github.com/kubeshark/kubeshark/misc/fsUtils" "github.com/rs/zerolog/log" ) func startProxyReportErrorIfAny(kubernetesProvider *kubernetes.Provider, ctx context.Context, serviceName string, podName string, proxyPortLabel string, srcPort uint16, dstPort uint16, healthCheck string) { httpServer, err := kubernetes.StartProxy(kubernetesProvider, config.Config.Tap.Proxy.Host, srcPort, config.Config.Tap.Release.Namespace, serviceName) if err != nil { log.Error(). Err(errormessage.FormatError(err)). Msg(fmt.Sprintf("Error occurred while running K8s proxy. Try setting different port using --%s", proxyPortLabel)) return } connector := connect.NewConnector(kubernetes.GetProxyOnPort(srcPort), connect.DefaultRetries, connect.DefaultTimeout) if err := connector.TestConnection(healthCheck); err != nil { log.Warn(). Str("service", serviceName). Msg("Couldn't connect using proxy, stopping proxy and trying to create port-forward...") if err := httpServer.Shutdown(ctx); err != nil { log.Error(). Err(errormessage.FormatError(err)). Msg("Error occurred while stopping proxy.") } podRegex, _ := regexp.Compile(podName) if _, err := kubernetes.NewPortForward(kubernetesProvider, config.Config.Tap.Release.Namespace, podRegex, srcPort, dstPort, ctx); err != nil { log.Error(). Str("pod-regex", podRegex.String()). Err(errormessage.FormatError(err)). Msg(fmt.Sprintf("Error occurred while running port forward. Try setting different port using --%s", proxyPortLabel)) return } connector = connect.NewConnector(kubernetes.GetProxyOnPort(srcPort), connect.DefaultRetries, connect.DefaultTimeout) if err := connector.TestConnection(healthCheck); err != nil { log.Error(). Str("service", serviceName). Err(errormessage.FormatError(err)). Msg("Couldn't connect to service.") return } } } func getKubernetesProviderForCli(silent bool, dontCheckVersion bool) (*kubernetes.Provider, error) { kubeConfigPath := config.Config.KubeConfigPath() kubernetesProvider, err := kubernetes.NewProvider(kubeConfigPath, config.Config.Kube.Context) if err != nil { handleKubernetesProviderError(err) return nil, err } if !silent { log.Info().Str("path", kubeConfigPath).Msg("Using kubeconfig:") } if err := kubernetesProvider.ValidateNotProxy(); err != nil { handleKubernetesProviderError(err) return nil, err } if !dontCheckVersion { kubernetesVersion, err := kubernetesProvider.GetKubernetesVersion() if err != nil { handleKubernetesProviderError(err) return nil, err } if err := kubernetes.ValidateKubernetesVersion(kubernetesVersion); err != nil { handleKubernetesProviderError(err) return nil, err } } return kubernetesProvider, nil } func handleKubernetesProviderError(err error) { var clusterBehindProxyErr *kubernetes.ClusterBehindProxyError if ok := errors.As(err, &clusterBehindProxyErr); ok { log.Error().Msg(fmt.Sprintf("Cannot establish http-proxy connection to the Kubernetes cluster. If you’re using Lens or similar tool, please run '%s' with regular kubectl config using --%v %v=$HOME/.kube/config flag", misc.Program, config.SetCommandName, config.KubeConfigPathConfigName)) } else { log.Error().Err(err).Send() } } func finishSelfExecution(kubernetesProvider *kubernetes.Provider) { removalCtx, cancel := context.WithTimeout(context.Background(), cleanupTimeout) defer cancel() dumpLogsIfNeeded(removalCtx, kubernetesProvider) } func dumpLogsIfNeeded(ctx context.Context, kubernetesProvider *kubernetes.Provider) { if !config.Config.DumpLogs { return } dotDir := misc.GetDotFolderPath() filePath := path.Join(dotDir, fmt.Sprintf("%s_logs_%s.zip", misc.Program, time.Now().Format("2006_01_02__15_04_05"))) if err := fsUtils.DumpLogs(ctx, kubernetesProvider, filePath, config.Config.Logs.Grep); err != nil { log.Error().Err(err).Msg("Failed to dump logs.") } } 07070100000016000081A4000000000000000000000001673DBE280000067A000000000000000000000000000000000000002400000000kubeshark-cli-52.3.90/cmd/config.gopackage cmd import ( "fmt" "path" "github.com/creasty/defaults" "github.com/kubeshark/kubeshark/config" "github.com/kubeshark/kubeshark/config/configStructs" "github.com/kubeshark/kubeshark/misc" "github.com/kubeshark/kubeshark/utils" "github.com/rs/zerolog/log" "github.com/spf13/cobra" ) var configCmd = &cobra.Command{ Use: "config", Short: fmt.Sprintf("Generate %s config with default values", misc.Software), RunE: func(cmd *cobra.Command, args []string) error { if config.Config.Config.Regenerate { defaultConfig := config.CreateDefaultConfig() if err := defaults.Set(&defaultConfig); err != nil { log.Error().Err(err).Send() return nil } if err := config.WriteConfig(&defaultConfig); err != nil { log.Error().Err(err).Msg("Failed generating config with defaults.") return nil } log.Info().Str("config-path", config.ConfigFilePath).Msg("Template file written to config path.") } else { template, err := utils.PrettyYaml(config.Config) if err != nil { log.Error().Err(err).Msg("Failed converting config with defaults to YAML.") return nil } log.Debug().Str("template", template).Msg("Printing template config...") fmt.Printf("%v", template) } return nil }, } func init() { rootCmd.AddCommand(configCmd) defaultConfig := config.CreateDefaultConfig() if err := defaults.Set(&defaultConfig); err != nil { log.Debug().Err(err).Send() } configCmd.Flags().BoolP(configStructs.RegenerateConfigName, "r", defaultConfig.Config.Regenerate, fmt.Sprintf("Regenerate the config file with default values to path %s", path.Join(misc.GetDotFolderPath(), "config.yaml"))) } 07070100000017000081A4000000000000000000000001673DBE28000010D4000000000000000000000000000000000000002500000000kubeshark-cli-52.3.90/cmd/console.gopackage cmd import ( "fmt" "net/http" "net/url" "os" "os/signal" "strings" "time" "github.com/creasty/defaults" "github.com/gorilla/websocket" "github.com/kubeshark/kubeshark/config" "github.com/kubeshark/kubeshark/config/configStructs" "github.com/kubeshark/kubeshark/kubernetes" "github.com/kubeshark/kubeshark/utils" "github.com/rs/zerolog/log" "github.com/spf13/cobra" ) var consoleCmd = &cobra.Command{ Use: "console", Short: "Stream the scripting console logs into shell", RunE: func(cmd *cobra.Command, args []string) error { runConsole() return nil }, } func init() { rootCmd.AddCommand(consoleCmd) defaultTapConfig := configStructs.TapConfig{} if err := defaults.Set(&defaultTapConfig); err != nil { log.Debug().Err(err).Send() } consoleCmd.Flags().Uint16(configStructs.ProxyFrontPortLabel, defaultTapConfig.Proxy.Front.Port, "Provide a custom port for the Kubeshark") consoleCmd.Flags().String(configStructs.ProxyHostLabel, defaultTapConfig.Proxy.Host, "Provide a custom host for the Kubeshark") consoleCmd.Flags().StringP(configStructs.ReleaseNamespaceLabel, "s", defaultTapConfig.Release.Namespace, "Release namespace of Kubeshark") } func runConsoleWithoutProxy() { log.Info().Msg("Starting scripting console ...") time.Sleep(5 * time.Second) hubUrl := kubernetes.GetHubUrl() for { // Attempt to connect to the Hub every second response, err := http.Get(fmt.Sprintf("%s/echo", hubUrl)) if err != nil || response.StatusCode != 200 { log.Info().Msg(fmt.Sprintf(utils.Yellow, "Couldn't connect to Hub.")) time.Sleep(5 * time.Second) continue } interrupt := make(chan os.Signal, 1) signal.Notify(interrupt, os.Interrupt) log.Info().Str("host", config.Config.Tap.Proxy.Host).Str("url", hubUrl).Msg("Connecting to:") u := url.URL{ Scheme: "ws", Host: fmt.Sprintf("%s:%d", config.Config.Tap.Proxy.Host, config.Config.Tap.Proxy.Front.Port), Path: "/api/scripts/logs", } headers := http.Header{} headers.Set(utils.X_KUBESHARK_CAPTURE_HEADER_KEY, utils.X_KUBESHARK_CAPTURE_HEADER_IGNORE_VALUE) headers.Set("License-Key", config.Config.License) c, _, err := websocket.DefaultDialer.Dial(u.String(), headers) if err != nil { log.Error().Err(err).Msg("Websocket dial error, retrying in 5 seconds...") time.Sleep(5 * time.Second) // Delay before retrying continue } defer c.Close() done := make(chan struct{}) go func() { defer close(done) for { _, message, err := c.ReadMessage() if err != nil { log.Error().Err(err).Msg("Error reading websocket message, reconnecting...") break // Break to reconnect } msg := string(message) if strings.Contains(msg, ":ERROR]") { msg = fmt.Sprintf(utils.Red, msg) fmt.Fprintln(os.Stderr, msg) } else { fmt.Fprintln(os.Stdout, msg) } } }() ticker := time.NewTicker(time.Second) defer ticker.Stop() select { case <-done: log.Warn().Msg(fmt.Sprintf(utils.Yellow, "Connection closed, reconnecting...")) time.Sleep(5 * time.Second) // Delay before reconnecting continue // Reconnect after error case <-interrupt: err := c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, "")) if err != nil { log.Error().Err(err).Send() continue } select { case <-done: case <-time.After(time.Second): } return } } } func runConsole() { go runConsoleWithoutProxy() // Create interrupt channel and setup signal handling once interrupt := make(chan os.Signal, 1) signal.Notify(interrupt, os.Interrupt) done := make(chan struct{}) ticker := time.NewTicker(5 * time.Second) defer ticker.Stop() for { select { case <-interrupt: // Handle interrupt and exit gracefully log.Warn().Msg(fmt.Sprintf(utils.Yellow, "Received interrupt, exiting...")) select { case <-done: case <-time.After(time.Second): } return case <-ticker.C: // Attempt to connect to the Hub every second hubUrl := kubernetes.GetHubUrl() response, err := http.Get(fmt.Sprintf("%s/echo", hubUrl)) if err != nil || response.StatusCode != 200 { log.Info().Msg(fmt.Sprintf(utils.Yellow, "Couldn't connect to Hub. Establishing proxy...")) runProxy(false, true) } } } } 07070100000018000081A4000000000000000000000001673DBE2800000163000000000000000000000000000000000000002500000000kubeshark-cli-52.3.90/cmd/license.gopackage cmd import ( "fmt" "github.com/kubeshark/kubeshark/config" "github.com/spf13/cobra" ) var licenseCmd = &cobra.Command{ Use: "license", Short: "Print the license loaded string", RunE: func(cmd *cobra.Command, args []string) error { fmt.Println(config.Config.License) return nil }, } func init() { rootCmd.AddCommand(licenseCmd) } 07070100000019000081A4000000000000000000000001673DBE2800000640000000000000000000000000000000000000002200000000kubeshark-cli-52.3.90/cmd/logs.gopackage cmd import ( "context" "fmt" "github.com/creasty/defaults" "github.com/kubeshark/kubeshark/config" "github.com/kubeshark/kubeshark/config/configStructs" "github.com/kubeshark/kubeshark/errormessage" "github.com/kubeshark/kubeshark/misc" "github.com/kubeshark/kubeshark/misc/fsUtils" "github.com/rs/zerolog/log" "github.com/spf13/cobra" ) var logsCmd = &cobra.Command{ Use: "logs", Short: "Create a ZIP file with logs for GitHub issues or troubleshooting", RunE: func(cmd *cobra.Command, args []string) error { kubernetesProvider, err := getKubernetesProviderForCli(false, false) if err != nil { return nil } ctx := context.Background() if validationErr := config.Config.Logs.Validate(); validationErr != nil { return errormessage.FormatError(validationErr) } log.Debug().Str("logs-path", config.Config.Logs.FilePath()).Msg("Using this logs path...") if dumpLogsErr := fsUtils.DumpLogs(ctx, kubernetesProvider, config.Config.Logs.FilePath(), config.Config.Logs.Grep); dumpLogsErr != nil { log.Error().Err(dumpLogsErr).Msg("Failed to dump logs.") } return nil }, } func init() { rootCmd.AddCommand(logsCmd) defaultLogsConfig := configStructs.LogsConfig{} if err := defaults.Set(&defaultLogsConfig); err != nil { log.Debug().Err(err).Send() } logsCmd.Flags().StringP(configStructs.FileLogsName, "f", defaultLogsConfig.FileStr, fmt.Sprintf("Path for zip file (default current <pwd>\\%s_logs.zip)", misc.Program)) logsCmd.Flags().StringP(configStructs.GrepLogsName, "g", defaultLogsConfig.Grep, "Regexp to do grepping on the logs") } 0707010000001A000081A4000000000000000000000001673DBE2800000DA6000000000000000000000000000000000000002600000000kubeshark-cli-52.3.90/cmd/pcapDump.gopackage cmd import ( "errors" "path/filepath" "github.com/creasty/defaults" "github.com/kubeshark/kubeshark/config/configStructs" "github.com/rs/zerolog/log" "github.com/spf13/cobra" "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/util/homedir" ) // pcapDumpCmd represents the consolidated pcapdump command var pcapDumpCmd = &cobra.Command{ Use: "pcapdump", Short: "Store all captured traffic (including decrypted TLS) in a PCAP file.", RunE: func(cmd *cobra.Command, args []string) error { // Retrieve the kubeconfig path from the flag kubeconfig, _ := cmd.Flags().GetString(configStructs.PcapKubeconfig) // If kubeconfig is not provided, use the default location if kubeconfig == "" { if home := homedir.HomeDir(); home != "" { kubeconfig = filepath.Join(home, ".kube", "config") } else { return errors.New("kubeconfig flag not provided and no home directory available for default config location") } } // Use the current context in kubeconfig config, err := clientcmd.BuildConfigFromFlags("", kubeconfig) if err != nil { log.Error().Err(err).Msg("Error building kubeconfig") return err } clientset, err := kubernetes.NewForConfig(config) if err != nil { log.Error().Err(err).Msg("Error creating Kubernetes client") return err } // Handle copy operation if the copy string is provided if !cmd.Flags().Changed(configStructs.PcapDumpEnabled) { destDir, _ := cmd.Flags().GetString(configStructs.PcapDest) log.Info().Msg("Copying PCAP files") err = copyPcapFiles(clientset, config, destDir) if err != nil { log.Error().Err(err).Msg("Error copying PCAP files") return err } } else { // Handle start operation if the start string is provided enabled, err := cmd.Flags().GetBool(configStructs.PcapDumpEnabled) if err != nil { log.Error().Err(err).Msg("Error getting pcapdump enable flag") return err } timeInterval, _ := cmd.Flags().GetString(configStructs.PcapTimeInterval) maxTime, _ := cmd.Flags().GetString(configStructs.PcapMaxTime) maxSize, _ := cmd.Flags().GetString(configStructs.PcapMaxSize) err = startStopPcap(clientset, enabled, timeInterval, maxTime, maxSize) if err != nil { log.Error().Err(err).Msg("Error starting/stopping PCAP dump") return err } if enabled { log.Info().Msg("Pcapdump started successfully") return nil } else { log.Info().Msg("Pcapdump stopped successfully") return nil } } return nil }, } func init() { rootCmd.AddCommand(pcapDumpCmd) defaultPcapDumpConfig := configStructs.PcapDumpConfig{} if err := defaults.Set(&defaultPcapDumpConfig); err != nil { log.Debug().Err(err).Send() } pcapDumpCmd.Flags().String(configStructs.PcapTimeInterval, defaultPcapDumpConfig.PcapTimeInterval, "Time interval for PCAP file rotation (used with --start)") pcapDumpCmd.Flags().String(configStructs.PcapMaxTime, defaultPcapDumpConfig.PcapMaxTime, "Maximum time for retaining old PCAP files (used with --start)") pcapDumpCmd.Flags().String(configStructs.PcapMaxSize, defaultPcapDumpConfig.PcapMaxSize, "Maximum size of PCAP files before deletion (used with --start)") pcapDumpCmd.Flags().String(configStructs.PcapDest, "", "Local destination path for copied PCAP files (can not be used together with --enabled)") pcapDumpCmd.Flags().String(configStructs.PcapKubeconfig, "", "Enabled/Disable to pcap dumps (can not be used together with --dest)") } 0707010000001B000081A4000000000000000000000001673DBE2800002EFD000000000000000000000000000000000000002C00000000kubeshark-cli-52.3.90/cmd/pcapDumpRunner.gopackage cmd import ( "bytes" "context" "fmt" "os" "path/filepath" "strconv" "strings" "github.com/kubeshark/gopacket" "github.com/kubeshark/gopacket/layers" "github.com/kubeshark/gopacket/pcapgo" "github.com/rs/zerolog/log" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" clientk8s "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" "k8s.io/client-go/tools/remotecommand" ) const label = "app.kubeshark.co/app=worker" const SELF_RESOURCES_PREFIX = "kubeshark-" const SUFFIX_CONFIG_MAP = "config-map" // NamespaceFiles represents the namespace and the files found in that namespace. type NamespaceFiles struct { Namespace string // The namespace in which the files were found SrcDir string // The source directory from which the files were listed Files []string // List of files found in the namespace } // listWorkerPods fetches all worker pods from multiple namespaces func listWorkerPods(ctx context.Context, clientset *clientk8s.Clientset, namespaces []string) ([]corev1.Pod, error) { var allPods []corev1.Pod labelSelector := label for _, namespace := range namespaces { // List all pods matching the label in the current namespace pods, err := clientset.CoreV1().Pods(namespace).List(ctx, metav1.ListOptions{ LabelSelector: labelSelector, }) if err != nil { return nil, fmt.Errorf("failed to list worker pods in namespace %s: %w", namespace, err) } // Accumulate the pods allPods = append(allPods, pods.Items...) } return allPods, nil } // listFilesInPodDir lists all files in the specified directory inside the pod across multiple namespaces func listFilesInPodDir(ctx context.Context, clientset *clientk8s.Clientset, config *rest.Config, podName string, namespaces []string, configMapName, configMapKey string) ([]NamespaceFiles, error) { var namespaceFilesList []NamespaceFiles for _, namespace := range namespaces { // Attempt to get the ConfigMap in the current namespace configMap, err := clientset.CoreV1().ConfigMaps(namespace).Get(ctx, configMapName, metav1.GetOptions{}) if err != nil { continue } // Check if the source directory exists in the ConfigMap srcDir, ok := configMap.Data[configMapKey] if !ok || srcDir == "" { log.Error().Msgf("source directory not found in ConfigMap %s in namespace %s", configMapName, namespace) continue } // Attempt to get the pod in the current namespace pod, err := clientset.CoreV1().Pods(namespace).Get(ctx, podName, metav1.GetOptions{}) if err != nil { log.Error().Err(err).Msgf("failed to get pod %s in namespace %s", podName, namespace) continue } nodeName := pod.Spec.NodeName srcFilePath := filepath.Join("data", nodeName, srcDir) cmd := []string{"ls", srcFilePath} req := clientset.CoreV1().RESTClient().Post(). Resource("pods"). Name(podName). Namespace(namespace). SubResource("exec"). Param("container", "sniffer"). Param("stdout", "true"). Param("stderr", "true"). Param("command", cmd[0]). Param("command", cmd[1]) exec, err := remotecommand.NewSPDYExecutor(config, "POST", req.URL()) if err != nil { log.Error().Err(err).Msgf("failed to initialize executor for pod %s in namespace %s", podName, namespace) continue } var stdoutBuf bytes.Buffer var stderrBuf bytes.Buffer // Execute the command to list files err = exec.StreamWithContext(ctx, remotecommand.StreamOptions{ Stdout: &stdoutBuf, Stderr: &stderrBuf, }) if err != nil { log.Error().Err(err).Msgf("error listing files in pod %s in namespace %s: %s", podName, namespace, stderrBuf.String()) continue } // Split the output (file names) into a list files := strings.Split(strings.TrimSpace(stdoutBuf.String()), "\n") if len(files) > 0 { // Append the NamespaceFiles struct to the list namespaceFilesList = append(namespaceFilesList, NamespaceFiles{ Namespace: namespace, SrcDir: srcDir, Files: files, }) } } if len(namespaceFilesList) == 0 { return nil, fmt.Errorf("no files found in pod %s across the provided namespaces", podName) } return namespaceFilesList, nil } // copyFileFromPod copies a single file from a pod to a local destination func copyFileFromPod(ctx context.Context, clientset *kubernetes.Clientset, config *rest.Config, podName, namespace, srcDir, srcFile, destFile string) error { // Get the pod to retrieve its node name pod, err := clientset.CoreV1().Pods(namespace).Get(ctx, podName, metav1.GetOptions{}) if err != nil { return fmt.Errorf("failed to get pod %s in namespace %s: %w", podName, namespace, err) } // Construct the complete path using /data, the node name, srcDir, and srcFile nodeName := pod.Spec.NodeName srcFilePath := filepath.Join("data", nodeName, srcDir, srcFile) // Execute the `cat` command to read the file at the srcFilePath cmd := []string{"cat", srcFilePath} req := clientset.CoreV1().RESTClient().Post(). Resource("pods"). Name(podName). Namespace(namespace). SubResource("exec"). Param("container", "sniffer"). Param("stdout", "true"). Param("stderr", "true"). Param("command", cmd[0]). Param("command", cmd[1]) exec, err := remotecommand.NewSPDYExecutor(config, "POST", req.URL()) if err != nil { return fmt.Errorf("failed to initialize executor for pod %s in namespace %s: %w", podName, namespace, err) } // Create the local file to write the content to outFile, err := os.Create(destFile) if err != nil { return fmt.Errorf("failed to create destination file: %w", err) } defer outFile.Close() // Capture stderr for error logging var stderrBuf bytes.Buffer // Stream the file content from the pod to the local file err = exec.StreamWithContext(ctx, remotecommand.StreamOptions{ Stdout: outFile, Stderr: &stderrBuf, }) if err != nil { return fmt.Errorf("error copying file from pod %s in namespace %s: %s", podName, namespace, stderrBuf.String()) } return nil } func mergePCAPs(outputFile string, inputFiles []string) error { // Create the output file f, err := os.Create(outputFile) if err != nil { return err } defer f.Close() // Create a pcap writer for the output file writer := pcapgo.NewWriter(f) err = writer.WriteFileHeader(65536, layers.LinkTypeEthernet) // Snapshot length and LinkType if err != nil { return err } for _, inputFile := range inputFiles { log.Info().Msgf("Merging %s int %s", inputFile, outputFile) // Open each input file file, err := os.Open(inputFile) if err != nil { log.Error().Err(err).Msgf("Failed to open %v", inputFile) continue } defer file.Close() reader, err := pcapgo.NewReader(file) if err != nil { log.Error().Err(err).Msgf("Failed to create pcapng reader for %v", file.Name()) continue } // Create the packet source packetSource := gopacket.NewPacketSource(reader, layers.LinkTypeEthernet) for packet := range packetSource.Packets() { err := writer.WritePacket(packet.Metadata().CaptureInfo, packet.Data()) if err != nil { log.Error().Err(err).Msgf("Failed to write packet to %v", outputFile) continue } } } return nil } // setPcapConfigInKubernetes sets the PCAP config for all pods across multiple namespaces func setPcapConfigInKubernetes(ctx context.Context, clientset *clientk8s.Clientset, podName string, namespaces []string, enabledPcap bool, timeInterval, maxTime, maxSize string) error { for _, namespace := range namespaces { // Load the existing ConfigMap in the current namespace configMap, err := clientset.CoreV1().ConfigMaps(namespace).Get(ctx, "kubeshark-config-map", metav1.GetOptions{}) if err != nil { log.Error().Err(err).Msgf("failed to get ConfigMap in namespace %s", namespace) continue } // Update the values with user-provided input configMap.Data["PCAP_TIME_INTERVAL"] = timeInterval configMap.Data["PCAP_MAX_SIZE"] = maxSize configMap.Data["PCAP_MAX_TIME"] = maxTime configMap.Data["PCAP_DUMP_ENABLE"] = strconv.FormatBool(enabledPcap) // Apply the updated ConfigMap back to the cluster in the current namespace _, err = clientset.CoreV1().ConfigMaps(namespace).Update(ctx, configMap, metav1.UpdateOptions{}) if err != nil { log.Error().Err(err).Msgf("failed to update ConfigMap in namespace %s", namespace) continue } } return nil } // startPcap function for starting the PCAP capture func startStopPcap(clientset *kubernetes.Clientset, pcapEnable bool, timeInterval, maxTime, maxSize string) error { kubernetesProvider, err := getKubernetesProviderForCli(false, false) if err != nil { log.Error().Err(err).Send() return err } targetNamespaces := kubernetesProvider.GetNamespaces() // List worker pods workerPods, err := listWorkerPods(context.Background(), clientset, targetNamespaces) if err != nil { log.Error().Err(err).Msg("Error listing worker pods") return err } // Iterate over each pod to start the PCAP capture by updating the configuration in Kubernetes for _, pod := range workerPods { err := setPcapConfigInKubernetes(context.Background(), clientset, pod.Name, targetNamespaces, pcapEnable, timeInterval, maxTime, maxSize) if err != nil { log.Error().Err(err).Msgf("Error setting PCAP config for pod %s", pod.Name) continue } } return nil } // copyPcapFiles function for copying the PCAP files from the worker pods func copyPcapFiles(clientset *kubernetes.Clientset, config *rest.Config, destDir string) error { kubernetesProvider, err := getKubernetesProviderForCli(false, false) if err != nil { log.Error().Err(err).Send() return err } targetNamespaces := kubernetesProvider.GetNamespaces() // List worker pods workerPods, err := listWorkerPods(context.Background(), clientset, targetNamespaces) if err != nil { log.Error().Err(err).Msg("Error listing worker pods") return err } var currentFiles []string // Iterate over each pod to get the PCAP directory from config and copy files for _, pod := range workerPods { // Get the list of NamespaceFiles (files per namespace) and their source directories namespaceFiles, err := listFilesInPodDir(context.Background(), clientset, config, pod.Name, targetNamespaces, SELF_RESOURCES_PREFIX+SUFFIX_CONFIG_MAP, "PCAP_SRC_DIR") if err != nil { log.Error().Err(err).Msgf("Error listing files in pod %s", pod.Name) continue } // Copy each file from the pod to the local destination for each namespace for _, nsFiles := range namespaceFiles { for _, file := range nsFiles.Files { destFile := filepath.Join(destDir, file) // Pass the correct namespace and related details to the function err = copyFileFromPod(context.Background(), clientset, config, pod.Name, nsFiles.Namespace, nsFiles.SrcDir, file, destFile) if err != nil { log.Error().Err(err).Msgf("Error copying file from pod %s in namespace %s", pod.Name, nsFiles.Namespace) } else { log.Info().Msgf("Copied %s from %s to %s", file, pod.Name, destFile) } currentFiles = append(currentFiles, destFile) } } } if len(currentFiles) == 0 { log.Error().Msgf("No files to merge") return nil // continue } // Generate a temporary filename based on the first file tempMergedFile := currentFiles[0] + "_temp" // Merge the PCAPs into the temporary file err = mergePCAPs(tempMergedFile, currentFiles) if err != nil { log.Error().Err(err).Msgf("Error merging files") return err // continue } // Remove the original files after merging for _, file := range currentFiles { err := os.Remove(file) if err != nil { log.Error().Err(err).Msgf("Error removing file %s", file) } } // Rename the temp file to the final name (removing "_temp") finalMergedFile := strings.TrimSuffix(tempMergedFile, "_temp") err = os.Rename(tempMergedFile, finalMergedFile) if err != nil { log.Error().Err(err).Msgf("Error renaming merged file %s", tempMergedFile) // continue return err } log.Info().Msgf("Merged file created: %s", finalMergedFile) return nil } 0707010000001C000081A4000000000000000000000001673DBE28000004E9000000000000000000000000000000000000002300000000kubeshark-cli-52.3.90/cmd/pprof.gopackage cmd import ( "github.com/creasty/defaults" "github.com/kubeshark/kubeshark/config/configStructs" "github.com/rs/zerolog/log" "github.com/spf13/cobra" ) var pprofCmd = &cobra.Command{ Use: "pprof", Short: "Select a Kubeshark container and open the pprof web UI in the browser", RunE: func(cmd *cobra.Command, args []string) error { runPprof() return nil }, } func init() { rootCmd.AddCommand(pprofCmd) defaultTapConfig := configStructs.TapConfig{} if err := defaults.Set(&defaultTapConfig); err != nil { log.Debug().Err(err).Send() } pprofCmd.Flags().Uint16(configStructs.ProxyFrontPortLabel, defaultTapConfig.Proxy.Front.Port, "Provide a custom port for the proxy/port-forward") pprofCmd.Flags().String(configStructs.ProxyHostLabel, defaultTapConfig.Proxy.Host, "Provide a custom host for the proxy/port-forward") pprofCmd.Flags().StringP(configStructs.ReleaseNamespaceLabel, "s", defaultTapConfig.Release.Namespace, "Release namespace of Kubeshark") pprofCmd.Flags().Uint16(configStructs.PprofPortLabel, defaultTapConfig.Pprof.Port, "Provide a custom port for the pprof server") pprofCmd.Flags().String(configStructs.PprofViewLabel, defaultTapConfig.Pprof.View, "Change the default view of the pprof web interface") } 0707010000001D000081A4000000000000000000000001673DBE28000011F3000000000000000000000000000000000000002900000000kubeshark-cli-52.3.90/cmd/pprofRunner.gopackage cmd import ( "context" "fmt" "github.com/go-cmd/cmd" "github.com/kubeshark/kubeshark/config" "github.com/kubeshark/kubeshark/kubernetes" "github.com/kubeshark/kubeshark/utils" "github.com/rivo/tview" "github.com/rs/zerolog/log" v1 "k8s.io/api/core/v1" ) func runPprof() { runProxy(false, true) provider, err := getKubernetesProviderForCli(false, false) if err != nil { return } ctx, cancel := context.WithCancel(context.Background()) defer cancel() hubPods, err := provider.ListPodsByAppLabel(ctx, config.Config.Tap.Release.Namespace, map[string]string{kubernetes.AppLabelKey: "hub"}) if err != nil { log.Error(). Err(err). Msg("Failed to list hub pods!") cancel() return } workerPods, err := provider.ListPodsByAppLabel(ctx, config.Config.Tap.Release.Namespace, map[string]string{kubernetes.AppLabelKey: "worker"}) if err != nil { log.Error(). Err(err). Msg("Failed to list worker pods!") cancel() return } fullscreen := true app := tview.NewApplication() list := tview.NewList() var currentCmd *cmd.Cmd i := 48 for _, pod := range hubPods { for _, container := range pod.Spec.Containers { log.Info().Str("pod", pod.Name).Str("container", container.Name).Send() homeUrl := fmt.Sprintf("%s/debug/pprof/", kubernetes.GetHubUrl()) modal := buildNewModal( pod, container, homeUrl, app, list, fullscreen, currentCmd, ) list.AddItem(fmt.Sprintf("pod: %s container: %s", pod.Name, container.Name), pod.Spec.NodeName, rune(i), func() { app.SetRoot(modal, fullscreen) }) i++ } } for _, pod := range workerPods { for _, container := range pod.Spec.Containers { log.Info().Str("pod", pod.Name).Str("container", container.Name).Send() homeUrl := fmt.Sprintf("%s/pprof/%s/%s/", kubernetes.GetHubUrl(), pod.Status.HostIP, container.Name) modal := buildNewModal( pod, container, homeUrl, app, list, fullscreen, currentCmd, ) list.AddItem(fmt.Sprintf("pod: %s container: %s", pod.Name, container.Name), pod.Spec.NodeName, rune(i), func() { app.SetRoot(modal, fullscreen) }) i++ } } list.AddItem("Quit", "Press to exit", 'q', func() { if currentCmd != nil { err = currentCmd.Stop() if err != nil { log.Error().Err(err).Str("name", currentCmd.Name).Msg("Failed to stop process!") } } app.Stop() }) if err := app.SetRoot(list, fullscreen).EnableMouse(true).Run(); err != nil { panic(err) } } func buildNewModal( pod v1.Pod, container v1.Container, homeUrl string, app *tview.Application, list *tview.List, fullscreen bool, currentCmd *cmd.Cmd, ) *tview.Modal { return tview.NewModal(). SetText(fmt.Sprintf("pod: %s container: %s", pod.Name, container.Name)). AddButtons([]string{ "Open Debug Home Page", "Profile: CPU", "Profile: Memory", "Profile: Goroutine", "Cancel", }). SetDoneFunc(func(buttonIndex int, buttonLabel string) { var err error port := fmt.Sprintf(":%d", config.Config.Tap.Pprof.Port) view := fmt.Sprintf("http://localhost%s/ui/%s", port, config.Config.Tap.Pprof.View) switch buttonLabel { case "Open Debug Home Page": utils.OpenBrowser(homeUrl) case "Profile: CPU": if currentCmd != nil { err = currentCmd.Stop() if err != nil { log.Error().Err(err).Str("name", currentCmd.Name).Msg("Failed to stop process!") } } currentCmd = cmd.NewCmd("go", "tool", "pprof", "-http", port, "-no_browser", fmt.Sprintf("%sprofile", homeUrl)) currentCmd.Start() utils.OpenBrowser(view) case "Profile: Memory": if currentCmd != nil { err = currentCmd.Stop() if err != nil { log.Error().Err(err).Str("name", currentCmd.Name).Msg("Failed to stop process!") } } currentCmd = cmd.NewCmd("go", "tool", "pprof", "-http", port, "-no_browser", fmt.Sprintf("%sheap", homeUrl)) currentCmd.Start() utils.OpenBrowser(view) case "Profile: Goroutine": if currentCmd != nil { err = currentCmd.Stop() if err != nil { log.Error().Err(err).Str("name", currentCmd.Name).Msg("Failed to stop process!") } } currentCmd = cmd.NewCmd("go", "tool", "pprof", "-http", port, "-no_browser", fmt.Sprintf("%sgoroutine", homeUrl)) currentCmd.Start() utils.OpenBrowser(view) case "Cancel": if currentCmd != nil { err = currentCmd.Stop() if err != nil { log.Error().Err(err).Str("name", currentCmd.Name).Msg("Failed to stop process!") } } fallthrough default: app.SetRoot(list, fullscreen) } }) } 0707010000001E000081A4000000000000000000000001673DBE28000003E4000000000000000000000000000000000000002300000000kubeshark-cli-52.3.90/cmd/proxy.gopackage cmd import ( "github.com/creasty/defaults" "github.com/kubeshark/kubeshark/config/configStructs" "github.com/rs/zerolog/log" "github.com/spf13/cobra" ) var proxyCmd = &cobra.Command{ Use: "proxy", Short: "Open the web UI (front-end) in the browser via proxy/port-forward", RunE: func(cmd *cobra.Command, args []string) error { runProxy(true, false) return nil }, } func init() { rootCmd.AddCommand(proxyCmd) defaultTapConfig := configStructs.TapConfig{} if err := defaults.Set(&defaultTapConfig); err != nil { log.Debug().Err(err).Send() } proxyCmd.Flags().Uint16(configStructs.ProxyFrontPortLabel, defaultTapConfig.Proxy.Front.Port, "Provide a custom port for the proxy/port-forward") proxyCmd.Flags().String(configStructs.ProxyHostLabel, defaultTapConfig.Proxy.Host, "Provide a custom host for the proxy/port-forward") proxyCmd.Flags().StringP(configStructs.ReleaseNamespaceLabel, "s", defaultTapConfig.Release.Namespace, "Release namespace of Kubeshark") } 0707010000001F000081A4000000000000000000000001673DBE2800000B2F000000000000000000000000000000000000002900000000kubeshark-cli-52.3.90/cmd/proxyRunner.gopackage cmd import ( "context" "fmt" "net/http" "github.com/kubeshark/kubeshark/config" "github.com/kubeshark/kubeshark/config/configStructs" "github.com/kubeshark/kubeshark/internal/connect" "github.com/kubeshark/kubeshark/kubernetes" "github.com/kubeshark/kubeshark/misc" "github.com/kubeshark/kubeshark/utils" "github.com/rs/zerolog/log" ) func runProxy(block bool, noBrowser bool) { kubernetesProvider, err := getKubernetesProviderForCli(false, false) if err != nil { return } ctx, cancel := context.WithCancel(context.Background()) defer cancel() exists, err := kubernetesProvider.DoesServiceExist(ctx, config.Config.Tap.Release.Namespace, kubernetes.FrontServiceName) if err != nil { log.Error(). Str("service", kubernetes.FrontServiceName). Err(err). Msg("Failed to found service!") cancel() return } if !exists { log.Error(). Str("service", kubernetes.FrontServiceName). Str("command", fmt.Sprintf("%s %s", misc.Program, tapCmd.Use)). Msg("Service not found! You should run the command first:") cancel() return } exists, err = kubernetesProvider.DoesServiceExist(ctx, config.Config.Tap.Release.Namespace, kubernetes.HubServiceName) if err != nil { log.Error(). Str("service", kubernetes.HubServiceName). Err(err). Msg("Failed to found service!") cancel() return } if !exists { log.Error(). Str("service", kubernetes.HubServiceName). Str("command", fmt.Sprintf("%s %s", misc.Program, tapCmd.Use)). Msg("Service not found! You should run the command first:") cancel() return } var establishedProxy bool frontUrl := kubernetes.GetProxyOnPort(config.Config.Tap.Proxy.Front.Port) response, err := http.Get(fmt.Sprintf("%s/", frontUrl)) if err == nil && response.StatusCode == 200 { log.Info(). Str("service", kubernetes.FrontServiceName). Int("port", int(config.Config.Tap.Proxy.Front.Port)). Msg("Found a running service.") okToOpen("Kubeshark", frontUrl, noBrowser) } else { startProxyReportErrorIfAny( kubernetesProvider, ctx, kubernetes.FrontServiceName, kubernetes.FrontPodName, configStructs.ProxyFrontPortLabel, config.Config.Tap.Proxy.Front.Port, configStructs.ContainerPort, "", ) connector := connect.NewConnector(frontUrl, connect.DefaultRetries, connect.DefaultTimeout) if err := connector.TestConnection(""); err != nil { log.Error().Msg(fmt.Sprintf(utils.Red, "Couldn't connect to Front.")) return } establishedProxy = true okToOpen("Kubeshark", frontUrl, noBrowser) } if establishedProxy && block { utils.WaitForTermination(ctx, cancel) } } func okToOpen(name string, url string, noBrowser bool) { log.Info().Str("url", url).Msg(fmt.Sprintf(utils.Green, fmt.Sprintf("%s is available at:", name))) if !config.Config.HeadlessMode && !noBrowser { utils.OpenBrowser(url) } } 07070100000020000081A4000000000000000000000001673DBE28000004D9000000000000000000000000000000000000002200000000kubeshark-cli-52.3.90/cmd/root.gopackage cmd import ( "fmt" "github.com/creasty/defaults" "github.com/kubeshark/kubeshark/config" "github.com/kubeshark/kubeshark/misc" "github.com/rs/zerolog/log" "github.com/spf13/cobra" ) var rootCmd = &cobra.Command{ Use: "kubeshark", Short: fmt.Sprintf("%s: %s", misc.Software, misc.Description), Long: fmt.Sprintf(`%s: %s An extensible Kubernetes-aware network sniffer and kernel tracer. For more info: %s`, misc.Software, misc.Description, misc.Website), PersistentPreRunE: func(cmd *cobra.Command, args []string) error { if err := config.InitConfig(cmd); err != nil { log.Fatal().Err(err).Send() } return nil }, } func init() { defaultConfig := config.CreateDefaultConfig() if err := defaults.Set(&defaultConfig); err != nil { log.Debug().Err(err).Send() } rootCmd.PersistentFlags().StringSlice(config.SetCommandName, []string{}, fmt.Sprintf("Override values using --%s", config.SetCommandName)) rootCmd.PersistentFlags().BoolP(config.DebugFlag, "d", false, "Enable debug mode") } // Execute adds all child commands to the root command and sets flags appropriately. // This is called by main.main(). It only needs to happen once to the tapCmd. func Execute() { cobra.CheckErr(rootCmd.Execute()) } 07070100000021000081A4000000000000000000000001673DBE28000022FC000000000000000000000000000000000000002500000000kubeshark-cli-52.3.90/cmd/scripts.gopackage cmd import ( "context" "encoding/json" "errors" "os" "os/signal" "strings" "sync" "time" "github.com/creasty/defaults" "github.com/fsnotify/fsnotify" "github.com/kubeshark/kubeshark/config" "github.com/kubeshark/kubeshark/config/configStructs" "github.com/kubeshark/kubeshark/kubernetes" "github.com/kubeshark/kubeshark/misc" "github.com/rs/zerolog/log" "github.com/spf13/cobra" k8serrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/watch" ) var scriptsCmd = &cobra.Command{ Use: "scripts", Short: "Watch the `scripting.source` and/or `scripting.sources` folders for changes and update the scripts", RunE: func(cmd *cobra.Command, args []string) error { runScripts() return nil }, } func init() { rootCmd.AddCommand(scriptsCmd) defaultTapConfig := configStructs.TapConfig{} if err := defaults.Set(&defaultTapConfig); err != nil { log.Debug().Err(err).Send() } scriptsCmd.Flags().Uint16(configStructs.ProxyFrontPortLabel, defaultTapConfig.Proxy.Front.Port, "Provide a custom port for the Kubeshark") scriptsCmd.Flags().String(configStructs.ProxyHostLabel, defaultTapConfig.Proxy.Host, "Provide a custom host for the Kubeshark") scriptsCmd.Flags().StringP(configStructs.ReleaseNamespaceLabel, "s", defaultTapConfig.Release.Namespace, "Release namespace of Kubeshark") } func runScripts() { if config.Config.Scripting.Source == "" && len(config.Config.Scripting.Sources) == 0 { log.Error().Msg("Both `scripting.source` and `scripting.sources` fields are empty.") return } kubernetesProvider, err := getKubernetesProviderForCli(false, false) if err != nil { log.Error().Err(err).Send() return } var wg sync.WaitGroup ctx, cancel := context.WithCancel(context.Background()) defer cancel() signalChan := make(chan os.Signal, 1) signal.Notify(signalChan, os.Interrupt) wg.Add(1) go func() { defer wg.Done() watchConfigMap(ctx, kubernetesProvider) }() wg.Add(1) go func() { defer wg.Done() watchScripts(ctx, kubernetesProvider, true) }() go func() { <-signalChan log.Debug().Msg("Received interrupt, stopping watchers.") cancel() }() wg.Wait() } func createScript(provider *kubernetes.Provider, script misc.ConfigMapScript) (index int64, err error) { const maxRetries = 5 var scripts map[int64]misc.ConfigMapScript for i := 0; i < maxRetries; i++ { scripts, err = kubernetes.ConfigGetScripts(provider) if err != nil { return } script.Active = kubernetes.IsActiveScript(provider, script.Title) index = int64(len(scripts)) if script.Title != "New Script" { for i, v := range scripts { if v.Title == script.Title { index = int64(i) } } } scripts[index] = script log.Info().Str("title", script.Title).Bool("Active", script.Active).Int64("Index", index).Msg("Creating script") var data []byte data, err = json.Marshal(scripts) if err != nil { return } _, err = kubernetes.SetConfig(provider, kubernetes.CONFIG_SCRIPTING_SCRIPTS, string(data)) if err == nil { return index, nil } if k8serrors.IsConflict(err) { log.Warn().Err(err).Msg("Conflict detected, retrying update...") time.Sleep(500 * time.Millisecond) continue } return 0, err } log.Error().Msg("Max retries reached for creating script due to conflicts.") return 0, errors.New("max retries reached due to conflicts while creating script") } func updateScript(provider *kubernetes.Provider, index int64, script misc.ConfigMapScript) (err error) { var scripts map[int64]misc.ConfigMapScript scripts, err = kubernetes.ConfigGetScripts(provider) if err != nil { return } script.Active = kubernetes.IsActiveScript(provider, script.Title) scripts[index] = script var data []byte data, err = json.Marshal(scripts) if err != nil { return } _, err = kubernetes.SetConfig(provider, kubernetes.CONFIG_SCRIPTING_SCRIPTS, string(data)) if err != nil { return } return } func deleteScript(provider *kubernetes.Provider, index int64) (err error) { var scripts map[int64]misc.ConfigMapScript scripts, err = kubernetes.ConfigGetScripts(provider) if err != nil { return } err = kubernetes.DeleteActiveScriptByTitle(provider, scripts[index].Title) if err != nil { return } delete(scripts, index) var data []byte data, err = json.Marshal(scripts) if err != nil { return } _, err = kubernetes.SetConfig(provider, kubernetes.CONFIG_SCRIPTING_SCRIPTS, string(data)) if err != nil { return } return } func watchScripts(ctx context.Context, provider *kubernetes.Provider, block bool) { files := make(map[string]int64) scripts, err := config.Config.Scripting.GetScripts() if err != nil { log.Error().Err(err).Send() return } for _, script := range scripts { index, err := createScript(provider, script.ConfigMap()) if err != nil { log.Error().Err(err).Send() continue } files[script.Path] = index } watcher, err := fsnotify.NewWatcher() if err != nil { log.Error().Err(err).Send() return } if block { defer watcher.Close() } ctx, cancel := context.WithCancel(ctx) defer cancel() signalChan := make(chan os.Signal, 1) signal.Notify(signalChan, os.Interrupt) go func() { <-signalChan log.Debug().Msg("Received interrupt, stopping script watch.") cancel() watcher.Close() }() if err := watcher.Add(config.Config.Scripting.Source); err != nil { log.Error().Err(err).Msg("Failed to add scripting source to watcher") return } go func() { for { select { case <-ctx.Done(): log.Debug().Msg("Script watcher exiting gracefully.") return // watch for events case event := <-watcher.Events: if !strings.HasSuffix(event.Name, "js") { log.Info().Str("file", event.Name).Msg("Ignoring file") continue } switch event.Op { case fsnotify.Create: script, err := misc.ReadScriptFile(event.Name) if err != nil { log.Error().Err(err).Send() continue } index, err := createScript(provider, script.ConfigMap()) if err != nil { log.Error().Err(err).Send() continue } files[script.Path] = index case fsnotify.Write: index := files[event.Name] script, err := misc.ReadScriptFile(event.Name) if err != nil { log.Error().Err(err).Send() continue } err = updateScript(provider, index, script.ConfigMap()) if err != nil { log.Error().Err(err).Send() continue } case fsnotify.Rename: index := files[event.Name] err := deleteScript(provider, index) if err != nil { log.Error().Err(err).Send() continue } default: // pass } case err, ok := <-watcher.Errors: if !ok { log.Info().Msg("Watcher errors channel closed.") return } log.Error().Err(err).Msg("Watcher error encountered") } } }() if err := watcher.Add(config.Config.Scripting.Source); err != nil { log.Error().Err(err).Send() } for _, source := range config.Config.Scripting.Sources { if err := watcher.Add(source); err != nil { log.Error().Err(err).Send() } } log.Info().Str("folder", config.Config.Scripting.Source).Interface("folders", config.Config.Scripting.Sources).Msg("Watching scripts against changes:") if block { <-ctx.Done() } } func watchConfigMap(ctx context.Context, provider *kubernetes.Provider) { clientset := provider.GetClientSet() configMapName := kubernetes.SELF_RESOURCES_PREFIX + kubernetes.SUFFIX_CONFIG_MAP for { select { case <-ctx.Done(): log.Info().Msg("ConfigMap watcher exiting gracefully.") return default: watcher, err := clientset.CoreV1().ConfigMaps(config.Config.Tap.Release.Namespace).Watch(context.TODO(), metav1.ListOptions{ FieldSelector: "metadata.name=" + configMapName, }) if err != nil { log.Warn().Err(err).Msg("ConfigMap not found, retrying in 5 seconds...") time.Sleep(5 * time.Second) continue } for event := range watcher.ResultChan() { select { case <-ctx.Done(): log.Info().Msg("ConfigMap watcher loop exiting gracefully.") watcher.Stop() return default: if event.Type == watch.Added { log.Info().Msg("ConfigMap created or modified") runScriptsSync(provider) } else if event.Type == watch.Deleted { log.Warn().Msg("ConfigMap deleted, waiting for recreation...") watcher.Stop() break } } } time.Sleep(5 * time.Second) } } } func runScriptsSync(provider *kubernetes.Provider) { files := make(map[string]int64) scripts, err := config.Config.Scripting.GetScripts() if err != nil { log.Error().Err(err).Send() return } for _, script := range scripts { index, err := createScript(provider, script.ConfigMap()) if err != nil { log.Error().Err(err).Send() continue } files[script.Path] = index } log.Info().Msg("Synchronized scripts with ConfigMap.") } 07070100000022000081A4000000000000000000000001673DBE2800000F54000000000000000000000000000000000000002100000000kubeshark-cli-52.3.90/cmd/tap.gopackage cmd import ( "errors" "github.com/creasty/defaults" "github.com/kubeshark/kubeshark/config" "github.com/kubeshark/kubeshark/config/configStructs" "github.com/kubeshark/kubeshark/errormessage" "github.com/rs/zerolog/log" "github.com/spf13/cobra" ) var tapCmd = &cobra.Command{ Use: "tap [POD REGEX]", Short: "Capture the network traffic in your Kubernetes cluster", RunE: func(cmd *cobra.Command, args []string) error { tap() return nil }, PreRunE: func(cmd *cobra.Command, args []string) error { if len(args) == 1 { config.Config.Tap.PodRegexStr = args[0] } else if len(args) > 1 { return errors.New("unexpected number of arguments") } if err := config.Config.Tap.Validate(); err != nil { return errormessage.FormatError(err) } return nil }, } func init() { rootCmd.AddCommand(tapCmd) defaultTapConfig := configStructs.TapConfig{} if err := defaults.Set(&defaultTapConfig); err != nil { log.Debug().Err(err).Send() } tapCmd.Flags().StringP(configStructs.DockerRegistryLabel, "r", defaultTapConfig.Docker.Registry, "The Docker registry that's hosting the images") tapCmd.Flags().StringP(configStructs.DockerTagLabel, "t", defaultTapConfig.Docker.Tag, "The tag of the Docker images that are going to be pulled") tapCmd.Flags().String(configStructs.DockerImagePullPolicy, defaultTapConfig.Docker.ImagePullPolicy, "ImagePullPolicy for the Docker images") tapCmd.Flags().StringSlice(configStructs.DockerImagePullSecrets, defaultTapConfig.Docker.ImagePullSecrets, "ImagePullSecrets for the Docker images") tapCmd.Flags().Uint16(configStructs.ProxyFrontPortLabel, defaultTapConfig.Proxy.Front.Port, "Provide a custom port for the proxy/port-forward") tapCmd.Flags().String(configStructs.ProxyHostLabel, defaultTapConfig.Proxy.Host, "Provide a custom host for the proxy/port-forward") tapCmd.Flags().StringSliceP(configStructs.NamespacesLabel, "n", defaultTapConfig.Namespaces, "Namespaces selector") tapCmd.Flags().StringSliceP(configStructs.ExcludedNamespacesLabel, "e", defaultTapConfig.ExcludedNamespaces, "Excluded namespaces") tapCmd.Flags().StringP(configStructs.ReleaseNamespaceLabel, "s", defaultTapConfig.Release.Namespace, "Release namespace of Kubeshark") tapCmd.Flags().Bool(configStructs.PersistentStorageLabel, defaultTapConfig.PersistentStorage, "Enable persistent storage (PersistentVolumeClaim)") tapCmd.Flags().Bool(configStructs.PersistentStorageStaticLabel, defaultTapConfig.PersistentStorageStatic, "Persistent storage static provision") tapCmd.Flags().String(configStructs.EfsFileSytemIdAndPathLabel, defaultTapConfig.EfsFileSytemIdAndPath, "EFS file system ID") tapCmd.Flags().String(configStructs.StorageLimitLabel, defaultTapConfig.StorageLimit, "Override the default storage limit (per node)") tapCmd.Flags().String(configStructs.StorageClassLabel, defaultTapConfig.StorageClass, "Override the default storage class of the PersistentVolumeClaim (per node)") tapCmd.Flags().Bool(configStructs.DryRunLabel, defaultTapConfig.DryRun, "Preview of all pods matching the regex, without tapping them") tapCmd.Flags().Bool(configStructs.ServiceMeshLabel, defaultTapConfig.ServiceMesh, "Capture the encrypted traffic if the cluster is configured with a service mesh and with mTLS") tapCmd.Flags().Bool(configStructs.TlsLabel, defaultTapConfig.Tls, "Capture the traffic that's encrypted with OpenSSL or Go crypto/tls libraries") tapCmd.Flags().Bool(configStructs.IgnoreTaintedLabel, defaultTapConfig.IgnoreTainted, "Ignore tainted pods while running Worker DaemonSet") tapCmd.Flags().Bool(configStructs.IngressEnabledLabel, defaultTapConfig.Ingress.Enabled, "Enable Ingress") tapCmd.Flags().Bool(configStructs.TelemetryEnabledLabel, defaultTapConfig.Telemetry.Enabled, "Enable/disable Telemetry") tapCmd.Flags().Bool(configStructs.ResourceGuardEnabledLabel, defaultTapConfig.ResourceGuard.Enabled, "Enable/disable resource guard") } 07070100000023000081A4000000000000000000000001673DBE280000362A000000000000000000000000000000000000002700000000kubeshark-cli-52.3.90/cmd/tapRunner.gopackage cmd import ( "context" "encoding/json" "fmt" "os" "regexp" "strings" "sync" "time" "github.com/kubeshark/kubeshark/kubernetes/helm" "github.com/kubeshark/kubeshark/misc" "github.com/kubeshark/kubeshark/utils" core "k8s.io/api/core/v1" "github.com/kubeshark/kubeshark/config" "github.com/kubeshark/kubeshark/config/configStructs" "github.com/kubeshark/kubeshark/errormessage" "github.com/kubeshark/kubeshark/kubernetes" "github.com/rs/zerolog/log" ) const cleanupTimeout = time.Minute type tapState struct { startTime time.Time targetNamespaces []string } var state tapState type Readiness struct { Hub bool Front bool Proxy bool sync.Mutex } var ready *Readiness func tap() { ready = &Readiness{} state.startTime = time.Now() log.Info().Str("registry", config.Config.Tap.Docker.Registry).Str("tag", config.Config.Tap.Docker.Tag).Msg("Using Docker:") log.Info(). Str("limit", config.Config.Tap.StorageLimit). Msg(fmt.Sprintf("%s will store the traffic up to a limit (per node). Oldest TCP/UDP streams will be removed once the limit is reached.", misc.Software)) kubernetesProvider, err := getKubernetesProviderForCli(false, false) if err != nil { log.Error().Err(err).Send() return } ctx, cancel := context.WithCancel(context.Background()) defer cancel() // cancel will be called when this function exits state.targetNamespaces = kubernetesProvider.GetNamespaces() log.Info(). Bool("enabled", config.Config.Tap.Telemetry.Enabled). Str("notice", "Telemetry can be disabled by setting the flag: --telemetry-enabled=false"). Msg("Telemetry") log.Info().Strs("namespaces", state.targetNamespaces).Msg("Targeting pods in:") if err := printTargetedPodsPreview(ctx, kubernetesProvider, state.targetNamespaces); err != nil { log.Error().Err(errormessage.FormatError(err)).Msg("Error listing pods!") } if config.Config.Tap.DryRun { return } log.Info().Msg(fmt.Sprintf("Waiting for the creation of %s resources...", misc.Software)) rel, err := helm.NewHelm( config.Config.Tap.Release.Repo, config.Config.Tap.Release.Name, config.Config.Tap.Release.Namespace, ).Install() if err != nil { if err.Error() != "cannot re-use a name that is still in use" { log.Error().Err(err).Send() os.Exit(1) } log.Info().Msg("Found an existing installation, skipping Helm install...") updateConfig(kubernetesProvider) postFrontStarted(ctx, kubernetesProvider, cancel) } else { log.Info().Msgf("Installed the Helm release: %s", rel.Name) go watchHubEvents(ctx, kubernetesProvider, cancel) go watchHubPod(ctx, kubernetesProvider, cancel) go watchFrontPod(ctx, kubernetesProvider, cancel) } defer finishTapExecution(kubernetesProvider) // block until exit signal or error utils.WaitForTermination(ctx, cancel) if !config.Config.Tap.Ingress.Enabled { printProxyCommandSuggestion() } } func printProxyCommandSuggestion() { log.Warn(). Str("command", fmt.Sprintf("%s proxy", misc.Program)). Msg(fmt.Sprintf(utils.Yellow, "To re-establish a proxy/port-forward, run:")) } func finishTapExecution(kubernetesProvider *kubernetes.Provider) { finishSelfExecution(kubernetesProvider) } /* This function is a bit problematic as it might be detached from the actual pods the Kubeshark that targets. The alternative would be to wait for Hub to be ready and then query it for the pods it listens to, this has the arguably worse drawback of taking a relatively very long time before the user sees which pods are targeted, if any. */ func printTargetedPodsPreview(ctx context.Context, kubernetesProvider *kubernetes.Provider, namespaces []string) error { if matchingPods, err := kubernetesProvider.ListAllRunningPodsMatchingRegex(ctx, config.Config.Tap.PodRegex(), namespaces); err != nil { return err } else { if len(matchingPods) == 0 { printNoPodsFoundSuggestion(namespaces) } for _, targetedPod := range matchingPods { log.Info().Msg(fmt.Sprintf("Targeted pod: %s", fmt.Sprintf(utils.Green, targetedPod.Name))) } return nil } } func printNoPodsFoundSuggestion(targetNamespaces []string) { var suggestionStr string if !utils.Contains(targetNamespaces, kubernetes.K8sAllNamespaces) { suggestionStr = ". You can also try selecting a different namespace with -n or target all namespaces with -A" } log.Warn().Msg(fmt.Sprintf("Did not find any currently running pods that match the regex argument, %s will automatically target matching pods if any are created later%s", misc.Software, suggestionStr)) } func watchHubPod(ctx context.Context, kubernetesProvider *kubernetes.Provider, cancel context.CancelFunc) { podExactRegex := regexp.MustCompile(fmt.Sprintf("^%s", kubernetes.HubPodName)) podWatchHelper := kubernetes.NewPodWatchHelper(kubernetesProvider, podExactRegex) eventChan, errorChan := kubernetes.FilteredWatch(ctx, podWatchHelper, []string{config.Config.Tap.Release.Namespace}, podWatchHelper) isPodReady := false timeAfter := time.After(120 * time.Second) for { select { case wEvent, ok := <-eventChan: if !ok { eventChan = nil continue } switch wEvent.Type { case kubernetes.EventAdded: log.Info().Str("pod", kubernetes.HubPodName).Msg("Added:") case kubernetes.EventDeleted: log.Info().Str("pod", kubernetes.HubPodName).Msg("Removed:") cancel() return case kubernetes.EventModified: modifiedPod, err := wEvent.ToPod() if err != nil { log.Error().Str("pod", kubernetes.HubPodName).Err(err).Msg("While watching pod.") cancel() continue } log.Debug(). Str("pod", kubernetes.HubPodName). Interface("phase", modifiedPod.Status.Phase). Interface("containers-statuses", modifiedPod.Status.ContainerStatuses). Msg("Watching pod.") if modifiedPod.Status.Phase == core.PodRunning && !isPodReady { isPodReady = true ready.Lock() ready.Hub = true ready.Unlock() log.Info().Str("pod", kubernetes.HubPodName).Msg("Ready.") } ready.Lock() proxyDone := ready.Proxy hubPodReady := ready.Hub frontPodReady := ready.Front ready.Unlock() if !proxyDone && hubPodReady && frontPodReady { ready.Lock() ready.Proxy = true ready.Unlock() postFrontStarted(ctx, kubernetesProvider, cancel) } case kubernetes.EventBookmark: break case kubernetes.EventError: break } case err, ok := <-errorChan: if !ok { errorChan = nil continue } log.Error(). Str("pod", kubernetes.HubPodName). Str("namespace", config.Config.Tap.Release.Namespace). Err(err). Msg("Failed creating pod.") cancel() case <-timeAfter: if !isPodReady { log.Error(). Str("pod", kubernetes.HubPodName). Msg("Pod was not ready in time.") cancel() } case <-ctx.Done(): log.Debug(). Str("pod", kubernetes.HubPodName). Msg("Watching pod, context done.") return } } } func watchFrontPod(ctx context.Context, kubernetesProvider *kubernetes.Provider, cancel context.CancelFunc) { podExactRegex := regexp.MustCompile(fmt.Sprintf("^%s", kubernetes.FrontPodName)) podWatchHelper := kubernetes.NewPodWatchHelper(kubernetesProvider, podExactRegex) eventChan, errorChan := kubernetes.FilteredWatch(ctx, podWatchHelper, []string{config.Config.Tap.Release.Namespace}, podWatchHelper) isPodReady := false timeAfter := time.After(120 * time.Second) for { select { case wEvent, ok := <-eventChan: if !ok { eventChan = nil continue } switch wEvent.Type { case kubernetes.EventAdded: log.Info().Str("pod", kubernetes.FrontPodName).Msg("Added:") case kubernetes.EventDeleted: log.Info().Str("pod", kubernetes.FrontPodName).Msg("Removed:") cancel() return case kubernetes.EventModified: modifiedPod, err := wEvent.ToPod() if err != nil { log.Error().Str("pod", kubernetes.FrontPodName).Err(err).Msg("While watching pod.") cancel() continue } log.Debug(). Str("pod", kubernetes.FrontPodName). Interface("phase", modifiedPod.Status.Phase). Interface("containers-statuses", modifiedPod.Status.ContainerStatuses). Msg("Watching pod.") if modifiedPod.Status.Phase == core.PodRunning && !isPodReady { isPodReady = true ready.Lock() ready.Front = true ready.Unlock() log.Info().Str("pod", kubernetes.FrontPodName).Msg("Ready.") } ready.Lock() proxyDone := ready.Proxy hubPodReady := ready.Hub frontPodReady := ready.Front ready.Unlock() if !proxyDone && hubPodReady && frontPodReady { ready.Lock() ready.Proxy = true ready.Unlock() postFrontStarted(ctx, kubernetesProvider, cancel) } case kubernetes.EventBookmark: break case kubernetes.EventError: break } case err, ok := <-errorChan: if !ok { errorChan = nil continue } log.Error(). Str("pod", kubernetes.FrontPodName). Str("namespace", config.Config.Tap.Release.Namespace). Err(err). Msg("Failed creating pod.") case <-timeAfter: if !isPodReady { log.Error(). Str("pod", kubernetes.FrontPodName). Msg("Pod was not ready in time.") cancel() } case <-ctx.Done(): log.Debug(). Str("pod", kubernetes.FrontPodName). Msg("Watching pod, context done.") return } } } func watchHubEvents(ctx context.Context, kubernetesProvider *kubernetes.Provider, cancel context.CancelFunc) { podExactRegex := regexp.MustCompile(fmt.Sprintf("^%s", kubernetes.HubPodName)) eventWatchHelper := kubernetes.NewEventWatchHelper(kubernetesProvider, podExactRegex, "pod") eventChan, errorChan := kubernetes.FilteredWatch(ctx, eventWatchHelper, []string{config.Config.Tap.Release.Namespace}, eventWatchHelper) for { select { case wEvent, ok := <-eventChan: if !ok { eventChan = nil continue } event, err := wEvent.ToEvent() if err != nil { log.Error(). Str("pod", kubernetes.HubPodName). Err(err). Msg("Parsing resource event.") continue } if state.startTime.After(event.CreationTimestamp.Time) { continue } log.Debug(). Str("pod", kubernetes.HubPodName). Str("event", event.Name). Time("time", event.CreationTimestamp.Time). Str("name", event.Regarding.Name). Str("kind", event.Regarding.Kind). Str("reason", event.Reason). Str("note", event.Note). Msg("Watching events.") switch event.Reason { case "FailedScheduling", "Failed": log.Error(). Str("pod", kubernetes.HubPodName). Str("event", event.Name). Time("time", event.CreationTimestamp.Time). Str("name", event.Regarding.Name). Str("kind", event.Regarding.Kind). Str("reason", event.Reason). Str("note", event.Note). Msg("Watching events.") cancel() } case err, ok := <-errorChan: if !ok { errorChan = nil continue } log.Error(). Str("pod", kubernetes.HubPodName). Err(err). Msg("While watching events.") case <-ctx.Done(): log.Debug(). Str("pod", kubernetes.HubPodName). Msg("Watching pod events, context done.") return } } } func postFrontStarted(ctx context.Context, kubernetesProvider *kubernetes.Provider, cancel context.CancelFunc) { startProxyReportErrorIfAny( kubernetesProvider, ctx, kubernetes.FrontServiceName, kubernetes.FrontPodName, configStructs.ProxyFrontPortLabel, config.Config.Tap.Proxy.Front.Port, configStructs.ContainerPort, "", ) var url string if config.Config.Tap.Ingress.Enabled { url = fmt.Sprintf("http://%s", config.Config.Tap.Ingress.Host) } else { url = kubernetes.GetProxyOnPort(config.Config.Tap.Proxy.Front.Port) } log.Info().Str("url", url).Msg(fmt.Sprintf(utils.Green, fmt.Sprintf("%s is available at:", misc.Software))) if !config.Config.HeadlessMode { utils.OpenBrowser(url) } for !ready.Hub { time.Sleep(100 * time.Millisecond) } if (config.Config.Scripting.Source != "" || len(config.Config.Scripting.Sources) > 0) && config.Config.Scripting.WatchScripts { watchScripts(ctx, kubernetesProvider, false) } if config.Config.Scripting.Console { go runConsoleWithoutProxy() } } func updateConfig(kubernetesProvider *kubernetes.Provider) { _, _ = kubernetes.SetSecret(kubernetesProvider, kubernetes.SECRET_LICENSE, config.Config.License) _, _ = kubernetes.SetConfig(kubernetesProvider, kubernetes.CONFIG_POD_REGEX, config.Config.Tap.PodRegexStr) _, _ = kubernetes.SetConfig(kubernetesProvider, kubernetes.CONFIG_NAMESPACES, strings.Join(config.Config.Tap.Namespaces, ",")) _, _ = kubernetes.SetConfig(kubernetesProvider, kubernetes.CONFIG_EXCLUDED_NAMESPACES, strings.Join(config.Config.Tap.ExcludedNamespaces, ",")) data, err := json.Marshal(config.Config.Scripting.Env) if err != nil { log.Error().Str("config", kubernetes.CONFIG_SCRIPTING_ENV).Err(err).Send() return } else { _, _ = kubernetes.SetConfig(kubernetesProvider, kubernetes.CONFIG_SCRIPTING_ENV, string(data)) } ingressEnabled := "" if config.Config.Tap.Ingress.Enabled { ingressEnabled = "true" } authEnabled := "" if config.Config.Tap.Auth.Enabled { authEnabled = "true" } _, _ = kubernetes.SetConfig(kubernetesProvider, kubernetes.CONFIG_INGRESS_ENABLED, ingressEnabled) _, _ = kubernetes.SetConfig(kubernetesProvider, kubernetes.CONFIG_INGRESS_HOST, config.Config.Tap.Ingress.Host) _, _ = kubernetes.SetConfig(kubernetesProvider, kubernetes.CONFIG_PROXY_FRONT_PORT, fmt.Sprint(config.Config.Tap.Proxy.Front.Port)) _, _ = kubernetes.SetConfig(kubernetesProvider, kubernetes.CONFIG_AUTH_ENABLED, authEnabled) _, _ = kubernetes.SetConfig(kubernetesProvider, kubernetes.CONFIG_AUTH_TYPE, config.Config.Tap.Auth.Type) _, _ = kubernetes.SetConfig(kubernetesProvider, kubernetes.CONFIG_AUTH_SAML_IDP_METADATA_URL, config.Config.Tap.Auth.Saml.IdpMetadataUrl) } 07070100000024000081A4000000000000000000000001673DBE28000002C2000000000000000000000000000000000000002500000000kubeshark-cli-52.3.90/cmd/version.gopackage cmd import ( "fmt" "strconv" "time" "github.com/kubeshark/kubeshark/config" "github.com/kubeshark/kubeshark/misc" "github.com/rs/zerolog/log" "github.com/spf13/cobra" ) var versionCmd = &cobra.Command{ Use: "version", Short: "Print version info", RunE: func(cmd *cobra.Command, args []string) error { timeStampInt, _ := strconv.ParseInt(misc.BuildTimestamp, 10, 0) if config.DebugMode { log.Info(). Str("version", misc.Ver). Str("branch", misc.Branch). Str("commit-hash", misc.GitCommitHash). Time("build-time", time.Unix(timeStampInt, 0)). Send() } else { fmt.Println(misc.Ver) } return nil }, } func init() { rootCmd.AddCommand(versionCmd) } 07070100000025000081A4000000000000000000000001673DBE2800000074000000000000000000000000000000000000002200000000kubeshark-cli-52.3.90/codecov.ymlcoverage: status: project: default: threshold: 1% patch: default: enabled: no 07070100000026000041ED000000000000000000000002673DBE2800000000000000000000000000000000000000000000001D00000000kubeshark-cli-52.3.90/config07070100000027000081A4000000000000000000000001673DBE2800002A1A000000000000000000000000000000000000002700000000kubeshark-cli-52.3.90/config/config.gopackage config import ( "errors" "fmt" "io" "os" "path" "path/filepath" "reflect" "strconv" "strings" "github.com/creasty/defaults" "github.com/goccy/go-yaml" "github.com/kubeshark/kubeshark/misc" "github.com/kubeshark/kubeshark/misc/version" "github.com/kubeshark/kubeshark/utils" "github.com/rs/zerolog" "github.com/rs/zerolog/log" "github.com/spf13/cobra" "github.com/spf13/pflag" ) const ( Separator = "=" SetCommandName = "set" FieldNameTag = "yaml" ReadonlyTag = "readonly" DebugFlag = "debug" ) var ( Config ConfigStruct DebugMode bool cmdName string ConfigFilePath string ) func InitConfig(cmd *cobra.Command) error { var err error DebugMode, err = cmd.Flags().GetBool(DebugFlag) if err != nil { log.Error().Err(err).Msg(fmt.Sprintf("Can't receive '%s' flag", DebugFlag)) } if DebugMode { zerolog.SetGlobalLevel(zerolog.DebugLevel) } if cmd.Use == "version" { return nil } if !utils.Contains([]string{ "console", "pro", "manifests", "license", }, cmd.Use) { go version.CheckNewerVersion() } Config = CreateDefaultConfig() Config.Tap.Debug = DebugMode cmdName = cmd.Name() if utils.Contains([]string{ "clean", "console", "pro", "proxy", "scripts", "pprof", }, cmdName) { cmdName = "tap" } if err := defaults.Set(&Config); err != nil { return err } ConfigFilePath = path.Join(misc.GetDotFolderPath(), "config.yaml") if err := loadConfigFile(&Config, utils.Contains([]string{ "manifests", "license", }, cmd.Use)); err != nil { if !os.IsNotExist(err) { return fmt.Errorf("invalid config, %w\n"+ "you can regenerate the file by removing it (%v) and using `kubeshark config -r`", err, ConfigFilePath) } } cmd.Flags().Visit(initFlag) log.Debug().Interface("config", Config).Msg("Init config is finished.") return nil } func GetConfigWithDefaults() (*ConfigStruct, error) { defaultConf := ConfigStruct{} if err := defaults.Set(&defaultConf); err != nil { return nil, err } configElem := reflect.ValueOf(&defaultConf).Elem() setZeroForReadonlyFields(configElem) return &defaultConf, nil } func WriteConfig(config *ConfigStruct) error { template, err := utils.PrettyYaml(config) if err != nil { return fmt.Errorf("failed converting config to yaml, err: %v", err) } data := []byte(template) if _, err := os.Stat(ConfigFilePath); os.IsNotExist(err) { err = os.MkdirAll(filepath.Dir(ConfigFilePath), 0700) if err != nil { return fmt.Errorf("failed creating directories, err: %v", err) } } if err := os.WriteFile(ConfigFilePath, data, 0644); err != nil { return fmt.Errorf("failed writing config, err: %v", err) } return nil } func loadConfigFile(config *ConfigStruct, silent bool) error { cwd, err := os.Getwd() if err != nil { return err } cwdConfig := filepath.Join(cwd, fmt.Sprintf("%s.yaml", misc.Program)) reader, err := os.Open(cwdConfig) if err != nil { reader, err = os.Open(ConfigFilePath) if err != nil { return err } } else { ConfigFilePath = cwdConfig } defer reader.Close() buf, err := io.ReadAll(reader) if err != nil { return err } if err := yaml.Unmarshal(buf, config); err != nil { return err } if !silent { log.Info().Str("path", ConfigFilePath).Msg("Found config file!") } return nil } func initFlag(f *pflag.Flag) { configElemValue := reflect.ValueOf(&Config).Elem() var flagPath []string flagPath = append(flagPath, cmdName) flagPath = append(flagPath, strings.Split(f.Name, "-")...) sliceValue, isSliceValue := f.Value.(pflag.SliceValue) if !isSliceValue { if err := mergeFlagValue(configElemValue, flagPath, strings.Join(flagPath, "."), f.Value.String()); err != nil { log.Warn().Err(err).Send() } return } if f.Name == SetCommandName { if err := mergeSetFlag(configElemValue, sliceValue.GetSlice()); err != nil { log.Warn().Err(err).Send() } return } if err := mergeFlagValues(configElemValue, flagPath, strings.Join(flagPath, "."), sliceValue.GetSlice()); err != nil { log.Warn().Err(err).Send() } } func mergeSetFlag(configElemValue reflect.Value, setValues []string) error { var setErrors []string setMap := map[string][]string{} for _, setValue := range setValues { if !strings.Contains(setValue, Separator) { setErrors = append(setErrors, fmt.Sprintf("Ignoring set argument %s (set argument format: <flag name>=<flag value>)", setValue)) continue } split := strings.SplitN(setValue, Separator, 2) argumentKey, argumentValue := split[0], split[1] setMap[argumentKey] = append(setMap[argumentKey], argumentValue) } for argumentKey, argumentValues := range setMap { flagPath := strings.Split(argumentKey, ".") if len(argumentValues) > 1 { if err := mergeFlagValues(configElemValue, flagPath, argumentKey, argumentValues); err != nil { setErrors = append(setErrors, fmt.Sprintf("%v", err)) } } else { if err := mergeFlagValue(configElemValue, flagPath, argumentKey, argumentValues[0]); err != nil { setErrors = append(setErrors, fmt.Sprintf("%v", err)) } } } if len(setErrors) > 0 { return errors.New(strings.Join(setErrors, "\n")) } return nil } func mergeFlagValue(configElemValue reflect.Value, flagPath []string, fullFlagName string, flagValue string) error { mergeFunction := func(flagName string, currentFieldStruct reflect.StructField, currentFieldElemValue reflect.Value, currentElemValue reflect.Value) error { currentFieldKind := currentFieldStruct.Type.Kind() if currentFieldKind == reflect.Slice { return mergeFlagValues(currentElemValue, []string{flagName}, fullFlagName, []string{flagValue}) } parsedValue, err := getParsedValue(currentFieldKind, flagValue) if err != nil { return fmt.Errorf("invalid value %s for flag name %s, expected %s", flagValue, flagName, currentFieldKind) } currentFieldElemValue.Set(parsedValue) return nil } return mergeFlag(configElemValue, flagPath, fullFlagName, mergeFunction) } func mergeFlagValues(configElemValue reflect.Value, flagPath []string, fullFlagName string, flagValues []string) error { mergeFunction := func(flagName string, currentFieldStruct reflect.StructField, currentFieldElemValue reflect.Value, currentElemValue reflect.Value) error { currentFieldKind := currentFieldStruct.Type.Kind() if currentFieldKind != reflect.Slice { return fmt.Errorf("invalid values %s for flag name %s, expected %s", strings.Join(flagValues, ","), flagName, currentFieldKind) } flagValueKind := currentFieldStruct.Type.Elem().Kind() parsedValues := reflect.MakeSlice(reflect.SliceOf(currentFieldStruct.Type.Elem()), 0, 0) for _, flagValue := range flagValues { parsedValue, err := getParsedValue(flagValueKind, flagValue) if err != nil { return fmt.Errorf("invalid value %s for flag name %s, expected %s", flagValue, flagName, flagValueKind) } parsedValues = reflect.Append(parsedValues, parsedValue) } currentFieldElemValue.Set(parsedValues) return nil } return mergeFlag(configElemValue, flagPath, fullFlagName, mergeFunction) } func mergeFlag(currentElemValue reflect.Value, currentFlagPath []string, fullFlagName string, mergeFunction func(flagName string, currentFieldStruct reflect.StructField, currentFieldElemValue reflect.Value, currentElemValue reflect.Value) error) error { if len(currentFlagPath) == 0 { return fmt.Errorf("flag \"%s\" not found", fullFlagName) } for i := 0; i < currentElemValue.NumField(); i++ { currentFieldStruct := currentElemValue.Type().Field(i) currentFieldElemValue := currentElemValue.FieldByName(currentFieldStruct.Name) if currentFieldStruct.Type.Kind() == reflect.Struct && getFieldNameByTag(currentFieldStruct) == currentFlagPath[0] { return mergeFlag(currentFieldElemValue, currentFlagPath[1:], fullFlagName, mergeFunction) } if len(currentFlagPath) > 1 || getFieldNameByTag(currentFieldStruct) != currentFlagPath[0] { continue } return mergeFunction(currentFlagPath[0], currentFieldStruct, currentFieldElemValue, currentElemValue) } return fmt.Errorf("flag \"%s\" not found", fullFlagName) } func getFieldNameByTag(field reflect.StructField) string { return strings.Split(field.Tag.Get(FieldNameTag), ",")[0] } func getParsedValue(kind reflect.Kind, value string) (reflect.Value, error) { switch kind { case reflect.String: return reflect.ValueOf(value), nil case reflect.Bool: boolArgumentValue, err := strconv.ParseBool(value) if err != nil { break } return reflect.ValueOf(boolArgumentValue), nil case reflect.Int: intArgumentValue, err := strconv.ParseInt(value, 10, 64) if err != nil { break } return reflect.ValueOf(int(intArgumentValue)), nil case reflect.Int8: intArgumentValue, err := strconv.ParseInt(value, 10, 8) if err != nil { break } return reflect.ValueOf(int8(intArgumentValue)), nil case reflect.Int16: intArgumentValue, err := strconv.ParseInt(value, 10, 16) if err != nil { break } return reflect.ValueOf(int16(intArgumentValue)), nil case reflect.Int32: intArgumentValue, err := strconv.ParseInt(value, 10, 32) if err != nil { break } return reflect.ValueOf(int32(intArgumentValue)), nil case reflect.Int64: intArgumentValue, err := strconv.ParseInt(value, 10, 64) if err != nil { break } return reflect.ValueOf(intArgumentValue), nil case reflect.Uint: uintArgumentValue, err := strconv.ParseUint(value, 10, 64) if err != nil { break } return reflect.ValueOf(uint(uintArgumentValue)), nil case reflect.Uint8: uintArgumentValue, err := strconv.ParseUint(value, 10, 8) if err != nil { break } return reflect.ValueOf(uint8(uintArgumentValue)), nil case reflect.Uint16: uintArgumentValue, err := strconv.ParseUint(value, 10, 16) if err != nil { break } return reflect.ValueOf(uint16(uintArgumentValue)), nil case reflect.Uint32: uintArgumentValue, err := strconv.ParseUint(value, 10, 32) if err != nil { break } return reflect.ValueOf(uint32(uintArgumentValue)), nil case reflect.Uint64: uintArgumentValue, err := strconv.ParseUint(value, 10, 64) if err != nil { break } return reflect.ValueOf(uintArgumentValue), nil } return reflect.ValueOf(nil), errors.New("value to parse does not match type") } func setZeroForReadonlyFields(currentElem reflect.Value) { for i := 0; i < currentElem.NumField(); i++ { currentField := currentElem.Type().Field(i) currentFieldByName := currentElem.FieldByName(currentField.Name) if currentField.Type.Kind() == reflect.Struct { setZeroForReadonlyFields(currentFieldByName) continue } if _, ok := currentField.Tag.Lookup(ReadonlyTag); ok { currentFieldByName.Set(reflect.Zero(currentField.Type)) } } } 07070100000028000081A4000000000000000000000001673DBE28000012F7000000000000000000000000000000000000002D00000000kubeshark-cli-52.3.90/config/configStruct.gopackage config import ( "os" "path/filepath" "github.com/kubeshark/kubeshark/config/configStructs" v1 "k8s.io/api/core/v1" "k8s.io/client-go/util/homedir" ) const ( KubeConfigPathConfigName = "kube-configPath" ) func CreateDefaultConfig() ConfigStruct { return ConfigStruct{ Tap: configStructs.TapConfig{ NodeSelectorTerms: []v1.NodeSelectorTerm{ { MatchExpressions: []v1.NodeSelectorRequirement{ { Key: "kubernetes.io/os", Operator: v1.NodeSelectorOpIn, Values: []string{"linux"}, }, }, }, }, Capabilities: configStructs.CapabilitiesConfig{ NetworkCapture: []string{ // NET_RAW is required to listen the network traffic "NET_RAW", // NET_ADMIN is required to listen the network traffic "NET_ADMIN", }, ServiceMeshCapture: []string{ // SYS_ADMIN is required to read /proc/PID/net/ns + to install eBPF programs (kernel < 5.8) "SYS_ADMIN", // SYS_PTRACE is required to set netns to other process + to open libssl.so of other process "SYS_PTRACE", // DAC_OVERRIDE is required to read /proc/PID/environ "DAC_OVERRIDE", }, EBPFCapture: []string{ // SYS_ADMIN is required to read /proc/PID/net/ns + to install eBPF programs (kernel < 5.8) "SYS_ADMIN", // SYS_PTRACE is required to set netns to other process + to open libssl.so of other process "SYS_PTRACE", // SYS_RESOURCE is required to change rlimits for eBPF "SYS_RESOURCE", // IPC_LOCK is required for ebpf perf buffers allocations after some amount of size buffer size: // https://github.com/kubeshark/tracer/blob/13e24725ba8b98216dd0e553262e6d9c56dce5fa/main.go#L82) "IPC_LOCK", }, }, Auth: configStructs.AuthConfig{ Saml: configStructs.SamlConfig{ RoleAttribute: "role", Roles: map[string]configStructs.Role{ "admin": { Filter: "", CanDownloadPCAP: true, CanUseScripting: true, CanUpdateTargetedPods: true, CanStopTrafficCapturing: true, ShowAdminConsoleLink: true, }, }, }, }, EnabledDissectors: []string{ "amqp", "dns", "http", "icmp", "kafka", "redis", "sctp", "syscall", // "tcp", // "udp", "ws", "tls", }, }, } } type KubeConfig struct { ConfigPathStr string `yaml:"configPath" json:"configPath"` Context string `yaml:"context" json:"context"` } type ManifestsConfig struct { Dump bool `yaml:"dump" json:"dump"` } type ConfigStruct struct { Tap configStructs.TapConfig `yaml:"tap" json:"tap"` Logs configStructs.LogsConfig `yaml:"logs" json:"logs"` Config configStructs.ConfigConfig `yaml:"config,omitempty" json:"config,omitempty"` PcapDump configStructs.PcapDumpConfig `yaml:"pcapdump" json:"pcapdump"` Kube KubeConfig `yaml:"kube" json:"kube"` DumpLogs bool `yaml:"dumpLogs" json:"dumpLogs" default:"false"` HeadlessMode bool `yaml:"headless" json:"headless" default:"false"` License string `yaml:"license" json:"license" default:""` CloudLicenseEnabled bool `yaml:"cloudLicenseEnabled" json:"cloudLicenseEnabled" default:"true"` SupportChatEnabled bool `yaml:"supportChatEnabled" json:"supportChatEnabled" default:"true"` InternetConnectivity bool `yaml:"internetConnectivity" json:"internetConnectivity" default:"true"` DissectorsUpdatingEnabled bool `yaml:"dissectorsUpdatingEnabled" json:"dissectorsUpdatingEnabled" default:"true"` Scripting configStructs.ScriptingConfig `yaml:"scripting" json:"scripting"` Manifests ManifestsConfig `yaml:"manifests,omitempty" json:"manifests,omitempty"` Timezone string `yaml:"timezone" json:"timezone"` } func (config *ConfigStruct) ImagePullPolicy() v1.PullPolicy { return v1.PullPolicy(config.Tap.Docker.ImagePullPolicy) } func (config *ConfigStruct) ImagePullSecrets() []v1.LocalObjectReference { var ref []v1.LocalObjectReference for _, name := range config.Tap.Docker.ImagePullSecrets { ref = append(ref, v1.LocalObjectReference{Name: name}) } return ref } func (config *ConfigStruct) KubeConfigPath() string { if config.Kube.ConfigPathStr != "" { return config.Kube.ConfigPathStr } envKubeConfigPath := os.Getenv("KUBECONFIG") if envKubeConfigPath != "" { return envKubeConfigPath } home := homedir.HomeDir() return filepath.Join(home, ".kube", "config") } 07070100000029000041ED000000000000000000000002673DBE2800000000000000000000000000000000000000000000002B00000000kubeshark-cli-52.3.90/config/configStructs0707010000002A000081A4000000000000000000000001673DBE28000000CB000000000000000000000000000000000000003B00000000kubeshark-cli-52.3.90/config/configStructs/configConfig.gopackage configStructs const ( RegenerateConfigName = "regenerate" ) type ConfigConfig struct { Regenerate bool `yaml:"regenerate,omitempty" json:"regenerate,omitempty" default:"false" readonly:""` } 0707010000002B000081A4000000000000000000000001673DBE28000002C4000000000000000000000000000000000000003900000000kubeshark-cli-52.3.90/config/configStructs/logsConfig.gopackage configStructs import ( "fmt" "os" "path" "github.com/kubeshark/kubeshark/misc" ) const ( FileLogsName = "file" GrepLogsName = "grep" ) type LogsConfig struct { FileStr string `yaml:"file" json:"file"` Grep string `yaml:"grep" json:"grep"` } func (config *LogsConfig) Validate() error { if config.FileStr == "" { _, err := os.Getwd() if err != nil { return fmt.Errorf("failed to get PWD, %v (try using `%s logs -f <full path dest zip file>)`", err, misc.Program) } } return nil } func (config *LogsConfig) FilePath() string { if config.FileStr == "" { pwd, _ := os.Getwd() return path.Join(pwd, fmt.Sprintf("%s_logs.zip", misc.Program)) } return config.FileStr } 0707010000002C000081A4000000000000000000000001673DBE28000009F1000000000000000000000000000000000000003E00000000kubeshark-cli-52.3.90/config/configStructs/scriptingConfig.gopackage configStructs import ( "fmt" "io/fs" "os" "path/filepath" "strings" "github.com/kubeshark/kubeshark/misc" "github.com/rs/zerolog/log" ) type ScriptingConfig struct { Env map[string]interface{} `yaml:"env" json:"env" default:"{}"` Source string `yaml:"source" json:"source" default:""` Sources []string `yaml:"sources" json:"sources" default:"[]"` WatchScripts bool `yaml:"watchScripts" json:"watchScripts" default:"true"` Active []string `yaml:"active" json:"active" default:"[]"` Console bool `yaml:"console" json:"console" default:"true"` } func (config *ScriptingConfig) GetScripts() (scripts []*misc.Script, err error) { // Check if both Source and Sources are empty if config.Source == "" && len(config.Sources) == 0 { return nil, nil } var allFiles []struct { Source string File fs.DirEntry } // Handle single Source directory if config.Source != "" { files, err := os.ReadDir(config.Source) if err != nil { return nil, fmt.Errorf("failed to read directory %s: %v", config.Source, err) } for _, file := range files { allFiles = append(allFiles, struct { Source string File fs.DirEntry }{Source: config.Source, File: file}) } } // Handle multiple Sources directories if len(config.Sources) > 0 { for _, source := range config.Sources { files, err := os.ReadDir(source) if err != nil { return nil, fmt.Errorf("failed to read directory %s: %v", source, err) } for _, file := range files { allFiles = append(allFiles, struct { Source string File fs.DirEntry }{Source: source, File: file}) } } } // Iterate over all collected files for _, f := range allFiles { if f.File.IsDir() { continue } // Construct the full path based on the relevant source directory path := filepath.Join(f.Source, f.File.Name()) if !strings.HasSuffix(f.File.Name(), ".js") { // Use file name suffix for skipping non-JS files log.Info().Str("path", path).Msg("Skipping non-JS file") continue } // Read the script file var script *misc.Script script, err = misc.ReadScriptFile(path) if err != nil { return nil, fmt.Errorf("failed to read script file %s: %v", path, err) } // Append the valid script to the scripts slice scripts = append(scripts, script) log.Debug().Str("path", path).Msg("Found script:") } // Return the collected scripts and nil error if successful return scripts, nil } 0707010000002D000081A4000000000000000000000001673DBE28000033C4000000000000000000000000000000000000003800000000kubeshark-cli-52.3.90/config/configStructs/tapConfig.gopackage configStructs import ( "fmt" "regexp" v1 "k8s.io/api/core/v1" networking "k8s.io/api/networking/v1" ) const ( DockerRegistryLabel = "docker-registry" DockerTagLabel = "docker-tag" DockerImagePullPolicy = "docker-imagePullPolicy" DockerImagePullSecrets = "docker-imagePullSecrets" ProxyFrontPortLabel = "proxy-front-port" ProxyHubPortLabel = "proxy-hub-port" ProxyHostLabel = "proxy-host" NamespacesLabel = "namespaces" ExcludedNamespacesLabel = "excludedNamespaces" ReleaseNamespaceLabel = "release-namespace" PersistentStorageLabel = "persistentStorage" PersistentStorageStaticLabel = "persistentStorageStatic" EfsFileSytemIdAndPathLabel = "efsFileSytemIdAndPath" StorageLimitLabel = "storageLimit" StorageClassLabel = "storageClass" DryRunLabel = "dryRun" PcapLabel = "pcap" ServiceMeshLabel = "serviceMesh" TlsLabel = "tls" IgnoreTaintedLabel = "ignoreTainted" IngressEnabledLabel = "ingress-enabled" TelemetryEnabledLabel = "telemetry-enabled" ResourceGuardEnabledLabel = "resource-guard-enabled" PprofPortLabel = "pprof-port" PprofViewLabel = "pprof-view" DebugLabel = "debug" ContainerPort = 8080 ContainerPortStr = "8080" PcapDest = "dest" PcapMaxSize = "maxSize" PcapMaxTime = "maxTime" PcapTimeInterval = "timeInterval" PcapKubeconfig = "kubeconfig" PcapDumpEnabled = "enabled" ) type ResourceLimitsHub struct { CPU string `yaml:"cpu" json:"cpu" default:"0"` Memory string `yaml:"memory" json:"memory" default:"5Gi"` } type ResourceLimitsWorker struct { CPU string `yaml:"cpu" json:"cpu" default:"0"` Memory string `yaml:"memory" json:"memory" default:"3Gi"` } type ResourceRequests struct { CPU string `yaml:"cpu" json:"cpu" default:"50m"` Memory string `yaml:"memory" json:"memory" default:"50Mi"` } type ResourceRequirementsHub struct { Limits ResourceLimitsHub `yaml:"limits" json:"limits"` Requests ResourceRequests `yaml:"requests" json:"requests"` } type ResourceRequirementsWorker struct { Limits ResourceLimitsHub `yaml:"limits" json:"limits"` Requests ResourceRequests `yaml:"requests" json:"requests"` } type WorkerConfig struct { SrvPort uint16 `yaml:"srvPort" json:"srvPort" default:"30001"` } type HubConfig struct { SrvPort uint16 `yaml:"srvPort" json:"srvPort" default:"8898"` } type FrontConfig struct { Port uint16 `yaml:"port" json:"port" default:"8899"` } type ProxyConfig struct { Worker WorkerConfig `yaml:"worker" json:"worker"` Hub HubConfig `yaml:"hub" json:"hub"` Front FrontConfig `yaml:"front" json:"front"` Host string `yaml:"host" json:"host" default:"127.0.0.1"` } type OverrideImageConfig struct { Worker string `yaml:"worker" json:"worker"` Hub string `yaml:"hub" json:"hub"` Front string `yaml:"front" json:"front"` } type OverrideTagConfig struct { Worker string `yaml:"worker" json:"worker"` Hub string `yaml:"hub" json:"hub"` Front string `yaml:"front" json:"front"` } type DockerConfig struct { Registry string `yaml:"registry" json:"registry" default:"docker.io/kubeshark"` Tag string `yaml:"tag" json:"tag" default:""` TagLocked bool `yaml:"tagLocked" json:"tagLocked" default:"true"` ImagePullPolicy string `yaml:"imagePullPolicy" json:"imagePullPolicy" default:"Always"` ImagePullSecrets []string `yaml:"imagePullSecrets" json:"imagePullSecrets"` OverrideImage OverrideImageConfig `yaml:"overrideImage" json:"overrideImage"` OverrideTag OverrideTagConfig `yaml:"overrideTag" json:"overrideTag"` } type ResourcesConfig struct { Hub ResourceRequirementsHub `yaml:"hub" json:"hub"` Sniffer ResourceRequirementsWorker `yaml:"sniffer" json:"sniffer"` Tracer ResourceRequirementsWorker `yaml:"tracer" json:"tracer"` } type Role struct { Filter string `yaml:"filter" json:"filter" default:""` CanDownloadPCAP bool `yaml:"canDownloadPCAP" json:"canDownloadPCAP" default:"false"` CanUseScripting bool `yaml:"canUseScripting" json:"canUseScripting" default:"false"` CanUpdateTargetedPods bool `yaml:"canUpdateTargetedPods" json:"canUpdateTargetedPods" default:"false"` CanStopTrafficCapturing bool `yaml:"canStopTrafficCapturing" json:"canStopTrafficCapturing" default:"false"` ShowAdminConsoleLink bool `yaml:"showAdminConsoleLink" json:"showAdminConsoleLink" default:"false"` } type SamlConfig struct { IdpMetadataUrl string `yaml:"idpMetadataUrl" json:"idpMetadataUrl"` X509crt string `yaml:"x509crt" json:"x509crt"` X509key string `yaml:"x509key" json:"x509key"` RoleAttribute string `yaml:"roleAttribute" json:"roleAttribute"` Roles map[string]Role `yaml:"roles" json:"roles"` } type AuthConfig struct { Enabled bool `yaml:"enabled" json:"enabled" default:"false"` Type string `yaml:"type" json:"type" default:"saml"` Saml SamlConfig `yaml:"saml" json:"saml"` } type IngressConfig struct { Enabled bool `yaml:"enabled" json:"enabled" default:"false"` ClassName string `yaml:"className" json:"className" default:""` Host string `yaml:"host" json:"host" default:"ks.svc.cluster.local"` TLS []networking.IngressTLS `yaml:"tls" json:"tls" default:"[]"` Annotations map[string]string `yaml:"annotations" json:"annotations" default:"{}"` } type ReleaseConfig struct { Repo string `yaml:"repo" json:"repo" default:"https://helm.kubeshark.co"` Name string `yaml:"name" json:"name" default:"kubeshark"` Namespace string `yaml:"namespace" json:"namespace" default:"default"` } type TelemetryConfig struct { Enabled bool `yaml:"enabled" json:"enabled" default:"true"` } type ResourceGuardConfig struct { Enabled bool `yaml:"enabled" json:"enabled" default:"false"` } type SentryConfig struct { Enabled bool `yaml:"enabled" json:"enabled" default:"false"` Environment string `yaml:"environment" json:"environment" default:"production"` } type CapabilitiesConfig struct { NetworkCapture []string `yaml:"networkCapture" json:"networkCapture" default:"[]"` ServiceMeshCapture []string `yaml:"serviceMeshCapture" json:"serviceMeshCapture" default:"[]"` EBPFCapture []string `yaml:"ebpfCapture" json:"ebpfCapture" default:"[]"` } type MetricsConfig struct { Port uint16 `yaml:"port" json:"port" default:"49100"` } type PprofConfig struct { Enabled bool `yaml:"enabled" json:"enabled" default:"false"` Port uint16 `yaml:"port" json:"port" default:"8000"` View string `yaml:"view" json:"view" default:"flamegraph"` } type MiscConfig struct { JsonTTL string `yaml:"jsonTTL" json:"jsonTTL" default:"5m"` PcapTTL string `yaml:"pcapTTL" json:"pcapTTL" default:"10s"` PcapErrorTTL string `yaml:"pcapErrorTTL" json:"pcapErrorTTL" default:"60s"` TrafficSampleRate int `yaml:"trafficSampleRate" json:"trafficSampleRate" default:"100"` TcpStreamChannelTimeoutMs int `yaml:"tcpStreamChannelTimeoutMs" json:"tcpStreamChannelTimeoutMs" default:"10000"` TcpStreamChannelTimeoutShow bool `yaml:"tcpStreamChannelTimeoutShow" json:"tcpStreamChannelTimeoutShow" default:"false"` ResolutionStrategy string `yaml:"resolutionStrategy" json:"resolutionStrategy" default:"auto"` DuplicateTimeframe string `yaml:"duplicateTimeframe" json:"duplicateTimeframe" default:"200ms"` DetectDuplicates bool `yaml:"detectDuplicates" json:"detectDuplicates" default:"false"` StaleTimeoutSeconds int `yaml:"staleTimeoutSeconds" json:"staleTimeoutSeconds" default:"30"` } type PcapDumpConfig struct { PcapDumpEnabled bool `yaml:"enabled" json:"enabled" default:"true"` PcapTimeInterval string `yaml:"timeInterval" json:"timeInterval" default:"1m"` PcapMaxTime string `yaml:"maxTime" json:"maxTime" default:"1h"` PcapMaxSize string `yaml:"maxSize" json:"maxSize" default:"500MB"` PcapSrcDir string `yaml:"pcapSrcDir" json:"pcapSrcDir" default:"pcapdump"` } type TapConfig struct { Docker DockerConfig `yaml:"docker" json:"docker"` Proxy ProxyConfig `yaml:"proxy" json:"proxy"` PodRegexStr string `yaml:"regex" json:"regex" default:".*"` Namespaces []string `yaml:"namespaces" json:"namespaces" default:"[]"` ExcludedNamespaces []string `yaml:"excludedNamespaces" json:"excludedNamespaces" default:"[]"` BpfOverride string `yaml:"bpfOverride" json:"bpfOverride" default:""` Stopped bool `yaml:"stopped" json:"stopped" default:"false"` Release ReleaseConfig `yaml:"release" json:"release"` PersistentStorage bool `yaml:"persistentStorage" json:"persistentStorage" default:"false"` PersistentStorageStatic bool `yaml:"persistentStorageStatic" json:"persistentStorageStatic" default:"false"` EfsFileSytemIdAndPath string `yaml:"efsFileSytemIdAndPath" json:"efsFileSytemIdAndPath" default:""` StorageLimit string `yaml:"storageLimit" json:"storageLimit" default:"5000Mi"` StorageClass string `yaml:"storageClass" json:"storageClass" default:"standard"` DryRun bool `yaml:"dryRun" json:"dryRun" default:"false"` Resources ResourcesConfig `yaml:"resources" json:"resources"` ServiceMesh bool `yaml:"serviceMesh" json:"serviceMesh" default:"true"` Tls bool `yaml:"tls" json:"tls" default:"true"` DisableTlsLog bool `yaml:"disableTlsLog" json:"disableTlsLog" default:"true"` PacketCapture string `yaml:"packetCapture" json:"packetCapture" default:"best"` IgnoreTainted bool `yaml:"ignoreTainted" json:"ignoreTainted" default:"false"` Labels map[string]string `yaml:"labels" json:"labels" default:"{}"` Annotations map[string]string `yaml:"annotations" json:"annotations" default:"{}"` NodeSelectorTerms []v1.NodeSelectorTerm `yaml:"nodeSelectorTerms" json:"nodeSelectorTerms" default:"[]"` Auth AuthConfig `yaml:"auth" json:"auth"` Ingress IngressConfig `yaml:"ingress" json:"ingress"` IPv6 bool `yaml:"ipv6" json:"ipv6" default:"true"` Debug bool `yaml:"debug" json:"debug" default:"false"` Telemetry TelemetryConfig `yaml:"telemetry" json:"telemetry"` ResourceGuard ResourceGuardConfig `yaml:"resourceGuard" json:"resourceGuard"` Sentry SentryConfig `yaml:"sentry" json:"sentry"` DefaultFilter string `yaml:"defaultFilter" json:"defaultFilter" default:"!dns and !tcp and !udp and !icmp"` ScriptingDisabled bool `yaml:"scriptingDisabled" json:"scriptingDisabled" default:"false"` TargetedPodsUpdateDisabled bool `yaml:"targetedPodsUpdateDisabled" json:"targetedPodsUpdateDisabled" default:"false"` PresetFiltersChangingEnabled bool `yaml:"presetFiltersChangingEnabled" json:"presetFiltersChangingEnabled" default:"true"` RecordingDisabled bool `yaml:"recordingDisabled" json:"recordingDisabled" default:"false"` StopTrafficCapturingDisabled bool `yaml:"stopTrafficCapturingDisabled" json:"stopTrafficCapturingDisabled" default:"false"` Capabilities CapabilitiesConfig `yaml:"capabilities" json:"capabilities"` GlobalFilter string `yaml:"globalFilter" json:"globalFilter" default:""` EnabledDissectors []string `yaml:"enabledDissectors" json:"enabledDissectors"` Metrics MetricsConfig `yaml:"metrics" json:"metrics"` Pprof PprofConfig `yaml:"pprof" json:"pprof"` Misc MiscConfig `yaml:"misc" json:"misc"` } func (config *TapConfig) PodRegex() *regexp.Regexp { podRegex, _ := regexp.Compile(config.PodRegexStr) return podRegex } func (config *TapConfig) Validate() error { _, compileErr := regexp.Compile(config.PodRegexStr) if compileErr != nil { return fmt.Errorf("%s is not a valid regex %s", config.PodRegexStr, compileErr) } return nil } 0707010000002E000081A4000000000000000000000001673DBE28000040B1000000000000000000000000000000000000003500000000kubeshark-cli-52.3.90/config/config_internal_test.gopackage config import ( "fmt" "reflect" "testing" ) type ConfigMock struct { SectionMock SectionMock `yaml:"section"` Test string `yaml:"test"` StringField string `yaml:"string-field"` IntField int `yaml:"int-field"` BoolField bool `yaml:"bool-field"` UintField uint `yaml:"uint-field"` StringSliceField []string `yaml:"string-slice-field"` IntSliceField []int `yaml:"int-slice-field"` BoolSliceField []bool `yaml:"bool-slice-field"` UintSliceField []uint `yaml:"uint-slice-field"` } type SectionMock struct { Test string `yaml:"test"` } type FieldSetValues struct { SetValues []string FieldName string FieldValue interface{} } func TestMergeSetFlagNoSeparator(t *testing.T) { tests := []struct { Name string SetValues []string }{ {Name: "empty value", SetValues: []string{""}}, {Name: "single char", SetValues: []string{"t"}}, {Name: "combine empty value and single char", SetValues: []string{"", "t"}}, {Name: "two values without separator", SetValues: []string{"test", "test:true"}}, {Name: "four values without separator", SetValues: []string{"test", "test:true", "testing!", "true"}}, } for _, test := range tests { t.Run(test.Name, func(t *testing.T) { configMock := ConfigMock{} configMockElemValue := reflect.ValueOf(&configMock).Elem() err := mergeSetFlag(configMockElemValue, test.SetValues) if err == nil { t.Errorf("unexpected unhandled error - SetValues: %v", test.SetValues) return } for i := 0; i < configMockElemValue.NumField(); i++ { currentField := configMockElemValue.Type().Field(i) currentFieldByName := configMockElemValue.FieldByName(currentField.Name) if !currentFieldByName.IsZero() { t.Errorf("unexpected value with not default value - SetValues: %v", test.SetValues) } } }) } } func TestMergeSetFlagInvalidFlagName(t *testing.T) { tests := []struct { Name string SetValues []string }{ {Name: "invalid flag name", SetValues: []string{"invalid_flag=true"}}, {Name: "invalid flag name inside section struct", SetValues: []string{"section.invalid_flag=test"}}, {Name: "flag name is a struct", SetValues: []string{"section=test"}}, {Name: "empty flag name", SetValues: []string{"=true"}}, {Name: "four tests combined", SetValues: []string{"invalid_flag=true", "config.invalid_flag=test", "section=test", "=true"}}, } for _, test := range tests { t.Run(test.Name, func(t *testing.T) { configMock := ConfigMock{} configMockElemValue := reflect.ValueOf(&configMock).Elem() err := mergeSetFlag(configMockElemValue, test.SetValues) if err == nil { t.Errorf("unexpected unhandled error - SetValues: %v", test.SetValues) return } for i := 0; i < configMockElemValue.NumField(); i++ { currentField := configMockElemValue.Type().Field(i) currentFieldByName := configMockElemValue.FieldByName(currentField.Name) if !currentFieldByName.IsZero() { t.Errorf("unexpected case - SetValues: %v", test.SetValues) } } }) } } func TestMergeSetFlagInvalidFlagValue(t *testing.T) { tests := []struct { Name string SetValues []string }{ {Name: "bool value to int field", SetValues: []string{"int-field=true"}}, {Name: "int value to bool field", SetValues: []string{"bool-field:5"}}, {Name: "int value to uint field", SetValues: []string{"uint-field=-1"}}, {Name: "bool value to int slice field", SetValues: []string{"int-slice-field=true"}}, {Name: "int value to bool slice field", SetValues: []string{"bool-slice-field=5"}}, {Name: "int value to uint slice field", SetValues: []string{"uint-slice-field=-1"}}, {Name: "int slice value to int field", SetValues: []string{"int-field=6", "int-field=66"}}, } for _, test := range tests { t.Run(test.Name, func(t *testing.T) { configMock := ConfigMock{} configMockElemValue := reflect.ValueOf(&configMock).Elem() err := mergeSetFlag(configMockElemValue, test.SetValues) if err == nil { t.Errorf("unexpected unhandled error - SetValues: %v", test.SetValues) return } for i := 0; i < configMockElemValue.NumField(); i++ { currentField := configMockElemValue.Type().Field(i) currentFieldByName := configMockElemValue.FieldByName(currentField.Name) if !currentFieldByName.IsZero() { t.Errorf("unexpected case - SetValues: %v", test.SetValues) } } }) } } func TestMergeSetFlagNotSliceValues(t *testing.T) { tests := []struct { Name string FieldsSetValues []FieldSetValues }{ {Name: "string field", FieldsSetValues: []FieldSetValues{{SetValues: []string{"string-field=test"}, FieldName: "StringField", FieldValue: "test"}}}, {Name: "int field", FieldsSetValues: []FieldSetValues{{SetValues: []string{"int-field=6"}, FieldName: "IntField", FieldValue: 6}}}, {Name: "bool field", FieldsSetValues: []FieldSetValues{{SetValues: []string{"bool-field=true"}, FieldName: "BoolField", FieldValue: true}}}, {Name: "uint field", FieldsSetValues: []FieldSetValues{{SetValues: []string{"uint-field=6"}, FieldName: "UintField", FieldValue: uint(6)}}}, {Name: "four fields combined", FieldsSetValues: []FieldSetValues { {SetValues: []string{"string-field=test"}, FieldName: "StringField", FieldValue: "test"}, {SetValues: []string{"int-field=6"}, FieldName: "IntField", FieldValue: 6}, {SetValues: []string{"bool-field=true"}, FieldName: "BoolField", FieldValue: true}, {SetValues: []string{"uint-field=6"}, FieldName: "UintField", FieldValue: uint(6)}, }}, } for _, test := range tests { t.Run(test.Name, func(t *testing.T) { configMock := ConfigMock{} configMockElemValue := reflect.ValueOf(&configMock).Elem() var setValues []string for _, fieldSetValues := range test.FieldsSetValues { setValues = append(setValues, fieldSetValues.SetValues...) } err := mergeSetFlag(configMockElemValue, setValues) if err != nil { t.Errorf("unexpected error result - err: %v", err) return } for _, fieldSetValues := range test.FieldsSetValues { fieldValue := configMockElemValue.FieldByName(fieldSetValues.FieldName).Interface() if fieldValue != fieldSetValues.FieldValue { t.Errorf("unexpected result - expected: %v, actual: %v", fieldSetValues.FieldValue, fieldValue) } } }) } } func TestMergeSetFlagSliceValues(t *testing.T) { tests := []struct { Name string FieldsSetValues []FieldSetValues }{ {Name: "string slice field single value", FieldsSetValues: []FieldSetValues{{SetValues: []string{"string-slice-field=test"}, FieldName: "StringSliceField", FieldValue: []string{"test"}}}}, {Name: "int slice field single value", FieldsSetValues: []FieldSetValues{{SetValues: []string{"int-slice-field=6"}, FieldName: "IntSliceField", FieldValue: []int{6}}}}, {Name: "bool slice field single value", FieldsSetValues: []FieldSetValues{{SetValues: []string{"bool-slice-field=true"}, FieldName: "BoolSliceField", FieldValue: []bool{true}}}}, {Name: "uint slice field single value", FieldsSetValues: []FieldSetValues{{SetValues: []string{"uint-slice-field=6"}, FieldName: "UintSliceField", FieldValue: []uint{uint(6)}}}}, {Name: "four single value fields combined", FieldsSetValues: []FieldSetValues{ {SetValues: []string{"string-slice-field=test"}, FieldName: "StringSliceField", FieldValue: []string{"test"}}, {SetValues: []string{"int-slice-field=6"}, FieldName: "IntSliceField", FieldValue: []int{6}}, {SetValues: []string{"bool-slice-field=true"}, FieldName: "BoolSliceField", FieldValue: []bool{true}}, {SetValues: []string{"uint-slice-field=6"}, FieldName: "UintSliceField", FieldValue: []uint{uint(6)}}, }}, {Name: "string slice field two values", FieldsSetValues: []FieldSetValues{{SetValues: []string{"string-slice-field=test", "string-slice-field=test2"}, FieldName: "StringSliceField", FieldValue: []string{"test", "test2"}}}}, {Name: "int slice field two values", FieldsSetValues: []FieldSetValues{{SetValues: []string{"int-slice-field=6", "int-slice-field=66"}, FieldName: "IntSliceField", FieldValue: []int{6, 66}}}}, {Name: "bool slice field two values", FieldsSetValues: []FieldSetValues{{SetValues: []string{"bool-slice-field=true", "bool-slice-field=false"}, FieldName: "BoolSliceField", FieldValue: []bool{true, false}}}}, {Name: "uint slice field two values", FieldsSetValues: []FieldSetValues{{SetValues: []string{"uint-slice-field=6", "uint-slice-field=66"}, FieldName: "UintSliceField", FieldValue: []uint{uint(6), uint(66)}}}}, {Name: "four two values fields combined", FieldsSetValues: []FieldSetValues{ {SetValues: []string{"string-slice-field=test", "string-slice-field=test2"}, FieldName: "StringSliceField", FieldValue: []string{"test", "test2"}}, {SetValues: []string{"int-slice-field=6", "int-slice-field=66"}, FieldName: "IntSliceField", FieldValue: []int{6, 66}}, {SetValues: []string{"bool-slice-field=true", "bool-slice-field=false"}, FieldName: "BoolSliceField", FieldValue: []bool{true, false}}, {SetValues: []string{"uint-slice-field=6", "uint-slice-field=66"}, FieldName: "UintSliceField", FieldValue: []uint{uint(6), uint(66)}}, }}, } for _, test := range tests { t.Run(test.Name, func(t *testing.T) { configMock := ConfigMock{} configMockElemValue := reflect.ValueOf(&configMock).Elem() var setValues []string for _, fieldSetValues := range test.FieldsSetValues { setValues = append(setValues, fieldSetValues.SetValues...) } err := mergeSetFlag(configMockElemValue, setValues) if err != nil { t.Errorf("unexpected error result - err: %v", err) return } for _, fieldSetValues := range test.FieldsSetValues { fieldValue := configMockElemValue.FieldByName(fieldSetValues.FieldName).Interface() if !reflect.DeepEqual(fieldValue, fieldSetValues.FieldValue) { t.Errorf("unexpected result - expected: %v, actual: %v", fieldSetValues.FieldValue, fieldValue) } } }) } } func TestMergeSetFlagMixValues(t *testing.T) { tests := []struct { Name string FieldsSetValues []FieldSetValues }{ {Name: "single value all fields", FieldsSetValues: []FieldSetValues{ {SetValues: []string{"string-slice-field=test"}, FieldName: "StringSliceField", FieldValue: []string{"test"}}, {SetValues: []string{"int-slice-field=6"}, FieldName: "IntSliceField", FieldValue: []int{6}}, {SetValues: []string{"bool-slice-field=true"}, FieldName: "BoolSliceField", FieldValue: []bool{true}}, {SetValues: []string{"uint-slice-field=6"}, FieldName: "UintSliceField", FieldValue: []uint{uint(6)}}, {SetValues: []string{"string-field=test"}, FieldName: "StringField", FieldValue: "test"}, {SetValues: []string{"int-field=6"}, FieldName: "IntField", FieldValue: 6}, {SetValues: []string{"bool-field=true"}, FieldName: "BoolField", FieldValue: true}, {SetValues: []string{"uint-field=6"}, FieldName: "UintField", FieldValue: uint(6)}, }}, {Name: "two values slice fields and single value fields", FieldsSetValues: []FieldSetValues{ {SetValues: []string{"string-slice-field=test", "string-slice-field=test2"}, FieldName: "StringSliceField", FieldValue: []string{"test", "test2"}}, {SetValues: []string{"int-slice-field=6", "int-slice-field=66"}, FieldName: "IntSliceField", FieldValue: []int{6, 66}}, {SetValues: []string{"bool-slice-field=true", "bool-slice-field=false"}, FieldName: "BoolSliceField", FieldValue: []bool{true, false}}, {SetValues: []string{"uint-slice-field=6", "uint-slice-field=66"}, FieldName: "UintSliceField", FieldValue: []uint{uint(6), uint(66)}}, {SetValues: []string{"string-field=test"}, FieldName: "StringField", FieldValue: "test"}, {SetValues: []string{"int-field=6"}, FieldName: "IntField", FieldValue: 6}, {SetValues: []string{"bool-field=true"}, FieldName: "BoolField", FieldValue: true}, {SetValues: []string{"uint-field=6"}, FieldName: "UintField", FieldValue: uint(6)}, }}, } for _, test := range tests { t.Run(test.Name, func(t *testing.T) { configMock := ConfigMock{} configMockElemValue := reflect.ValueOf(&configMock).Elem() var setValues []string for _, fieldSetValues := range test.FieldsSetValues { setValues = append(setValues, fieldSetValues.SetValues...) } err := mergeSetFlag(configMockElemValue, setValues) if err != nil { t.Errorf("unexpected error result - err: %v", err) return } for _, fieldSetValues := range test.FieldsSetValues { fieldValue := configMockElemValue.FieldByName(fieldSetValues.FieldName).Interface() if !reflect.DeepEqual(fieldValue, fieldSetValues.FieldValue) { t.Errorf("unexpected result - expected: %v, actual: %v", fieldSetValues.FieldValue, fieldValue) } } }) } } func TestGetParsedValueValidValue(t *testing.T) { tests := []struct { StringValue string Kind reflect.Kind ActualValue interface{} }{ {StringValue: "test", Kind: reflect.String, ActualValue: "test"}, {StringValue: "123", Kind: reflect.String, ActualValue: "123"}, {StringValue: "true", Kind: reflect.Bool, ActualValue: true}, {StringValue: "false", Kind: reflect.Bool, ActualValue: false}, {StringValue: "6", Kind: reflect.Int, ActualValue: 6}, {StringValue: "-6", Kind: reflect.Int, ActualValue: -6}, {StringValue: "6", Kind: reflect.Int8, ActualValue: int8(6)}, {StringValue: "-6", Kind: reflect.Int8, ActualValue: int8(-6)}, {StringValue: "6", Kind: reflect.Int16, ActualValue: int16(6)}, {StringValue: "-6", Kind: reflect.Int16, ActualValue: int16(-6)}, {StringValue: "6", Kind: reflect.Int32, ActualValue: int32(6)}, {StringValue: "-6", Kind: reflect.Int32, ActualValue: int32(-6)}, {StringValue: "6", Kind: reflect.Int64, ActualValue: int64(6)}, {StringValue: "-6", Kind: reflect.Int64, ActualValue: int64(-6)}, {StringValue: "6", Kind: reflect.Uint, ActualValue: uint(6)}, {StringValue: "66", Kind: reflect.Uint, ActualValue: uint(66)}, {StringValue: "6", Kind: reflect.Uint8, ActualValue: uint8(6)}, {StringValue: "66", Kind: reflect.Uint8, ActualValue: uint8(66)}, {StringValue: "6", Kind: reflect.Uint16, ActualValue: uint16(6)}, {StringValue: "66", Kind: reflect.Uint16, ActualValue: uint16(66)}, {StringValue: "6", Kind: reflect.Uint32, ActualValue: uint32(6)}, {StringValue: "66", Kind: reflect.Uint32, ActualValue: uint32(66)}, {StringValue: "6", Kind: reflect.Uint64, ActualValue: uint64(6)}, {StringValue: "66", Kind: reflect.Uint64, ActualValue: uint64(66)}, } for _, test := range tests { t.Run(fmt.Sprintf("%v %v", test.Kind, test.StringValue), func(t *testing.T) { parsedValue, err := getParsedValue(test.Kind, test.StringValue) if err != nil { t.Errorf("unexpected error result - err: %v", err) return } if parsedValue.Interface() != test.ActualValue { t.Errorf("unexpected result - expected: %v, actual: %v", test.ActualValue, parsedValue) } }) } } func TestGetParsedValueInvalidValue(t *testing.T) { tests := []struct { StringValue string Kind reflect.Kind }{ {StringValue: "test", Kind: reflect.Bool}, {StringValue: "123", Kind: reflect.Bool}, {StringValue: "test", Kind: reflect.Int}, {StringValue: "true", Kind: reflect.Int}, {StringValue: "test", Kind: reflect.Int8}, {StringValue: "true", Kind: reflect.Int8}, {StringValue: "test", Kind: reflect.Int16}, {StringValue: "true", Kind: reflect.Int16}, {StringValue: "test", Kind: reflect.Int32}, {StringValue: "true", Kind: reflect.Int32}, {StringValue: "test", Kind: reflect.Int64}, {StringValue: "true", Kind: reflect.Int64}, {StringValue: "test", Kind: reflect.Uint}, {StringValue: "-6", Kind: reflect.Uint}, {StringValue: "test", Kind: reflect.Uint8}, {StringValue: "-6", Kind: reflect.Uint8}, {StringValue: "test", Kind: reflect.Uint16}, {StringValue: "-6", Kind: reflect.Uint16}, {StringValue: "test", Kind: reflect.Uint32}, {StringValue: "-6", Kind: reflect.Uint32}, {StringValue: "test", Kind: reflect.Uint64}, {StringValue: "-6", Kind: reflect.Uint64}, } for _, test := range tests { t.Run(fmt.Sprintf("%v %v", test.Kind, test.StringValue), func(t *testing.T) { parsedValue, err := getParsedValue(test.Kind, test.StringValue) if err == nil { t.Errorf("unexpected unhandled error - stringValue: %v, Kind: %v", test.StringValue, test.Kind) return } if parsedValue != reflect.ValueOf(nil) { t.Errorf("unexpected parsed value - parsedValue: %v", parsedValue) } }) } } 0707010000002F000041ED000000000000000000000002673DBE2800000000000000000000000000000000000000000000001F00000000kubeshark-cli-52.3.90/debounce07070100000030000081A4000000000000000000000001673DBE28000003BC000000000000000000000000000000000000002B00000000kubeshark-cli-52.3.90/debounce/debounce.gopackage debounce import ( "fmt" "time" ) func NewDebouncer(timeout time.Duration, callback func()) *Debouncer { var debouncer Debouncer debouncer.setTimeout(timeout) debouncer.setCallback(callback) return &debouncer } type Debouncer struct { callback func() running bool canceled bool timeout time.Duration timer *time.Timer } func (d *Debouncer) setTimeout(timeout time.Duration) { // TODO: Return err if d.running d.timeout = timeout } func (d *Debouncer) setCallback(callback func()) { callbackWrapped := func() { if !d.canceled { callback() } d.running = false } d.callback = callbackWrapped } func (d *Debouncer) Cancel() { d.canceled = true } func (d *Debouncer) SetOn() error { if d.canceled { return fmt.Errorf("debouncer cancelled") } if d.running { return nil } d.running = true d.timer = time.AfterFunc(d.timeout, d.callback) return nil } func (d *Debouncer) IsOn() bool { return d.running } 07070100000031000041ED000000000000000000000002673DBE2800000000000000000000000000000000000000000000002300000000kubeshark-cli-52.3.90/errormessage07070100000032000081A4000000000000000000000001673DBE28000004F2000000000000000000000000000000000000003300000000kubeshark-cli-52.3.90/errormessage/errormessage.gopackage errormessage import ( "errors" "fmt" regexpsyntax "regexp/syntax" "github.com/kubeshark/kubeshark/config" "github.com/kubeshark/kubeshark/config/configStructs" "github.com/kubeshark/kubeshark/misc" k8serrors "k8s.io/apimachinery/pkg/api/errors" ) // formatError wraps error with a detailed message that is meant for the user. // While the errors are meant to be displayed, they are not meant to be exported as classes outsite of CLI. func FormatError(err error) error { var errorNew error if k8serrors.IsForbidden(err) { errorNew = fmt.Errorf("insufficient permissions: %w. "+ "supply the required permission or control %s's access to namespaces by setting %s "+ "in the config file or setting the targeted namespace with --%s %s=<NAMESPACE>", err, misc.Software, configStructs.ReleaseNamespaceLabel, config.SetCommandName, configStructs.ReleaseNamespaceLabel) } else if syntaxError, isSyntaxError := asRegexSyntaxError(err); isSyntaxError { errorNew = fmt.Errorf("regex %s is invalid: %w", syntaxError.Expr, err) } else { errorNew = err } return errorNew } func asRegexSyntaxError(err error) (*regexpsyntax.Error, bool) { var syntaxError *regexpsyntax.Error return syntaxError, errors.As(err, &syntaxError) } 07070100000033000081A4000000000000000000000001673DBE2800001EBB000000000000000000000000000000000000001D00000000kubeshark-cli-52.3.90/go.modmodule github.com/kubeshark/kubeshark go 1.21.1 require ( github.com/creasty/defaults v1.5.2 github.com/fsnotify/fsnotify v1.6.0 github.com/go-cmd/cmd v1.4.3 github.com/goccy/go-yaml v1.11.2 github.com/google/go-github/v37 v37.0.0 github.com/gorilla/websocket v1.4.2 github.com/kubeshark/gopacket v1.1.39 github.com/pkg/errors v0.9.1 github.com/rivo/tview v0.0.0-20240818110301-fd649dbf1223 github.com/robertkrimen/otto v0.2.1 github.com/rs/zerolog v1.28.0 github.com/spf13/cobra v1.7.0 github.com/spf13/pflag v1.0.5 github.com/tanqiangyes/grep-go v0.0.0-20220515134556-b36bff9c3d8e helm.sh/helm/v3 v3.12.0 k8s.io/api v0.28.3 k8s.io/apimachinery v0.28.3 k8s.io/client-go v0.28.3 k8s.io/kubectl v0.28.3 ) require ( github.com/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1 // indirect github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/BurntSushi/toml v1.2.1 // indirect github.com/MakeNowJust/heredoc v1.0.0 // indirect github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/semver/v3 v3.2.0 // indirect github.com/Masterminds/sprig/v3 v3.2.3 // indirect github.com/Masterminds/squirrel v1.5.3 // indirect github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/chai2010/gettext-go v1.0.2 // indirect github.com/containerd/containerd v1.7.0 // indirect github.com/cyphar/filepath-securejoin v0.2.3 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/docker/cli v20.10.21+incompatible // indirect github.com/docker/distribution v2.8.2+incompatible // indirect github.com/docker/docker v20.10.24+incompatible // indirect github.com/docker/docker-credential-helpers v0.7.0 // indirect github.com/docker/go-connections v0.4.0 // indirect github.com/docker/go-metrics v0.0.1 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/emicklei/go-restful/v3 v3.10.1 // indirect github.com/evanphx/json-patch v5.6.0+incompatible // indirect github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f // indirect github.com/fatih/color v1.13.0 // indirect github.com/gdamore/encoding v1.0.0 // indirect github.com/gdamore/tcell/v2 v2.7.1 // indirect github.com/go-errors/errors v1.4.2 // indirect github.com/go-gorp/gorp/v3 v3.0.5 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/swag v0.22.3 // indirect github.com/go-playground/validator/v10 v10.14.0 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/google/btree v1.0.1 // indirect github.com/google/gnostic-models v0.6.8 // indirect github.com/google/go-cmp v0.5.9 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/google/uuid v1.3.0 // indirect github.com/gorilla/mux v1.8.0 // indirect github.com/gosuri/uitable v0.0.4 // indirect github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/huandu/xstrings v1.4.0 // indirect github.com/imdario/mergo v0.3.13 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jmoiron/sqlx v1.3.5 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.16.0 // indirect github.com/kubeshark/tracerproto v1.0.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.7 // indirect github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.19 // indirect github.com/mattn/go-runewidth v0.0.15 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/go-wordwrap v1.0.1 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/moby/locker v1.0.1 // indirect github.com/moby/spdystream v0.2.0 // indirect github.com/moby/term v0.0.0-20221205130635-1aeaba878587 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect github.com/morikuni/aec v1.0.0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b // indirect github.com/peterbourgon/diskv v2.0.1+incompatible // indirect github.com/prometheus/client_golang v1.16.0 // indirect github.com/prometheus/client_model v0.4.0 // indirect github.com/prometheus/common v0.44.0 // indirect github.com/prometheus/procfs v0.10.1 // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/rubenv/sql-migrate v1.3.1 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/shopspring/decimal v1.3.1 // indirect github.com/sirupsen/logrus v1.9.0 // indirect github.com/spf13/cast v1.5.0 // indirect github.com/stretchr/testify v1.8.3 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xeipuuv/gojsonschema v1.2.0 // indirect github.com/xlab/treeprint v1.2.0 // indirect go.opentelemetry.io/otel v1.14.0 // indirect go.opentelemetry.io/otel/trace v1.14.0 // indirect go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect golang.org/x/crypto v0.14.0 // indirect golang.org/x/mod v0.10.0 // indirect golang.org/x/net v0.17.0 // indirect golang.org/x/oauth2 v0.8.0 // indirect golang.org/x/sync v0.2.0 // indirect golang.org/x/sys v0.17.0 // indirect golang.org/x/term v0.17.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.3.0 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 // indirect google.golang.org/grpc v1.54.0 // indirect google.golang.org/protobuf v1.30.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/sourcemap.v1 v1.0.5 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/apiextensions-apiserver v0.27.1 // indirect k8s.io/apiserver v0.27.1 // indirect k8s.io/cli-runtime v0.28.3 // indirect k8s.io/component-base v0.28.3 // indirect k8s.io/klog/v2 v2.100.1 // indirect k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 // indirect k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 // indirect oras.land/oras-go v1.2.2 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 // indirect sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect sigs.k8s.io/yaml v1.3.0 // indirect ) 07070100000034000081A4000000000000000000000001673DBE280001BDD3000000000000000000000000000000000000001D00000000kubeshark-cli-52.3.90/go.sumcloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1 h1:EKPd1INOIyr5hWOWhvpmQpY6tKjeG0hT1s3AMC/9fic= github.com/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1/go.mod h1:VzwV+t+dZ9j/H867F1M2ziD+yLHtB46oM35FxxMJ4d0= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak= github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ= github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE= 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.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= github.com/Masterminds/semver/v3 v3.2.0 h1:3MEsd0SM6jqZojhjLWWeBY+Kcjy9i6MQAeY7YgDP83g= github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= github.com/Masterminds/sprig/v3 v3.2.1/go.mod h1:UoaO7Yp8KlPnJIYWTFkMaqPUYKTfGFPhxNuwnnxkKlk= github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA= github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM= github.com/Masterminds/squirrel v1.5.3 h1:YPpoceAcxuzIljlr5iWpNKaql7hLeG1KLSrhvdHpkZc= github.com/Masterminds/squirrel v1.5.3/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10= github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg= github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE= github.com/Microsoft/hcsshim v0.10.0-rc.7 h1:HBytQPxcv8Oy4244zbQbe6hnOnx544eL5QPUqhJldz8= github.com/Microsoft/hcsshim v0.10.0-rc.7/go.mod h1:ILuwjA+kNW+MrN/w5un7n3mTqkwsFu4Bp05/okFUZlE= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d h1:UrqY+r/OJnIp5u0s1SbQ8dVfLCZJsnvazdBP5hS4iRs= github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= github.com/a8m/expect v1.0.0/go.mod h1:4IwSCMumY49ScypDnjNbYEjgVeqy1/U2cEs3Lat96eA= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 h1:4daAzAu0S6Vi7/lbWECcX0j45yZReDZ56BQsrVBOEEY= github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= github.com/bshuster-repo/logrus-logstash-hook v1.0.0 h1:e+C0SB5R1pu//O4MQ3f9cFuPGoOVeF2fE4Og9otCc70= github.com/bshuster-repo/logrus-logstash-hook v1.0.0/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd h1:rFt+Y/IK1aEZkEHchZRSq9OQbsSzIT/OrI8YFFmRIng= github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b h1:otBG+dV+YK+Soembjv71DPz3uX/V/6MMlSyD9JBQ6kQ= github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50= github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0 h1:nvj0OLI3YqYXer/kZD8Ri1aaunCxIEsOst1BVJswV0o= github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chai2010/gettext-go v1.0.2 h1:1Lwwip6Q2QGsAdl/ZKPCwTe9fe0CjlUbqj5bFNSjIRk= github.com/chai2010/gettext-go v1.0.2/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHeQQ+5AjwawxA= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM= github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw= github.com/containerd/containerd v1.7.0 h1:G/ZQr3gMZs6ZT0qPUZ15znx5QSdQdASW11nXTLTM2Pg= github.com/containerd/containerd v1.7.0/go.mod h1:QfR7Efgb/6X2BDpTPJRvPTYDE9rsF0FsXX9J8sIs/sc= github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg= github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/creasty/defaults v1.5.2 h1:/VfB6uxpyp6h0fr7SPp7n8WJBoV8jfxQXPCnkVSjyls= github.com/creasty/defaults v1.5.2/go.mod h1:FPZ+Y0WNrbqOVw+c6av63eyHUAl6pMHZwqLPvXUZGfY= github.com/cyphar/filepath-securejoin v0.2.3 h1:YX6ebbZCZP7VkM3scTTokDgBL2TY741X51MTk3ycuNI= github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/denisenkom/go-mssqldb v0.9.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/distribution/distribution/v3 v3.0.0-20221208165359-362910506bc2 h1:aBfCb7iqHmDEIp6fBvC/hQUddQfg+3qdYjwzaiP9Hnc= github.com/distribution/distribution/v3 v3.0.0-20221208165359-362910506bc2/go.mod h1:WHNsWjnIn2V1LYOrME7e8KxSeKunYHsxEm4am0BUtcI= github.com/docker/cli v20.10.21+incompatible h1:qVkgyYUnOLQ98LtXBrwd/duVqPT2X4SHndOuGsfwyhU= github.com/docker/cli v20.10.21+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v20.10.24+incompatible h1:Ugvxm7a8+Gz6vqQYQQ2W7GYq5EUPaAiuPgIfVyI3dYE= github.com/docker/docker v20.10.24+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker-credential-helpers v0.7.0 h1:xtCHsjxogADNZcdv1pKUHXryefjlVRqWqIhk/uXJp0A= github.com/docker/docker-credential-helpers v0.7.0/go.mod h1:rETQfLdHNT3foU5kuNkFR1R1V12OJRRO5lzt2D1b5X0= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c h1:+pKlWGMw7gf6bQ+oDZB4KHQFypsfjYlq/C4rfL7D3g8= github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8= github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1 h1:ZClxb8laGDf5arXfYcAtECDFgAgHklGI8CxgjHnXKJ4= github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= github.com/emicklei/go-restful/v3 v3.10.1 h1:rc42Y5YTp7Am7CS630D7JmhRjq4UlEUuEKfrDac4bSQ= github.com/emicklei/go-restful/v3 v3.10.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f h1:Wl78ApPPB2Wvf/TIe2xdyJxTlb6obmF18d8QdkxNDu4= github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f/go.mod h1:OSYXu++VVOHnXeitef/D8n/6y4QV8uLHSFXX4NeXMGc= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/foxcpp/go-mockdns v1.0.0 h1:7jBqxd3WDWwi/6WhDvacvH1XsN3rOLXyHM1uhvIx6FI= github.com/foxcpp/go-mockdns v1.0.0/go.mod h1:lgRN6+KxQBawyIghpnl5CezHFGS9VLzvtVlwxvzXTQ4= github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko= github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg= github.com/gdamore/tcell/v2 v2.7.1 h1:TiCcmpWHiAU7F0rA2I3S2Y4mmLmO9KHxJ7E1QhYzQbc= github.com/gdamore/tcell/v2 v2.7.1/go.mod h1:dSXtXTSK0VsW1biw65DZLZ2NKr7j0qP/0J7ONmsraWg= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-cmd/cmd v1.4.3 h1:6y3G+3UqPerXvPcXvj+5QNPHT02BUw7p6PsqRxLNA7Y= github.com/go-cmd/cmd v1.4.3/go.mod h1:u3hxg/ry+D5kwh8WvUkHLAMe2zQCaXd00t35WfQaOFk= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gorp/gorp/v3 v3.0.5 h1:PUjzYdYu3HBOh8LE+UUmRG2P0IRDak9XMeGNvaeq4Ow= github.com/go-gorp/gorp/v3 v3.0.5/go.mod h1:dLEjIyyRNiXvNZ8PSmzpt1GsWAUK8kjVhEpjH8TixEw= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/gobuffalo/logger v1.0.6 h1:nnZNpxYo0zx+Aj9RfMPBm+x9zAU2OayFh/xrAWi34HU= github.com/gobuffalo/logger v1.0.6/go.mod h1:J31TBEHR1QLV2683OXTAItYIg8pv2JMHnF/quuAbMjs= github.com/gobuffalo/packd v1.0.1 h1:U2wXfRr4E9DH8IdsDLlRFwTZTK7hLfq9qT/QHXGVe/0= github.com/gobuffalo/packd v1.0.1/go.mod h1:PP2POP3p3RXGz7Jh6eYEf93S7vA2za6xM7QT85L4+VY= github.com/gobuffalo/packr/v2 v2.8.3 h1:xE1yzvnO56cUC0sTpKR3DIbxZgB54AftTFMhB2XEWlY= github.com/gobuffalo/packr/v2 v2.8.3/go.mod h1:0SahksCVcx4IMnigTjiFuyldmTrdTctXsOdiU5KwbKc= 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/goccy/go-yaml v1.11.2 h1:joq77SxuyIs9zzxEjgyLBugMQ9NEgTWxXfz2wVqwAaQ= github.com/goccy/go-yaml v1.11.2/go.mod h1:wKnAMd44+9JAAnGQpWVEgBzGt3YuTaQ4uXoHvE4m7WU= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godror/godror v0.24.2/go.mod h1:wZv/9vPiUib6tkoDl+AZ/QLf5YZgMravZ7jxH2eQWAE= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/gomodule/redigo v1.8.2 h1:H5XSIre1MB5NbPYFp+i1NBbb5qN1W8Y8YAQoAYbkm8k= github.com/gomodule/redigo v1.8.2/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-github/v37 v37.0.0 h1:rCspN8/6kB1BAJWZfuafvHhyfIo5fkAulaP/3bOQ/tM= github.com/google/go-github/v37 v37.0.0/go.mod h1:LM7in3NmXDrX58GbEHy7FtNLbI2JijX93RnMKvWG3m4= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= 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/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gosuri/uitable v0.0.4 h1:IG2xLKRvErL3uhY6e1BylFzG+aJiwQviDDTfOKeKTpY= github.com/gosuri/uitable v0.0.4/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16vt0PJo= github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA= github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU= github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g= github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= 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.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/karrick/godirwalk v1.16.1 h1:DynhcF+bztK8gooS0+NDJFrdNZjJ3gzVzC545UNA9iw= github.com/karrick/godirwalk v1.16.1/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.16.0 h1:iULayQNOReoYUe+1qtKOqw9CwJv3aNQu8ivo7lw1HU4= github.com/klauspost/compress v1.16.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kortschak/utter v1.0.1/go.mod h1:vSmSjbyrlKjjsL71193LmzBOKgwePk9DH6uFaWHIInc= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kubeshark/gopacket v1.1.39 h1:NNiMTPO8v2+5FVlJTulT0Z+O0TLEAzavJBto10AY7js= github.com/kubeshark/gopacket v1.1.39/go.mod h1:Qo8/i/tdT74CCT7/pjO0L55Pktv5dQfj7M/Arv8MKm8= github.com/kubeshark/tracerproto v1.0.0 h1:/euPX9KMrKDS92hSMrLuhncYAX22dYlsnM2aD4AYhhE= github.com/kubeshark/tracerproto v1.0.0/go.mod h1:+efDYkwXxwakmHRpxHVEekyXNtg/aFx0uSo/I0lGV9k= github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq6+3iTQz8KNCLtVX6idSoTLdUw= github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o= github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhRWSsG5rVo6hYhAB/ADZrk= github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw= github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw= github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/markbates/errx v1.1.0 h1:QDFeR+UP95dO12JgW+tgi2UVfo0V8YBHiUIOaeBPiEI= github.com/markbates/errx v1.1.0/go.mod h1:PLa46Oex9KNbVDZhKel8v1OT7hD5JZ2eI7AHhA0wswc= github.com/markbates/oncer v1.0.0 h1:E83IaVAHygyndzPimgUYJjbshhDTALZyXxvk9FOlQRY= github.com/markbates/oncer v1.0.0/go.mod h1:Z59JA581E9GP6w96jai+TGqafHPW+cPfRxz2aSZ0mcI= github.com/markbates/safe v1.0.1 h1:yjZkbvRM6IzKj9tlu/zMJLS0n/V351OZWRnF3QfaUxI= github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-oci8 v0.1.1/go.mod h1:wjDx6Xm9q7dFtHJvIlrI99JytznLw5wQ4R+9mNXJwGI= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI= github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.25 h1:dFwPR6SfLtrSwgDcIq2bcU/gVutB4sNApq2HBdqcakg= github.com/miekg/dns v1.1.25/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/cli v1.1.5/go.mod h1:v8+iFts2sPIKUV1ltktPXMCC8fumSKFItNcD2cLtRR4= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg= github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc= github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= github.com/moby/sys/mountinfo v0.6.2 h1:BzJjoreD5BMFNmD9Rus6gdd1pLuecOFPt8wC+Vygl78= github.com/moby/sys/mountinfo v0.6.2/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI= github.com/moby/term v0.0.0-20221205130635-1aeaba878587 h1:HfkjXDfhgVaN5rmueG8cL8KKeFNecRCXFhaJ2qZ5SKA= github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0= github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= 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/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/nelsam/hel/v2 v2.3.2/go.mod h1:1ZTGfU2PFTOd5mx22i5O0Lc2GY933lQ2wb/ggy+rL3w= github.com/nelsam/hel/v2 v2.3.3/go.mod h1:1ZTGfU2PFTOd5mx22i5O0Lc2GY933lQ2wb/ggy+rL3w= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo/v2 v2.9.4 h1:xR7vG4IXt5RWx6FfIjyAtsoMAtnc3C/rFXBBd2AjZwE= github.com/onsi/ginkgo/v2 v2.9.4/go.mod h1:gCQYp2Q+kSoIj7ykSVb9nskRSsR6PUj4AiLywzIhbKM= github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b h1:YWuSjZCQAPM8UUBLkYUk1e+rZcvWHJmFb6i6rM44Xs8= github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= github.com/poy/onpar v0.0.0-20200406201722-06f95a1c68e8/go.mod h1:nSbFQvMj97ZyhFRSJYtut+msi4sOY6zJDGCdSc+/rZU= github.com/poy/onpar v1.1.2 h1:QaNrNiZx0+Nar5dLgTVp5mXkyoVFIbepjyEoGSnhbAY= github.com/poy/onpar v1.1.2/go.mod h1:6X8FLNoxyr9kkmnlqpK6LSoiOtrO6MICtWwEuWkLjzg= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8= github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg= github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rivo/tview v0.0.0-20240818110301-fd649dbf1223 h1:N+DggyldbUDqFlk0b8JeRjB9zGpmQ8wiKpq+VBbzRso= github.com/rivo/tview v0.0.0-20240818110301-fd649dbf1223/go.mod h1:02iFIz7K/A9jGCvrizLPvoqr4cEIx7q54RH5Qudkrss= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/robertkrimen/otto v0.2.1 h1:FVP0PJ0AHIjC+N4pKCG9yCDz6LHNPCwi/GKID5pGGF0= github.com/robertkrimen/otto v0.2.1/go.mod h1:UPwtJ1Xu7JrLcZjNWN8orJaM5n5YEtqL//farB5FlRY= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.28.0 h1:MirSo27VyNi7RJYP3078AA1+Cyzd2GB66qy3aUHvsWY= github.com/rs/zerolog v1.28.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0= github.com/rubenv/sql-migrate v1.3.1 h1:Vx+n4Du8X8VTYuXbhNxdEUoh6wiJERA0GlWocR5FrbA= github.com/rubenv/sql-migrate v1.3.1/go.mod h1:YzG/Vh82CwyhTFXy+Mf5ahAiiEOpAlHurg+23VEzcsk= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8= github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= github.com/spf13/cobra v0.0.6/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk= github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/tanqiangyes/grep-go v0.0.0-20220515134556-b36bff9c3d8e h1:+qDZ81UqxfZsWK6Vq9wET3AsdQxHGbViYOqkNxZ9FnU= github.com/tanqiangyes/grep-go v0.0.0-20220515134556-b36bff9c3d8e/go.mod h1:ANZlXE3vfRYCYnkojePl2hJODYmOeCVD+XahuhDdTbI= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ= github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43 h1:+lm10QQTNSBd8DVTNGHx7o/IKu9HYDvLMffDhbyLccI= github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs= github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50 h1:hlE8//ciYMztlGpl/VA+Zm1AcTPHYkHJPbHqE6WJUXE= github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA= github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f h1:ERexzlUfuTvpE74urLSbIQW0Z/6hF9t8U4NsJLaioAY= github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/otel v1.14.0 h1:/79Huy8wbf5DnIPhemGB+zEPVwnN6fuQybr/SRXa6hM= go.opentelemetry.io/otel v1.14.0/go.mod h1:o4buv+dJzx8rohcUeRmWUZhqupFvzWis188WlggnNeU= go.opentelemetry.io/otel/trace v1.14.0 h1:wp2Mmvj41tDsyAJXiWDWpfNsOiIyd38fy85pyKcFq/M= go.opentelemetry.io/otel/trace v1.14.0/go.mod h1:8avnQLK+CG77yNLUae4ea2JDQ6iT+gozhnZjy/rw9G8= go.starlark.net v0.0.0-20230525235612-a134d8f9ddca h1:VdD38733bfYv5tUZwEIskMM93VanwNIi5bIKnDrJdEY= go.starlark.net v0.0.0-20230525235612-a134d8f9ddca/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU= golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/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-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8= golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20221013171732-95e765b1cc43/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200313205530-4303120df7d8/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.8.0 h1:vSDcovVPld282ceKgDimkRSC8kpaH1dgyc9UMzlt84Y= golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4= 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= golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 h1:0nDDozoAU19Qb2HwhXadU8OcsiO/09cnTqhUtq2MEOM= google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.54.0 h1:EhTqbhiYeixwWQtAEZAxmV9MGqcjEU2mFx52xCzNyag= google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/sourcemap.v1 v1.0.5 h1:inv58fC9f9J3TK2Y2R1NPntXEn3/wjWHkonhIUODNTI= gopkg.in/sourcemap.v1 v1.0.5/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o= gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g= helm.sh/helm/v3 v3.12.0 h1:rOq2TPVzg5jt4q5ermAZGZFxNW2uQhKjRhBneAutMEM= helm.sh/helm/v3 v3.12.0/go.mod h1:8K/469yxjUMu6BaD2EagCitkPjELUL/l2AgCO142G94= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= k8s.io/api v0.28.3 h1:Gj1HtbSdB4P08C8rs9AR94MfSGpRhJgsS+GF9V26xMM= k8s.io/api v0.28.3/go.mod h1:MRCV/jr1dW87/qJnZ57U5Pak65LGmQVkKTzf3AtKFHc= k8s.io/apiextensions-apiserver v0.27.1 h1:Hp7B3KxKHBZ/FxmVFVpaDiXI6CCSr49P1OJjxKO6o4g= k8s.io/apiextensions-apiserver v0.27.1/go.mod h1:8jEvRDtKjVtWmdkhOqE84EcNWJt/uwF8PC4627UZghY= k8s.io/apimachinery v0.28.3 h1:B1wYx8txOaCQG0HmYF6nbpU8dg6HvA06x5tEffvOe7A= k8s.io/apimachinery v0.28.3/go.mod h1:uQTKmIqs+rAYaq+DFaoD2X7pcjLOqbQX2AOiO0nIpb8= k8s.io/apiserver v0.27.1 h1:phY+BtXjjzd+ta3a4kYbomC81azQSLa1K8jo9RBw7Lg= k8s.io/apiserver v0.27.1/go.mod h1:UGrOjLY2KsieA9Fw6lLiTObxTb8Z1xEba4uqSuMY0WU= k8s.io/cli-runtime v0.28.3 h1:lvuJYVkwCqHEvpS6KuTZsUVwPePFjBfSGvuaLl2SxzA= k8s.io/cli-runtime v0.28.3/go.mod h1:jeX37ZPjIcENVuXDDTskG3+FnVuZms5D9omDXS/2Jjc= k8s.io/client-go v0.28.3 h1:2OqNb72ZuTZPKCl+4gTKvqao0AMOl9f3o2ijbAj3LI4= k8s.io/client-go v0.28.3/go.mod h1:LTykbBp9gsA7SwqirlCXBWtK0guzfhpoW4qSm7i9dxo= k8s.io/component-base v0.28.3 h1:rDy68eHKxq/80RiMb2Ld/tbH8uAE75JdCqJyi6lXMzI= k8s.io/component-base v0.28.3/go.mod h1:fDJ6vpVNSk6cRo5wmDa6eKIG7UlIQkaFmZN2fYgIUD8= k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg= k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 h1:LyMgNKD2P8Wn1iAwQU5OhxCKlKJy0sHc+PcDwFB24dQ= k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9/go.mod h1:wZK2AVp1uHCp4VamDVgBP2COHZjqD1T68Rf0CM3YjSM= k8s.io/kubectl v0.28.3 h1:H1Peu1O3EbN9zHkJCcvhiJ4NUj6lb88sGPO5wrWIM6k= k8s.io/kubectl v0.28.3/go.mod h1:RDAudrth/2wQ3Sg46fbKKl4/g+XImzvbsSRZdP2RiyE= k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 h1:qY1Ad8PODbnymg2pRbkyMT/ylpTrCM8P2RJ0yroCyIk= k8s.io/utils v0.0.0-20230406110748-d93618cff8a2/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= oras.land/oras-go v1.2.2 h1:0E9tOHUfrNH7TCDk5KU0jVBEzCqbfdyuVfGmJ7ZeRPE= oras.land/oras-go v1.2.2/go.mod h1:Apa81sKoZPpP7CDciE006tSZ0x3Q3+dOoBcMZ/aNxvw= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 h1:XX3Ajgzov2RKUdc5jW3t5jwY7Bo7dcRm+tFxT+NfgY0= sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3/go.mod h1:9n16EZKMhXBNSiUC5kSdFQJkdH3zbxS/JoO619G1VAY= sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 h1:W6cLQc5pnqM7vh3b7HvGNfXrJ/xL6BDMS0v1V/HHg5U= sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3/go.mod h1:JWP1Fj0VWGHyw3YUPjXSQnRnrwezrZSrApfX5S0nIag= sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= 07070100000035000041ED000000000000000000000002673DBE2800000000000000000000000000000000000000000000002100000000kubeshark-cli-52.3.90/helm-chart07070100000036000081A4000000000000000000000001673DBE2800000257000000000000000000000000000000000000002C00000000kubeshark-cli-52.3.90/helm-chart/Chart.yamlapiVersion: v2 name: kubeshark version: "52.3.90" description: The API Traffic Analyzer for Kubernetes home: https://kubeshark.co keywords: - kubeshark - packet capture - traffic capture - traffic analyzer - network sniffer - observability - devops - microservice - forensics - api kubeVersion: '>= 1.16.0-0' maintainers: - email: info@kubeshark.co name: Kubeshark url: https://kubeshark.co sources: - https://github.com/kubeshark/kubeshark/tree/master/helm-chart type: application icon: https://raw.githubusercontent.com/kubeshark/assets/master/logo/vector/logo.svg 07070100000037000081A4000000000000000000000001673DBE2800002A05000000000000000000000000000000000000002900000000kubeshark-cli-52.3.90/helm-chart/LICENSE Apache License Version 2.0, January 2004 https://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS Copyright 2022 Kubeshark Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. 07070100000038000081A4000000000000000000000001673DBE2800004E8E000000000000000000000000000000000000002B00000000kubeshark-cli-52.3.90/helm-chart/README.md# Helm Chart of Kubeshark ## Official Add the Helm repo for Kubeshark: ```shell helm repo add kubeshark https://helm.kubeshark.co ``` then install Kubeshark: ```shell helm install kubeshark kubeshark/kubeshark ``` ## Local Clone the repo: ```shell git clone git@github.com:kubeshark/kubeshark.git --depth 1 cd kubeshark/helm-chart ``` In case you want to clone a specific tag of the repo (e.g. `v52.3.59`): ```shell git clone git@github.com:kubeshark/kubeshark.git --depth 1 --branch <tag> cd kubeshark/helm-chart ``` > See the list of available tags here: https://github.com/kubeshark/kubeshark/tags Render the templates ```shell helm template . ``` Install Kubeshark: ```shell helm install kubeshark . ``` Uninstall Kubeshark: ```shell helm uninstall kubeshark ``` ## Port-forward Do the port forwarding: ```shell kubectl port-forward service/kubeshark-front 8899:80 ``` Visit [localhost:8899](http://localhost:8899) You can also use `kubeshark proxy` for a more stable port-forward connection. ## Add a License Key When it's necessary, you can use: ```shell --set license=YOUR_LICENSE_GOES_HERE ``` Get your license from Kubeshark's [Admin Console](https://console.kubeshark.co/). ## Installing with Ingress (EKS) enabled ```shell helm install kubeshark kubeshark/kubeshark -f values.yaml ``` Set this `value.yaml`: ```shell tap: ingress: enabled: true className: "alb" host: ks.example.com tls: [] annotations: alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:us-east-1:7..8:certificate/b...65c alb.ingress.kubernetes.io/target-type: ip alb.ingress.kubernetes.io/scheme: internet-facing ``` ## Disabling IPV6 Not all have IPV6 enabled, hence this has to be disabled as follows: ```shell helm install kubeshark kubeshark/kubeshark \ --set tap.ipv6=false ``` ## Prometheus Metrics Please refer to [metrics](./metrics.md) documentation for details. ## Override Tag, Tags, Images In addition to using a private registry, you can further override the images' tag, specific image tags and specific image names. Example for overriding image names: ```yaml docker: overrideImage: worker: docker.io/kubeshark/worker:v52.3.87 front: docker.io/kubeshark/front:v52.3.87 hub: docker.io/kubeshark/hub:v52.3.87 ``` ## Configuration | Parameter | Description | Default | |-------------------------------------------|-----------------------------------------------|---------------------------------------------------------| | `tap.docker.registry` | Docker registry to pull from | `docker.io/kubeshark` | | `tap.docker.tag` | Tag of the Docker images | `latest` | | `tap.docker.tagLocked` | Lock the Docker image tags to prevent automatic upgrades to the latest branch image version. | `true` | | `tap.docker.tagLocked` | If `false` - use latest minor tag | `true` | | `tap.docker.imagePullPolicy` | Kubernetes image pull policy | `Always` | | `tap.docker.imagePullSecrets` | Kubernetes secrets to pull the images | `[]` | | `tap.docker.overrideImage` | Can be used to directly override image names | `""` | | `tap.docker.overrideTag` | Can be used to override image tags | `""` | | `tap.proxy.hub.srvPort` | Hub server port. Change if already occupied. | `8898` | | `tap.proxy.worker.srvPort` | Worker server port. Change if already occupied.| `30001` | | `tap.proxy.front.port` | Front service port. Change if already occupied.| `8899` | | `tap.proxy.host` | Change to 0.0.0.0 top open up to the world. | `127.0.0.1` | | `tap.regex` | Target (process traffic from) pods that match regex | `.*` | | `tap.namespaces` | Target pods in namespaces | `[]` | | `tap.excludedNamespaces` | Exclude pods in namespaces | `[]` | | `tap.bpfOverride` | When using AF_PACKET as a traffic capture backend, override any existing pod targeting rules and set explicit BPF expression (e.g. `net 0.0.0.0/0`). | `[]` | | `tap.stopped` | Set to `false` to have traffic processing start automatically. When set to `true`, traffic processing is stopped by default, resulting in almost no resource consumption (e.g. Kubeshark is dormant). This property can be dynamically control via the dashboard. | `false` | | `tap.release.repo` | URL of the Helm chart repository | `https://helm.kubeshark.co` | | `tap.release.name` | Helm release name | `kubeshark` | | `tap.release.namespace` | Helm release namespace | `default` | | `tap.persistentStorage` | Use `persistentVolumeClaim` instead of `emptyDir` | `false` | | `tap.persistentStorageStatic` | Use static persistent volume provisioning (explicitly defined `PersistentVolume` ) | `false` | | `tap.efsFileSytemIdAndPath` | [EFS file system ID and, optionally, subpath and/or access point](https://github.com/kubernetes-sigs/aws-efs-csi-driver/blob/master/examples/kubernetes/access_points/README.md) `<FileSystemId>:<Path>:<AccessPointId>` | "" | | `tap.storageLimit` | Limit of either the `emptyDir` or `persistentVolumeClaim` | `500Mi` | | `tap.storageClass` | Storage class of the `PersistentVolumeClaim` | `standard` | | `tap.dryRun` | Preview of all pods matching the regex, without tapping them | `false` | | `tap.resources.hub.limits.cpu` | CPU limit for hub | `""` (no limit) | | `tap.resources.hub.limits.memory` | Memory limit for hub | `5Gi` | | `tap.resources.hub.requests.cpu` | CPU request for hub | `50m` | | `tap.resources.hub.requests.memory` | Memory request for hub | `50Mi` | | `tap.resources.sniffer.limits.cpu` | CPU limit for sniffer | `""` (no limit) | | `tap.resources.sniffer.limits.memory` | Memory limit for sniffer | `3Gi` | | `tap.resources.sniffer.requests.cpu` | CPU request for sniffer | `50m` | | `tap.resources.sniffer.requests.memory` | Memory request for sniffer | `50Mi` | | `tap.resources.tracer.limits.cpu` | CPU limit for tracer | `""` (no limit) | | `tap.resources.tracer.limits.memory` | Memory limit for tracer | `3Gi` | | `tap.resources.tracer.requests.cpu` | CPU request for tracer | `50m` | | `tap.resources.tracer.requests.memory` | Memory request for tracer | `50Mi` | | `tap.serviceMesh` | Capture traffic from service meshes like Istio, Linkerd, Consul, etc. | `true` | | `tap.tls` | Capture the encrypted/TLS traffic from cryptography libraries like OpenSSL | `true` | | `tap.disableTlsLog` | Suppress logging for TLS/eBPF | `true` | | `tap.ignoreTainted` | Whether to ignore tainted nodes | `false` | | `tap.labels` | Kubernetes labels to apply to all Kubeshark resources | `{}` | | `tap.annotations` | Kubernetes annotations to apply to all Kubeshark resources | `{}` | | `tap.nodeSelectorTerms` | Node selector terms | `[{"matchExpressions":[{"key":"kubernetes.io/os","operator":"In","values":["linux"]}]}]` | | `tap.auth.enabled` | Enable authentication | `false` | | `tap.auth.type` | Authentication type (1 option available: `saml`) | `saml` | | `tap.auth.approvedEmails` | List of approved email addresses for authentication | `[]` | | `tap.auth.approvedDomains` | List of approved email domains for authentication | `[]` | | `tap.auth.saml.idpMetadataUrl` | SAML IDP metadata URL <br/>(effective, if `tap.auth.type = saml`) | `` | | `tap.auth.saml.x509crt` | A self-signed X.509 `.cert` contents <br/>(effective, if `tap.auth.type = saml`) | `` | | `tap.auth.saml.x509key` | A self-signed X.509 `.key` contents <br/>(effective, if `tap.auth.type = saml`) | `` | | `tap.auth.saml.roleAttribute` | A SAML attribute name corresponding to user's authorization role <br/>(effective, if `tap.auth.type = saml`) | `role` | | `tap.auth.saml.roles` | A list of SAML authorization roles and their permissions <br/>(effective, if `tap.auth.type = saml`) | `{"admin":{"canDownloadPCAP":true,"canUpdateTargetedPods":true,"canUseScripting":true, "canStopTrafficCapturing":true, "filter":"","showAdminConsoleLink":true}}` | | `tap.ingress.enabled` | Enable `Ingress` | `false` | | `tap.ingress.className` | Ingress class name | `""` | | `tap.ingress.host` | Host of the `Ingress` | `ks.svc.cluster.local` | | `tap.ingress.tls` | `Ingress` TLS configuration | `[]` | | `tap.ingress.annotations` | `Ingress` annotations | `{}` | | `tap.ipv6` | Enable IPv6 support for the front-end | `true` | | `tap.debug` | Enable debug mode | `false` | | `tap.telemetry.enabled` | Enable anonymous usage statistics collection | `true` | | `tap.resourceGuard.enabled` | Enable resource guard worker process, which watches RAM/disk usage and enables/disables traffic capture based on available resources | `false` | | `tap.sentry.enabled` | Enable sending of error logs to Sentry | `false` | | `tap.sentry.environment` | Sentry environment to label error logs with | `production` | | `tap.defaultFilter` | Sets the default dashboard KFL filter (e.g. `http`). By default, this value is set to filter out noisy protocols such as DNS, UDP, ICMP and TCP. The user can easily change this in the Dashboard. You can also change this value to change this behavior. | `"!dns and !tcp and !udp and !icmp"` | | `tap.globalFilter` | Prepends to any KFL filter and can be used to limit what is visible in the dashboard. For example, `redact("request.headers.Authorization")` will redact the appropriate field. Another example `!dns` will not show any DNS traffic. | `""` | | `tap.metrics.port` | Pod port used to expose Prometheus metrics | `49100` | | `tap.enabledDissectors` | This is an array of strings representing the list of supported protocols. Remove or comment out redundant protocols (e.g., dns).| The default list excludes: `dns` and `tcp` | | `logs.file` | Logs dump path | `""` | | `pcapdump.enabled` | Enable recording of all traffic captured according to other parameters. Whatever Kubeshark captures, considering pod targeting rules, will be stored in pcap files ready to be viewed by tools | `true` | | `pcapdump.maxTime` | The time window into the past that will be stored. Older traffic will be discarded. | `2h` | | `pcapdump.maxSize` | The maximum storage size the PCAP files will consume. Old files that cause to surpass storage consumption will get discarded. | `500MB` | | `kube.configPath` | Path to the `kubeconfig` file (`$HOME/.kube/config`) | `""` | | `kube.context` | Kubernetes context to use for the deployment | `""` | | `dumpLogs` | Enable dumping of logs | `false` | | `headless` | Enable running in headless mode | `false` | | `license` | License key for the Pro/Enterprise edition | `""` | | `scripting.env` | Environment variables for the scripting | `{}` | | `scripting.source` | Source directory of the scripts | `""` | | `scripting.watchScripts` | Enable watch mode for the scripts in source directory | `true` | | `timezone` | IANA time zone applied to time shown in the front-end | `""` (local time zone applies) | | `supportChatEnabled` | Enable real-time support chat channel based on Intercom | `true` | | `internetConnectivity` | Turns off API requests that are dependant on Internet connectivity such as `telemetry` and `online-support`. | `true` | | `dissectorsUpdatingEnabled` | Turns off UI for enabling/disabling dissectors | `true` | KernelMapping pairs kernel versions with a DriverContainer image. Kernel versions can be matched literally or using a regular expression ## Installing with SAML enabled ### Prerequisites: ##### 1. Generate X.509 certificate & key (TL;DR: https://ubuntu.com/server/docs/security-certificates) **Example:** ``` openssl genrsa -out mykey.key 2048 openssl req -new -key mykey.key -out mycsr.csr openssl x509 -signkey mykey.key -in mycsr.csr -req -days 365 -out mycert.crt ``` **What you get:** - `mycert.crt` - use it for `tap.auth.saml.x509crt` - `mykey.key` - use it for `tap.auth.saml.x509crt` ##### 2. Prepare your SAML IDP You should set up the required SAML IDP (Google, Auth0, your custom IDP, etc.) During setup, an IDP provider will typically request to enter: - Metadata URL - ACS URL (Assertion Consumer Service URL, aka Callback URL) - SLO URL (Single Logout URL) Correspondingly, you will enter these (if you run the most default Kubeshark setup): - [http://localhost:8899/saml/metadata](http://localhost:8899/saml/metadata) - [http://localhost:8899/saml/acs](http://localhost:8899/saml/acs) - [http://localhost:8899/saml/slo](http://localhost:8899/saml/slo) Otherwise, if you have `tap.ingress.enabled == true`, change protocol & domain respectively - showing example domain: - [https://kubeshark.example.com/saml/metadata](https://kubeshark.example.com/saml/metadata) - [https://kubeshark.example.com/saml/acs](https://kubeshark.example.com/saml/acs) - [https://kubeshark.example.com/saml/slo](https://kubeshark.example.com/saml/slo) ```shell helm install kubeshark kubeshark/kubeshark -f values.yaml ``` Set this `value.yaml`: ```shell tap: auth: enabled: true type: saml saml: idpMetadataUrl: "https://ti..th0.com/samlp/metadata/MpWiDCM..qdnDG" x509crt: | -----BEGIN CERTIFICATE----- MIIDlTCCAn0CFFRUzMh+dZvp+FvWd4gRaiBVN8EvMA0GCSqGSIb3DQEBCwUAMIGG MSQwIgYJKoZIhvcNAQkBFhV3ZWJtYXN0ZXJAZXhhbXBsZS5jb20wHhcNMjMxMjI4 ........<redacted: please, generate your own X.509 cert>........ ZMzM7YscqZwoVhTOhrD4/5nIfOD/hTWG/MBe2Um1V1IYF8aVEllotTKTgsF6ZblA miCOgl6lIlZy -----END CERTIFICATE----- x509key: | -----BEGIN PRIVATE KEY----- MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDlgDFKsRHj+mok euOF0IpwToOEpQGtafB75ytv3psD/tQAzEIug+rkDriVvsfcvafj0qcaTeYvnCoz ........<redacted: please, generate your own X.509 key>......... sUpBCu0E3nRJM/QB2ui5KhNR7uvPSL+kSsaEq19/mXqsL+mRi9aqy2wMEvUSU/kt UaV5sbRtTzYLxpOSQyi8CEFA+A== -----END PRIVATE KEY----- ``` 07070100000039000081A4000000000000000000000001673DBE2800000935000000000000000000000000000000000000002C00000000kubeshark-cli-52.3.90/helm-chart/metrics.md# Metrics Kubeshark provides metrics from `worker` components. It can be useful for monitoring and debugging purpose. ## Configuration By default, Kubeshark uses port `49100` to expose metrics via service `kubeshark-worker-metrics`. In case you use [kube-prometheus-stack] (https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack) community Helm chart, additional scrape configuration for Kubeshark worker metrics endpoint can be configured with values: ``` prometheus: enabled: true prometheusSpec: additionalScrapeConfigs: | - job_name: 'kubeshark-worker-metrics' kubernetes_sd_configs: - role: endpoints relabel_configs: - source_labels: [__meta_kubernetes_pod_name] target_label: pod - source_labels: [__meta_kubernetes_pod_node_name] target_label: node - source_labels: [__meta_kubernetes_endpoint_port_name] action: keep regex: ^metrics$ - source_labels: [__address__, __meta_kubernetes_endpoint_port_number] action: replace regex: ([^:]+)(?::\d+)? replacement: $1:49100 target_label: __address__ - action: labelmap regex: __meta_kubernetes_service_label_(.+) ``` ## Available metrics | Name | Type | Description | | --- | --- | --- | | kubeshark_received_packets_total | Counter | Total number of packets received | | kubeshark_dropped_packets_total | Counter | Total number of packets dropped | | kubeshark_processed_bytes_total | Counter | Total number of bytes processed | | kubeshark_tcp_packets_total | Counter | Total number of TCP packets | | kubeshark_dns_packets_total | Counter | Total number of DNS packets | | kubeshark_icmp_packets_total | Counter | Total number of ICMP packets | | kubeshark_reassembled_tcp_payloads_total | Counter | Total number of reassembled TCP payloads | | kubeshark_matched_pairs_total | Counter | Total number of matched pairs | | kubeshark_dropped_tcp_streams_total | Counter | Total number of dropped TCP streams | | kubeshark_live_tcp_streams | Gauge | Number of live TCP streams | ## Ready-to-use Dashboard You can import a ready-to-use dashboard from [Grafana's Dashboards Portal](https://grafana.com/grafana/dashboards/21332-kubeshark-dashboard-v3-4/). 0707010000003A000041ED000000000000000000000002673DBE2800000000000000000000000000000000000000000000002B00000000kubeshark-cli-52.3.90/helm-chart/templates0707010000003B000081A4000000000000000000000001673DBE2800000143000000000000000000000000000000000000004300000000kubeshark-cli-52.3.90/helm-chart/templates/01-service-account.yaml--- apiVersion: v1 kind: ServiceAccount metadata: labels: {{- include "kubeshark.labels" . | nindent 4 }} annotations: {{- if .Values.tap.annotations }} {{- toYaml .Values.tap.annotations | nindent 4 }} {{- end }} name: {{ include "kubeshark.serviceAccountName" . }} namespace: {{ .Release.Namespace }} 0707010000003C000081A4000000000000000000000001673DBE2800000588000000000000000000000000000000000000004000000000kubeshark-cli-52.3.90/helm-chart/templates/02-cluster-role.yaml--- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: labels: {{- include "kubeshark.labels" . | nindent 4 }} annotations: {{- if .Values.tap.annotations }} {{- toYaml .Values.tap.annotations | nindent 4 }} {{- end }} name: kubeshark-cluster-role-{{ .Release.Namespace }} namespace: {{ .Release.Namespace }} rules: - apiGroups: - "" - extensions - apps resources: - nodes - pods - services - endpoints - persistentvolumeclaims verbs: - list - get - watch - apiGroups: - "" resources: - namespaces verbs: - get resourceNames: - kube-system - apiGroups: - networking.k8s.io resources: - networkpolicies verbs: - get - list - watch - create - update - delete --- apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: labels: {{- include "kubeshark.labels" . | nindent 4 }} annotations: {{- if .Values.tap.annotations }} {{- toYaml .Values.tap.annotations | nindent 4 }} {{- end }} name: kubeshark-self-config-role namespace: {{ .Release.Namespace }} rules: - apiGroups: - "" - v1 resourceNames: - kubeshark-secret - kubeshark-config-map resources: - secrets - configmaps verbs: - get - watch - list - update - patch 0707010000003D000081A4000000000000000000000001673DBE280000049A000000000000000000000000000000000000004800000000kubeshark-cli-52.3.90/helm-chart/templates/03-cluster-role-binding.yaml--- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: labels: {{- include "kubeshark.labels" . | nindent 4 }} annotations: {{- if .Values.tap.annotations }} {{- toYaml .Values.tap.annotations | nindent 4 }} {{- end }} name: kubeshark-cluster-role-binding-{{ .Release.Namespace }} namespace: {{ .Release.Namespace }} roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: kubeshark-cluster-role-{{ .Release.Namespace }} subjects: - kind: ServiceAccount name: {{ include "kubeshark.serviceAccountName" . }} namespace: {{ .Release.Namespace }} --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: labels: {{- include "kubeshark.labels" . | nindent 4 }} annotations: {{- if .Values.tap.annotations }} {{- toYaml .Values.tap.annotations | nindent 4 }} {{- end }} name: kubeshark-self-config-role-binding namespace: {{ .Release.Namespace }} roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: kubeshark-self-config-role subjects: - kind: ServiceAccount name: {{ include "kubeshark.serviceAccountName" . }} namespace: {{ .Release.Namespace }} 0707010000003E000081A4000000000000000000000001673DBE2800000FD0000000000000000000000000000000000000004200000000kubeshark-cli-52.3.90/helm-chart/templates/04-hub-deployment.yaml--- apiVersion: apps/v1 kind: Deployment metadata: labels: app.kubeshark.co/app: hub {{- include "kubeshark.labels" . | nindent 4 }} annotations: {{- if .Values.tap.annotations }} {{- toYaml .Values.tap.annotations | nindent 4 }} {{- end }} name: {{ include "kubeshark.name" . }}-hub namespace: {{ .Release.Namespace }} spec: replicas: 1 # Set the desired number of replicas selector: matchLabels: app.kubeshark.co/app: hub {{- include "kubeshark.selectorLabels" . | nindent 6 }} template: metadata: labels: app.kubeshark.co/app: hub {{- include "kubeshark.labels" . | nindent 8 }} spec: dnsPolicy: ClusterFirstWithHostNet serviceAccountName: {{ include "kubeshark.serviceAccountName" . }} containers: - name: hub command: - ./hub - -port - "8080" {{- if .Values.tap.debug }} - -debug {{- end }} env: - name: POD_NAME valueFrom: fieldRef: fieldPath: metadata.name - name: POD_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace - name: SENTRY_ENABLED value: '{{ (include "sentry.enabled" .) }}' - name: SENTRY_ENVIRONMENT value: '{{ .Values.tap.sentry.environment }}' - name: KUBESHARK_CLOUD_API_URL value: 'https://api.kubeshark.co' - name: PROFILING_ENABLED value: '{{ .Values.tap.pprof.enabled }}' {{- if .Values.tap.docker.overrideImage.hub }} image: '{{ .Values.tap.docker.overrideImage.hub }}' {{- else if .Values.tap.docker.overrideTag.hub }} image: '{{ .Values.tap.docker.registry }}/hub:{{ .Values.tap.docker.overrideTag.hub }}' {{ else }} image: '{{ .Values.tap.docker.registry }}/hub:{{ not (eq .Values.tap.docker.tag "") | ternary .Values.tap.docker.tag (include "kubeshark.defaultVersion" .) }}' {{- end }} imagePullPolicy: {{ .Values.tap.docker.imagePullPolicy }} {{- if .Values.tap.docker.imagePullSecrets }} imagePullSecrets: {{- range .Values.tap.docker.imagePullSecrets }} - name: {{ . }} {{- end }} {{- end }} readinessProbe: periodSeconds: 1 failureThreshold: 3 successThreshold: 1 initialDelaySeconds: 3 tcpSocket: port: 8080 livenessProbe: periodSeconds: 1 failureThreshold: 3 successThreshold: 1 initialDelaySeconds: 3 tcpSocket: port: 8080 resources: limits: {{ if ne (toString .Values.tap.resources.hub.limits.cpu) "0" }} cpu: {{ .Values.tap.resources.hub.limits.cpu }} {{ end }} {{ if ne (toString .Values.tap.resources.hub.limits.memory) "0" }} memory: {{ .Values.tap.resources.hub.limits.memory }} {{ end }} requests: {{ if ne (toString .Values.tap.resources.hub.requests.cpu) "0" }} cpu: {{ .Values.tap.resources.hub.requests.cpu }} {{ end }} {{ if ne (toString .Values.tap.resources.hub.requests.memor) "0" }} memory: {{ .Values.tap.resources.hub.requests.memory }} {{ end }} volumeMounts: - name: saml-x509-volume mountPath: "/etc/saml/x509" readOnly: true volumes: - name: saml-x509-volume projected: sources: - secret: name: kubeshark-saml-x509-crt-secret items: - key: AUTH_SAML_X509_CRT path: kubeshark.crt - secret: name: kubeshark-saml-x509-key-secret items: - key: AUTH_SAML_X509_KEY path: kubeshark.key 0707010000003F000081A4000000000000000000000001673DBE28000001C4000000000000000000000000000000000000003F00000000kubeshark-cli-52.3.90/helm-chart/templates/05-hub-service.yaml--- apiVersion: v1 kind: Service metadata: labels: app.kubeshark.co/app: hub {{- include "kubeshark.labels" . | nindent 4 }} annotations: {{- if .Values.tap.annotations }} {{- toYaml .Values.tap.annotations | nindent 4 }} {{- end }} name: kubeshark-hub namespace: {{ .Release.Namespace }} spec: ports: - name: kubeshark-hub port: 80 targetPort: 8080 selector: app.kubeshark.co/app: hub type: ClusterIP 07070100000040000081A4000000000000000000000001673DBE2800001466000000000000000000000000000000000000004400000000kubeshark-cli-52.3.90/helm-chart/templates/06-front-deployment.yamlapiVersion: apps/v1 kind: Deployment metadata: labels: app.kubeshark.co/app: front {{- include "kubeshark.labels" . | nindent 4 }} annotations: {{- if .Values.tap.annotations }} {{- toYaml .Values.tap.annotations | nindent 4 }} {{- end }} name: {{ include "kubeshark.name" . }}-front namespace: {{ .Release.Namespace }} spec: replicas: 1 # Set the desired number of replicas selector: matchLabels: app.kubeshark.co/app: front {{- include "kubeshark.selectorLabels" . | nindent 6 }} template: metadata: labels: app.kubeshark.co/app: front {{- include "kubeshark.labels" . | nindent 8 }} spec: containers: - env: - name: REACT_APP_AUTH_ENABLED value: '{{- if or (and .Values.cloudLicenseEnabled (not (empty .Values.license))) (not .Values.internetConnectivity) -}} "false" {{- else -}} {{ .Values.cloudLicenseEnabled | ternary "true" .Values.tap.auth.enabled }} {{- end }}' - name: REACT_APP_AUTH_TYPE value: '{{ not (eq .Values.tap.auth.type "") | ternary (.Values.cloudLicenseEnabled | ternary "oidc" .Values.tap.auth.type) " " }}' - name: REACT_APP_AUTH_SAML_IDP_METADATA_URL value: '{{ not (eq .Values.tap.auth.saml.idpMetadataUrl "") | ternary .Values.tap.auth.saml.idpMetadataUrl " " }}' - name: REACT_APP_TIMEZONE value: '{{ not (eq .Values.timezone "") | ternary .Values.timezone " " }}' - name: REACT_APP_SCRIPTING_DISABLED value: '{{ .Values.tap.scriptingDisabled }}' - name: REACT_APP_TARGETED_PODS_UPDATE_DISABLED value: '{{ .Values.tap.targetedPodsUpdateDisabled }}' - name: REACT_APP_PRESET_FILTERS_CHANGING_ENABLED value: '{{ .Values.tap.presetFiltersChangingEnabled }}' - name: REACT_APP_BPF_OVERRIDE_DISABLED value: '{{ eq .Values.tap.packetCapture "ebpf" | ternary "true" "false" }}' - name: REACT_APP_RECORDING_DISABLED value: '{{ .Values.tap.recordingDisabled }}' - name: REACT_APP_STOP_TRAFFIC_CAPTURING_DISABLED value: '{{- if and .Values.tap.stopTrafficCapturingDisabled .Values.tap.stopped -}} false {{- else -}} {{ .Values.tap.stopTrafficCapturingDisabled | ternary "true" "false" }} {{- end -}}' - name: 'REACT_APP_CLOUD_LICENSE_ENABLED' value: '{{- if or (and .Values.cloudLicenseEnabled (not (empty .Values.license))) (not .Values.internetConnectivity) -}} "false" {{- else -}} {{ .Values.cloudLicenseEnabled }} {{- end }}' - name: REACT_APP_SUPPORT_CHAT_ENABLED value: '{{ and .Values.supportChatEnabled .Values.internetConnectivity | ternary "true" "false" }}' - name: REACT_APP_DISSECTORS_UPDATING_ENABLED value: '{{ .Values.dissectorsUpdatingEnabled | ternary "true" "false" }}' - name: REACT_APP_SENTRY_ENABLED value: '{{ (include "sentry.enabled" .) }}' - name: REACT_APP_SENTRY_ENVIRONMENT value: '{{ .Values.tap.sentry.environment }}' {{- if .Values.tap.docker.overrideImage.front }} image: '{{ .Values.tap.docker.overrideImage.front }}' {{- else if .Values.tap.docker.overrideTag.front }} image: '{{ .Values.tap.docker.registry }}/front:{{ .Values.tap.docker.overrideTag.front }}' {{ else }} image: '{{ .Values.tap.docker.registry }}/front:{{ not (eq .Values.tap.docker.tag "") | ternary .Values.tap.docker.tag (include "kubeshark.defaultVersion" .) }}' {{- end }} imagePullPolicy: {{ .Values.tap.docker.imagePullPolicy }} {{- if .Values.tap.docker.imagePullSecrets }} imagePullSecrets: {{- range .Values.tap.docker.imagePullSecrets }} - name: {{ . }} {{- end }} {{- end }} name: kubeshark-front livenessProbe: periodSeconds: 1 failureThreshold: 3 successThreshold: 1 initialDelaySeconds: 3 tcpSocket: port: 8080 readinessProbe: periodSeconds: 1 failureThreshold: 3 successThreshold: 1 initialDelaySeconds: 3 tcpSocket: port: 8080 timeoutSeconds: 1 resources: limits: cpu: 750m memory: 1Gi requests: cpu: 50m memory: 50Mi volumeMounts: - name: nginx-config mountPath: /etc/nginx/conf.d/default.conf subPath: default.conf readOnly: true volumes: - name: nginx-config configMap: name: kubeshark-nginx-config-map dnsPolicy: ClusterFirstWithHostNet serviceAccountName: {{ include "kubeshark.serviceAccountName" . }} 07070100000041000081A4000000000000000000000001673DBE28000001AC000000000000000000000000000000000000004100000000kubeshark-cli-52.3.90/helm-chart/templates/07-front-service.yaml--- apiVersion: v1 kind: Service metadata: labels: {{- include "kubeshark.labels" . | nindent 4 }} annotations: {{- if .Values.tap.annotations }} {{- toYaml .Values.tap.annotations | nindent 4 }} {{- end }} name: kubeshark-front namespace: {{ .Release.Namespace }} spec: ports: - name: kubeshark-front port: 80 targetPort: 8080 selector: app.kubeshark.co/app: front type: ClusterIP 07070100000042000081A4000000000000000000000001673DBE2800000442000000000000000000000000000000000000004B00000000kubeshark-cli-52.3.90/helm-chart/templates/08-persistent-volume-claim.yaml--- {{- if .Values.tap.persistentStorageStatic }} apiVersion: v1 kind: PersistentVolume metadata: name: kubeshark-persistent-volume namespace: {{ .Release.Namespace }} spec: capacity: storage: {{ .Values.tap.storageLimit }} volumeMode: Filesystem accessModes: - ReadWriteMany persistentVolumeReclaimPolicy: Retain storageClassName: {{ .Values.tap.storageClass }} {{- if .Values.tap.efsFileSytemIdAndPath }} csi: driver: efs.csi.aws.com volumeHandle: {{ .Values.tap.efsFileSytemIdAndPath }} {{ end }} --- {{ end }} {{- if .Values.tap.persistentStorage }} apiVersion: v1 kind: PersistentVolumeClaim metadata: labels: {{- include "kubeshark.labels" . | nindent 4 }} annotations: {{- if .Values.tap.annotations }} {{- toYaml .Values.tap.annotations | nindent 4 }} {{- end }} name: kubeshark-persistent-volume-claim namespace: {{ .Release.Namespace }} spec: accessModes: - ReadWriteMany resources: requests: storage: {{ .Values.tap.storageLimit }} storageClassName: {{ .Values.tap.storageClass }} status: {} {{- end }} 07070100000043000081A4000000000000000000000001673DBE2800002853000000000000000000000000000000000000004500000000kubeshark-cli-52.3.90/helm-chart/templates/09-worker-daemon-set.yaml--- apiVersion: apps/v1 kind: DaemonSet metadata: labels: app.kubeshark.co/app: worker sidecar.istio.io/inject: "false" {{- include "kubeshark.labels" . | nindent 4 }} annotations: {{- if .Values.tap.annotations }} {{- toYaml .Values.tap.annotations | nindent 4 }} {{- end }} name: kubeshark-worker-daemon-set namespace: {{ .Release.Namespace }} spec: selector: matchLabels: app.kubeshark.co/app: worker {{- include "kubeshark.selectorLabels" . | nindent 6 }} template: metadata: labels: app.kubeshark.co/app: worker {{- include "kubeshark.labels" . | nindent 8 }} name: kubeshark-worker-daemon-set namespace: kubeshark spec: containers: - command: - ./worker - -i - any - -port - '{{ .Values.tap.proxy.worker.srvPort }}' - -metrics-port - '{{ .Values.tap.metrics.port }}' - -packet-capture - '{{ .Values.tap.packetCapture }}' {{- if .Values.tap.tls }} - -unixsocket {{- end }} {{- if .Values.tap.serviceMesh }} - -servicemesh {{- end }} - -procfs - /hostproc {{- if ne .Values.tap.packetCapture "ebpf" }} - -disable-ebpf {{- end }} {{- if .Values.tap.resourceGuard.enabled }} - -enable-resource-guard {{- end }} - -resolution-strategy - '{{ .Values.tap.misc.resolutionStrategy }}' - -staletimeout - '{{ .Values.tap.misc.staleTimeoutSeconds }}' {{- if .Values.tap.debug }} - -debug {{- end }} {{- if .Values.tap.docker.overrideImage.worker }} image: '{{ .Values.tap.docker.overrideImage.worker }}' {{- else if .Values.tap.docker.overrideTag.worker }} image: '{{ .Values.tap.docker.registry }}/worker:{{ .Values.tap.docker.overrideTag.worker }}{{ include "kubeshark.dockerTagDebugVersion" . }}' {{ else }} image: '{{ .Values.tap.docker.registry }}/worker:{{ not (eq .Values.tap.docker.tag "") | ternary .Values.tap.docker.tag (include "kubeshark.defaultVersion" .) }}{{ include "kubeshark.dockerTagDebugVersion" . }}' {{- end }} imagePullPolicy: {{ .Values.tap.docker.imagePullPolicy }} {{- if .Values.tap.docker.imagePullSecrets }} imagePullSecrets: {{- range .Values.tap.docker.imagePullSecrets }} - name: {{ . }} {{- end }} {{- end }} name: sniffer ports: - containerPort: {{ .Values.tap.metrics.port }} protocol: TCP name: metrics env: - name: POD_NAME valueFrom: fieldRef: fieldPath: metadata.name - name: POD_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace - name: TCP_STREAM_CHANNEL_TIMEOUT_MS value: '{{ .Values.tap.misc.tcpStreamChannelTimeoutMs }}' - name: TCP_STREAM_CHANNEL_TIMEOUT_SHOW value: '{{ .Values.tap.misc.tcpStreamChannelTimeoutShow }}' - name: KUBESHARK_CLOUD_API_URL value: 'https://api.kubeshark.co' - name: PROFILING_ENABLED value: '{{ .Values.tap.pprof.enabled }}' - name: SENTRY_ENABLED value: '{{ (include "sentry.enabled" .) }}' - name: SENTRY_ENVIRONMENT value: '{{ .Values.tap.sentry.environment }}' resources: limits: {{ if ne (toString .Values.tap.resources.sniffer.limits.cpu) "0" }} cpu: {{ .Values.tap.resources.sniffer.limits.cpu }} {{ end }} {{ if ne (toString .Values.tap.resources.sniffer.limits.memory) "0" }} memory: {{ .Values.tap.resources.sniffer.limits.memory }} {{ end }} requests: {{ if ne (toString .Values.tap.resources.sniffer.requests.cpu) "0" }} cpu: {{ .Values.tap.resources.sniffer.requests.cpu }} {{ end }} {{ if ne (toString .Values.tap.resources.sniffer.requests.memory) "0" }} memory: {{ .Values.tap.resources.sniffer.requests.memory }} {{ end }} securityContext: capabilities: add: {{- range .Values.tap.capabilities.networkCapture }} {{ print "- " . }} {{- end }} {{- if .Values.tap.serviceMesh }} {{- range .Values.tap.capabilities.serviceMeshCapture }} {{ print "- " . }} {{- end }} {{- end }} drop: - ALL readinessProbe: periodSeconds: 1 failureThreshold: 3 successThreshold: 1 initialDelaySeconds: 5 tcpSocket: port: {{ .Values.tap.proxy.worker.srvPort }} livenessProbe: periodSeconds: 1 failureThreshold: 3 successThreshold: 1 initialDelaySeconds: 5 tcpSocket: port: {{ .Values.tap.proxy.worker.srvPort }} volumeMounts: - mountPath: /hostproc name: proc readOnly: true - mountPath: /sys name: sys readOnly: true - mountPath: /app/data name: data {{- if .Values.tap.tls }} - command: - ./tracer - -procfs - /hostproc {{- if ne .Values.tap.packetCapture "ebpf" }} - -disable-ebpf {{- end }} {{- if .Values.tap.debug }} - -debug {{- end }} {{- if .Values.tap.disableTlsLog }} - -disable-tls-log {{- end }} {{- if .Values.tap.pprof.enabled }} - -port - '{{ add .Values.tap.proxy.worker.srvPort 1 }}' {{- end }} {{- if .Values.tap.docker.overrideTag.worker }} image: '{{ .Values.tap.docker.registry }}/worker:{{ .Values.tap.docker.overrideTag.worker }}{{ include "kubeshark.dockerTagDebugVersion" . }}' {{ else }} image: '{{ .Values.tap.docker.registry }}/worker:{{ not (eq .Values.tap.docker.tag "") | ternary .Values.tap.docker.tag (include "kubeshark.defaultVersion" .) }}{{ include "kubeshark.dockerTagDebugVersion" . }}' {{- end }} imagePullPolicy: {{ .Values.tap.docker.imagePullPolicy }} {{- if .Values.tap.docker.imagePullSecrets }} imagePullSecrets: {{- range .Values.tap.docker.imagePullSecrets }} - name: {{ . }} {{- end }} {{- end }} name: tracer env: - name: POD_NAME valueFrom: fieldRef: fieldPath: metadata.name - name: POD_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace - name: PROFILING_ENABLED value: '{{ .Values.tap.pprof.enabled }}' - name: SENTRY_ENABLED value: '{{ (include "sentry.enabled" .) }}' - name: SENTRY_ENVIRONMENT value: '{{ .Values.tap.sentry.environment }}' resources: limits: {{ if ne (toString .Values.tap.resources.tracer.limits.cpu) "0" }} cpu: {{ .Values.tap.resources.tracer.limits.cpu }} {{ end }} {{ if ne (toString .Values.tap.resources.tracer.limits.memory) "0" }} memory: {{ .Values.tap.resources.tracer.limits.memory }} {{ end }} requests: {{ if ne (toString .Values.tap.resources.tracer.requests.cpu) "0" }} cpu: {{ .Values.tap.resources.tracer.requests.cpu }} {{ end }} {{ if ne (toString .Values.tap.resources.tracer.requests.memory) "0" }} memory: {{ .Values.tap.resources.tracer.requests.memory }} {{ end }} securityContext: capabilities: add: {{- range .Values.tap.capabilities.ebpfCapture }} {{ print "- " . }} {{- end }} {{- range .Values.tap.capabilities.networkCapture }} {{ print "- " . }} {{- end }} drop: - ALL volumeMounts: - mountPath: /hostproc name: proc readOnly: true - mountPath: /sys name: sys readOnly: true - mountPath: /app/data name: data - mountPath: /etc/os-release name: os-release readOnly: true - mountPath: /hostroot mountPropagation: HostToContainer name: root readOnly: true {{- end }} dnsPolicy: ClusterFirstWithHostNet hostNetwork: true serviceAccountName: {{ include "kubeshark.serviceAccountName" . }} terminationGracePeriodSeconds: 0 tolerations: - effect: NoExecute operator: Exists {{- if not .Values.tap.ignoreTainted }} - effect: NoSchedule operator: Exists {{- end }} {{- if gt (len .Values.tap.nodeSelectorTerms) 0}} affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: {{- toYaml .Values.tap.nodeSelectorTerms | nindent 12 }} {{- end }} volumes: - hostPath: path: /proc name: proc - hostPath: path: /sys name: sys - name: lib-modules hostPath: path: /lib/modules - hostPath: path: /etc/os-release name: os-release - hostPath: path: / name: root - name: data {{- if .Values.tap.persistentStorage }} persistentVolumeClaim: claimName: kubeshark-persistent-volume-claim {{- else }} emptyDir: sizeLimit: {{ .Values.tap.storageLimit }} {{- end }} 07070100000044000081A4000000000000000000000001673DBE280000040C000000000000000000000000000000000000003B00000000kubeshark-cli-52.3.90/helm-chart/templates/10-ingress.yaml--- {{- if .Values.tap.ingress.enabled }} apiVersion: networking.k8s.io/v1 kind: Ingress metadata: annotations: nginx.org/websocket-services: "kubeshark-front" {{- if .Values.tap.annotations }} {{- toYaml .Values.tap.annotations | nindent 4 }} {{- end }} {{- if .Values.tap.ingress.annotations }} {{- toYaml .Values.tap.ingress.annotations | nindent 4 }} {{- end }} labels: {{- include "kubeshark.labels" . | nindent 4 }} name: kubeshark-ingress namespace: {{ .Release.Namespace }} spec: {{- if .Values.tap.ingress.className }} ingressClassName: {{ .Values.tap.ingress.className }} {{- end }} rules: - host: {{ .Values.tap.ingress.host }} http: paths: - backend: service: name: kubeshark-front port: number: 80 path: / pathType: Prefix {{- if .Values.tap.ingress.tls }} tls: {{- toYaml .Values.tap.ingress.tls | nindent 2 }} {{- end }} status: loadBalancer: {} {{- end }} 07070100000045000081A4000000000000000000000001673DBE28000006B1000000000000000000000000000000000000004400000000kubeshark-cli-52.3.90/helm-chart/templates/11-nginx-config-map.yaml--- apiVersion: v1 kind: ConfigMap metadata: name: kubeshark-nginx-config-map namespace: {{ .Release.Namespace }} labels: {{- include "kubeshark.labels" . | nindent 4 }} data: default.conf: | server { listen 8080; {{- if .Values.tap.ipv6 }} listen [::]:8080; {{- end }} access_log /dev/stdout; error_log /dev/stdout; client_body_buffer_size 64k; client_header_buffer_size 32k; large_client_header_buffers 8 64k; location /api { rewrite ^/api(.*)$ $1 break; proxy_pass http://kubeshark-hub; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header Host $http_host; proxy_set_header Upgrade websocket; proxy_set_header Connection Upgrade; proxy_set_header Authorization $http_authorization; proxy_pass_header Authorization; proxy_connect_timeout 4s; proxy_read_timeout 120s; proxy_send_timeout 12s; proxy_pass_request_headers on; } location /saml { rewrite ^/saml(.*)$ /saml$1 break; proxy_pass http://kubeshark-hub; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header Host $http_host; proxy_connect_timeout 4s; proxy_read_timeout 120s; proxy_send_timeout 12s; proxy_pass_request_headers on; } location / { root /usr/share/nginx/html; index index.html index.htm; try_files $uri $uri/ /index.html; expires -1; add_header Cache-Control no-cache; } error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } } 07070100000046000081A4000000000000000000000001673DBE2800000F11000000000000000000000000000000000000003E00000000kubeshark-cli-52.3.90/helm-chart/templates/12-config-map.yamlkind: ConfigMap apiVersion: v1 metadata: name: kubeshark-config-map namespace: {{ .Release.Namespace }} labels: app.kubeshark.co/app: hub {{- include "kubeshark.labels" . | nindent 4 }} data: POD_REGEX: '{{ .Values.tap.regex }}' NAMESPACES: '{{ gt (len .Values.tap.namespaces) 0 | ternary (join "," .Values.tap.namespaces) "" }}' EXCLUDED_NAMESPACES: '{{ gt (len .Values.tap.excludedNamespaces) 0 | ternary (join "," .Values.tap.excludedNamespaces) "" }}' BPF_OVERRIDE: '{{ .Values.tap.bpfOverride }}' STOPPED: '{{ .Values.tap.stopped | ternary "true" "false" }}' SCRIPTING_SCRIPTS: '{}' SCRIPTING_ACTIVE_SCRIPTS: '{{ gt (len .Values.scripting.active) 0 | ternary (join "," .Values.scripting.active) "" }}' INGRESS_ENABLED: '{{ .Values.tap.ingress.enabled }}' INGRESS_HOST: '{{ .Values.tap.ingress.host }}' PROXY_FRONT_PORT: '{{ .Values.tap.proxy.front.port }}' AUTH_ENABLED: '{{- if and .Values.cloudLicenseEnabled (not (empty .Values.license)) -}} "false" {{- else -}} {{ .Values.cloudLicenseEnabled | ternary "true" (.Values.tap.auth.enabled | ternary "true" "") }} {{- end }}' AUTH_TYPE: '{{ .Values.cloudLicenseEnabled | ternary "oidc" (.Values.tap.auth.type) }}' AUTH_SAML_IDP_METADATA_URL: '{{ .Values.tap.auth.saml.idpMetadataUrl }}' AUTH_SAML_ROLE_ATTRIBUTE: '{{ .Values.tap.auth.saml.roleAttribute }}' AUTH_SAML_ROLES: '{{ .Values.tap.auth.saml.roles | toJson }}' TELEMETRY_DISABLED: '{{ not .Values.internetConnectivity | ternary "true" (not .Values.tap.telemetry.enabled | ternary "true" "false") }}' SCRIPTING_DISABLED: '{{ .Values.tap.scriptingDisabled | ternary "true" "" }}' TARGETED_PODS_UPDATE_DISABLED: '{{ .Values.tap.targetedPodsUpdateDisabled | ternary "true" "" }}' PRESET_FILTERS_CHANGING_ENABLED: '{{ .Values.tap.presetFiltersChangingEnabled | ternary "true" "" }}' RECORDING_DISABLED: '{{ .Values.tap.recordingDisabled | ternary "true" "" }}' STOP_TRAFFIC_CAPTURING_DISABLED: '{{- if and .Values.tap.stopTrafficCapturingDisabled .Values.tap.stopped -}} false {{- else -}} {{ .Values.tap.stopTrafficCapturingDisabled | ternary "true" "false" }} {{- end }}' GLOBAL_FILTER: {{ include "kubeshark.escapeDoubleQuotes" .Values.tap.globalFilter | quote }} DEFAULT_FILTER: {{ include "kubeshark.escapeDoubleQuotes" .Values.tap.defaultFilter | quote }} TRAFFIC_SAMPLE_RATE: '{{ .Values.tap.misc.trafficSampleRate }}' JSON_TTL: '{{ .Values.tap.misc.jsonTTL }}' PCAP_TTL: '{{ .Values.tap.misc.pcapTTL }}' PCAP_ERROR_TTL: '{{ .Values.tap.misc.pcapErrorTTL }}' TIMEZONE: '{{ not (eq .Values.timezone "") | ternary .Values.timezone " " }}' CLOUD_LICENSE_ENABLED: '{{- if and .Values.cloudLicenseEnabled (not (empty .Values.license)) -}} false {{- else -}} {{ .Values.cloudLicenseEnabled }} {{- end }}' DUPLICATE_TIMEFRAME: '{{ .Values.tap.misc.duplicateTimeframe }}' ENABLED_DISSECTORS: '{{ gt (len .Values.tap.enabledDissectors) 0 | ternary (join "," .Values.tap.enabledDissectors) "" }}' DISSECTORS_UPDATING_ENABLED: '{{ .Values.dissectorsUpdatingEnabled | ternary "true" "false" }}' DETECT_DUPLICATES: '{{ .Values.tap.misc.detectDuplicates | ternary "true" "false" }}' PCAP_DUMP_ENABLE: '{{ .Values.pcapdump.enabled }}' PCAP_TIME_INTERVAL: '{{ .Values.pcapdump.timeInterval }}' PCAP_MAX_TIME: '{{ .Values.pcapdump.maxTime }}' PCAP_MAX_SIZE: '{{ .Values.pcapdump.maxSize }}' PCAP_SRC_DIR: '{{ .Values.pcapdump.pcapSrcDir }}' 07070100000047000081A4000000000000000000000001673DBE280000038B000000000000000000000000000000000000003A00000000kubeshark-cli-52.3.90/helm-chart/templates/13-secret.yamlkind: Secret apiVersion: v1 metadata: name: kubeshark-secret namespace: {{ .Release.Namespace }} labels: app.kubeshark.co/app: hub {{- include "kubeshark.labels" . | nindent 4 }} stringData: LICENSE: '{{ .Values.license }}' SCRIPTING_ENV: '{{ .Values.scripting.env | toJson }}' --- kind: Secret apiVersion: v1 metadata: name: kubeshark-saml-x509-crt-secret namespace: {{ .Release.Namespace }} labels: app.kubeshark.co/app: hub {{- include "kubeshark.labels" . | nindent 4 }} stringData: AUTH_SAML_X509_CRT: | {{ .Values.tap.auth.saml.x509crt | nindent 4 }} --- kind: Secret apiVersion: v1 metadata: name: kubeshark-saml-x509-key-secret namespace: {{ .Release.Namespace }} labels: app.kubeshark.co/app: hub {{- include "kubeshark.labels" . | nindent 4 }} stringData: AUTH_SAML_X509_KEY: | {{ .Values.tap.auth.saml.x509key | nindent 4 }} --- 07070100000048000081A4000000000000000000000001673DBE2800000476000000000000000000000000000000000000005A00000000kubeshark-cli-52.3.90/helm-chart/templates/14-openshift-security-context-constraints.yaml{{- if .Capabilities.APIVersions.Has "security.openshift.io/v1/SecurityContextConstraints" }} apiVersion: security.openshift.io/v1 kind: SecurityContextConstraints metadata: labels: {{- include "kubeshark.labels" . | nindent 4 }} annotations: "helm.sh/hook": pre-install {{- if .Values.tap.annotations }} {{- toYaml .Values.tap.annotations | nindent 4 }} {{- end }} name: kubeshark-scc priority: 10 allowPrivilegedContainer: true allowHostDirVolumePlugin: true allowHostNetwork: true allowHostPorts: true allowHostPID: true allowHostIPC: true readOnlyRootFilesystem: false requiredDropCapabilities: - MKNOD allowedCapabilities: - NET_RAW - NET_ADMIN - SYS_ADMIN - SYS_PTRACE - DAC_OVERRIDE - SYS_RESOURCE - SYS_MODULE - IPC_LOCK runAsUser: type: RunAsAny fsGroup: type: MustRunAs seLinuxContext: type: RunAsAny supplementalGroups: type: RunAsAny seccompProfiles: - '*' volumes: - configMap - downwardAPI - emptyDir - persistentVolumeClaim - secret - hostPath - projected - ephemeral users: - system:serviceaccount:{{ .Release.Namespace }}:kubeshark-service-account {{- end }} 07070100000049000081A4000000000000000000000001673DBE280000026C000000000000000000000000000000000000004A00000000kubeshark-cli-52.3.90/helm-chart/templates/15-worker-service-metrics.yaml--- kind: Service apiVersion: v1 metadata: labels: {{- include "kubeshark.labels" . | nindent 4 }} annotations: prometheus.io/scrape: 'true' prometheus.io/port: '{{ .Values.tap.metrics.port }}' {{- if .Values.tap.annotations }} {{- toYaml .Values.tap.annotations | nindent 4 }} {{- end }} name: kubeshark-worker-metrics namespace: {{ .Release.Namespace }} spec: selector: app.kubeshark.co/app: worker {{- include "kubeshark.labels" . | nindent 4 }} ports: - name: metrics protocol: TCP port: {{ .Values.tap.metrics.port }} targetPort: {{ .Values.tap.metrics.port }} 0707010000004A000081A4000000000000000000000001673DBE280000068D000000000000000000000000000000000000004400000000kubeshark-cli-52.3.90/helm-chart/templates/16-network-policies.yamlapiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: labels: {{- include "kubeshark.labels" . | nindent 4 }} annotations: {{- if .Values.tap.annotations }} {{- toYaml .Values.tap.annotations | nindent 4 }} {{- end }} name: kubeshark-hub-network-policy namespace: {{ .Release.Namespace }} spec: podSelector: matchLabels: app.kubeshark.co/app: hub policyTypes: - Ingress - Egress ingress: - ports: - protocol: TCP port: 8080 egress: - {} --- apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: labels: {{- include "kubeshark.labels" . | nindent 4 }} annotations: {{- if .Values.tap.annotations }} {{- toYaml .Values.tap.annotations | nindent 4 }} {{- end }} name: kubeshark-front-network-policy namespace: {{ .Release.Namespace }} spec: podSelector: matchLabels: app.kubeshark.co/app: front policyTypes: - Ingress - Egress ingress: - ports: - protocol: TCP port: 8080 egress: - {} --- apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: labels: {{- include "kubeshark.labels" . | nindent 4 }} annotations: {{- if .Values.tap.annotations }} {{- toYaml .Values.tap.annotations | nindent 4 }} {{- end }} name: kubeshark-worker-network-policy namespace: {{ .Release.Namespace }} spec: podSelector: matchLabels: app.kubeshark.co/app: worker policyTypes: - Ingress - Egress ingress: - ports: - protocol: TCP port: {{ .Values.tap.proxy.worker.srvPort }} - protocol: TCP port: {{ .Values.tap.metrics.port }} egress: - {} 0707010000004B000081A4000000000000000000000001673DBE280000056D000000000000000000000000000000000000003500000000kubeshark-cli-52.3.90/helm-chart/templates/NOTES.txtThank you for installing {{ title .Chart.Name }}. Registry: {{ .Values.tap.docker.registry }} Tag: {{ not (eq .Values.tap.docker.tag "") | ternary .Values.tap.docker.tag (printf "v%s" .Chart.Version) }} {{- if .Values.tap.docker.overrideTag.worker }} Overridden worker tag: {{ .Values.tap.docker.overrideTag.worker }} {{ end }} {{- if .Values.tap.docker.overrideTag.hub }} Overridden hub tag: {{ .Values.tap.docker.overrideTag.hub }} {{ end }} {{- if .Values.tap.docker.overrideTag.front }} Overridden front tag: {{ .Values.tap.docker.overrideTag.front }} {{ end }} Your deployment has been successful. The release is named `{{ .Release.Name }}` and it has been deployed in the `{{ .Release.Namespace }}` namespace. {{- if .Values.tap.telemetry.enabled }} Notice: Telemetry is enabled. Kubeshark will collect anonymous usage statistics. {{ end }} {{- if .Values.tap.ingress.enabled }} You can now access the application through the following URL: http{{ if .Values.tap.ingress.tls }}s{{ end }}://{{ .Values.tap.ingress.host }} {{- else }} To access the application, follow these steps: 1. Perform port forwarding with the following commands: kubectl port-forward -n {{ .Release.Namespace }} service/kubeshark-front 8899:80 2. Once port forwarding is done, you can access the application by visiting the following URL in your web browser: http://0.0.0.0:8899 {{ end }} 0707010000004C000081A4000000000000000000000001673DBE2800000950000000000000000000000000000000000000003800000000kubeshark-cli-52.3.90/helm-chart/templates/_helpers.tpl{{/* Expand the name of the chart. */}} {{- define "kubeshark.name" -}} {{- .Release.Name | trunc 63 | trimSuffix "-" }} {{- end }} {{/* Create a default fully qualified app name. We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). If release name contains chart name it will be used as a full name. */}} {{- define "kubeshark.fullname" -}} {{- printf "%s-%s" .Release.Name .Chart.Name | trunc 63 | trimSuffix "-" }} {{- end }} {{/* Create chart name and version as used by the chart label. */}} {{- define "kubeshark.chart" -}} {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} {{- end }} {{/* Common labels */}} {{- define "kubeshark.labels" -}} helm.sh/chart: {{ include "kubeshark.chart" . }} {{ include "kubeshark.selectorLabels" . }} app.kubernetes.io/version: {{ .Chart.Version | quote }} app.kubernetes.io/managed-by: {{ .Release.Service }} {{- if .Values.tap.labels }} {{ toYaml .Values.tap.labels }} {{- end }} {{- end }} {{/* Selector labels */}} {{- define "kubeshark.selectorLabels" -}} app.kubernetes.io/name: {{ include "kubeshark.name" . }} app.kubernetes.io/instance: {{ .Release.Name }} {{- end }} {{/* Create the name of the service account to use */}} {{- define "kubeshark.serviceAccountName" -}} {{- printf "%s-service-account" .Release.Name }} {{- end }} {{/* Escape double quotes in a string */}} {{- define "kubeshark.escapeDoubleQuotes" -}} {{- regexReplaceAll "\"" . "\"" -}} {{- end -}} {{/* Define debug docker tag suffix */}} {{- define "kubeshark.dockerTagDebugVersion" -}} {{- .Values.tap.pprof.enabled | ternary "-debug" "" }} {{- end -}} {{/* Create docker tag default version */}} {{- define "kubeshark.defaultVersion" -}} {{- $defaultVersion := (printf "v%s" .Chart.Version) -}} {{- if not .Values.tap.docker.tagLocked }} {{- $defaultVersion = regexReplaceAll "^([^.]+\\.[^.]+).*" $defaultVersion "$1" -}} {{- end }} {{- $defaultVersion }} {{- end -}} {{/* Set sentry based on internet connectivity and telemetry */}} {{- define "sentry.enabled" -}} {{- $sentryEnabledVal := .Values.tap.sentry.enabled -}} {{- if not .Values.internetConnectivity -}} {{- $sentryEnabledVal = false -}} {{- else if not .Values.tap.telemetry.enabled -}} {{- $sentryEnabledVal = false -}} {{- end -}} {{- $sentryEnabledVal -}} {{- end -}} 0707010000004D000081A4000000000000000000000001673DBE2800000D6D000000000000000000000000000000000000002D00000000kubeshark-cli-52.3.90/helm-chart/values.yaml# find a detailed description here: https://github.com/kubeshark/kubeshark/blob/master/helm-chart/README.md tap: docker: registry: docker.io/kubeshark tag: "" tagLocked: true imagePullPolicy: Always imagePullSecrets: [] overrideImage: worker: "" hub: "" front: "" overrideTag: worker: "" hub: "" front: "" proxy: worker: srvPort: 30001 hub: srvPort: 8898 front: port: 8899 host: 127.0.0.1 regex: .* namespaces: [] excludedNamespaces: [] bpfOverride: "" stopped: false release: repo: https://helm.kubeshark.co name: kubeshark namespace: default persistentStorage: false persistentStorageStatic: false efsFileSytemIdAndPath: "" storageLimit: 5000Mi storageClass: standard dryRun: false resources: hub: limits: cpu: "0" memory: 5Gi requests: cpu: 50m memory: 50Mi sniffer: limits: cpu: "0" memory: 5Gi requests: cpu: 50m memory: 50Mi tracer: limits: cpu: "0" memory: 5Gi requests: cpu: 50m memory: 50Mi serviceMesh: true tls: true disableTlsLog: true packetCapture: best ignoreTainted: false labels: {} annotations: {} nodeSelectorTerms: - matchExpressions: - key: kubernetes.io/os operator: In values: - linux auth: enabled: false type: saml saml: idpMetadataUrl: "" x509crt: "" x509key: "" roleAttribute: role roles: admin: filter: "" canDownloadPCAP: true canUseScripting: true canUpdateTargetedPods: true canStopTrafficCapturing: true showAdminConsoleLink: true ingress: enabled: false className: "" host: ks.svc.cluster.local tls: [] annotations: {} ipv6: true debug: false telemetry: enabled: true resourceGuard: enabled: false sentry: enabled: false environment: production defaultFilter: "!dns and !tcp and !udp and !icmp" scriptingDisabled: false targetedPodsUpdateDisabled: false presetFiltersChangingEnabled: true recordingDisabled: false stopTrafficCapturingDisabled: false capabilities: networkCapture: - NET_RAW - NET_ADMIN serviceMeshCapture: - SYS_ADMIN - SYS_PTRACE - DAC_OVERRIDE ebpfCapture: - SYS_ADMIN - SYS_PTRACE - SYS_RESOURCE - IPC_LOCK globalFilter: "" enabledDissectors: - amqp - dns - http - icmp - kafka - redis - sctp - syscall - ws - tls metrics: port: 49100 pprof: enabled: false port: 8000 view: flamegraph misc: jsonTTL: 5m pcapTTL: 10s pcapErrorTTL: 60s trafficSampleRate: 100 tcpStreamChannelTimeoutMs: 10000 tcpStreamChannelTimeoutShow: false resolutionStrategy: auto duplicateTimeframe: 200ms detectDuplicates: false staleTimeoutSeconds: 30 logs: file: "" grep: "" pcapdump: enabled: true timeInterval: 1m maxTime: 1h maxSize: 500MB pcapSrcDir: pcapdump kube: configPath: "" context: "" dumpLogs: false headless: false license: "" cloudLicenseEnabled: true supportChatEnabled: true internetConnectivity: true dissectorsUpdatingEnabled: true scripting: env: {} source: "" sources: [] watchScripts: true active: [] console: true timezone: "" 0707010000004E000081A4000000000000000000000001673DBE2800000BF2000000000000000000000000000000000000002100000000kubeshark-cli-52.3.90/install.sh#!/bin/sh EXE_NAME=kubeshark ALIAS_NAME=ks PROG_NAME=Kubeshark INSTALL_PATH=/usr/local/bin/$EXE_NAME ALIAS_PATH=/usr/local/bin/$ALIAS_NAME REPO=https://github.com/kubeshark/kubeshark OS=$(echo $(uname -s) | tr '[:upper:]' '[:lower:]') ARCH=$(echo $(uname -m) | tr '[:upper:]' '[:lower:]') SUPPORTED_PAIRS="linux_amd64 linux_arm64 darwin_amd64 darwin_arm64" ESC="\033[" F_DEFAULT=39 F_RED=31 F_GREEN=32 F_YELLOW=33 B_DEFAULT=49 B_RED=41 B_BLUE=44 B_LIGHT_BLUE=104 if [ "$ARCH" = "x86_64" ]; then ARCH="amd64" fi if [ "$ARCH" = "aarch64" ]; then ARCH="arm64" fi echo $SUPPORTED_PAIRS | grep -w -q "${OS}_${ARCH}" if [ $? != 0 ] ; then echo "\n${ESC}${F_RED}m🛑 Unsupported OS \"$OS\" or architecture \"$ARCH\". Failed to install $PROG_NAME.${ESC}${F_DEFAULT}m" echo "${ESC}${B_RED}mPlease report 🐛 to $REPO/issues${ESC}${F_DEFAULT}m" exit 1 fi # Check for Homebrew and kubeshark installation if command -v brew >/dev/null; then if brew list kubeshark &>/dev/null; then echo "📦 Found $PROG_NAME instance installed with Homebrew" echo "${ESC}${F_GREEN}m⬇️ Removing before installation with script${ESC}${F_DEFAULT}m" brew uninstall kubeshark fi fi echo "\n🦈 ${ESC}${F_DEFAULT};${B_BLUE}m Started to download $PROG_NAME ${ESC}${B_DEFAULT};${F_DEFAULT}m" if curl -# --fail -Lo $EXE_NAME ${REPO}/releases/latest/download/${EXE_NAME}_${OS}_${ARCH} ; then chmod +x $PWD/$EXE_NAME echo "\n${ESC}${F_GREEN}m⬇️ $PROG_NAME is downloaded into $PWD/$EXE_NAME${ESC}${F_DEFAULT}m" else echo "\n${ESC}${F_RED}m🛑 Couldn't download ${REPO}/releases/latest/download/${EXE_NAME}_${OS}_${ARCH}\n\ ⚠️ Check your internet connection.\n\ ⚠️ Make sure 'curl' command is available.\n\ ⚠️ Make sure there is no directory named '${EXE_NAME}' in ${PWD}\n\ ${ESC}${F_DEFAULT}m" echo "${ESC}${B_RED}mPlease report 🐛 to $REPO/issues${ESC}${F_DEFAULT}m" exit 1 fi use_cmd=$EXE_NAME printf "Do you want to install system-wide? Requires sudo 😇 (y/N)? " old_stty_cfg=$(stty -g) stty raw -echo ; answer=$(head -c 1) ; stty $old_stty_cfg if echo "$answer" | grep -iq "^y" ;then echo "$answer" sudo mv ./$EXE_NAME $INSTALL_PATH || exit 1 echo "${ESC}${F_GREEN}m$PROG_NAME is installed into $INSTALL_PATH${ESC}${F_DEFAULT}m\n" ls $ALIAS_PATH >> /dev/null 2>&1 if [ $? != 0 ] ; then printf "Do you want to add 'ks' alias for Kubeshark? (y/N)? " old_stty_cfg=$(stty -g) stty raw -echo ; answer=$(head -c 1) ; stty $old_stty_cfg if echo "$answer" | grep -iq "^y" ; then echo "$answer" sudo ln -s $INSTALL_PATH $ALIAS_PATH use_cmd=$ALIAS_NAME else echo "$answer" fi else use_cmd=$ALIAS_NAME fi else echo "$answer" use_cmd="./$EXE_NAME" fi echo "${ESC}${F_GREEN}m✅ You can use the ${ESC}${F_DEFAULT};${B_LIGHT_BLUE}m $use_cmd ${ESC}${B_DEFAULT};${F_GREEN}m command now.${ESC}${F_DEFAULT}m" echo "\n${ESC}${F_YELLOW}mPlease give us a star 🌟 on ${ESC}${F_DEFAULT}m$REPO${ESC}${F_YELLOW}m if you ❤️ $PROG_NAME!${ESC}${F_DEFAULT}m" 0707010000004F000041ED000000000000000000000002673DBE2800000000000000000000000000000000000000000000001F00000000kubeshark-cli-52.3.90/internal07070100000050000041ED000000000000000000000002673DBE2800000000000000000000000000000000000000000000002700000000kubeshark-cli-52.3.90/internal/connect07070100000051000081A4000000000000000000000001673DBE28000010B1000000000000000000000000000000000000002E00000000kubeshark-cli-52.3.90/internal/connect/hub.gopackage connect import ( "bytes" "encoding/json" "fmt" "io" "net/http" "net/url" "os" "time" "github.com/kubeshark/kubeshark/config" "github.com/kubeshark/kubeshark/utils" "github.com/rs/zerolog/log" v1 "k8s.io/api/core/v1" ) type Connector struct { url string retries int client *http.Client } const DefaultRetries = 3 const DefaultTimeout = 2 * time.Second const DefaultSleep = 1 * time.Second func NewConnector(url string, retries int, timeout time.Duration) *Connector { return &Connector{ url: url, retries: retries, client: &http.Client{ Timeout: timeout, }, } } func (connector *Connector) TestConnection(path string) error { retriesLeft := connector.retries for retriesLeft > 0 { if isReachable, err := connector.isReachable(path); err != nil || !isReachable { log.Debug().Str("url", connector.url).Err(err).Msg("Not ready yet!") } else { log.Debug().Str("url", connector.url).Msg("Connection test passed successfully.") break } retriesLeft -= 1 time.Sleep(5 * DefaultSleep) } if retriesLeft == 0 { return fmt.Errorf("Couldn't reach the URL: %s after %d retries!", connector.url, connector.retries) } return nil } func (connector *Connector) isReachable(path string) (bool, error) { targetUrl := fmt.Sprintf("%s%s", connector.url, path) if _, err := utils.Get(targetUrl, connector.client); err != nil { return false, err } else { return true, nil } } func (connector *Connector) PostWorkerPodToHub(pod *v1.Pod) { postWorkerUrl := fmt.Sprintf("%s/pods/worker", connector.url) if podMarshalled, err := json.Marshal(pod); err != nil { log.Error().Err(err).Msg("Failed to marshal the Worker pod:") } else { ok := false for !ok { var resp *http.Response if resp, err = utils.Post(postWorkerUrl, "application/json", bytes.NewBuffer(podMarshalled), connector.client, config.Config.License); err != nil || resp.StatusCode != http.StatusOK { if _, ok := err.(*url.Error); ok { break } log.Warn().Err(err).Msg("Failed sending the Worker pod to Hub. Retrying...") } else { log.Debug().Interface("worker-pod", pod).Msg("Reported worker pod to Hub:") return } time.Sleep(DefaultSleep) } } } type postLicenseRequest struct { License string `json:"license"` } func (connector *Connector) PostLicense(license string) { postLicenseUrl := fmt.Sprintf("%s/license", connector.url) payload := postLicenseRequest{ License: license, } if payloadMarshalled, err := json.Marshal(payload); err != nil { log.Error().Err(err).Msg("Failed to marshal the payload:") } else { ok := false for !ok { var resp *http.Response if resp, err = utils.Post(postLicenseUrl, "application/json", bytes.NewBuffer(payloadMarshalled), connector.client, config.Config.License); err != nil || resp.StatusCode != http.StatusOK { if _, ok := err.(*url.Error); ok { break } log.Warn().Err(err).Msg("Failed sending the license to Hub. Retrying...") } else { log.Debug().Str("license", license).Msg("Reported license to Hub:") return } time.Sleep(DefaultSleep) } } } func (connector *Connector) PostPcapsMerge(out *os.File) { postEnvUrl := fmt.Sprintf("%s/pcaps/merge", connector.url) if envMarshalled, err := json.Marshal(map[string]string{"query": ""}); err != nil { log.Error().Err(err).Msg("Failed to marshal the env:") } else { ok := false for !ok { var resp *http.Response if resp, err = utils.Post(postEnvUrl, "application/json", bytes.NewBuffer(envMarshalled), connector.client, config.Config.License); err != nil || resp.StatusCode != http.StatusOK { if _, ok := err.(*url.Error); ok { break } log.Warn().Err(err).Msg("Failed exported PCAP download. Retrying...") } else { defer resp.Body.Close() // Check server response if resp.StatusCode != http.StatusOK { log.Error().Str("status", resp.Status).Err(err).Msg("Failed exported PCAP download.") return } // Writer the body to file _, err = io.Copy(out, resp.Body) if err != nil { log.Error().Err(err).Msg("Failed writing PCAP export:") return } log.Info().Str("path", out.Name()).Msg("Downloaded exported PCAP:") return } time.Sleep(DefaultSleep) } } } 07070100000052000081ED000000000000000000000001673DBE2800000265000000000000000000000000000000000000002100000000kubeshark-cli-52.3.90/kubectl.sh#!/bin/bash # Useful kubectl commands for Kubeshark development # This command outputs all Kubernetes resources using YAML format and pipes it to VS Code if [ $1 = "view-all-resources" ] ; then kubectl get $(kubectl api-resources | awk '{print $1}' | tail -n +2 | tr '\n' ',' | sed s/,\$//) -o yaml | code - fi # This command outputs all Kubernetes resources in "kubeshark" namespace using YAML format and pipes it to VS Code if [[ $1 = "view-kubeshark-resources" ]] ; then kubectl get $(kubectl api-resources | awk '{print $1}' | tail -n +2 | tr '\n' ',' | sed s/,\$//) -n kubeshark -o yaml | code - fi 07070100000053000041ED000000000000000000000002673DBE2800000000000000000000000000000000000000000000002100000000kubeshark-cli-52.3.90/kubernetes07070100000054000081A4000000000000000000000001673DBE28000010B8000000000000000000000000000000000000002B00000000kubeshark-cli-52.3.90/kubernetes/config.gopackage kubernetes import ( "context" "encoding/json" "slices" "strings" "github.com/kubeshark/kubeshark/config" "github.com/kubeshark/kubeshark/misc" "github.com/rs/zerolog/log" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) const ( SUFFIX_SECRET = "secret" SUFFIX_CONFIG_MAP = "config-map" SECRET_LICENSE = "LICENSE" CONFIG_POD_REGEX = "POD_REGEX" CONFIG_NAMESPACES = "NAMESPACES" CONFIG_EXCLUDED_NAMESPACES = "EXCLUDED_NAMESPACES" CONFIG_SCRIPTING_ENV = "SCRIPTING_ENV" CONFIG_INGRESS_ENABLED = "INGRESS_ENABLED" CONFIG_INGRESS_HOST = "INGRESS_HOST" CONFIG_PROXY_FRONT_PORT = "PROXY_FRONT_PORT" CONFIG_AUTH_ENABLED = "AUTH_ENABLED" CONFIG_AUTH_TYPE = "AUTH_TYPE" CONFIG_AUTH_SAML_IDP_METADATA_URL = "AUTH_SAML_IDP_METADATA_URL" CONFIG_SCRIPTING_SCRIPTS = "SCRIPTING_SCRIPTS" CONFIG_SCRIPTING_ACTIVE_SCRIPTS = "SCRIPTING_ACTIVE_SCRIPTS" CONFIG_PCAP_DUMP_ENABLE = "PCAP_DUMP_ENABLE" CONFIG_TIME_INTERVAL = "TIME_INTERVAL" CONFIG_MAX_TIME = "MAX_TIME" CONFIG_MAX_SIZE = "MAX_SIZE" ) func SetSecret(provider *Provider, key string, value string) (updated bool, err error) { var secret *v1.Secret secret, err = provider.clientSet.CoreV1().Secrets(config.Config.Tap.Release.Namespace).Get(context.TODO(), SELF_RESOURCES_PREFIX+SUFFIX_SECRET, metav1.GetOptions{}) if err != nil { return } if secret.StringData[key] != value { updated = true } secret.Data[key] = []byte(value) _, err = provider.clientSet.CoreV1().Secrets(config.Config.Tap.Release.Namespace).Update(context.TODO(), secret, metav1.UpdateOptions{}) if err == nil { if updated { log.Info().Str("secret", key).Str("value", value).Msg("Updated:") } } else { log.Error().Str("secret", key).Err(err).Send() } return } func GetConfig(provider *Provider, key string) (value string, err error) { var configMap *v1.ConfigMap configMap, err = provider.clientSet.CoreV1().ConfigMaps(config.Config.Tap.Release.Namespace).Get(context.TODO(), SELF_RESOURCES_PREFIX+SUFFIX_CONFIG_MAP, metav1.GetOptions{}) if err != nil { return } value = configMap.Data[key] return } func SetConfig(provider *Provider, key string, value string) (updated bool, err error) { var configMap *v1.ConfigMap configMap, err = provider.clientSet.CoreV1().ConfigMaps(config.Config.Tap.Release.Namespace).Get(context.TODO(), SELF_RESOURCES_PREFIX+SUFFIX_CONFIG_MAP, metav1.GetOptions{}) if err != nil { return } if configMap.Data[key] != value { updated = true } configMap.Data[key] = value _, err = provider.clientSet.CoreV1().ConfigMaps(config.Config.Tap.Release.Namespace).Update(context.TODO(), configMap, metav1.UpdateOptions{}) if err == nil { if updated { log.Info(). Str("config", key). Str("value", func() string { if len(value) > 10 { return value[:10] } return value }()). Int("length", len(value)). Msg("Updated. Printing only 10 first characters of value:") } } else { log.Error().Str("config", key).Err(err).Send() } return } func ConfigGetScripts(provider *Provider) (scripts map[int64]misc.ConfigMapScript, err error) { var data string data, err = GetConfig(provider, CONFIG_SCRIPTING_SCRIPTS) if err != nil { return } err = json.Unmarshal([]byte(data), &scripts) return } func IsActiveScript(provider *Provider, title string) bool { configActiveScripts, err := GetConfig(provider, CONFIG_SCRIPTING_ACTIVE_SCRIPTS) if err != nil { return false } return strings.Contains(configActiveScripts, title) } func DeleteActiveScriptByTitle(provider *Provider, title string) (err error) { configActiveScripts, err := GetConfig(provider, CONFIG_SCRIPTING_ACTIVE_SCRIPTS) if err != nil { return err } activeScripts := strings.Split(configActiveScripts, ",") idx := slices.Index(activeScripts, title) if idx != -1 { activeScripts = slices.Delete(activeScripts, idx, idx+1) _, err = SetConfig(provider, CONFIG_SCRIPTING_ACTIVE_SCRIPTS, strings.Join(activeScripts, ",")) if err != nil { return err } } return nil } 07070100000055000081A4000000000000000000000001673DBE2800000194000000000000000000000000000000000000002B00000000kubeshark-cli-52.3.90/kubernetes/consts.gopackage kubernetes const ( SELF_RESOURCES_PREFIX = "kubeshark-" FrontPodName = SELF_RESOURCES_PREFIX + "front" FrontServiceName = FrontPodName HubPodName = SELF_RESOURCES_PREFIX + "hub" HubServiceName = HubPodName K8sAllNamespaces = "" MinKubernetesServerVersion = "1.16.0" AppLabelKey = "app.kubeshark.co/app" ) 07070100000056000081A4000000000000000000000001673DBE2800000F8E000000000000000000000000000000000000002700000000kubeshark-cli-52.3.90/kubernetes/cp.gopackage kubernetes import ( "archive/tar" "bufio" "context" "fmt" "io" "os" "path" "path/filepath" "strings" "github.com/rs/zerolog/log" v1 "k8s.io/api/core/v1" "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/tools/remotecommand" ) func CopyFromPod(ctx context.Context, provider *Provider, pod v1.Pod, srcPath string, dstPath string) error { const containerName = "sniffer" cmdArr := []string{"tar", "cf", "-", srcPath} req := provider.clientSet.CoreV1().RESTClient(). Post(). Namespace(pod.Namespace). Resource("pods"). Name(pod.Name). SubResource("exec"). VersionedParams(&v1.PodExecOptions{ Container: containerName, Command: cmdArr, Stdin: true, Stdout: true, Stderr: true, TTY: false, }, scheme.ParameterCodec) exec, err := remotecommand.NewSPDYExecutor(&provider.clientConfig, "POST", req.URL()) if err != nil { return err } reader, outStream := io.Pipe() errReader, errStream := io.Pipe() go logErrors(errReader, pod) go func() { defer outStream.Close() err = exec.StreamWithContext(ctx, remotecommand.StreamOptions{ Stdin: os.Stdin, Stdout: outStream, Stderr: errStream, Tty: false, }) if err != nil { log.Error().Err(err).Str("pod", pod.Name).Msg("SPDYExecutor:") } }() prefix := getPrefix(srcPath) prefix = path.Clean(prefix) prefix = stripPathShortcuts(prefix) dstPath = path.Join(dstPath, path.Base(prefix)) err = untarAll(reader, dstPath, prefix) // fo(reader) return err } // func fo(fi io.Reader) { // fo, err := os.Create("output.tar") // if err != nil { // panic(err) // } // // make a buffer to keep chunks that are read // buf := make([]byte, 1024) // for { // // read a chunk // n, err := fi.Read(buf) // if err != nil && err != io.EOF { // panic(err) // } // if n == 0 { // break // } // // write a chunk // if _, err := fo.Write(buf[:n]); err != nil { // panic(err) // } // } // } func logErrors(reader io.Reader, pod v1.Pod) { r := bufio.NewReader(reader) for { msg, _, err := r.ReadLine() log.Warn().Str("pod", pod.Name).Str("msg", string(msg)).Msg("SPDYExecutor:") if err != nil { if err != io.EOF { log.Error().Err(err).Send() } return } } } func untarAll(reader io.Reader, destDir, prefix string) error { tarReader := tar.NewReader(reader) for { header, err := tarReader.Next() if err != nil { if err != io.EOF { return err } break } if !strings.HasPrefix(header.Name, prefix) { return fmt.Errorf("tar contents corrupted") } mode := header.FileInfo().Mode() destFileName := filepath.Join(destDir, header.Name[len(prefix):]) baseName := filepath.Dir(destFileName) if err := os.MkdirAll(baseName, 0755); err != nil { return err } if header.FileInfo().IsDir() { if err := os.MkdirAll(destFileName, 0755); err != nil { return err } continue } evaledPath, err := filepath.EvalSymlinks(baseName) if err != nil { return err } if mode&os.ModeSymlink != 0 { linkname := header.Linkname if !filepath.IsAbs(linkname) { _ = filepath.Join(evaledPath, linkname) } if err := os.Symlink(linkname, destFileName); err != nil { return err } } else { outFile, err := os.Create(destFileName) if err != nil { return err } defer outFile.Close() if _, err := io.Copy(outFile, tarReader); err != nil { return err } if err := outFile.Close(); err != nil { return err } } } return nil } func getPrefix(file string) string { return strings.TrimLeft(file, "/") } func stripPathShortcuts(p string) string { newPath := p trimmed := strings.TrimPrefix(newPath, "../") for trimmed != newPath { newPath = trimmed trimmed = strings.TrimPrefix(newPath, "../") } // trim leftover {".", ".."} if newPath == "." || newPath == ".." { newPath = "" } if len(newPath) > 0 && string(newPath[0]) == "/" { return newPath[1:] } return newPath } 07070100000057000081A4000000000000000000000001673DBE28000002CD000000000000000000000000000000000000002B00000000kubeshark-cli-52.3.90/kubernetes/errors.gopackage kubernetes type K8sTapManagerErrorReason string const ( TapManagerWorkerUpdateError K8sTapManagerErrorReason = "WORKER_UPDATE_ERROR" TapManagerPodWatchError K8sTapManagerErrorReason = "POD_WATCH_ERROR" TapManagerPodListError K8sTapManagerErrorReason = "POD_LIST_ERROR" ) type K8sTapManagerError struct { OriginalError error TapManagerReason K8sTapManagerErrorReason } // K8sTapManagerError implements the Error interface. func (e *K8sTapManagerError) Error() string { return e.OriginalError.Error() } type ClusterBehindProxyError struct{} // ClusterBehindProxyError implements the Error interface. func (e *ClusterBehindProxyError) Error() string { return "Cluster is behind proxy" } 07070100000058000081A4000000000000000000000001673DBE28000004C6000000000000000000000000000000000000003500000000kubeshark-cli-52.3.90/kubernetes/eventWatchHelper.gopackage kubernetes import ( "context" "regexp" "strings" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/watch" ) type EventWatchHelper struct { kubernetesProvider *Provider NameRegexFilter *regexp.Regexp Kind string } func NewEventWatchHelper(kubernetesProvider *Provider, NameRegexFilter *regexp.Regexp, kind string) *EventWatchHelper { return &EventWatchHelper{ kubernetesProvider: kubernetesProvider, NameRegexFilter: NameRegexFilter, Kind: kind, } } // Implements the EventFilterer Interface func (wh *EventWatchHelper) Filter(wEvent *WatchEvent) (bool, error) { event, err := wEvent.ToEvent() if err != nil { return false, nil } if !wh.NameRegexFilter.MatchString(event.Name) { return false, nil } if !strings.EqualFold(event.Regarding.Kind, wh.Kind) { return false, nil } return true, nil } // Implements the WatchCreator Interface func (wh *EventWatchHelper) NewWatcher(ctx context.Context, namespace string) (watch.Interface, error) { watcher, err := wh.kubernetesProvider.clientSet.EventsV1().Events(namespace).Watch(ctx, metav1.ListOptions{Watch: true}) if err != nil { return nil, err } return watcher, nil } 07070100000059000041ED000000000000000000000002673DBE2800000000000000000000000000000000000000000000002600000000kubeshark-cli-52.3.90/kubernetes/helm0707010000005A000081A4000000000000000000000001673DBE2800001233000000000000000000000000000000000000002E00000000kubeshark-cli-52.3.90/kubernetes/helm/helm.gopackage helm import ( "encoding/json" "fmt" "os" "path/filepath" "regexp" "strings" "github.com/kubeshark/kubeshark/config" "github.com/kubeshark/kubeshark/misc" "github.com/pkg/errors" "github.com/rs/zerolog/log" "helm.sh/helm/v3/pkg/action" "helm.sh/helm/v3/pkg/chart" "helm.sh/helm/v3/pkg/chart/loader" "helm.sh/helm/v3/pkg/cli" "helm.sh/helm/v3/pkg/downloader" "helm.sh/helm/v3/pkg/getter" "helm.sh/helm/v3/pkg/kube" "helm.sh/helm/v3/pkg/registry" "helm.sh/helm/v3/pkg/release" "helm.sh/helm/v3/pkg/repo" ) const ENV_HELM_DRIVER = "HELM_DRIVER" var settings = cli.New() type Helm struct { repo string releaseName string releaseNamespace string } func NewHelm(repo string, releaseName string, releaseNamespace string) *Helm { return &Helm{ repo: repo, releaseName: releaseName, releaseNamespace: releaseNamespace, } } func parseOCIRef(chartRef string) (string, string, error) { refTagRegexp := regexp.MustCompile(`^(oci://[^:]+(:[0-9]{1,5})?[^:]+):(.*)$`) caps := refTagRegexp.FindStringSubmatch(chartRef) if len(caps) != 4 { return "", "", errors.Errorf("improperly formatted oci chart reference: %s", chartRef) } chartRef = caps[1] tag := caps[3] return chartRef, tag, nil } func (h *Helm) Install() (rel *release.Release, err error) { kubeConfigPath := config.Config.KubeConfigPath() actionConfig := new(action.Configuration) if err = actionConfig.Init(kube.GetConfig(kubeConfigPath, "", h.releaseNamespace), h.releaseNamespace, os.Getenv(ENV_HELM_DRIVER), func(format string, v ...interface{}) { log.Info().Msgf(format, v...) }); err != nil { return } client := action.NewInstall(actionConfig) client.Namespace = h.releaseNamespace client.ReleaseName = h.releaseName chartPath := os.Getenv(fmt.Sprintf("%s_HELM_CHART_PATH", strings.ToUpper(misc.Program))) if chartPath == "" { var chartURL string chartURL, err = repo.FindChartInRepoURL(h.repo, h.releaseName, "", "", "", "", getter.All(&cli.EnvSettings{})) if err != nil { return } var cp string cp, err = client.ChartPathOptions.LocateChart(chartURL, settings) if err != nil { return } m := &downloader.Manager{ Out: os.Stdout, ChartPath: cp, Keyring: client.ChartPathOptions.Keyring, SkipUpdate: false, Getters: getter.All(settings), RepositoryConfig: settings.RepositoryConfig, RepositoryCache: settings.RepositoryCache, Debug: settings.Debug, } dl := downloader.ChartDownloader{ Out: m.Out, Verify: m.Verify, Keyring: m.Keyring, RepositoryConfig: m.RepositoryConfig, RepositoryCache: m.RepositoryCache, RegistryClient: m.RegistryClient, Getters: m.Getters, Options: []getter.Option{ getter.WithInsecureSkipVerifyTLS(false), }, } repoPath := filepath.Dir(m.ChartPath) err = os.MkdirAll(repoPath, os.ModePerm) if err != nil { return } version := "" if registry.IsOCI(chartURL) { chartURL, version, err = parseOCIRef(chartURL) if err != nil { return } dl.Options = append(dl.Options, getter.WithRegistryClient(m.RegistryClient), getter.WithTagName(version)) } log.Info(). Str("url", chartURL). Str("repo-path", repoPath). Msg("Downloading Helm chart:") if _, _, err = dl.DownloadTo(chartURL, version, repoPath); err != nil { return } chartPath = m.ChartPath } var chart *chart.Chart chart, err = loader.Load(chartPath) if err != nil { return } log.Info(). Str("release", chart.Metadata.Name). Str("version", chart.Metadata.Version). Strs("source", chart.Metadata.Sources). Str("kube-version", chart.Metadata.KubeVersion). Msg("Installing using Helm:") var configMarshalled []byte configMarshalled, err = json.Marshal(config.Config) if err != nil { return } var configUnmarshalled map[string]interface{} err = json.Unmarshal(configMarshalled, &configUnmarshalled) if err != nil { return } rel, err = client.Run(chart, configUnmarshalled) if err != nil { return } return } func (h *Helm) Uninstall() (resp *release.UninstallReleaseResponse, err error) { kubeConfigPath := config.Config.KubeConfigPath() actionConfig := new(action.Configuration) if err = actionConfig.Init(kube.GetConfig(kubeConfigPath, "", h.releaseNamespace), h.releaseNamespace, os.Getenv(ENV_HELM_DRIVER), func(format string, v ...interface{}) { log.Info().Msgf(format, v...) }); err != nil { return } client := action.NewUninstall(actionConfig) resp, err = client.Run(h.releaseName) if err != nil { return } return } 0707010000005B000081A4000000000000000000000001673DBE2800000410000000000000000000000000000000000000003300000000kubeshark-cli-52.3.90/kubernetes/podWatchHelper.gopackage kubernetes import ( "context" "regexp" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/watch" ) type PodWatchHelper struct { kubernetesProvider *Provider NameRegexFilter *regexp.Regexp } func NewPodWatchHelper(kubernetesProvider *Provider, NameRegexFilter *regexp.Regexp) *PodWatchHelper { return &PodWatchHelper{ kubernetesProvider: kubernetesProvider, NameRegexFilter: NameRegexFilter, } } // Implements the EventFilterer Interface func (wh *PodWatchHelper) Filter(wEvent *WatchEvent) (bool, error) { pod, err := wEvent.ToPod() if err != nil { return false, nil } if !wh.NameRegexFilter.MatchString(pod.Name) { return false, nil } return true, nil } // Implements the WatchCreator Interface func (wh *PodWatchHelper) NewWatcher(ctx context.Context, namespace string) (watch.Interface, error) { watcher, err := wh.kubernetesProvider.clientSet.CoreV1().Pods(namespace).Watch(ctx, metav1.ListOptions{Watch: true}) if err != nil { return nil, err } return watcher, nil } 0707010000005C000081A4000000000000000000000001673DBE2800002565000000000000000000000000000000000000002D00000000kubeshark-cli-52.3.90/kubernetes/provider.gopackage kubernetes import ( "bufio" "bytes" "context" "fmt" "io" "net/url" "path/filepath" "regexp" "strings" "github.com/kubeshark/kubeshark/config" "github.com/kubeshark/kubeshark/misc" "github.com/kubeshark/kubeshark/semver" "github.com/kubeshark/kubeshark/utils" "github.com/rs/zerolog/log" "github.com/tanqiangyes/grep-go/reader" core "k8s.io/api/core/v1" k8serrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/version" "k8s.io/client-go/kubernetes" _ "k8s.io/client-go/plugin/pkg/client/auth" "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" ) type Provider struct { clientSet *kubernetes.Clientset kubernetesConfig clientcmd.ClientConfig clientConfig rest.Config managedBy string createdBy string } func NewProvider(kubeConfigPath string, contextName string) (*Provider, error) { kubernetesConfig := loadKubernetesConfiguration(kubeConfigPath, contextName) restClientConfig, err := kubernetesConfig.ClientConfig() if err != nil { if clientcmd.IsEmptyConfig(err) { return nil, fmt.Errorf("couldn't find the kube config file, or file is empty (%s)\n"+ "you can set alternative kube config file path by adding the kube-config-path field to the %s config file, err: %w", kubeConfigPath, misc.Program, err) } if clientcmd.IsConfigurationInvalid(err) { return nil, fmt.Errorf("invalid kube config file (%s)\n"+ "you can set alternative kube config file path by adding the kube-config-path field to the %s config file, err: %w", kubeConfigPath, misc.Program, err) } return nil, fmt.Errorf("error while using kube config (%s)\n"+ "you can set alternative kube config file path by adding the kube-config-path field to the %s config file, err: %w", kubeConfigPath, misc.Program, err) } clientSet, err := getClientSet(restClientConfig) if err != nil { return nil, fmt.Errorf("error while using kube config (%s)\n"+ "you can set alternative kube config file path by adding the kube-config-path field to the %s config file, err: %w", kubeConfigPath, misc.Program, err) } log.Debug(). Str("host", restClientConfig.Host). Str("api-path", restClientConfig.APIPath). Str("user-agent", restClientConfig.UserAgent). Msg("K8s client config.") return &Provider{ clientSet: clientSet, kubernetesConfig: kubernetesConfig, clientConfig: *restClientConfig, managedBy: misc.Program, createdBy: misc.Program, }, nil } func (provider *Provider) DoesServiceExist(ctx context.Context, namespace string, name string) (bool, error) { serviceResource, err := provider.clientSet.CoreV1().Services(namespace).Get(ctx, name, metav1.GetOptions{}) return provider.doesResourceExist(serviceResource, err) } func (provider *Provider) doesResourceExist(resource interface{}, err error) (bool, error) { // Getting NotFound error is the expected behavior when a resource does not exist. if k8serrors.IsNotFound(err) { return false, nil } if err != nil { return false, err } return resource != nil, nil } func (provider *Provider) listPodsImpl(ctx context.Context, regex *regexp.Regexp, namespaces []string, listOptions metav1.ListOptions) ([]core.Pod, error) { var pods []core.Pod for _, namespace := range namespaces { namespacePods, err := provider.clientSet.CoreV1().Pods(namespace).List(ctx, listOptions) if err != nil { return nil, fmt.Errorf("failed to get pods in ns: [%s], %w", namespace, err) } pods = append(pods, namespacePods.Items...) } matchingPods := make([]core.Pod, 0) for _, pod := range pods { if regex.MatchString(pod.Name) { matchingPods = append(matchingPods, pod) } } return matchingPods, nil } func (provider *Provider) ListAllPodsMatchingRegex(ctx context.Context, regex *regexp.Regexp, namespaces []string) ([]core.Pod, error) { return provider.listPodsImpl(ctx, regex, namespaces, metav1.ListOptions{}) } func (provider *Provider) ListAllRunningPodsMatchingRegex(ctx context.Context, regex *regexp.Regexp, namespaces []string) ([]core.Pod, error) { pods, err := provider.ListAllPodsMatchingRegex(ctx, regex, namespaces) if err != nil { return nil, err } matchingPods := make([]core.Pod, 0) for _, pod := range pods { if IsPodRunning(&pod) { matchingPods = append(matchingPods, pod) } } return matchingPods, nil } func (provider *Provider) ListPodsByAppLabel(ctx context.Context, namespaces string, labels map[string]string) ([]core.Pod, error) { pods, err := provider.clientSet.CoreV1().Pods(namespaces).List(ctx, metav1.ListOptions{ LabelSelector: metav1.FormatLabelSelector( &metav1.LabelSelector{ MatchLabels: labels, }, ), }) if err != nil { return nil, err } return pods.Items, err } func (provider *Provider) GetPodLogs(ctx context.Context, namespace string, podName string, containerName string, grep string) (string, error) { podLogOpts := core.PodLogOptions{Container: containerName} req := provider.clientSet.CoreV1().Pods(namespace).GetLogs(podName, &podLogOpts) podLogs, err := req.Stream(ctx) if err != nil { return "", fmt.Errorf("error opening log stream on ns: %s, pod: %s, %w", namespace, podName, err) } defer podLogs.Close() buf := new(bytes.Buffer) if _, err = io.Copy(buf, podLogs); err != nil { return "", fmt.Errorf("error copy information from podLogs to buf, ns: %s, pod: %s, %w", namespace, podName, err) } if grep != "" { finder, err := reader.NewFinder(grep, true, true) if err != nil { panic(err) } read, err := reader.NewStdReader(bufio.NewReader(buf), []reader.Finder{finder}) if err != nil { panic(err) } read.Run() result := read.Result()[0] log.Info().Str("namespace", namespace).Str("pod", podName).Str("container", containerName).Int("lines", len(result.Lines)).Str("grep", grep).Send() return strings.Join(result.MatchString, "\n"), nil } else { log.Info().Str("namespace", namespace).Str("pod", podName).Str("container", containerName).Send() return buf.String(), nil } } func (provider *Provider) GetNamespaceEvents(ctx context.Context, namespace string) (string, error) { eventList, err := provider.clientSet.CoreV1().Events(namespace).List(ctx, metav1.ListOptions{}) if err != nil { return "", fmt.Errorf("error getting events on ns: %s, %w", namespace, err) } return eventList.String(), nil } // ValidateNotProxy We added this after a customer tried to run kubeshark from lens, which used len's kube config, which have cluster server configuration, which points to len's local proxy. // The workaround was to use the user's local default kube config. // For now - we are blocking the option to run kubeshark through a proxy to k8s server func (provider *Provider) ValidateNotProxy() error { kubernetesUrl, err := url.Parse(provider.clientConfig.Host) if err != nil { log.Debug().Err(err).Msg("While parsing Kubernetes host!") return nil } restProxyClientConfig, _ := provider.kubernetesConfig.ClientConfig() restProxyClientConfig.Host = kubernetesUrl.Host clientProxySet, err := getClientSet(restProxyClientConfig) if err == nil { proxyServerVersion, err := clientProxySet.ServerVersion() if err != nil { return nil } if *proxyServerVersion == (version.Info{}) { return &ClusterBehindProxyError{} } } return nil } func (provider *Provider) GetKubernetesVersion() (*semver.SemVersion, error) { serverVersion, err := provider.clientSet.ServerVersion() if err != nil { log.Debug().Err(err).Msg("While getting Kubernetes server version!") return nil, err } serverVersionSemVer := semver.SemVersion(serverVersion.GitVersion) return &serverVersionSemVer, nil } func (provider *Provider) GetNamespaces() (namespaces []string) { if len(config.Config.Tap.Namespaces) > 0 { namespaces = utils.Unique(config.Config.Tap.Namespaces) } else { namespaceList, err := provider.clientSet.CoreV1().Namespaces().List(context.TODO(), metav1.ListOptions{}) if err != nil { log.Error().Err(err).Send() return } for _, ns := range namespaceList.Items { namespaces = append(namespaces, ns.Name) } } namespaces = utils.Diff(namespaces, config.Config.Tap.ExcludedNamespaces) return } func (provider *Provider) GetClientSet() *kubernetes.Clientset { return provider.clientSet } func getClientSet(config *rest.Config) (*kubernetes.Clientset, error) { clientSet, err := kubernetes.NewForConfig(config) if err != nil { return nil, err } return clientSet, nil } func ValidateKubernetesVersion(serverVersionSemVer *semver.SemVersion) error { minKubernetesServerVersionSemVer := semver.SemVersion(MinKubernetesServerVersion) if minKubernetesServerVersionSemVer.GreaterThan(*serverVersionSemVer) { return fmt.Errorf("kubernetes server version %v is not supported, supporting only kubernetes server version of %v or higher", serverVersionSemVer, MinKubernetesServerVersion) } return nil } func loadKubernetesConfiguration(kubeConfigPath string, context string) clientcmd.ClientConfig { configPathList := filepath.SplitList(kubeConfigPath) configLoadingRules := &clientcmd.ClientConfigLoadingRules{} if len(configPathList) <= 1 { configLoadingRules.ExplicitPath = kubeConfigPath } else { configLoadingRules.Precedence = configPathList } contextName := context return clientcmd.NewNonInteractiveDeferredLoadingClientConfig( configLoadingRules, &clientcmd.ConfigOverrides{ CurrentContext: contextName, }, ) } func IsPodRunning(pod *core.Pod) bool { return pod.Status.Phase == core.PodRunning } 0707010000005D000081A4000000000000000000000001673DBE28000016D2000000000000000000000000000000000000002A00000000kubeshark-cli-52.3.90/kubernetes/proxy.gopackage kubernetes import ( "bytes" "context" "fmt" "net" "net/http" "net/url" "regexp" "strings" "time" "github.com/kubeshark/kubeshark/config" "github.com/rs/zerolog/log" "k8s.io/apimachinery/pkg/util/httpstream" "k8s.io/client-go/tools/portforward" "k8s.io/client-go/transport/spdy" "k8s.io/kubectl/pkg/proxy" ) const k8sProxyApiPrefix = "/" const selfServicePort = 80 func StartProxy(kubernetesProvider *Provider, proxyHost string, srcPort uint16, selfNamespace string, selfServiceName string) (*http.Server, error) { log.Info(). Str("proxy-host", proxyHost). Str("namespace", selfNamespace). Str("service", selfServiceName). Int("src-port", int(srcPort)). Msg("Starting proxy...") filter := &proxy.FilterServer{ AcceptPaths: proxy.MakeRegexpArrayOrDie(proxy.DefaultPathAcceptRE), RejectPaths: proxy.MakeRegexpArrayOrDie(proxy.DefaultPathRejectRE), AcceptHosts: proxy.MakeRegexpArrayOrDie("^.*"), RejectMethods: proxy.MakeRegexpArrayOrDie(proxy.DefaultMethodRejectRE), } proxyHandler, err := proxy.NewProxyHandler(k8sProxyApiPrefix, filter, &kubernetesProvider.clientConfig, time.Second*2, false) if err != nil { return nil, err } mux := http.NewServeMux() mux.Handle(k8sProxyApiPrefix, getRerouteHttpHandlerSelfAPI(proxyHandler, selfNamespace, selfServiceName)) mux.Handle("/static/", getRerouteHttpHandlerSelfStatic(proxyHandler, selfNamespace, selfServiceName)) l, err := net.Listen("tcp", fmt.Sprintf("%s:%d", proxyHost, int(srcPort))) if err != nil { return nil, err } server := &http.Server{ Handler: mux, } go func() { if err := server.Serve(l); err != nil && err != http.ErrServerClosed { log.Error().Err(err).Msg("While creating proxy!") return } }() return server, nil } func getSelfHubProxiedHostAndPath(selfNamespace string, selfServiceName string) string { return fmt.Sprintf("/api/v1/namespaces/%s/services/%s:%d/proxy", selfNamespace, selfServiceName, selfServicePort) } func GetProxyOnPort(port uint16) string { return fmt.Sprintf("http://%s:%d", config.Config.Tap.Proxy.Host, port) } func GetHubUrl() string { return fmt.Sprintf("%s/api", GetProxyOnPort(config.Config.Tap.Proxy.Front.Port)) } func getRerouteHttpHandlerSelfAPI(proxyHandler http.Handler, selfNamespace string, selfServiceName string) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Access-Control-Allow-Origin", "*") w.Header().Set("Access-Control-Allow-Credentials", "true") w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With, x-session-token") w.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS, GET, PUT, DELETE") if r.Method == "OPTIONS" { w.WriteHeader(http.StatusNoContent) return } proxiedPath := getSelfHubProxiedHostAndPath(selfNamespace, selfServiceName) //avoid redirecting several times if !strings.Contains(r.URL.Path, proxiedPath) { r.URL.Path = fmt.Sprintf("%s%s", getSelfHubProxiedHostAndPath(selfNamespace, selfServiceName), r.URL.Path) } proxyHandler.ServeHTTP(w, r) }) } func getRerouteHttpHandlerSelfStatic(proxyHandler http.Handler, selfNamespace string, selfServiceName string) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { r.URL.Path = strings.Replace(r.URL.Path, "/static/", fmt.Sprintf("%s/static/", getSelfHubProxiedHostAndPath(selfNamespace, selfServiceName)), 1) proxyHandler.ServeHTTP(w, r) }) } func NewPortForward(kubernetesProvider *Provider, namespace string, podRegex *regexp.Regexp, srcPort uint16, dstPort uint16, ctx context.Context) (*portforward.PortForwarder, error) { pods, err := kubernetesProvider.ListPodsByAppLabel(ctx, namespace, map[string]string{AppLabelKey: "front"}) if err != nil { return nil, err } else if len(pods) == 0 { return nil, fmt.Errorf("didn't find pod to port-forward") } podName := pods[0].Name log.Info(). Str("namespace", namespace). Str("pod", podName). Int("src-port", int(srcPort)). Int("dst-port", int(dstPort)). Msg("Starting proxy using port-forward method...") dialer, err := getHttpDialer(kubernetesProvider, namespace, podName) if err != nil { return nil, err } stopChan, readyChan := make(chan struct{}, 1), make(chan struct{}, 1) out, errOut := new(bytes.Buffer), new(bytes.Buffer) forwarder, err := portforward.New(dialer, []string{fmt.Sprintf("%d:%d", srcPort, dstPort)}, stopChan, readyChan, out, errOut) if err != nil { return nil, err } go func() { if err = forwarder.ForwardPorts(); err != nil { log.Error().Err(err).Msg("While Kubernetes port-forwarding!") log.Info().Str("command", fmt.Sprintf("kubectl port-forward -n %s service/kubeshark-front 8899:80", config.Config.Tap.Release.Namespace)).Msg("Please try running:") return } }() return forwarder, nil } func getHttpDialer(kubernetesProvider *Provider, namespace string, podName string) (httpstream.Dialer, error) { roundTripper, upgrader, err := spdy.RoundTripperFor(&kubernetesProvider.clientConfig) if err != nil { log.Error().Err(err).Msg("While creating HTTP dialer!") return nil, err } clientConfigHostUrl, err := url.Parse(kubernetesProvider.clientConfig.Host) if err != nil { return nil, fmt.Errorf("Failed parsing client config host URL %s, error %w", kubernetesProvider.clientConfig.Host, err) } path := fmt.Sprintf("%s/api/v1/namespaces/%s/pods/%s/portforward", clientConfigHostUrl.Path, namespace, podName) serverURL := url.URL{Scheme: "https", Path: path, Host: clientConfigHostUrl.Host} log.Debug(). Str("url", serverURL.String()). Msg("HTTP dialer URL:") return spdy.NewDialer(upgrader, &http.Client{Transport: roundTripper}, http.MethodPost, &serverURL), nil } 0707010000005E000081A4000000000000000000000001673DBE2800000912000000000000000000000000000000000000002A00000000kubeshark-cli-52.3.90/kubernetes/watch.gopackage kubernetes import ( "context" "errors" "fmt" "sync" "time" "github.com/kubeshark/kubeshark/debounce" "github.com/rs/zerolog/log" "k8s.io/apimachinery/pkg/watch" ) type EventFilterer interface { Filter(*WatchEvent) (bool, error) } type WatchCreator interface { NewWatcher(ctx context.Context, namespace string) (watch.Interface, error) } func FilteredWatch(ctx context.Context, watcherCreator WatchCreator, targetNamespaces []string, filterer EventFilterer) (<-chan *WatchEvent, <-chan error) { eventChan := make(chan *WatchEvent) errorChan := make(chan error) var wg sync.WaitGroup for _, targetNamespace := range targetNamespaces { wg.Add(1) go func(targetNamespace string) { defer wg.Done() watchRestartDebouncer := debounce.NewDebouncer(1*time.Minute, func() {}) for { watcher, err := watcherCreator.NewWatcher(ctx, targetNamespace) if err != nil { errorChan <- fmt.Errorf("error in k8s watch: %v", err) break } err = startWatchLoop(ctx, watcher, filterer, eventChan) // blocking watcher.Stop() select { case <-ctx.Done(): return default: break } if err != nil { errorChan <- fmt.Errorf("error in k8s watch: %v", err) break } else { if !watchRestartDebouncer.IsOn() { if err := watchRestartDebouncer.SetOn(); err != nil { log.Error().Err(err).Send() } log.Warn().Msg("K8s watch channel closed, restarting watcher...") time.Sleep(time.Second * 5) continue } else { errorChan <- errors.New("K8s watch unstable, closes frequently") break } } } }(targetNamespace) } go func() { <-ctx.Done() wg.Wait() close(eventChan) close(errorChan) }() return eventChan, errorChan } func startWatchLoop(ctx context.Context, watcher watch.Interface, filterer EventFilterer, eventChan chan<- *WatchEvent) error { resultChan := watcher.ResultChan() for { select { case e, isChannelOpen := <-resultChan: if !isChannelOpen { return nil } wEvent := WatchEvent(e) if wEvent.Type == watch.Error { return wEvent.ToError() } if pass, err := filterer.Filter(&wEvent); err != nil { return err } else if !pass { continue } eventChan <- &wEvent case <-ctx.Done(): return nil } } } 0707010000005F000081A4000000000000000000000001673DBE2800000442000000000000000000000000000000000000002F00000000kubeshark-cli-52.3.90/kubernetes/watchEvent.gopackage kubernetes import ( "fmt" "reflect" corev1 "k8s.io/api/core/v1" eventsv1 "k8s.io/api/events/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/watch" ) const ( EventAdded = watch.Added EventModified = watch.Modified EventDeleted = watch.Deleted EventBookmark = watch.Bookmark EventError = watch.Error ) type InvalidObjectType struct { RequestedType reflect.Type } // Implements the error interface func (iot *InvalidObjectType) Error() string { return fmt.Sprintf("Cannot convert event to type %s", iot.RequestedType) } type WatchEvent watch.Event func (we *WatchEvent) ToPod() (*corev1.Pod, error) { pod, ok := we.Object.(*corev1.Pod) if !ok { return nil, &InvalidObjectType{RequestedType: reflect.TypeOf(pod)} } return pod, nil } func (we *WatchEvent) ToEvent() (*eventsv1.Event, error) { event, ok := we.Object.(*eventsv1.Event) if !ok { return nil, &InvalidObjectType{RequestedType: reflect.TypeOf(event)} } return event, nil } func (we *WatchEvent) ToError() error { return apierrors.FromObject(we.Object) } 07070100000060000081A4000000000000000000000001673DBE280000026D000000000000000000000000000000000000002300000000kubeshark-cli-52.3.90/kubeshark.gopackage main import ( "os" "strconv" "time" "github.com/kubeshark/kubeshark/cmd" "github.com/rs/zerolog" "github.com/rs/zerolog/log" ) func main() { zerolog.SetGlobalLevel(zerolog.InfoLevel) // Short caller (file:line) zerolog.CallerMarshalFunc = func(pc uintptr, file string, line int) string { short := file for i := len(file) - 1; i > 0; i-- { if file[i] == '/' { short = file[i+1:] break } } file = short return file + ":" + strconv.Itoa(line) } log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr, TimeFormat: time.RFC3339}).With().Caller().Logger() cmd.Execute() } 07070100000061000041ED000000000000000000000002673DBE2800000000000000000000000000000000000000000000002000000000kubeshark-cli-52.3.90/manifests07070100000062000081A4000000000000000000000001673DBE2800000211000000000000000000000000000000000000002A00000000kubeshark-cli-52.3.90/manifests/README.md# Manifests ## Apply Clone the repo: ```shell git clone git@github.com:kubeshark/kubeshark.git --depth 1 cd kubeshark/manifests ``` To apply the manifests, run: ```shell kubectl apply -f . ``` To clean up: ```shell kubectl delete namespace kubeshark kubectl delete clusterrolebinding kubeshark-cluster-role-binding kubectl delete clusterrole kubeshark-cluster-role ``` ## Accessing Do the port forwarding: ```shell kubectl port-forward service/kubeshark-front 8899:80 ``` Visit [localhost:8899](http://localhost:8899) 07070100000063000081A4000000000000000000000001673DBE2800005E0D000000000000000000000000000000000000002E00000000kubeshark-cli-52.3.90/manifests/complete.yaml--- # Source: kubeshark/templates/16-network-policies.yaml apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: labels: helm.sh/chart: kubeshark-52.3.90 app.kubernetes.io/name: kubeshark app.kubernetes.io/instance: kubeshark app.kubernetes.io/version: "52.3.90" app.kubernetes.io/managed-by: Helm annotations: name: kubeshark-hub-network-policy namespace: default spec: podSelector: matchLabels: app.kubeshark.co/app: hub policyTypes: - Ingress - Egress ingress: - ports: - protocol: TCP port: 8080 egress: - {} --- # Source: kubeshark/templates/16-network-policies.yaml apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: labels: helm.sh/chart: kubeshark-52.3.90 app.kubernetes.io/name: kubeshark app.kubernetes.io/instance: kubeshark app.kubernetes.io/version: "52.3.90" app.kubernetes.io/managed-by: Helm annotations: name: kubeshark-front-network-policy namespace: default spec: podSelector: matchLabels: app.kubeshark.co/app: front policyTypes: - Ingress - Egress ingress: - ports: - protocol: TCP port: 8080 egress: - {} --- # Source: kubeshark/templates/16-network-policies.yaml apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: labels: helm.sh/chart: kubeshark-52.3.90 app.kubernetes.io/name: kubeshark app.kubernetes.io/instance: kubeshark app.kubernetes.io/version: "52.3.90" app.kubernetes.io/managed-by: Helm annotations: name: kubeshark-worker-network-policy namespace: default spec: podSelector: matchLabels: app.kubeshark.co/app: worker policyTypes: - Ingress - Egress ingress: - ports: - protocol: TCP port: 30001 - protocol: TCP port: 49100 egress: - {} --- # Source: kubeshark/templates/01-service-account.yaml apiVersion: v1 kind: ServiceAccount metadata: labels: helm.sh/chart: kubeshark-52.3.90 app.kubernetes.io/name: kubeshark app.kubernetes.io/instance: kubeshark app.kubernetes.io/version: "52.3.90" app.kubernetes.io/managed-by: Helm annotations: name: kubeshark-service-account namespace: default --- # Source: kubeshark/templates/13-secret.yaml kind: Secret apiVersion: v1 metadata: name: kubeshark-secret namespace: default labels: app.kubeshark.co/app: hub helm.sh/chart: kubeshark-52.3.90 app.kubernetes.io/name: kubeshark app.kubernetes.io/instance: kubeshark app.kubernetes.io/version: "52.3.90" app.kubernetes.io/managed-by: Helm stringData: LICENSE: '' SCRIPTING_ENV: '{}' --- # Source: kubeshark/templates/13-secret.yaml kind: Secret apiVersion: v1 metadata: name: kubeshark-saml-x509-crt-secret namespace: default labels: app.kubeshark.co/app: hub helm.sh/chart: kubeshark-52.3.90 app.kubernetes.io/name: kubeshark app.kubernetes.io/instance: kubeshark app.kubernetes.io/version: "52.3.90" app.kubernetes.io/managed-by: Helm stringData: AUTH_SAML_X509_CRT: | --- # Source: kubeshark/templates/13-secret.yaml kind: Secret apiVersion: v1 metadata: name: kubeshark-saml-x509-key-secret namespace: default labels: app.kubeshark.co/app: hub helm.sh/chart: kubeshark-52.3.90 app.kubernetes.io/name: kubeshark app.kubernetes.io/instance: kubeshark app.kubernetes.io/version: "52.3.90" app.kubernetes.io/managed-by: Helm stringData: AUTH_SAML_X509_KEY: | --- # Source: kubeshark/templates/11-nginx-config-map.yaml apiVersion: v1 kind: ConfigMap metadata: name: kubeshark-nginx-config-map namespace: default labels: helm.sh/chart: kubeshark-52.3.90 app.kubernetes.io/name: kubeshark app.kubernetes.io/instance: kubeshark app.kubernetes.io/version: "52.3.90" app.kubernetes.io/managed-by: Helm data: default.conf: | server { listen 8080; listen [::]:8080; access_log /dev/stdout; error_log /dev/stdout; client_body_buffer_size 64k; client_header_buffer_size 32k; large_client_header_buffers 8 64k; location /api { rewrite ^/api(.*)$ $1 break; proxy_pass http://kubeshark-hub; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header Host $http_host; proxy_set_header Upgrade websocket; proxy_set_header Connection Upgrade; proxy_set_header Authorization $http_authorization; proxy_pass_header Authorization; proxy_connect_timeout 4s; proxy_read_timeout 120s; proxy_send_timeout 12s; proxy_pass_request_headers on; } location /saml { rewrite ^/saml(.*)$ /saml$1 break; proxy_pass http://kubeshark-hub; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header Host $http_host; proxy_connect_timeout 4s; proxy_read_timeout 120s; proxy_send_timeout 12s; proxy_pass_request_headers on; } location / { root /usr/share/nginx/html; index index.html index.htm; try_files $uri $uri/ /index.html; expires -1; add_header Cache-Control no-cache; } error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } } --- # Source: kubeshark/templates/12-config-map.yaml kind: ConfigMap apiVersion: v1 metadata: name: kubeshark-config-map namespace: default labels: app.kubeshark.co/app: hub helm.sh/chart: kubeshark-52.3.90 app.kubernetes.io/name: kubeshark app.kubernetes.io/instance: kubeshark app.kubernetes.io/version: "52.3.90" app.kubernetes.io/managed-by: Helm data: POD_REGEX: '.*' NAMESPACES: '' EXCLUDED_NAMESPACES: '' BPF_OVERRIDE: '' STOPPED: 'false' SCRIPTING_SCRIPTS: '{}' SCRIPTING_ACTIVE_SCRIPTS: '' INGRESS_ENABLED: 'false' INGRESS_HOST: 'ks.svc.cluster.local' PROXY_FRONT_PORT: '8899' AUTH_ENABLED: 'true' AUTH_TYPE: 'oidc' AUTH_SAML_IDP_METADATA_URL: '' AUTH_SAML_ROLE_ATTRIBUTE: 'role' AUTH_SAML_ROLES: '{"admin":{"canDownloadPCAP":true,"canStopTrafficCapturing":true,"canUpdateTargetedPods":true,"canUseScripting":true,"filter":"","showAdminConsoleLink":true}}' TELEMETRY_DISABLED: 'false' SCRIPTING_DISABLED: '' TARGETED_PODS_UPDATE_DISABLED: '' PRESET_FILTERS_CHANGING_ENABLED: 'true' RECORDING_DISABLED: '' STOP_TRAFFIC_CAPTURING_DISABLED: 'false' GLOBAL_FILTER: "" DEFAULT_FILTER: "!dns and !tcp and !udp and !icmp" TRAFFIC_SAMPLE_RATE: '100' JSON_TTL: '5m' PCAP_TTL: '10s' PCAP_ERROR_TTL: '60s' TIMEZONE: ' ' CLOUD_LICENSE_ENABLED: 'true' DUPLICATE_TIMEFRAME: '200ms' ENABLED_DISSECTORS: 'amqp,dns,http,icmp,kafka,redis,sctp,syscall,ws,tls' DISSECTORS_UPDATING_ENABLED: 'true' DETECT_DUPLICATES: 'false' PCAP_DUMP_ENABLE: 'true' PCAP_TIME_INTERVAL: '1m' PCAP_MAX_TIME: '1h' PCAP_MAX_SIZE: '500MB' PCAP_SRC_DIR: 'pcapdump' --- # Source: kubeshark/templates/02-cluster-role.yaml apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: labels: helm.sh/chart: kubeshark-52.3.90 app.kubernetes.io/name: kubeshark app.kubernetes.io/instance: kubeshark app.kubernetes.io/version: "52.3.90" app.kubernetes.io/managed-by: Helm annotations: name: kubeshark-cluster-role-default namespace: default rules: - apiGroups: - "" - extensions - apps resources: - nodes - pods - services - endpoints - persistentvolumeclaims verbs: - list - get - watch - apiGroups: - "" resources: - namespaces verbs: - get resourceNames: - kube-system - apiGroups: - networking.k8s.io resources: - networkpolicies verbs: - get - list - watch - create - update - delete --- # Source: kubeshark/templates/03-cluster-role-binding.yaml apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: labels: helm.sh/chart: kubeshark-52.3.90 app.kubernetes.io/name: kubeshark app.kubernetes.io/instance: kubeshark app.kubernetes.io/version: "52.3.90" app.kubernetes.io/managed-by: Helm annotations: name: kubeshark-cluster-role-binding-default namespace: default roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: kubeshark-cluster-role-default subjects: - kind: ServiceAccount name: kubeshark-service-account namespace: default --- # Source: kubeshark/templates/02-cluster-role.yaml apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: labels: helm.sh/chart: kubeshark-52.3.90 app.kubernetes.io/name: kubeshark app.kubernetes.io/instance: kubeshark app.kubernetes.io/version: "52.3.90" app.kubernetes.io/managed-by: Helm annotations: name: kubeshark-self-config-role namespace: default rules: - apiGroups: - "" - v1 resourceNames: - kubeshark-secret - kubeshark-config-map resources: - secrets - configmaps verbs: - get - watch - list - update - patch --- # Source: kubeshark/templates/03-cluster-role-binding.yaml apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: labels: helm.sh/chart: kubeshark-52.3.90 app.kubernetes.io/name: kubeshark app.kubernetes.io/instance: kubeshark app.kubernetes.io/version: "52.3.90" app.kubernetes.io/managed-by: Helm annotations: name: kubeshark-self-config-role-binding namespace: default roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: kubeshark-self-config-role subjects: - kind: ServiceAccount name: kubeshark-service-account namespace: default --- # Source: kubeshark/templates/05-hub-service.yaml apiVersion: v1 kind: Service metadata: labels: app.kubeshark.co/app: hub helm.sh/chart: kubeshark-52.3.90 app.kubernetes.io/name: kubeshark app.kubernetes.io/instance: kubeshark app.kubernetes.io/version: "52.3.90" app.kubernetes.io/managed-by: Helm annotations: name: kubeshark-hub namespace: default spec: ports: - name: kubeshark-hub port: 80 targetPort: 8080 selector: app.kubeshark.co/app: hub type: ClusterIP --- # Source: kubeshark/templates/07-front-service.yaml apiVersion: v1 kind: Service metadata: labels: helm.sh/chart: kubeshark-52.3.90 app.kubernetes.io/name: kubeshark app.kubernetes.io/instance: kubeshark app.kubernetes.io/version: "52.3.90" app.kubernetes.io/managed-by: Helm annotations: name: kubeshark-front namespace: default spec: ports: - name: kubeshark-front port: 80 targetPort: 8080 selector: app.kubeshark.co/app: front type: ClusterIP --- # Source: kubeshark/templates/15-worker-service-metrics.yaml kind: Service apiVersion: v1 metadata: labels: helm.sh/chart: kubeshark-52.3.90 app.kubernetes.io/name: kubeshark app.kubernetes.io/instance: kubeshark app.kubernetes.io/version: "52.3.90" app.kubernetes.io/managed-by: Helm annotations: prometheus.io/scrape: 'true' prometheus.io/port: '49100' name: kubeshark-worker-metrics namespace: default spec: selector: app.kubeshark.co/app: worker helm.sh/chart: kubeshark-52.3.90 app.kubernetes.io/name: kubeshark app.kubernetes.io/instance: kubeshark app.kubernetes.io/version: "52.3.90" app.kubernetes.io/managed-by: Helm ports: - name: metrics protocol: TCP port: 49100 targetPort: 49100 --- # Source: kubeshark/templates/09-worker-daemon-set.yaml apiVersion: apps/v1 kind: DaemonSet metadata: labels: app.kubeshark.co/app: worker sidecar.istio.io/inject: "false" helm.sh/chart: kubeshark-52.3.90 app.kubernetes.io/name: kubeshark app.kubernetes.io/instance: kubeshark app.kubernetes.io/version: "52.3.90" app.kubernetes.io/managed-by: Helm annotations: name: kubeshark-worker-daemon-set namespace: default spec: selector: matchLabels: app.kubeshark.co/app: worker app.kubernetes.io/name: kubeshark app.kubernetes.io/instance: kubeshark template: metadata: labels: app.kubeshark.co/app: worker helm.sh/chart: kubeshark-52.3.90 app.kubernetes.io/name: kubeshark app.kubernetes.io/instance: kubeshark app.kubernetes.io/version: "52.3.90" app.kubernetes.io/managed-by: Helm name: kubeshark-worker-daemon-set namespace: kubeshark spec: containers: - command: - ./worker - -i - any - -port - '30001' - -metrics-port - '49100' - -packet-capture - 'best' - -unixsocket - -servicemesh - -procfs - /hostproc - -disable-ebpf - -resolution-strategy - 'auto' - -staletimeout - '30' image: 'docker.io/kubeshark/worker:v52.3.90' imagePullPolicy: Always name: sniffer ports: - containerPort: 49100 protocol: TCP name: metrics env: - name: POD_NAME valueFrom: fieldRef: fieldPath: metadata.name - name: POD_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace - name: TCP_STREAM_CHANNEL_TIMEOUT_MS value: '10000' - name: TCP_STREAM_CHANNEL_TIMEOUT_SHOW value: 'false' - name: KUBESHARK_CLOUD_API_URL value: 'https://api.kubeshark.co' - name: PROFILING_ENABLED value: 'false' - name: SENTRY_ENABLED value: 'false' - name: SENTRY_ENVIRONMENT value: 'production' resources: limits: memory: 5Gi requests: cpu: 50m memory: 50Mi securityContext: capabilities: add: - NET_RAW - NET_ADMIN - SYS_ADMIN - SYS_PTRACE - DAC_OVERRIDE drop: - ALL readinessProbe: periodSeconds: 1 failureThreshold: 3 successThreshold: 1 initialDelaySeconds: 5 tcpSocket: port: 30001 livenessProbe: periodSeconds: 1 failureThreshold: 3 successThreshold: 1 initialDelaySeconds: 5 tcpSocket: port: 30001 volumeMounts: - mountPath: /hostproc name: proc readOnly: true - mountPath: /sys name: sys readOnly: true - mountPath: /app/data name: data - command: - ./tracer - -procfs - /hostproc - -disable-ebpf - -disable-tls-log image: 'docker.io/kubeshark/worker:v52.3.90' imagePullPolicy: Always name: tracer env: - name: POD_NAME valueFrom: fieldRef: fieldPath: metadata.name - name: POD_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace - name: PROFILING_ENABLED value: 'false' - name: SENTRY_ENABLED value: 'false' - name: SENTRY_ENVIRONMENT value: 'production' resources: limits: memory: 5Gi requests: cpu: 50m memory: 50Mi securityContext: capabilities: add: - SYS_ADMIN - SYS_PTRACE - SYS_RESOURCE - IPC_LOCK - NET_RAW - NET_ADMIN drop: - ALL volumeMounts: - mountPath: /hostproc name: proc readOnly: true - mountPath: /sys name: sys readOnly: true - mountPath: /app/data name: data - mountPath: /etc/os-release name: os-release readOnly: true - mountPath: /hostroot mountPropagation: HostToContainer name: root readOnly: true dnsPolicy: ClusterFirstWithHostNet hostNetwork: true serviceAccountName: kubeshark-service-account terminationGracePeriodSeconds: 0 tolerations: - effect: NoExecute operator: Exists - effect: NoSchedule operator: Exists affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: kubernetes.io/os operator: In values: - linux volumes: - hostPath: path: /proc name: proc - hostPath: path: /sys name: sys - name: lib-modules hostPath: path: /lib/modules - hostPath: path: /etc/os-release name: os-release - hostPath: path: / name: root - name: data emptyDir: sizeLimit: 5000Mi --- # Source: kubeshark/templates/04-hub-deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: labels: app.kubeshark.co/app: hub helm.sh/chart: kubeshark-52.3.90 app.kubernetes.io/name: kubeshark app.kubernetes.io/instance: kubeshark app.kubernetes.io/version: "52.3.90" app.kubernetes.io/managed-by: Helm annotations: name: kubeshark-hub namespace: default spec: replicas: 1 # Set the desired number of replicas selector: matchLabels: app.kubeshark.co/app: hub app.kubernetes.io/name: kubeshark app.kubernetes.io/instance: kubeshark template: metadata: labels: app.kubeshark.co/app: hub helm.sh/chart: kubeshark-52.3.90 app.kubernetes.io/name: kubeshark app.kubernetes.io/instance: kubeshark app.kubernetes.io/version: "52.3.90" app.kubernetes.io/managed-by: Helm spec: dnsPolicy: ClusterFirstWithHostNet serviceAccountName: kubeshark-service-account containers: - name: hub command: - ./hub - -port - "8080" env: - name: POD_NAME valueFrom: fieldRef: fieldPath: metadata.name - name: POD_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace - name: SENTRY_ENABLED value: 'false' - name: SENTRY_ENVIRONMENT value: 'production' - name: KUBESHARK_CLOUD_API_URL value: 'https://api.kubeshark.co' - name: PROFILING_ENABLED value: 'false' image: 'docker.io/kubeshark/hub:v52.3.90' imagePullPolicy: Always readinessProbe: periodSeconds: 1 failureThreshold: 3 successThreshold: 1 initialDelaySeconds: 3 tcpSocket: port: 8080 livenessProbe: periodSeconds: 1 failureThreshold: 3 successThreshold: 1 initialDelaySeconds: 3 tcpSocket: port: 8080 resources: limits: memory: 5Gi requests: cpu: 50m memory: 50Mi volumeMounts: - name: saml-x509-volume mountPath: "/etc/saml/x509" readOnly: true volumes: - name: saml-x509-volume projected: sources: - secret: name: kubeshark-saml-x509-crt-secret items: - key: AUTH_SAML_X509_CRT path: kubeshark.crt - secret: name: kubeshark-saml-x509-key-secret items: - key: AUTH_SAML_X509_KEY path: kubeshark.key --- # Source: kubeshark/templates/06-front-deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: labels: app.kubeshark.co/app: front helm.sh/chart: kubeshark-52.3.90 app.kubernetes.io/name: kubeshark app.kubernetes.io/instance: kubeshark app.kubernetes.io/version: "52.3.90" app.kubernetes.io/managed-by: Helm annotations: name: kubeshark-front namespace: default spec: replicas: 1 # Set the desired number of replicas selector: matchLabels: app.kubeshark.co/app: front app.kubernetes.io/name: kubeshark app.kubernetes.io/instance: kubeshark template: metadata: labels: app.kubeshark.co/app: front helm.sh/chart: kubeshark-52.3.90 app.kubernetes.io/name: kubeshark app.kubernetes.io/instance: kubeshark app.kubernetes.io/version: "52.3.90" app.kubernetes.io/managed-by: Helm spec: containers: - env: - name: REACT_APP_AUTH_ENABLED value: 'true' - name: REACT_APP_AUTH_TYPE value: 'oidc' - name: REACT_APP_AUTH_SAML_IDP_METADATA_URL value: ' ' - name: REACT_APP_TIMEZONE value: ' ' - name: REACT_APP_SCRIPTING_DISABLED value: 'false' - name: REACT_APP_TARGETED_PODS_UPDATE_DISABLED value: 'false' - name: REACT_APP_PRESET_FILTERS_CHANGING_ENABLED value: 'true' - name: REACT_APP_BPF_OVERRIDE_DISABLED value: 'false' - name: REACT_APP_RECORDING_DISABLED value: 'false' - name: REACT_APP_STOP_TRAFFIC_CAPTURING_DISABLED value: 'false' - name: 'REACT_APP_CLOUD_LICENSE_ENABLED' value: 'true' - name: REACT_APP_SUPPORT_CHAT_ENABLED value: 'true' - name: REACT_APP_DISSECTORS_UPDATING_ENABLED value: 'true' - name: REACT_APP_SENTRY_ENABLED value: 'false' - name: REACT_APP_SENTRY_ENVIRONMENT value: 'production' image: 'docker.io/kubeshark/front:v52.3.90' imagePullPolicy: Always name: kubeshark-front livenessProbe: periodSeconds: 1 failureThreshold: 3 successThreshold: 1 initialDelaySeconds: 3 tcpSocket: port: 8080 readinessProbe: periodSeconds: 1 failureThreshold: 3 successThreshold: 1 initialDelaySeconds: 3 tcpSocket: port: 8080 timeoutSeconds: 1 resources: limits: cpu: 750m memory: 1Gi requests: cpu: 50m memory: 50Mi volumeMounts: - name: nginx-config mountPath: /etc/nginx/conf.d/default.conf subPath: default.conf readOnly: true volumes: - name: nginx-config configMap: name: kubeshark-nginx-config-map dnsPolicy: ClusterFirstWithHostNet serviceAccountName: kubeshark-service-account 07070100000064000041ED000000000000000000000002673DBE2800000000000000000000000000000000000000000000002B00000000kubeshark-cli-52.3.90/manifests/prometheus07070100000065000081A4000000000000000000000001673DBE280000036F000000000000000000000000000000000000004600000000kubeshark-cli-52.3.90/manifests/prometheus/kube_prometheus_stack.yamlgrafana: additionalDataSources: [] prometheus: prometheusSpec: scrapeInterval: 10s evaluationInterval: 30s additionalScrapeConfigs: | - job_name: 'kubeshark-worker-metrics' kubernetes_sd_configs: - role: endpoints relabel_configs: - source_labels: [__meta_kubernetes_pod_name] target_label: pod - source_labels: [__meta_kubernetes_pod_node_name] target_label: node - source_labels: [__meta_kubernetes_endpoint_port_name] action: keep regex: ^metrics$ - source_labels: [__address__, __meta_kubernetes_endpoint_port_number] action: replace regex: ([^:]+)(?::\d+)? replacement: $1:49100 target_label: __address__ - action: labelmap regex: __meta_kubernetes_service_label_(.+) 07070100000066000041ED000000000000000000000002673DBE2800000000000000000000000000000000000000000000002400000000kubeshark-cli-52.3.90/manifests/tls07070100000067000081A4000000000000000000000001673DBE28000000EE000000000000000000000000000000000000003500000000kubeshark-cli-52.3.90/manifests/tls/certificate.yamlapiVersion: cert-manager.io/v1 kind: Certificate metadata: name: kubeshark-tls namespace: default spec: issuerRef: name: letsencrypt-prod kind: ClusterIssuer secretName: cert-kubeshark dnsNames: - ks.svc.cluster.local 07070100000068000081A4000000000000000000000001673DBE280000014B000000000000000000000000000000000000003800000000kubeshark-cli-52.3.90/manifests/tls/cluster-issuer.yamlapiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: name: letsencrypt-prod spec: acme: server: https://acme-v02.api.letsencrypt.org/directory email: info@kubeshark.co privateKeySecretRef: name: letsencrypt-prod-key solvers: - http01: ingress: class: kubeshark-ingress-class 07070100000069000081ED000000000000000000000001673DBE28000001C1000000000000000000000000000000000000002B00000000kubeshark-cli-52.3.90/manifests/tls/run.sh#!/bin/bash __dir="$(cd -P -- "$(dirname -- "$0")" && pwd -P)" helm repo add jetstack https://charts.jetstack.io helm repo update kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.9.1/cert-manager.crds.yaml helm install \ cert-manager jetstack/cert-manager \ --namespace cert-manager \ --create-namespace \ --version v1.9.1 kubectl apply -f ${__dir}/cluster-issuer.yaml kubectl apply -f ${__dir}/certificate.yaml 0707010000006A000041ED000000000000000000000002673DBE2800000000000000000000000000000000000000000000001B00000000kubeshark-cli-52.3.90/misc0707010000006B000081A4000000000000000000000001673DBE28000002B3000000000000000000000000000000000000002500000000kubeshark-cli-52.3.90/misc/consts.gopackage misc import ( "fmt" "os" "path" ) var ( Software = "Kubeshark" Program = "kubeshark" Description = "The API Traffic Analyzer for Kubernetes" Website = "https://kubeshark.co" Email = "info@kubeshark.co" Ver = "0.0.0" Branch = "master" GitCommitHash = "" // this var is overridden using ldflags in makefile when building BuildTimestamp = "" // this var is overridden using ldflags in makefile when building RBACVersion = "v1" Platform = "" ) func GetDotFolderPath() string { home, homeDirErr := os.UserHomeDir() if homeDirErr != nil { return "" } return path.Join(home, fmt.Sprintf(".%s", Program)) } 0707010000006C000041ED000000000000000000000002673DBE2800000000000000000000000000000000000000000000002300000000kubeshark-cli-52.3.90/misc/fsUtils0707010000006D000081A4000000000000000000000001673DBE280000019C000000000000000000000000000000000000002F00000000kubeshark-cli-52.3.90/misc/fsUtils/dirUtils.gopackage fsUtils import ( "fmt" "os" ) func EnsureDir(dirName string) error { err := os.Mkdir(dirName, 0700) if err == nil { return nil } if os.IsExist(err) { // check that the existing path is a directory info, err := os.Stat(dirName) if err != nil { return err } if !info.IsDir() { return fmt.Errorf("path exists but is not a directory: %s", dirName) } return nil } return err } 0707010000006E000081A4000000000000000000000001673DBE2800000153000000000000000000000000000000000000003000000000kubeshark-cli-52.3.90/misc/fsUtils/globUtils.gopackage fsUtils import ( "fmt" "os" "path/filepath" ) func RemoveFilesByExtension(dirPath string, ext string) error { files, err := filepath.Glob(filepath.Join(dirPath, fmt.Sprintf("/*.%s", ext))) if err != nil { return err } for _, f := range files { if err := os.Remove(f); err != nil { return err } } return nil } 0707010000006F000081A4000000000000000000000001673DBE2800000A2A000000000000000000000000000000000000003900000000kubeshark-cli-52.3.90/misc/fsUtils/kubesharkLogsUtils.gopackage fsUtils import ( "archive/zip" "context" "fmt" "os" "regexp" "github.com/kubeshark/kubeshark/config" "github.com/kubeshark/kubeshark/kubernetes" "github.com/kubeshark/kubeshark/misc" "github.com/rs/zerolog/log" ) func DumpLogs(ctx context.Context, provider *kubernetes.Provider, filePath string, grep string) error { podExactRegex := regexp.MustCompile("^" + kubernetes.SELF_RESOURCES_PREFIX) pods, err := provider.ListAllPodsMatchingRegex(ctx, podExactRegex, []string{config.Config.Tap.Release.Namespace}) if err != nil { return err } if len(pods) == 0 { return fmt.Errorf("No %s pods found in namespace %s", misc.Software, config.Config.Tap.Release.Namespace) } newZipFile, err := os.Create(filePath) if err != nil { return err } defer newZipFile.Close() zipWriter := zip.NewWriter(newZipFile) defer zipWriter.Close() for _, pod := range pods { for _, container := range pod.Spec.Containers { logs, err := provider.GetPodLogs(ctx, pod.Namespace, pod.Name, container.Name, grep) if err != nil { log.Error().Err(err).Msg("Failed to get logs!") continue } else { log.Debug(). Int("length", len(logs)). Str("namespace", pod.Namespace). Str("pod", pod.Name). Str("container", container.Name). Msg("Successfully read log length.") } if err := AddStrToZip(zipWriter, logs, fmt.Sprintf("%s.%s.%s.log", pod.Namespace, pod.Name, container.Name)); err != nil { log.Error().Err(err).Msg("Failed write logs!") } else { log.Debug(). Int("length", len(logs)). Str("namespace", pod.Namespace). Str("pod", pod.Name). Str("container", container.Name). Msg("Successfully added log length.") } } } events, err := provider.GetNamespaceEvents(ctx, config.Config.Tap.Release.Namespace) if err != nil { log.Error().Err(err).Msg("Failed to get k8b events!") } else { log.Debug().Str("namespace", config.Config.Tap.Release.Namespace).Msg("Successfully read events.") } if err := AddStrToZip(zipWriter, events, fmt.Sprintf("%s_events.log", config.Config.Tap.Release.Namespace)); err != nil { log.Error().Err(err).Msg("Failed write logs!") } else { log.Debug().Str("namespace", config.Config.Tap.Release.Namespace).Msg("Successfully added events.") } if err := AddFileToZip(zipWriter, config.ConfigFilePath); err != nil { log.Error().Err(err).Msg("Failed write file!") } else { log.Debug().Str("file-path", config.ConfigFilePath).Msg("Successfully added file.") } log.Info().Str("path", filePath).Msg("You can find the ZIP file with all logs at:") return nil } 07070100000070000081A4000000000000000000000001673DBE2800000ABA000000000000000000000000000000000000002F00000000kubeshark-cli-52.3.90/misc/fsUtils/zipUtils.gopackage fsUtils import ( "archive/zip" "fmt" "io" "os" "path/filepath" "strings" "github.com/rs/zerolog/log" ) func AddFileToZip(zipWriter *zip.Writer, filename string) error { fileToZip, err := os.Open(filename) if err != nil { return fmt.Errorf("failed to open file %s, %w", filename, err) } defer fileToZip.Close() // Get the file information info, err := fileToZip.Stat() if err != nil { return fmt.Errorf("failed to get file information %s, %w", filename, err) } header, err := zip.FileInfoHeader(info) if err != nil { return err } // Using FileInfoHeader() above only uses the basename of the file. If we want // to preserve the folder structure we can overwrite this with the full path. header.Name = filepath.Base(filename) // Change to deflate to gain better compression // see http://golang.org/pkg/archive/zip/#pkg-constants header.Method = zip.Deflate writer, err := zipWriter.CreateHeader(header) if err != nil { return fmt.Errorf("failed to create header in zip for %s, %w", filename, err) } _, err = io.Copy(writer, fileToZip) return err } func AddStrToZip(writer *zip.Writer, logs string, fileName string) error { if zipFile, err := writer.Create(fileName); err != nil { return fmt.Errorf("couldn't create a log file inside zip for %s, %w", fileName, err) } else { if _, err = zipFile.Write([]byte(logs)); err != nil { return fmt.Errorf("couldn't write logs to zip file: %s, %w", fileName, err) } } return nil } func Unzip(reader *zip.Reader, dest string) error { dest, _ = filepath.Abs(dest) _ = os.MkdirAll(dest, os.ModePerm) // Closure to address file descriptors issue with all the deferred .Close() methods extractAndWriteFile := func(f *zip.File) error { rc, err := f.Open() if err != nil { return err } defer func() { if err := rc.Close(); err != nil { panic(err) } }() path := filepath.Join(dest, f.Name) // Check for ZipSlip (Directory traversal) if !strings.HasPrefix(path, filepath.Clean(dest)+string(os.PathSeparator)) { return fmt.Errorf("illegal file path: %s", path) } if f.FileInfo().IsDir() { _ = os.MkdirAll(path, f.Mode()) } else { _ = os.MkdirAll(filepath.Dir(path), f.Mode()) log.Info().Str("path", path).Msg("Writing HAR file...") f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode()) if err != nil { return err } defer func() { if err := f.Close(); err != nil { panic(err) } log.Info().Str("path", path).Msg("HAR file at:") }() _, err = io.Copy(f, rc) if err != nil { return err } } return nil } for _, f := range reader.File { err := extractAndWriteFile(f) if err != nil { return err } } return nil } 07070100000071000081A4000000000000000000000001673DBE28000004F9000000000000000000000000000000000000002800000000kubeshark-cli-52.3.90/misc/scripting.gopackage misc import ( "os" "path/filepath" "github.com/robertkrimen/otto/ast" "github.com/robertkrimen/otto/file" "github.com/robertkrimen/otto/parser" ) type Script struct { Path string `json:"path"` Title string `json:"title"` Code string `json:"code"` Active bool `json:"active"` } type ConfigMapScript struct { Title string `json:"title"` Code string `json:"code"` Active bool `json:"active"` } func (s *Script) ConfigMap() ConfigMapScript { return ConfigMapScript{ Title: s.Title, Code: s.Code, Active: s.Active, } } func ReadScriptFile(path string) (script *Script, err error) { filename := filepath.Base(path) var body []byte body, err = os.ReadFile(path) if err != nil { return } content := string(body) var program *ast.Program program, err = parser.ParseFile(nil, filename, content, parser.StoreComments) if err != nil { return } var title string var titleIsSet bool code := content var idx0 file.Idx for node, comments := range program.Comments { if (titleIsSet && node.Idx0() > idx0) || len(comments) == 0 { continue } idx0 = node.Idx0() title = comments[0].Text titleIsSet = true } script = &Script{ Path: path, Title: title, Code: code, Active: false, } return } 07070100000072000041ED000000000000000000000002673DBE2800000000000000000000000000000000000000000000002300000000kubeshark-cli-52.3.90/misc/version07070100000073000081A4000000000000000000000001673DBE28000005B8000000000000000000000000000000000000003300000000kubeshark-cli-52.3.90/misc/version/versionCheck.gopackage version import ( "context" "fmt" "os" "runtime" "strings" "time" "github.com/kubeshark/kubeshark/misc" "github.com/kubeshark/kubeshark/utils" "github.com/rs/zerolog/log" "github.com/google/go-github/v37/github" ) func CheckNewerVersion() { if os.Getenv(fmt.Sprintf("%s_DISABLE_VERSION_CHECK", strings.ToUpper(misc.Program))) != "" { return } log.Info().Msg("Checking for a newer version...") start := time.Now() client := github.NewClient(nil) latestRelease, _, err := client.Repositories.GetLatestRelease(context.Background(), misc.Program, misc.Program) if err != nil { log.Error().Msg("Failed to get the latest release.") return } latestVersion := *latestRelease.TagName log.Debug(). Str("upstream-version", latestVersion). Str("local-version", misc.Ver). Dur("elapsed-time", time.Since(start)). Msg("Fetched the latest release:") if misc.Ver != latestVersion { var downloadCommand string if runtime.GOOS == "windows" { downloadCommand = fmt.Sprintf("curl -LO %v/%s.exe", strings.Replace(*latestRelease.HTMLURL, "tag", "download", 1), misc.Program) } else { downloadCommand = fmt.Sprintf("sh <(curl -Ls %s/install)", misc.Website) } msg := fmt.Sprintf("There is a new release! %v -> %v Please upgrade to the latest release, as new releases are not always backward compatible. Run:", misc.Ver, latestVersion) log.Warn().Str("command", downloadCommand).Msg(fmt.Sprintf(utils.Yellow, msg)) } } 07070100000074000041ED000000000000000000000002673DBE2800000000000000000000000000000000000000000000001D00000000kubeshark-cli-52.3.90/semver07070100000075000081A4000000000000000000000001673DBE28000003C4000000000000000000000000000000000000002700000000kubeshark-cli-52.3.90/semver/semver.gopackage semver import ( "regexp" ) type SemVersion string func (v SemVersion) IsValid() bool { re := regexp.MustCompile(`\d+`) breakdown := re.FindAllString(string(v), 3) return len(breakdown) == 3 } func (v SemVersion) Breakdown() (string, string, string) { re := regexp.MustCompile(`\d+`) breakdown := re.FindAllString(string(v), 3) return breakdown[0], breakdown[1], breakdown[2] } func (v SemVersion) Major() string { major, _, _ := v.Breakdown() return major } func (v SemVersion) Minor() string { _, minor, _ := v.Breakdown() return minor } func (v SemVersion) Patch() string { _, _, patch := v.Breakdown() return patch } func (v SemVersion) GreaterThan(v2 SemVersion) bool { if v.Major() > v2.Major() { return true } else if v.Major() < v2.Major() { return false } if v.Minor() > v2.Minor() { return true } else if v.Minor() < v2.Minor() { return false } if v.Patch() > v2.Patch() { return true } return false } 07070100000076000041ED000000000000000000000002673DBE2800000000000000000000000000000000000000000000001C00000000kubeshark-cli-52.3.90/utils07070100000077000081A4000000000000000000000001673DBE28000001FD000000000000000000000000000000000000002700000000kubeshark-cli-52.3.90/utils/browser.gopackage utils import ( "fmt" "os/exec" "runtime" "github.com/rs/zerolog/log" ) func OpenBrowser(url string) { var err error switch runtime.GOOS { case "linux": err = exec.Command("xdg-open", url).Start() case "windows": err = exec.Command("rundll32", "url.dll,FileProtocolHandler", url).Start() case "darwin": err = exec.Command("open", url).Start() default: err = fmt.Errorf("unsupported platform") } if err != nil { log.Error().Err(err).Msg("While trying to open a browser") } } 07070100000078000081A4000000000000000000000001673DBE2800000121000000000000000000000000000000000000002600000000kubeshark-cli-52.3.90/utils/colors.gopackage utils const ( Black = "\033[1;30m%s\033[0m" Red = "\033[1;31m%s\033[0m" Green = "\033[1;32m%s\033[0m" Yellow = "\033[1;33m%s\033[0m" Blue = "\033[1;34m%s\033[0m" Magenta = "\033[1;35m%s\033[0m" Cyan = "\033[1;36m%s\033[0m" White = "\033[1;37m%s\033[0m" ) 07070100000079000081A4000000000000000000000001673DBE2800000836000000000000000000000000000000000000002400000000kubeshark-cli-52.3.90/utils/http.gopackage utils import ( "bytes" "fmt" "io" "net/http" "strings" ) const ( X_KUBESHARK_CAPTURE_HEADER_KEY = "X-Kubeshark-Capture" X_KUBESHARK_CAPTURE_HEADER_IGNORE_VALUE = "ignore" ) // Get - When err is nil, resp always contains a non-nil resp.Body. // Caller should close resp.Body when done reading from it. func Get(url string, client *http.Client) (*http.Response, error) { req, err := http.NewRequest(http.MethodGet, url, nil) if err != nil { return nil, err } AddIgnoreCaptureHeader(req) return checkError(client.Do(req)) } // Post - When err is nil, resp always contains a non-nil resp.Body. // Caller should close resp.Body when done reading from it. func Post(url, contentType string, body io.Reader, client *http.Client, licenseKey string) (*http.Response, error) { req, err := http.NewRequest(http.MethodPost, url, body) if err != nil { return nil, err } AddIgnoreCaptureHeader(req) req.Header.Set("Content-Type", "application/json") req.Header.Set("License-Key", licenseKey) return checkError(client.Do(req)) } // Do - When err is nil, resp always contains a non-nil resp.Body. // Caller should close resp.Body when done reading from it. func Do(req *http.Request, client *http.Client) (*http.Response, error) { return checkError(client.Do(req)) } func checkError(response *http.Response, errInOperation error) (*http.Response, error) { if errInOperation != nil { return response, errInOperation // Check only if status != 200 (and not status >= 300). Hub return only 200 on success. } else if response.StatusCode != http.StatusOK { body, err := io.ReadAll(response.Body) response.Body.Close() response.Body = io.NopCloser(bytes.NewBuffer(body)) // rewind if err != nil { return response, err } errorMsg := strings.ReplaceAll(string(body), "\n", ";") return response, fmt.Errorf("got response with status code: %d, body: %s", response.StatusCode, errorMsg) } return response, nil } func AddIgnoreCaptureHeader(req *http.Request) { req.Header.Set(X_KUBESHARK_CAPTURE_HEADER_KEY, X_KUBESHARK_CAPTURE_HEADER_IGNORE_VALUE) } 0707010000007A000081A4000000000000000000000001673DBE2800000123000000000000000000000000000000000000002400000000kubeshark-cli-52.3.90/utils/json.gopackage utils import ( "strconv" "strings" "github.com/rs/zerolog/log" ) func UnescapeUnicodeCharacters(raw string) string { str, err := strconv.Unquote(strings.Replace(strconv.Quote(raw), `\\u`, `\u`, -1)) if err != nil { log.Error().Err(err).Send() return raw } return str } 0707010000007B000081A4000000000000000000000001673DBE280000012F000000000000000000000000000000000000002600000000kubeshark-cli-52.3.90/utils/pretty.gopackage utils import ( "bytes" "github.com/goccy/go-yaml" ) func PrettyYaml(data interface{}) (result string, err error) { buffer := new(bytes.Buffer) encoder := yaml.NewEncoder(buffer, yaml.Indent(2)) err = encoder.Encode(data) if err != nil { return } result = buffer.String() return } 0707010000007C000081A4000000000000000000000001673DBE28000003A8000000000000000000000000000000000000002500000000kubeshark-cli-52.3.90/utils/slice.gopackage utils func Contains(slice []string, containsValue string) bool { for _, sliceValue := range slice { if sliceValue == containsValue { return true } } return false } func Unique(slice []string) []string { keys := make(map[string]bool) var list []string for _, entry := range slice { if _, value := keys[entry]; !value { keys[entry] = true list = append(list, entry) } } return list } func EqualStringSlices(slice1 []string, slice2 []string) bool { if len(slice1) != len(slice2) { return false } for _, v := range slice1 { if !Contains(slice2, v) { return false } } return true } // Diff returns the elements in `a` that aren't in `b`. func Diff(a, b []string) []string { mb := make(map[string]struct{}, len(b)) for _, x := range b { mb[x] = struct{}{} } var diff []string for _, x := range a { if _, found := mb[x]; !found { diff = append(diff, x) } } return diff } 0707010000007D000081A4000000000000000000000001673DBE280000023B000000000000000000000000000000000000002400000000kubeshark-cli-52.3.90/utils/wait.gopackage utils import ( "context" "os" "os/signal" "syscall" "github.com/rs/zerolog/log" ) func WaitForTermination(ctx context.Context, cancel context.CancelFunc) { log.Debug().Msg("Waiting to finish...") sigChan := make(chan os.Signal, 1) signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT) // block until ctx cancel is called or termination signal is received select { case <-ctx.Done(): log.Debug().Msg("Context done.") break case <-sigChan: log.Debug().Msg("Got a termination signal, canceling execution...") cancel() } } 07070100000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000B00000000TRAILER!!!899 blocks
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor