Skip to content
Merged
Show file tree
Hide file tree
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
38 changes: 38 additions & 0 deletions .github/configs/helm-render-values/br-spi.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# CI-only render fixture for br-spi. Dummy values, NOT a production example and
# NOT real credentials. Exercises the external-infra path (the target-environment
# reality): all four components + the migration Job enabled, Postgres/Redis
# external. The declared Bitnami subcharts stay disabled; the render gate still
# runs the release-name collapse renders against them.
core:
configmap:
POSTGRES_HOST: "pg.example.svc"
STREAMING_BROKERS: "kafka-dummy:9092"
secrets:
POSTGRES_PASSWORD: "dummy-ci-password"

spi:
configmap:
POSTGRES_HOST: "pg.example.svc"
STREAMING_BROKERS: "kafka-dummy:9092"
BACEN_SPI_ENDPOINT: "http://mock-bacen.example.svc:8080"
secrets:
POSTGRES_PASSWORD: "dummy-ci-password"

brcode:
configmap:
POSTGRES_HOST: "pg.example.svc"
secrets:
POSTGRES_PASSWORD: "dummy-ci-password"

dict:
configmap:
POSTGRES_HOST: "pg.example.svc"
REDIS_HOST: "redis.example.svc:6379"
secrets:
POSTGRES_PASSWORD: "dummy-ci-password"
REDIS_PASSWORD: "dummy-ci-redis"

migrations:
enabled: true
postgres:
host: "pg.example.svc"
9 changes: 9 additions & 0 deletions charts/br-spi/Chart.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
dependencies:
- name: postgresql
repository: https://charts.bitnami.com/bitnami
version: 16.3.5
- name: valkey
repository: oci://registry-1.docker.io/bitnamicharts
version: 2.4.7
digest: sha256:52ff7322d903f193a03cdb12e017ea953e3f7c06cd6019216410086fef3bcd6b
generated: "2026-07-02T18:30:40.65224-07:00"
49 changes: 49 additions & 0 deletions charts/br-spi/Chart.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
apiVersion: v2
name: br-spi-helm
description: A Helm chart for the br-sfn SPI (Pix) rail — the four Go binaries (core, spi, brcode, dict) that connect an FI to BACEN SPI/DICT/Pix and emit settlement CloudEvents onto a Redpanda bus

type: application
annotations:
lerian.studio/chart-type: multi-component

home: https://github.com/LerianStudio/helm

sources:
- https://github.com/LerianStudio/helm/tree/main/charts/br-spi
- https://github.com/LerianStudio/br-spi

maintainers:
- name: "Lerian Studio"
email: "support@lerian.studio"

version: 0.1.0-beta.1

# NOTE: appVersion is the default image tag for every component and the
# migration Job. Override per component via <component>.image.tag when a
# component needs to pin a different build.
appVersion: "0.1.0"

keywords:
- br-spi
- spi
- pix
- bacen
- dict
- lerian
- settlement

icon: https://avatars.githubusercontent.com/u/148895005?s=200&v=4

# Bitnami subcharts are DECLARED (exact pins, condition-gated) so the chart can
# optionally bundle infra, but they default to disabled: on the target
# environments Postgres and Redis are EXTERNAL and pre-provisioned. Chart.lock is
# committed; re-verify Secret name/key against `helm template` on any pin bump.
dependencies:
- name: postgresql
version: "16.3.5"
repository: "https://charts.bitnami.com/bitnami"
condition: postgresql.enabled
- name: valkey
version: "2.4.7"
repository: "oci://registry-1.docker.io/bitnamicharts"
condition: valkey.enabled
Comment on lines +41 to +49

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

Is the Bitnami classic chart repository charts.bitnami.com/bitnami still available in 2026, or has PostgreSQL moved to OCI-only distribution?

💡 Result:

As of July 3, 2026, the traditional Bitnami Helm chart repository (https://charts.bitnami.com/bitnami) is considered deprecated and is not the recommended method for accessing Bitnami charts [1][2]. While it may still technically resolve in some contexts, it has been replaced by OCI-based distribution [3][2]. Bitnami completed its transition to OCI-only distribution for its Helm charts well before 2026 [4][2]. Furthermore, as of August 28, 2025, Bitnami stopped publishing new public updates for its Helm charts on Docker Hub [2]. For ongoing updates and security support for charts like PostgreSQL, users are directed to use the Bitnami Secure Images catalog, which requires a subscription [5][6][2]. For existing deployments, you should no longer rely on the charts.bitnami.com repository [2]. If you need to continue using older Bitnami charts, you must migrate your configurations to use OCI-based installation (e.g., oci://registry-1.docker.io/bitnamicharts/postgresql) [7][2] and, for image-related updates or continued access, manually override the container image registry to point to the bitnamilegacy repository or a secure alternative as required by your subscription level [8][6][9].

Citations:


🌐 Web query:

Bitnami PostgreSQL chart 16.3.5 repository charts.bitnami.com/bitnami or oci://registry-1.docker.io/bitnamicharts: does version 16.3.5 exist and is the legacy repo still a supported source?

💡 Result:

Yes, Bitnami PostgreSQL Helm chart version 16.3.5 exists; it was released on January 3, 2025 [1]. Regarding the status of the repository sources: 1. Legacy HTTP Repository (charts.bitnami.com/bitnami): While this repository URL remains functional for backward compatibility, it has been deprecated as the primary distribution method [2][3][4]. Bitnami transitioned to OCI-based distribution as the standard method starting in November 2024 [3][5][4]. The index.yaml served at this legacy URL now points to the OCI artifacts [2][3]. 2. OCI Registry (oci://registry-1.docker.io/bitnamicharts): This is the current, supported, and recommended source for all Bitnami Helm charts [3][4][6]. Important Note on Image Availability: Following catalog changes in 2025, while the Helm charts themselves remain available in the OCI registry [7][8], many charts require updating their container image references [7][9][8]. As of late 2025, only a specific subset of charts (including PostgreSQL) are configured to work out-of-the-box with supported Bitnami Secure Images [8]. Other charts may require you to override the image repository to point to a valid source (such as the legacy image registry or a private registry) to remain functional [7][9][8]. The legacy image registry (docker.io/bitnamilegacy) is not actively maintained and should only be used for temporary migration purposes [7][9].

Citations:


Move the PostgreSQL Bitnami dependency to OCI. postgresql 16.3.5 still exists at the legacy repo, but charts.bitnami.com/bitnami is deprecated; using oci://registry-1.docker.io/bitnamicharts for both Bitnami charts keeps the source consistent.

🤖 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/br-spi/Chart.yaml` around lines 41 - 49, The Chart.yaml dependencies
still reference the PostgreSQL Bitnami chart from the legacy repository, so
update the postgresql entry in the dependencies list to use the same OCI source
as valkey. Keep the existing version and condition, but change the repository
for postgresql 16.3.5 to oci://registry-1.docker.io/bitnamicharts so both
Bitnami dependencies are sourced consistently.

73 changes: 73 additions & 0 deletions charts/br-spi/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# br-spi Helm Chart

Deploys the **br-sfn SPI (Pix) rail** — the four Go binaries (`core`, `spi`, `brcode`, `dict`) that connect a financial institution to BACEN SPI / DICT / Pix — into Kubernetes. When streaming is enabled, `core` becomes a CloudEvents **producer**, emitting `studio.lerian.settlement.*` onto the `br-spi.settlement` topic of a Redpanda/Kafka bus.

## Chart Contract

- Chart type: `multi-component`
- Required secrets: **None for a default render.** For external Postgres (the default), provide each component's `POSTGRES_PASSWORD` (all four share the single `brspi` database) via `<component>.secrets.POSTGRES_PASSWORD` or `<component>.useExistingSecret`; on the target environments this is sourced from GitOps/Vault. `dict` additionally needs `REDIS_PASSWORD` when its external Redis requires auth. When the bundled `postgresql`/`valkey` subcharts are enabled instead, those passwords are **single-sourced** from the subchart Secrets (read at runtime via `secretKeyRef`) and are not stored in the app Secrets. No credential is ever placed in a ConfigMap. Optional at-rest / PII keys added under `<component>.secrets` are emitted only when set.
- Dependency notes: Bundled `postgresql` (16.3.5) and `valkey` (2.4.7) Bitnami subcharts are **declared but disabled by default** — Postgres and Redis are external and pre-provisioned on the target environments. Kafka/Redpanda is external and referenced only by `STREAMING_BROKERS` (plaintext; no SASL/TLS knobs). Enable the subcharts only for a self-contained install.
- Production overrides: Set `<component>.image.tag` (defaults to `Chart.appVersion`); `POSTGRES_HOST` and `POSTGRES_PASSWORD` for every enabled component; `STREAMING_BROKERS` for `core` and `spi` (a producer with `STREAMING_ENABLED=true` and empty `STREAMING_BROKERS`/`STREAMING_CLOUDEVENTS_SOURCE` **fails closed at boot** by design); `REDIS_HOST` for `dict`; and per-component `ingress`, `autoscaling`, and `resources` as needed. `useExistingSecret`/`existingSecretName` are supported per component and for the migration Job.
- Source/license: Source is in `github.com/LerianStudio/helm`; chart license is Apache-2.0. The `br-spi` service source is `github.com/LerianStudio/br-spi`.

## Components

All four components are the same Go binary family (identical deployment shape). The chart renders them from one shared template library, so env — especially `STREAMING_*` — is emitted uniformly and a component can never silently drop a producer knob.

| Component | Image (default) | Listens | Streams | Role |
|-----------|-----------------|---------|---------|------|
| `core` | `ghcr.io/lerianstudio/br-sfn-core` | `:8080` | **yes** | Settlement engine; sole producer of `studio.lerian.settlement.*` |
| `spi` | `ghcr.io/lerianstudio/br-sfn-spi` | `:8080` | **yes** | ISO 20022 / BACEN SPI; writes the `spi->core` seam |
| `brcode` | `ghcr.io/lerianstudio/br-sfn-brcode` | `:8080` | no | Pix BR Code (QR) REST |
| `dict` | `ghcr.io/lerianstudio/br-sfn-dict` | `:8080` | no | DICT (Pix directory) REST; **requires `REDIS_HOST`** |

Each component exposes: `<component>.enabled`, `image.{repository,tag,pullPolicy}`, `replicaCount`, `service`, `ingress`, `autoscaling`, `pdb`, `resources`, `configmap` (map, emitted verbatim), `secrets`, `useExistingSecret`/`existingSecretName`, `extraEnvVars` (raw env list escape). Probes are `/health` (liveness) and `/readyz` (readiness) on the `http` port (containerPort `8080`).

### Settlement producer coupling

`core` produces `settlement.*` only by **consuming** the `spi->core` seam topics that `spi` writes. Therefore **both** `core` and `spi` must have `STREAMING_ENABLED=true`, the **same** `STREAMING_BROKERS`, and the **same** Postgres, or no settlement event is emitted at all. `brcode` and `dict` are REST-only and stream `false`.

## Configuration knobs (ConfigMap passthrough)

`<component>.configmap` is emitted verbatim into the component ConfigMap — it is **not** a fixed allowlist. Any additional env (BACEN endpoints, Postgres pool tuning, signer/JOSE knobs) can be added under `<component>.configmap` without editing the chart. `STREAMING_ENABLED`, `STREAMING_BROKERS`, `STREAMING_CLOUDEVENTS_SOURCE`, `POSTGRES_HOST`, and `REDIS_HOST` are handled first-class by the template (the hosts derive from the bundled subchart when enabled). Secrets must go under `<component>.secrets`, never `configmap`.

| Key | Default | Notes |
|-----|---------|-------|
| `ENV_NAME` | `development` | SPI env; `development` relaxes BACEN mTLS + accepts `http://`/mock endpoints |
| `SERVER_ADDRESS` | `:8080` | host:port form (container port is 8080) |
| `POSTGRES_{HOST,PORT,USER,DB,SSLMODE}` | see values | All four share the `brspi` database |
| `REDIS_HOST` | `""` | host:port; **required for `dict`** |
| `OUTBOX_ENABLED` | `true` | keep on for the producer |
| `IDEMPOTENCY_RETRY_WINDOW_SEC` | `300` | `core` only; must be `> 0` |
| `STREAMING_ENABLED` | `true` (core/spi), `false` (brcode/dict) | fail-closed when brokers/source empty |
| `STREAMING_BROKERS` | `""` | CSV; **required when streaming enabled** |
| `STREAMING_CLOUDEVENTS_SOURCE` | `studio.lerian.core` / `studio.lerian.spi` | required when streaming enabled |
| `ENABLE_TELEMETRY` | `false` | when `true`, `OTEL_EXPORTER_OTLP_ENDPOINT` is set to `$(HOST_IP):4317` (gRPC) |
| `OTEL_RESOURCE_SERVICE_NAME` | `br-spi-<component>` | distinct per binary so dashboards don't collapse |

## Detached migrations

`migrations.enabled` (default `true`) ships an ArgoCD **PreSync** Secret (`hook-weight: -2`) + Job (`hook-weight: -1`) that runs `ghcr.io/lerianstudio/br-sfn-spi-migrations`. That image's entrypoint applies the 6-module `golang-migrate` loop in manifest order (`global events spi dict brcode core`) to the single `brspi` database, using the per-module `x-migrations-table=schema_migrations_<module>` naming that `/readyz` reads back. `systemplane` is **not** applied by `golang-migrate` — it is managed by lib-systemplane at runtime. br-sfn runtime binaries are detached — they verify the schema on boot and refuse to start unmigrated — so the PreSync Job runs before every component Deployment. The Job pod is hardened (non-root, read-only rootfs, drop ALL, no service-account token) and waits for Postgres via a `busybox` initContainer. Supports `migrations.useExistingSecret`/`existingSecretName`.

Source code:
* https://github.com/LerianStudio/helm/tree/main/charts/br-spi
* https://github.com/LerianStudio/br-spi

## Install

```console
$ helm install br-spi oci://ghcr.io/lerianstudio/br-spi-helm --version 0.1.0 -n br-spi --create-namespace \
--set core.configmap.POSTGRES_HOST=pg-dev,core.secrets.POSTGRES_PASSWORD=... \
--set core.configmap.STREAMING_BROKERS=kafka-dev:9092
```

## External vs bundled infrastructure

Default (external): leave `postgresql.enabled=false` and `valkey.enabled=false`, set `POSTGRES_HOST`/`REDIS_HOST` per component, and provide `POSTGRES_PASSWORD` (and `REDIS_PASSWORD` if the Redis needs auth).

Bundled (self-contained): set `postgresql.enabled=true` (and `valkey.enabled=true`); the app reads the subchart-generated passwords via `secretKeyRef` (single-sourced), and `POSTGRES_HOST`/`REDIS_HOST` derive from the subchart Service names collapse-aware via `common.names.dependency.fullname`.

## Support & Community

- **GitHub Issues**: https://github.com/LerianStudio/br-spi/issues
- **Email**: contact@lerian.studio
Loading
Loading