From b6bba632702aeda82a58247ac5c3a32c3e692346 Mon Sep 17 00:00:00 2001 From: Dan Farrelly Date: Mon, 6 Jul 2026 17:28:08 -0400 Subject: [PATCH 1/3] Fix chart for maildev 2.x and repair chart publishing Fixes #5 and #6. The published chart was broken on two axes: 1. The chart still targeted the maildev 1.x interface (hardcoded flags, MAILDEV_DISABLE_WEB env var that no longer works in 2.x), so installs were misconfigured. 2. The release workflows used deprecated actions that no longer run on current GitHub runners, so no working chart release was ever published (gh-pages index.yaml still points at the dead splitt3r/helm assets). Chart changes (adapted from community PR #7 by @pando85 / @thibveni): - Bump appVersion 1.1.0 -> 2.2.1, chart version 0.1.3 -> 0.2.0 - Rename outgoing_relay -> outgoingRelay; image tag now follows appVersion - Replace hardcoded args with conditional flags (--verbose, --auto-relay, --outgoing-secure, --disable-web) - Drop the broken MAILDEV_DISABLE_WEB env var (use --disable-web) - Only emit outgoing-relay env vars when values are set; gate HTTPS key/cert on https.enabled - Add outgoingRelay.autoRelay toggle; render relay rules from values and gate the ConfigMap/volume on it; roll pods via checksum annotation - Keep the fullname-templated relay ConfigMap name (do not regress to the hardcoded name from PR #7) Workflow changes: - release.yaml: checkout@v4 (fetch-depth 0), setup-helm@v4, chart-releaser-action@v1.6.0, add contents:write permission so the default GITHUB_TOKEN can create releases - lint-test.yaml: modern chart-testing-action@v2 invocation (ct lint / ct install), checkout@v4, kind-action@v1.10.0 Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/lint-test.yaml | 42 ++++++++----- .github/workflows/release.yaml | 15 ++--- charts/maildev/Chart.yaml | 4 +- charts/maildev/README.md | 35 +++++------ .../templates/cm-auto-relay-rules.yaml | 4 +- charts/maildev/templates/deployment.yaml | 60 +++++++++++++------ charts/maildev/values.yaml | 55 ++++++++++------- 7 files changed, 131 insertions(+), 84 deletions(-) diff --git a/.github/workflows/lint-test.yaml b/.github/workflows/lint-test.yaml index c758ac4..5c60fe5 100644 --- a/.github/workflows/lint-test.yaml +++ b/.github/workflows/lint-test.yaml @@ -7,24 +7,38 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 + with: + fetch-depth: 0 - - name: Fetch history - run: git fetch --prune --unshallow + - name: Set up Helm + uses: azure/setup-helm@v4 + with: + version: v3.16.2 - - name: Run chart-testing (lint) - id: lint - uses: helm/chart-testing-action@v1.0.0 + - name: Set up Python + uses: actions/setup-python@v5 with: - command: lint - config: ct.yaml + python-version: '3.x' + + - name: Set up chart-testing + uses: helm/chart-testing-action@v2.6.1 + + - name: Run chart-testing (list-changed) + id: list-changed + run: | + changed=$(ct list-changed --config ct.yaml) + if [[ -n "$changed" ]]; then + echo "changed=true" >> "$GITHUB_OUTPUT" + fi + + - name: Run chart-testing (lint) + run: ct lint --config ct.yaml - name: Create kind cluster - uses: helm/kind-action@v1.0.0 - if: steps.lint.outputs.changed == 'true' + uses: helm/kind-action@v1.10.0 + if: steps.list-changed.outputs.changed == 'true' - name: Run chart-testing (install) - uses: helm/chart-testing-action@v1.0.0 - with: - command: install - config: ct.yaml + run: ct install --config ct.yaml + if: steps.list-changed.outputs.changed == 'true' diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index cf65ada..9b20471 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -8,12 +8,13 @@ on: jobs: release: runs-on: ubuntu-latest + permissions: + contents: write steps: - name: Checkout - uses: actions/checkout@v2 - - - name: Fetch history - run: git fetch --prune --unshallow + uses: actions/checkout@v4 + with: + fetch-depth: 0 - name: Configure Git run: | @@ -21,11 +22,11 @@ jobs: git config user.email "$GITHUB_ACTOR@users.noreply.github.com" - name: Install Helm - uses: azure/setup-helm@v1 + uses: azure/setup-helm@v4 with: - version: v3.4.0 + version: v3.16.2 - name: Run chart-releaser - uses: helm/chart-releaser-action@v1.0.0 + uses: helm/chart-releaser-action@v1.6.0 env: CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}" diff --git a/charts/maildev/Chart.yaml b/charts/maildev/Chart.yaml index cd73dd4..cab8044 100644 --- a/charts/maildev/Chart.yaml +++ b/charts/maildev/Chart.yaml @@ -1,7 +1,7 @@ apiVersion: v2 name: maildev -version: 0.1.3 -appVersion: 1.1.0 +version: 0.2.0 +appVersion: 2.2.1 type: application description: SMTP Server + Web Interface for viewing and testing emails during development. keywords: diff --git a/charts/maildev/README.md b/charts/maildev/README.md index faa3cb3..45d25b9 100644 --- a/charts/maildev/README.md +++ b/charts/maildev/README.md @@ -16,30 +16,27 @@ even if the `/tmp/maildev` folder, where MailDev stores mails, is persisted. MailDev source code can be found here: https://github.com/maildev/maildev. -## Known issue with Env Vars - -GitHub issue: https://github.com/maildev/maildev/issues/315 - -So, not every option can be configured using env vars, so, a few options are hardcoded in the deployment: -`["--verbose", "--outgoing-secure", "--auto-relay"]` - ## Configuration Table with the most relevant parameters for MailDev. Not listing here the more general paramaters such as tolerations, nodeSelectors, etc. -| Parameter | Description | Default | -|------------------------------:|:--------------------------------------------------------------------------------------------------|:--------------------------------------------| -| **outgoing_relay.host** | SMTP Relay host, `MAILDEV_OUTGOING_HOST`. | `` | -| **outgoing_relay.port** | SMTP Relay port, `MAILDEV_OUTGOING_PORT`. | `` | -| **outgoing_relay.user** | SMTP Relay user, `MAILDEV_OUTGOING_USER`. | `` | -| **outgoing_relay.pass** | SMTP Relay password, `MAILDEV_OUTGOING_PASS`. | `` | -| **outgoing_relay.secure** | Use SMTP SSL for outgoing emails, `MAILDEV_OUTGOING_SECURE`. | `true`. Hardcoded in the deployment due to a bug. | -| **ports.smtp** | Port where the SMTP service is listening. (Irrelevant for OCP/K8S), `MAILDEV_SMTP_PORT`. | `1025` | -| **ports.web** | Port where the Web interface service is listening. (Irrelevant for OCP/K8S), `MAILDEV_WEB_PORT`. | `1080` | -| **web.disable** | Disable Web interface. `MAILDEV_DISABLE_WEB`. | `false` | -| **web.user** | Web interface user, `MAILDEV_WEB_USER`. | `admin` | -| **web.pass** | Web interface password, `MAILDEV_WEB_PASS`. | `` | +| Parameter | Description | Default | +|-------------------------------------:|:--------------------------------------------------------------------------------------------------|:--------------------------------------------| +| **verbose** | Enable verbose logging, `--verbose`. | `false` | +| **outgoingRelay.host** | SMTP Relay host, `MAILDEV_OUTGOING_HOST`. Only set when defined. | `` | +| **outgoingRelay.port** | SMTP Relay port, `MAILDEV_OUTGOING_PORT`. Only set when defined. | `` | +| **outgoingRelay.user** | SMTP Relay user, `MAILDEV_OUTGOING_USER`. Only set when defined. | `` | +| **outgoingRelay.pass** | SMTP Relay password, `MAILDEV_OUTGOING_PASS`. Only set when defined. | `` | +| **outgoingRelay.secure** | Use SMTP SSL for outgoing emails, `--outgoing-secure`. | `false` | +| **outgoingRelay.autoRelay.enabled** | Relay all incoming emails to the outgoing relay, `--auto-relay`. | `false` | +| **outgoingRelay.autoRelay.receiver** | Relay to a single receiver instead of the original recipient, `MAILDEV_AUTO_RELAY`. | `` | +| **outgoingRelay.autoRelay.rules** | Auto relay rules rendered to `auto-relay-rules.json`, `MAILDEV_AUTO_RELAY_RULES`. | `[{allow: '*'}]` | +| **ports.smtp** | Port where the SMTP service is listening. (Irrelevant for OCP/K8S), `MAILDEV_SMTP_PORT`. | `1025` | +| **ports.web** | Port where the Web interface service is listening. (Irrelevant for OCP/K8S), `MAILDEV_WEB_PORT`. | `1080` | +| **web.disable** | Disable Web interface, `--disable-web`. | `false` | +| **web.user** | Web interface user, `MAILDEV_WEB_USER`. Only set when defined. | `` | +| **web.pass** | Web interface password, `MAILDEV_WEB_PASS`. Only set when defined. | `` | | **https.enabled** | Switch from http to https protocol, `MAILDEV_HTTPS`. | `false` | | **https.key** | The file path to the ssl private key, `MAILDEV_HTTPS_KEY`. | | | **https.cert** | The file path to the ssl cert file, `MAILDEV_HTTPS_CERT`. | | diff --git a/charts/maildev/templates/cm-auto-relay-rules.yaml b/charts/maildev/templates/cm-auto-relay-rules.yaml index a1413f0..bd54538 100644 --- a/charts/maildev/templates/cm-auto-relay-rules.yaml +++ b/charts/maildev/templates/cm-auto-relay-rules.yaml @@ -1,3 +1,4 @@ +{{- if .Values.outgoingRelay.autoRelay.enabled -}} apiVersion: v1 kind: ConfigMap metadata: @@ -5,4 +6,5 @@ metadata: labels: {{- include "maildev.labels" . | nindent 4 }} data: - auto-relay-rules.json: "[\n\t{ \"allow\": \"*\" }\n]\n" + auto-relay-rules.json: '{{ .Values.outgoingRelay.autoRelay.rules | toJson }}' +{{- end -}} diff --git a/charts/maildev/templates/deployment.yaml b/charts/maildev/templates/deployment.yaml index 0b19223..9ec564a 100644 --- a/charts/maildev/templates/deployment.yaml +++ b/charts/maildev/templates/deployment.yaml @@ -11,10 +11,11 @@ spec: {{- include "maildev.selectorLabels" . | nindent 6 }} template: metadata: - {{- with .Values.podAnnotations }} annotations: + checksum/cm-auto-relay-rules: {{ include (print $.Template.BasePath "/cm-auto-relay-rules.yaml") . | sha256sum }} + {{- with .Values.podAnnotations }} {{- toYaml . | nindent 8 }} - {{- end }} + {{- end }} labels: {{- include "maildev.selectorLabels" . | nindent 8 }} spec: @@ -30,8 +31,19 @@ spec: securityContext: {{- toYaml .Values.securityContext | nindent 12 }} image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" - command: ["/usr/src/app/bin/maildev"] - args: ["--verbose", "--outgoing-secure", "--auto-relay"] + args: + {{- if .Values.verbose }} + - "--verbose" + {{- end }} + {{- if .Values.outgoingRelay.autoRelay.enabled }} + - "--auto-relay" + {{- end }} + {{- if .Values.outgoingRelay.secure }} + - "--outgoing-secure" + {{- end }} + {{- if .Values.web.disable }} + - "--disable-web" + {{- end }} imagePullPolicy: {{ .Values.image.pullPolicy }} ports: - name: smtp-port @@ -41,8 +53,6 @@ spec: containerPort: {{ .Values.ports.web }} protocol: TCP env: - - name: MAILDEV_DISABLE_WEB - value: "{{ .Values.web.disable }}" {{- if or .Values.web.user .Values.web.pass}} - name: MAILDEV_WEB_USER value: "{{ .Values.web.user }}" @@ -55,24 +65,36 @@ spec: value: "{{ .Values.ports.web }}" - name: MAILDEV_HTTPS value: "{{ .Values.https.enabled }}" - {{- if .Values.https.key }} + {{- if .Values.https.enabled }} - name: MAILDEV_HTTPS_KEY value: "{{ .Values.https.key }}" - {{- end }} - {{- if .Values.https.cert }} - name: MAILDEV_HTTPS_CERT value: "{{ .Values.https.cert }}" {{- end }} + {{- if .Values.outgoingRelay.host }} - name: MAILDEV_OUTGOING_HOST - value: "{{ .Values.outgoing_relay.host }}" + value: "{{ .Values.outgoingRelay.host }}" + {{- end }} + {{- if .Values.outgoingRelay.port }} - name: MAILDEV_OUTGOING_PORT - value: "{{ .Values.outgoing_relay.port }}" + value: "{{ .Values.outgoingRelay.port }}" + {{- end }} + {{- if .Values.outgoingRelay.user }} - name: MAILDEV_OUTGOING_USER - value: "{{ .Values.outgoing_relay.user }}" + value: "{{ .Values.outgoingRelay.user }}" + {{- end }} + {{- if .Values.outgoingRelay.pass }} - name: MAILDEV_OUTGOING_PASS - value: "{{ .Values.outgoing_relay.pass }}" - - name: MAILDEV_OUTGOING_SECURE - value: "{{ .Values.outgoing_relay.secure }}" + value: "{{ .Values.outgoingRelay.pass }}" + {{- end }} + {{- if .Values.outgoingRelay.autoRelay.enabled }} + - name: MAILDEV_AUTO_RELAY_RULES + value: /etc/maildev/auto-relay-rules.json + {{- if .Values.outgoingRelay.autoRelay.receiver }} + - name: MAILDEV_AUTO_RELAY + value: "{{ .Values.outgoingRelay.autoRelay.receiver }}" + {{- end }} + {{- end }} {{- if .Values.incoming }} - name: MAILDEV_INCOMING_USER value: "{{ .Values.incoming.user }}" @@ -89,17 +111,17 @@ spec: port: {{ .Values.ports.web }} resources: {{- toYaml .Values.resources | nindent 12 }} + {{- if .Values.outgoingRelay.autoRelay.enabled }} volumeMounts: - name: auto-relay-rules mountPath: /etc/maildev - subPath: auto-relay-rules.json + {{- end }} + {{- if .Values.outgoingRelay.autoRelay.enabled }} volumes: - name: auto-relay-rules configMap: name: {{ include "maildev.fullname" . }}-relay-rules - items: - - key: auto-relay-rules.json - path: auto-relay-rules.json + {{- end }} {{- with .Values.nodeSelector }} nodeSelector: {{- toYaml . | nindent 8 }} diff --git a/charts/maildev/values.yaml b/charts/maildev/values.yaml index 9212fa3..9d12bb7 100644 --- a/charts/maildev/values.yaml +++ b/charts/maildev/values.yaml @@ -4,24 +4,35 @@ image: repository: maildev/maildev pullPolicy: IfNotPresent # Overrides the image tag whose default is the chart appVersion. - tag: 1.1.0 - -outgoing_relay: - # MAILDEV_OUTGOING_HOST - host: smtp.gmail.com - # MAILDEV_OUTGOING_PORT - port: 465 - # MAILDEV_OUTGOING_USER - user: 'XXX' - # MAILDEV_OUTGOING_PASS - pass: 'YYY' - # MAILDEV_OUTGOING_SECURE - secure: true - -incoming: - # MAILDEV_INCOMING_USER + tag: "" + +# Enable verbose logging (--verbose). +verbose: false + +outgoingRelay: + # # MAILDEV_OUTGOING_HOST + # host: smtp.gmail.com + # # MAILDEV_OUTGOING_PORT + # port: 465 + # # MAILDEV_OUTGOING_USER + # user: 'XXX' + # # MAILDEV_OUTGOING_PASS + # pass: 'YYY' + # Use SMTP SSL for outgoing emails (--outgoing-secure). + secure: false + autoRelay: + # Relay all incoming emails to the outgoing SMTP relay (--auto-relay). + enabled: false + # Relay to a single receiver instead of the original recipient, MAILDEV_AUTO_RELAY. + # receiver: test@example.com + # Auto relay rules, rendered to the auto-relay-rules.json config file. + rules: + - allow: '*' + +incoming: {} + # # MAILDEV_INCOMING_USER # user: - # MAILDEV_INCOMING_PASS + # # MAILDEV_INCOMING_PASS # pass: ports: @@ -40,12 +51,12 @@ https: # Web interface web: - # MAILDEV_DISABLE_WEB + # Disable the web interface (--disable-web). disable: false - # MAILDEV_WEB_USER - user: admin - # MAILDEV_WEB_PASS - pass: admin + # # MAILDEV_WEB_USER + # user: admin + # # MAILDEV_WEB_PASS + # pass: admin imagePullSecrets: [] nameOverride: "" From 1f9196e67a78931f49e95b55529be93b00086f55 Mon Sep 17 00:00:00 2001 From: Dan Farrelly Date: Mon, 6 Jul 2026 17:41:10 -0400 Subject: [PATCH 2/3] Only set MAILDEV_HTTPS when HTTPS is enabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit maildev parses env vars as `process.env[VAR] || default`, so the string "false" is truthy and enables HTTPS. With HTTPS on but no cert, web.js (lib/web.js:80) logs an error and returns before starting the web server, so /healthz is refused, the liveness probe kills the pod, and maildev crashes on shutdown (io.close on an uninitialized io) — the chart-testing install failure on CI. Emit MAILDEV_HTTPS (as "true") only when https.enabled is set, alongside the key/cert, so the default HTTP path works. Verified against maildev/maildev:2.2.1: with the var omitted /healthz returns 200; with MAILDEV_HTTPS=false the web server never starts. Co-Authored-By: Claude Opus 4.8 (1M context) --- charts/maildev/templates/deployment.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/charts/maildev/templates/deployment.yaml b/charts/maildev/templates/deployment.yaml index 9ec564a..03d7e62 100644 --- a/charts/maildev/templates/deployment.yaml +++ b/charts/maildev/templates/deployment.yaml @@ -63,9 +63,9 @@ spec: value: "{{ .Values.ports.smtp }}" - name: MAILDEV_WEB_PORT value: "{{ .Values.ports.web }}" - - name: MAILDEV_HTTPS - value: "{{ .Values.https.enabled }}" {{- if .Values.https.enabled }} + - name: MAILDEV_HTTPS + value: "true" - name: MAILDEV_HTTPS_KEY value: "{{ .Values.https.key }}" - name: MAILDEV_HTTPS_CERT From 1e950b5b022e37ab90ab74cd043027c9d09fb838 Mon Sep 17 00:00:00 2001 From: Dan Farrelly Date: Mon, 6 Jul 2026 17:55:58 -0400 Subject: [PATCH 3/3] Add extraArgs and extraEnv escape hatches MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adopt the flexibility idea from #8 (thanks @LordGaav) without giving up the structured, documented values. extraArgs are appended after the chart-generated flags and extraEnv is passed through verbatim, so users can set any maildev option the chart does not model — including env from Secrets via valueFrom, which a plain env map cannot express. Co-Authored-By: Claude Opus 4.8 (1M context) --- charts/maildev/README.md | 4 +++- charts/maildev/templates/deployment.yaml | 6 ++++++ charts/maildev/values.yaml | 17 +++++++++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/charts/maildev/README.md b/charts/maildev/README.md index 45d25b9..57e194e 100644 --- a/charts/maildev/README.md +++ b/charts/maildev/README.md @@ -23,7 +23,9 @@ Not listing here the more general paramaters such as tolerations, nodeSelectors, | Parameter | Description | Default | |-------------------------------------:|:--------------------------------------------------------------------------------------------------|:--------------------------------------------| -| **verbose** | Enable verbose logging, `--verbose`. | `false` | +| **verbose** | Enable verbose logging, `--verbose`. | `false` | +| **extraArgs** | Extra CLI args appended after the chart-generated flags, for options not modelled below. | `[]` | +| **extraEnv** | Extra container env vars (list of `name`/`value` or `valueFrom` entries), for options not modelled below. | `[]` | | **outgoingRelay.host** | SMTP Relay host, `MAILDEV_OUTGOING_HOST`. Only set when defined. | `` | | **outgoingRelay.port** | SMTP Relay port, `MAILDEV_OUTGOING_PORT`. Only set when defined. | `` | | **outgoingRelay.user** | SMTP Relay user, `MAILDEV_OUTGOING_USER`. Only set when defined. | `` | diff --git a/charts/maildev/templates/deployment.yaml b/charts/maildev/templates/deployment.yaml index 03d7e62..35212de 100644 --- a/charts/maildev/templates/deployment.yaml +++ b/charts/maildev/templates/deployment.yaml @@ -44,6 +44,9 @@ spec: {{- if .Values.web.disable }} - "--disable-web" {{- end }} + {{- with .Values.extraArgs }} + {{- toYaml . | nindent 10 }} + {{- end }} imagePullPolicy: {{ .Values.image.pullPolicy }} ports: - name: smtp-port @@ -101,6 +104,9 @@ spec: - name: MAILDEV_INCOMING_PASS value: "{{ .Values.incoming.pass }}" {{- end }} + {{- with .Values.extraEnv }} + {{- toYaml . | nindent 10 }} + {{- end }} livenessProbe: httpGet: path: /healthz diff --git a/charts/maildev/values.yaml b/charts/maildev/values.yaml index 9d12bb7..90f115d 100644 --- a/charts/maildev/values.yaml +++ b/charts/maildev/values.yaml @@ -9,6 +9,23 @@ image: # Enable verbose logging (--verbose). verbose: false +# Escape hatches for maildev options this chart does not model directly. +# See https://github.com/maildev/maildev#usage for all flags/env vars. +# Extra CLI args appended after the flags the chart generates, e.g.: +# extraArgs: +# - --hide-extensions +# - STARTTLS +extraArgs: [] +# Extra container env vars, passed through verbatim (supports valueFrom). +# Quote string/numeric values yourself, e.g.: +# extraEnv: +# - name: MAILDEV_OUTGOING_PASS +# valueFrom: +# secretKeyRef: +# name: maildev-smtp +# key: password +extraEnv: [] + outgoingRelay: # # MAILDEV_OUTGOING_HOST # host: smtp.gmail.com