diff --git a/hips/hip-9999.md b/hips/hip-9999.md new file mode 100644 index 00000000..2a35f650 --- /dev/null +++ b/hips/hip-9999.md @@ -0,0 +1,610 @@ +--- +hip: 9999 +title: "H4HIP: Chart-defined plugins" +authors: + ["Scott Rigby ", "George Jenkins "] +created: "2025-04-11" +type: "feature" +status: "draft" +helm-version: "4" +--- + +## Abstract + +This HIP builds upon [H4HIP: Wasm plugin system](./hip-0026.md) to define how charts can specify and use plugins in Helm 4. It enables chart authors to define plugins that are required for their charts to function, such as alternative render engines or download protocols for dependencies. + +## Motivation + +While the main plugin system HIP enables users to extend Helm's functionality, chart authors ([Application Distributors](https://github.com/helm/community/blob/main/user-profiles.md#2-application-distributor)) need a way to specify which plugins their charts require. This allows charts to use alternative render engines, download protocols, and other plugin-based functionality while ensuring users have the necessary plugins installed. + +## Specification + +Support for Chart-defined plugins will be added starting in Chart API v3. `Chart.yaml` will define a top-level `plugins` key, and `Chart.lock` will capture specific plugin versions and checksums. + +### Chart-defined Plugin Types + +For the initial release of the new plugin system, chart authors will be able to define custom plugins for the following categories: + +- **`getter/v1`** - Download protocols for subcharts beyond HTTP/S and OCI (e.g., S3, Git) +- **`render/v1`** - Manifest rendering using alternative engines beyond gotemplate (e.g., YamlScript, Cue, Kustomize) + +After the initial plugin system release, the intention is to make it easy to continue adding new chart-defined plugin types to extend additional categories of non-default chart behavior as this becomes desirable. Some examples may be: + +- **Values schema validation** (for validating the chart's `values.yaml` file using something other than JSON Schema) +- **Dependency resolution** (for using a different subchart dependency resolver than the one currently used by Helm) + +To plan for forward compatibility, a [`minimumHelmVersion` field](https://github.com/helm/community/pull/370) may be added to allow charts to specify the minimum version of Helm required. However, for plugin types specifically, Helm can auto-detect compatibility by validating plugin types at chart load time (see [Backwards compatibility](#backwards-compatibility)). + +### Chart.yaml Plugin Syntax + +The `plugins` key is defined as a **list** (not a map). This is critical for `render/v1` plugins because: + +- Go does not guarantee YAML map key ordering +- Sequential execution allows earlier plugins to modify a shared `SourceFiles` object in-memory +- Later plugins can then target files created or modified by earlier plugins +- This enables plugin composition where one plugin creates files and another processes them + +Example `Chart.yaml` for Charts v3: + +```yaml +apiVersion: v3 +name: my-chart +version: 1.0.0 + +# Chart-defined plugins (sequential list order matters for render plugins) +plugins: + - name: yamlscript + type: render/v1 + repository: oci://ghcr.io/yamlscript/helm-yamlscript + version: 0.1.0 + - name: s3 + type: getter/v1 + repository: oci://ghcr.io/hypnoglow/helm-s3 + version: 0.16.3 + +# Renamed from "dependencies" in v2 +subcharts: + - name: postgresql + version: 12.x.x + repository: https://charts.bitnami.com/bitnami +``` + +### Render/v1 Plugin Specification + +The `render/v1` plugin type enables chart authors to use alternative rendering engines beyond gotemplate. + +> **Terminology note**: The plugin type is named `render/v1` (not `template/v1`) because not all rendering engines use templating. For example, Cue-lang uses code evaluation rather than template substitution. + +#### Multiple Render Plugins per Chart + +A chart can specify multiple render plugins simultaneously. This enables: + +- Progressive migration from gotemplate to alternative renderers +- Using gotemplate for some templates while other plugins handle specialized files +- Plugin composition where one plugin generates files and another processes them + +#### File Targeting Strategy + +Each `render/v1` plugin declares which files it manages via **glob patterns** in its `plugin.yaml` configuration. At chart load time, Helm matches files to plugins using a "most specific pattern wins" approach: + +```yaml +# Example plugin.yaml config for render/v1 plugins +config: + patterns: + - "/templates/*.yaml" + - "/templates/*.tpl" + - "/templates/NOTES.txt" +``` + +**Example file targeting scenarios:** + +- Gotemplate plugin: `["/templates/*.yaml", "/templates/*.tpl", "/templates/NOTES.txt", "/tests/*.yaml"]` +- Pkl plugin: `["/templates/*.pkl", "*.pkl.yaml"]` +- YamlScript plugin: `["/templates/*.ys", "*.ys.yaml"]` +- Kustomize plugin: `["kustomization.yaml", "overlays/*.yaml"]` +- Cue plugin: `[".cue", "*.cue.json", "*.cue.yaml"]` + +This allows plugins to manage complete file dependency sets (e.g., gotemplate managing both `.tpl` partials and `.yaml` templates). + +#### Plugin Invocation + +All `render/v1` plugins receive the same Helm built-in objects via JSON serialization through Extism: + +- `Release` - Release-specific information (name, namespace, etc.) +- `Values` - Merged values from values.yaml and --set flags +- `Chart` - Chart metadata +- `Subcharts` - Metadata about subchart dependencies +- `Files` - Non-template files accessible to the chart +- `Capabilities` - Information about the Kubernetes cluster +- `SourceFiles` - All source files in the chart (plugins can add, modify, or remove) +- `Template` - Template-specific information (name, base path) - see [Open Issue #5](#5-template-built-in-object) + +Plugins return rendered Kubernetes manifests as a map of `filename -> content`. + +#### Sequential Execution + +When multiple `render/v1` plugins are defined, they execute sequentially in list order: + +1. All chart files are loaded into a shared `SourceFiles` object +2. Each plugin receives the current `SourceFiles` state +3. Plugin can add, modify, or remove files +4. Modified `SourceFiles` passed to next plugin +5. Final output merged and returned to Helm + +This enables powerful composition patterns where earlier plugins prepare files for later plugins to process. + +### Charts v3 Dependency Model + +In Chart API v3, both subcharts and plugins are treated as dependencies: + +- The `dependencies` key is renamed to `subcharts` (no functional changes) +- Both `plugins` and `subcharts` lists are processed by `helm dependency build/update` +- `Chart.lock` captures versions, checksums, and digests for both types +- **Subcharts** are downloaded to the local `charts/` directory +- **Plugins** are cached and extracted to a global versioned plugin cache + +This unified model ensures reproducible builds while supporting version-specific plugin storage across charts. + +### Helm dependency commands + +The existing `helm dependency` commands are extended to handle chart-defined plugins: + +- `helm dependency update` - Resolves and downloads both subcharts and plugins, updates `Chart.lock` +- `helm dependency build` - Downloads locked versions of subcharts and plugins from `Chart.lock` +- `helm dependency list` - Shows status of both subcharts and plugins + +**Workflow for chart consumers:** + +1. Chart author defines plugins in `Chart.yaml` +2. Run `helm dependency update` → downloads plugins to global cache, updates `Chart.lock` +3. `Chart.lock` committed to version control ensures reproducible builds +4. Other users run `helm dependency build` → installs exact locked versions +5. `helm template/install/upgrade` uses plugins from cache automatically + +### Distribution + +Chart-defined plugins **must be**: + +1. Implemented using the **Wasm runtime** (via Extism) +2. Distributed as **OCI artifacts** + +Plugins are referenced by OCI URL in `Chart.yaml` (not packaged within charts). This keeps chart sizes small while ensuring plugins are: + +- Versioned and locked via `Chart.lock` (includes SHA256 digest) +- Cached as tarballs in content-addressable storage at `$HELM_CACHE_HOME/content/` +- Loaded directly from tarballs at runtime (no persistent extraction) +- Shared across multiple charts using the same plugin version +- Downloadable ahead of time for airgap scenarios via `helm dependency build` + +**Plugin caching:** Plugin tarballs are stored in Helm's content-addressable cache (`$HELM_CACHE_HOME/content/`) keyed by SHA256 digest, matching how charts are cached. At runtime, plugins are loaded directly from the cached tarball - the `plugin.yaml` and `.wasm` files are read into memory without extracting to disk. + +**Plugin versioning:** The content cache supports multiple versions of the same plugin, allowing different charts to depend on different plugin versions without conflicts. + +### Plugin Storage: Installed vs Cached + +Plugins exist in two distinct storage models: + +| Storage | Description | +| ------------- | --------------------------------------------------------------------------------------------- | +| **Installed** | Globally installed via `helm plugin install`, available for all Helm commands | +| **Cached** | Transient cache for chart-defined plugins, exists only for performance (avoid re-downloading) | + +**Storage locations:** + +| Type | Path | Purpose | +| -------------------------- | ------------------------------------------ | ------------------------------------- | +| Global install destination | `$PLUGINS_DIR//` | Final location for installed plugins | +| Chart-defined cache | `$HELM_CACHE_HOME/content/{digest}.plugin` | Content-addressable cache (transient) | + +**Important distinction:** Chart-defined plugins are **cached**, not **managed**. The content cache is transient storage that can be cleared at any time (`rm -rf $HELM_CACHE_HOME/content/`) without breaking workflows - plugins will simply be re-fetched on next use. This is analogous to chart caching: users don't "manage" cached charts, they manage chart dependencies via `Chart.yaml` and `Chart.lock`. + +**Content-addressable caching:** Plugin tarballs are stored using their SHA256 digest, enabling: + +- Deduplication: Same plugin version used by multiple charts is stored once +- Verification: Digest from `Chart.lock` validates cached content +- Consistency: Same loading pattern as charts (tarball → in-memory) +- Transience: Cache can be cleared without breaking chart workflows + +**Key distinctions:** + +- **Installed** plugins appear in `helm plugin list` and are available for any Helm operation +- **Cached** plugins are loaded on-demand when a chart specifies them in `Chart.yaml` +- `helm plugin list` shows only installed plugins (cached plugins are not listed) +- Installed plugins and chart-defined plugins are separate systems (no fallback between them) + +**Plugin identity:** + +Chart-defined plugins are identified by their **content hash** (SHA256 digest), not by name/version. This ensures deterministic builds: + +- `Chart.yaml` specifies name/version for human convenience +- `helm dependency update` resolves to OCI digest, computes content hash, stores in `Chart.lock` +- At runtime, Helm loads the plugin by content hash from `Chart.lock` +- If the hash is not in the cache, the plugin is downloaded + +### Airgap Support + +For airgap deployments, users need a way to access chart-defined plugins without direct internet access. + +**Recommended approach: Registry mirroring via registries.conf** + +The [registries.conf HIP](https://github.com/helm/community/pull/391) proposes registry configuration that would allow: + +```yaml +# ~/.config/helm/registries.conf +[[registry]] +prefix = "ghcr.io" +location = "internal-registry.corp.com/mirror" +``` + +This redirects plugin downloads to an internal mirror, following the same pattern used for container images and OCI artifacts. This is the preferred solution because: + +- Reuses established OCI registry mirroring patterns +- No Helm-specific tooling required - standard registry mirroring works +- Charts and plugins use the same airgap solution +- Organizations already have registry mirroring infrastructure + +**Note:** Prioritize registries.conf implementation before moving chart-defined plugins out of experimental. A dedicated `helm plugin download` command is not planned (see Rejected Ideas). + +### SDK API + +The Helm SDK is used by various tools and platforms beyond the CLI, including Kubernetes controllers (e.g., Flux helm-controller), CI/CD pipelines, custom automation tools, and Platform-as-a-Service offerings. These SDK users have unique constraints that the plugin system addresses. + +#### SDK Configuration Options + +To support diverse deployment environments, the SDK provides the `PluginRenderer` with configurable options: + +```go +type PluginRenderer struct { + // ContentCachePath is the path to the content cache directory. + // Plugins are loaded from cached archives using their digest from Chart.lock. + // Set to "" to disable disk-based loading (use with PreloadedPlugins). + ContentCachePath string + + // CompilationCache allows custom Wasm compilation cache. + // Default: disk-based at $HELM_CACHE_HOME/wazero-build/ + // For non-writable filesystems, use wazero.NewCompilationCache() for in-memory. + CompilationCache wazero.CompilationCache + + // PreloadedPlugins allows passing pre-loaded plugin archives as raw bytes. + // Map keys are the plugin digest (matching Chart.lock). + // Useful for non-writable filesystems where plugins are embedded at build time. + PreloadedPlugins map[string][]byte +} +``` + +#### Long-Running Processes + +Controllers and servers keep the Helm SDK loaded in memory continuously. Considerations: + +- **Memory management**: Compiled Wasm modules consume memory; lifecycle hooks available to release +- **Cache eviction**: LRU or time-based eviction for compilation cache +- **Plugin instance reuse**: Share compiled modules across multiple Helm operations + +#### Memory-Constrained Environments + +Some deployments have strict memory limits. The SDK supports: + +- **Bounded compilation cache**: Configurable maximum size +- **Lazy loading**: Only load plugins when needed +- **Cleanup callbacks**: Explicit memory release after operations + +#### Non-Writable Filesystems + +Some environments run with read-only filesystems. SDK users must: + +1. Set `ContentCachePath` to `""` (empty string) to disable disk access +2. Provide `PreloadedPlugins` with embedded plugin archives keyed by digest + +#### Native Go Plugin Runtime (SDK Only) + +For SDK users who want to bypass Wasm entirely, a separate HIP proposes a `go/v1` runtime that allows registering native Go implementations for plugin types. This is SDK-only (CLI always uses Wasm for sandboxing) and covered in a dedicated HIP. + +## Backwards compatibility + +Requirements for chart-defined plugins: + +- Chart-defined plugins, which are required to use the chart, MUST be made easily available to the end user. +- Any plugin functionality that affects Chart apiVersion 3 after its inclusion in a full release of Helm 4 MUST follow the standard backwards compatibility contract within the same MAJOR version (i.e., charts made prior to new plugins should "just work"). New charts using initial or future plugin types may require a newer Helm version for forward compatibility. + +### Plugin Type Validation + +When Helm loads a chart, it validates that all plugin types declared in `Chart.yaml` are supported by the current Helm version. If a chart uses an unknown plugin type, Helm fails with a clear error message: + +``` +Error: chart "my-chart" requires plugin type "values/v1" which is not supported by this version of Helm (4.0.0). + +Supported plugin types: render/v1, getter/v1 + +For information about plugin types and which Helm versions support them, +see: https://helm.sh/docs/plugins/types +``` + +This approach: + +1. **Fails fast**: Users immediately know if their Helm version is incompatible +2. **Provides actionable information**: Lists supported types and links to documentation +3. **Requires no action from chart authors**: Helm auto-detects incompatibility based on plugin types + +**Precedent in Helm:** + +- `kubeVersion` validation: Charts can require specific Kubernetes versions, and Helm produces clear errors when incompatible +- API version validation: `helm create --api-version v1` fails with "unsupported chart API version: v1 (supported: v2, v3)" +- Getter scheme validation: Unknown URL schemes fail with "scheme X not supported" + +**Documentation requirement:** Before releasing chart-defined plugin support, Helm documentation must include a [Plugin Types](https://helm.sh/docs/plugins/types) page listing all plugin types, their purposes, and the Helm version that introduced each type. This URL is included in error messages to help users self-service. + +## Security implications + +In Helm 4, users may still manually install plugins, but chart-defined plugins can also be downloaded automatically if not already cached. This could surprise a user if they are not made aware of this. + +Helm 4 will address this in the following ways: + +- Notify the user: + + To ensure Helm does not run third-party code without a user's knowledge, any chart-defined plugins not loaded as part of Helm's default distribution will notify the user when commands are run that would make use of those plugins. + +- Opt-in flags: + + The user will need to pass flags to explicitly acknowledge and opt-in to downloading (if not present) and running these third-party chart plugins. They will also need to pass a flag to opt-in when installing an unsigned plugin (see below). + +## Implementation Plan + +This work is dependent on, and will be in conjunction with, [H4HIP: Charts v3 Enablement](https://github.com/helm/community/blob/main/hips/hip-0020.md): + +> **Note:** Items below have been implemented in the [reference implementation](#reference-implementation) to validate the design. Upstream integration into Helm core is pending HIP approval. + +### Core Plugin Support + +- Add Chart-defined `plugins` list to Charts v2/v3 Metadata struct +- Add `render/v1` plugin type to plugin system + - Define `InputMessageRenderV1`, `OutputMessageRenderV1`, `ConfigRenderV1` schemas + - Implement file targeting logic (glob matching) + - Create render plugin invoker (JSON serialization of built-in objects) +- Implement content-addressable plugin cache (`$HELM_CACHE_HOME/content/{digest}.plugin`) +- Extend `helm dependency build/update` to process `plugins` list +- Update `Chart.lock` to include plugin versions +- Wire render plugins into template rendering pipeline + +### Getter Plugin Support + +- Add `getter/v1` as chart-defined plugin type (extends existing getter plugins) +- Update dependency downloader to use chart-defined getter plugins + +### Security & CLI + +- Add flags to `helm template/install/upgrade` for chart-defined plugin opt-in +- Implement user notification for chart-defined plugin usage +- Automatic plugin signature verification (with bypass flags) +- Plugin provenance support (reuse chart provenance mechanisms) + +### Documentation + +- Document plugin development workflow + +### Reference Implementation + +A reference implementation has been developed to validate this design: + +- **Helm core changes**: [scottrigby/helm@chart-defined-plugins](https://github.com/scottrigby/helm/tree/chart-defined-plugins) - Adds render/v1 schema, plugin metadata fields, render plugin invoker, versioned storage, and dependency command updates +- **Reference plugins**: [scottrigby/ref-hip-chart-defined-plugins](https://github.com/scottrigby/ref-hip-chart-defined-plugins) - Wasm render/v1 plugins using Extism Go PDK +- **Example charts**: [scottrigby/ref-hip-chart-defined-plugins/charts](https://github.com/scottrigby/ref-hip-chart-defined-plugins/tree/main/charts) - Demonstrates Chart.yaml with plugins list + +## Reference Links + +- [Helm Built-in Objects](https://helm.sh/docs/chart_template_guide/builtin_objects/) +- [YamlScript Helm Discussion](https://github.com/yaml/yamlscript/discussions/243) + +## How to teach this + +- Create examples of Chart-defined plugins for the new plugin system that contributors can use as a model for their own plugins + - Chart-defined plugin example. The Gotemplate `render` plugin will have already created +- Write concise and easy to follow documentation for chart-defined plugins +- Write a blog post outlining how chart authors will benefit from chart-defined plugins, which can link to the documentation and these examples +- Create a presentation to propose for conference talks as another communition channel to make the community aware of chart-defined plugins + +## Open issues + +_Points still being decided/discussed._ + +### 1. Gotemplate as Plugin for Charts v3 + +Should gotemplate rendering be provided via a Helm-maintained plugin for Chart API v3 (rather than built-in)? + +**Pros:** + +- Cleaner architecture aligning with plugin-based design +- Enables organic deprecation: as chart authors adopt alternative renderers, gotemplate phases out naturally +- Separate deprecation cycle from Helm/Charts API major versions +- Plugin could be separate Helm subproject with independent release cycle + +**Cons:** + +- Users must download plugin for functionality assumed built-in for Charts v2 +- Could surprise users expecting gotemplate to "just work" + +**Mitigation:** + +- Users already assume subchart dependencies must be downloaded +- Plugins cached by version globally and shared across charts +- Can be downloaded ahead of time for airgap scenarios +- Small trade-off for much more flexible chart-defined plugin functionality + +**Decision needed:** Should this be part of initial Charts v3 release or introduced later? + +### 2. ArtifactHub Integration + +How should chart-defined plugins be discovered and listed on ArtifactHub? + +**Considerations:** + +- Plugin subtypes (render, getter, etc.) as entry properties +- Unified catalog format across artifact kinds +- Search/filter by plugin type +- Automated public key discovery for plugin provenance verification (see below) + +**Decision needed:** ArtifactHub schema for chart-defined plugins? + +### 3. Trust Workflow Improvements + +Users must approve chart-defined plugins before use (provenance verification). To reduce this burden, several improvements are planned: + +**Potential enhancements:** + +- **ArtifactHub integration**: Automatic public key fetching for plugins listed on ArtifactHub +- **Trusted publishers config**: Store approved publisher keys so users approve once per publisher, not once per plugin +- **Simple approval workflow**: Yes/no prompt with optional `--trust-publisher` flag to remember the decision +- **Organization-wide trust**: Config file for pre-approved publishers in enterprise environments + +These improvements would make the approval process seamless while maintaining security, eliminating the need to expose cache internals for "what have I already approved" visibility. + +**Decision needed:** Priority and implementation approach for trust workflow? + +### 4. Template Built-in Object + +The current `Template` built-in object (providing template name and base path) may need to be: + +1. **Renamed** to something more generic (e.g., `Source` or `File`) since `render/v1` plugins handle non-template files +2. **Removed** entirely since the `SourceFiles` object now provides file information to plugins + +**Current `Template` provides:** + +- `Name` - Current template filename +- `BasePath` - Base path for template lookups + +**Question:** With `SourceFiles` available to `render/v1` plugins containing all source file metadata, is `Template` still needed? Or is it only relevant for gotemplate's `include`/`tpl` functions? + +**Potential resolution:** If gotemplate becomes a render/v1 plugin for Charts v3 (see Open Issue #1), it could retrieve and handle the current file properly from the `SourceFiles` object and assign that to a `Template` object internally to maintain backwards compatibility with existing gotemplate functionality. This would make `Template` an implementation detail of the gotemplate plugin rather than a Helm built-in. + +**Decision needed:** Keep, rename, or deprecate `Template` built-in for render plugins? + +### 5. Plugin Grouping in Chart.yaml + +Should plugins be grouped by type in `Chart.yaml`? + +**Current syntax (flat list):** + +```yaml +plugins: + - name: yamlscript + type: render/v1 + repository: oci://... + - name: s3 + type: getter/v1 + repository: oci://... +``` + +**Alternative (grouped by type):** + +```yaml +plugins: + render: + - name: yamlscript + repository: oci://... + getter: + - name: s3 + repository: oci://... +``` + +**Considerations:** + +- Flat list preserves explicit ordering across all plugin types +- Grouped syntax may be clearer when many plugins are defined +- Grouped syntax requires defining execution order rules per group + +**Decision needed:** Flat list vs grouped syntax for Chart.yaml plugins? + +## Rejected ideas + +_Why certain ideas that were brought while discussing this HIP were not ultimately pursued._ + +1. **Source code distribution** was considered but rejected. + + The idea was to distribute Go source code (instead of compiled Wasm binaries) in OCI artifacts, with Helm compiling the source to Wasm on-demand using the system's Go toolchain. + + **Arguments for:** + - Smaller artifact size (~10KB source vs ~5MB Wasm) + - Users can inspect and trust source code + - Compiled binary matches inspectable source (supply chain transparency) + + **Arguments against:** + - Requires Go toolchain on user's system + - Compilation time on first use (~1-5 seconds) + - Build reproducibility concerns (different compiler versions) + - Complexity: Helm becomes a build system + + **Decision:** Distribute pre-compiled Wasm binaries. The Wasm runtime (Wazero) handles compilation to native machine code at load time (~500ms cold, ~75ms warm with disk cache). Disk caching is enabled by default at `$HELM_CACHE_HOME/wazero-build/`. + +2. Helm 4 will not support chart-defined required plugins for Chart API v2. + + While Helm 3 currently allows additional keys to be added to the Chart struct while retaining backwards-compatibility, any keys that add _required_ functionality for new charts to install would not be forwards compatible with older versions of Helm (such as renderer plugins). Therefore, for practical reasons, a top level `plugins` key to `Chart.yaml` will wait for Chart API v3. See [Specification](#Specification). + +3. Helm 4 will not continue to only support gotemplate for rendering manifests as Helm 3 did. + + By allowing alternative rendering engines, the Helm project accepts the additional complexity for users to troubleshoot or contribute to charts that may require learning new rendering engines other than gotemplate. This is a trade-off that Helm maintainers are willing to make in order to satisfy the many requests from the community for this feature. + + It also means the Helm project will not be able to write a comprehensive guide covering all the different template engines, since there will be many different rendering engines to choose from. + +4. **`helm plugin list --status` for chart-defined plugins** was considered but rejected. + + The idea was to extend `helm plugin list` with flags like `--status=downloaded` or `--status=all` to show cached chart-defined plugins alongside installed plugins. + + **Arguments against:** + - Chart-defined plugins are **cached**, not **managed** - they exist transiently for performance + - The content cache should be clearable without user concern (caches are transient by nature) + - Exposing cache contents as "downloads" conflates caching with installation + - `helm plugin install/uninstall` semantics don't apply to chart-defined plugins + - Chart-defined plugins are managed via `Chart.yaml` and `Chart.lock`, not plugin commands + + **Decision:** `helm plugin list` shows only globally installed plugins. Chart-defined plugin versions are managed through chart dependency workflows (`helm dependency list` shows plugin status within a chart context). + +5. **`helm plugin download` command** was considered but rejected. + + The idea was to provide a dedicated command to pre-download plugins for airgap scenarios: + + ```bash + helm plugin download oci://ghcr.io/helm-plugins/yamlscript-render:0.1.0 + ``` + + **Arguments against:** + - Encourages treating the cache as managed storage (it's transient) + - Registry mirroring via `registries.conf` is the proper airgap solution + - Duplicates functionality already available via `helm dependency build` + - Adds complexity for a use case better solved at the infrastructure level + + **Decision:** Use `registries.conf` for airgap scenarios. Charts can pre-fetch plugins via `helm dependency build`, which populates the cache as a side effect. + +6. **Fallback to globally installed plugins** was considered but rejected. + + The idea was that if a chart-defined plugin wasn't in the cache, Helm could fall back to a globally installed plugin with the same name and version. + + **Arguments against:** + - Breaks determinism: `Chart.lock` contains the plugin's content hash (digest) + - An installed plugin with the same name/version may have different content + - No way to verify installed plugin matches the locked digest + - Undermines the reproducible builds guarantee that `Chart.lock` provides + + **Decision:** Chart-defined plugins are identified by content hash, not name/version. No fallback to installed plugins. If the hash from `Chart.lock` isn't in the cache, the plugin must be downloaded. + +7. **Pre-packaging plugins within charts** was considered but rejected. + + The idea was to allow chart authors to bundle plugin tarballs directly within the chart archive. + + **Arguments against:** + - Inflates chart size significantly (Wasm binaries are ~5MB each) + - Duplicates plugin content across every chart using the same plugin + - Defeats the purpose of the content-addressable cache + - OCI distribution with caching provides the same offline capability + + **Decision:** Plugins are always referenced by OCI URL and cached externally. For airgap scenarios, use registry mirroring via `registries.conf`. + +8. **Requiring chart authors to set `minimumHelmVersion` for plugin types** was considered but rejected. + + The idea was that chart authors would need to manually specify which Helm version introduced each plugin type they use, to ensure forward compatibility. + + **Arguments against:** + - Adds manual burden to chart authors who must research Helm version history + - Error-prone: authors may specify incorrect versions + - Redundant: Helm already knows which plugin types it supports + - Helm can auto-detect unknown plugin types at chart load time and fail with a helpful error + + **Decision:** Helm validates plugin types at chart load time and fails with a clear error listing supported types and a documentation URL. Chart authors don't need to track which Helm version introduced which plugin type. The [`minimumHelmVersion` field](https://github.com/helm/community/pull/370) remains available for other compatibility requirements beyond plugin types.