[api] Reject tenant names with dashes at Create time#2380
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughKind-gated validation was added so Tenant names containing dashes are rejected at the aggregated API. Validation signature now accepts kind info, a Tenant-specific regex and constant were added, REST delegates to the updated validator, tests and README were updated, and an e2e Bats test was added. Changes
Sequence Diagram(s)(omitted) Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Code Review
This pull request introduces stricter naming validation for Tenant applications, requiring them to be alphanumeric and start with a lowercase letter to avoid ambiguity in Helm-generated resource names. The changes include updates to the validation logic in the aggregated API, documentation updates, and the addition of comprehensive E2E and unit tests to verify the new constraints and error messages. I have no feedback to provide as there were no review comments to assess.
There was a problem hiding this comment.
🧹 Nitpick comments (1)
pkg/registry/apps/application/rest_validation_test.go (1)
53-60: Prefervalidation.TenantKindover"Tenant"literals in test cases.Using the shared constant consistently will avoid silent drift if the kind string is ever renamed.
Proposed refactor
- {"tenant accepts alphanumeric", "Tenant", "foo", false}, + {"tenant accepts alphanumeric", validation.TenantKind, "foo", false}, ... - Application: config.ApplicationConfig{Kind: "Tenant"}, + Application: config.ApplicationConfig{Kind: validation.TenantKind}, ... - kindName: "Tenant", + kindName: validation.TenantKind,Also applies to: 98-99, 118-120
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@pkg/registry/apps/application/rest_validation_test.go` around lines 53 - 60, Replace the hard-coded "Tenant" string literals in the test table entries with the shared constant validation.TenantKind (e.g., change occurrences in rest_validation_test.go where the test case kind is "Tenant" to use validation.TenantKind) so the tests track the canonical kind name; update all other similar occurrences in the same file noted in the comment (the additional test cases referenced) to use validation.TenantKind as well. Ensure imports include the validation package if not already present and run tests to verify no compile errors.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@pkg/registry/apps/application/rest_validation_test.go`:
- Around line 53-60: Replace the hard-coded "Tenant" string literals in the test
table entries with the shared constant validation.TenantKind (e.g., change
occurrences in rest_validation_test.go where the test case kind is "Tenant" to
use validation.TenantKind) so the tests track the canonical kind name; update
all other similar occurrences in the same file noted in the comment (the
additional test cases referenced) to use validation.TenantKind as well. Ensure
imports include the validation package if not already present and run tests to
verify no compile errors.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 9935b725-0c17-4be2-8575-ec65458b80ee
📒 Files selected for processing (6)
hack/e2e-install-cozystack.batspackages/apps/tenant/README.mdpkg/apis/apps/validation/validation.gopkg/apis/apps/validation/validation_test.gopkg/registry/apps/application/rest.gopkg/registry/apps/application/rest_validation_test.go
ValidateApplicationName previously delegated to IsDNS1035Label, which permits hyphens. The tenant Helm chart's tenant.name helper rejects them at template time, so users saw a successful kubectl apply followed by a Flux reconciliation error. Extend ValidateApplicationName with a kindName parameter and enforce alphanumeric-only names for the Tenant kind, matching the documented naming rules. Wire the check into REST.Create via a small validateNameFormat wrapper that mirrors validateNameLength. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la>
The README stated that dashes are 'allowed but discouraged' in tenant names, but the tenant.name Helm helper explicitly fails on release names that contain more than one dash, and the platform guide on the website already says tenant names must be alphanumeric. Bring the chart README in line with both the website documentation and the enforcement now present on the aggregated API. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la>
Two follow-ups from review:
1. The original tenantNameRegex ^[a-z0-9]+$ let leading-digit names like 123foo slip past the tenant check and receive a generic DNS-1035 error, which defeated the goal of surfacing a tenant-specific message. Require a leading lowercase letter so every tenant-invalid name returns the tenant-contract error.
2. Add a BATS regression test in hack/e2e-install-cozystack.bats that exercises the aggregated API end-to-end. Unit tests construct REST{kindName: "Tenant"} by hand, so a future change to ApplicationDefinition kind registration could break real behavior without breaking the unit tests.
Also pin the error-message contract with a new TestValidateApplicationName_TenantErrorMessage that asserts every tenant-invalid input returns a message containing 'tenant names must' (not the generic DNS-1035 text).
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
Follow-up from review round 2: The BATS regression test now pins a namespace precondition, disables kubectl client-side validation with --validate=false so the request is guaranteed to reach the server-side name check, and documents the intent of each assertion. Previously a client-side schema rejection could have produced a false negative on the tenant-specific error grep, and a missing tenant-root namespace could have produced an unrelated failure that was hard to diagnose. Also pin the edge case where a tenant name consists of valid characters but exceeds the DNS-1035 63-char label limit. The resulting error is intentionally the generic DNS-1035 message because length is not a tenant-specific constraint — the package-level function is not responsible for the stricter Helm-release-prefix length budget that REST.validateNameLength enforces. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la>
Three follow-ups from review:
1. Add defensive cleanup of the foo-bar tenant before and after the e2e regression test. If a prior run left the object in the cluster (e.g. a transient validation regression), the test no longer inherits that state; and if the test itself trips a regression in the future, the cluster is left clean for subsequent tests.
2. Switch kubectl --validate=false to --validate=ignore. The bool form was deprecated in kubectl 1.25 and only kept as an alias; --validate=ignore is the modern, stable spelling.
3. Drop the brittle Contains("63") assertion in TestValidateApplicationName_TenantLengthFallthrough. It pinned the test to the exact DNS-1035 error text from k8s.io/apimachinery, which could break on unrelated upstream wording changes. The surviving assertions still cover the intent: an error exists and it is not the tenant-specific message.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
Four follow-ups from review round 4: 1. BLOCKER: the Update(forceAllowCreate=true) path delegates to Create() when the object does not yet exist (rest.go:452) — the typical kubectl apply upsert flow. Add TestUpdate_ForceAllowCreate_RejectsTenantDashName using a fake client so a future refactor of that delegation cannot silently bypass the tenant name check that r.validateNameFormat alone cannot catch. 2. BLOCKER: the e2e BATS test used || true inside the command substitution, which swallowed the kubectl exit code. Rework the test to capture exit code and stdout+stderr explicitly, then assert the exit code is non-zero before asserting on the error message. This distinguishes validation-success (kubectl exit 0 — regression) from environmental failures (exit non-zero but wrong message) from the happy path. 3. Extract TenantKind = "Tenant" as a named constant in the validation package with a comment pointing at the upstream ApplicationDefinition source of truth, and switch the kindName check to use it. 4. Add a clarifying comment on TestValidateApplicationName_TenantLengthFallthrough that it pins an architectural layering decision and is not a user-facing requirement, so a future promotion of tenant length into tenant-specific wording is a legitimate change rather than a test regression. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la>
The convertHelmReleaseToApplication fall-through that populates Status.Namespace for tenant resources still compared r.kindName against the bare string "Tenant". The validation package already exposes TenantKind for exactly this reason: if the kind string ever diverges from the ApplicationDefinition source of truth, the constant and the call site drift together rather than silently desynchronizing. Add TestConvertHelmReleaseToApplication_TenantNamespaceKindGate to pin both sides of the gate: tenant kind populates Status.Namespace, non-tenant kind leaves it empty. Also rewrite the TestUpdate comment to describe the upsert invariant directly instead of referencing an issue number. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la>
2e7b7dd to
d188aaf
Compare
There was a problem hiding this comment.
🧹 Nitpick comments (1)
pkg/registry/apps/application/rest.go (1)
157-176: Usevalidation.TenantKindconsistently inCreatetenant gate.
Createstill checksr.kindName == "Tenant"for namespace-length validation. Since this PR centralizes tenant-kind identity viavalidation.TenantKind, this should use the same constant to avoid drift.♻️ Proposed consistency fix
- if r.kindName == "Tenant" { + if r.kindName == validation.TenantKind { if nsErrs := r.validateTenantNamespaceLength(app.Namespace, app.Name); len(nsErrs) > 0 { return nil, apierrors.NewInvalid(r.gvk.GroupKind(), app.Name, nsErrs) } }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@pkg/registry/apps/application/rest.go` around lines 157 - 176, Replace the hard-coded kind string check in the Create flow with the centralized constant: change the conditional that uses r.kindName == "Tenant" to compare against validation.TenantKind (i.e., if r.kindName == validation.TenantKind) so the namespace-length gate that calls r.validateTenantNamespaceLength(app.Namespace, app.Name) uses the shared tenant-kind identifier consistently.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@pkg/registry/apps/application/rest.go`:
- Around line 157-176: Replace the hard-coded kind string check in the Create
flow with the centralized constant: change the conditional that uses r.kindName
== "Tenant" to compare against validation.TenantKind (i.e., if r.kindName ==
validation.TenantKind) so the namespace-length gate that calls
r.validateTenantNamespaceLength(app.Namespace, app.Name) uses the shared
tenant-kind identifier consistently.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 8544bdea-3629-489e-b345-1e2c638763b1
📒 Files selected for processing (6)
hack/e2e-install-cozystack.batspackages/apps/tenant/README.mdpkg/apis/apps/validation/validation.gopkg/apis/apps/validation/validation_test.gopkg/registry/apps/application/rest.gopkg/registry/apps/application/rest_validation_test.go
✅ Files skipped from review due to trivial changes (1)
- packages/apps/tenant/README.md
🚧 Files skipped from review as they are similar to previous changes (1)
- hack/e2e-install-cozystack.bats
Replace bare "Tenant" string literals with the validation.TenantKind constant in all test table entries, struct fields, and TypeMeta. Prevents silent drift if the canonical kind string is ever renamed. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la>
What this PR does
The aggregated API previously accepted tenant names containing hyphens (e.g.
foo-bar) becauseValidateApplicationNamedelegated entirely toIsDNS1035Label, which permits them. The tenant Helm chart'stenant.namehelper then rejected the release at template time — so users saw a successfulkubectl applyfollowed by a confusing Flux/HelmRelease reconciliation error.This PR extends
ValidateApplicationNamewith akindNameparameter and enforces an alphanumeric-only rule (^[a-z][a-z0-9]*$) for the Tenant kind. ATenantKindconstant centralizes the kind string, andREST.validateNameFormatwraps the check symmetrically with the existingvalidateNameLength. The tenant chart README is updated to match the already-correct website documentation.Test coverage includes:
Fixes #2375
Release note
Summary by CodeRabbit
New Features
Documentation
Tests