From cefe162646d766376d0270b5f90606c9e5e44396 Mon Sep 17 00:00:00 2001 From: Scott Rigby Date: Mon, 12 May 2025 16:35:01 -0400 Subject: [PATCH 01/10] Moved chart-defined plugins to this follow-up HIP from #388 Co-authored-by: George Jenkins Signed-off-by: Scott Rigby --- hips/hip-9999.md | 134 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 hips/hip-9999.md diff --git a/hips/hip-9999.md b/hips/hip-9999.md new file mode 100644 index 000000000..8aac106bd --- /dev/null +++ b/hips/hip-9999.md @@ -0,0 +1,134 @@ +--- +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: Improve and extend plugin system](./hip-9999.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` capturing specific plugin versions and checksums. + +For the initial release of the new plugin system, chart authors will be able to define custom plugins for the following categories: + +- **Download** (to allow chart authors to specify plugins for downloading subcharts with different protocols than the default) +- **Manifest render** (for rendering a chart's templates into a set of Kubernetes resources using some other engine than gotemplate) + +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 may be added to allow future plugins to specify the minimum version of Helm that must be used for the chart (or since this is the version of Helm that introduced the new plugin, perhaps this can be auto-detected). + +A first pass for Chart-defined plugin syntax in `Chart.yaml`: + +```yaml +# made up URLs—these are not actual Helm 4 plugins yet +plugins: + - name: pkl + type: render.plugins.helm.sh/v1 + url: https://github.com/pkl-community/helm-pkl + version: 0.1.0 + - name: helmys + type: render.plugins.helm.sh/v1 + url: https://github.com/kubeys/helmys + version: 0.1.4 + - name: s3 + type: download.plugins.helm.sh/v1 + url: https://github.com/hypnoglow/helm-s3 + version: 0.16.3 + - name: git + type: download.plugins.helm.sh/v1 + url: https://github.com/aslafy-z/helm-git + version: 1.3.0 +``` + +### Helm plugin commands + +Commands will be added to allow packaging Chart-defined plugins within the chart: + +- `helm chart plugin build` similar to `helm dependency build` but for plugins +- `helm chart plugin update` similar to `helm dependency update` but for plugins + +### Distribution + +To enable airgapped installations and other use cases where downloading Chart-defined plugins is not feasible, plugins may be packaged and distributed with the chart itself, similar to how Helm 3 allows this for a chart's subchart dependencies. A command will be added to enable this (see H4HIP 9999: Improve and extend plugin system [Helm plugin commands specification](./hip-9999.md#Helm-plugin-commands-specification)). + +## 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 affect Chart apiVersion 3 after it's inclusion in a full release of Helm 4 MUST follow the standard backwards compatibility contract within the same MAJOR version (ie, charts made previous to new plugins should "just work". New charts using initial or future plugins however may require a Helm minimum version for forward compatibility). + +## Security implications + +In Helm 4, users may still manually install plugins, but chart-defined plugins can also be either downloaded automatically or pre-packaged within a chart if not already downloaded. 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): + +- [ ] add Chart-defined `plugins` to Charts v3 schema + - [ ] `render`: allow chart authors to specify alternative render plugins + - [ ] `download`: allow chart authors to specify alternative download plugins (for non-default chart dependency schemes) +- [ ] allow Chart-defined plugins to be packaged within a chart's `plugins` directory. Particularly useful for airgap: + - [ ] update `pkg/action/package` to apply to Chart-defined plugins as well as subchart dependencies + - [ ] add CLI command to package these within the chart. Similar to `helm dependency update`, `dependency build` +- [ ] update other helm CLI commands that will invoke Chart-defined plugins (`helm template`, `install`, `upgrade`) + - [ ] add flags described in [Security implications](#Security-implications) + - [ ] automatically attempt to download chart-defined plugins, if they don't already exist locally + - [ ] automatically attempt to verify plugin signature (unless bypass flags are passed) + - [ ] automatically install the plugin if it is signed, and if the signature verifies (unless bypass flags are passed) + +## 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 + +*Any points that are still being decided/discussed.* + +1. Chart-defined plugins will be required to use the chart. How will these plugins be made available to the end user? + - The chart will need to include a `plugins` section that lists the plugins that should be installed for the chart. + - Previously, users needed to opt-in to any non-Helm core code by installing plugins manually, but now the chart will include CHart-defined non-Helm core plugins by default. Is it enough for these plugins to be discoverable by the user with a new command `helm chart plugins list`? Or should an explicit flag be added to any Helm commands that use custom plugins (such as `install`, `template`, etc.) to require the user to opt-in to non-Helm core plugins before commands run them? + +## Rejected ideas + +*Why certain ideas that were brought while discussing this HIP were not ultimately pursued.* + +1. 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). + +1. 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. From 8b84fea26466bb0766964b8747a6510c64aef086 Mon Sep 17 00:00:00 2001 From: Scott Rigby Date: Mon, 23 Feb 2026 12:33:40 -0500 Subject: [PATCH 02/10] docs: Update HIP chart-defined plugins specification - Resolve open issues from implementation experience - Document content cache at $HELM_CACHE_HOME/content/ - Add archive-based plugin loading details - Add airgap support considerations (Open Issue #5) - Clean up rejected ideas section Signed-off-by: Scott Rigby --- hips/hip-9999.md | 482 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 431 insertions(+), 51 deletions(-) diff --git a/hips/hip-9999.md b/hips/hip-9999.md index 8aac106bd..325d8f481 100644 --- a/hips/hip-9999.md +++ b/hips/hip-9999.md @@ -1,7 +1,8 @@ --- hip: 9999 title: "H4HIP: Chart-defined plugins" -authors: [ "Scott Rigby ", "George Jenkins " ] +authors: + ["Scott Rigby ", "George Jenkins "] created: "2025-04-11" type: "feature" status: "draft" @@ -10,7 +11,7 @@ helm-version: "4" ## Abstract -This HIP builds upon [H4HIP: Improve and extend plugin system](./hip-9999.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. +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 @@ -18,53 +19,239 @@ While the main plugin system HIP enables users to extend Helm's functionality, c ## 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` capturing specific plugin versions and checksums. +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: -- **Download** (to allow chart authors to specify plugins for downloading subcharts with different protocols than the default) -- **Manifest render** (for rendering a chart's templates into a set of Kubernetes resources using some other engine than gotemplate) +- **`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., Pkl, 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) +- **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 may be added to allow future plugins to specify the minimum version of Helm that must be used for the chart (or since this is the version of Helm that introduced the new plugin, perhaps this can be auto-detected). -A first pass for Chart-defined plugin syntax in `Chart.yaml`: +### 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 -# made up URLs—these are not actual Helm 4 plugins yet +apiVersion: v3 +name: my-chart +version: 1.0.0 + +# Chart-defined plugins (sequential list order matters for render plugins) plugins: - name: pkl - type: render.plugins.helm.sh/v1 - url: https://github.com/pkl-community/helm-pkl + type: render/v1 + repository: oci://ghcr.io/pkl-community/helm-pkl version: 0.1.0 - - name: helmys - type: render.plugins.helm.sh/v1 - url: https://github.com/kubeys/helmys - version: 0.1.4 - name: s3 - type: download.plugins.helm.sh/v1 - url: https://github.com/hypnoglow/helm-s3 + type: getter/v1 + repository: oci://ghcr.io/hypnoglow/helm-s3 version: 0.16.3 - - name: git - type: download.plugins.helm.sh/v1 - url: https://github.com/aslafy-z/helm-git - version: 1.3.0 + +# 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" ``` -### Helm plugin commands +**Example file targeting scenarios:** + +- Gotemplate plugin: `["/templates/*.yaml", "/templates/*.tpl", "/templates/NOTES.txt", "/tests/*.yaml"]` +- Pkl plugin: `["/templates/*.pkl", "*.pkl.yaml"]` +- Kustomize plugin: `["kustomization.yaml", "overlays/*.yaml"]` +- Cue plugin: `[".cue", "*.cue.json", "*.cue.yaml"]` -Commands will be added to allow packaging Chart-defined plugins within the chart: +This allows plugins to manage complete file dependency sets (e.g., gotemplate managing both `.tpl` partials and `.yaml` templates). -- `helm chart plugin build` similar to `helm dependency build` but for plugins -- `helm chart plugin update` similar to `helm dependency update` but for plugins +#### 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 +- `Template` - Template-specific information (name, base path) + +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 -To enable airgapped installations and other use cases where downloading Chart-defined plugins is not feasible, plugins may be packaged and distributed with the chart itself, similar to how Helm 3 allows this for a chart's subchart dependencies. A command will be added to enable this (see H4HIP 9999: Improve and extend plugin system [Helm plugin commands specification](./hip-9999.md#Helm-plugin-commands-specification)). +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 Status: Downloaded vs Installed + +Plugins can exist in two states: + +| Status | Description | +| -------------- | ----------------------------------------------------------------------------- | +| **Installed** | Globally installed via `helm plugin install`, available for all Helm commands | +| **Downloaded** | Fetched for chart-defined use, only available when chart specifies it | + +**Storage locations:** + +| Type | Path | Purpose | +| -------------------------- | ------------------------------------------ | --------------------------------------------- | +| Global install destination | `$PLUGINS_DIR//` | Final location for installed plugins | +| Global install cache | `$HELM_CACHE_HOME/plugins/{oci-key}/` | Temporary extraction during installation | +| Chart-defined tarball | `$HELM_CACHE_HOME/content/{digest}.plugin` | Content-addressable cache (loaded at runtime) | + +Chart-defined plugins are loaded directly from the cached tarball at runtime, matching how charts are loaded. There is no persistent extracted directory - the `plugin.yaml` and `.wasm` files are read into memory when needed. + +**Content-addressable caching:** Chart-defined 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) + +**Key distinctions:** + +- **Installed** plugins appear in `helm plugin list` and are available for any Helm operation +- **Downloaded** plugins are only used when a chart explicitly specifies that version in `Chart.yaml` +- Downloaded plugins can be "installed" (promoted to global) via `helm plugin install` which creates a symlink +- The same plugin can exist in both states (e.g., v1.0.0 installed globally, v2.0.0 downloaded for a specific chart) + +**Installing a downloaded plugin globally:** + +```bash +# After downloading via helm dependency update, install globally: +helm plugin install --from-download pkl-render 0.2.0 + +# This creates a symlink: +# $PLUGINS_DIR/pkl-render -> versions/pkl-render/0.2.0 +``` + +**Plugin loading precedence:** + +When a chart specifies a plugin, Helm looks in this order: + +1. **Downloaded path first:** `$PLUGINS_DIR/versions///` +2. **Fallback to installed:** `$PLUGINS_DIR//` (only if version matches) + +If the fallback path is used, the installed plugin's version **must match** the version specified in `Chart.yaml`. This prevents accidental use of incompatible plugin versions. + +**`helm plugin list` enhancements:** + +To support chart-defined plugins, `helm plugin list` will be extended: + +```bash +# Show only globally installed plugins (default, backwards compatible) +helm plugin list + +# Show only downloaded (chart-defined) plugins +helm plugin list --status=downloaded + +# Show all plugins with status column +helm plugin list --status=all +``` + +Example output with `--status=all`: + +``` +NAME VERSION STATUS TYPE DESCRIPTION +pkl-render 0.1.0 installed render/v1 Pkl template renderer +pkl-render 0.2.0 downloaded render/v1 Pkl template renderer +s3-getter 1.0.0 installed getter/v1 S3 protocol support +``` ## Backwards compatibility @@ -81,54 +268,247 @@ 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. + 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). + + 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): -- [ ] add Chart-defined `plugins` to Charts v3 schema - - [ ] `render`: allow chart authors to specify alternative render plugins - - [ ] `download`: allow chart authors to specify alternative download plugins (for non-default chart dependency schemes) -- [ ] allow Chart-defined plugins to be packaged within a chart's `plugins` directory. Particularly useful for airgap: - - [ ] update `pkg/action/package` to apply to Chart-defined plugins as well as subchart dependencies - - [ ] add CLI command to package these within the chart. Similar to `helm dependency update`, `dependency build` -- [ ] update other helm CLI commands that will invoke Chart-defined plugins (`helm template`, `install`, `upgrade`) - - [ ] add flags described in [Security implications](#Security-implications) - - [ ] automatically attempt to download chart-defined plugins, if they don't already exist locally - - [ ] automatically attempt to verify plugin signature (unless bypass flags are passed) - - [ ] automatically install the plugin if it is signed, and if the signature verifies (unless bypass flags are passed) +**Phase 1: Core Plugin Support** + +- [x] Add Chart-defined `plugins` list to Charts v2/v3 Metadata struct +- [x] Add `render/v1` plugin type to plugin system + - [x] Define `InputMessageRenderV1`, `OutputMessageRenderV1`, `ConfigRenderV1` schemas + - [x] Implement file targeting logic (glob matching) + - [x] Create render plugin invoker (JSON serialization of built-in objects) +- [x] Implement versioned plugin storage (`~/.local/share/helm/plugins/versions///`) +- [x] Extend `helm dependency build/update` to process `plugins` list +- [x] Update `Chart.lock` to include plugin versions +- [x] Wire render plugins into template rendering pipeline + +**Phase 2: Getter Plugin Support** + +- [ ] Add `getter/v1` as chart-defined plugin type (extends existing getter plugins) +- [ ] Update dependency downloader to use chart-defined getter plugins + +**Phase 3: 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) + +**Phase 4: Reference Implementation** + +- [x] Create example `render/v1` plugin (Pkl) +- [x] Create example Chart v3 using Pkl render plugin +- [ ] 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 +- **Pkl render/v1 plugin**: [scottrigby/ref-hip-chart-defined-plugins](https://github.com/scottrigby/ref-hip-chart-defined-plugins) - A Wasm plugin using Extism Go PDK that processes `.pkl` files +- **Example Pkl chart**: [scottrigby/ref-hip-chart-defined-plugins/charts/pkl-chart](https://github.com/scottrigby/ref-hip-chart-defined-plugins/tree/main/charts/pkl-chart) - Demonstrates Chart.yaml with plugins list and Pkl templates + +## Reference Links + +- [HIP PR](https://github.com/helm/community/pull/400) +- [Helm Built-in Objects](https://helm.sh/docs/chart_template_guide/builtin_objects/) +- [Pkl Helm Discussion](https://github.com/apple/pkl/discussions/1190#discussioncomment-15262863) ## 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 + - 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 -*Any points that are still being decided/discussed.* +_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 + +**Decision needed:** ArtifactHub schema for chart-defined plugins? + +### 3. Flux Integration Architecture + +For GitOps deployments using Flux, helm-controller has unique constraints: + +- **No disk access**: helm-controller fetches artifacts via HTTP into memory +- **Long-running process**: Keeping all compiled Wasm modules in memory could exhaust resources +- **Performance requirements**: Pre-compiled machine code matches native Go; in-memory JIT has overhead + +**Proposed solution**: HelmPlugin controller + +A dedicated Flux controller that: + +1. Watches HelmPlugin CRs referencing OCI plugin artifacts +2. Compiles Wasm to native machine code for cluster architecture +3. Publishes compiled artifacts via ExternalArtifact API +4. helm-controller fetches pre-compiled code via existing artifact mechanism + +```yaml +apiVersion: helm.toolkit.fluxcd.io/v1 +kind: HelmPlugin +metadata: + name: varsubst-render +spec: + type: render/v1 + ref: + oci: oci://ghcr.io/helm/plugins/varsubst-render + tag: v1.0.0 +status: + artifact: + url: http://helmplugin-controller/artifacts/varsubst-render.tar.gz + digest: sha256:... +``` + +**Benefits:** -1. Chart-defined plugins will be required to use the chart. How will these plugins be made available to the end user? - - The chart will need to include a `plugins` section that lists the plugins that should be installed for the chart. - - Previously, users needed to opt-in to any non-Helm core code by installing plugins manually, but now the chart will include CHart-defined non-Helm core plugins by default. Is it enough for these plugins to be discoverable by the user with a new command `helm chart plugins list`? Or should an explicit flag be added to any Helm commands that use custom plugins (such as `install`, `template`, etc.) to require the user to opt-in to non-Helm core plugins before commands run them? +- Decouples compilation from execution +- Fits Flux's ExternalArtifact extensibility pattern +- Memory-efficient: load-execute-release pattern +- Version coupling acceptable (Flux controllers released together) + +**SDK Implementation Requirement:** + +To support SDK users like Flux who need filesystem-independent plugin loading, the internal `plugin.Invoke()` must be abstracted to not assume direct filesystem access: + +- Pre-loading: Disk loading, HTTP fetching, or other acquisition happens in advance +- Invocation: Compiled machine code is passed as an in-memory object (e.g., `[]byte` or `wazero.CompiledModule`) +- Benefit: SDK users control how/where plugins are sourced without Helm assuming disk access + +**Phased rollout:** + +1. Helm CLI: Disk-cached compilation (implemented, enabled by default) +2. SDK API: Abstract `Invoke()` to accept pre-loaded compiled modules +3. Flux MVP: LRU compilation cache in helm-controller (bounded memory) +4. Flux Scale: HelmPlugin controller + ExternalArtifact +5. Enterprise: Multi-arch OCI distribution + +See [FLUX-WASM-INTEGRATION.md](../docs/FLUX-WASM-INTEGRATION.md) for detailed Flux architecture. + +### 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? + +**Decision needed:** Keep, rename, or deprecate `Template` built-in for render plugins? + +### 5. Airgap Support: Download Command vs Registry Mirroring + +For airgap deployments, users need a way to pre-fetch chart-defined plugins. + +**Option A: `helm plugin download` command** + +A dedicated command to download plugins from OCI registries to the local content cache, independent of any chart: + +```bash +# Download specific plugin version +helm plugin download oci://ghcr.io/helm-plugins/pkl-render:0.1.0 + +# Download all plugins required by a chart +helm plugin download --from-chart ./my-chart/ +``` + +**Option B: 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 would redirect plugin downloads to an internal mirror without code changes. + +**Considerations:** + +- Option A provides explicit control but adds a new command +- Option B reuses existing OCI patterns but requires registry infrastructure +- Both options may be valuable for different scenarios + +**Decision needed:** Implement `helm plugin download`, wait for registries.conf, or both? ## Rejected ideas -*Why certain ideas that were brought while discussing this HIP were not ultimately pursued.* +_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/`. -1. Helm 4 will not support chart-defined required plugins for Chart API v2. +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). + 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). -1. Helm 4 will not continue to only support gotemplate for rendering manifests as Helm 3 did. +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. + 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. + 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. From 3886fe2205eb1b04cdaa9fe4db629d7abf555f18 Mon Sep 17 00:00:00 2001 From: Scott Rigby Date: Tue, 24 Feb 2026 23:03:32 -0500 Subject: [PATCH 03/10] docs: Update HIP chart-defined plugins specification - Fix storage locations table (remove incorrect install cache row) - Add SDK considerations section for controller/platform use cases - Add note about gotemplate plugin handling Template built-in - Clarify helm plugin list --status=all shows separate rows - Note --from-download flag as future enhancement Signed-off-by: Scott Rigby --- hips/hip-9999.md | 107 +++++++++++++++++++++++++---------------------- 1 file changed, 58 insertions(+), 49 deletions(-) diff --git a/hips/hip-9999.md b/hips/hip-9999.md index 325d8f481..0f7b50b16 100644 --- a/hips/hip-9999.md +++ b/hips/hip-9999.md @@ -192,10 +192,10 @@ Plugins can exist in two states: | Type | Path | Purpose | | -------------------------- | ------------------------------------------ | --------------------------------------------- | | Global install destination | `$PLUGINS_DIR//` | Final location for installed plugins | -| Global install cache | `$HELM_CACHE_HOME/plugins/{oci-key}/` | Temporary extraction during installation | | Chart-defined tarball | `$HELM_CACHE_HOME/content/{digest}.plugin` | Content-addressable cache (loaded at runtime) | +| Chart-defined extracted | `$PLUGINS_DIR/versions///` | Versioned plugin files for execution | -Chart-defined plugins are loaded directly from the cached tarball at runtime, matching how charts are loaded. There is no persistent extracted directory - the `plugin.yaml` and `.wasm` files are read into memory when needed. +Chart-defined plugins are cached as tarballs in the content-addressable cache and extracted to versioned directories for execution. This enables efficient storage and deduplication while supporting Wasm compilation which requires file paths. **Content-addressable caching:** Chart-defined plugin tarballs are stored using their SHA256 digest, enabling: @@ -210,16 +210,18 @@ Chart-defined plugins are loaded directly from the cached tarball at runtime, ma - Downloaded plugins can be "installed" (promoted to global) via `helm plugin install` which creates a symlink - The same plugin can exist in both states (e.g., v1.0.0 installed globally, v2.0.0 downloaded for a specific chart) -**Installing a downloaded plugin globally:** +**Installing a downloaded plugin globally (future enhancement):** ```bash # After downloading via helm dependency update, install globally: helm plugin install --from-download pkl-render 0.2.0 -# This creates a symlink: +# This would create a symlink: # $PLUGINS_DIR/pkl-render -> versions/pkl-render/0.2.0 ``` +> **Note**: The `--from-download` flag is a proposed enhancement, not yet implemented. It would allow users to promote a downloaded (chart-defined) plugin to a globally installed plugin. + **Plugin loading precedence:** When a chart specifies a plugin, Helm looks in this order: @@ -249,10 +251,13 @@ Example output with `--status=all`: ``` NAME VERSION STATUS TYPE DESCRIPTION pkl-render 0.1.0 installed render/v1 Pkl template renderer +pkl-render 0.1.0 downloaded render/v1 Pkl template renderer pkl-render 0.2.0 downloaded render/v1 Pkl template renderer s3-getter 1.0.0 installed getter/v1 S3 protocol support ``` +> **Note**: A plugin version can appear twice if it exists in both installed and downloaded states (stored in different locations). Each row represents a distinct physical location. + ## Backwards compatibility Requirements for chart-defined plugins: @@ -313,8 +318,8 @@ This work is dependent on, and will be in conjunction with, [H4HIP: Charts v3 En 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 -- **Pkl render/v1 plugin**: [scottrigby/ref-hip-chart-defined-plugins](https://github.com/scottrigby/ref-hip-chart-defined-plugins) - A Wasm plugin using Extism Go PDK that processes `.pkl` files -- **Example Pkl chart**: [scottrigby/ref-hip-chart-defined-plugins/charts/pkl-chart](https://github.com/scottrigby/ref-hip-chart-defined-plugins/tree/main/charts/pkl-chart) - Demonstrates Chart.yaml with plugins list and Pkl templates +- **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 @@ -371,63 +376,65 @@ How should chart-defined plugins be discovered and listed on ArtifactHub? **Decision needed:** ArtifactHub schema for chart-defined plugins? -### 3. Flux Integration Architecture +### 3. SDK Considerations -For GitOps deployments using Flux, helm-controller has unique constraints: +The Helm SDK is used by various tools and platforms beyond the CLI, including: -- **No disk access**: helm-controller fetches artifacts via HTTP into memory -- **Long-running process**: Keeping all compiled Wasm modules in memory could exhaust resources -- **Performance requirements**: Pre-compiled machine code matches native Go; in-memory JIT has overhead +- **Kubernetes controllers** (e.g., Flux helm-controller) +- **CI/CD pipelines** +- **Custom automation tools** +- **Platform-as-a-Service offerings** -**Proposed solution**: HelmPlugin controller +These SDK users have unique constraints that the plugin system must address: -A dedicated Flux controller that: +#### Long-Running Processes -1. Watches HelmPlugin CRs referencing OCI plugin artifacts -2. Compiles Wasm to native machine code for cluster architecture -3. Publishes compiled artifacts via ExternalArtifact API -4. helm-controller fetches pre-compiled code via existing artifact mechanism +Controllers and servers keep the Helm SDK loaded in memory continuously. Considerations: -```yaml -apiVersion: helm.toolkit.fluxcd.io/v1 -kind: HelmPlugin -metadata: - name: varsubst-render -spec: - type: render/v1 - ref: - oci: oci://ghcr.io/helm/plugins/varsubst-render - tag: v1.0.0 -status: - artifact: - url: http://helmplugin-controller/artifacts/varsubst-render.tar.gz - digest: sha256:... -``` +- **Memory management**: Compiled Wasm modules consume memory; need lifecycle hooks 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 should support: -**Benefits:** +- **Bounded compilation cache**: Configurable maximum size +- **Lazy loading**: Only load plugins when needed +- **Cleanup callbacks**: Explicit memory release after operations -- Decouples compilation from execution -- Fits Flux's ExternalArtifact extensibility pattern -- Memory-efficient: load-execute-release pattern -- Version coupling acceptable (Flux controllers released together) +#### Non-Writable Filesystems -**SDK Implementation Requirement:** +Some environments run with read-only filesystems. The SDK should support: -To support SDK users like Flux who need filesystem-independent plugin loading, the internal `plugin.Invoke()` must be abstracted to not assume direct filesystem access: +- **In-memory cache option**: Alternative to disk-based compilation cache +- **Pre-compiled plugin loading**: Accept pre-compiled Wasm modules +- **HTTP-based plugin fetching**: Load plugins from URLs without local extraction -- Pre-loading: Disk loading, HTTP fetching, or other acquisition happens in advance -- Invocation: Compiled machine code is passed as an in-memory object (e.g., `[]byte` or `wazero.CompiledModule`) -- Benefit: SDK users control how/where plugins are sourced without Helm assuming disk access +#### SDK API Requirements -**Phased rollout:** +To support these use cases, the SDK must abstract plugin loading: -1. Helm CLI: Disk-cached compilation (implemented, enabled by default) -2. SDK API: Abstract `Invoke()` to accept pre-loaded compiled modules -3. Flux MVP: LRU compilation cache in helm-controller (bounded memory) -4. Flux Scale: HelmPlugin controller + ExternalArtifact -5. Enterprise: Multi-arch OCI distribution +```go +// SDK users can customize caching behavior +type RenderOptions struct { + // CompilationCache allows custom Wasm compilation cache + // Default: disk-based at $HELM_CACHE_HOME/wazero-build/ + CompilationCache wazero.CompilationCache -See [FLUX-WASM-INTEGRATION.md](../docs/FLUX-WASM-INTEGRATION.md) for detailed Flux architecture. + // ContentCache allows custom plugin tarball cache + // Default: disk-based at $HELM_CACHE_HOME/content/ + ContentCache downloader.Cache + + // PreloadedPlugins allows passing pre-compiled plugins + // Useful for non-writable filesystems or pre-warmed caches + PreloadedPlugins map[string]wazero.CompiledModule +} +``` + +#### 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. ### 4. Template Built-in Object @@ -443,6 +450,8 @@ The current `Template` built-in object (providing template name and base path) m **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. Airgap Support: Download Command vs Registry Mirroring From faac6cad758cd674bd3c0c9204878737ed93d868 Mon Sep 17 00:00:00 2001 From: Scott Rigby Date: Tue, 24 Feb 2026 23:03:32 -0500 Subject: [PATCH 04/10] docs (hip-chart-defined-plugins): update storage to content-cache-only architecture - Remove "Chart-defined extracted" row from storage locations table - Update explanation: plugins loaded directly from tarball into memory - Update plugin loading precedence: content cache is primary path - Update --from-download example to show extraction (not symlink) - Update implementation checklist to reflect content-addressable cache The Wasm runtime (extism/v1) supports loading plugin binaries directly from bytes via CreatePluginFromData, eliminating the need for disk extraction to a versioned directory. Signed-off-by: Scott Rigby --- hips/hip-9999.md | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/hips/hip-9999.md b/hips/hip-9999.md index 0f7b50b16..28a912307 100644 --- a/hips/hip-9999.md +++ b/hips/hip-9999.md @@ -193,9 +193,8 @@ Plugins can exist in two states: | -------------------------- | ------------------------------------------ | --------------------------------------------- | | Global install destination | `$PLUGINS_DIR//` | Final location for installed plugins | | Chart-defined tarball | `$HELM_CACHE_HOME/content/{digest}.plugin` | Content-addressable cache (loaded at runtime) | -| Chart-defined extracted | `$PLUGINS_DIR/versions///` | Versioned plugin files for execution | -Chart-defined plugins are cached as tarballs in the content-addressable cache and extracted to versioned directories for execution. This enables efficient storage and deduplication while supporting Wasm compilation which requires file paths. +Chart-defined plugins are cached as tarballs in the content-addressable cache and loaded directly into memory at runtime (no disk extraction required). The Wasm runtime loads plugin binaries from the tarball bytes. **Content-addressable caching:** Chart-defined plugin tarballs are stored using their SHA256 digest, enabling: @@ -216,17 +215,17 @@ Chart-defined plugins are cached as tarballs in the content-addressable cache an # After downloading via helm dependency update, install globally: helm plugin install --from-download pkl-render 0.2.0 -# This would create a symlink: -# $PLUGINS_DIR/pkl-render -> versions/pkl-render/0.2.0 +# This would extract the plugin from the content cache to: +# $PLUGINS_DIR/pkl-render/ ``` -> **Note**: The `--from-download` flag is a proposed enhancement, not yet implemented. It would allow users to promote a downloaded (chart-defined) plugin to a globally installed plugin. +> **Note**: The `--from-download` flag is a proposed enhancement, not yet implemented. It would extract a cached plugin tarball to the global plugins directory. **Plugin loading precedence:** When a chart specifies a plugin, Helm looks in this order: -1. **Downloaded path first:** `$PLUGINS_DIR/versions///` +1. **Content cache first:** `$HELM_CACHE_HOME/content/{digest}.plugin` (loaded directly from tarball) 2. **Fallback to installed:** `$PLUGINS_DIR//` (only if version matches) If the fallback path is used, the installed plugin's version **must match** the version specified in `Chart.yaml`. This prevents accidental use of incompatible plugin versions. @@ -290,7 +289,7 @@ This work is dependent on, and will be in conjunction with, [H4HIP: Charts v3 En - [x] Define `InputMessageRenderV1`, `OutputMessageRenderV1`, `ConfigRenderV1` schemas - [x] Implement file targeting logic (glob matching) - [x] Create render plugin invoker (JSON serialization of built-in objects) -- [x] Implement versioned plugin storage (`~/.local/share/helm/plugins/versions///`) +- [x] Implement content-addressable plugin cache (`$HELM_CACHE_HOME/content/{digest}.plugin`) - [x] Extend `helm dependency build/update` to process `plugins` list - [x] Update `Chart.lock` to include plugin versions - [x] Wire render plugins into template rendering pipeline From fb04592bc42b4df1c4b1214a584c100f74826e6d Mon Sep 17 00:00:00 2001 From: Scott Rigby Date: Tue, 24 Feb 2026 23:03:33 -0500 Subject: [PATCH 05/10] docs: clarify plugin identity by content hash - Update Plugin Storage section to clarify no fallback between installed plugins and chart-defined plugins - Add Plugin identity section explaining content hash identification - Add rejected idea #6: fallback to installed plugins Chart-defined plugins are identified by their SHA256 digest from Chart.lock, ensuring deterministic builds. An installed plugin with matching name/version cannot substitute because there's no way to verify the content matches the locked digest. Signed-off-by: Scott Rigby --- hips/hip-9999.md | 174 ++++++++++++++++++++++++----------------------- 1 file changed, 90 insertions(+), 84 deletions(-) diff --git a/hips/hip-9999.md b/hips/hip-9999.md index 28a912307..939a96dfe 100644 --- a/hips/hip-9999.md +++ b/hips/hip-9999.md @@ -178,84 +178,46 @@ Plugins are referenced by OCI URL in `Chart.yaml` (not packaged within charts). **Plugin versioning:** The content cache supports multiple versions of the same plugin, allowing different charts to depend on different plugin versions without conflicts. -### Plugin Status: Downloaded vs Installed +### Plugin Storage: Installed vs Cached -Plugins can exist in two states: +Plugins exist in two distinct storage models: -| Status | Description | -| -------------- | ----------------------------------------------------------------------------- | -| **Installed** | Globally installed via `helm plugin install`, available for all Helm commands | -| **Downloaded** | Fetched for chart-defined use, only available when chart specifies it | +| 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 tarball | `$HELM_CACHE_HOME/content/{digest}.plugin` | Content-addressable cache (loaded at runtime) | +| 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) | -Chart-defined plugins are cached as tarballs in the content-addressable cache and loaded directly into memory at runtime (no disk extraction required). The Wasm runtime loads plugin binaries from the tarball bytes. +**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:** Chart-defined plugin tarballs are stored using their SHA256 digest, enabling: +**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 -- **Downloaded** plugins are only used when a chart explicitly specifies that version in `Chart.yaml` -- Downloaded plugins can be "installed" (promoted to global) via `helm plugin install` which creates a symlink -- The same plugin can exist in both states (e.g., v1.0.0 installed globally, v2.0.0 downloaded for a specific chart) +- **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) -**Installing a downloaded plugin globally (future enhancement):** +**Plugin identity:** -```bash -# After downloading via helm dependency update, install globally: -helm plugin install --from-download pkl-render 0.2.0 +Chart-defined plugins are identified by their **content hash** (SHA256 digest), not by name/version. This ensures deterministic builds: -# This would extract the plugin from the content cache to: -# $PLUGINS_DIR/pkl-render/ -``` - -> **Note**: The `--from-download` flag is a proposed enhancement, not yet implemented. It would extract a cached plugin tarball to the global plugins directory. - -**Plugin loading precedence:** - -When a chart specifies a plugin, Helm looks in this order: - -1. **Content cache first:** `$HELM_CACHE_HOME/content/{digest}.plugin` (loaded directly from tarball) -2. **Fallback to installed:** `$PLUGINS_DIR//` (only if version matches) - -If the fallback path is used, the installed plugin's version **must match** the version specified in `Chart.yaml`. This prevents accidental use of incompatible plugin versions. - -**`helm plugin list` enhancements:** - -To support chart-defined plugins, `helm plugin list` will be extended: - -```bash -# Show only globally installed plugins (default, backwards compatible) -helm plugin list - -# Show only downloaded (chart-defined) plugins -helm plugin list --status=downloaded - -# Show all plugins with status column -helm plugin list --status=all -``` - -Example output with `--status=all`: - -``` -NAME VERSION STATUS TYPE DESCRIPTION -pkl-render 0.1.0 installed render/v1 Pkl template renderer -pkl-render 0.1.0 downloaded render/v1 Pkl template renderer -pkl-render 0.2.0 downloaded render/v1 Pkl template renderer -s3-getter 1.0.0 installed getter/v1 S3 protocol support -``` - -> **Note**: A plugin version can appear twice if it exists in both installed and downloaded states (stored in different locations). Each row represents a distinct physical location. +- `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 ## Backwards compatibility @@ -372,10 +334,26 @@ How should chart-defined plugins be discovered and listed on ArtifactHub? - 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. SDK Considerations +### 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. SDK Considerations The Helm SDK is used by various tools and platforms beyond the CLI, including: @@ -435,7 +413,7 @@ type RenderOptions struct { 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. -### 4. Template Built-in Object +### 5. Template Built-in Object The current `Template` built-in object (providing template name and base path) may need to be: @@ -453,23 +431,11 @@ The current `Template` built-in object (providing template name and base path) m **Decision needed:** Keep, rename, or deprecate `Template` built-in for render plugins? -### 5. Airgap Support: Download Command vs Registry Mirroring +### 6. Airgap Support: Registry Mirroring -For airgap deployments, users need a way to pre-fetch chart-defined plugins. +For airgap deployments, users need a way to access chart-defined plugins without direct internet access. -**Option A: `helm plugin download` command** - -A dedicated command to download plugins from OCI registries to the local content cache, independent of any chart: - -```bash -# Download specific plugin version -helm plugin download oci://ghcr.io/helm-plugins/pkl-render:0.1.0 - -# Download all plugins required by a chart -helm plugin download --from-chart ./my-chart/ -``` - -**Option B: Registry mirroring via registries.conf** +**Recommended approach: Registry mirroring via registries.conf** The [registries.conf HIP](https://github.com/helm/community/pull/391) proposes registry configuration that would allow: @@ -480,15 +446,14 @@ prefix = "ghcr.io" location = "internal-registry.corp.com/mirror" ``` -This would redirect plugin downloads to an internal mirror without code changes. - -**Considerations:** +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: -- Option A provides explicit control but adds a new command -- Option B reuses existing OCI patterns but requires registry infrastructure -- Both options may be valuable for different scenarios +- 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 -**Decision needed:** Implement `helm plugin download`, wait for registries.conf, or both? +**Decision:** Prioritize registries.conf implementation before moving chart-defined plugins out of experimental. A dedicated `helm plugin download` command is not planned (see Rejected Ideas). ## Rejected ideas @@ -520,3 +485,44 @@ _Why certain ideas that were brought while discussing this HIP were not ultimate 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/pkl-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. From 742886a732f7bbe757bc2a0cc1d553220dd2e3d1 Mon Sep 17 00:00:00 2001 From: Scott Rigby Date: Tue, 24 Feb 2026 23:03:33 -0500 Subject: [PATCH 06/10] docs: update SDK API to match reference implementation Update the SDK API Requirements section to reflect the reference implementation PluginRenderer struct: - ContentCachePath (string path) instead of ContentCache interface - PreloadedPlugins as raw bytes, not pre-compiled modules - Add explicit requirements for non-writable filesystems Signed-off-by: Scott Rigby --- hips/hip-9999.md | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/hips/hip-9999.md b/hips/hip-9999.md index 939a96dfe..73a871257 100644 --- a/hips/hip-9999.md +++ b/hips/hip-9999.md @@ -390,25 +390,32 @@ Some environments run with read-only filesystems. The SDK should support: #### SDK API Requirements -To support these use cases, the SDK must abstract plugin loading: +To support these use cases, the SDK provides the `PluginRenderer` with configurable options: ```go -// SDK users can customize caching behavior -type RenderOptions struct { - // CompilationCache allows custom Wasm compilation cache +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 - // ContentCache allows custom plugin tarball cache - // Default: disk-based at $HELM_CACHE_HOME/content/ - ContentCache downloader.Cache - - // PreloadedPlugins allows passing pre-compiled plugins - // Useful for non-writable filesystems or pre-warmed caches - PreloadedPlugins map[string]wazero.CompiledModule + // 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 } ``` +**For non-writable 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. From fa290913509d74f7201b71476c20292175496b2c Mon Sep 17 00:00:00 2001 From: Scott Rigby Date: Thu, 26 Feb 2026 17:35:27 -0500 Subject: [PATCH 07/10] docs(hip-9999): Clarify design decisions and implementation status - Fix security section: plugins downloaded, not pre-packaged in charts - Replace Pkl with YamlScript as primary render example (Pkl blocked on Java/Wasm support, but kept in file targeting examples) - Move SDK API from open issues to specification (already designed) - Move Airgap Support from open issues to specification (decided on registries.conf) - Add SourceFiles to built-in objects, link Template to open issue - Clarify implementation plan: ref impl complete, upstream pending - Add rejected idea #7: pre-packaging plugins within charts - Update reference link to YamlScript Helm discussion Signed-off-by: Scott Rigby --- hips/hip-9999.md | 243 ++++++++++++++++++++++++----------------------- 1 file changed, 122 insertions(+), 121 deletions(-) diff --git a/hips/hip-9999.md b/hips/hip-9999.md index 73a871257..7003c655e 100644 --- a/hips/hip-9999.md +++ b/hips/hip-9999.md @@ -26,7 +26,7 @@ Support for Chart-defined plugins will be added starting in Chart API v3. `Chart 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., Pkl, Cue, Kustomize) +- **`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: @@ -53,9 +53,9 @@ version: 1.0.0 # Chart-defined plugins (sequential list order matters for render plugins) plugins: - - name: pkl + - name: yamlscript type: render/v1 - repository: oci://ghcr.io/pkl-community/helm-pkl + repository: oci://ghcr.io/yamlscript/helm-yamlscript version: 0.1.0 - name: s3 type: getter/v1 @@ -100,6 +100,7 @@ config: - 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"]` @@ -115,7 +116,8 @@ All `render/v1` plugins receive the same Helm built-in objects via JSON serializ - `Subcharts` - Metadata about subchart dependencies - `Files` - Non-template files accessible to the chart - `Capabilities` - Information about the Kubernetes cluster -- `Template` - Template-specific information (name, base path) +- `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`. @@ -219,6 +221,84 @@ Chart-defined plugins are identified by their **content hash** (SHA256 digest), - 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: @@ -228,7 +308,7 @@ Requirements for chart-defined plugins: ## Security implications -In Helm 4, users may still manually install plugins, but chart-defined plugins can also be either downloaded automatically or pre-packaged within a chart if not already downloaded. This could surprise a user if they are not made aware of this. +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: @@ -244,35 +324,35 @@ Helm 4 will address this in the following ways: 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): -**Phase 1: Core Plugin Support** +> **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 -- [x] Add Chart-defined `plugins` list to Charts v2/v3 Metadata struct -- [x] Add `render/v1` plugin type to plugin system - - [x] Define `InputMessageRenderV1`, `OutputMessageRenderV1`, `ConfigRenderV1` schemas - - [x] Implement file targeting logic (glob matching) - - [x] Create render plugin invoker (JSON serialization of built-in objects) -- [x] Implement content-addressable plugin cache (`$HELM_CACHE_HOME/content/{digest}.plugin`) -- [x] Extend `helm dependency build/update` to process `plugins` list -- [x] Update `Chart.lock` to include plugin versions -- [x] Wire render plugins into template rendering pipeline +- 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 -**Phase 2: Getter Plugin Support** +### Getter Plugin Support -- [ ] Add `getter/v1` as chart-defined plugin type (extends existing getter plugins) -- [ ] Update dependency downloader to use chart-defined getter plugins +- Add `getter/v1` as chart-defined plugin type (extends existing getter plugins) +- Update dependency downloader to use chart-defined getter plugins -**Phase 3: Security & CLI** +### 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) +- 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) -**Phase 4: Reference Implementation** +### Documentation -- [x] Create example `render/v1` plugin (Pkl) -- [x] Create example Chart v3 using Pkl render plugin -- [ ] Document plugin development workflow +- Document plugin development workflow ### Reference Implementation @@ -286,7 +366,7 @@ A reference implementation has been developed to validate this design: - [HIP PR](https://github.com/helm/community/pull/400) - [Helm Built-in Objects](https://helm.sh/docs/chart_template_guide/builtin_objects/) -- [Pkl Helm Discussion](https://github.com/apple/pkl/discussions/1190#discussioncomment-15262863) +- [YamlScript Helm Discussion](https://github.com/yaml/yamlscript/discussions/243) ## How to teach this @@ -353,74 +433,7 @@ These improvements would make the approval process seamless while maintaining se **Decision needed:** Priority and implementation approach for trust workflow? -### 4. SDK Considerations - -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** -- **Platform-as-a-Service offerings** - -These SDK users have unique constraints that the plugin system must address: - -#### Long-Running Processes - -Controllers and servers keep the Helm SDK loaded in memory continuously. Considerations: - -- **Memory management**: Compiled Wasm modules consume memory; need lifecycle hooks 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 should support: - -- **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. The SDK should support: - -- **In-memory cache option**: Alternative to disk-based compilation cache -- **Pre-compiled plugin loading**: Accept pre-compiled Wasm modules -- **HTTP-based plugin fetching**: Load plugins from URLs without local extraction - -#### SDK API Requirements - -To support these use cases, 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 -} -``` - -**For non-writable 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. - -### 5. Template Built-in Object +### 4. Template Built-in Object The current `Template` built-in object (providing template name and base path) may need to be: @@ -438,30 +451,6 @@ The current `Template` built-in object (providing template name and base path) m **Decision needed:** Keep, rename, or deprecate `Template` built-in for render plugins? -### 6. Airgap Support: Registry Mirroring - -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 - -**Decision:** Prioritize registries.conf implementation before moving chart-defined plugins out of experimental. A dedicated `helm plugin download` command is not planned (see Rejected Ideas). - ## Rejected ideas _Why certain ideas that were brought while discussing this HIP were not ultimately pursued._ @@ -511,7 +500,7 @@ _Why certain ideas that were brought while discussing this HIP were not ultimate The idea was to provide a dedicated command to pre-download plugins for airgap scenarios: ```bash - helm plugin download oci://ghcr.io/helm-plugins/pkl-render:0.1.0 + helm plugin download oci://ghcr.io/helm-plugins/yamlscript-render:0.1.0 ``` **Arguments against:** @@ -533,3 +522,15 @@ _Why certain ideas that were brought while discussing this HIP were not ultimate - 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`. From 1ff1bdb0a9fee5443ec016ff8654fd040754914b Mon Sep 17 00:00:00 2001 From: Scott Rigby Date: Thu, 26 Feb 2026 17:44:40 -0500 Subject: [PATCH 08/10] Add open question about plugin definiion syntax in Chart.yaml Signed-off-by: Scott Rigby --- hips/hip-9999.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/hips/hip-9999.md b/hips/hip-9999.md index 7003c655e..42b9e6ab3 100644 --- a/hips/hip-9999.md +++ b/hips/hip-9999.md @@ -451,6 +451,42 @@ The current `Template` built-in object (providing template name and base path) m **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._ From 6d75b978a6b4283ea06d3941604476ab5e5776e9 Mon Sep 17 00:00:00 2001 From: Scott Rigby Date: Fri, 27 Feb 2026 18:00:08 -0500 Subject: [PATCH 09/10] Remove self-referential HIP PR link Signed-off-by: Scott Rigby --- hips/hip-9999.md | 1 - 1 file changed, 1 deletion(-) diff --git a/hips/hip-9999.md b/hips/hip-9999.md index 42b9e6ab3..4447df710 100644 --- a/hips/hip-9999.md +++ b/hips/hip-9999.md @@ -364,7 +364,6 @@ A reference implementation has been developed to validate this design: ## Reference Links -- [HIP PR](https://github.com/helm/community/pull/400) - [Helm Built-in Objects](https://helm.sh/docs/chart_template_guide/builtin_objects/) - [YamlScript Helm Discussion](https://github.com/yaml/yamlscript/discussions/243) From 706e8d174957a9d5baf9a6356a3677722f5d0a8d Mon Sep 17 00:00:00 2001 From: Scott Rigby Date: Fri, 27 Feb 2026 23:44:55 -0500 Subject: [PATCH 10/10] docs: Add plugin type validation for backwards compatibility Add detailed documentation for how Helm handles unknown plugin types: - Helm validates plugin types at chart load time - Unknown types fail with clear error listing supported types - Error message includes documentation URL (helm.sh/docs/plugins/types) - No action required from chart authors Add links to minimumHelmVersion HIP PR #370. Add Rejected Idea #8: Requiring chart authors to manually set minimumHelmVersion for plugin types. Auto-detection is preferred. Signed-off-by: Scott Rigby --- hips/hip-9999.md | 43 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/hips/hip-9999.md b/hips/hip-9999.md index 4447df710..2a35f650c 100644 --- a/hips/hip-9999.md +++ b/hips/hip-9999.md @@ -33,7 +33,7 @@ After the initial plugin system release, the intention is to make it easy to con - **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 may be added to allow future plugins to specify the minimum version of Helm that must be used for the chart (or since this is the version of Helm that introduced the new plugin, perhaps this can be auto-detected). +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 @@ -304,7 +304,34 @@ For SDK users who want to bypass Wasm entirely, a separate HIP proposes a `go/v1 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 affect Chart apiVersion 3 after it's inclusion in a full release of Helm 4 MUST follow the standard backwards compatibility contract within the same MAJOR version (ie, charts made previous to new plugins should "just work". New charts using initial or future plugins however may require a Helm minimum version for forward compatibility). +- 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 @@ -569,3 +596,15 @@ _Why certain ideas that were brought while discussing this HIP were not ultimate - 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.