feat(helm): add Helm chart for Kubernetes deployment #520

Merged
fuzzy merged 1 commit from feat/helm-chart into main 2026-08-04 10:06:29 +00:00
Owner

What

Add a Helm chart at deploy/charts/thwap-pagesd to deploy the daemon on Kubernetes:

  • Configurable replicas, resources, ingress (#113)replicaCount, container CPU/memory resources, liveness/readiness probes on /healthz and /readyz, node selector/tolerations/affinity, an optional HPA, and an optional Ingress with configurable className/annotations/hosts/tls.
  • Environment variables and secrets management (#114) — every runtime setting is injected as a THWAP_PAGESD_* environment variable: non-secret values via a ConfigMap consumed with envFrom, and the Forgejo token plus webhook secret via a Secret consumed with secretKeyRef. Secrets can be generated from values or referenced as an existing existingSecret.
  • RBAC — namespace-scoped Role/RoleBinding granting the daemon's ServiceAccount access to the ConfigMaps, PVCs, Services, Deployments, and Ingresses it manages (least privilege).
  • Security — hardened pod/container security contexts matching the Dockerfile's non-root thwap user (uid 100): runAsNonRoot, allowPrivilegeEscalation: false, dropped capabilities, readOnlyRootFilesystem.
  • Excludes Helm templates from the pre-commit check-yaml hook (Go-template directives are not valid YAML).

Why

Phase 8 task #115 — provides a reproducible, configurable deployment path for the daemon.

Testing

  • helm lint deploy/charts/thwap-pagesd — 0 failures
  • helm template renders across defaults, existingSecret reuse, and autoscaling.enabled configurations
  • go build ./..., go vet ./... — clean (no Go changes)
  • pre-commit hooks all pass

Breaking Changes

None.

Notes

  • Issues #113, #114, #115 closed via the Forgejo API as part of this task per the workflow.
  • helm lint notes the chart icon is unset (informational only).

Closes #113
Closes #114
Closes #115

## What Add a Helm chart at `deploy/charts/thwap-pagesd` to deploy the daemon on Kubernetes: - **Configurable replicas, resources, ingress (#113)** — `replicaCount`, container CPU/memory `resources`, liveness/readiness probes on `/healthz` and `/readyz`, node selector/tolerations/affinity, an optional HPA, and an optional Ingress with configurable `className`/`annotations`/`hosts`/`tls`. - **Environment variables and secrets management (#114)** — every runtime setting is injected as a `THWAP_PAGESD_*` environment variable: non-secret values via a ConfigMap consumed with `envFrom`, and the Forgejo token plus webhook secret via a Secret consumed with `secretKeyRef`. Secrets can be generated from values or referenced as an existing `existingSecret`. - **RBAC** — namespace-scoped Role/RoleBinding granting the daemon's ServiceAccount access to the ConfigMaps, PVCs, Services, Deployments, and Ingresses it manages (least privilege). - **Security** — hardened pod/container security contexts matching the Dockerfile's non-root `thwap` user (uid 100): `runAsNonRoot`, `allowPrivilegeEscalation: false`, dropped capabilities, `readOnlyRootFilesystem`. - Excludes Helm templates from the pre-commit `check-yaml` hook (Go-template directives are not valid YAML). ## Why Phase 8 task #115 — provides a reproducible, configurable deployment path for the daemon. ## Testing - [x] `helm lint deploy/charts/thwap-pagesd` — 0 failures - [x] `helm template` renders across defaults, `existingSecret` reuse, and `autoscaling.enabled` configurations - [x] `go build ./...`, `go vet ./...` — clean (no Go changes) - [x] pre-commit hooks all pass ## Breaking Changes None. ## Notes - Issues #113, #114, #115 closed via the Forgejo API as part of this task per the workflow. - `helm lint` notes the chart icon is unset (informational only). Closes #113 Closes #114 Closes #115
feat(helm): add Helm chart for Kubernetes deployment
All checks were successful
Test and Release / lint (pull_request) Successful in 27s
Test and Release / test (pull_request) Successful in 57s
72ea784929
Add a Helm chart under deploy/charts/thwap-pagesd to deploy the daemon
on Kubernetes:

- Configurable replica count, container resources, probes, node
  selectors/tolerations/affinity, optional HPA, and an optional Ingress
  exposing the daemon (#113)
- All runtime settings injected as THWAP_PAGESD_* environment variables:
  non-secret values via a ConfigMap (envFrom) and the Forgejo token plus
  webhook secret via a Secret referenced with secretKeyRef; the Secret
  can be generated from values or replaced by an existingSecret (#114)
- Namespace-scoped Role/RoleBinding granting the daemon's ServiceAccount
  access to the ConfigMaps, PVCs, Services, Deployments, and Ingresses
  it manages (least privilege)
- Hardened pod/container security contexts matching the Dockerfile's
  non-root thwap user (uid 100), probes wired to /healthz and /readyz

Exclude Helm templates from the pre-commit check-yaml hook, since
Go-template directives are not valid YAML. Verified with helm lint and
helm template renders across defaults, existingSecret, and
autoscaling-enabled configurations. Mark task done in ROADMAP.md.

closes #113
closes #114
closes #115
the.auditor left a comment

Review Summary

Verified locally on the PR head (72ea784): helm lint passes (0 failures; only the informational icon warning), helm template renders correctly across all three variants — defaults, existingSecret reuse (Secret omitted, deployment references the external secret), and autoscaling.enabled (HPA rendered, replicas correctly omitted from the Deployment). Go build/vet/test unaffected (chart-only PR).

The chart is well-constructed. Env mapping matches the daemon's THWAP_PAGESD_ + _-for-. convention exactly (verified in rendered ConfigMap: THWAP_PAGESD_KUBERNETES_NAMESPACE, THWAP_PAGESD_LOGGING_LEVEL, etc.), with empty values correctly falling back to daemon defaults. RBAC is genuinely least-privilege and covers every resource kind the daemon touches (ConfigMaps, PVCs, Services, Deployments, Ingresses). Security contexts match the Dockerfile's non-root uid 100 with dropped capabilities and readOnlyRootFilesystem. The check-yaml exclude for templates/ is correct (Go template directives aren't valid YAML) and the alternation regex is sound.

No blocking issues.

Non-blocking observations:

  1. The Role is scoped to the install namespace, while config.kubernetes.namespace (default thwap-pagesd) is where site resources land — operators installing into a different namespace must set both consistently or the daemon can't manage site resources. A values comment or helm template note would help.
  2. image.repository defaults to ghcr.io/thwap/thwap-pagesd, which isn't where this self-hosted project publishes images — worth documenting that it must be overridden (or pointing at the Forgejo container registry when #507 lands).
  3. envFromConfig is defined in _helpers.tpl but unused (the Deployment injects via envFrom: configMapRef); harmless dead template.
  4. readOnlyRootFilesystem is fine today (no local writes); when content population lands, git clones land in /tmp (kubelet tmpfs, writable) — worth keeping in mind.

Approving.

## Review Summary Verified locally on the PR head (`72ea784`): `helm lint` passes (0 failures; only the informational icon warning), `helm template` renders correctly across all three variants — defaults, `existingSecret` reuse (Secret omitted, deployment references the external secret), and `autoscaling.enabled` (HPA rendered, `replicas` correctly omitted from the Deployment). Go build/vet/test unaffected (chart-only PR). The chart is well-constructed. Env mapping matches the daemon's `THWAP_PAGESD_` + `_`-for-`.` convention exactly (verified in rendered ConfigMap: `THWAP_PAGESD_KUBERNETES_NAMESPACE`, `THWAP_PAGESD_LOGGING_LEVEL`, etc.), with empty values correctly falling back to daemon defaults. RBAC is genuinely least-privilege and covers every resource kind the daemon touches (ConfigMaps, PVCs, Services, Deployments, Ingresses). Security contexts match the Dockerfile's non-root uid 100 with dropped capabilities and `readOnlyRootFilesystem`. The `check-yaml` exclude for `templates/` is correct (Go template directives aren't valid YAML) and the alternation regex is sound. **No blocking issues.** Non-blocking observations: 1. The Role is scoped to the *install* namespace, while `config.kubernetes.namespace` (default `thwap-pagesd`) is where site resources land — operators installing into a different namespace must set both consistently or the daemon can't manage site resources. A values comment or `helm template` note would help. 2. `image.repository` defaults to `ghcr.io/thwap/thwap-pagesd`, which isn't where this self-hosted project publishes images — worth documenting that it must be overridden (or pointing at the Forgejo container registry when #507 lands). 3. `envFromConfig` is defined in `_helpers.tpl` but unused (the Deployment injects via `envFrom: configMapRef`); harmless dead template. 4. `readOnlyRootFilesystem` is fine today (no local writes); when content population lands, git clones land in `/tmp` (kubelet tmpfs, writable) — worth keeping in mind. Approving.
fuzzy merged commit 72ea784929 into main 2026-08-04 10:06:29 +00:00
fuzzy deleted branch feat/helm-chart 2026-08-04 10:06:29 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
thwap/thwap-pagesd!520
No description provided.