From 5795e40c097159747f7d3406b6d86749f0ea802e Mon Sep 17 00:00:00 2001 From: Jansen Fuller Date: Sat, 30 May 2026 18:09:56 -0600 Subject: [PATCH 1/3] Adding health probes and fixing container permissions --- .../templates/deployment.yaml | 24 +++++++++++++++++++ .../templates/serviceaccount.yaml | 3 ++- helm/taskchampion-sync-server/values.yaml | 14 +++++------ 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/helm/taskchampion-sync-server/templates/deployment.yaml b/helm/taskchampion-sync-server/templates/deployment.yaml index 2ee7409..54ffb0e 100644 --- a/helm/taskchampion-sync-server/templates/deployment.yaml +++ b/helm/taskchampion-sync-server/templates/deployment.yaml @@ -32,6 +32,8 @@ spec: imagePullPolicy: {{ .Values.postgres.initContainer.imagePullPolicy }} securityContext: allowPrivilegeEscalation: false + runAsNonRoot: true + runAsUser: 1000 env: - name: PGURI valueFrom: @@ -90,6 +92,16 @@ spec: imagePullPolicy: {{ .Values.image.pullPolicy }} securityContext: allowPrivilegeEscalation: false + runAsNonRoot: true + runAsUser: 1092 + readOnlyRootFilesystem: true + {{- if eq .Values.postgres.enabled true }} + command: + - /bin/taskchampion-sync-server-postgres + {{- else }} + command: + - /bin/taskchampion-sync-server + {{- end }} env: {{- range $name, $value := .Values.env }} - name: {{ $name }} @@ -117,6 +129,18 @@ spec: - name: http containerPort: {{ .Values.service.targetPort }} protocol: TCP + livenessProbe: + httpGet: + path: / + port: http + initialDelaySeconds: 5 + periodSeconds: 10 + readinessProbe: + httpGet: + path: / + port: http + initialDelaySeconds: 5 + periodSeconds: 10 {{- with .Values.resources }} resources: {{- toYaml . | nindent 12 }} diff --git a/helm/taskchampion-sync-server/templates/serviceaccount.yaml b/helm/taskchampion-sync-server/templates/serviceaccount.yaml index d4742a8..4bb353f 100644 --- a/helm/taskchampion-sync-server/templates/serviceaccount.yaml +++ b/helm/taskchampion-sync-server/templates/serviceaccount.yaml @@ -9,6 +9,7 @@ metadata: annotations: {{- toYaml . | nindent 4 }} {{- end }} +automountServiceAccountToken: false --- apiVersion: rbac.authorization.k8s.io/v1 kind: Role @@ -35,4 +36,4 @@ subjects: - kind: ServiceAccount name: {{ include "taskchampion-sync-server.fullname" . }} namespace: {{ .Release.Namespace }} -{{- end -}} \ No newline at end of file +{{- end -}} diff --git a/helm/taskchampion-sync-server/values.yaml b/helm/taskchampion-sync-server/values.yaml index 1c07ab3..1c17a12 100644 --- a/helm/taskchampion-sync-server/values.yaml +++ b/helm/taskchampion-sync-server/values.yaml @@ -72,13 +72,13 @@ httpRoute: port: 8080 # Resource limits and requests -resources: {} - # limits: - # memory: 128Mi - # cpu: 100m - # requests: - # memory: 64Mi - # cpu: 50m +resources: + limits: + memory: 25Mi + cpu: 100m + requests: + memory: 5Mi + cpu: 10m # Replica configuration (only applies when postgres is enabled) replicas: From 4d8bccf7f073a8d65d8fdd3d3589923ea32aca42 Mon Sep 17 00:00:00 2001 From: Jansen Fuller Date: Sat, 30 May 2026 18:35:21 -0600 Subject: [PATCH 2/3] Bump version --- helm/taskchampion-sync-server/Chart.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helm/taskchampion-sync-server/Chart.yaml b/helm/taskchampion-sync-server/Chart.yaml index a7ac268..a7813e6 100644 --- a/helm/taskchampion-sync-server/Chart.yaml +++ b/helm/taskchampion-sync-server/Chart.yaml @@ -2,7 +2,7 @@ apiVersion: v2 name: taskchampion-sync-server description: A Helm chart for deploying TaskChampion Sync Server on Kubernetes type: application -version: 0.1.2 +version: 0.1.3 appVersion: "0.7.0" keywords: - taskchampion From b47b258e911f11cda3f52823d63bb92703fd2624 Mon Sep 17 00:00:00 2001 From: Jansen Fuller Date: Mon, 1 Jun 2026 14:02:06 -0600 Subject: [PATCH 3/3] Cleanup --- helm/taskchampion-sync-server/.helmignore | 4 +- .../examples/postgres-values.yaml | 9 ++-- .../examples/sqlite-values.yaml | 9 ++-- .../templates/NOTES.txt | 46 +++++++++++++++++++ .../templates/_helpers.tpl | 8 +--- .../templates/deployment.yaml | 15 +++--- .../templates/ingress.yaml | 29 +++++++++++- .../templates/serviceaccount.yaml | 39 ---------------- helm/taskchampion-sync-server/values.yaml | 29 ++++++++---- 9 files changed, 114 insertions(+), 74 deletions(-) create mode 100644 helm/taskchampion-sync-server/templates/NOTES.txt delete mode 100644 helm/taskchampion-sync-server/templates/serviceaccount.yaml diff --git a/helm/taskchampion-sync-server/.helmignore b/helm/taskchampion-sync-server/.helmignore index 6c3a50f..1a65796 100644 --- a/helm/taskchampion-sync-server/.helmignore +++ b/helm/taskchampion-sync-server/.helmignore @@ -1,5 +1,5 @@ # Patterns to ignore when building the Helm chart .git -.gitignore -*.md examples/ +.DS_Store +*.tgz diff --git a/helm/taskchampion-sync-server/examples/postgres-values.yaml b/helm/taskchampion-sync-server/examples/postgres-values.yaml index ed2ae0b..938a88b 100644 --- a/helm/taskchampion-sync-server/examples/postgres-values.yaml +++ b/helm/taskchampion-sync-server/examples/postgres-values.yaml @@ -10,9 +10,12 @@ postgres: clientIdSecret: "taskchampion-client-ids" env: - RUST_LOG: debug - LISTEN: "0.0.0.0:8080" - CREATE_CLIENTS: "false" + - name: RUST_LOG + value: debug + - name: LISTEN + value: "0.0.0.0:8080" + - name: CREATE_CLIENTS + value: "false" replicas: enabled: true diff --git a/helm/taskchampion-sync-server/examples/sqlite-values.yaml b/helm/taskchampion-sync-server/examples/sqlite-values.yaml index 9159979..6beee3c 100644 --- a/helm/taskchampion-sync-server/examples/sqlite-values.yaml +++ b/helm/taskchampion-sync-server/examples/sqlite-values.yaml @@ -12,9 +12,12 @@ postgres: clientIdSecret: "taskchampion-client-ids" env: - RUST_LOG: info - LISTEN: "0.0.0.0:8080" - CREATE_CLIENTS: "false" + - name: RUST_LOG + value: info + - name: LISTEN + value: "0.0.0.0:8080" + - name: CREATE_CLIENTS + value: "false" ingress: enabled: true diff --git a/helm/taskchampion-sync-server/templates/NOTES.txt b/helm/taskchampion-sync-server/templates/NOTES.txt new file mode 100644 index 0000000..6ede624 --- /dev/null +++ b/helm/taskchampion-sync-server/templates/NOTES.txt @@ -0,0 +1,46 @@ +Thank you for installing {{ .Chart.Name }} — version {{ .Chart.Version }} (app: {{ .Chart.AppVersion }}). + +## Storage Backend + +{{- if eq .Values.sqlite.enabled true }} +**SQLite** — Data is stored at `{{ .Values.sqlite.dataDir }}`. +{{- if .Values.sqlite.persistence.enabled }} + PersistentVolumeClaim: `{{ include "taskchampion-sync-server.fullname" . }}-pvc` +{{- else if .Values.sqlite.existingPV }} + Using existing PVC: `{{ .Values.sqlite.existingPV }}` +{{- else }} + Using an emptyDir volume (ephemeral — data is lost on pod restart). + Set `sqlite.persistence.enabled=true` for persistent storage. +{{- end }} +{{- end }} + +{{- if eq .Values.postgres.enabled true }} +**PostgreSQL** — Connection URI stored in Secret `{{ include "taskchampion-sync-server.postgres-secret-name" . }}`. + Host: {{ .Values.postgres.host }}:{{ .Values.postgres.port }} + Database: {{ .Values.postgres.database }} +{{- end }} + +## Verify the Deployment + + kubectl get pods -l {{ include "taskchampion-sync-server.selectorLabels" . | replace ": " "=" | replace "\n" "," | trimSuffix "," }} + +## Check Pod Logs + + kubectl logs -l {{ include "taskchampion-sync-server.selectorLabels" . | replace ": " "=" | replace "\n" "," | trimSuffix "," }} + +## Test the API + + kubectl port-forward svc/{{ include "taskchampion-sync-server.fullname" . }} {{ .Values.service.port }}:{{ .Values.service.port }} + curl http://localhost:{{ .Values.service.port }}/ + +## View Connection Secret (PostgreSQL only) + +{{- if eq .Values.postgres.enabled true }} + kubectl get secret {{ include "taskchampion-sync-server.postgres-secret-name" . }} -o jsonpath="{.data.connection}" | base64 -d +{{- end }} + +## Configuration + +For full configuration options, see: + + https://github.com/GothenburgBitFactory/taskchampion-sync-server diff --git a/helm/taskchampion-sync-server/templates/_helpers.tpl b/helm/taskchampion-sync-server/templates/_helpers.tpl index 1b04f91..2e8e33a 100644 --- a/helm/taskchampion-sync-server/templates/_helpers.tpl +++ b/helm/taskchampion-sync-server/templates/_helpers.tpl @@ -23,6 +23,7 @@ taskchampion-sync-server helpers helm.sh/chart: {{ printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} app.kubernetes.io/name: {{ include "taskchampion-sync-server.name" . }} app.kubernetes.io/instance: {{ .Release.Name }} +app.kubernetes.io/component: server app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} app.kubernetes.io/managed-by: {{ .Release.Service }} {{- end }} @@ -32,13 +33,6 @@ app.kubernetes.io/name: {{ include "taskchampion-sync-server.name" . }} app.kubernetes.io/instance: {{ .Release.Name }} {{- end }} -{{- define "taskchampion-sync-server.serviceAccountName" -}} -{{- if .Values.serviceAccount.create }} -{{- default (include "taskchampion-sync-server.fullname" .) .Values.serviceAccount.name }} -{{- else }} -{{- default "default" .Values.serviceAccount.name }} -{{- end }} -{{- end }} {{- define "taskchampion-sync-server.postgres-connection" -}} {{- $host := .Values.postgres.host -}} diff --git a/helm/taskchampion-sync-server/templates/deployment.yaml b/helm/taskchampion-sync-server/templates/deployment.yaml index 54ffb0e..39215c3 100644 --- a/helm/taskchampion-sync-server/templates/deployment.yaml +++ b/helm/taskchampion-sync-server/templates/deployment.yaml @@ -18,10 +18,10 @@ spec: labels: {{- include "taskchampion-sync-server.selectorLabels" . | nindent 8 }} spec: - {{- if .Values.serviceAccount.create }} - serviceAccountName: {{ include "taskchampion-sync-server.fullname" . }} - {{- else if .Values.serviceAccount.name }} - serviceAccountName: {{ .Values.serviceAccount.name }} + + {{- with .Values.image.pullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} {{- end }} securityContext: {{- toYaml .Values.securityContext | nindent 8 }} @@ -33,7 +33,7 @@ spec: securityContext: allowPrivilegeEscalation: false runAsNonRoot: true - runAsUser: 1000 + runAsUser: 999 env: - name: PGURI valueFrom: @@ -103,10 +103,7 @@ spec: - /bin/taskchampion-sync-server {{- end }} env: - {{- range $name, $value := .Values.env }} - - name: {{ $name }} - value: {{ $value | quote }} - {{- end }} + {{- toYaml .Values.env | nindent 12 }} {{- if .Values.clientIdSecret }} - name: CLIENT_ID valueFrom: diff --git a/helm/taskchampion-sync-server/templates/ingress.yaml b/helm/taskchampion-sync-server/templates/ingress.yaml index 8565711..c33db5e 100644 --- a/helm/taskchampion-sync-server/templates/ingress.yaml +++ b/helm/taskchampion-sync-server/templates/ingress.yaml @@ -18,7 +18,10 @@ spec: {{- toYaml .Values.ingress.tls | nindent 4 }} {{- end }} rules: + {{- $svcName := include "taskchampion-sync-server.fullname" . -}} + {{- $svcPort := $.Values.service.port -}} {{- range .Values.ingress.hosts }} + {{- if kindIs "string" . }} - host: {{ . | quote }} http: paths: @@ -26,8 +29,30 @@ spec: pathType: Prefix backend: service: - name: {{ include "taskchampion-sync-server.fullname" $ }} + name: {{ $svcName }} port: - number: {{ $.Values.service.port }} + number: {{ $svcPort }} + {{- else }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ .path | default "/" | quote }} + pathType: {{ .pathType | default "Prefix" }} + backend: + service: + name: {{ $svcName }} + port: + number: {{ $svcPort }} + {{- else }} + - path: / + pathType: Prefix + backend: + service: + name: {{ $svcName }} + port: + number: {{ $svcPort }} + {{- end }} + {{- end }} {{- end }} {{- end }} diff --git a/helm/taskchampion-sync-server/templates/serviceaccount.yaml b/helm/taskchampion-sync-server/templates/serviceaccount.yaml deleted file mode 100644 index 4bb353f..0000000 --- a/helm/taskchampion-sync-server/templates/serviceaccount.yaml +++ /dev/null @@ -1,39 +0,0 @@ -{{- if .Values.serviceAccount.create -}} -apiVersion: v1 -kind: ServiceAccount -metadata: - name: {{ include "taskchampion-sync-server.fullname" . }} - labels: - {{- include "taskchampion-sync-server.labels" . | nindent 4 }} - {{- with .Values.serviceAccount.annotations }} - annotations: - {{- toYaml . | nindent 4 }} - {{- end }} -automountServiceAccountToken: false ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - name: {{ include "taskchampion-sync-server.fullname" . }}-secret-manager - labels: - {{- include "taskchampion-sync-server.labels" . | nindent 4 }} -rules: -- apiGroups: [""] - resources: ["secrets"] - verbs: ["create", "get", "update", "patch"] ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: {{ include "taskchampion-sync-server.fullname" . }}-secret-binding - labels: - {{- include "taskchampion-sync-server.labels" . | nindent 4 }} -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: {{ include "taskchampion-sync-server.fullname" . }}-secret-manager -subjects: -- kind: ServiceAccount - name: {{ include "taskchampion-sync-server.fullname" . }} - namespace: {{ .Release.Namespace }} -{{- end -}} diff --git a/helm/taskchampion-sync-server/values.yaml b/helm/taskchampion-sync-server/values.yaml index 1c17a12..91d3a3e 100644 --- a/helm/taskchampion-sync-server/values.yaml +++ b/helm/taskchampion-sync-server/values.yaml @@ -16,10 +16,19 @@ clientIdSecret: "" # Environment variables passed directly to the container # NOTE: DATA_DIR and CONNECTION are set automatically based on backend +# To add secret/configMap references, use valueFrom: +# - name: MY_SECRET_VAR +# valueFrom: +# secretKeyRef: +# name: my-secret +# key: my-key env: - RUST_LOG: info - LISTEN: "0.0.0.0:8080" - CREATE_CLIENTS: "true" + - name: RUST_LOG + value: info + - name: LISTEN + value: "0.0.0.0:8080" + - name: CREATE_CLIENTS + value: "true" # Service configuration service: @@ -28,6 +37,14 @@ service: targetPort: 8080 # Ingress configuration +# Each host can be a string (simple) or a map with path rules: +# hosts: +# - host: app.example.com +# paths: +# - path: / +# pathType: Prefix +# - path: /api +# pathType: Exact ingress: enabled: false className: "" @@ -107,12 +124,6 @@ sqlite: storageClass: "" existingClaim: "" -# Service account configuration -serviceAccount: - create: true # Default: automatically create service account - name: "" # Optional: use existing service account - annotations: {} - # PostgreSQL configuration postgres: enabled: false