FairwindsOps/pluto: finding deprecated Kubernetes apiVersions before an upgrade breaks you
A cli tool to help discover deprecated apiVersions in Kubernetes
At a glance
- What is it?
- Pluto scans manifests, Helm charts and live Helm releases for apiVersions that Kubernetes has deprecated or removed. It is a focused CLI with a narrow job, and the narrowness is the point.
- Who is it for?
- Adopt pluto if you run Kubernetes upgrades on a schedule and need a pre-upgrade inventory of deprecated apiVersions across IaC repos and live Helm releases; the detect-files and detect-helm commands plus the GitHub Action cover that ground without a cluster-side agent. Do not adopt it if you need continuous policy enforcement or a record of findings over time, since the README points to Fairwinds Insights for multi-cluster tracking and Slack, Datadog and Jira integration.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 9 days ago.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 24, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The api-server will not tell you what you actually deployed
The problem pluto addresses is not that Kubernetes deprecates apiVersions. That is documented and scheduled. The problem is finding every place you used one. The README makes the trap explicit: if you ask the api-server for deployments.v1.apps and the workload was originally deployed as deployments.v1beta1.extensions, the api-server converts the version and hands back a manifest with apps/v1. The response looks clean. Your repository and your stored Helm release do not.
That gap matters at upgrade time. Kubernetes deprecation policy separates deprecation from removal, and pluto reflects that split by reporting a resource as DEPRECATED or REMOVED. A DEPRECATED apiVersion still serves traffic; a REMOVED one does not. If your only visibility comes from querying a live cluster, you learn about the removal when the manifest fails to apply, which is usually during the upgrade window.
Pluto is aimed at platform engineers and release owners who own that upgrade. It reads the places where the original apiVersion is still written down: Infrastructure-as-Code repositories holding static manifests and Helm charts, and live Helm 2 and Helm 3 releases in a cluster. It is a pre-flight inventory tool, not a controller.
How pluto decides what is deprecated
Pluto is a Go binary with a small dependency surface for what it does. The go.mod shows cobra for the command structure, viper for configuration, helm.sh/helm/v3 for release handling, and client-go plus apimachinery for cluster access. The version data itself is not fetched at runtime from the Kubernetes API. The repository carries a versions.yaml file at the top level, and embed.go sits alongside it, which indicates the deprecation table is compiled into the binary.
That design has a direct consequence. The binary knows the deprecation timeline as of the release you installed, and it does not need network access to make a judgement. It also means the table ages with the binary. New deprecations land in new pluto releases, and the release history shows a steady cadence rather than a single long-lived artifact. If you pin an old pluto binary in CI and forget it, your scanner will be quieter than reality.
The scanning itself works on the apiVersion field in the resources it finds, comparing each one against the embedded table and classifying the result as DEPRECATED or REMOVED. For files it walks a directory tree; for Helm it resolves the release contents. The README does not document how the Helm path handles releases whose stored manifest is already unreadable, so treat that as unverified.
Installing pluto and running a first detection
The README points to the documentation at pluto.docs.fairwinds.com and to the GitHub releases page for distribution, so the download path is the release artifacts rather than a package manager command. The repository does include a Makefile with a build target if you prefer to compile from source, and a Dockerfile that produces an image running as the nobody user with the binary at the filesystem root.
The container registry changed in v5.24.0. Images moved to us-docker.pkg.dev/fairwinds-ops/oss/pluto, and the README marks quay.io/fairwinds/pluto as deprecated. The README's required action is a one-line substitution:
- quay.io/fairwinds/pluto:<tag>
+ us-docker.pkg.dev/fairwinds-ops/oss/pluto:<tag>Once you are on the new registry, the README recommends full version tags or a digest pin:
us-docker.pkg.dev/fairwinds-ops/oss/pluto:v<major>.<minor>.<patch>us-docker.pkg.dev/fairwinds-ops/oss/pluto@sha256:<digest>The README's own example of the file-scanning command uses a test data directory, which is a useful reminder that -d takes a path you choose:
pluto detect-files -d pkg/finder/testdataFor CI, the project ships a GitHub Action. The README gives this workflow shape, which downloads the binary and then invokes it:
- name: Download Pluto
uses: FairwindsOps/pluto/github-action@master
- name: Use pluto
run: |
pluto detect-files -d pkg/finder/testdataNote the two separate steps: the action installs pluto, and the run step calls the pluto binary. If you skip the download step, the run step fails with a command-not-found.
Registry migration, immutable tags and what breaks on upgrade
The v5.23.6 to v5.24.0 transition is the sharpest operational edge in this project, and it is worth reading before you touch anything. Three changes land together. Images moved to the Google Artifact Registry path. Images are now signed. Tags are immutable, and the floating tags v5, v5.23 and latest no longer exist.
If your CI or Helm values reference quay.io/fairwinds/pluto:latest, that reference is now doubly broken: wrong registry, and a tag that is gone. The README's required action is the one-line substitution shown above, and it recommends full version tags of the form v<major>.<minor>.<patch> or a digest pin of the form sha256:<digest>.
This is a deliberate trade-off. Immutable, signed tags mean a given tag always resolves to the same bytes, which is what you want for a supply-chain-sensitive scanner running in CI. The cost is that you must now own version bumps explicitly. Nothing floats you forward. For teams that relied on latest to pick up new deprecation data automatically, the migration removes that convenience and replaces it with a maintenance task. Given that the deprecation table is embedded in the binary, that task is not optional if you want current results.
Where pluto is the wrong tool
Pluto answers one question: does this manifest, chart or release contain an apiVersion that is deprecated or removed? It does not enforce anything. There is no admission controller, no cluster-side agent, and no continuous reconciliation loop described in the README. If you need a policy that blocks a deprecated apiVersion from being applied in the first place, pluto is the wrong layer; it is a scanner you run, not a gate that runs itself.
The second limitation is history. Pluto reports on the state of the files and releases you point it at, at the moment you run it. The README is explicit that running pluto in multiple clusters, tracking results over time, and integrating with Slack, Datadog and Jira is the territory of Fairwinds Insights, the commercial platform. If your requirement is a dashboard showing which clusters drifted and when, pluto alone will not produce it, and the README does not claim otherwise.
Third, the embedded version table means the tool's accuracy is bounded by its release date. A pluto binary from months ago will not know about deprecations announced since. The repository layout also shows a versions.yaml at the top level, which suggests the table is maintainable, but the README does not document a supported workflow for supplying your own version data, so do not assume you can patch around a stale binary.
Pluto against Polaris, from the same maintainer
The most relevant comparison is not a third-party tool but Polaris, which Fairwinds lists among its other projects. The README describes Polaris as auditing, enforcing and building policies for Kubernetes resources, with over 20 built-in checks for best practices. Polaris runs as a workload in the cluster and can enforce. Pluto runs as a CLI over files and Helm releases and reports.
That difference in approach determines which one you reach for. If your question is whether a workload in the live cluster violates a best practice right now, Polaris is built for that. If your question is whether your repository and your stored Helm releases contain an apiVersion that will stop being served after the next Kubernetes upgrade, pluto is built for that, and it can answer it without cluster access at all when scanning files.
They are complementary rather than competing. A reasonable split is Polaris for in-cluster posture and pluto for the pre-upgrade inventory, with the caveat that neither gives you the multi-cluster history the README assigns to Fairwinds Insights.
Licence, maintenance and the cost of staying current
Pluto is Apache-2.0, and the Dockerfile labels the image with the same identifier. For most internal use this is a permissive licence with the usual obligations around notices and attribution; the repository carries a LICENSE file and a .licenserc.yaml, which suggests automated licence header checks run in CI. Nothing here is legal advice, and if you redistribute the binary or embed it in a product, read the licence text rather than this summary.
The maintenance picture is straightforward. The repository is not archived, and the last push was on 2026-09-22. Recent releases include v5.24.4 on 2026-09-15, v5.24.3 on 2026-08-10 and v5.24.1 on 2026-07-10, which is a roughly monthly cadence over that window. The project is written in Go and the Makefile exposes the usual targets: build, test, lint, and cross-compilation for linux and windows.
The upgrade cost is the part teams underestimate. Because tags are immutable and floating tags were removed, every version bump is an explicit edit to a CI config, a Dockerfile or a Helm value. Because the deprecation table is embedded, skipping bumps means stale results. Budget for a scheduled bump of the pinned digest or full version tag, and treat the GitHub Action reference as something to pin rather than track at master.
Editorial conclusion
Adopt pluto if you run Kubernetes upgrades on a schedule and need a pre-upgrade inventory of deprecated apiVersions across IaC repos and live Helm releases; the detect-files and detect-helm commands plus the GitHub Action cover that ground without a cluster-side agent. Do not adopt it if you need continuous policy enforcement or a record of findings over time, since the README points to Fairwinds Insights for multi-cluster tracking and Slack, Datadog and Jira integration. Before rollout, verify that your container references use the us-docker.pkg.dev/fairwinds-ops/oss/pluto registry rather than the deprecated quay.io path, and confirm your tooling can pin full version tags or digests, because v5.24.0 removed the floating v5, v5.23 and latest tags.
Frequently asked questions
What is FairwindsOps/pluto and what does it scan?
Pluto is a CLI utility that finds deprecated Kubernetes apiVersions. According to the README it can check Infrastructure-as-Code repositories, including static manifests and Helm charts, and live Helm 2 and Helm 3 releases running in a cluster.
How do I install pluto?
The README points to the documentation at pluto.docs.fairwinds.com and to the GitHub releases page for distribution. The repository also includes a Makefile build target and a Dockerfile, and starting with v5.24.0 the container image lives at us-docker.pkg.dev/fairwinds-ops/oss/pluto.
Why can't I just ask the Kubernetes api-server which apiVersions I used?
The README explains that if you request deployments.v1.apps and the workload was deployed as deployments.v1beta1.extensions, the api-server converts the version and returns a manifest with apps/v1. The original apiVersion is not visible from that response.
Does pluto tell me the difference between a deprecated and a removed apiVersion?
Yes. The README states that pluto differentiates between the two and reports whether a version is DEPRECATED or REMOVED, matching the Kubernetes deprecation policy where apiVersions are deprecated first and later removed entirely.
Can pluto track deprecated apiVersions across multiple clusters over time?
The README directs that use case to Fairwinds Insights, which it describes as a platform for auditing and enforcing policy in Kubernetes clusters, with tracking over time and Slack, Datadog and Jira integration. Pluto itself is a CLI you run against files or Helm releases.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/fairwindsops-pluto)