From 934f7811f21ecfab6090aec2bb2941c837189c44 Mon Sep 17 00:00:00 2001 From: Christian Mehlmauer <105281+firefart@users.noreply.github.com> Date: Wed, 26 Aug 2026 20:53:25 +0200 Subject: [PATCH 1/3] update --- .github/workflows/validate.yml | 46 +++++++ .github/workflows/yamllint.yml | 9 +- .gitignore | 14 +-- .goreleaser.yaml | 46 ------- AGENTS.md | 31 +++++ CLAUDE.md | 4 +- Dockerfile | 6 +- Readme.md | 18 ++- SECURITY.md | 19 +++ dev-helm.sh | 28 ++--- docker-compose.dev.yml | 4 +- docker-compose.yml | 6 +- helm/Chart.yaml | 2 +- helm/templates/NOTES.txt | 29 ++--- helm/templates/_helpers.tpl | 37 +++++- helm/templates/configmap.yaml | 8 +- helm/templates/deployment-postgres.yaml | 10 +- helm/templates/deployment-rt.yaml | 89 +++++++++----- helm/templates/hpa-rt.yaml | 4 +- helm/templates/ingress.yaml | 4 +- helm/templates/jobs.yaml | 155 +++++++++++------------- helm/templates/networkpolicy.yaml | 2 +- helm/templates/pdb.yaml | 2 +- helm/templates/pvc-postgres.yaml | 6 +- helm/templates/pvc.yaml | 24 +++- helm/templates/route.yaml | 6 +- helm/templates/secret-db.yaml | 2 +- helm/templates/secret-mail.yaml | 14 +++ helm/templates/service-mailgate.yaml | 16 +++ helm/templates/service-postgres.yaml | 2 +- helm/templates/service-rt.yaml | 7 +- helm/templates/serviceaccount.yaml | 2 +- helm/values.yaml | 64 ++++++---- k8s-jobs/db-init.yaml | 23 ++-- k8s-jobs/db-update.yaml | 23 ++-- k8s-jobs/install-ingress.sh | 7 +- 36 files changed, 464 insertions(+), 305 deletions(-) create mode 100644 .github/workflows/validate.yml delete mode 100644 .goreleaser.yaml create mode 100644 AGENTS.md create mode 100644 SECURITY.md create mode 100644 helm/templates/secret-mail.yaml create mode 100644 helm/templates/service-mailgate.yaml diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml new file mode 100644 index 0000000..59a595d --- /dev/null +++ b/.github/workflows/validate.yml @@ -0,0 +1,46 @@ +name: Validate repository + +on: + push: + pull_request: + workflow_dispatch: + +permissions: + contents: read + +jobs: + validate: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + - uses: azure/setup-helm@v4.3.1 + - name: Install ShellCheck + run: | + sudo apt-get update + sudo apt-get install --yes shellcheck + - name: Check shell scripts + run: shellcheck ./*.sh k8s-jobs/*.sh + - name: Validate Helm chart + run: | + helm lint helm/ + helm template rt helm/ > /tmp/rt-rendered.yaml + helm template custom helm/ --set fullnameOverride=custom --set postgres.enabled=false --set db.host=db.example.test > /tmp/rt-external-db.yaml + helm template rt helm/ --set-json 'cronjobs=[{"name":"getmail","schedule":"* * * * *","command":["/usr/bin/getmail","--rcfile=/getmailrc"]}]' > /tmp/rt-cronjob.yaml + - name: Validate Kubernetes schemas + run: | + docker run --rm -i ghcr.io/yannh/kubeconform:v0.7.0 -strict -summary -ignore-missing-schemas < /tmp/rt-rendered.yaml + docker run --rm -i ghcr.io/yannh/kubeconform:v0.7.0 -strict -summary -ignore-missing-schemas < /tmp/rt-external-db.yaml + docker run --rm -i ghcr.io/yannh/kubeconform:v0.7.0 -strict -summary -ignore-missing-schemas < /tmp/rt-cronjob.yaml + - name: Prepare example Compose configuration + run: | + cp RT_SiteConfig.pm.example RT_SiteConfig.pm + cp Caddyfile.example Caddyfile + cp msmtp.conf.example msmtp/msmtp.conf + cp getmailrc.example getmail/getmailrc + cp crontab.example crontab + printf 'test' > pgadmin_password.secret + printf 'test' > postgres_password.secret + - name: Validate Compose models + run: | + docker compose config --quiet + docker compose -f docker-compose.yml -f docker-compose.dev.yml config --quiet diff --git a/.github/workflows/yamllint.yml b/.github/workflows/yamllint.yml index 9693d7d..c54c61b 100644 --- a/.github/workflows/yamllint.yml +++ b/.github/workflows/yamllint.yml @@ -14,8 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 - - uses: karancode/yamllint-github-action@master - with: - # fail on warnings and errors - yamllint_strict: true - yamllint_config_filepath: ".yamllint.yml" + - name: Install yamllint + run: pipx install yamllint + - name: Lint YAML + run: yamllint --strict --config-file .yamllint.yml . diff --git a/.gitignore b/.gitignore index 0ad4c32..34ead68 100644 --- a/.gitignore +++ b/.gitignore @@ -1,17 +1,6 @@ -*.sh -!dev.sh -!dev-helm.sh -!prod.sh -!k8s-jobs/install-ingress.sh RT_SiteConfig.pm *.pem *.key -!dev.sh -!prod.sh -!logs_prod.sh -!bash_functions.sh -!restart_prod.sh -!cron_entrypoint.sh Caddyfile crontab /certs/* @@ -27,9 +16,8 @@ shredder/*.sql *.env .env *.pgpass -*.json +.claude/settings.local.json docker-compose.override.yml *.patch # Added by goreleaser init: dist/ -*.pm \ No newline at end of file diff --git a/.goreleaser.yaml b/.goreleaser.yaml deleted file mode 100644 index a2b447c..0000000 --- a/.goreleaser.yaml +++ /dev/null @@ -1,46 +0,0 @@ -# This is an example .goreleaser.yml file with some sensible defaults. -# Make sure to check the documentation at https://goreleaser.com - -# The lines below are called `modelines`. See `:help modeline` -# Feel free to remove those if you don't want/need to use them. -# yaml-language-server: $schema=https://goreleaser.com/static/schema.json -# vim: set ts=2 sw=2 tw=0 fo=cnqoj - -version: 2 - -before: - hooks: - # You may remove this if you don't use go modules. - - go mod tidy - # you may remove this if you don't need go generate - - go generate ./... - -builds: - - env: - - CGO_ENABLED=0 - goos: - - linux - - windows - - darwin - -archives: - - formats: [tar.gz] - # this name template makes the OS and Arch compatible with the results of `uname`. - name_template: >- - {{ .ProjectName }}_ - {{- title .Os }}_ - {{- if eq .Arch "amd64" }}x86_64 - {{- else if eq .Arch "386" }}i386 - {{- else }}{{ .Arch }}{{ end }} - {{- if .Arm }}v{{ .Arm }}{{ end }} - # use zip for windows archives - format_overrides: - - goos: windows - formats: [zip] - -changelog: - sort: asc - filters: - exclude: - - "^docs:" - - "^test:" diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..8213ea9 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,31 @@ +# Repository Guidelines + +## Project Structure & Module Organization + +This repository packages Request Tracker (RT) and RTIR for Docker and Kubernetes. `Dockerfile` builds the image; `docker-compose.yml` defines production services, while `docker-compose.dev.yml` adds PostgreSQL and pgAdmin. Root shell scripts manage startup and logs. The Helm chart lives in `helm/`; database jobs are in `k8s-jobs/`. Files ending in `.example` are configuration templates. + +## Build, Test, and Development Commands + +- `./dev.sh` validates configuration, builds the image, and starts the development stack. +- `./prod.sh` pulls published images and recreates the production stack; use `./restart_prod.sh` to restart without pulling. +- `./logs_prod.sh` follows production service logs. +- `docker compose -f docker-compose.yml -f docker-compose.dev.yml config` validates the merged development configuration. +- `helm lint helm/` and `helm template rt helm/` validate and render the chart without modifying a cluster. + +Before running the stack, copy the required templates to `RT_SiteConfig.pm`, `Caddyfile`, `msmtp/msmtp.conf`, `crontab`, and `getmail/getmailrc`. See `Readme.md` for development-only certificates and secrets. + +## Coding Style & Naming Conventions + +Shell scripts use Bash, `set -euf -o pipefail`, quoted expansions, four-space indentation, and `snake_case` functions. Use two-space indentation for YAML and preserve existing Helm Go-template conventions. Run `yamllint .`, `hadolint Dockerfile`, and `kube-linter lint helm/` when available. Keep version mappings synchronized between `Dockerfile`, `helm/Chart.yaml`, and CI workflows. + +## Testing Guidelines + +There is no standalone unit-test suite. Required checks are linting, image builds, Compose validation, and Helm rendering. For service changes, start the dev stack and inspect container health and logs. Test database initialization manifests in a disposable cluster. + +## Commit & Pull Request Guidelines + +History favors short subjects such as `Update Dockerfile` or `Fix RTIR version mapping`; dependency updates use `Bump from to `. Keep commits focused. Pull requests should explain deployment impact, list validation performed, link issues, and call out configuration, port, image-tag, or migration changes. Include screenshots only for visible UI behavior. + +## Security & Configuration + +Never commit credentials, private keys, generated certificates, or live RT/mail configuration. Preserve the Caddy rule that blocks the unauthenticated mail-gateway endpoint on the public RT virtual host. Review volume permissions carefully: runtime data is expected to be owned by UID 1000 with restrictive modes. diff --git a/CLAUDE.md b/CLAUDE.md index 335efb4..2e52fe2 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -73,8 +73,8 @@ docker compose run --rm rt bash -c 'cd /opt/rt && perl ./sbin/rt-validator --che ### Docker Image (Multi-stage Dockerfile) 1. **`msmtp-builder`** stage (debian:13-slim): Compiles msmtp from source with GPG verification against the upstream signing key. -2. **`builder`** stage (perl:5.42.2): Downloads and builds RT + RT-IR with GPG signature verification, installs CPAN dependencies, and installs all RT extensions. Build args: `RT_VERSION` (default 6.0.3) and `RTIR_VERSION` (default 6.0.3). The `ADDITIONAL_CPANM_ARGS` build arg is used in dev to pass `-n` (skip tests). -3. **Final image** (perl:5.42.2-slim): Copies compiled artifacts from builder stages, installs `getmail6` via `uv`, runs RT via `spawn-fcgi` on port 9000 (FastCGI). A final `rt-test-dependencies` check validates all Perl deps were copied correctly. +2. **`builder`** stage (perl:5.44.0): Downloads and builds RT + RT-IR with GPG signature verification, installs CPAN dependencies, and installs all RT extensions. Build args: `RT_VERSION` (default 6.0.3) and `RTIR_VERSION` (default 6.0.3). The `ADDITIONAL_CPANM_ARGS` build arg is used in dev to pass `-n` (skip tests). +3. **Final image** (perl:5.44.0-slim): Copies compiled artifacts from builder stages, installs `getmail6` via `uv`, runs RT via `spawn-fcgi` on port 9000 (FastCGI). A final `rt-test-dependencies` check validates all Perl deps were copied correctly. The container exposes port 9000 (FastCGI) and uses a healthcheck via `cgi-fcgi`. diff --git a/Dockerfile b/Dockerfile index 8d44775..4fddd58 100644 --- a/Dockerfile +++ b/Dockerfile @@ -273,8 +273,8 @@ COPY --chown=rt:rt --from=builder /opt/rt /opt/rt # run a final dependency check if we copied all RUN perl /opt/rt/sbin/rt-test-dependencies --with-pg --with-fastcgi --with-gpg --with-graphviz --with-gd -# uv and uvx (needed for getmail6) -COPY --from=docker.io/astral/uv:latest /uv /uvx /bin/ +# uv and uvx (needed for getmail6); pin this independently from the base image. +COPY --from=docker.io/astral/uv:0.8.13 /uv /uvx /bin/ RUN true \ # msmtp config @@ -320,7 +320,7 @@ EXPOSE 9000 # install getmail as the rt user USER rt -RUN uv tool install getmail6 \ +RUN uv tool install getmail6==6.20.1 \ && uv cache clean USER root diff --git a/Readme.md b/Readme.md index 9bbe1eb..52340df 100644 --- a/Readme.md +++ b/Readme.md @@ -410,18 +410,24 @@ To include additional containers in this setup like pgadmin or change a default ## Kubernetes setup -The chart needs a Secret called `rt-db-creds` holding the database credentials -(keys `dbname`, `username`, `password`). Either create it yourself: +The chart scopes resource names to the Helm release. For release `rt`, it expects +`rt-request-tracker-db-creds` with keys `dbname`, `username`, and `password`: ```bash -kubectl create secret generic rt-db-creds \ +kubectl create secret generic rt-request-tracker-db-creds \ --from-literal=dbname=rt \ --from-literal=username=rt \ --from-literal=password='changeme' ``` or let the chart manage it via values (`db.create=true`, `db.password=...`), or -point the chart at an existing Secret with `db.existingSecret`. +point the chart at an existing Secret with `db.existingSecret`. For an external +database, also set `postgres.enabled=false` and `db.host`. + +For production mail settings, create a Secret with keys `msmtp` and `getmailrc`, +then set `mail.existingSecret`. Do not commit credentials in a values file. The +mailgate port is protected by a NetworkPolicy and only chart CronJobs are allowed +to connect by default. ```bash helm install rt helm/ @@ -438,3 +444,7 @@ kubectl apply -f k8s-jobs/db-init.yaml ```bash kubectl apply -f k8s-jobs/db-update.yaml ``` + +The standalone jobs assume release `rt`; adjust their image and resource names +for other releases. Back up PostgreSQL and RT data before upgrades. Chart PVCs +use Helm's keep policy, so uninstall leaves them for deliberate manual cleanup. diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..b2aa5b5 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,19 @@ +# Security Policy + +## Reporting a Vulnerability + +Do not open a public issue for a suspected vulnerability. Use GitHub's private +security-advisory reporting feature for this repository and include affected +versions, reproduction steps, impact, and any proposed mitigation. + +Avoid including production credentials, private keys, customer data, or live +Request Tracker configuration in a report. Maintainers will acknowledge a +report, investigate it, and coordinate disclosure and remediation when the +issue is confirmed. + +## Supported Versions + +Security fixes are applied to the RT image versions currently built by +`.github/workflows/docker.yml`. Older image tags remain available but should not +be assumed to receive fixes. Prefer a concrete version tag over `latest` and +regularly rebuild or pull the selected tag to receive refreshed dependencies. diff --git a/dev-helm.sh b/dev-helm.sh index e3b9bbc..8810aaa 100755 --- a/dev-helm.sh +++ b/dev-helm.sh @@ -2,21 +2,17 @@ set -euf -o pipefail -echo "uninstalling old stuff" -kubectl delete job --all --ignore-not-found -helm uninstall --ignore-not-found rt -kubectl delete secret --all --ignore-not-found -echo "sleeping 15 seconds to let things settle" -sleep 15 -echo "installing new stuff" -kubectl create secret generic rt-db-creds \ +NAMESPACE="${RT_DEV_NAMESPACE:-rt-dev}" +RELEASE="${RT_DEV_RELEASE:-rt}" + +kubectl create namespace "${NAMESPACE}" --dry-run=client -o yaml | kubectl apply -f - +kubectl -n "${NAMESPACE}" create secret generic "${RELEASE}-request-tracker-db-creds" \ --from-literal=dbname=rt \ --from-literal=username=rt \ - --from-literal=password='rt' -helm install rt helm/ -echo "sleeping 2 minutes to let the database come up" -sleep 120 -echo "initializing the database" -kubectl apply -f k8s-jobs/db-init.yaml -echo "done" -kubectl get pods + --from-literal=password='rt' \ + --dry-run=client -o yaml | kubectl apply -f - +helm upgrade --install "${RELEASE}" helm/ --namespace "${NAMESPACE}" +kubectl -n "${NAMESPACE}" rollout status "deployment/${RELEASE}-request-tracker-db" --timeout=180s +kubectl -n "${NAMESPACE}" apply -f k8s-jobs/db-init.yaml +kubectl -n "${NAMESPACE}" wait --for=condition=complete job/db-init-job --timeout=300s +kubectl -n "${NAMESPACE}" get pods diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index ea66d5a..6c64928 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -26,7 +26,7 @@ services: restart: "no" db: - image: postgres:latest + image: postgres:17.6 restart: "no" environment: POSTGRES_DB: rt @@ -48,7 +48,7 @@ services: - net pgadmin: - image: dpage/pgadmin4:latest + image: dpage/pgadmin4:9.8 restart: "no" ports: - "127.0.0.1:8888:80" diff --git a/docker-compose.yml b/docker-compose.yml index 5916b31..cf998e5 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,7 +1,7 @@ x-app: &default-app build: context: . - image: firefart/requesttracker:latest + image: ${RT_IMAGE:-firefart/requesttracker:6.0.3} restart: unless-stopped configs: - source: rt_site_config @@ -31,7 +31,7 @@ services: hostname: rt deploy: mode: replicated - replicas: 5 + replicas: ${RT_REPLICAS:-5} endpoint_mode: vip cron: @@ -58,7 +58,7 @@ services: restart: true caddy: - image: caddy:latest + image: caddy:2.10 hostname: caddy restart: unless-stopped ports: diff --git a/helm/Chart.yaml b/helm/Chart.yaml index a76f767..2d63080 100644 --- a/helm/Chart.yaml +++ b/helm/Chart.yaml @@ -2,7 +2,7 @@ apiVersion: v2 name: request-tracker description: A Helm chart for installing request tracker on Kubernetes/OpenShift clusters. type: application -version: 0.2.0 +version: 0.3.0 # the default container image tag is derived from this when rt.image.tag is empty appVersion: "6.0.3" sources: diff --git a/helm/templates/NOTES.txt b/helm/templates/NOTES.txt index 4ad2525..6b10497 100644 --- a/helm/templates/NOTES.txt +++ b/helm/templates/NOTES.txt @@ -1,22 +1,17 @@ -1. Get the application URL by running these commands: +Request Tracker was installed as {{ include "request-tracker.fullname" . }}. + {{- if .Values.ingress.enabled }} +Configured ingress URLs: {{- range $host := .Values.ingress.hosts }} - {{- range .paths }} +{{- range .paths }} http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }} - {{- end }} {{- end }} -{{- else if contains "NodePort" .Values.caddy.service.type }} - export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services rt) - export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") - echo http://$NODE_IP:$NODE_PORT -{{- else if contains "LoadBalancer" .Values.caddy.service.type }} - NOTE: It may take a few minutes for the LoadBalancer IP to be available. - You can watch its status by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w rt' - export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} rt --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") - echo http://$SERVICE_IP:{{ .Values.caddy.service.port }} -{{- else if contains "ClusterIP" .Values.caddy.service.type }} - export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name=rt,app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") - export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") - echo "Visit http://127.0.0.1:8080 to use your application" - kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT {{- end }} +{{- else }} +To access it locally: + kubectl --namespace {{ .Release.Namespace }} port-forward service/{{ include "request-tracker.caddyName" . }} 8080:{{ .Values.caddy.service.port }} + echo http://127.0.0.1:8080 +{{- end }} + +The database and application-data PVCs have the Helm keep policy. Back them up +before upgrades and remove them manually only when their data is no longer needed. diff --git a/helm/templates/_helpers.tpl b/helm/templates/_helpers.tpl index 711c925..07b55da 100644 --- a/helm/templates/_helpers.tpl +++ b/helm/templates/_helpers.tpl @@ -5,6 +5,35 @@ Create chart name and version as used by the chart label. {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} {{- end }} +{{- define "request-tracker.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{- define "request-tracker.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name (include "request-tracker.name" .) | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} + +{{- define "request-tracker.postgresName" -}}{{ include "request-tracker.fullname" . }}-db{{- end }} +{{- define "request-tracker.dbHost" -}}{{ .Values.db.host | default (include "request-tracker.postgresName" .) }}{{- end }} +{{- define "request-tracker.caddyName" -}}{{ include "request-tracker.fullname" . }}-caddy{{- end }} +{{- define "request-tracker.mailgateName" -}}{{ include "request-tracker.fullname" . }}-mailgate{{- end }} +{{- define "request-tracker.configName" -}}{{ include "request-tracker.fullname" . }}-config{{- end }} +{{- define "request-tracker.mailSecretName" -}} +{{- .Values.mail.existingSecret | default (printf "%s-mail" (include "request-tracker.fullname" .)) -}} +{{- end }} + +{{- define "request-tracker.serviceAccountName" -}} +{{- if .Values.serviceAccount.create -}} +{{- include "request-tracker.fullname" . -}} +{{- else -}} +{{- required "serviceAccount.name is required when serviceAccount.create is false" .Values.serviceAccount.name -}} +{{- end -}} +{{- end }} + {{/* Common labels */}} @@ -21,19 +50,19 @@ app.kubernetes.io/managed-by: {{ .Release.Service }} Selector labels */}} {{- define "request-tracker.selectorLabels" -}} -app.kubernetes.io/name: rt +app.kubernetes.io/name: {{ include "request-tracker.name" . }} app.kubernetes.io/instance: {{ .Release.Name }} {{- end }} {{/* Name of the Secret holding the database credentials. -Uses db.existingSecret when set, otherwise the chart-managed "rt-db-creds". +Uses db.existingSecret when set, otherwise a release-scoped chart Secret. */}} {{- define "request-tracker.dbSecretName" -}} {{- if .Values.db.existingSecret -}} {{- .Values.db.existingSecret -}} {{- else -}} -rt-db-creds +{{ include "request-tracker.fullname" . }}-db-creds {{- end -}} {{- end }} @@ -52,7 +81,7 @@ Validate value combinations that would otherwise fail silently at runtime. {{- if $multiReplica -}} {{- range $name, $pvc := .Values.pvc -}} {{- if and $pvc.enabled (eq $pvc.accessMode "ReadWriteOnce") -}} -{{- if not (or (eq $name "postgresData") (eq $name "caddyData") (eq $name "caddyConfig")) -}} +{{- if ne $name "postgresData" -}} {{- fail (printf "pvc.%s uses ReadWriteOnce but rt runs with multiple replicas; this volume is mounted by every rt pod and must be ReadWriteMany. Set pvc.%s.accessMode=ReadWriteMany or rt.replicaCount=1." $name $name) -}} {{- end -}} {{- end -}} diff --git a/helm/templates/configmap.yaml b/helm/templates/configmap.yaml index 2133b94..04206d5 100644 --- a/helm/templates/configmap.yaml +++ b/helm/templates/configmap.yaml @@ -1,15 +1,11 @@ apiVersion: v1 kind: ConfigMap metadata: - name: rt-config + name: {{ include "request-tracker.configName" . }} labels: {{- include "request-tracker.labels" . | nindent 4 }} data: rtSiteConfig: |- -{{ .Values.config.rtSiteConfig | indent 4}} - msmtp: |- -{{ .Values.config.msmtp | indent 4 }} - getmailrc: |- -{{ .Values.config.getmailrc | indent 4 }} +{{ .Values.rtConfig.rtSiteConfig | indent 4 }} caddyfile: |- {{ .Values.config.caddyfile | indent 4 }} diff --git a/helm/templates/deployment-postgres.yaml b/helm/templates/deployment-postgres.yaml index 303466e..0d8575e 100644 --- a/helm/templates/deployment-postgres.yaml +++ b/helm/templates/deployment-postgres.yaml @@ -2,7 +2,7 @@ apiVersion: apps/v1 kind: Deployment metadata: - name: rt-db + name: {{ include "request-tracker.postgresName" . }} labels: {{- include "request-tracker.labels" . | nindent 4 }} app.kubernetes.io/component: postgres @@ -33,7 +33,7 @@ spec: imagePullSecrets: {{- toYaml . | nindent 8 }} {{- end }} - serviceAccountName: rt + serviceAccountName: {{ include "request-tracker.serviceAccountName" . }} {{- with .Values.postgres.podSecurityContext }} securityContext: {{- toYaml . | nindent 8 }} @@ -107,8 +107,12 @@ spec: {{- end }} volumes: - name: postgres-data + {{- if .Values.pvc.postgresData.enabled }} persistentVolumeClaim: - claimName: rt-postgres-data + claimName: {{ include "request-tracker.fullname" . }}-postgres-data + {{- else }} + emptyDir: {} + {{- end }} - name: postgres-run emptyDir: sizeLimit: 100Mi diff --git a/helm/templates/deployment-rt.yaml b/helm/templates/deployment-rt.yaml index 8ac01ca..bf33100 100644 --- a/helm/templates/deployment-rt.yaml +++ b/helm/templates/deployment-rt.yaml @@ -2,7 +2,7 @@ apiVersion: apps/v1 kind: Deployment metadata: - name: rt + name: {{ include "request-tracker.fullname" . }} labels: {{- include "request-tracker.labels" . | nindent 4 }} app.kubernetes.io/component: rt @@ -36,7 +36,7 @@ spec: imagePullSecrets: {{- toYaml . | nindent 8 }} {{- end }} - serviceAccountName: rt + serviceAccountName: {{ include "request-tracker.serviceAccountName" . }} {{- with .Values.rt.podSecurityContext }} securityContext: {{- toYaml . | nindent 8 }} @@ -52,7 +52,10 @@ spec: allowPrivilegeEscalation: false runAsUser: 65534 # nobody user in the busybox image runAsGroup: 65534 # nobody user in the busybox image - command: ['sh', '-c', "until nslookup rt-db.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for rt-db; sleep 2; done"] + command: + - sh + - -c + - {{ printf "until nslookup %s; do echo waiting for database DNS; sleep 2; done" (include "request-tracker.postgresName" .) | quote }} {{- with .Values.rt.resourcesInitContainer }} resources: {{- toYaml . | nindent 12 }} @@ -68,7 +71,7 @@ spec: command: - bash - -c - - until pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB} -h rt-db; do echo waiting for database; sleep 2; done; + - until pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB} -h {{ include "request-tracker.postgresName" . }}; do echo waiting for database; sleep 2; done; {{- with .Values.rt.resourcesInitContainer }} resources: {{- toYaml . | nindent 12 }} @@ -91,20 +94,14 @@ spec: key: password {{- end }} - name: generate-config - image: "hairyhenderson/gomplate:stable-alpine" - imagePullPolicy: IfNotPresent + image: {{ .Values.configRenderer.image | quote }} + imagePullPolicy: {{ .Values.configRenderer.pullPolicy }} securityContext: - readOnlyRootFilesystem: true - runAsNonRoot: true - allowPrivilegeEscalation: false - runAsUser: 65534 # nobody user - runAsGroup: 65534 # nobody group + {{- toYaml .Values.configRenderer.securityContext | nindent 12 }} command: - - gomplate - - -f - - /templates/RT_SiteConfig.pm - - -o - - /output/RT_SiteConfig.pm + - sh + - -c + - gomplate -f /templates/RT_SiteConfig.pm -o /output/RT_SiteConfig.pm && gomplate -f /templates/getmailrc -o /output/getmailrc {{- with .Values.rt.resourcesInitContainer }} resources: {{- toYaml . | nindent 12 }} @@ -115,6 +112,10 @@ spec: secretKeyRef: name: {{ include "request-tracker.dbSecretName" . }} key: dbname + - name: RT_DB_HOST + value: {{ include "request-tracker.dbHost" . | quote }} + - name: RT_CADDY_HOST + value: {{ include "request-tracker.mailgateName" . | quote }} - name: RT_DB_USER valueFrom: secretKeyRef: @@ -130,6 +131,10 @@ spec: mountPath: /templates/RT_SiteConfig.pm subPath: RT_SiteConfig.pm readOnly: true + - name: getmailrc-template + mountPath: /templates/getmailrc + subPath: getmailrc + readOnly: true - name: rt-config mountPath: /output readOnly: false @@ -265,36 +270,54 @@ spec: volumes: - name: rt-config-template configMap: - name: rt-config + name: {{ include "request-tracker.configName" . }} items: - key: rtSiteConfig path: RT_SiteConfig.pm - name: rt-config emptyDir: {} - name: msmtp-config - configMap: - name: rt-config + secret: + secretName: {{ include "request-tracker.mailSecretName" . }} items: - key: msmtp path: msmtp.conf - - name: getmailrc-config - configMap: - name: rt-config + - name: getmailrc-template + secret: + secretName: {{ include "request-tracker.mailSecretName" . }} items: - key: getmailrc path: getmailrc + - name: getmailrc-config + emptyDir: {} - name: rt-gpg + {{- if .Values.pvc.gpg.enabled }} persistentVolumeClaim: - claimName: rt-gpg + claimName: {{ include "request-tracker.fullname" . }}-gpg + {{- else }} + emptyDir: {} + {{- end }} - name: rt-smime + {{- if .Values.pvc.smime.enabled }} persistentVolumeClaim: - claimName: rt-smime + claimName: {{ include "request-tracker.fullname" . }}-smime + {{- else }} + emptyDir: {} + {{- end }} - name: rt-shredder + {{- if .Values.pvc.shredder.enabled }} persistentVolumeClaim: - claimName: rt-shredder + claimName: {{ include "request-tracker.fullname" . }}-shredder + {{- else }} + emptyDir: {} + {{- end }} - name: rt-cron + {{- if .Values.pvc.cron.enabled }} persistentVolumeClaim: - claimName: rt-cron + claimName: {{ include "request-tracker.fullname" . }}-cron + {{- else }} + emptyDir: {} + {{- end }} - name: tmp emptyDir: {} - name: mason-data @@ -304,16 +327,24 @@ spec: {{- end }} - name: caddy-configfile configMap: - name: rt-config + name: {{ include "request-tracker.configName" . }} items: - key: caddyfile path: Caddyfile - name: caddy-data + {{- if .Values.pvc.caddyData.enabled }} persistentVolumeClaim: - claimName: rt-caddy-data + claimName: {{ include "request-tracker.fullname" . }}-caddy-data + {{- else }} + emptyDir: {} + {{- end }} - name: caddy-config + {{- if .Values.pvc.caddyConfig.enabled }} persistentVolumeClaim: - claimName: rt-caddy-config + claimName: {{ include "request-tracker.fullname" . }}-caddy-config + {{- else }} + emptyDir: {} + {{- end }} {{- with .Values.caddy.volumes }} {{- toYaml . | nindent 8 }} {{- end }} diff --git a/helm/templates/hpa-rt.yaml b/helm/templates/hpa-rt.yaml index 085a9c4..dbfdac9 100644 --- a/helm/templates/hpa-rt.yaml +++ b/helm/templates/hpa-rt.yaml @@ -2,14 +2,14 @@ apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: - name: rt + name: {{ include "request-tracker.fullname" . }} labels: {{- include "request-tracker.labels" . | nindent 4 }} spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment - name: rt + name: {{ include "request-tracker.fullname" . }} minReplicas: {{ .Values.rt.autoscaling.minReplicas }} maxReplicas: {{ .Values.rt.autoscaling.maxReplicas }} metrics: diff --git a/helm/templates/ingress.yaml b/helm/templates/ingress.yaml index 2998d13..2341e6c 100644 --- a/helm/templates/ingress.yaml +++ b/helm/templates/ingress.yaml @@ -2,7 +2,7 @@ apiVersion: networking.k8s.io/v1 kind: Ingress metadata: - name: rt-ingress + name: {{ include "request-tracker.fullname" . }} labels: {{- include "request-tracker.labels" . | nindent 4 }} {{- with .Values.ingress.annotations }} @@ -35,7 +35,7 @@ spec: {{- end }} backend: service: - name: rt-caddy + name: {{ include "request-tracker.caddyName" $ }} port: number: {{ $.Values.caddy.service.port }} {{- end }} diff --git a/helm/templates/jobs.yaml b/helm/templates/jobs.yaml index db1ee90..ddfe9da 100644 --- a/helm/templates/jobs.yaml +++ b/helm/templates/jobs.yaml @@ -3,104 +3,89 @@ apiVersion: batch/v1 kind: CronJob metadata: - name: "{{ printf "rt-%s" .name | trunc -63 | replace "_" "-" }}" + name: "{{ printf "%s-%s" (include "request-tracker.fullname" $) .name | trunc 63 | trimSuffix "-" | replace "_" "-" }}" labels: {{- include "request-tracker.labels" $ | nindent 4 }} spec: - schedule: "{{ .schedule }}" + schedule: {{ .schedule | quote }} concurrencyPolicy: {{ .concurrencyPolicy | default "Forbid" }} - timeZone: {{ .timeZone | default "UTC" }} + timeZone: {{ .timeZone | default $.Values.timezone | default "UTC" | quote }} jobTemplate: spec: template: + metadata: + labels: + {{- include "request-tracker.selectorLabels" $ | nindent 12 }} + app.kubernetes.io/component: cron spec: - serviceAccountName: rt + serviceAccountName: {{ include "request-tracker.serviceAccountName" $ }} securityContext: - {{- toYaml .podSecurityContext | default $.Values.rt.podSecurityContext | nindent 12 }} + {{- toYaml (.podSecurityContext | default $.Values.rt.podSecurityContext) | nindent 12 }} + initContainers: + - name: generate-config + image: {{ $.Values.configRenderer.image | quote }} + imagePullPolicy: {{ $.Values.configRenderer.pullPolicy }} + securityContext: + {{- toYaml $.Values.configRenderer.securityContext | nindent 16 }} + command: ["sh", "-c", "gomplate -f /templates/RT_SiteConfig.pm -o /output/RT_SiteConfig.pm && gomplate -f /templates/getmailrc -o /output/getmailrc"] + env: + - name: RT_DB_HOST + value: {{ include "request-tracker.dbHost" $ | quote }} + - name: RT_CADDY_HOST + value: {{ include "request-tracker.mailgateName" $ | quote }} + {{- range $env, $key := dict "RT_DB_NAME" "dbname" "RT_DB_USER" "username" "RT_DB_PASS" "password" }} + - name: {{ $env }} + valueFrom: + secretKeyRef: + name: {{ include "request-tracker.dbSecretName" $ }} + key: {{ $key }} + {{- end }} + volumeMounts: + - {name: rt-config-template, mountPath: /templates/RT_SiteConfig.pm, subPath: RT_SiteConfig.pm, readOnly: true} + - {name: getmailrc-template, mountPath: /templates/getmailrc, subPath: getmailrc, readOnly: true} + - {name: generated-config, mountPath: /output} containers: - - name: "{{ printf "rt-%s" .name | trunc -63 | replace "_" "-" }}" - securityContext: - {{- toYaml (.securityContext | default $.Values.rt.securityContext) | nindent 14 }} - {{- $img := .image | default dict }} - image: "{{ $img.repository | default $.Values.rt.image.repository }}:{{ $img.tag | default (include "request-tracker.rtImageTag" $) }}" - imagePullPolicy: {{ $img.pullPolicy | default $.Values.rt.image.pullPolicy }} - {{- with $.Values.timezone }} - env: - - name: TZ - value: {{ . | quote }} - {{- end }} - command: - {{- toYaml .command | nindent 14 }} - {{- with .resources }} - resources: - {{- toYaml . | nindent 14 }} - {{- end }} - volumeMounts: - - name: rt-config - mountPath: /opt/rt/etc/RT_SiteConfig.pm - subPath: RT_SiteConfig.pm - readOnly: true - - name: msmtp-config - mountPath: /msmtp/msmtp.conf - subPath: msmtp.conf - readOnly: true - - name: getmailrc-config - mountPath: /getmailrc - subPath: getmailrc - readOnly: true - - name: getmail-dir - mountPath: /getmail - readOnly: false - - name: rt-gpg - mountPath: /opt/rt/var/data/gpg - readOnly: false - - name: rt-smime - mountPath: /opt/rt/var/data/smime - readOnly: true - - name: rt-shredder - mountPath: /opt/rt/var/data/RT-Shredder - readOnly: false - - name: rt-cron - mountPath: /cron - readOnly: false - {{- with $.Values.rt.volumeMounts }} - {{- toYaml . | nindent 12 }} - {{- end }} + - name: "{{ printf "rt-%s" .name | trunc 63 | trimSuffix "-" | replace "_" "-" }}" + securityContext: + {{- toYaml (.securityContext | default $.Values.rt.securityContext) | nindent 16 }} + {{- $img := .image | default dict }} + image: "{{ $img.repository | default $.Values.rt.image.repository }}:{{ $img.tag | default (include "request-tracker.rtImageTag" $) }}" + imagePullPolicy: {{ $img.pullPolicy | default $.Values.rt.image.pullPolicy }} + {{- with $.Values.timezone }} + env: + - {name: TZ, value: {{ . | quote }}} + {{- end }} + command: + {{- toYaml .command | nindent 16 }} + {{- with .resources }} + resources: + {{- toYaml . | nindent 16 }} + {{- end }} + volumeMounts: + - {name: generated-config, mountPath: /opt/rt/etc/RT_SiteConfig.pm, subPath: RT_SiteConfig.pm, readOnly: true} + - {name: msmtp-config, mountPath: /etc/msmtprc, subPath: msmtp.conf, readOnly: true} + - {name: generated-config, mountPath: /getmailrc, subPath: getmailrc, readOnly: true} + - {name: getmail-dir, mountPath: /getmail} + {{- with $.Values.rt.volumeMounts }} + {{- toYaml . | nindent 16 }} + {{- end }} volumes: - - name: rt-config + - name: rt-config-template configMap: - name: rt-config - items: - - key: rtSiteConfig - path: RT_SiteConfig.pm + name: {{ include "request-tracker.configName" $ }} + items: [{key: rtSiteConfig, path: RT_SiteConfig.pm}] + - name: getmailrc-template + secret: + secretName: {{ include "request-tracker.mailSecretName" $ }} + items: [{key: getmailrc, path: getmailrc}] - name: msmtp-config - configMap: - name: rt-config - items: - - key: msmtp - path: msmtp.conf - - name: getmailrc-config - configMap: - name: rt-config - items: - - key: getmailrc - path: getmailrc - - name: getmail-dir - emptyDir: {} - - name: rt-gpg - persistentVolumeClaim: - claimName: rt-gpg - - name: rt-smime - persistentVolumeClaim: - claimName: rt-smime - - name: rt-shredder - persistentVolumeClaim: - claimName: rt-shredder - - name: rt-cron - persistentVolumeClaim: - claimName: rt-cron - {{- with $.Values.rt.volumes }} + secret: + secretName: {{ include "request-tracker.mailSecretName" $ }} + items: [{key: msmtp, path: msmtp.conf}] + - {name: generated-config, emptyDir: {}} + - {name: getmail-dir, emptyDir: {}} + {{- with $.Values.rt.volumes }} {{- toYaml . | nindent 12 }} - {{- end }} + {{- end }} restartPolicy: {{ .restartPolicy | default "Never" }} {{- end }} diff --git a/helm/templates/networkpolicy.yaml b/helm/templates/networkpolicy.yaml index a45c625..1dd0b7a 100644 --- a/helm/templates/networkpolicy.yaml +++ b/helm/templates/networkpolicy.yaml @@ -2,7 +2,7 @@ apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: - name: rt + name: {{ include "request-tracker.fullname" . }} labels: {{- include "request-tracker.labels" . | nindent 4 }} spec: diff --git a/helm/templates/pdb.yaml b/helm/templates/pdb.yaml index 5876ea9..68eed75 100644 --- a/helm/templates/pdb.yaml +++ b/helm/templates/pdb.yaml @@ -2,7 +2,7 @@ apiVersion: policy/v1 kind: PodDisruptionBudget metadata: - name: rt + name: {{ include "request-tracker.fullname" . }} labels: {{- include "request-tracker.labels" . | nindent 4 }} spec: diff --git a/helm/templates/pvc-postgres.yaml b/helm/templates/pvc-postgres.yaml index d1fcf93..c2f2572 100644 --- a/helm/templates/pvc-postgres.yaml +++ b/helm/templates/pvc-postgres.yaml @@ -1,8 +1,10 @@ -{{- if .Values.postgres.enabled -}} +{{- if and .Values.postgres.enabled .Values.pvc.postgresData.enabled -}} apiVersion: v1 kind: PersistentVolumeClaim metadata: - name: rt-postgres-data + name: {{ include "request-tracker.fullname" . }}-postgres-data + annotations: + helm.sh/resource-policy: keep labels: {{- include "request-tracker.labels" . | nindent 4 }} spec: diff --git a/helm/templates/pvc.yaml b/helm/templates/pvc.yaml index fb21f5e..ac41fd2 100644 --- a/helm/templates/pvc.yaml +++ b/helm/templates/pvc.yaml @@ -2,7 +2,9 @@ apiVersion: v1 kind: PersistentVolumeClaim metadata: - name: rt-gpg + name: {{ include "request-tracker.fullname" . }}-gpg + annotations: + helm.sh/resource-policy: keep labels: {{- include "request-tracker.labels" . | nindent 4 }} spec: @@ -21,7 +23,9 @@ spec: apiVersion: v1 kind: PersistentVolumeClaim metadata: - name: rt-smime + name: {{ include "request-tracker.fullname" . }}-smime + annotations: + helm.sh/resource-policy: keep labels: {{- include "request-tracker.labels" . | nindent 4 }} spec: @@ -40,7 +44,9 @@ spec: apiVersion: v1 kind: PersistentVolumeClaim metadata: - name: rt-shredder + name: {{ include "request-tracker.fullname" . }}-shredder + annotations: + helm.sh/resource-policy: keep labels: {{- include "request-tracker.labels" . | nindent 4 }} spec: @@ -59,7 +65,9 @@ spec: apiVersion: v1 kind: PersistentVolumeClaim metadata: - name: rt-cron + name: {{ include "request-tracker.fullname" . }}-cron + annotations: + helm.sh/resource-policy: keep labels: {{- include "request-tracker.labels" . | nindent 4 }} spec: @@ -78,7 +86,9 @@ spec: apiVersion: v1 kind: PersistentVolumeClaim metadata: - name: rt-caddy-data + name: {{ include "request-tracker.fullname" . }}-caddy-data + annotations: + helm.sh/resource-policy: keep labels: {{- include "request-tracker.labels" . | nindent 4 }} spec: @@ -96,7 +106,9 @@ spec: apiVersion: v1 kind: PersistentVolumeClaim metadata: - name: rt-caddy-config + name: {{ include "request-tracker.fullname" . }}-caddy-config + annotations: + helm.sh/resource-policy: keep labels: {{- include "request-tracker.labels" . | nindent 4 }} spec: diff --git a/helm/templates/route.yaml b/helm/templates/route.yaml index 8931048..d6a3e70 100644 --- a/helm/templates/route.yaml +++ b/helm/templates/route.yaml @@ -2,7 +2,7 @@ kind: Route apiVersion: route.openshift.io/v1 metadata: - name: rt-route + name: {{ include "request-tracker.fullname" . }} labels: {{- include "request-tracker.labels" . | nindent 4 }} {{- with .Values.route.annotations }} @@ -18,5 +18,5 @@ spec: targetPort: http to: kind: Service - name: rt-caddy -{{- end }} \ No newline at end of file + name: {{ include "request-tracker.caddyName" . }} +{{- end }} diff --git a/helm/templates/secret-db.yaml b/helm/templates/secret-db.yaml index 78860a6..ab1e6a9 100644 --- a/helm/templates/secret-db.yaml +++ b/helm/templates/secret-db.yaml @@ -2,7 +2,7 @@ apiVersion: v1 kind: Secret metadata: - name: rt-db-creds + name: {{ include "request-tracker.dbSecretName" . }} labels: {{- include "request-tracker.labels" . | nindent 4 }} type: Opaque diff --git a/helm/templates/secret-mail.yaml b/helm/templates/secret-mail.yaml new file mode 100644 index 0000000..31e61c3 --- /dev/null +++ b/helm/templates/secret-mail.yaml @@ -0,0 +1,14 @@ +{{- if not .Values.mail.existingSecret }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "request-tracker.mailSecretName" . }} + labels: + {{- include "request-tracker.labels" . | nindent 4 }} +type: Opaque +stringData: + msmtp: |- +{{ .Values.mail.msmtp | indent 4 }} + getmailrc: |- +{{ .Values.mail.getmailrc | indent 4 }} +{{- end }} diff --git a/helm/templates/service-mailgate.yaml b/helm/templates/service-mailgate.yaml new file mode 100644 index 0000000..83eec01 --- /dev/null +++ b/helm/templates/service-mailgate.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "request-tracker.mailgateName" . }} + labels: + {{- include "request-tracker.labels" . | nindent 4 }} +spec: + type: ClusterIP + ports: + - port: {{ .Values.caddy.service.mailgatePort }} + targetPort: mailgate + protocol: TCP + name: mailgate + selector: + {{- include "request-tracker.selectorLabels" . | nindent 4 }} + app.kubernetes.io/component: rt diff --git a/helm/templates/service-postgres.yaml b/helm/templates/service-postgres.yaml index 8864024..28e49ca 100644 --- a/helm/templates/service-postgres.yaml +++ b/helm/templates/service-postgres.yaml @@ -2,7 +2,7 @@ apiVersion: v1 kind: Service metadata: - name: rt-db + name: {{ include "request-tracker.postgresName" . }} labels: {{- include "request-tracker.labels" . | nindent 4 }} app.kubernetes.io/component: postgres diff --git a/helm/templates/service-rt.yaml b/helm/templates/service-rt.yaml index 462ea55..b6e7e93 100644 --- a/helm/templates/service-rt.yaml +++ b/helm/templates/service-rt.yaml @@ -1,7 +1,7 @@ apiVersion: v1 kind: Service metadata: - name: rt-caddy + name: {{ include "request-tracker.caddyName" . }} labels: {{- include "request-tracker.labels" . | nindent 4 }} spec: @@ -11,9 +11,6 @@ spec: targetPort: http protocol: TCP name: rt - - port: {{ .Values.caddy.service.mailgatePort }} - targetPort: mailgate - protocol: TCP - name: mailgate selector: {{- include "request-tracker.selectorLabels" . | nindent 4 }} + app.kubernetes.io/component: rt diff --git a/helm/templates/serviceaccount.yaml b/helm/templates/serviceaccount.yaml index 77ba852..b061659 100644 --- a/helm/templates/serviceaccount.yaml +++ b/helm/templates/serviceaccount.yaml @@ -2,7 +2,7 @@ apiVersion: v1 kind: ServiceAccount metadata: - name: rt + name: {{ include "request-tracker.serviceAccountName" . }} labels: {{- include "request-tracker.labels" . | nindent 4 }} {{- with .Values.serviceAccount.annotations }} diff --git a/helm/values.yaml b/helm/values.yaml index 47e4cda..9c43d89 100644 --- a/helm/values.yaml +++ b/helm/values.yaml @@ -1,3 +1,6 @@ +nameOverride: "" +fullnameOverride: "" + rt: replicaCount: 1 autoscaling: @@ -28,9 +31,8 @@ rt: runAsUser: 1000 # the user id of the rt user in the container runAsGroup: 1000 # the group id of the rt user in the container allowPrivilegeEscalation: false - # capabilities: - # drop: - # - ALL + capabilities: + drop: ["ALL"] podSecurityContext: {} @@ -59,6 +61,18 @@ rt: # the port the RT-FCGI server listens on port: 9000 +configRenderer: + image: hairyhenderson/gomplate:v4.3.3-alpine + pullPolicy: IfNotPresent + securityContext: + readOnlyRootFilesystem: true + runAsNonRoot: true + runAsUser: 65534 + runAsGroup: 65534 + allowPrivilegeEscalation: false + capabilities: + drop: ["ALL"] + caddy: image: repository: caddy @@ -71,9 +85,9 @@ caddy: runAsNonRoot: true runAsUser: 65534 # nobody user in the caddy image runAsGroup: 65534 # nobody group in the caddy image - # capabilities: - # drop: - # - ALL + allowPrivilegeEscalation: false + capabilities: + drop: ["ALL"] resources: limits: @@ -136,9 +150,8 @@ postgres: runAsNonRoot: true runAsUser: 999 # postgres user in the postgres image runAsGroup: 999 # postgres group in the postgres image - # capabilities: - # drop: - # - ALL + capabilities: + drop: ["ALL"] podSecurityContext: fsGroup: 999 # postgres group in the postgres image @@ -159,10 +172,12 @@ postgres: type: ClusterIP port: 5432 -# Database credentials, consumed via the "rt-db-creds" Secret. +# Database credentials, consumed via a release-scoped Secret. db: + # Set this to an external PostgreSQL hostname when postgres.enabled is false. + host: "" # When true the chart creates the Secret from the values below. - # When false (default) you must create a Secret named "rt-db-creds" + # When false (default) you must provide the release-scoped credentials Secret # yourself (see dev-helm.sh) or point existingSecret at one. create: false # Use an already existing Secret instead of the chart-managed one. @@ -188,23 +203,24 @@ podDisruptionBudget: # docker-compose it is only bound to localhost. When enabled, only pods # carrying one of mailgateAllowLabels may reach it; the web port stays open. networkPolicy: - enabled: false + enabled: true # additional namespace/pod selectors allowed to reach the web port ingress: [] # pods allowed to reach the mailgate port (e.g. the getmail cronjob) mailgateAllowLabels: - app.kubernetes.io/name: rt + app.kubernetes.io/component: cron serviceAccount: create: true - automount: true + name: "" + automount: false annotations: {} podAnnotations: {} podLabels: {} ingress: - enabled: true + enabled: false className: "nginx" annotations: {} hosts: @@ -391,7 +407,7 @@ pvc: storageClass: "" size: 1Gi -config: +rtConfig: rtSiteConfig: | ### Base configuration ### Set($rtname, 'rt'); @@ -405,7 +421,7 @@ config: ### Database connection ### Set($DatabaseType, 'Pg' ); - Set($DatabaseHost, 'rt-db'); + Set($DatabaseHost, '{{ .Env.RT_DB_HOST }}'); Set($DatabasePort, '5432'); Set($DatabaseUser, '{{ .Env.RT_DB_USER }}'); Set($DatabasePassword, '{{ .Env.RT_DB_PASS }}'); @@ -416,7 +432,7 @@ config: ### GnuPG configuration ### Set(%GnuPG, - Enable => 1, + Enable => 0, GnuPG => 'gpg', Passphrase => undef, OutgoingMessagesFormat => 'RFC' @@ -432,8 +448,8 @@ config: ### SMIME configuration ### Set(%SMIME, - Enable => 1, - AcceptUntrustedCAs => 1, + Enable => 0, + AcceptUntrustedCAs => 0, OpenSSL => '/usr/bin/openssl', Keyring => '/opt/rt/var/data/smime', CAPath => '/opt/rt/var/data/smime/signing-ca.pem', @@ -444,6 +460,10 @@ config: ); 1; +mail: + # Use an existing Secret with the keys msmtp and getmailrc, or let the chart + # create one from these values. Do not commit real credentials to values files. + existingSecret: "" msmtp: | defaults @@ -477,15 +497,15 @@ config: user = rt group = rt # 8080 is the mailgate vhost - arguments = ("--url", "http://rt-caddy:8080/", "--queue", "general", "--action", "correspond",) + arguments = ("--url", "http://{{ .Env.RT_CADDY_HOST }}:8080/", "--queue", "general", "--action", "correspond",) [options] read_all = false delete = true verbose = 0 +config: caddyfile: | { - debug admin off auto_https off } diff --git a/k8s-jobs/db-init.yaml b/k8s-jobs/db-init.yaml index ebc01d5..4111779 100644 --- a/k8s-jobs/db-init.yaml +++ b/k8s-jobs/db-init.yaml @@ -4,12 +4,15 @@ metadata: name: db-init-job spec: ttlSecondsAfterFinished: 3600 # Clean up the job after 1 hour + backoffLimit: 2 + activeDeadlineSeconds: 600 template: spec: restartPolicy: Never + automountServiceAccountToken: false initContainers: - name: generate-config - image: "hairyhenderson/gomplate:stable-alpine" + image: "hairyhenderson/gomplate:v4.3.3-alpine" imagePullPolicy: IfNotPresent securityContext: readOnlyRootFilesystem: true @@ -31,20 +34,22 @@ spec: cpu: 50m memory: 64Mi env: + - name: RT_DB_HOST + value: rt-request-tracker-db - name: RT_DB_NAME valueFrom: secretKeyRef: - name: rt-db-creds + name: rt-request-tracker-db-creds key: dbname - name: RT_DB_USER valueFrom: secretKeyRef: - name: rt-db-creds + name: rt-request-tracker-db-creds key: username - name: RT_DB_PASS valueFrom: secretKeyRef: - name: rt-db-creds + name: rt-request-tracker-db-creds key: password volumeMounts: - name: rt-config-template @@ -69,8 +74,8 @@ spec: requests: cpu: 100m memory: 128Mi - image: "firefart/requesttracker:latest" # adjest the tag as needed - imagePullPolicy: "Always" + image: "firefart/requesttracker:6.0.3" # adjust the tag as needed + imagePullPolicy: "IfNotPresent" command: ["/opt/rt/sbin/rt-setup-database"] args: ["--action", "init", "--skip-create"] workingDir: /opt/rt @@ -91,7 +96,7 @@ spec: volumes: - name: rt-config-template configMap: - name: rt-config + name: rt-request-tracker-config items: - key: rtSiteConfig path: RT_SiteConfig.pm @@ -99,9 +104,9 @@ spec: emptyDir: {} - name: rt-gpg persistentVolumeClaim: - claimName: rt-gpg + claimName: rt-request-tracker-gpg - name: rt-smime persistentVolumeClaim: - claimName: rt-smime + claimName: rt-request-tracker-smime - name: tmp emptyDir: {} diff --git a/k8s-jobs/db-update.yaml b/k8s-jobs/db-update.yaml index c23900e..12d5e45 100644 --- a/k8s-jobs/db-update.yaml +++ b/k8s-jobs/db-update.yaml @@ -4,12 +4,15 @@ metadata: name: db-update-job spec: ttlSecondsAfterFinished: 3600 # Clean up the job after 1 hour + backoffLimit: 2 + activeDeadlineSeconds: 600 template: spec: restartPolicy: Never + automountServiceAccountToken: false initContainers: - name: generate-config - image: "hairyhenderson/gomplate:stable-alpine" + image: "hairyhenderson/gomplate:v4.3.3-alpine" imagePullPolicy: IfNotPresent securityContext: readOnlyRootFilesystem: true @@ -31,20 +34,22 @@ spec: cpu: 50m memory: 64Mi env: + - name: RT_DB_HOST + value: rt-request-tracker-db - name: RT_DB_NAME valueFrom: secretKeyRef: - name: rt-db-creds + name: rt-request-tracker-db-creds key: dbname - name: RT_DB_USER valueFrom: secretKeyRef: - name: rt-db-creds + name: rt-request-tracker-db-creds key: username - name: RT_DB_PASS valueFrom: secretKeyRef: - name: rt-db-creds + name: rt-request-tracker-db-creds key: password volumeMounts: - name: rt-config-template @@ -69,8 +74,8 @@ spec: requests: cpu: 100m memory: 128Mi - image: "firefart/requesttracker:latest" # adjest the tag as needed - imagePullPolicy: "Always" + image: "firefart/requesttracker:6.0.3" # adjust the tag as needed + imagePullPolicy: "IfNotPresent" command: ["/opt/rt/sbin/rt-setup-database"] args: ["--action", "upgrade", "--upgrade-from=4.4.2"] # adjust the version as needed workingDir: /opt/rt @@ -91,7 +96,7 @@ spec: volumes: - name: rt-config-template configMap: - name: rt-config + name: rt-request-tracker-config items: - key: rtSiteConfig path: RT_SiteConfig.pm @@ -99,9 +104,9 @@ spec: emptyDir: {} - name: rt-gpg persistentVolumeClaim: - claimName: rt-gpg + claimName: rt-request-tracker-gpg - name: rt-smime persistentVolumeClaim: - claimName: rt-smime + claimName: rt-request-tracker-smime - name: tmp emptyDir: {} diff --git a/k8s-jobs/install-ingress.sh b/k8s-jobs/install-ingress.sh index 209df2f..c04492e 100755 --- a/k8s-jobs/install-ingress.sh +++ b/k8s-jobs/install-ingress.sh @@ -1,3 +1,8 @@ #!/usr/bin/env bash -helm install --namespace kube-system nginx ingress-nginx --repo https://kubernetes.github.io/ingress-nginx +set -euo pipefail + +helm upgrade --install nginx ingress-nginx \ + --namespace ingress-nginx \ + --create-namespace \ + --repo https://kubernetes.github.io/ingress-nginx From 009274c5af1b6fa877c2a3a2b6049c0d326bb1f3 Mon Sep 17 00:00:00 2001 From: Christian Mehlmauer <105281+firefart@users.noreply.github.com> Date: Thu, 27 Aug 2026 09:33:47 +0200 Subject: [PATCH 2/3] update --- k8s-jobs/install-ingress.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/k8s-jobs/install-ingress.sh b/k8s-jobs/install-ingress.sh index c04492e..a96d109 100755 --- a/k8s-jobs/install-ingress.sh +++ b/k8s-jobs/install-ingress.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -set -euo pipefail +set -euf pipefail helm upgrade --install nginx ingress-nginx \ --namespace ingress-nginx \ From 4412a3a152278a708fcbc2543557a75c1b36c5e3 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Thu, 27 Aug 2026 09:36:18 +0200 Subject: [PATCH 3/3] Persist RT state volumes in Helm CronJobs (#100) Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: firefart <105281+firefart@users.noreply.github.com> --- helm/templates/jobs.yaml | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/helm/templates/jobs.yaml b/helm/templates/jobs.yaml index ddfe9da..3f7f3e4 100644 --- a/helm/templates/jobs.yaml +++ b/helm/templates/jobs.yaml @@ -66,6 +66,10 @@ spec: - {name: msmtp-config, mountPath: /etc/msmtprc, subPath: msmtp.conf, readOnly: true} - {name: generated-config, mountPath: /getmailrc, subPath: getmailrc, readOnly: true} - {name: getmail-dir, mountPath: /getmail} + - {name: rt-gpg, mountPath: /opt/rt/var/data/gpg, readOnly: false} + - {name: rt-smime, mountPath: /opt/rt/var/data/smime, readOnly: true} + - {name: rt-shredder, mountPath: /opt/rt/var/data/RT-Shredder, readOnly: false} + - {name: rt-cron, mountPath: /cron, readOnly: false} {{- with $.Values.rt.volumeMounts }} {{- toYaml . | nindent 16 }} {{- end }} @@ -84,6 +88,34 @@ spec: items: [{key: msmtp, path: msmtp.conf}] - {name: generated-config, emptyDir: {}} - {name: getmail-dir, emptyDir: {}} + - name: rt-gpg + {{- if $.Values.pvc.gpg.enabled }} + persistentVolumeClaim: + claimName: {{ include "request-tracker.fullname" $ }}-gpg + {{- else }} + emptyDir: {} + {{- end }} + - name: rt-smime + {{- if $.Values.pvc.smime.enabled }} + persistentVolumeClaim: + claimName: {{ include "request-tracker.fullname" $ }}-smime + {{- else }} + emptyDir: {} + {{- end }} + - name: rt-shredder + {{- if $.Values.pvc.shredder.enabled }} + persistentVolumeClaim: + claimName: {{ include "request-tracker.fullname" $ }}-shredder + {{- else }} + emptyDir: {} + {{- end }} + - name: rt-cron + {{- if $.Values.pvc.cron.enabled }} + persistentVolumeClaim: + claimName: {{ include "request-tracker.fullname" $ }}-cron + {{- else }} + emptyDir: {} + {{- end }} {{- with $.Values.rt.volumes }} {{- toYaml . | nindent 12 }} {{- end }}