Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
142 changes: 142 additions & 0 deletions charts/lerian-notification/docs/UPGRADE-1.0.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
# Helm Upgrade from v0.x to v1.x

## Topics

- **[Overview](#overview)**
- **[Features](#features)**
- [1. Migrations Job rewritten to invoke `/migrate` directly](#1-migrations-job-rewritten-to-invoke-migrate-directly)
- [2. New required value: `secrets.DATABASE_URL`](#2-new-required-value-secretsdatabase_url)
- [3. PSS-restricted Pod Security Context defaults](#3-pss-restricted-pod-security-context-defaults)
- [4. Deterministic ConfigMap / Secret key ordering](#4-deterministic-configmap--secret-key-ordering)
- [5. HPA fails fast when autoscaling is enabled without a target metric](#5-hpa-fails-fast-when-autoscaling-is-enabled-without-a-target-metric)
- [6. PDB respects explicit `maxUnavailable: 0`](#6-pdb-respects-explicit-maxunavailable-0)
- [7. Redis retry-backoff defaults corrected](#7-redis-retry-backoff-defaults-corrected)
- **[Configuration Changes](#configuration-changes)**
- **[Migration Steps](#migration-steps)**
- **[Preview changes before upgrading](#preview-changes-before-upgrading)**
- **[Command to upgrade](#command-to-upgrade)**

## Overview

This guide covers the `lerian-notification` chart upgrade from `0.1.0` to `1.0.0-beta.3`. The application image (`appVersion: 0.1.0`) is unchanged, but the chart is now production-shaped: the migrations Job is rewritten for distroless, the security context defaults align with the Kubernetes Pod Security Standards restricted profile, and several rendering bugs (HPA, PDB, Redis defaults) are fixed.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if stable 1.0.0 is published in the OCI registry
helm show chart oci://registry-1.docker.io/lerianstudio/lerian-notification-helm --version 1.0.0 2>&1 || echo "Stable 1.0.0 not found"
helm show chart oci://registry-1.docker.io/lerianstudio/lerian-notification-helm --version 1.0.0-beta.3 2>&1 || echo "Beta 1.0.0-beta.3 not found"

Repository: LerianStudio/helm

Length of output: 198


🏁 Script executed:

#!/bin/bash
set -euo pipefail
FILE="charts/lerian-notification/docs/UPGRADE-1.0.md"
if [ ! -f "$FILE" ]; then echo "Missing $FILE"; exit 1; fi
nl -ba "$FILE" | sed -n '1,220p'

Repository: LerianStudio/helm

Length of output: 104


🌐 Web query:

lerianstudio l erian-notification-helm 1.0.0 chart version

💡 Result:

Chart version for lerianstudio/lerian-notification-helm 1.0.0: 1.0.0. Lerian’s Helm chart version compatibility documentation shows that Helm chart version 1.0.0 corresponds to appVersion 1.0.0 (i.e., chart version and app version are the same for 1.0.0) [1].

Citations:


🌐 Web query:

oci://registry-1.docker.io/lerianstudio/lerian-notification-helm versions 1.0.0

💡 Result:

There is no publicly available evidence of a Helm chart named oci://registry-1.docker.io/lerianstudio/lerian-notification-helm [1][2][3]. While Lerian Studio maintains a repository of OCI-based Helm charts for their platform—including components like Midaz, plugins, and infrastructure tools like tracer-helm and reporter-helm [1][2][3][4][5]—the specific chart path provided does not appear in their official documentation or public registries [2][3][5]. If you are looking for a notification-related component within the Lerian ecosystem, it is recommended to check their official documentation index at https://docs.lerian.studio/en/platform/helm/helm-overview or consult the version compatibility matrix provided in their platform documentation [2][3][4].

Citations:


🌐 Web query:

lerian-notification-helm 1.0.0-beta.3 release

💡 Result:

I could not find any authoritative release information for “lerian-notification-helm” version “1.0.0-beta.3”. The closest matches in search results are: 1) A GitHub release tag “v1.0.0-beta.3” under the unrelated repository “LerianStudio/lib-observability” (published 2026-05-13) [1]. 2) Lerian’s Helm chart docs and repo overview pages, which describe Lerian’s Helm chart distribution (OCI registry) and versioning scheme, but do not mention a chart named “lerian-notification-helm” or a “1.0.0-beta.3” release for it [2][3]. 3) A Lerian Helm charts repository readme that shows chart version mappings for various products/plugins, but again no “lerian-notification-helm” chart name or the specific beta release tag appears in the surfaced material [4]. If you can share the exact chart repository/OCI path (e.g., something like oci://registry-1.docker.io/lerianstudio/) or a link to the release page you mean, I can precisely pull the “1.0.0-beta.3” release notes/artifacts and summarize them.

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail
FILE="charts/lerian-notification/docs/UPGRADE-1.0.md"
test -f "$FILE" || { echo "Missing $FILE"; exit 1; }

echo "=== Title & first 120 lines (with line numbers) ==="
awk '{printf "%5d %s\n", NR, $0}' "$FILE" | sed -n '1,120p'

echo
echo "=== Version-related references ==="
rg -n "beta|1\.0\.0|v1\.x|v0\.x" "$FILE" || true

Repository: LerianStudio/helm

Length of output: 9821


Align the upgrade target/version in UPGRADE-1.0.md title with the documented destination

The guide title says v1.x (line 1), but the content consistently targets 1.0.0-beta.3 (overview line 21, version table line 83, and upgrade commands lines 133/141). Update the title to v1.0.0-beta.3 (or switch all 1.0.0-beta.3 references to 1.0.0 if that’s the intended stable target).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@charts/lerian-notification/docs/UPGRADE-1.0.md` at line 21, The document
title in UPGRADE-1.0.md currently reads "v1.x" but the body targets
"1.0.0-beta.3"; update the title string "v1.x" to "v1.0.0-beta.3" so it matches
the overview line and all version references (search for the title header and
replace it), ensuring consistency with the documented destination version
throughout the file; alternatively, if the intended target is a stable release,
change all occurrences of "1.0.0-beta.3" in the document (overview, version
table, and upgrade commands) to "1.0.0" instead—pick one approach and apply it
consistently.


This is a **breaking** chart upgrade. A new value, `secrets.DATABASE_URL`, is required when `migrations.enabled` is true. Read [Migration Steps](#migration-steps) before upgrading.

## Features

### 1. Migrations Job rewritten to invoke `/migrate` directly

Previously the migrations Job ran a `/bin/sh -ec` script that assembled a DSN at runtime from `POSTGRES_*` env vars (URL-encoding the password with `od | sed`). Starting at `lerian-notification` v1.0.0-beta.2 the API image is distroless and bundles a static `/migrate` binary; there is no shell to run the old script.

The Job now:

- Sets `command: ["/migrate"]` and passes a fixed `args` list (`-path /migrations -database $(DATABASE_URL) ... up`).
- Reads `DATABASE_URL` either from `.Values.secrets.DATABASE_URL` (rendered into the chart's Secret) or, when `.Values.secretRef.name` is set, from a `DATABASE_URL` key inside that externally-managed Secret.
- No longer sets `serviceAccountName` on the hook pod. Helm applies hook resources before the chart's ServiceAccount, so the Job now uses the namespace's default SA, which always exists at hook time.

### 2. New required value: `secrets.DATABASE_URL`

The migrations Job no longer assembles a DSN from `POSTGRES_USER` / `POSTGRES_PASSWORD` / `POSTGRES_HOST` etc. You must provide a pre-built, URL-escaped Postgres DSN:

```yaml
secrets:
DATABASE_URL: "postgres://USER:URLENCODED_PW@HOST:PORT/DB?sslmode=disable"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Use a secure SSL mode in the DATABASE_URL example.

The example shows sslmode=disable, which disables encryption for database connections and is inappropriate for production. Update the example to use sslmode=require or sslmode=verify-full, or add an explicit warning that the shown mode is for local development only.

🔒 Proposed fix for secure default
-  DATABASE_URL: "postgres://USER:URLENCODED_PW@HOST:PORT/DB?sslmode=disable"
+  DATABASE_URL: "postgres://USER:URLENCODED_PW@HOST:PORT/DB?sslmode=require"

Or add a warning if the insecure mode is intentional for the example:

+> **Security:** The example shows `sslmode=disable` for simplicity. Production deployments should use `sslmode=require` or `sslmode=verify-full`.
+
 ```yaml
 secrets:
   DATABASE_URL: "postgres://USER:URLENCODED_PW@HOST:PORT/DB?sslmode=disable"
</details>

<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

```suggestion
  DATABASE_URL: "postgres://USER:URLENCODED_PW@HOST:PORT/DB?sslmode=require"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@charts/lerian-notification/docs/UPGRADE-1.0.md` at line 43, The DATABASE_URL
example currently uses an insecure query parameter ("sslmode=disable"); update
the example value (the DATABASE_URL secret string) to use a secure SSL mode such
as "sslmode=require" or "sslmode=verify-full", or, if keeping "sslmode=disable"
for local/dev only, add an explicit inline warning comment alongside the
DATABASE_URL example stating it is for local development only and must not be
used in production.

```

If you reference an external Secret via `secretRef.name`, that Secret must contain a `DATABASE_URL` key with the same shape.

> **Note:** Special characters in the password must be percent-encoded by the consumer (typically via ArgoCD Vault Plugin or your secrets pipeline) before being placed in `DATABASE_URL`. The chart does not URL-encode at render time.

### 3. PSS-restricted Pod Security Context defaults

Every component (`api`, `migrations`, `workerEmail`, `workerSms`, `workerWebhook`) now ships with the two fields required to land cleanly inside a Pod Security Standards "restricted" namespace:

```yaml
securityContext:
allowPrivilegeEscalation: false
seccompProfile:
type: RuntimeDefault
```

These are added on top of the existing `runAsNonRoot`, `runAsUser: 65532`, `runAsGroup: 65532`, `capabilities.drop: [ALL]`, and `readOnlyRootFilesystem: true` defaults from v0.1.0.

### 4. Deterministic ConfigMap / Secret key ordering

`templates/configmap.yaml` and `templates/secret.yaml` now iterate keys via `keys ... | sortAlpha` instead of ranging over the map directly. Rendered output is stable, so identical values no longer produce a diff because of Go map iteration order. `extraConfig` also now applies the same version-key exclusion (`VERSION`, `OTEL_RESOURCE_SERVICE_VERSION`, `SWAGGER_VERSION`) that `config` already had.

### 5. HPA fails fast when autoscaling is enabled without a target metric

`templates/api/hpa.yaml` previously rendered an empty `metrics: []` block when neither `targetCPUUtilizationPercentage` nor `targetMemoryUtilizationPercentage` was set, producing an HPA that the API server would reject at apply time. The template now `{{ fail }}`s at render time with a clear message:

```
api.autoscaling.enabled=true requires targetCPUUtilizationPercentage and/or targetMemoryUtilizationPercentage
```

### 6. PDB respects explicit `maxUnavailable: 0`

`templates/api/pdb.yaml` previously used `{{- with .Values.api.pdb.maxUnavailable }}`, which skips the value when it is `0` (Helm's `with` treats `0` as empty). The template now uses an explicit `hasKey` / `ne nil` check, so setting `api.pdb.maxUnavailable: 0` is honored instead of silently falling through to `minAvailable`.

### 7. Redis retry-backoff defaults corrected

The `REDIS_MIN_RETRY_BACKOFF` and `REDIS_MAX_RETRY_BACKOFF` defaults were inverted in v0.1.0 (min `8`, max `1`). They are now `min: 1`, `max: 8`:

| Setting | v0.1.0 | v1.0.0-beta.3 |
|---------|--------|---------------|
| `config.REDIS_MIN_RETRY_BACKOFF` | `"8"` | `"1"` |
| `config.REDIS_MAX_RETRY_BACKOFF` | `"1"` | `"8"` |

## Configuration Changes

Summary of `values.yaml` impact:

| Category | Detail |
|----------|--------|
| Added | `secrets.DATABASE_URL` (required when `migrations.enabled: true`) |
| Added | `allowPrivilegeEscalation: false` + `seccompProfile.type: RuntimeDefault` on `api`, `migrations`, `workerEmail`, `workerSms`, `workerWebhook` securityContext |
| Changed | `config.REDIS_MIN_RETRY_BACKOFF` `"8"` -> `"1"` |
| Changed | `config.REDIS_MAX_RETRY_BACKOFF` `"1"` -> `"8"` |
| Removed | none |

Chart files modified between `0.1.0` and `1.0.0-beta.3`:

- `charts/lerian-notification/Chart.yaml`
- `charts/lerian-notification/values.yaml`
- `charts/lerian-notification/templates/configmap.yaml`
- `charts/lerian-notification/templates/secret.yaml`
- `charts/lerian-notification/templates/migrations-job.yaml`
- `charts/lerian-notification/templates/api/hpa.yaml`
- `charts/lerian-notification/templates/api/pdb.yaml`

## Migration Steps

1. **Build `DATABASE_URL` before upgrading.** Choose one:
- Inline via values: set `secrets.DATABASE_URL` to a URL-escaped Postgres DSN.
- External Secret: ensure the Secret referenced by `secretRef.name` contains a `DATABASE_URL` key.
Without this, the migrations Job will fail with an empty `-database` flag.
2. **Check your Redis settings.** If you explicitly set `REDIS_MIN_RETRY_BACKOFF` or `REDIS_MAX_RETRY_BACKOFF`, the chart defaults are now correct; remove your override if you were working around the old bug.
3. **Audit any HPA override.** If you set `api.autoscaling.enabled: true` without `targetCPUUtilizationPercentage` or `targetMemoryUtilizationPercentage`, the upgrade will now `helm template`-fail with a clear message rather than rendering an invalid HPA. Add at least one target.
4. **Re-check PDB intent.** If you previously set `api.pdb.maxUnavailable: 0` and relied on the buggy fall-through to `minAvailable`, the chart will now honor `0` literally and block all disruptions. Switch to `minAvailable` if that was unintended.
5. Review the rendered diff using the helm-diff plugin (see [Preview changes before upgrading](#preview-changes-before-upgrading)).
6. Run the upgrade. The migrations Job runs as a `pre-install` / `pre-upgrade` hook; verify it completed before checking app pods:

```bash
kubectl get jobs -n lerian-notification
kubectl logs -n lerian-notification job/<migrations-job-name>
kubectl rollout status -n lerian-notification deploy/<api-deployment-name>
```

> **Note:** Hook Jobs are removed on success. If the upgrade aborts mid-flight, you can inspect the last failed hook with `helm history -n lerian-notification lerian-notification` and `kubectl get events -n lerian-notification`.

## Preview changes before upgrading

```bash
helm diff upgrade lerian-notification oci://registry-1.docker.io/lerianstudio/lerian-notification-helm --version 1.0.0-beta.3 -n lerian-notification
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add values file reference to Helm commands.

Both the preview and upgrade commands omit -f values.yaml, but Migration Step 1 requires setting secrets.DATABASE_URL. Add the values file flag or include a note reminding users to supply their configuration.

📝 Proposed fix
-helm diff upgrade lerian-notification oci://registry-1.docker.io/lerianstudio/lerian-notification-helm --version 1.0.0-beta.3 -n lerian-notification
+helm diff upgrade lerian-notification oci://registry-1.docker.io/lerianstudio/lerian-notification-helm --version 1.0.0-beta.3 -f values.yaml -n lerian-notification
-helm upgrade lerian-notification oci://registry-1.docker.io/lerianstudio/lerian-notification-helm --version 1.0.0-beta.3 -n lerian-notification
+helm upgrade lerian-notification oci://registry-1.docker.io/lerianstudio/lerian-notification-helm --version 1.0.0-beta.3 -f values.yaml -n lerian-notification

Or add a note before the commands:

> **Note:** Replace `values.yaml` with your values file path, or use `--set` flags for individual overrides.

Also applies to: 141-141

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@charts/lerian-notification/docs/UPGRADE-1.0.md` at line 133, Update the Helm
preview and upgrade commands in UPGRADE-1.0.md to include a values file
reference or call out that users must supply configuration; specifically modify
the shown helm diff/upgrade command examples (the lines containing "helm diff
upgrade lerian-notification ..." and the corresponding upgrade command at the
later occurrence) to either append "-f values.yaml" (or "-f
<path/to/values.yaml>") or add a preceding note: "Note: Replace values.yaml with
your values file path, or use --set flags to override individual values (you
must set secrets.DATABASE_URL)". Ensure the change is made for both occurrences
referenced in the comment.

```

> **Note:** Requires the [helm-diff plugin](https://github.com/databus23/helm-diff). Install with: `helm plugin install https://github.com/databus23/helm-diff`

## Command to upgrade

```bash
helm upgrade lerian-notification oci://registry-1.docker.io/lerianstudio/lerian-notification-helm --version 1.0.0-beta.3 -n lerian-notification
```
Loading