Changelog
1. 1.2.1
1.1. Dependencies
-
Template engine moved to
gotmpl4j 1.3.0(from 1.2.0). Picks up a Go-parity correctness fix — variadic method calls on values now resolve instead of silently returning nil — plus custom action delimiters, a thread-safe template cache, and the 1.3.0 engine perf batch (shareable function registry, cached method/field dispatch, cheaper scope handling). Additive and non-breaking; no jhelm API or rendering change (chart-parity suite unchanged).
1.2. Performance
The render hot path was profiled (JFR / jvmlens) and tightened. Every change is byte-for-byte identical to Helm across the full chart-parity suite (547 charts, 0 diffs):
-
Function registry reused across renders — the ServiceLoader result and the template-independent Sprig function set (~260 functions), plus their reflection/dispatch caches, are built once per
Engineand shared by every render instead of rebuilt each call (#717). -
Render thread reused instead of spawned per render — rendering runs on a single reused daemon executor rather than creating and joining a fresh large-stack thread every call. On the JMH render harness this is ~1.6x throughput with far less GC churn, and it also closes a pre-existing data race on shared engine state under concurrent renders (#721).
-
toYamlquote-stripping scans in one pass — the YAML post-processor no longer splits the document into aString[]and rebuilds it; it scans in place, allocating only for the lines it actually rewrites (#720). -
Render values boxed once per render — numeric leaf coercion runs a single time and the boxed leaves are reused, instead of deep-copying the value tree twice (#718).
-
Template parse cache on by default — a new
Engine()now keeps a 256-entry parsed-template cache, so re-rendering a chart skips re-parsing unchanged templates (#726).
1.3. Fixes
-
Library-chart
define`s are no longer served from a partial parse-cache entry— with the parse cache enabled, a global `define registered by an earlier template could be served from an incomplete cached node-delta when a second chart reused the same cache key, dropping the definition (include: Template '…' not found). Templates carrying adefinenow always parse in full, keeping the cache safe for library charts such as Bitnami Common (#726). -
install/upgradeno longer choke on---inside a YAML comment — a rendered manifest with a decorative comment such as# ---------------- Postgres ----------------failed to apply with a SnakeYAML parse error, because the manifest document splitter matched the---inside the comment as a document separator and produced an invalid fragment (jhelm templatewas unaffected; the bug was only in the apply/diff/get path that re-splits the manifest). The splitter is now line-anchored — only a line that is exactly---(optionally with trailing whitespace or a comment) starts a new document — via a sharedManifestDocuments.splitreused by hook stripping, manifest diffing, andget. #713.
2. 1.2.0
Closing CLI flag-parity gaps with Helm across the template, install, and query commands, so
more helm scripts run unchanged against jhelm. See CLI Flag Parity.
2.1. Helm parity
-
Machine-readable output on more commands —
-o table\|json\|yamlnow coversstatus,history,install,upgrade,repo list, andsearch hub, emitting Helm-shaped output (nestedinfo, snake_case keys) for scripts and agents (#678). -
templatesource markers — rendered manifests carry a Helm-style# Source: <chart>/templates/<file>marker before each document (#679). -
templaterender-control flags —-s/--show-only,--output-dir,--skip-tests,--include-crds, and--is-upgrade(#679). -
install --generate-name— omit the release name and pass-g/--generate-nameto auto-generate<chart>-<timestamp>, as Helm does (#680). -
install --description/--labels— store a custom release description and custom labels on the release Secret (#680). -
upgrade --description/--labels— set the new revision’s description and labels; without--labels, the previous release’s labels are carried forward, matching Helm (#680). -
--set-literal— oninstall,upgrade,template, andlint: set a value taken fully literally (no type coercion, no comma or escape interpretation), applied at the highest precedence in the--setfamily (#680). -
--dependency-update— oninstall,upgrade, andtemplate: update a local chart’scharts/from itsChart.yamldependencies (likehelm dependency update) before the operation. The update flow is now a reusableDependencyUpdateActionshared with thedependency updatecommand (#680). -
listfiltering & pagination —listgains-l/--selector(label selector,key=value/key!=value, comma-ANDed),--filter(regex on the release name), and--offset/-m/--max(paginate; default max 256). Results are sorted by name (#681). -
liststatus filters —-a/--allshows every status, and--deployed/--failed/--pending/--uninstalled/--uninstalling/--supersededrestrict to those states. The default view hides uninstalled and superseded releases, matching Helm (#681). -
list -A/--all-namespaces— list releases across every namespace, backed by a newKubeService.listAllReleases()(lists release Secrets cluster-wide). Releases are keyed by namespace+name so same-named releases in different namespaces stay distinct (#681). -
install/upgradefrom a repository — pass a chart name with--versionand an ad-hoc--repo <url>(plus--username/--passwordand TLS--cert-file/--key-file/--ca-file/--insecure-skip-tls-verify/--pass-credentials) to fetch the chart directly, matchinghelm install/upgrade --repo. Arepo/chartoroci://reference is also resolved via the registered repositories. Local chart paths still work unchanged (#682). -
uninstallwait/cascade semantics —--dry-run(report without deleting),--wait/--timeout(block until the resources are gone, backed by a newKubeService.waitForDeleted),--cascadebackground\|foreground\|orphan(Kubernetes deletion propagation), and--description(stored on the release when--keep-historyis set). Mirrored on REST (DELETEquery params) and MCP (#683). -
rollbackforce/cleanup semantics —--dry-run,--force(delete-and-recreate),--cleanup-on-fail(delete resources created during a failed rollback),--recreate-pods(rolling restart of the release’s workloads via a restart annotation), and--wait/--wait-for-jobs/--timeout. The rollback readiness wait now lives in the action so REST and MCP honor it too (#683). -
pullunpack & provenance —--untar/--untardirunpack the fetched chart (and drop the.tgz), and--verify/--prov/--keyringfetch the chart’s detached.provand check its PGP provenance before use (reusing theverifylayer). RESTPOST /repos/pullgains averifyflag.--devel(prerelease resolution) remains the one open pull gap — it needs semver latest-version resolution jhelm does not have yet (#684). -
repo addauth, TLS & update control —--username/--password/--cert-file/--key-file/--ca-file/--insecure-skip-tls-verify/--pass-credentialsare persisted intorepositories.yamland honored (host-gated) on every index refresh and chart pull;--force-updatereplaces an existing repo (a duplicate name otherwise fails) and--no-updateskips the immediate index fetch. Mirrored on RESTPOST /repos(#685). -
Validating
registry login—registry loginnow follows Helm’s flow: it validates the credentials against the registry (a/v2/ping and, on a Bearer challenge, a token exchange) before storing them, and honors the login-time transport flags--insecure,--plain-http,--ca-file,--cert-file, and--key-file. As in Helm, those transport options apply only to the handshake and are not persisted — only the credentials are stored. A wrong password, TLS failure, or unreachable registry now fails the login instead of silently saving. Completes #708. -
Global persistent flags — Helm’s cluster/config flags are now accepted on every command (before or after the subcommand):
--kubeconfig,--kube-context,--kube-apiserver,--registry-config,--repository-config,--repository-cache, and--debug. They are resolved before the application context is built (they configure startup beans) and take precedence over the equivalentjhelm.*properties/env (#708). -
Misc command flags —
package --version/--app-version(rewrites theChart.yamlinside the archive) and-u/--dependency-update;show chart\|values\|readme\|crds\|all--version/--repo/--username/--password+ TLS (show a chart from a repository without a priorpull);lint --quiet/--with-subcharts/--kube-version; andversion --template(Go-templates the version output).show --develremains a documented gap (#687). -
REST releases API now returns Helm-shaped JSON — the
/releaseslist/status/history and install/upgrade responses now use Helm’s-o jsonschema (snake_case, nestedinfo) instead of jhelm’s internal DTO, so REST consumers see the same shape ashelm … -o jsonand the CLI (#686). Breaking: clients reading the old fields must migrate (e.g.statusmoves from$.statusto$.info.status; listchartNamebecomeschart; historyversionbecomesrevision). -
MCP tools return structured JSON —
helm_list,helm_status, andhelm_historynow return Helm-shaped JSON (array of rows / nestedinfoobject) instead of prose text, so agents can parse them directly (#686). -
Install options on the API — the REST install endpoints and the MCP
helm_installtool acceptdescriptionandlabels, mirroring the CLI’s--description/--labels(#686). -
Template render controls on the API — the REST template endpoints and the MCP
helm_templatetool acceptshowOnly,skipTests,includeCrds, andisUpgrade, mirroring the CLI’s--show-only/--skip-tests/--include-crds/--is-upgrade(#686).
3. 1.1.0
The first release to extend beyond Helm parity: a Spring-Boot-style value-management layer — profiles, a Spring Cloud Config Server source, and encrypted secret values — layered on top of the Helm-compatible core. Every addition is opt-in; charts that don’t use these features render byte-for-byte as Go Helm.
3.1. Features
-
Value profiles — keep environment-specific values (dev, staging, prod, …) in one place and activate them at render/install/upgrade time with
-P/--profile, mirroring Spring Boot. Profiles come from----separated documents gated byspring.config.activate.on-profileor fromvalues-<profile>.yamlsidecars, and apply to a chart’s ownvalues.yamland to-ffiles (#670). -
Values from a Spring Cloud Config Server — fetch values from a central, git-backed Spring Cloud Config Server over jhelm’s SSRF-guarded HTTP path, reusing the active profiles for the requested profile and slotting into the override order the way Spring Boot’s config-data model does. Disabled by default (#671).
-
Encrypted values —
{cipher}<hex>secret tokens in any values source are decrypted at render time whenjhelm.encrypt.keyis set, byte-compatible with Spring Cloud Config’s encryption. Ships ajhelm encrypt/jhelm decryptCLI tool and a runnable, securedjhelm-config-server-samplemodule as a DevOps starting point and test fixture. Inert unless a key is configured (#674).
3.2. Fixes
-
jhelm testno longer hangs on a completed pod — terminal pod phases (Succeeded/Failed) are handled instead of being waited on indefinitely (#668). -
Manifests apply/delete as unstructured maps — resources are applied and deleted as unstructured maps rather than typed models, fixing kinds the typed path mishandled (#666).
4. 1.0.2
A maintenance release fixing two bugs found in triage. No public API changes.
4.1. Fixes
-
lookupreturns the full resource and queries the live cluster — thelookuptemplate function now returns the whole object (includingSecret/ConfigMapdataas base64), and is wired to the live Kubernetes API in the CLI and anyjhelm-kube-backed app, as Helm does during install/upgrade. Previously it silently returned the empty stub (and, even when reached, only the resource’s metadata), which regenerated the reuse-existing-password idiomindex $existing.data "key" \| b64decon every upgrade and corrupted bundled-database passwords (#663). -
CLI reports the real build version —
jhelm --version,-V,jhelm versionandjhelm envnow report the actual build version (sourced from Spring Boot build-info, the same source Actuator’s/actuator/infouses) instead of a hardcoded0.0.1. The REST OpenAPI document reports the same (#662).
5. 1.0.1
A maintenance release: bug fixes across the Kubernetes layer and the CLI, plus CLI startup and ergonomics improvements. No public API changes.
5.1. Fixes
-
Cluster-scoped resources — kinds such as
ClusterRole,ClusterRoleBinding,CustomResourceDefinition,Namespace,StorageClassandPriorityClassare now applied and deleted at the cluster scope instead of being forced through the namespaced API path, which the API server rejected (#650). -
CLI exit codes — commands exit non-zero on failure (for example a
--waitreadiness timeout), so scripts and CI can detect a failed operation instead of seeing a spurious success (#647).
5.2. CLI security
-
The CLI now honors
jhelm.security.modeand defaults toFULL(read-write), matchinghelm— the local kubeconfig and cluster RBAC are the trust boundary. Settingjhelm.security.mode=READ_ONLYrefuses the cluster-mutating commands (install,upgrade,uninstall,rollback,test) with a non-zero exit. The API key stays a REST/MCP concern and is not required to unlock the CLI (#653, #654, #657).
5.3. CLI ergonomics
-
Faster startup through lazy bean initialization and trimming auto-configurations a one-shot CLI never uses (#649, #651).
-
Quieted a benign picocli-spring
INFOline ("Unable to get bean of class interface java.util.List …") that surfaced on multi-value options such as--setand read like a stacktrace (#656).
6. 1.0.0
The first stable release. 1.0 draws a supported public API surface, hardens security and
provenance, verifies Helm interoperability against the real helm binary, and makes the
chart-parity claims honest about exactly what is measured.
6.1. Security
-
SSRF controls — an opt-in server-mode block of private / link-local / site-local targets (
jhelm.security.block-private-networks, default off) applied through the repository and OCI HTTP clients and a DNS-resolver guard, so a hosted jhelm cannot be steered at internal addresses. -
Credential and archive hardening — repository credentials are host-gated (not sent on a redirect to a different host), chart un-tar is capped against decompression bombs, OCI reference URLs are validated, and the written registry-credentials file gets owner-only permissions.
6.2. Provenance
-
Key usability checks —
verifynow rejects a revoked or expired signing key, so a retired or compromised provenance key can no longer validate a chart even with an intact signature. -
Clear-sign correctness — OpenPGP dash-escaping (RFC 4880 §7.1) is reversed before verifying, so a
helm/GnuPG-produced.provwhose signed body contains a--leading line verifies correctly.
6.3. Real cluster capabilities
-
.Capabilitiesfrom the cluster —.Capabilities.KubeVersionand.APIVersionsare now populated from the connected cluster forinstall/upgrade;templateaccepts--kube-versionand-a/--api-versionsto pin them offline (defaulting to a fixed Kubernetes version for deterministic rendering).
6.4. Helm interoperability
-
Shared release storage — the release record (including the embedded chart) is now byte-schema-compatible with Helm 3’s
sh.helm.release.v1Secret format, so a release installed by one tool is listable, upgradable, roll-back-able, and removable by the other. Covered by a two-wayhelm↔jhelmintegration suite that runs against a real cluster and the realhelmbinary in CI. See Interoperability with Helm. -
Shared configuration — jhelm honors Helm’s
HELM_*environment variables and reads/writes Helm’s ownrepositories.yamlandregistry/config.jsonat Helm’s locations. See Configuration.
6.5. CLI parity
-
New commands / flags —
repo update;list -o json|yaml;pull --repo <URL>with inline auth/TLS flags;upgrade --force(delete-and-recreate);--dry-run=client|server|nonewith real server-side dry-run and--wait-for-jobs; and an enrichedenvthat reports the effective Helm config locations. -
See the CLI flag parity reference for the full helm ↔ jhelm map.
6.6. REST & MCP
-
OpenAPI —
jhelm-restships a well-documented springdoc OpenAPI document. -
Upgrade value strategy — the upgrade endpoints expose
valueStrategy(DEFAULT/RESET/REUSE/RESET_THEN_REUSE), mirroring the CLI’s value-retention flags.
6.7. API surface & stability
-
Published API surface — a documented, supported public API with a stability statement (Supported API); the
jhelm-kubeservice implementation moved behind an.internalpackage, and theKubernetesProviderSPI plus the 1.0 model mutability contract are documented. -
Metrics — action-layer and chart-pull metrics in
JhelmMetrics.
6.8. Correctness & release quality
-
Honest parity — the chart-parity suite compares against
helm templatewith default values and a pinned--kube-version, byte-for-byte apart from a documented set of non-semantic comparison-ignores; over-emitting a resourcehelmdoes not is now a hard test failure rather than a warning. The docs state precisely what parity does and does not cover. -
Packaging — the CLI fat-jar is excluded from the Maven Central bundle; Javadoc doclint is enforced on build.
7. 0.4.0
The pre-1.0 API freeze release, plus an MCP server, a REST library/starter split, and the
upgrade value-handling fixes (including the value-retention flags listed as a known
limitation in 0.2.0).
7.1. API freeze (breaking, pre-1.0)
-
Unchecked exceptions — the action layer and
KubeServicenow throw the uncheckedJhelmExceptionhierarchy instead ofthrows Exception. -
No leaked client types — the kubernetes-client
ApiException/ApiClientare wrapped behindKubeClient, and the BouncyCastle PGP types behindSigningKey/VerificationKeyring. -
Options objects — the action API now takes immutable
InstallOptions,UpgradeOptions,UninstallOptions, andRollbackOptionsobjects instead of long parameter lists. -
Immutable result models —
Release,ReleaseInfo, andMapConfigare now immutable; releasestatusis a typedReleaseStatusenum and the lifecycle phase aLifecyclePhaseenum.
7.2. MCP server
-
jhelm-mcp+jhelm-mcp-starter— a new Model Context Protocol server exposing jhelm operations as tools for AI agents, built on Spring AI 2.0 and mirroring the REST operation set. AREAD_ONLY/FULLaccess mode (jhelm.mcp.mode, defaultREAD_ONLY) gates the cluster-mutating tools.
7.3. REST library/starter split
-
Pure library —
jhelm-restis now a pure library; the newjhelm-rest-startercarries the auto-configuration (Spring-Boot-Admin style). -
Access mode — a
READ_ONLY/FULLmode (jhelm.rest.mode, defaultFULL) gates the cluster-mutating endpoints. Authentication is the embedding application’s responsibility (Spring Security).
7.4. Upgrade value handling
-
User values persisted — user-supplied values are now persisted as the release config, fixing a data-loss bug (and
get values). -
Value-retention flags implemented —
--reset-values,--reuse-values, and--reset-then-reuse-valuesare now implemented. These were listed as a known limitation in0.2.0.
7.5. New flags
-
Value flags —
--setnow type-coerces like Helm (int/bool/null; floats and leading-zero values stay strings), joined by--set-string,--set-file, and--set-json. -
Lifecycle flags —
--no-hooks(install/upgrade/uninstall/rollback),--history-max(release-history pruning, default 10), and--create-namespace.
7.6. Engine
-
Loud render failures — recursive / too-deep template rendering now fails with a
TemplateRenderExceptioninstead of baking anERROR:string into the manifest. -
gotmpl4j 1.1.0 — the engine dependency moves to
gotmpl4j 1.1.0(perf wave: double formatting withoutBigDecimal, cached property accessors, an allocation-free lexer).
8. 0.2.0
Helm template-function conformance improvements, grinding jhelm-gotemplate-helm against
Helm’s own pkg/engine/funcs_test.go suite (the divergence backlog drops from 37 cases to 1).
-
Helm 4 duration helpers — implemented
mustToDuration,durationSeconds,durationMinutes,durationHours,durationDays,durationWeeks,durationMilliseconds,durationMicroseconds,durationNanoseconds,durationRoundTo, anddurationTruncateTo, as faithful ports of Go’stime.Duration(parsing, rounding, andString()formatting). -
fromerror reporting* —fromJson/fromYamlandfromJsonArray/fromYamlArraynow return Helm’smap[Error:<message>]/[<message>]with Go’sjson.Unmarshaltype-mismatch text when handed valid input of the wrong shape, instead of silently returning an empty container. -
toTomltable output — now emits Go BurntSushi-style[table]/headers with the matching key ordering and indentation, instead of Jackson’s dotted keys.
All 346 reference charts continue to render byte-identically to helm template.
8.1. Known limitations
-
The
helm upgradevalue-retention flags (--reset-values,--reuse-values,--reset-then-reuse-values) remain unimplemented. -
One
fromTomlconformance case (a malformed-input syntax error) still differs from Helm in the exact error wording, an inherent difference between the Jackson and Go (BurntSushi) TOML parsers.
9. 0.1.0 — first public prerelease
The first published release of jhelm, on Maven Central (marked pre-release).
-
Helm-faithful rendering — chart templates render byte-for-byte identically to
helm templateacross a CI-enforced suite of 346 real-world charts (Bitnami, Grafana, GitLab, Kubernetes-monitoring, and others). -
Go template engine — the full Go
text/templatelanguage plus Helm’s Sprig function set, provided by the standalone gotmpl4j library (gotmpl4j 0.3.0). Renders absent/nil values as the empty string (missingkey=zero), matching Helm. -
Helm template functions —
include,tpl,required,lookup,toYaml/fromYaml,toJson/fromJson,toToml, and the chart/capabilities/files helpers. -
Chart lifecycle — install, upgrade, rollback, uninstall, list, status, history, test.
-
Repositories & registries — classic HTTP repositories and OCI registries, with digest verification and content-based caching.
-
Dependency management — list, update, and build chart dependencies; recursive value coalescing across subcharts.
-
Packaging & provenance — package charts to
.tgz; PGP sign and verify. -
JSON Schema validation — chart values validated against
values.schema.json(Draft-07). -
Distribution surfaces — embeddable library, Spring Boot starter (auto-configured action beans), REST API (
jhelm-rest, with OpenAPI docs), Maven packaging plugin (jhelm-plugin), and a 22-command CLI. -
Built on Java 21, Spring Boot 4.0.7, Kubernetes Client 26.0.0, Picocli 4.7.7.
9.1. Known limitations
The following are out of scope for this first prerelease and are planned for 0.2.0:
-
helm upgradevalue-retention flags —--reset-values,--reuse-values, and--reset-then-reuse-valuesare not yet implemented.upgradeapplies the chart defaults merged with the values you pass on the command line. -
Helm function fidelity — a small number of functions have documented partial-fidelity behaviour: the Helm 4 duration helpers, the
fromYaml/fromJsonerror-map format, and nestedtoTomltables. See Function Coverage. -
Subchart value coalescing — deeply-nested umbrella charts (GitLab-scale) may differ from Helm in rare value-coalesce edge cases; the common cases render byte-identically (the 346-chart parity suite).