Skip to content

Releases: haproxy-haptic/HAPTIC

v0.10.0

Choose a tag to compare

@github-actions github-actions released this 02 Nov 13:22
d231c96

[0.10.0] - 2026-11-02

Added

  • fileRegistry.Register("secret", …) delivers a file to sidecars under spec.dataplane.secretsDir (default /etc/haproxy/secrets) without a reload. Its content is published only as a Kubernetes Secret, readable resources carry a keyed digest instead of a content digest, and the secret:<name> validation test target asserts on it.
  • haptic preflight --resources <path> and --resources-from-cluster also render the configuration against the resources the controller will watch and run haproxy -c on the result (#586).

Fixed

  • A map or file whose template reads a watched resource directly (such as with GetSingle) or fetches over HTTP now picks up changes to that input after a render reused its previous output; before, it could keep stale content indefinitely (#604).
  • A render no longer panics when a template imports a snippet exporting a var function both directly and from inside a macro; the snippet now initializes at whichever import runs first (#585).
  • After a release was only partly applied, the pre-rollout hook failed every later sync or upgrade with "finish the current apply before upgrading". It now validates the incoming release and applies it, which completes the partial one (#559).

Helm chart

Added

  • Gateway API v1.7.0 support, including its sessionPersistence shape; sessionPersistence.cookie.path sets the cookie's Path.
  • A secret-storage tmpfs volume at /etc/haproxy/secrets, mounted in the agent and SPOA hub containers but not in the HAProxy container.
  • haproxy-haptic.org/sso-auth signs users in with OpenID Connect through the SPOA hub's sso-auth plugin, using a provider Secret in the Ingress's namespace; sso-auth-allowed-groups admits only members of the listed groups, and pass-token forwards the ID or access token as Authorization: Bearer and refreshes it (#548).
  • controller.config.templatingSettings.extraContext.ssoAuth.allowedIssuers lists the identity providers sso-auth provider Secrets may use.
  • Governance rules take a label selector to apply only to matching resources, and defaultFrom to pick a default by a value of the resource such as its hosts (#582).
  • haproxy-haptic.org/error-pages names a ConfigMap whose pages replace the 401, 403, 413, and 429 HAProxy sends when it refuses a request and the 500, 502, 503, and 504 it generates for the Ingress's backends, as a static file or an lf-file limited to operator-allowed expressions (#571, #577, #578).
  • controller.config.templatingSettings.extraContext.customResponses.defaultErrorPages names a ConfigMap whose error pages apply to every Ingress; an Ingress's own error-pages override it per status code (#583).
  • controller.config.templatingSettings.extraContext.tls.requireSniHostMatch and the haproxy-haptic.org/require-sni-host-match annotation answer 421 when an HTTPS request's Host differs from its TLS SNI (#567).
  • vector.requestMetrics.serverLabel: counters adds the server label to requests_total only, keeping it off the histograms (#564).

Changed

  • The CRDs moved from crds/ to the haptic-crds subchart (charts/haptic-crds/crds/), which keeps them out of the Helm release Secret; Helm still installs them, and the apply-crds hook still upgrades them (#588).
  • Update the bundled Vector image to 0.61.0.
  • The controller requests 500m CPU instead of 100m, so its startup validation finishes within the startup probe on a busy node (#570).

Fixed

  • Restart the controllers when the SPOA hub plugin set changes, so their validator stops rejecting configurations that use a newly enabled plugin (#546).
  • The oauth annotations of the HAPTIC and haproxy-ingress libraries send the request's path and query as rd to oauth2-proxy's sign-in instead of the literal %[path]; a trailing $escaped_request_uri in any auth-signin URL is expanded the same way (#550).
  • The oauth annotations no longer apply external authentication to the Ingress's own oauth2-proxy path, which redirected browsers in a loop (#551).
  • The vector and spoa-hub sidecar health checks no longer trigger Falco's "Redirect STDOUT/STDIN to Network Connection in Container" rule every few seconds (#555).
  • Source allow-lists and deny-lists of every annotation family are enforced before the SPOA hub, so a refused client is denied before WAF, external authentication or OIDC sign-in (#568).

Security

  • Plain HTTP to an Ingress that requires a client certificate is redirected to HTTPS instead of being served without verification; only ACME HTTP-01 challenge requests stay on HTTP.

v0.9.0

Choose a tag to compare

@github-actions github-actions released this 30 Oct 22:02
02986e7

[0.9.0] - 2026-10-30

HAPTIC 0.9 pins release charts to signed image digests, splits the Grafana
dashboard into controller and traffic views, and fixes request-metric data loss
in the Vector sidecar.

Before upgrading: if you install from an image mirror, check that it keeps
the original image index. Read the
upgrade notes.

Helm chart

Added

  • Optional vector.requestMetrics.serverLabel identifies the selected upstream server in request counters and duration histograms (#533).

Changed

  • Published release charts select matching multi-platform controller image digests by default, including agents and lifecycle hooks; explicit image tags and digests retain precedence (#527).
  • The built-in Grafana dashboard is split into controller and traffic dashboards, adding route, status, termination-state, latency, throughput, and backend-target panels. The haptic.json ConfigMap key and haptic UID remain the controller view; haptic-traffic.json and UID haptic-traffic are new.
  • Request counters use the conventional _requests_total name; the unsuffixed counter remains as a compatibility alias (#531).

Fixed

  • Prometheus no longer drops Vector request metrics as out-of-order samples: the exporters omit sample timestamps (#537).
  • Vector keeps request histogram counts when a configuration reload changes the metric pipeline inputs (#532).
  • Vector forwards newline-terminated access logs without extra blank stdout records (#534).
  • Grafana panels read registered configuration-validation outcomes and observability-drop counts instead of an absent histogram and an event-dependent subscriber series (#530).

v0.8.1

Choose a tag to compare

@github-actions github-actions released this 29 Oct 01:06
01b586a

[0.8.1] - 2026-10-29

Fixed

  • Identical configuration updates no longer discard passing validation results or restart retry backoff, avoiding redundant tests and false timeout rejections (#522).

Known issues

  • An intermittent HTTPRouteRequestMirror conformance failure remains under investigation: affected runs did not observe mirrored requests in backend logs (#517).

v0.8.0

Choose a tag to compare

@github-actions github-actions released this 28 Oct 14:12
b586bd7

[0.8.0] - 2026-10-28

HAPTIC 0.8 adds client-certificate identity checks and headers for Ingress,
and serves TLSRoute termination and passthrough listeners on the same port.
It also closes Ingress client-certificate verification bypasses and tightens
trust of client-address headers.

Before upgrading: if you use src-ip-header, check which proxies may set
that header. Routes protected by client-certificate verification now enforce it
when using the default TLS certificate too. Read the
upgrade notes.

Added

  • validationTests.<name>.useDeploymentWatchScopes checks fixtures against configured watch namespaces, including expected out-of-scope lookup rejections in haptic preflight.

Fixed

  • Validation tests no longer reject deterministic auxiliary files because their generated section markers change between renders.

Security

  • Build with Go 1.27.3 to reject compromised intermediate certificates in TLS verification (CVE-2026-111943).
  • Update golang.org/x/net to 0.62.0 for HTML parsing and rendering security fixes (#519).

Helm chart

Added

  • Serve TLSRoute termination and passthrough listeners on one port with isolated certificates and client-validation policies.
  • haproxy-haptic.org/auth-tls-match-subject limits a host to client certificates whose subject DN matches a regular expression.
  • haproxy-haptic.org/auth-tls-cn-header forwards the verified client certificate's CN in a request header you name, such as X-Scope-OrgID.
  • Pin controller, agent, and lifecycle hook images with controller.image.digest.

Changed

  • BREAKING: src-ip-header no longer trusts client-sent X-Real-IP, X-Client-IP, or Client-IP by itself. List the L7 proxy in forwardedHeaders.trustedProxies or produce the header in an operator snippet; L4 PROXY-protocol client addresses need no header annotation.
  • Update the bundled Vector image to 0.60.0.

Fixed

  • Forward Ingress client-certificate headers on resumed TLS sessions and when annotation libraries coexist.
  • HTTPRoute hostname specificity takes precedence over path length and header conditions when routes intersect the same listener hostname.
  • Keep TLS passthrough listener isolation on the shared HTTPS address after routes are removed or listener modes change; unmatched Gateway names still reach Ingress routes.

Security

  • Enforce Ingress client-certificate verification with default TLS certificates, including when the certificate names the protected host.
  • Reject requests to a client-certificate-protected Ingress with 421 when TLS SNI names another host or is absent, instead of bypassing verification.
  • Drop untrusted client-sent Forwarded, X-Forwarded-Prefix, X-Forwarded-Server, X-Real-IP, X-Client-IP, and Client-IP headers, while preserving trusted proxies and operator header changes (#490).

Known issues

  • An intermittent HTTPRouteRequestMirror conformance failure remains under investigation: affected runs did not observe mirrored requests in backend logs (#517).

v0.7.0

Choose a tag to compare

@github-actions github-actions released this 20 Oct 21:32
8387dce

[0.7.0] - 2026-10-20

HAPTIC 0.7 hardens two trust boundaries: raw HAProxy configuration annotations,
which let an Ingress writer change the configuration for every host, need an
explicit opt-in, and every HTTP frontend replaces client-sent forwarded headers,
so clients can't forge their address. Chart upgrades roll the controller to the
new image before applying new templates.

Before upgrading: check your Ingresses for raw configuration annotations and
haproxy-ingress.github.io/forwardfor, and list any L7 proxies in front of
HAPTIC. Read the upgrade notes.

Added

  • watchedResources.<name>.namespaces restricts watches and template lookups to listed namespaces; namespacesSetting identifies the setting in rejection messages.
  • Metrics:
    • haptic_config_validated{status,reason}: each replica's Validated condition, one series per state, so an alert can match a configuration stuck at Unknown or False.
    • haptic_config_validation_total{result}: valid, invalid, and inconclusive verdicts on the HAProxyTemplateConfig, the startup load gate included. haptic_validation_errors_total counts only HAProxy's verdicts on rendered configurations.
  • on_own_lines(render_glob "prefix-*") template function: renders the matching snippets so that each starts on a new line.

Changed

  • haptic_render_total and haptic_render_errors_total export every cache_state at zero, and haptic_config_rejected_total every validator, so increase() and the HAProxyControllerConfigRejected alert see the first failure.
  • A change to a server's maxconn is applied with HAProxy's runtime API instead of a reload.
  • The controller logs Reload required at INFO with the pod and the reasons whenever it reloads a pod, instead of only at DEBUG.

Fixed

  • haptic preflight validates sidecar configurations even when a restrictive umask would prevent the container user from reading temporary files.
  • When an upgrade adds runtime operations, older agents still apply supported runtime changes without a reload.
  • Frequent per-pod status writes no longer block publication of a changed HAProxyCfg with resource-version conflicts.
  • An unchanged successful render-gate verdict no longer rewrites HAProxyCfg status on every render.
  • A change to the credentials Secret that leaves dataplane_username and dataplane_password unchanged, such as every Helm upgrade, no longer restarts the controller iteration, which briefly doubled controller memory and could OOMKill large installs (#456).
  • A controller container restarted during its startup validation no longer fails every validationTest with no space left on device. Each test's scratch files are removed when it finishes, instead of when the whole suite does.
  • A controller could stop deploying, leaving HAProxy pods unready, when the render gate's verdict reached the deployment scheduler before the render it named. Each component now receives an event before any reaction to it.
  • A configuration change on a large install no longer hands leadership to a replica with a cold render graph while the warm-up render is still running, which delayed deployments until the new leader rendered from scratch.
  • Deployments no longer contend with leader Lease renewals or log spurious Failed to update lease errors.
  • A new leader preserves the latest configuration validation verdict instead of reporting an older accepted configuration as valid over a newer rejected or unvalidated generation.
  • Configuration changes fetch watched-resource schemas in parallel, and API discovery timeouts leave validation inconclusive and retry it instead of rejecting templates that use typed fields.
  • Admission denials show the governance rule's message and the watched object; other render errors identify the watched object without exposing encoded cache keys.
  • Startup-validation messages describe retrying NotReady pods and stalled rollouts instead of claiming the controller exits on rejection.
  • A deployment cancelled because the HAProxy pod set changed no longer logs context canceled errors, emits ApplyFailed Pod events, or counts in haptic_deployment_errors_total (#430).
  • Expected events log at INFO instead of WARN: config publisher API calls cancelled by its own shutdown, the wait for the render gate's first verdict after a start or configuration change, and a leader drained during a configuration hand-over (#444, #445, #453).

Helm chart

Added

  • extraContext.forwardedHeaders.trustedProxies: the L7 load balancers whose X-Forwarded-For, -Proto, -Host, and -Port headers HAPTIC keeps.
  • controller.rbac.releaseNamespaceSecretsOnly limits Secret reads to the release namespace and rejects references elsewhere.
  • A watched resource that lists namespaces is granted by a Role in each listed namespace instead of the ClusterRole.
  • HAProxyControllerConfigNotValidated alert (controller.monitoring.prometheusRule.defaultRules.configNotValidated): a replica hasn't validated its newest HAProxyTemplateConfig for 10 minutes.

Changed

  • The pre-upgrade hook rolls the controller Deployment to the new image before Helm applies new templates, so old replicas no longer reject a valid incoming configuration. See controller preparation for custom image tags and deployments without hooks.
  • BREAKING: haproxy-ingress: haproxy-ingress.github.io/forwardfor: add replaces the client's X-Forwarded-For and update appends to it, as upstream does; HAPTIC had them the other way round. Check your Ingresses before upgrading.
  • An Ingress that sets X-Forwarded-For handling through annotations from two families is rejected at admission, like other mixed-family features.
  • A helm upgrade that changes only the chart version no longer changes the HAProxyTemplateConfig, so running controllers don't start a new iteration mid-rollout. The controller-managed HAProxy Service drops its helm.sh/chart, app.kubernetes.io/version, and app.kubernetes.io/managed-by labels.
  • Controller pods no longer carry the helm.sh/chart and app.kubernetes.io/version labels; the Deployment keeps them. A chart upgrade then rolls the controllers once instead of twice; the upgrade to 0.7.0 itself still rolls them twice (#467).

Fixed

  • Preflight compiles Varnish configurations with the deployed image when caching is enabled and a released fixture image when it is disabled.
  • Custom TCP frontends that accept PROXY protocol pass validation when the built-in HTTP/HTTPS PROXY listeners are disabled.
  • haproxy.org/pod-maxconn and haproxy-haptic.org/pod-maxconn set maxconn on each server line, so a change in the ready HAProxy pod count (for example during a rollout) updates it at runtime instead of reloading every HAProxy pod (#474).
  • haproxy-haptic.org/forwardfor and haproxy-ingress.github.io/forwardfor: add and update no longer send the client address twice, and ifmissing and ignore no longer append it to the client's header.
  • haproxytech: haproxy.org/forwarded-for: "false" forwards the client's X-Forwarded-For unchanged; it was ignored.
  • A snippet at an extension point starts on its own line whether or not its template begins or ends with a newline. A frontend-extra-* or other snippet without a leading newline could join the previous line and fail validation.

Security

  • BREAKING: Raw HAProxy configuration annotations (haproxy-haptic.org/config-*, haproxy-ingress.github.io/config-*, haproxy.org/backend-config-snippet, and nginx.ingress.kubernetes.io/configuration-snippet) are rejected unless controller.config.templatingSettings.extraContext.ingressPermissions.allowRawHAProxyConfig is true. Any Ingress writer in a watched namespace could otherwise change the configuration for every host or read HAProxy's TLS keys. waf.ingressPermissions.allowRawHAProxyConfig can only narrow it. Check your Ingresses before upgrading.
  • WAF governance's allowRawHAProxyConfig: false also rejects raw configuration annotations when the hapticAnnotations library is disabled.
  • BREAKING: Every HTTP frontend replaces a client-sent X-Forwarded-For with the client address, sets X-Forwarded-Proto to https or http, and drops a client-sent X-Forwarded-Host and X-Forwarded-Port, so clients can't forge their address or scheme (#406). X-Forwarded-Host, -Port, and -Proto set by frontend-extra-* snippets are kept. Behind an L7 load balancer, list it in trustedProxies; trustedProxies: ["0.0.0.0/0", "::/0"] restores the old X-Forwarded-For handling.

v0.6.0

Choose a tag to compare

@github-actions github-actions released this 18 Oct 06:39
aac42ed

[0.6.0] - 2026-10-18

HAPTIC 0.6 moves to GitHub, requires Kubernetes 1.35 or newer, and drops
HAProxy 3.1. It ships security updates for Go, HAProxy, and the bundled Coraza
WAF plugin, and makes retained recovery hold up through ordinary leader changes
and critical http.Fetch outages.

Before upgrading: check your Kubernetes version, move off HAProxy 3.1, and
remove any registry.gitlab.com image overrides. Read the
upgrade notes.

Added

  • Metrics:
    • haptic_render_errors_total: failed reconcile renders on every replica, by cache state.
    • haptic_haproxy_checks_total and haptic_haproxy_checks_reused_total: haproxy -c runs per validator and result on every replica, and the runs answered by an identical input's verdict instead.
    • haptic_admission_render_slot_wait_seconds: how long admission dry runs queue for a render slot.
  • Select several validation tests in one run by repeating haptic validate --test.
  • MUTEX_PROFILE_FRACTION and BLOCK_PROFILE_RATE enable the mutex and block profiles on /debug/pprof.

Changed

  • BREAKING: The Go module path is now github.com/haproxy-haptic/HAPTIC (was gitlab.com/haproxy-haptic/haptic). Programs that import HAPTIC packages must update their import paths.
  • Development, issues, releases, and container images moved to GitHub: github.com/haproxy-haptic/HAPTIC and ghcr.io/haproxy-haptic. Releases up to 0.5.0 are available there with their original digests and signatures.
  • Reconciliation CPU and latency no longer grow with the size of the watched set: input isolation inspects only the resources changed since its last capture.
  • The leader runs haproxy -c once per render instead of twice: the render gate reuses the verdict input acceptance just gave the identical config and files.
  • Recovery checkpoints share unchanged auxiliary files instead of copying every map, file, and certificate Secret, and publications read auxiliary files with one list per kind. Steady deployment churn no longer creates a full object set per checkpoint, and most of the controller's API requests are gone.
  • Drift prevention no longer re-applies every HAProxy pod's unchanged status to the HAProxyCfg and each auxiliary file every interval: it reads them live and corrects only entries that changed. On an idle fleet this removes about two thirds of the controller's API requests.
  • Startup validation may use 80% of the controller's startup probe window (240 seconds by default) instead of a fixed 120 seconds, so a large validation-test suite on a small node no longer crash-loops the controller.
  • Failed renders count in haptic_render_total, and failed reconciliations in haptic_reconciliation_duration_seconds. A follower warns when its renders start failing.
  • haptic_webhook_request_duration_seconds buckets extend to 30 seconds, so latencies near the admission timeout are measurable.
  • Validation test totals and results are logged at INFO.
  • Fewer allocations during input isolation, validation, and rendering.

Fixed

  • Retained recovery:
    • A leader that stops gracefully finishes its deployment in progress, including a pending HAProxy reload, and saves its recovery checkpoint before it releases the Lease. Previously, after an ordinary leader change, replacement HAProxy pods could stay NotReady with RetainedConfigUnavailable while rendering was blocked.
    • A verified /v1/state read that overlapped an apply could restore the dataplane agent's previous file set, so the pod reported disk_is_the_desired_set until it restarted and new pods could not recover from the checkpoint.
    • Recovery starts after leader failover when a critical HTTP source is unavailable, including with large watched sets.
    • Pruned checkpoints are recreated when their configuration is deployed again, and retained configurations no longer exceed the storage limit once recovery plans are included.
  • Critical http.Fetch outages: a replica without the source's content no longer renders, or re-reads every watched resource, on every change. It refetches the source every interval (30 seconds by default) and renders when the source answers.
  • A standby replica that became leader after more than 1.5 × driftPreventionInterval failed liveness until it deployed, so the kubelet restarted it, for example while a critical http.Fetch source was down.
  • An idle drift-prevention round no longer resends and rewrites every file on every HAProxy pod: the dataplane agent's verified read keeps a file's proof while the file still has the bytes, mode, and owner the agent wrote.
  • Valid changes are no longer denied with a timeout during heavy resource churn: a CPU stays free for each admission render.
  • A schema fetch timeout no longer rejects a valid HAProxyTemplateConfig change for good: it shows Validated=Unknown (ValidationInconclusive) and is validated again with backoff. Schema reads fetch only the watched CRDs.
  • A configuration that fails haproxy -c or rendering independently of watched resources is reported after two checks at startup instead of one per watched object.
  • A cold render cancelled while a template published a shared value no longer deadlocks the replica's first render, which left admission denied.
  • Shared rate limiting no longer falls back to per-pod budgets for 5 seconds after one slow store reply (rate-limit plugin v0.4.2).
  • The dataplane agent no longer reports ready before its admin and drain sockets exist, and no longer stalls 30 seconds when HAProxy is still starting its worker.
  • /livez and /readyz say why a component is unhealthy.
  • Auxiliary-file deployedToPods entries name only the pods that run each file. A pod's entry no longer goes missing until the next drift check when its status lands before or while its configuration is published, and no longer lands on the previous configuration's files.
  • Queued events no longer delay controller shutdown.
  • The playground escapes quotes in resource, annotation, and template names, so a shared link cannot inject HTML attributes.
  • A new leader deploys a critical http.Fetch source's first content as soon as its replica accepts it. Previously, if the content was accepted just after the leader's first render, HAProxy pods stayed NotReady until the next drift-prevention round (60 seconds by default), for example right after the controller started.

Security

  • Go 1.27.2 and its HTTP/2 dependency fix HTTP, TLS, and filesystem vulnerabilities.
  • HAProxy 3.0.30, 3.2.26, 3.3.17, and 3.4.7 fix HTTP/2 PING frame handling and an over-long HTTP/1 chunk-size line, both marked major upstream.
  • The bundled Coraza SPOA plugin v0.10.1 is built against Coraza v3.8.1 and fixes WAF bypass and crash vulnerabilities (GHSA-6gcq-wc29-5xf2, GHSA-6r3q-mjv7-xr8m, and ten Medium advisories). It also stops a memory leak when the validator rechecks an invalid WAF policy.

Helm chart

Added

  • Opt-in Pod readiness gate haproxy-haptic.org/load-balancer-ready (controller.templateLibraries.kubernetesBackends.podReadinessGate.enabled): a gated pod becomes Ready only once every HAProxy pod routes to it, so single-replica rollouts drop no requests.

Changed

  • BREAKING: The chart requires Kubernetes 1.35 or newer; 1.33 is past its upstream end of life and 1.34 reaches it on 2026-10-27. Check your cluster version before upgrading.
  • BREAKING: HAProxy 3.1 is no longer supported: it is past its upstream end of life and misses the 2026-10-14 HTTP/1 and HTTP/2 fixes. Helm rejects haproxyVersion: "3.1"; switch to 3.2 or 3.4 before upgrading.
  • Default controller, SPOA hub, and Varnish images come from ghcr.io/haproxy-haptic/haptic, and the chart is published at oci://ghcr.io/haproxy-haptic/haptic/charts/haptic; its home and sources links point to GitHub.
  • Render the Helm chart faster by avoiding repeated YAML serialization of template libraries.
  • Default controller, SPOA hub, and Varnish images come from ghcr.io/haproxy-haptic/haptic, and the chart is published at oci://ghcr.io/haproxy-haptic/haptic/charts/haptic.
  • The chart renders faster.

Fixed

  • The controller NetworkPolicy accepts webhook calls from any source by default. Its 0.0.0.0/0 and ::/0 rules don't match node traffic on Cilium, so admission calls from other nodes timed out. controller.networkPolicy.ingress.webhook.from still restricts the webhook port when set.
  • With several releases in one cluster, each release's Ingress and Gateway status listed every release's load balancer addresses, so external-dns published names with other releases' IPs. Each controller now watches only its own release's load balancer Services.
  • TLS Gateways use isolated service addresses and pod ports, so they can't route to another Gateway's TLSRoutes.
  • Gateway API: TLSRoutes keep their hostname specificity after listener intersection, with older routes winning ties.
  • Pre-rollout validation and the load gate no longer fail with vector.enabled=false, vector.requestMetrics features off, spoaHub.enabled=false, or the mirror plugin off.
  • haproxy-ingress: an Ingress with haproxy-ingress.github.io/waf or waf-mode fails the render when spoaHub.enabled=false instead of being served without WAF inspection.
  • nginx-ingress: nginx.ingress.kubernetes.io/enable-modsecurity: "true" sends the route to the Coraza WAF in detect mode, like ingress-nginx's default; it was ignored.

v0.6.0-rc.2

v0.6.0-rc.2 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 17 Oct 16:51
4d1583f

[0.6.0-rc.2] - 2026-10-17

HAPTIC 0.6 moves to GitHub, requires Kubernetes 1.35 or newer, and drops
HAProxy 3.1. It ships security updates for Go, HAProxy, and the bundled Coraza
WAF plugin, and makes retained recovery hold up through ordinary leader changes
and critical http.Fetch outages.

Before upgrading: check your Kubernetes version, move off HAProxy 3.1, and
remove any registry.gitlab.com image overrides. Read the
upgrade notes.

Added

  • Metrics:
    • haptic_render_errors_total: failed reconcile renders on every replica, by cache state.
    • haptic_haproxy_checks_total and haptic_haproxy_checks_reused_total: haproxy -c runs per validator and result on every replica, and the runs answered by an identical input's verdict instead.
    • haptic_admission_render_slot_wait_seconds: how long admission dry runs queue for a render slot.
  • Select several validation tests in one run by repeating haptic validate --test.
  • MUTEX_PROFILE_FRACTION and BLOCK_PROFILE_RATE enable the mutex and block profiles on /debug/pprof.

Changed

  • BREAKING: The Go module path is now github.com/haproxy-haptic/HAPTIC (was gitlab.com/haproxy-haptic/haptic). Programs that import HAPTIC packages must update their import paths.
  • Development, issues, releases, and container images moved to GitHub: github.com/haproxy-haptic/HAPTIC and ghcr.io/haproxy-haptic. Releases up to 0.5.0 are available there with their original digests and signatures.
  • Reconciliation CPU and latency no longer grow with the size of the watched set: input isolation inspects only the resources changed since its last capture.
  • The leader runs haproxy -c once per render instead of twice: the render gate reuses the verdict input acceptance just gave the identical config and files.
  • Recovery checkpoints share unchanged auxiliary files instead of copying every map, file, and certificate Secret, and publications read auxiliary files with one list per kind. Steady deployment churn no longer creates a full object set per checkpoint, and most of the controller's API requests are gone.
  • Drift prevention no longer re-applies every HAProxy pod's unchanged status to the HAProxyCfg and each auxiliary file every interval: it reads them live and corrects only entries that changed. On an idle fleet this removes about two thirds of the controller's API requests.
  • Startup validation may use 80% of the controller's startup probe window (240 seconds by default) instead of a fixed 120 seconds, so a large validation-test suite on a small node no longer crash-loops the controller.
  • Failed renders count in haptic_render_total, and failed reconciliations in haptic_reconciliation_duration_seconds. A follower warns when its renders start failing.
  • haptic_webhook_request_duration_seconds buckets extend to 30 seconds, so latencies near the admission timeout are measurable.
  • Validation test totals and results are logged at INFO.
  • Fewer allocations during input isolation, validation, and rendering.

Fixed

  • Retained recovery:
    • A leader that stops gracefully finishes its deployment in progress, including a pending HAProxy reload, and saves its recovery checkpoint before it releases the Lease. Previously, after an ordinary leader change, replacement HAProxy pods could stay NotReady with RetainedConfigUnavailable while rendering was blocked.
    • A verified /v1/state read that overlapped an apply could restore the dataplane agent's previous file set, so the pod reported disk_is_the_desired_set until it restarted and new pods could not recover from the checkpoint.
    • Recovery starts after leader failover when a critical HTTP source is unavailable, including with large watched sets.
    • Pruned checkpoints are recreated when their configuration is deployed again, and retained configurations no longer exceed the storage limit once recovery plans are included.
  • Critical http.Fetch outages: a replica without the source's content no longer renders, or re-reads every watched resource, on every change. It refetches the source every interval (30 seconds by default) and renders when the source answers.
  • A standby replica that became leader after more than 1.5 × driftPreventionInterval failed liveness until it deployed, so the kubelet restarted it, for example while a critical http.Fetch source was down.
  • An idle drift-prevention round no longer resends and rewrites every file on every HAProxy pod: the dataplane agent's verified read keeps a file's proof while the file still has the bytes, mode, and owner the agent wrote.
  • Valid changes are no longer denied with a timeout during heavy resource churn: a CPU stays free for each admission render.
  • A schema fetch timeout no longer rejects a valid HAProxyTemplateConfig change for good: it shows Validated=Unknown (ValidationInconclusive) and is validated again with backoff. Schema reads fetch only the watched CRDs.
  • A configuration that fails haproxy -c or rendering independently of watched resources is reported after two checks at startup instead of one per watched object.
  • A cold render cancelled while a template published a shared value no longer deadlocks the replica's first render, which left admission denied.
  • Shared rate limiting no longer falls back to per-pod budgets for 5 seconds after one slow store reply (rate-limit plugin v0.4.2).
  • The dataplane agent no longer reports ready before its admin and drain sockets exist, and no longer stalls 30 seconds when HAProxy is still starting its worker.
  • /livez and /readyz say why a component is unhealthy.
  • A pod's deployedToPods entry no longer goes missing from the auxiliary-file resources until the next drift check when its status lands while the HAProxyCfg is being published.
  • Queued events no longer delay controller shutdown.
  • The playground escapes quotes in resource, annotation, and template names, so a shared link cannot inject HTML attributes.

Security

  • Go 1.27.2 and its HTTP/2 dependency fix HTTP, TLS, and filesystem vulnerabilities.
  • HAProxy 3.0.30, 3.2.26, 3.3.17, and 3.4.7 fix HTTP/2 PING frame handling and an over-long HTTP/1 chunk-size line, both marked major upstream.
  • The bundled Coraza SPOA plugin v0.10.1 is built against Coraza v3.8.1 and fixes WAF bypass and crash vulnerabilities (GHSA-6gcq-wc29-5xf2, GHSA-6r3q-mjv7-xr8m, and ten Medium advisories). It also stops a memory leak when the validator rechecks an invalid WAF policy.

Helm chart

Added

  • Opt-in Pod readiness gate haproxy-haptic.org/load-balancer-ready (controller.templateLibraries.kubernetesBackends.podReadinessGate.enabled): a gated pod becomes Ready only once every HAProxy pod routes to it, so single-replica rollouts drop no requests.

Changed

  • BREAKING: The chart requires Kubernetes 1.35 or newer; 1.33 is past its upstream end of life and 1.34 reaches it on 2026-10-27. Check your cluster version before upgrading.
  • BREAKING: HAProxy 3.1 is no longer supported: it is past its upstream end of life and misses the 2026-10-14 HTTP/1 and HTTP/2 fixes. Helm rejects haproxyVersion: "3.1"; switch to 3.2 or 3.4 before upgrading.
  • Default controller, SPOA hub, and Varnish images come from ghcr.io/haproxy-haptic/haptic, and the chart is published at oci://ghcr.io/haproxy-haptic/haptic/charts/haptic; its home and sources links point to GitHub.
  • Render the Helm chart faster by avoiding repeated YAML serialization of template libraries.
  • Default controller, SPOA hub, and Varnish images come from ghcr.io/haproxy-haptic/haptic, and the chart is published at oci://ghcr.io/haproxy-haptic/haptic/charts/haptic.
  • The chart renders faster.

Fixed

  • The controller NetworkPolicy accepts webhook calls from any source by default. Its 0.0.0.0/0 and ::/0 rules don't match node traffic on Cilium, so admission calls from other nodes timed out. controller.networkPolicy.ingress.webhook.from still restricts the webhook port when set.
  • With several releases in one cluster, each release's Ingress and Gateway status listed every release's load balancer addresses, so external-dns published names with other releases' IPs. Each controller now watches only its own release's load balancer Services.
  • TLS Gateways use isolated service addresses and pod ports, so they can't route to another Gateway's TLSRoutes.
  • Gateway API: TLSRoutes keep their hostname specificity after listener intersection, with older routes winning ties.
  • Pre-rollout validation and the load gate no longer fail with vector.enabled=false, vector.requestMetrics features off, spoaHub.enabled=false, or the mirror plugin off.
  • haproxy-ingress: an Ingress with haproxy-ingress.github.io/waf or waf-mode fails the render when spoaHub.enabled=false instead of being served without WAF inspection.
  • nginx-ingress: nginx.ingress.kubernetes.io/enable-modsecurity: "true" sends the route to the Coraza WAF in detect mode, like ingress-nginx's default; it was ignored.

Website publication archives

Pre-release

Choose a tag to compare

@github-actions github-actions released this 14 Oct 20:54
ff22ec0

Verified website content. The website-state branch records the published version catalog.

Website migration baseline, 13 October 2026

Choose a tag to compare

@phihos phihos released this 13 Oct 22:30
64e56a7

Complete static-site baseline for migrating haproxy-haptic.org to GitHub Pages.

The archive contains 4,196 files, all eight retained playground engines, and a manifest recording file checksums and source provenance. It restores 1,319,394,736 bytes. The GitHub Pages packaging step retains Brotli engine copies and verifies their decoded bytes against this baseline.

The source export was assembled during migration verification run 38424077823, including historical engines restored from the published site. This baseline is independent of Actions artifact retention.

Archive SHA-256: f9848bc4526524fafae16dc83ca990f55584265c85d0878e0d57de768cbc5422.

v0.5.0

Choose a tag to compare

@phihos phihos released this 14 Oct 16:41

[0.5.0] - 2026-10-08

HAPTIC 0.5 can restore HAProxy capacity during a controller restart or leader
change even when rendering is blocked. New pods load a retained, acknowledged
configuration after ownership, freshness, and current-HAProxy validation checks.

Before upgrading: retained recovery needs a successful deployment by a 0.5
controller before it can protect replacement pods. Read the
upgrade notes for this requirement
and the limits of serving retained endpoint lists.

Added

  • New HAProxy pods can load an acknowledged configuration retained in Kubernetes when a fresh leader cannot render, with current-binary validation, Warning events, and haptic_retained_config_active.
  • /healthz includes the last render failure without changing startup, readiness, or liveness decisions.

Fixed

  • Reduce controller startup time and temporary allocations while preserving every validation check and the existing memory budget.
  • Endpoint updates and admission requests no longer wait for each other's HAProxy validation checks.
  • Prevent repeated status writes across reconciliation phases from making valid Kubernetes updates time out.
  • Verified agent-state reads no longer race HAProxy reloads and invalidate the confirmed worker configuration.

Helm chart

Added

  • The bundled PrometheusRule alerts when a controller uses retained configuration while rendering is blocked.

Fixed

  • Gateway API: catch-all GRPCRoutes select the most specific hostname even when a broader route is older or its name sorts first.