Add the storageclass dynamic-dropdown x-cozystack-options annotation to the
storageClass field of the data apps (openbao, clickhouse, mariadb, redis,
harbor, opensearch, rabbitmq, mongodb, postgres, nats, kafka, qdrant,
foundationdb, http-cache) at the values.yaml source, so the extension is
emitted by cozyvalues-gen instead of hand-edited into values.schema.json.
kafka carries two (Kafka and ZooKeeper structs); foundationdb is nested
under the Storage struct.
Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Andrei Kvapil <andrei.kvapil@aenix.io>
Mark fields that reference cluster resources with the x-cozystack-options
vendor keyword so the dashboard renders them as dynamic dropdowns:
GPU, instanceType, instanceProfile, network (vm-instance), GPU/
instanceType (kubernetes nodeGroups), image (vm-disk), storagePool
(bucket), storageClass (all apps) and disks[].name (vm-instance). Drop
the stale static instanceProfile enum.
Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Andrei Kvapil <andrei.kvapil@aenix.io>
Resolve the conflict in the generated packages/system/postgres-rd/cozyrds/postgres.yaml by regenerating openAPISchema and keysOrder from the merged values. The CRD now carries both the chart's tls.enabled field and main's backup useSystemBucket / BackupClass-driven fields.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Arsolitt <arsolitt@gmail.com>
version is a general deployment parameter, not a TLS setting; relocate
its @param/@enum block back into Common parameters so the generated
parameter reference groups it correctly instead of under TLS.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Arsolitt <arsolitt@gmail.com>
The generated JSON schema types tls.enabled as a scalar boolean, which
rejects an explicit null value; describe the tri-state unset case as
"omitted" so the wording matches what the schema actually accepts.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Arsolitt <arsolitt@gmail.com>
Remove the jq post-processing patch that widened tls.enabled type to
["boolean","null"] in values.schema.json and the openAPISchema embedded
in the cozyrds CRD. Plain "type":"boolean" is emitted directly by
cozyvalues-gen and is the correct form.
The cozystack-api server unmarshals openAPISchema into
apiextv1.JSONSchemaProps whose Type field is a single string; an array
value silently zeros the field and disables server-side defaulting for
the entire app.
Tri-state semantics are preserved on the Helm template side via
kindIs "invalid": omitting tls.enabled triggers the external-based
fallback; null is no longer a valid input and is rejected by the schema.
Remove two helm-unittest cases that injected tls.enabled: null (now
intentionally rejected) and update the suite comment to match.
Signed-off-by: Arsolitt <arsolitt@gmail.com>
The dashboard RBAC intentionally does not grant access to the operator-managed
<release>-ca Secret (it contains ca.key, which would leak the private key).
Advertising it in cozyrds secrets.include created a UX gap: the dashboard
showed a Secret the tenant could never read.
CNPG bundles ca.crt in every user-credentials Secret it creates, so tenants
already have the trust anchor they need via the <release>-credentials Secret
which is covered by RBAC. Update README and the db.yaml comment to point there.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Arsolitt <arsolitt@gmail.com>
Add a precondition that fails early if cozyvalues-gen no longer emits
tls.enabled.type as the bare "boolean" string the patch step expects.
Without the guard, a generator output that drops or moves the field
would silently create it via the assignment, and the post-patch
equality check would still pass against the synthetic value.
Signed-off-by: Arsolitt <arsolitt@gmail.com>
The README still described the chart-side cert-manager chain that was
replaced when the chart switched to CNPG operator-managed TLS via
spec.certificates.serverAltDNSNames. Rewrite the section to explain the
actual cert ownership boundary (CNPG owns the chain, chart only injects
the external hostname), the trust anchor location (operator-managed
<release>-ca Secret, key ca.crt), and the chart-side semantics of the
tri-state tls.enabled flag. The values.yaml @field comment is updated
in the same direction, with regenerated schema/types.go/cozyrds.
Clarifies that tls.enabled=false only skips the chart-side SAN
injection - CNPG retains its built-in TLS on the wire regardless of
this flag. To force PostgreSQL TLS off entirely, the caller would set
postgresql.parameters.ssl="off" at the CNPG layer.
Signed-off-by: Arsolitt <arsolitt@gmail.com>
Drop the templates/certmanager.yaml suite entirely (the file no longer
exists) and rewrite the spec.certificates assertions to match the new
operator-managed flow: certificates block emitted only when both TLS is
on AND external is true, with serverAltDNSNames carrying just the
external hostname.
Signed-off-by: Arsolitt <arsolitt@gmail.com>
CNPG admission webhook rejects spec.certificates that combines a
serverTLSSecret with serverAltDNSNames, and the operator's internal
client-CA generation step expects ca.key on the secret bound to
serverCASecret — a field cert-manager does not produce, since it stores
the private key as tls.key. The previous chart configuration triggered
exactly this path and left the Cluster stuck on
"generating client CA certificate: missing ca.key secret data".
Drop the chart-rendered cert-manager Issuer/Certificate chain and the
spec.certificates.serverCASecret/serverTLSSecret references. CNPG now
auto-generates the self-signed CA and signs server, replication, and
client certs from it, producing the expected per-purpose secrets
(<release>-ca, <release>-server, <release>-replication). The operator's
default SAN list already covers the three built-in services
(rw, r, ro) in four DNS forms each.
The chart still needs to inject the external LoadBalancer hostname when
external=true, since that name lives outside the operator's auto-derived
set. Emit spec.certificates.serverAltDNSNames with that single entry
under that condition only.
End-to-end test on dev13: Cluster reaches "healthy state", probe pod
with PGSSLMODE=verify-full against the operator-managed CA succeeds and
SHOW ssl reports on.
Signed-off-by: Arsolitt <arsolitt@gmail.com>
- Add _tls.tpl helper with tri-state resolution logic (nil/false/true)
- Add certmanager.yaml to provision CA and leaf Certificate resources
- Wire TLS listener configuration into db.yaml when TLS is enabled
Signed-off-by: Arsolitt <arsolitt@gmail.com>
- Extend PostgresSpec with nullable Tls.Enabled (*bool) for tri-state control
- Regenerate deepcopy and update go.mod with k8s.io/utils as direct dep
- Add TLS fields to values.yaml, values.schema.json (with nullable support)
- Update README and Makefile; propagate TLS field to cozyrds postgres.yaml
Signed-off-by: Arsolitt <arsolitt@gmail.com>
Annotate storageClass as immutable across every stateful app whose
chart exposes one — clickhouse, foundationdb, harbor, http-cache,
kafka (Kafka + ZooKeeper), kubernetes (top-level only), mariadb,
mongodb, nats, openbao, opensearch, postgres, qdrant, rabbitmq,
redis, vm-disk. Without coverage across the catalogue the UI would
render storageClass read-only on some apps and editable on others —
a worse mental model than uniform behaviour.
The annotation lands at the schema layer (CEL XValidation rule
'self == oldSelf' on values.schema.json / types.go / embedded
openAPISchema in cozyrds/<app>.yaml). The cozystack aggregated
apiserver does not yet evaluate CEL on application-backed resources;
that is tracked at cozystack/cozystack#2657. The UI
(cozystack/cozystack-ui#6) consumes the marker today.
The PVC-pinning argument is identical for every chart: Kubernetes
fixes a PVC's storageClassName at creation time, so editing this
field on an existing resource never migrated data. The schema
annotation makes that contract explicit.
kubernetes.nodeGroups[name].storageClass is intentionally NOT
annotated: the field is optional and undefaulted, so a strict
'self == oldSelf' rule would block any future attempt to set it on
an existing node group. A richer ratcheting form is needed there —
see docs/storage-immutability.md.
A refactor in pkg/registry/apps/application/rest.go extracts the
inline schema-build path into buildSpecSchema so it can be
unit-tested. Three regression tests in rest_spec_schema_test.go pin
the contract that x-kubernetes-validations survives the
v1->internal->structural conversion (loaded from the actual MariaDB
ApplicationDefinition fixture on disk, not a hand-edited mock).
Each per-app README gains a one-line blockquote pointing to a new
docs/storage-immutability.md that explains the contract and which
consumers enforce it today.
Requires cozystack/cozyvalues-gen with @immutable support — bump the
pre-commit pin in .github/workflows/pre-commit.yml once the release
exists.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
Ivan's original schema edits were correct in intent but lived in the
generated artifacts (values.schema.json and the embedded openAPISchema
in postgres-rd/cozyrds/postgres.yaml). `make generate` reverts them
because values.yaml's `@field {map[string]string}` annotation is the
source of truth -- same regeneration trap that caught #2466 (issue #2597).
cozyvalues-gen v1.4.0 (cozystack/cozyvalues-gen#25, merged 2026-05-21)
adds an `intOrString` type alias for map values that emits
`additionalProperties.anyOf: [integer, string]` plus
`x-kubernetes-int-or-string: true`. Move the change to source by
flipping the annotation, then regenerate:
- packages/apps/postgres/values.yaml: `@field {map[string]intOrString}`
with updated description noting integer values are accepted.
- packages/apps/postgres/values.schema.json: regenerated -- now carries
anyOf + x-kubernetes-int-or-string: true.
- packages/system/postgres-rd/cozyrds/postgres.yaml: embedded
openAPISchema regenerated to match.
- packages/apps/postgres/README.md: regenerated type column.
- api/apps/v1alpha1/postgresql/types.go: Parameters is now
`map[string]intstr.IntOrString`.
The result survives future regenerations. The template's
`{{ \$value | toString | quote }}` already coerces both inputs to
quoted strings, verified end-to-end with helm template against both
`max_connections: 100` (int) and `max_connections: "100"` (string) --
identical render output. Dangerous-param block list still rejects
archive_cleanup_command and recovery_end_command additions from the
prior commit.
Co-Authored-By: IvanHunters <xorokhotnikov@gmail.com>
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
Add archive_cleanup_command and recovery_end_command to the dangerous
parameters blocklist in db.yaml. Both are PostgreSQL shell-exec hooks
identical in threat model to archive_command/restore_command and must
not be settable by tenants.
Also update the BLOCKED list in values.schema.json, values.yaml, and
the embedded openAPISchema in cozyrds/postgres.yaml to reflect the
two new blocked parameters.
Additionally update the embedded openAPISchema in cozyrds/postgres.yaml
to allow integer values for postgresql.parameters (anyOf string|integer),
matching the fix already applied to values.schema.json.
Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
The template already coerces all parameter values to strings via
'toString | quote', but the JSON schema had 'additionalProperties: {type: string}'
which caused Helm schema validation to fail before the template ran
when users passed integer values (e.g. max_connections: 100).
Accept both string and integer types in additionalProperties so that
existing configurations with unquoted numbers continue to work.
Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
Document the five instance-type series (t1/c1/s1/u1/m1) introduced
alongside the legacy preset deprecation, the per-size CPU and memory
matrix, and the 1:1 legacy-to-instance-type mapping table that powers
cozy-lib aliases, migration 39, and the operator-side deprecation
warning.
Single source of truth referenced from:
- packages/library/cozy-lib/templates/_resourcepresets.tpl
- packages/core/platform/images/migrations/migrations/39
- pkg/apis/apps/presets/legacy.go
Includes an explicit callout that legacy `medium` (1 CPU / 1Gi) and
instance-type `*.medium` (2 CPU) are not the same — same word,
different resources.
Replace inline preset tables in packages/apps/postgres/README.md and
packages/apps/kafka/README.md with a short paragraph that names the
five series and points at the canonical doc, since the per-app
inline tables listed only the legacy seven and would drift further
as the canonical matrix evolves.
Co-authored-by: Matthieu ROBIN <matthieu@hidora.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
Pin the 1:1 equivalence between legacy flat preset names and their
instance-type counterparts in helm-unittest for three charts that
exercise different preset shapes:
- postgres — top-level only
- clickhouse — top + nested clickhouseKeeper preset
- opensearch — top + nested dashboards preset
Each case asserts that nano <-> t1.nano, small <-> t1.small,
medium <-> c1.small, large <-> c1.medium, and micro <-> t1.micro
render the same CPU and memory.
packages/apps/{clickhouse,opensearch}/Makefile gain a `test:` target
that calls helm unittest so hack/helm-unit-tests.sh actually runs the
new suites in CI; without it the suites would land as dead weight.
hack/check-rd-presets.sh enforces two invariants in `make unit-tests`:
- every packages/system/*-rd/cozyrds/*.yaml openAPISchema carries
the canonical 47-preset enum (40 instance-type + 7 legacy);
- no chart template carries a hardcoded legacy preset literal in
a defaultingSanitize (list "<legacy>" ...) form.
Both turn an accidental drop of a per-chart Makefile step or an
accidental legacy hardcode into a CI failure rather than silent
production-time validation rejection.
Co-authored-by: Matthieu ROBIN <matthieu@hidora.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
Rewrite resourcesPreset values in every apps/* and extras/* chart from
the legacy flat names to the new instance-type form, using the 1:1
mapping:
nano -> t1.nano micro -> t1.micro
small -> t1.small medium -> c1.small
large -> c1.medium xlarge -> c1.large
2xlarge -> c1.xlarge
Each affected values.yaml carries the canonical 47-value enum (40
instance-type names plus 7 legacy aliases) so the schema accepts both
forms during the deprecation window. cozyvalues-gen regenerates the
matching api/apps/v1alpha1/*/types.go kubebuilder enum and defaults,
the chart values.schema.json, the README parameter table, and the
ApplicationDefinition openAPISchema in packages/system/*-rd/cozyrds.
Three hardcoded legacy literals in chart templates migrated:
- packages/apps/harbor/templates/harbor.yaml:121 (portal)
- packages/apps/opensearch/templates/opensearch.yaml:43 (dashboards)
- packages/system/keycloak/templates/sts.yaml:115 (heap fallback)
packages/apps/foundationdb/Makefile gains the missing hack/update-crd.sh
call. Without it, every regen left foundationdb-rd cozyrds stale and
new FoundationDB app CRs through cozystack-api were rejected at
validation for any non-legacy resourcesPreset value.
Every default-rendered chart produces identical CPU and memory to the
value applied before the rename, courtesy of the legacy alias table in
cozy-lib and the 1:1 default mapping.
Co-authored-by: Matthieu ROBIN <matthieu@hidora.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
Update description in values.yaml with corrected denylist and re-run
cozyvalues-gen to propagate changes to values.schema.json, README.md,
and types.go.
Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
Allow integer values in postgresql.parameters via anyOf schema, so existing
HelmReleases with max_connections: 100 (integer) are not broken on upgrade.
Template coerces all values to string via toString before quoting.
Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
PostgreSQL parameter names are case-insensitive, but the denylist
check was case-sensitive, allowing bypass via mixed-case names
(e.g., ARCHIVE_COMMAND instead of archive_command).
Normalize parameter names to lowercase before checking against the
denylist to prevent security bypass.
Thanks to CodeRabbit for catching this security issue.
Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
Fix regression where defaults were overriding user-supplied parameters.
Sprig merge gives precedence to first argument, so user values must be
merged before defaults to maintain correct override behavior.
Before: merge (dict) $defaults .Values.postgresql.parameters
After: merge (dict) .Values.postgresql.parameters $defaults
Now max_wal_senders and other user parameters correctly override defaults.
Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
- Regenerate deepcopy artifacts to remove orphaned PostgreSQLParameters methods
- Update e2e test to use string value for max_connections parameter
- Fix template to avoid .Values mutation and use quote function for safe YAML escaping
Signed-off-by: ohotnikov.ivan <ohotnikov.ivan@e-queo.net>
Allow users to configure any PostgreSQL server parameter via the
postgresql.parameters field. All parameter values must be provided
as strings (numeric values should be quoted).
Security measures:
- Block parameters that allow shell command execution (archive_command,
restore_command, ssl_passphrase_command, log_destination, event_source)
- Validation implemented in templates to prevent security vulnerabilities
Generated files updated:
- types.go: Add Parameters field with map[string]string type
- README.md: Add parameter documentation and warnings
- values.schema.json: Update schema for new field
- CRD: Update OpenAPI schema with new field and reordered properties
CloudNativePG manages certain parameters automatically (archive_mode,
primary_conninfo, wal_level). Users should not override these as it
may break backup/replication functionality.
Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
Update oldName and serverName field descriptions based on code review
feedback to avoid confusion about their actual roles:
- oldName: Remove misleading "(matches serverName in backup.info)"
text. This field represents the Kubernetes cluster resource name,
not the Barman server name.
- serverName: Provide clearer explanation that it's the S3 path prefix
(barmanObjectStore.serverName) used by the original cluster, and should
only be set when it differs from the Kubernetes resource name.
Updated in:
- values.yaml (source of truth for field documentation)
- types.go (Go API type comments)
- values.schema.json (JSON schema for validation)
- postgres.yaml (CRD with embedded OpenAPI schema)
Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
Add serverName field to bootstrap configuration to explicitly specify
Barman server name from backup.info. This fixes "no target backup found"
errors when server_name in backup.info differs from Kubernetes cluster name.
Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
## What this PR does
Previously, removing a database from `values.databases` had no effect —
the database and its associated roles (`<db>_admin`, `<db>_readonly`)
persisted in PostgreSQL indefinitely. This made it impossible to
declaratively manage database lifecycle via Helm values.
Added two cleanup stages to the init script, mirroring the existing user
deletion logic:
- **Delete databases** that have the `database managed by helm` comment
but are no longer listed in `values.databases` — active connections are
terminated before dropping
- **Delete orphaned roles** (`<db>_admin`, `<db>_readonly`) with proper
membership revocation (`REVOKE ... FROM`) before `REASSIGN OWNED` /
`DROP OWNED` / `DROP ROLE`
This also fixes the reported issue where creating a database, removing
it, and creating it again would silently retain stale data from the
first instance.
### Release note
```release-note
[postgres] Databases removed from `values.databases` are now properly dropped along with their associated roles. Previously removed databases and roles would persist indefinitely.
```
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Enhanced database initialization to automatically remove databases and
roles that were removed from your Helm configuration, avoiding orphaned
resources.
* Now force-terminates active sessions, reassigns owned objects, and
cleans up role memberships to ensure reliable removals.
* Improves consistency of database state during upgrades and
configuration changes.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Replace separate pg_terminate_backend + DROP DATABASE calls with a
single DROP DATABASE ... WITH (FORCE) statement. This eliminates the
race window where new sessions could reconnect between termination
and drop. Available since PostgreSQL 13.
Assisted-By: Claude AI
Signed-off-by: Kirill Ilin <stitch14@yandex.ru>
Previously, removing a database from values.databases had no effect —
the database and its associated roles persisted in PostgreSQL. This
made it impossible to cleanly delete databases via Helm.
Add two cleanup stages to the init script:
- Delete databases that have the 'database managed by helm' comment
but are no longer listed in values.databases
- Delete orphaned roles (db_admin, db_readonly) with proper membership
revocation before dropping
This mirrors the existing user deletion logic and completes the
declarative lifecycle for databases.
Assisted-By: Claude AI
Signed-off-by: Kirill Ilin <stitch14@yandex.ru>
Move common-envs.mk and package.mk from scripts/ to hack/ directory.
Update all Makefile includes to use new paths. Remove unused
issue-flux-certificates.sh script.
Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
Replace Helm lookup functions with FluxCD valuesFrom mechanism for
reading cluster and namespace configuration.
Changes:
- Create Secret cozystack-values in each namespace with values.yaml key
containing _cluster and _namespace configuration as nested YAML
- Configure HelmReleases to read from this Secret via valuesFrom
(valuesKey defaults to values.yaml, so it can be omitted)
- Update cozy-lib helpers to access config via .Values._cluster
- Add default values for required _cluster keys to ensure all fields exist
- Update Go code (cozystack-api and helm reconciler) to use new format
This eliminates the need for Helm lookup functions while maintaining
the same configuration interface for charts.
Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
This patch refactors the secret selectors to use the
`internal.cozystack.io/tenantresource` label for managing secret
visibility and removes any selectors based on it or the previous
`apps.cozystack.io/tenantresource` label, the idea being that this label
will only ever be set by the controller.
```
[controller,api] Refactor labels for the secret selector.
```
Signed-off-by: Timofei Larkin <lllamnyp@gmail.com>
[cozystack-controller] Introduce new dashboard-controller
[dashboard] Introduce new dashboard based on openapi-ui
Co-authored-by: kklinch0 <kklinch0@gmail.com>
Signed-off-by: kklinch0 <kklinch0@gmail.com>
Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
This patch populates existing CozystackResourceDefinitions with minimal
working examples of secret selectors to take advantage of the newest
revision of the ancestor tracking webhook.
```release-note
[platform] Specify secret selectors for existing managed apps in their
respective CozystackResourceDefinitions, which provides the last bit of
information necessary for the lineage webhook to correctly mark secrets
as user-facing or not.
```
Signed-off-by: Timofei Larkin <lllamnyp@gmail.com>
Some k8s secrets created when deploying managed applications are
unhelpful to the end user or are outright not meant to be shown, because
they contain internal credentials not meant to be presented to the user.
This patch adds an `apps.cozystack.io/tenantresource=false` label to
such resources which will be later used to filter out such secrets in
the web UI.
```release-note
[platform] Mark non-user-facing secrets as such to avoid clutter in the
dashboard and leaking internal credentials.
```
Signed-off-by: Timofei Larkin <lllamnyp@gmail.com>