fix(certificates): normalize domain case instead of rejecting it - #11
Merged
Merged
Conversation
`Domain::validate()` rejected any domain that was not already lowercase. DNS labels are case-insensitive (RFC 4343), so case carries no meaning and folding it is the correct handling — rejecting it turns a cosmetic difference into a hard failure on data that already exists. This surfaced on Appwrite Cloud's deletes worker, where deleting a rule whose stored domain had mixed case threw `InvalidArgumentException` and aborted the job, orphaning the certificate row it was about to remove. `Proxy` compounded it. Every public method called `select()`, which validated into a *local* variable and discarded the result, so the raw domain still reached the provider. Normalization now happens once at each entry point and the canonical value flows to both the `appDomain` comparison and the provider call. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Greptile SummaryThis PR changes domain validation from rejecting uppercase hostnames to returning their lowercase canonical form. It also normalizes domains at every proxy lifecycle entry point so routing comparisons and delegated provider calls consistently receive the canonical hostname.
Confidence Score: 5/5The PR appears safe to merge with no actionable correctness, security, or quality issues identified. The changed validation preserves hostname checks while canonicalizing case, and every reachable proxy routing and delegation path now consistently uses the returned canonical domain. Important Files Changed
Reviews (1): Last reviewed commit: "fix(certificates): normalize domain case..." | Re-trigger Greptile |
loks0n
added a commit
to appwrite/appwrite
that referenced
this pull request
Aug 29, 2026
Picks up the domain-case normalization fix (utopia-php/cdn#11). Without this the `^0.0.7` constraint here also pins downstream consumers, so Appwrite Cloud cannot move to 0.0.8 while server-ce holds 0.0.7. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Domain::validate()rejected any domain that was not already lowercase. DNS labels are case-insensitive (RFC 4343), so case carries no meaning — folding it is the correct handling. Rejecting turns a cosmetic difference into a hard failure on data that already exists.Proxycompounded it. Every public method calledselect(), which validated into a local variable and threw the result away, so the raw domain still reached the provider:Normalization now happens once at each public entry point, so the canonical value reaches both the
appDomaincomparison inselect()and the provider call.Incident
Appwrite Cloud 1.45.22, production fra1, 2026-08-28. Deleting a proxy rule whose stored domain had mixed case threw
InvalidArgumentExceptionout ofDomain::validate(). The throw aborted the delete job before the certificate row was removed, orphaning it.Verification
DomainTest: case folding, plus rejection of empty / scheme / port / path / trailing-slash / underscoreProxyTest: asserts the provider receives the canonical domain, and that a mixed-case app domain still routes to the app provider — which only holds if folding happens before theappDomaincomparisonDomainfold and reverting theProxyentry-point normalization each fail the new tests🤖 Generated with Claude Code