├── .github ├── CODEOWNERS └── workflows │ ├── main.yml │ ├── news.yaml │ └── release.yml ├── .gitignore ├── .golangci.yaml ├── .goreleaser.yaml ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── DEVELOPMENT.md ├── KNOWN_ISSUES.md ├── LICENSE.txt ├── README.md ├── SECURITY.md ├── changes ├── 32.doc ├── README.md └── version.properties ├── cmd ├── images.go ├── root.go └── version.go ├── go.mod ├── go.sum ├── internal ├── images │ ├── images.go │ └── images_test.go └── k8s │ └── k8s.go ├── main.go └── pyproject.toml /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @ArmDeveloperEcosystem/platform 2 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Main CI/CD 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: 7 | - main 8 | 9 | jobs: 10 | test-go: 11 | strategy: 12 | fail-fast: false 13 | matrix: 14 | os: [ubuntu-latest, ubuntu-24.04-arm] 15 | runs-on: ${{ matrix.os }} 16 | steps: 17 | - uses: actions/checkout@v4 18 | 19 | - name: Setup Go 20 | uses: actions/setup-go@v5 21 | with: 22 | go-version-file: "go.mod" 23 | 24 | - name: Install dependencies 25 | run: sudo apt-get install libbtrfs-dev -y 26 | 27 | - name: Download Go Modules 28 | run: go mod download 29 | 30 | - name: Linting 31 | uses: golangci/golangci-lint-action@v6 32 | with: 33 | version: latest 34 | args: "--print-issued-lines --print-linter-name --out-${NO_FUTURE}format colored-line-number --timeout 300s --max-issues-per-linter 0 --max-same-issues 0" 35 | 36 | - name: Test Go 37 | run: go test ./... --cover 38 | -------------------------------------------------------------------------------- /.github/workflows/news.yaml: -------------------------------------------------------------------------------- 1 | name: Check news 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - main 7 | 8 | env: 9 | python-version: "3.10" 10 | dependabot_user: "dependabot[bot]" 11 | 12 | permissions: 13 | contents: read 14 | 15 | jobs: 16 | # Check that a news file has been added to this branch when a PR is created 17 | assert-news: 18 | name: Assert news files (See CONTRIBUTING.md) 19 | runs-on: ubuntu-latest 20 | timeout-minutes: 5 21 | steps: 22 | # Checkout with full history for to allow compare with base branch 23 | - uses: actions/checkout@v4 24 | with: 25 | fetch-depth: 0 26 | 27 | # Towncrier is written in Python 28 | - uses: actions/setup-python@v5 29 | with: 30 | python-version: ${{ env.python-version }} 31 | 32 | - name: Check for dependabot user 33 | if: github.event.pull_request.user.login == env.dependabot_user 34 | run: | 35 | echo "::warning:: Skipping news file check as this is a dependency update and not included in the release notes." 36 | 37 | - name: Install CI tools 38 | if: github.event.pull_request.user.login != env.dependabot_user 39 | run: pip install towncrier 40 | 41 | # Fetch the base branch for the pull request so that towncrier can compare the current branch with the base branch. 42 | - name: Check for news fragments 43 | if: github.event.pull_request.user.login != env.dependabot_user 44 | run: | 45 | git fetch --no-tags origin +refs/heads/${BASE_BRANCH}:refs/remotes/origin/${BASE_BRANCH} 46 | python -m towncrier.check --compare-with origin/${BASE_BRANCH} 47 | env: 48 | BASE_BRANCH: ${{ github.base_ref }} 49 | 50 | - name: Report failure if needed 51 | if: ${{ failure() }} 52 | run: | 53 | echo "::error:: News file missing (See CONTRIBUTING.md guide for details)." 54 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: GitHub Release 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | env: 7 | python-version: "3.10" 8 | 9 | jobs: 10 | # News file based version calculation 11 | create-release: 12 | runs-on: ubuntu-latest 13 | timeout-minutes: 60 14 | steps: 15 | - uses: tibdex/github-app-token@v2 16 | id: get_installation_token 17 | with: 18 | app_id: 1020175 19 | private_key: ${{ secrets.OTG_PLT_DEVECO_APP_PRVT_KEY }} 20 | 21 | # Checkout with full history so commit number can be calculated for beta versions 22 | - uses: actions/checkout@v4 23 | with: 24 | token: ${{ steps.get_installation_token.outputs.token }} 25 | fetch-depth: 0 26 | 27 | - name: Set up Go 28 | uses: actions/setup-go@v5 29 | with: 30 | go-version-file: "go.mod" 31 | 32 | # Towncrier and CI tools are written in Python 33 | - uses: actions/setup-python@v5 34 | with: 35 | python-version: ${{ env.python-version }} 36 | 37 | - name: Install CI tools 38 | run: pip install continuous-delivery-scripts 39 | 40 | - name: Generate release notes from news files 41 | run: cd-generate-news --release-type release 42 | 43 | - name: Determine version number based on news files 44 | run: | 45 | echo "SEMVER_VERSION=$(cd-determine-version --release-type release)" >> $GITHUB_ENV 46 | - name: Report version number for run 47 | run: | 48 | echo "::notice:: Releasing $SEMVER_VERSION" 49 | 50 | - name: Commit changes 51 | uses: EndBug/add-and-commit@v9.1.4 52 | with: 53 | author_name: otg-platform-armdeveloperecosystem[bot] 54 | author_email: 184357714+otg-platform-armdeveloperecosystem[bot]@users.noreply.github.com 55 | message: "Release v${{ env.SEMVER_VERSION }} [skip ci]" 56 | add: "changes" 57 | tag: "v${{ env.SEMVER_VERSION }} -m 'Release v${{ env.SEMVER_VERSION }}'" 58 | 59 | - name: Run GoReleaser 60 | uses: goreleaser/goreleaser-action@v6 61 | with: 62 | distribution: goreleaser 63 | version: "~> v2" 64 | args: release --clean 65 | env: 66 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 67 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | .DS_Store 3 | **/*.log 4 | -------------------------------------------------------------------------------- /.golangci.yaml: -------------------------------------------------------------------------------- 1 | run: 2 | timeout: 10m 3 | 4 | linters: 5 | disable-all: true # Disable defaults, then enable the ones we want 6 | enable: 7 | - unused 8 | - errcheck 9 | - gosimple 10 | - govet 11 | - ineffassign 12 | - staticcheck 13 | - typecheck 14 | - unused 15 | - bodyclose 16 | - stylecheck 17 | - gosec 18 | - goimports 19 | - gci 20 | - revive 21 | - gocritic 22 | - unconvert 23 | 24 | linters-settings: 25 | goimports: 26 | local-prefixes: github.com/ArmDeveloperEcosystem 27 | gci: 28 | sections: 29 | - Standard 30 | - Default 31 | - Prefix(github.com/ArmDeveloperEcosystem) 32 | testifylint: 33 | # Enable all checkers (https://github.com/Antonboom/testifylint#checkers). 34 | enable-all: true 35 | -------------------------------------------------------------------------------- /.goreleaser.yaml: -------------------------------------------------------------------------------- 1 | # Goreleaser config for KubeArchInspect 2 | # Make sure to check the documentation at https://goreleaser.com 3 | 4 | # The lines below are called `modelines`. See `:help modeline` 5 | # Feel free to remove those if you don't want/need to use them. 6 | # yaml-language-server: $schema=https://goreleaser.com/static/schema.json 7 | # vim: set ts=2 sw=2 tw=0 fo=cnqoj 8 | 9 | version: 2 10 | 11 | before: 12 | hooks: 13 | - go mod tidy 14 | 15 | builds: 16 | - id: kubearchinspect 17 | env: 18 | - CGO_ENABLED=0 19 | goos: 20 | - linux 21 | - windows 22 | - darwin 23 | goarch: 24 | - amd64 25 | - arm64 26 | main: . 27 | ldflags: 28 | - -s -w 29 | - -X github.com/ArmDeveloperEcosystem/kubearchinspect/cmd.version={{.Version}} 30 | - -X github.com/ArmDeveloperEcosystem/kubearchinspect/cmd.commit={{.Commit}} 31 | - -X github.com/ArmDeveloperEcosystem/kubearchinspect/cmd.date={{.Date}} 32 | 33 | archives: 34 | - formats: tar.gz 35 | # this name template makes the OS and Arch compatible with the results of `uname`. 36 | name_template: >- 37 | {{ .ProjectName }}_ 38 | {{- title .Os }}_ 39 | {{- if eq .Arch "amd64" }}x86_64 40 | {{- else if eq .Arch "386" }}i386 41 | {{- else }}{{ .Arch }}{{ end }} 42 | {{- if .Arm }}v{{ .Arm }}{{ end }} 43 | # use zip for windows archives 44 | format_overrides: 45 | - goos: windows 46 | formats: zip 47 | 48 | changelog: 49 | sort: asc 50 | filters: 51 | exclude: 52 | - "^docs:" 53 | - "^test:" 54 | release: 55 | draft: false 56 | replace_existing_draft: true 57 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | Features 3 | -------- 4 | 5 | - Refine legend wording related to arm64 node compatibility (#31) 6 | 7 | 8 | Features 9 | -------- 10 | 11 | - Add `version` command (#29) 12 | - Update Kubernetes support to v1.33 as well as other Go dependencies (#30) 13 | 14 | 15 | Misc 16 | ---- 17 | 18 | - #20250205 19 | 20 | 21 | Features 22 | -------- 23 | 24 | - Allow to run the application against a given Kube config and K8S context (#24) 25 | 26 | 27 | Misc 28 | ---- 29 | 30 | - #22 31 | 32 | 33 | Features 34 | -------- 35 | 36 | - Added better error messages for common cases, and added a new `-l` flag for logging into a log file. (#19) 37 | - ✨ made the image checks run in parallel (#202412041140) 38 | 39 | 40 | Misc 41 | ---- 42 | 43 | - #20241029 44 | 45 | 46 | Features 47 | -------- 48 | 49 | - Sort images before displaying and improve readability of output. (#15) 50 | 51 | 52 | Misc 53 | ---- 54 | 55 | - #14, #18, #20241024 56 | 57 | 58 | kubearchinspect initial public release 59 | 60 | 61 | Features 62 | -------- 63 | 64 | - Initial release (#13092024) 65 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | 5 | 6 | # Contributor Covenant Code of Conduct 7 | 8 | ## Our Pledge 9 | 10 | We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible 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. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community. 13 | 14 | ## Our Standards 15 | 16 | Examples of behavior that contributes to a positive environment for our community include: 17 | 18 | - Demonstrating empathy and kindness toward other people 19 | - Being respectful of differing opinions, viewpoints, and experiences 20 | - Giving and gracefully accepting constructive feedback 21 | - Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience 22 | - Focusing on what is best not just for us as individuals, but for the overall community 23 | 24 | Examples of unacceptable behavior include: 25 | 26 | - The use of sexualized language or imagery, and sexual attention or 27 | advances of any kind 28 | - Trolling, insulting or derogatory comments, and personal or political attacks 29 | - Public or private harassment 30 | - Publishing others' private information, such as a physical or email 31 | address, without their explicit permission 32 | - Other conduct which could reasonably be considered inappropriate in a 33 | professional setting 34 | 35 | ## Enforcement Responsibilities 36 | 37 | Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful. 38 | 39 | Community leaders 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, and will communicate reasons for moderation decisions when appropriate. 40 | 41 | ## Scope 42 | 43 | This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. 44 | 45 | ## Enforcement 46 | 47 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at . All complaints will be reviewed and investigated promptly and fairly. 48 | 49 | All community leaders are obligated to respect the privacy and security of the reporter of any incident. 50 | 51 | ## Enforcement Guidelines 52 | 53 | Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct: 54 | 55 | ### 1. Correction 56 | 57 | **Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community. 58 | 59 | **Consequence**: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested. 60 | 61 | ### 2. Warning 62 | 63 | **Community Impact**: A violation through a single incident or series of actions. 64 | 65 | **Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban. 66 | 67 | ### 3. Temporary Ban 68 | 69 | **Community Impact**: A serious violation of community standards, including sustained inappropriate behavior. 70 | 71 | **Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban. 72 | 73 | ### 4. Permanent Ban 74 | 75 | **Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals. 76 | 77 | **Consequence**: A permanent ban from any sort of public interaction within the project community. 78 | 79 | ## Attribution 80 | 81 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.0, 82 | available at . 83 | 84 | Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity). 85 | 86 | [homepage]: https://www.contributor-covenant.org 87 | 88 | For answers to common questions about this code of conduct, see the FAQ at 89 | . Translations are available at . 90 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | 5 | 6 | # Contribution Guide 7 | 8 | We really appreciate your contributions to this tool. We are committed to 9 | fostering a welcoming community, please see our Code of Conduct, which can be found here: 10 | 11 | - [Code of Conduct](./CODE_OF_CONDUCT.md) 12 | 13 | There are several ways to contribute: 14 | 15 | - Raise an issue found via [GitHub Issues](https://github.com/ArmDeveloperEcosystem/kubearchinspect/issues). 16 | - Open an [pull request](https://github.com/ArmDeveloperEcosystem/kubearchinspect/pulls) to: 17 | - Provide a fix. 18 | - Add an enhancement feature. 19 | - Correct, update or add documentation. 20 | 21 | ## How to Contribute Documentation or Code 22 | 23 | Please keep contributions small and independent. We would much rather have multiple pull requests for each thing done 24 | rather than have them all in the same one. This will help us review, give feedback and merge in the changes. The 25 | normal process to make a change is as follows: 26 | 27 | 1. Fork the repository. 28 | 2. Make your change and write unit tests, please try to match the existing documentation and coding style. 29 | 3. Add a news file describing the changes and add it in the `/changes` directory, see the section [News Files](#news-files) below. 30 | 4. Write a [good commit message](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html). 31 | 5. Push to your fork. 32 | 6. Submit a pull request. 33 | 34 | We will review the proposed change as soon as we can and, if needed, give feedback. We may ask for updates not only to ensure that the proposed change meets our quality criteria, but also to make sure the that the 35 | change is generally useful and doesn't impact other uses cases or maintainability. 36 | 37 | ### News Files 38 | 39 | News files serve a different purpose to commit messages, which are generally written to inform developers of the 40 | project. News files will form part of the release notes so should be written to target the consumer of the package or 41 | tool. 42 | 43 | - At least, one news file should be added for each Merge/Pull request to the directory `/changes`. 44 | - The text of the file should be a single line describing the change and/or impact to the user. 45 | - The filename of the news file should take the form `.`, e.g, `20191231.feature` where: 46 | - The number is either the issue number or, if no issue exists, the date in the form `YYYYMMDDHHMM`. 47 | - The extension should indicate the type of change as described in the following table: 48 | 49 | | Change Type | Extension | Version Impact | 50 | | ---------------------------------------------------------------------------------------------------------------------- | ---------- | --------------- | 51 | | Backwards compatibility breakages or significant changes denoting a shift direction. | `.major` | Major increment | 52 | | New features and enhancements (non breaking). | `.feature` | Minor increment | 53 | | Bug fixes or corrections (non breaking). | `.bugfix` | Patch increment | 54 | | Documentation impacting the consumer of the package (not repo documentation, such as this file, for this use `.misc`). | `.doc` | N/A | 55 | | Deprecation of functionality or interfaces (not actual removal, for this use `.major`). | `.removal` | None | 56 | | Changes to the repository that do not impact functionality e.g. build scripts change. | `.misc` | None | 57 | 58 | ## Merging the Pull Request 59 | 60 | When merging the pull request we will squash merge the changes, give it a title which provides context to 61 | the changes: 62 | 63 | - ` (#)` 64 | 65 | An emoji is used to highlight what has occurred in the change. Commonly used emojis can be seen below, but for a full 66 | list please see [Gitmoji](https://gitmoji.carloscuesta.me/): 67 | 68 | | Emoji | Topic(s) | 69 | | ----- | ------------------------------------------- | 70 | | ✨ | New features or enhancements. | 71 | | 🐛 | Bug / defect fixes. | 72 | | 🔒 | Fixing security issues. | 73 | | ⚡️ | Improving performance. | 74 | | ♻️ | Refactoring or addressing technical debt. | 75 | | 💥 | Breaking changes or removing functionality. | 76 | | ❗️ | Notice of deprecation. | 77 | | 📝 | Writing or updating documentation. | 78 | | 👷 | Adding to the CI or build system. | 79 | | 💚️ | Fixing CI or build system issues. | 80 | | 🚀 | Releasing or deploying. | 81 | 82 | For more on the version number scheme please see the [ReadMe](./README.md). 83 | 84 | Thank you 85 | -------------------------------------------------------------------------------- /DEVELOPMENT.md: -------------------------------------------------------------------------------- 1 | 5 | 6 | # Development and Testing 7 | 8 | ## Local Development 9 | 10 | ### Build manually 11 | 12 | Clone the repo and run: 13 | 14 | ```sh 15 | go build 16 | ``` 17 | 18 | ### Running tests 19 | 20 | To run all tests: 21 | 22 | ```bash 23 | go test ./... 24 | ``` 25 | 26 | ### Static analysis and linting 27 | 28 | Static analysis tools and linters are run as part of CI. 29 | They come from [golangci-lint](https://golangci-lint.run/). To run this locally: 30 | 31 | ```bash 32 | # Must be in a directory with a go.mod file 33 | cd 34 | golangci-lint run ./... 35 | ``` 36 | 37 | # Releasing 38 | 39 | ## Release workflow 40 | 41 | 1. Navigate to the [GitHub Actions](https://github.com/ArmDeveloperEcosystem/kubearchinspect/actions/workflows/release.yml) page. 42 | 2. Select the **Run Workflow** button. 43 | 44 | ## Version Numbers 45 | 46 | The version number will be automatically calculated, based on the news files. This information will also be displayed when running the `version` command. 47 | -------------------------------------------------------------------------------- /KNOWN_ISSUES.md: -------------------------------------------------------------------------------- 1 | 5 | 6 | # Known Issues 7 | 8 | This project is a work-in-progress and we are not currently tracking issues. 9 | 10 | - It can be slow in large clusters 11 | - Does not handle rate-limiting 12 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright 2025 Arm Limited 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 5 | 6 | # KubeArchInspect 7 | 8 | [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) 9 | [![Main CI/CD](https://github.com/ArmDeveloperEcosystem/kubearchinspect/actions/workflows/main.yml/badge.svg)](https://github.com/ArmDeveloperEcosystem/kubearchinspect/actions/workflows/main.yml) 10 | 11 | ## Overview 12 | 13 | Migrating your websites and services to run on Arm infrastructure can bring benefits in cost savings and performance improvements. The first phase in migrating to Arm is to determine whether the container images in the Kubernetes cluster have support for the Arm architecture. It can be a manual and time consuming task to check compatibility. To make it easier we have developed the `kubearchinspect` tool which automates this process. 14 | 15 | The tool runs on a local client against the cluster to check the metadata of your images for Arm architecture support. If the current version of the image lacks support, it will also check newer versions for compatibility so that you can easily upgrade. 16 | 17 | This is Open Source Software and we appreciate contributions and feedback, please see the [Contribution Guidelines](CONTRIBUTING.md) for more information. 18 | 19 | ## Installation 20 | 21 | Pre-built binaries are available from the [releases page](https://github.com/ArmDeveloperEcosystem/kubearchinspect/releases), alternatively see the [Development Guide](DEVELOPMENT.md) for building locally. 22 | 23 | ## Running 24 | 25 | ### Prerequsites 26 | 27 | This tool includes built-in kubectl and container registry support using the [containers/image](https://github.com/containers/image) library. 28 | You do not need the kubectl, docker, podman, or skopeo CLI tools installed — only their configuration files. 29 | 30 | #### Kubernetes Configuration 31 | 32 | **Kubeconfig** (`~/.kube/config` or set via the `--kube-config-path` flag) 33 | Required to connect to the target Kubernetes cluster. 34 | 35 | Example: For AWS EKS clusters, configure access with: 36 | 37 | ```shell 38 | aws eks update-kubeconfig --region --name 39 | ``` 40 | 41 | If multiple clusters are configured in the `kubeconfig`, the tool will use the default context unless specified using `--kube-context` flag. 42 | 43 | ### Usage 44 | 45 | ```console 46 | kubearchinspect [command] [flags] 47 | ``` 48 | 49 | ### Commands 50 | 51 | - `images` : Check which images in your cluster support arm64 52 | 53 | | Flag | Description | 54 | | --------------------------------- | --------------------------------------------------------------------------- | 55 | | `-c`, `--kube-config-path string` | Path to your Kube config file. (Default: `~/.kube/config`) | 56 | | `--kube-context string` | The Kubernetes context to be used. (Default: Current context in the config) | 57 | 58 | - `version` : Check the version of KubeArchInspect you are running 59 | - `completion` : Generate the autocompletion script for the specified shell 60 | - `help` : Help about any command 61 | 62 | ### Global Flags 63 | 64 | | Flag | Description | 65 | | -------------------- | ----------------- | 66 | | `-d`, `--debug` | Enable debug mode | 67 | | `-l`, `--log string` | Enable logging | 68 | 69 | ## Example 70 | 71 | Output from a small cluster in EKS: 72 | 73 | ```console 74 | % kubearchinspect images 75 | 76 | Legend: 77 | ------- 78 | ✅ - arm64 node compatible 79 | 🆙 - arm64 node compatible (after update) 80 | ❌ - not arm64 node compatible 81 | 🚫 - error occurred 82 | ------------------------------------------------------------------------------------------------ 83 | 84 | 🚫 602401143452.dkr.ecr.eu-west-1.amazonaws.com/eks/csi-snapshotter:v6.3.2-eks-1-28-11 Authentication Error. The private image could not be queried, check the docker credentials are present and correct. 85 | 🚫 602401143452.dkr.ecr.eu-west-1.amazonaws.com/eks/kube-proxy:v1.25.16-minimal-eksbuild.1 Authentication Error. The private image could not be queried, check the docker credentials are present and correct. 86 | 🚫 602401143452.dkr.ecr.eu-west-1.amazonaws.com/eks/livenessprobe:v2.11.0-eks-1-28-11 Authentication Error. The private image could not be queried, check the docker credentials are present and correct. 87 | ✅ amazon/aws-for-fluent-bit:2.10.0 88 | ✅ amazon/cloudwatch-agent:1.247350.0b251780 89 | ✅ busybox:1.31.1 90 | ✅ curlimages/curl:7.85.0 91 | ✅ docker.io/alpine:3.13 92 | ✅ docker.io/bitnami/external-dns:0.14.0-debian-11-r2 93 | 🆙 docker.io/bitnami/metrics-server:0.6.2-debian-11-r20 94 | 🚫 secret.repo.arm.com/jcaap:3.7 Image not found. Some pods like `jcap-replica-pod-2` are using an image that no longer exists. 95 | ✅ mirrors--internal.aws.arm.com/grafana/grafana:9.3.8 96 | ✅ mirrors--internal.aws.arm.com/banzaicloud/vault-secrets-webhook:1.18.0 97 | 🆙 quay.io/argoproj/argocd:v2.0.5 98 | ✅ quay.io/kiwigrid/k8s-sidecar:1.22.0 99 | ✅ quay.io/prometheus-operator/prometheus-config-reloader:v0.63.0 100 | ✅ quay.io/prometheus-operator/prometheus-operator:v0.63.0 101 | ✅ quay.io/prometheus/alertmanager:v0.25.0 102 | ✅ quay.io/prometheus/blackbox-exporter:v0.24.0 103 | ✅ quay.io/prometheus/node-exporter:v1.5.0 104 | ✅ quay.io/prometheus/prometheus:v2.42.0 105 | ✅ redis:6.2.4-alpine 106 | ✅ registry.k8s.io/autoscaling/cluster-autoscaler:v1.25.3 107 | ✅ registry.k8s.io/kube-state-metrics/kube-state-metrics:v2.8.1 108 | ``` 109 | 110 | ### Errors in Output 111 | 112 | If there is an error whilst checking an image, the tool will display the 🚫 symbol and give a short description of the error at the end of the line. The current common errors are: 113 | 114 | - Authentication Error. The private image could not be queried, check the docker credentials are present and correct. 115 | - Communication error. Unable to communication with the registry, please ensure the registry host is available. 116 | - Image not found. One or more pods are using an image that no longer exists. 117 | - Unknown error, run in debug mode using the flag `-d` for more info 118 | 119 | ## Private Registry Authentication 120 | 121 | **Registry credentials** (`~/.docker/config.json` or `$XDG_RUNTIME_DIR/containers/auth.json`) 122 | Required only for accessing **private container registries**. 123 | 124 | > Many organisations and teams use private registries to store their container images for security, compliance, or version control. 125 | > These images are not publicly accessible and require authentication. 126 | 127 | The tool relies on `containers/image`, which uses the same credential configuration as: 128 | 129 | - [`docker login`](https://docs.docker.com/reference/cli/docker/login/) 130 | - [`podman login`](https://docs.podman.io/en/latest/markdown/podman-login.1.html) 131 | - [`skopeo login`](https://man.archlinux.org/man/extra/skopeo/skopeo-login.1.en) 132 | - [`buildah login`](https://manpages.ubuntu.com/manpages/jammy/man1/buildah-login.1.html) 133 | 134 | Any of these commands will populate or update the config file, which includes the necessary authentication tokens or credential store references. 135 | 136 | > Tip: You can use any of the above tools to authenticate. For example: 137 | 138 | ```shell 139 | podman login 140 | ``` 141 | 142 | Credential helpers defined in the config file (such as `credHelpers` or `credsStore`) are also supported. 143 | 144 | ## Releases 145 | 146 | For release notes and a history of changes of all releases, please see the following: 147 | 148 | - [Changelog](CHANGELOG.md) 149 | 150 | ## Project Structure 151 | 152 | The follow described the major aspects of the project structure: 153 | 154 | - `cmd/` - Application command logic. 155 | - `internal/` - Go project source files. 156 | - `changes/` - Collection of news files for unreleased changes. 157 | 158 | ## Getting Help 159 | 160 | - For a list of known issues and possible workarounds, please see [Known Issues](KNOWN_ISSUES.md). 161 | - To raise a defect or enhancement please use [GitHub Issues](https://github.com/ArmDeveloperEcosystem/kubearchinspect/issues). 162 | 163 | ## Contributing 164 | 165 | - We are committed to fostering a welcoming community, please see our 166 | [Code of Conduct](CODE_OF_CONDUCT.md) for more information. 167 | - For ways to contribute to the project, please see the [Contributions Guidelines](CONTRIBUTING.md) 168 | - For a technical introduction into developing this package, please see the [Development Guide](DEVELOPMENT.md) 169 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 5 | 6 | # Security Policy 7 | 8 | ## Reporting a Vulnerability 9 | 10 | If finding a security vulnerability in this library, please report it to us using the following [guidelines](https://developer.arm.com/documentation/102850/latest/). 11 | -------------------------------------------------------------------------------- /changes/32.doc: -------------------------------------------------------------------------------- 1 | Update README.md to clarify prerequisites regarding the kube config and container registry authentication 2 | -------------------------------------------------------------------------------- /changes/README.md: -------------------------------------------------------------------------------- 1 | 5 | 6 | # Changes directory 7 | 8 | This directory comprises information about all the changes that happened since the last release. 9 | 10 | A news file should be added to this directory for each PR. 11 | 12 | On release of the action, the content of the file becomes part of the [change log](../CHANGELOG.md) and this directory is reset. 13 | 14 | See the [contributions guide](../CONTRIBUTING.md) for more details. 15 | -------------------------------------------------------------------------------- /changes/version.properties: -------------------------------------------------------------------------------- 1 | # Semantic version number is automatically maintained by creating news files and releasing via CI. 2 | VERSION=0.7.0 3 | COMMIT=f248a2ca2c2bd4941eb087cb0f6444ec303c6305 4 | MAJOR=0 5 | MINOR=7 6 | PATCH=0 -------------------------------------------------------------------------------- /cmd/images.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 Arm Limited 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package cmd 18 | 19 | import ( 20 | "fmt" 21 | "log" 22 | "os" 23 | "sort" 24 | 25 | "github.com/spf13/cobra" 26 | 27 | "github.com/ArmDeveloperEcosystem/kubearchinspect/internal/images" 28 | "github.com/ArmDeveloperEcosystem/kubearchinspect/internal/k8s" 29 | ) 30 | 31 | const ( 32 | successIcon = "\xE2\x9C\x85" 33 | errorIcon = "\xF0\x9F\x9A\xAB" 34 | failedIcon = "\xE2\x9D\x8C" 35 | upgradeIcon = "\xF0\x9F\x86\x99" 36 | 37 | legend = "Legend:\n-------\n%s - arm64 node compatible\n%s - arm64 node compatible (after update)\n%s - not arm64 node compatible\n%s - error occurred\n%s" 38 | ) 39 | 40 | var ( 41 | kubeConfigPath string 42 | kubeContext string 43 | 44 | imagesCmd = &cobra.Command{ 45 | Use: "images", 46 | Short: "Check which images in your cluster support arm64", 47 | Long: `Check which images in your cluster support arm64`, 48 | Run: imagesCmdRun, 49 | } 50 | ) 51 | 52 | func imagesCmdRun(_ *cobra.Command, _ []string) { 53 | 54 | var loggingEnabled = len(loggingFile) > 0 55 | 56 | if loggingEnabled { 57 | file, err := os.OpenFile(loggingFile, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0666) 58 | if err != nil { 59 | log.Fatal(err) 60 | } 61 | 62 | log.SetOutput(file) 63 | } 64 | 65 | k8sClient, err := k8s.NewKubernetesClient(kubeConfigPath, kubeContext, debugEnabled) 66 | if err != nil { 67 | log.Fatal(err) 68 | } 69 | 70 | imageMap, err := k8sClient.GetAllImages() 71 | if err != nil { 72 | log.Fatal(err) 73 | } 74 | 75 | fmt.Printf( 76 | legend, 77 | successIcon, 78 | upgradeIcon, 79 | failedIcon, 80 | errorIcon, 81 | "------------------------------------------------------------------------------------------------\n\n", 82 | ) 83 | 84 | type result struct { 85 | image string 86 | icon string 87 | err error 88 | } 89 | 90 | results := make(chan result, len(imageMap)) 91 | 92 | for image := range imageMap { 93 | go func(image string) { 94 | var ( 95 | icon string 96 | supportsArm, err = images.CheckLinuxArm64Support(image) 97 | ) 98 | 99 | switch { 100 | case err != nil: 101 | icon = errorIcon 102 | case supportsArm: 103 | icon = successIcon 104 | default: 105 | latestImage := images.GetLatestImage(image) 106 | latestSupportsArm, _ := images.CheckLinuxArm64Support(latestImage) 107 | if latestSupportsArm { 108 | icon = upgradeIcon 109 | } else { 110 | icon = failedIcon 111 | } 112 | } 113 | 114 | results <- result{image: image, icon: icon, err: err} 115 | }(image) 116 | } 117 | 118 | var resultList []result 119 | for range imageMap { 120 | resultList = append(resultList, <-results) 121 | } 122 | 123 | sort.Slice(resultList, func(i, j int) bool { 124 | return resultList[i].image < resultList[j].image 125 | }) 126 | 127 | for _, res := range resultList { 128 | fmt.Printf("%s %s %s\n", res.icon, res.image, images.GetFriendlyErrorMessage(res.err)) 129 | if res.err != nil && debugEnabled { 130 | fmt.Printf("Error: %s\n", res.err) 131 | fmt.Printf("Pods: %s\n", imageMap[res.image]) 132 | } 133 | if res.err != nil && loggingEnabled { 134 | log.Println(res.icon, " image: ", res.image, " error: ", res.err, "\n", imageMap[res.image]) 135 | } 136 | } 137 | } 138 | 139 | func init() { 140 | rootCmd.AddCommand(imagesCmd) 141 | 142 | // Add flags 143 | imagesCmd.PersistentFlags().StringVarP(&kubeConfigPath, "kube-config-path", "c", "", "Path to your Kube config file. (Default: '~/.kube/config')") 144 | imagesCmd.PersistentFlags().StringVarP(&kubeContext, "kube-context", "", "", "The Kubernetes context to be used. (Default: Current context in the config)") 145 | } 146 | -------------------------------------------------------------------------------- /cmd/root.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 Arm Limited 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package cmd 18 | 19 | import ( 20 | "os" 21 | 22 | "github.com/spf13/cobra" 23 | ) 24 | 25 | var debugEnabled bool 26 | var loggingFile string 27 | 28 | var rootCmd = &cobra.Command{ 29 | Use: "kubearchinspect", 30 | Short: "Check how ready your Kubernetes cluster is to run on Arm.", 31 | Long: `Check how ready your Kubernetes cluster is to run on Arm.`, 32 | } 33 | 34 | func Execute() { 35 | err := rootCmd.Execute() 36 | if err != nil { 37 | os.Exit(1) 38 | } 39 | } 40 | 41 | func init() { 42 | // Add flags 43 | rootCmd.PersistentFlags().BoolVarP(&debugEnabled, "debug", "d", false, "Enable debug mode") 44 | rootCmd.PersistentFlags().StringVarP(&loggingFile, "log", "l", "", "Enable logging") 45 | } 46 | -------------------------------------------------------------------------------- /cmd/version.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 Arm Limited 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package cmd 18 | 19 | import ( 20 | "fmt" 21 | 22 | "github.com/spf13/cobra" 23 | ) 24 | 25 | const ascii = ` 26 | _ __ _ _ _____ _ 27 | | |/ / | | /\ | | |_ _| | | 28 | | ' /_ _| |__ ___ / \ _ __ ___| |__ | | _ __ ___ _ __ ___ ___| |_ 29 | | <| | | | '_ \ / _ \ / /\ \ | '__/ __| '_ \ | | | '_ \/ __| '_ \ / _ \/ __| __| 30 | | . \ |_| | |_) | __// ____ \| | | (__| | | |_| |_| | | \__ \ |_) | __/ (__| |_ 31 | |_|\_\__,_|_.__/ \___/_/ \_\_| \___|_| |_|_____|_| |_|___/ .__/ \___|\___|\__| 32 | | | 33 | |_| ` 34 | 35 | var ( 36 | version = "dev" 37 | commit = "none" 38 | date = "unknown" 39 | 40 | versionCmd = &cobra.Command{ 41 | Use: "version", 42 | Short: "Check the version of KubeArchInspect you are running", 43 | Long: `Check the version of KubeArchInspect you are running`, 44 | Run: versionCmdRun, 45 | } 46 | ) 47 | 48 | func versionCmdRun(_ *cobra.Command, _ []string) { 49 | fmt.Println(ascii) 50 | fmt.Printf("Version: %s\nCommit: %s\nBuilt at: %s\n", version, commit, date) 51 | } 52 | 53 | func init() { 54 | rootCmd.AddCommand(versionCmd) 55 | } 56 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/ArmDeveloperEcosystem/kubearchinspect 2 | 3 | go 1.24.2 4 | 5 | require ( 6 | github.com/containers/image/v5 v5.35.0 7 | github.com/spf13/cobra v1.9.1 8 | github.com/stretchr/testify v1.10.0 9 | k8s.io/api v0.33.0 10 | k8s.io/apimachinery v0.33.0 11 | k8s.io/client-go v0.33.0 12 | ) 13 | 14 | require ( 15 | dario.cat/mergo v1.0.1 // indirect 16 | github.com/BurntSushi/toml v1.5.0 // indirect 17 | github.com/Microsoft/go-winio v0.6.2 // indirect 18 | github.com/Microsoft/hcsshim v0.12.9 // indirect 19 | github.com/containerd/cgroups/v3 v3.0.5 // indirect 20 | github.com/containerd/errdefs v1.0.0 // indirect 21 | github.com/containerd/errdefs/pkg v0.3.0 // indirect 22 | github.com/containerd/stargz-snapshotter/estargz v0.16.3 // indirect 23 | github.com/containerd/typeurl/v2 v2.2.3 // indirect 24 | github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01 // indirect 25 | github.com/containers/ocicrypt v1.2.1 // indirect 26 | github.com/containers/storage v1.58.0 // indirect 27 | github.com/cyphar/filepath-securejoin v0.4.1 // indirect 28 | github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect 29 | github.com/distribution/reference v0.6.0 // indirect 30 | github.com/docker/distribution v2.8.3+incompatible // indirect 31 | github.com/docker/docker v28.1.1+incompatible // indirect 32 | github.com/docker/docker-credential-helpers v0.9.3 // indirect 33 | github.com/docker/go-connections v0.5.0 // indirect 34 | github.com/docker/go-units v0.5.0 // indirect 35 | github.com/emicklei/go-restful/v3 v3.12.2 // indirect 36 | github.com/felixge/httpsnoop v1.0.4 // indirect 37 | github.com/fxamacker/cbor/v2 v2.8.0 // indirect 38 | github.com/go-logr/logr v1.4.2 // indirect 39 | github.com/go-logr/stdr v1.2.2 // indirect 40 | github.com/go-openapi/jsonpointer v0.21.1 // indirect 41 | github.com/go-openapi/jsonreference v0.21.0 // indirect 42 | github.com/go-openapi/swag v0.23.1 // indirect 43 | github.com/gogo/protobuf v1.3.2 // indirect 44 | github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect 45 | github.com/google/gnostic-models v0.6.9 // indirect 46 | github.com/google/go-cmp v0.7.0 // indirect 47 | github.com/google/go-containerregistry v0.20.3 // indirect 48 | github.com/google/go-intervals v0.0.2 // indirect 49 | github.com/google/uuid v1.6.0 // indirect 50 | github.com/gorilla/mux v1.8.1 // indirect 51 | github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 // indirect 52 | github.com/inconshreveable/mousetrap v1.1.0 // indirect 53 | github.com/josharian/intern v1.0.0 // indirect 54 | github.com/json-iterator/go v1.1.12 // indirect 55 | github.com/klauspost/compress v1.18.0 // indirect 56 | github.com/klauspost/pgzip v1.2.6 // indirect 57 | github.com/mailru/easyjson v0.9.0 // indirect 58 | github.com/mistifyio/go-zfs/v3 v3.0.1 // indirect 59 | github.com/moby/docker-image-spec v1.3.1 // indirect 60 | github.com/moby/sys/atomicwriter v0.1.0 // indirect 61 | github.com/moby/sys/capability v0.4.0 // indirect 62 | github.com/moby/sys/mountinfo v0.7.2 // indirect 63 | github.com/moby/sys/user v0.4.0 // indirect 64 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 65 | github.com/modern-go/reflect2 v1.0.2 // indirect 66 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect 67 | github.com/opencontainers/go-digest v1.0.0 // indirect 68 | github.com/opencontainers/image-spec v1.1.1 // indirect 69 | github.com/opencontainers/runtime-spec v1.2.1 // indirect 70 | github.com/opencontainers/selinux v1.12.0 // indirect 71 | github.com/ostreedev/ostree-go v0.0.0-20210805093236-719684c64e4f // indirect 72 | github.com/pkg/errors v0.9.1 // indirect 73 | github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect 74 | github.com/sirupsen/logrus v1.9.3 // indirect 75 | github.com/spf13/pflag v1.0.6 // indirect 76 | github.com/sylabs/sif/v2 v2.21.1 // indirect 77 | github.com/tchap/go-patricia/v2 v2.3.2 // indirect 78 | github.com/ulikunitz/xz v0.5.14 // indirect 79 | github.com/vbatts/tar-split v0.12.1 // indirect 80 | github.com/x448/float16 v0.8.4 // indirect 81 | go.opencensus.io v0.24.0 // indirect 82 | go.opentelemetry.io/auto/sdk v1.1.0 // indirect 83 | go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 // indirect 84 | go.opentelemetry.io/otel v1.35.0 // indirect 85 | go.opentelemetry.io/otel/metric v1.35.0 // indirect 86 | go.opentelemetry.io/otel/trace v1.35.0 // indirect 87 | golang.org/x/net v0.39.0 // indirect 88 | golang.org/x/oauth2 v0.29.0 // indirect 89 | golang.org/x/sync v0.13.0 // indirect 90 | golang.org/x/sys v0.32.0 // indirect 91 | golang.org/x/term v0.31.0 // indirect 92 | golang.org/x/text v0.24.0 // indirect 93 | golang.org/x/time v0.11.0 // indirect 94 | google.golang.org/genproto/googleapis/rpc v0.0.0-20250428153025-10db94c68c34 // indirect 95 | google.golang.org/grpc v1.72.0 // indirect 96 | google.golang.org/protobuf v1.36.6 // indirect 97 | gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect 98 | gopkg.in/inf.v0 v0.9.1 // indirect 99 | gopkg.in/yaml.v3 v3.0.1 // indirect 100 | k8s.io/klog/v2 v2.130.1 // indirect 101 | k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff // indirect 102 | k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e // indirect 103 | sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect 104 | sigs.k8s.io/randfill v1.0.0 // indirect 105 | sigs.k8s.io/structured-merge-diff/v4 v4.7.0 // indirect 106 | sigs.k8s.io/yaml v1.4.0 // indirect 107 | ) 108 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 2 | dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= 3 | dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= 4 | github.com/14rcole/gopopulate v0.0.0-20180821133914-b175b219e774 h1:SCbEWT58NSt7d2mcFdvxC9uyrdcTfvBbPLThhkDmXzg= 5 | github.com/14rcole/gopopulate v0.0.0-20180821133914-b175b219e774/go.mod h1:6/0dYRLLXyJjbkIPeeGyoJ/eKOSI0eU6eTlCBYibgd0= 6 | github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= 7 | github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= 8 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 9 | github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg= 10 | github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= 11 | github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= 12 | github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= 13 | github.com/Microsoft/hcsshim v0.12.9 h1:2zJy5KA+l0loz1HzEGqyNnjd3fyZA31ZBCGKacp6lLg= 14 | github.com/Microsoft/hcsshim v0.12.9/go.mod h1:fJ0gkFAna6ukt0bLdKB8djt4XIJhF/vEPuoIWYVvZ8Y= 15 | github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= 16 | github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= 17 | github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= 18 | github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= 19 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 20 | github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= 21 | github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 22 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 23 | github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= 24 | github.com/containerd/cgroups/v3 v3.0.5 h1:44na7Ud+VwyE7LIoJ8JTNQOa549a8543BmzaJHo6Bzo= 25 | github.com/containerd/cgroups/v3 v3.0.5/go.mod h1:SA5DLYnXO8pTGYiAHXz94qvLQTKfVM5GEVisn4jpins= 26 | github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI= 27 | github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M= 28 | github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE= 29 | github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk= 30 | github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= 31 | github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= 32 | github.com/containerd/stargz-snapshotter/estargz v0.16.3 h1:7evrXtoh1mSbGj/pfRccTampEyKpjpOnS3CyiV1Ebr8= 33 | github.com/containerd/stargz-snapshotter/estargz v0.16.3/go.mod h1:uyr4BfYfOj3G9WBVE8cOlQmXAbPN9VEQpBBeJIuOipU= 34 | github.com/containerd/typeurl/v2 v2.2.3 h1:yNA/94zxWdvYACdYO8zofhrTVuQY73fFU1y++dYSw40= 35 | github.com/containerd/typeurl/v2 v2.2.3/go.mod h1:95ljDnPfD3bAbDJRugOiShd/DlAAsxGtUBhJxIn7SCk= 36 | github.com/containers/image/v5 v5.35.0 h1:T1OeyWp3GjObt47bchwD9cqiaAm/u4O4R9hIWdrdrP8= 37 | github.com/containers/image/v5 v5.35.0/go.mod h1:8vTsgb+1gKcBL7cnjyNOInhJQfTUQjJoO2WWkKDoebM= 38 | github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01 h1:Qzk5C6cYglewc+UyGf6lc8Mj2UaPTHy/iF2De0/77CA= 39 | github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01/go.mod h1:9rfv8iPl1ZP7aqh9YA68wnZv2NUDbXdcdPHVz0pFbPY= 40 | github.com/containers/ocicrypt v1.2.1 h1:0qIOTT9DoYwcKmxSt8QJt+VzMY18onl9jUXsxpVhSmM= 41 | github.com/containers/ocicrypt v1.2.1/go.mod h1:aD0AAqfMp0MtwqWgHM1bUwe1anx0VazI108CRrSKINQ= 42 | github.com/containers/storage v1.58.0 h1:Q7SyyCCjqgT3wYNgRNIL8o/wUS92heIj2/cc8Sewvcc= 43 | github.com/containers/storage v1.58.0/go.mod h1:w7Jl6oG+OpeLGLzlLyOZPkmUso40kjpzgrHUk5tyBlo= 44 | github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= 45 | github.com/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s= 46 | github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI= 47 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 48 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 49 | github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= 50 | github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 51 | github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= 52 | github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= 53 | github.com/docker/cli v28.0.4+incompatible h1:pBJSJeNd9QeIWPjRcV91RVJihd/TXB77q1ef64XEu4A= 54 | github.com/docker/cli v28.0.4+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= 55 | github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk= 56 | github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= 57 | github.com/docker/docker v28.1.1+incompatible h1:49M11BFLsVO1gxY9UX9p/zwkE/rswggs8AdFmXQw51I= 58 | github.com/docker/docker v28.1.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= 59 | github.com/docker/docker-credential-helpers v0.9.3 h1:gAm/VtF9wgqJMoxzT3Gj5p4AqIjCBS4wrsOh9yRqcz8= 60 | github.com/docker/docker-credential-helpers v0.9.3/go.mod h1:x+4Gbw9aGmChi3qTLZj8Dfn0TD20M/fuWy0E5+WDeCo= 61 | github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= 62 | github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= 63 | github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8= 64 | github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= 65 | github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= 66 | github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= 67 | github.com/emicklei/go-restful/v3 v3.12.2 h1:DhwDP0vY3k8ZzE0RunuJy8GhNpPL6zqLkDf9B/a0/xU= 68 | github.com/emicklei/go-restful/v3 v3.12.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= 69 | github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 70 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 71 | github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= 72 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= 73 | github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= 74 | github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= 75 | github.com/fxamacker/cbor/v2 v2.8.0 h1:fFtUGXUzXPHTIUdne5+zzMPTfffl3RD5qYnkY40vtxU= 76 | github.com/fxamacker/cbor/v2 v2.8.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= 77 | github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= 78 | github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= 79 | github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= 80 | github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= 81 | github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= 82 | github.com/go-openapi/jsonpointer v0.21.1 h1:whnzv/pNXtK2FbX/W9yJfRmE2gsmkfahjMKB0fZvcic= 83 | github.com/go-openapi/jsonpointer v0.21.1/go.mod h1:50I1STOfbY1ycR8jGz8DaMeLCdXiI6aDteEdRNNzpdk= 84 | github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= 85 | github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= 86 | github.com/go-openapi/swag v0.23.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU= 87 | github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0= 88 | github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= 89 | github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= 90 | github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= 91 | github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= 92 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 93 | github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 94 | github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ= 95 | github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw= 96 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 97 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 98 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 99 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= 100 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= 101 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= 102 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= 103 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= 104 | github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= 105 | github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 106 | github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= 107 | github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= 108 | github.com/google/gnostic-models v0.6.9 h1:MU/8wDLif2qCXZmzncUQ/BOfxWfthHi63KqpoNbWqVw= 109 | github.com/google/gnostic-models v0.6.9/go.mod h1:CiWsm0s6BSQd1hRn8/QmxqB6BesYcbSZxsz9b0KuDBw= 110 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 111 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 112 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 113 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 114 | github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 115 | github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 116 | github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 117 | github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= 118 | github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= 119 | github.com/google/go-containerregistry v0.20.3 h1:oNx7IdTI936V8CQRveCjaxOiegWwvM7kqkbXTpyiovI= 120 | github.com/google/go-containerregistry v0.20.3/go.mod h1:w00pIgBRDVUDFM6bq+Qx8lwNWK+cxgCuX1vd3PIBDNI= 121 | github.com/google/go-intervals v0.0.2 h1:FGrVEiUnTRKR8yE04qzXYaJMtnIYqobR5QbblK3ixcM= 122 | github.com/google/go-intervals v0.0.2/go.mod h1:MkaR3LNRfeKLPmqgJYs4E66z5InYjmCjbbr4TQlcT6Y= 123 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 124 | github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo= 125 | github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= 126 | github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 127 | github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 128 | github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= 129 | github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 130 | github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= 131 | github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= 132 | github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 h1:TmHmbvxPmaegwhDubVz0lICL0J5Ka2vwTzhoePEXsGE= 133 | github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0/go.mod h1:qztMSjm835F2bXf+5HKAPIS5qsmQDqZna/PgVt4rWtI= 134 | github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= 135 | github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= 136 | github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= 137 | github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= 138 | github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= 139 | github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 140 | github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= 141 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 142 | github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= 143 | github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= 144 | github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU= 145 | github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= 146 | github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= 147 | github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= 148 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 149 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 150 | github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= 151 | github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= 152 | github.com/mistifyio/go-zfs/v3 v3.0.1 h1:YaoXgBePoMA12+S1u/ddkv+QqxcfiZK4prI6HPnkFiU= 153 | github.com/mistifyio/go-zfs/v3 v3.0.1/go.mod h1:CzVgeB0RvF2EGzQnytKVvVSDwmKJXxkOTUGbNrTja/k= 154 | github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= 155 | github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= 156 | github.com/moby/sys/atomicwriter v0.1.0 h1:kw5D/EqkBwsBFi0ss9v1VG3wIkVhzGvLklJ+w3A14Sw= 157 | github.com/moby/sys/atomicwriter v0.1.0/go.mod h1:Ul8oqv2ZMNHOceF643P6FKPXeCmYtlQMvpizfsSoaWs= 158 | github.com/moby/sys/capability v0.4.0 h1:4D4mI6KlNtWMCM1Z/K0i7RV1FkX+DBDHKVJpCndZoHk= 159 | github.com/moby/sys/capability v0.4.0/go.mod h1:4g9IK291rVkms3LKCDOoYlnV8xKwoDTpIrNEE35Wq0I= 160 | github.com/moby/sys/mountinfo v0.7.2 h1:1shs6aH5s4o5H2zQLn796ADW1wMrIwHsyJ2v9KouLrg= 161 | github.com/moby/sys/mountinfo v0.7.2/go.mod h1:1YOa8w8Ih7uW0wALDUgT1dTTSBrZ+HiBLGws92L2RU4= 162 | github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU= 163 | github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko= 164 | github.com/moby/sys/user v0.4.0 h1:jhcMKit7SA80hivmFJcbB1vqmw//wU61Zdui2eQXuMs= 165 | github.com/moby/sys/user v0.4.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs= 166 | github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ= 167 | github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc= 168 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 169 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= 170 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 171 | github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= 172 | github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= 173 | github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= 174 | github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= 175 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= 176 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= 177 | github.com/onsi/ginkgo/v2 v2.21.0 h1:7rg/4f3rB88pb5obDgNZrNHrQ4e6WpjonchcpuBRnZM= 178 | github.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= 179 | github.com/onsi/gomega v1.35.1 h1:Cwbd75ZBPxFSuZ6T+rN/WCb/gOc6YgFBXLlZLhC7Ds4= 180 | github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog= 181 | github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= 182 | github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= 183 | github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= 184 | github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= 185 | github.com/opencontainers/runtime-spec v1.2.1 h1:S4k4ryNgEpxW1dzyqffOmhI1BHYcjzU8lpJfSlR0xww= 186 | github.com/opencontainers/runtime-spec v1.2.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= 187 | github.com/opencontainers/selinux v1.12.0 h1:6n5JV4Cf+4y0KNXW48TLj5DwfXpvWlxXplUkdTrmPb8= 188 | github.com/opencontainers/selinux v1.12.0/go.mod h1:BTPX+bjVbWGXw7ZZWUbdENt8w0htPSrlgOOysQaU62U= 189 | github.com/ostreedev/ostree-go v0.0.0-20210805093236-719684c64e4f h1:/UDgs8FGMqwnHagNDPGOlts35QkhAZ8by3DR7nMih7M= 190 | github.com/ostreedev/ostree-go v0.0.0-20210805093236-719684c64e4f/go.mod h1:J6OG6YJVEWopen4avK3VNQSnALmmjvniMmni/YFYAwc= 191 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 192 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 193 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 194 | github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= 195 | github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 196 | github.com/prometheus/client_golang v1.21.1 h1:DOvXXTqVzvkIewV/CDPFdejpMCGeMcbGCQ8YOmu+Ibk= 197 | github.com/prometheus/client_golang v1.21.1/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg= 198 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 199 | github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= 200 | github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= 201 | github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io= 202 | github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I= 203 | github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= 204 | github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= 205 | github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= 206 | github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= 207 | github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 208 | github.com/sebdah/goldie/v2 v2.5.5 h1:rx1mwF95RxZ3/83sdS4Yp7t2C5TCokvWP4TBRbAyEWY= 209 | github.com/sebdah/goldie/v2 v2.5.5/go.mod h1:oZ9fp0+se1eapSRjfYbsV/0Hqhbuu3bJVvKI/NNtssI= 210 | github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= 211 | github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= 212 | github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= 213 | github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= 214 | github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= 215 | github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= 216 | github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= 217 | github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 218 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 219 | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= 220 | github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= 221 | github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= 222 | github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= 223 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 224 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 225 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 226 | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= 227 | github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= 228 | github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= 229 | github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 230 | github.com/sylabs/sif/v2 v2.21.1 h1:GZ0b5//AFAqJEChd8wHV/uSKx/l1iuGYwjR8nx+4wPI= 231 | github.com/sylabs/sif/v2 v2.21.1/go.mod h1:YoqEGQnb5x/ItV653bawXHZJOXQaEWpGwHsSD3YePJI= 232 | github.com/tchap/go-patricia/v2 v2.3.2 h1:xTHFutuitO2zqKAQ5rCROYgUb7Or/+IC3fts9/Yc7nM= 233 | github.com/tchap/go-patricia/v2 v2.3.2/go.mod h1:VZRHKAb53DLaG+nA9EaYYiaEx6YztwDlLElMsnSHD4k= 234 | github.com/ulikunitz/xz v0.5.14 h1:uv/0Bq533iFdnMHZdRBTOlaNMdb1+ZxXIlHDZHIHcvg= 235 | github.com/ulikunitz/xz v0.5.14/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= 236 | github.com/vbatts/tar-split v0.12.1 h1:CqKoORW7BUWBe7UL/iqTVvkTBOF8UvOMKOIZykxnnbo= 237 | github.com/vbatts/tar-split v0.12.1/go.mod h1:eF6B6i6ftWQcDqEn3/iGFRFRo8cBIMSJVOpnNdfTMFA= 238 | github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= 239 | github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= 240 | github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 241 | github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 242 | go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= 243 | go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= 244 | go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= 245 | go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= 246 | go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 h1:sbiXRNDSWJOTobXh5HyQKjq6wUC5tNybqjIqDpAY4CU= 247 | go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0/go.mod h1:69uWxva0WgAA/4bu2Yy70SLDBwZXuQ6PbBpbsa5iZrQ= 248 | go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ= 249 | go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y= 250 | go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.33.0 h1:Vh5HayB/0HHfOQA7Ctx69E/Y/DcQSMPpKANYVMQ7fBA= 251 | go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.33.0/go.mod h1:cpgtDBaqD/6ok/UG0jT15/uKjAY8mRA53diogHBg3UI= 252 | go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.33.0 h1:wpMfgF8E1rkrT1Z6meFh1NDtownE9Ii3n3X2GJYjsaU= 253 | go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.33.0/go.mod h1:wAy0T/dUbs468uOlkT31xjvqQgEVXv58BRFWEgn5v/0= 254 | go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M= 255 | go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE= 256 | go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY= 257 | go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg= 258 | go.opentelemetry.io/otel/sdk/metric v1.35.0 h1:1RriWBmCKgkeHEhM7a2uMjMUfP7MsOF5JpUCaEqEI9o= 259 | go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w= 260 | go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs= 261 | go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc= 262 | go.opentelemetry.io/proto/otlp v1.4.0 h1:TA9WRvW6zMwP+Ssb6fLoUIuirti1gGbP28GcKG1jgeg= 263 | go.opentelemetry.io/proto/otlp v1.4.0/go.mod h1:PPBWZIP98o2ElSqI35IHfu7hIhSwvc5N38Jw8pXuGFY= 264 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 265 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 266 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 267 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 268 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 269 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 270 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 271 | golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 272 | golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 273 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 274 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 275 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 276 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 277 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 278 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 279 | golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 280 | golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 281 | golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 282 | golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY= 283 | golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E= 284 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 285 | golang.org/x/oauth2 v0.29.0 h1:WdYw2tdTK1S8olAzWHdgeqfy+Mtm9XNhv/xJsY65d98= 286 | golang.org/x/oauth2 v0.29.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= 287 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 288 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 289 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 290 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 291 | golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 292 | golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610= 293 | golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= 294 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 295 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 296 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 297 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 298 | golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 299 | golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= 300 | golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= 301 | golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o= 302 | golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw= 303 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 304 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 305 | golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0= 306 | golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU= 307 | golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0= 308 | golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= 309 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 310 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 311 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 312 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 313 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 314 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 315 | golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 316 | golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 317 | golang.org/x/tools v0.29.0 h1:Xx0h3TtM9rzQpQuR4dKLrdglAmCEN5Oi+P74JdhdzXE= 318 | golang.org/x/tools v0.29.0/go.mod h1:KMQVMRsVxU6nHCFXrBPhDB8XncLNLM0lIy/F14RP588= 319 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 320 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 321 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 322 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 323 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 324 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 325 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 326 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 327 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= 328 | google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80 h1:KAeGQVN3M9nD0/bQXnr/ClcEMJ968gUXJQ9pwfSynuQ= 329 | google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb h1:p31xT4yrYrSM/G4Sn2+TNUkVhFCbG9y8itM2S6Th950= 330 | google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:jbe3Bkdp+Dh2IrslsFCklNhweNTBgSYanP1UXhJDhKg= 331 | google.golang.org/genproto/googleapis/rpc v0.0.0-20250428153025-10db94c68c34 h1:h6p3mQqrmT1XkHVTfzLdNz1u7IhINeZkz67/xTbOuWs= 332 | google.golang.org/genproto/googleapis/rpc v0.0.0-20250428153025-10db94c68c34/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= 333 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 334 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 335 | google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= 336 | google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 337 | google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= 338 | google.golang.org/grpc v1.72.0 h1:S7UkcVa60b5AAQTaO6ZKamFp1zMZSU0fGDK2WZLbBnM= 339 | google.golang.org/grpc v1.72.0/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= 340 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= 341 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= 342 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= 343 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= 344 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= 345 | google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 346 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 347 | google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 348 | google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= 349 | google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= 350 | google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= 351 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 352 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= 353 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= 354 | gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4= 355 | gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= 356 | gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= 357 | gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= 358 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 359 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 360 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 361 | gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q= 362 | gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA= 363 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 364 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 365 | k8s.io/api v0.33.0 h1:yTgZVn1XEe6opVpP1FylmNrIFWuDqe2H0V8CT5gxfIU= 366 | k8s.io/api v0.33.0/go.mod h1:CTO61ECK/KU7haa3qq8sarQ0biLq2ju405IZAd9zsiM= 367 | k8s.io/apimachinery v0.33.0 h1:1a6kHrJxb2hs4t8EE5wuR/WxKDwGN1FKH3JvDtA0CIQ= 368 | k8s.io/apimachinery v0.33.0/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM= 369 | k8s.io/client-go v0.33.0 h1:UASR0sAYVUzs2kYuKn/ZakZlcs2bEHaizrrHUZg0G98= 370 | k8s.io/client-go v0.33.0/go.mod h1:kGkd+l/gNGg8GYWAPr0xF1rRKvVWvzh9vmZAMXtaKOg= 371 | k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= 372 | k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= 373 | k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff h1:/usPimJzUKKu+m+TE36gUyGcf03XZEP0ZIKgKj35LS4= 374 | k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff/go.mod h1:5jIi+8yX4RIb8wk3XwBo5Pq2ccx4FP10ohkbSKCZoK8= 375 | k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e h1:KqK5c/ghOm8xkHYhlodbp6i6+r+ChV2vuAuVRdFbLro= 376 | k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= 377 | sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE= 378 | sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= 379 | sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= 380 | sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= 381 | sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= 382 | sigs.k8s.io/structured-merge-diff/v4 v4.7.0 h1:qPeWmscJcXP0snki5IYF79Z8xrl8ETFxgMd7wez1XkI= 383 | sigs.k8s.io/structured-merge-diff/v4 v4.7.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps= 384 | sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= 385 | sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= 386 | -------------------------------------------------------------------------------- /internal/images/images.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 Arm Limited 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package images 18 | 19 | import ( 20 | "context" 21 | "fmt" 22 | "os" 23 | "path/filepath" 24 | "strings" 25 | 26 | "github.com/containers/image/v5/image" 27 | "github.com/containers/image/v5/transports/alltransports" 28 | "github.com/containers/image/v5/types" 29 | ) 30 | 31 | func containsAnyOf(input string, suggestions []string) bool { 32 | for _, suggestion := range suggestions { 33 | if strings.Contains(input, suggestion) { 34 | return true 35 | } 36 | } 37 | return false 38 | } 39 | 40 | func getDockerConfigPath() string { 41 | home, err := os.UserHomeDir() 42 | if err != nil { 43 | return "" 44 | } 45 | return filepath.Join(home, ".docker", "config.json") 46 | } 47 | 48 | func GetFriendlyErrorMessage(err error) string { 49 | if err == nil { 50 | return "" 51 | } 52 | 53 | errorMessage := err.Error() 54 | switch { 55 | case containsAnyOf(errorMessage, []string{"authentication", "auth", "authorized"}): 56 | return " Authentication Error. The private image could not be queried, please check the docker credentials are present and correct." 57 | case containsAnyOf(errorMessage, []string{"no image found", "image not found"}): 58 | return " Image not found. One or more pods are using an image that no longer exists." 59 | case containsAnyOf(errorMessage, []string{"no such host"}): 60 | return " Communication error. Unable to communicate with the registry, please ensure the registry host is available." 61 | default: 62 | return " An unknown error occurred. Please run in debug mode using the flag '-d' for more details." 63 | } 64 | } 65 | 66 | // CheckLinuxArm64Support checks for the existance of an arm64 linux image in the manifest 67 | func CheckLinuxArm64Support(imgName string) (bool, error) { 68 | sys := &types.SystemContext{ 69 | ArchitectureChoice: "arm64", 70 | OSChoice: "linux", 71 | DockerCompatAuthFilePath: getDockerConfigPath(), 72 | } 73 | 74 | // Docker references with both a tag and digest are currently not supported 75 | imgName = removeTagIfDigestExists(imgName) 76 | 77 | ref, err := alltransports.ParseImageName(fmt.Sprintf("docker://%s", imgName)) 78 | if err != nil { 79 | return false, fmt.Errorf("error parsing image name: %w", err) 80 | } 81 | 82 | src, err := ref.NewImageSource(context.Background(), sys) 83 | if err != nil { 84 | return false, fmt.Errorf("error getting image source: %w", err) 85 | } 86 | defer src.Close() 87 | 88 | img, err := image.FromUnparsedImage(context.TODO(), sys, image.UnparsedInstance(src, nil)) 89 | if err != nil { 90 | return false, fmt.Errorf("error parsing manifest: %w", err) 91 | } 92 | 93 | imgInspect, err := img.Inspect(context.TODO()) 94 | if err != nil { 95 | return false, fmt.Errorf("error inspecting image: %w", err) 96 | } 97 | 98 | return imgInspect.Architecture == "arm64", nil 99 | } 100 | 101 | func removeTagIfDigestExists(imgName string) string { 102 | // check for empty string 103 | if imgName == "" { 104 | return imgName 105 | } 106 | 107 | if strings.Contains(imgName, "@") { 108 | parts := strings.Split(imgName, "@") 109 | // Check if the first part contains a colon, indicating a tag 110 | if strings.Contains(parts[0], ":") { 111 | subParts := strings.Split(parts[0], ":") 112 | // Reconstruct the image name without the tag 113 | imgName = subParts[0] + "@" + parts[1] 114 | } 115 | } 116 | return imgName 117 | } 118 | 119 | func GetLatestImage(imgName string) string { 120 | 121 | // check for empty string 122 | if imgName == "" { 123 | return imgName 124 | } 125 | 126 | // Remove everything after '@' or ':' 127 | parts := strings.FieldsFunc(imgName, func(c rune) bool { 128 | return c == '@' || c == ':' 129 | }) 130 | 131 | return parts[0] + ":latest" 132 | } 133 | -------------------------------------------------------------------------------- /internal/images/images_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 Arm Limited 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package images 18 | 19 | import ( 20 | "testing" 21 | 22 | "github.com/stretchr/testify/assert" 23 | ) 24 | 25 | func TestRemoveTagIfDigestExists(t *testing.T) { 26 | 27 | tests := []struct { 28 | name string 29 | imgName string 30 | want string 31 | }{ 32 | { 33 | name: "Both digest and tag exist", 34 | imgName: "testingImage:latest@sha256:1234567890abcdefghijklmnopqrstuvwxyzabcdefg", 35 | want: "testingImage@sha256:1234567890abcdefghijklmnopqrstuvwxyzabcdefg", 36 | }, 37 | { 38 | name: "Only digest exists", 39 | imgName: "testingImage@sha256:1234567890abcdefghijklmnopqrstuvwxyzabcdefg", 40 | want: "testingImage@sha256:1234567890abcdefghijklmnopqrstuvwxyzabcdefg", 41 | }, 42 | { 43 | name: "Only tag exists", 44 | imgName: "testingImage:latest", 45 | want: "testingImage:latest", 46 | }, 47 | { 48 | name: "Empty string", 49 | imgName: "", 50 | want: "", 51 | }, 52 | { 53 | name: "No tag or digest", 54 | imgName: "testingImage", 55 | want: "testingImage", 56 | }, 57 | } 58 | 59 | for _, tt := range tests { 60 | t.Run(tt.name, func(t *testing.T) { 61 | assert.Equal(t, tt.want, removeTagIfDigestExists(tt.imgName)) 62 | }) 63 | } 64 | } 65 | 66 | func TestGetLatestImage(t *testing.T) { 67 | 68 | tests := []struct { 69 | name string 70 | imgName string 71 | want string 72 | }{ 73 | { 74 | name: "Image with a tag", 75 | imgName: "nginx:v1", 76 | want: "nginx:latest", 77 | }, 78 | { 79 | name: "Image with no tag", 80 | imgName: "nginx", 81 | want: "nginx:latest", 82 | }, 83 | { 84 | name: "Image with no tag but with digest", 85 | imgName: "nginx@sha256:1114555554555", 86 | want: "nginx:latest", 87 | }, 88 | { 89 | name: "Image with a tag and digest", 90 | imgName: "nginx:v2@sha256:1114555554555", 91 | want: "nginx:latest", 92 | }, 93 | { 94 | name: "Empty string", 95 | imgName: "", 96 | want: "", 97 | }, 98 | } 99 | 100 | for _, tt := range tests { 101 | t.Run(tt.name, func(t *testing.T) { 102 | t.Run(tt.name, func(t *testing.T) { 103 | assert.Equal(t, tt.want, GetLatestImage(tt.imgName)) 104 | }) 105 | }) 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /internal/k8s/k8s.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 Arm Limited 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package k8s 18 | 19 | import ( 20 | "context" 21 | "log" 22 | "os" 23 | "path/filepath" 24 | 25 | corev1 "k8s.io/api/core/v1" 26 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 27 | "k8s.io/client-go/kubernetes" 28 | "k8s.io/client-go/tools/clientcmd" 29 | ) 30 | 31 | type KubernetesClient struct { 32 | clientset kubernetes.Clientset 33 | } 34 | 35 | func NewKubernetesClient(kubeconfigPath, context string, debug bool) (*KubernetesClient, error) { 36 | // Check if user provided the kubeconfig location 37 | if kubeconfigPath == "" { 38 | // Try the kubeconfig in the default location 39 | home, err := os.UserHomeDir() 40 | if err != nil { 41 | return nil, err 42 | } 43 | 44 | kubeconfigPath = filepath.Join(home, ".kube", "config") 45 | } 46 | 47 | configOverrides := &clientcmd.ConfigOverrides{} 48 | if context != "" { 49 | configOverrides.CurrentContext = context 50 | } 51 | 52 | // Build the configuration from the kubeconfig file and overrides 53 | config, err := clientcmd.NewNonInteractiveDeferredLoadingClientConfig( 54 | &clientcmd.ClientConfigLoadingRules{ExplicitPath: kubeconfigPath}, 55 | configOverrides, 56 | ).ClientConfig() 57 | if err != nil { 58 | return nil, err 59 | } 60 | 61 | // Log the context being used 62 | if debug { 63 | log.Println("Using the kube config file at", kubeconfigPath) 64 | if context == "" { 65 | rawConfig, err := clientcmd.LoadFromFile(kubeconfigPath) 66 | if err != nil { 67 | return nil, err 68 | } 69 | context = rawConfig.CurrentContext 70 | } 71 | log.Println("Running the command against context:", context) 72 | } 73 | 74 | // Create the clientset 75 | clientset, err := kubernetes.NewForConfig(config) 76 | if err != nil { 77 | return nil, err 78 | } 79 | 80 | return &KubernetesClient{ 81 | clientset: *clientset, 82 | }, nil 83 | } 84 | 85 | // GetAllPods returns all Pods in all namespaces in the cluster 86 | func (k *KubernetesClient) GetAllPods() ([]corev1.Pod, error) { 87 | pods, err := k.clientset.CoreV1().Pods("").List(context.TODO(), metav1.ListOptions{}) 88 | if err != nil { 89 | return nil, err 90 | } 91 | return pods.Items, nil 92 | } 93 | 94 | // GetAllImages returns all unique images used by all current running Pods in the cluster 95 | // TODO: Get images from Deployments, CronJobs, etc which may not be running. 96 | func (k *KubernetesClient) GetAllImages() (map[string][]string, error) { 97 | pods, err := k.GetAllPods() 98 | if err != nil { 99 | return nil, err 100 | } 101 | 102 | imageMap := make(map[string][]string) 103 | for _, pod := range pods { 104 | for _, container := range pod.Spec.InitContainers { 105 | imageMap[container.Image] = append(imageMap[container.Image], pod.Name) 106 | } 107 | for _, container := range pod.Spec.Containers { 108 | imageMap[container.Image] = append(imageMap[container.Image], pod.Name) 109 | } 110 | } 111 | 112 | return imageMap, nil 113 | } 114 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 Arm Limited 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import "github.com/ArmDeveloperEcosystem/kubearchinspect/cmd" 20 | 21 | func main() { 22 | cmd.Execute() 23 | } 24 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [ProjectConfig] 2 | MASTER_BRANCH = "main" 3 | PROJECT_NAME = "kubearchinspect" 4 | PROJECT_ROOT = "." 5 | PROJECT_UUID = "576e054b-f0a7-4ae8-be5c-090de20ed0ca" 6 | NEWS_DIR = "changes/" 7 | RELEASE_BRANCH_PATTERN = "*" 8 | VERSION_FILE_PATH = "changes/version.properties" 9 | CHANGELOG_FILE_PATH = "CHANGELOG.md" 10 | PROGRAMMING_LANGUAGE = "go" 11 | 12 | AWS_BUCKET="" 13 | SOURCE_DIR = "" 14 | MODULE_TO_DOCUMENT = "" 15 | DOCUMENTATION_DEFAULT_OUTPUT_PATH = "./does-not-exist" 16 | DOCUMENTATION_PRODUCTION_OUTPUT_PATH = "./does-not-exist" 17 | 18 | [tool.towncrier] 19 | directory = "changes" 20 | filename = "CHANGELOG.md" 21 | title_format = false 22 | ignore = [ "version.properties" ] 23 | 24 | [[tool.towncrier.type]] 25 | directory = "major" 26 | name = "Major changes" 27 | showcontent = true 28 | 29 | [[tool.towncrier.type]] 30 | directory = "feature" 31 | name = "Features" 32 | showcontent = true 33 | 34 | [[tool.towncrier.type]] 35 | directory = "bugfix" 36 | name = "Bugfixes" 37 | showcontent = true 38 | 39 | [[tool.towncrier.type]] 40 | directory = "doc" 41 | name = "Improved Documentation" 42 | showcontent = true 43 | 44 | [[tool.towncrier.type]] 45 | directory = "removal" 46 | name = "Deprecations and Removals" 47 | showcontent = true 48 | 49 | [[tool.towncrier.type]] 50 | directory = "misc" 51 | name = "Misc" 52 | showcontent = false 53 | 54 | [AutoVersionConfig] 55 | CONFIG_NAME = "DEFAULT" 56 | PRERELEASE_TOKEN = "beta" 57 | BUILD_TOKEN = "dev" 58 | TAG_TEMPLATE = "v{version}" 59 | targets = [ "changes/version.properties",] 60 | 61 | [AutoVersionConfig.key_aliases] 62 | VERSION = "VERSION_KEY" 63 | MAJOR = "major" 64 | MINOR = "minor" 65 | PATCH = "patch" 66 | COMMIT = "COMMIT" 67 | 68 | [AutoVersionConfig.trigger_patterns] 69 | major = "changes/*.major" 70 | minor = "changes/*.feature" 71 | patch = "changes/*.bugfix" 72 | --------------------------------------------------------------------------------