🚀 Release v0.30.6 - #5381
Merged
Merged
🚀 Release v0.30.6#5381
Conversation
- Integrated Dropzone component into handle-organization.tsx. - Resolved dialog auto-close bug by decoupling Dialog from DropdownMenu trigger. - Added DOMPurify to sanitize uploaded SVG logos preventing XSS. - Implemented client-side compression via canvas to resize raster images to 256x256 WebP. - Enhanced UX with instant logo preview, masked base64 input strings, and a quick-clear button. - Updated Dropzone to accept classNameContent for local height overrides.
# Conflicts: # apps/dokploy/components/proprietary/whitelabeling/whitelabeling-provider.tsx # apps/dokploy/pages/_app.tsx
Adds Infomaniak alongside Cloudflare, AWS Route53 and Porkbun, following the
existing DnsClient interface in packages/server/src/utils/dns/.
- infomaniak.ts implements listZones, listRecords, upsertRecord, updateRecord,
deleteRecord and testConnection against the Infomaniak API. Zones come from
/1/product?service_name=domain and records from the v2 /2/zones/{zone}/records
endpoints, which are keyed by zone name rather than by product id.
- A new `infomaniak` value was added to the DnsProviderType enum along with an
infomaniakDnsConfigSchema (apiToken) in the discriminated union, plus the
Drizzle migration for the enum change.
- The token is masked/merged like the other providers in services/dns-provider.ts.
- UI: Infomaniak icon and API Token field in the DNS provider dialog, plus
registration in the provider selector.
Infomaniak's `source` is relative to the zone (empty for the apex), so record
names are translated between Dokploy's fully-qualified format and Infomaniak's
subdomain-only format internally, with the trailing dot handled. TXT targets are
stored quoted by the API and are unquoted on read / quoted on write so that
editing a record does not stack quotes on every save.
Also fills in the missing Porkbun label in show-dns-providers.tsx, which fell
back to displaying the raw enum value.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Adds OVHcloud alongside Cloudflare, AWS Route53 and Porkbun, following the
existing DnsClient interface in packages/server/src/utils/dns/.
- ovh.ts implements listZones, listRecords, upsertRecord, updateRecord,
deleteRecord and testConnection against the /domain/zone endpoints of the
OVHcloud API, on any of its seven regional endpoints (ovh-eu/ca/us, kimsufi
and soyoustart).
- A new `ovh` value was added to the DnsProviderType enum along with an
ovhDnsConfigSchema (endpoint, applicationKey, applicationSecret, consumerKey)
in the discriminated union, plus the Drizzle migration for the enum change.
- The application secret and the consumer key are masked/merged like the other
providers' secrets in services/dns-provider.ts.
- UI: OVHcloud icon, an endpoint selector and the three credential fields in the
DNS provider dialog, plus registration in the provider selector.
Three OVH-specific behaviours are handled explicitly:
- Requests are signed with `$1$` + sha1(applicationSecret+consumerKey+method+
url+body+timestamp). The timestamp comes from the API's own clock via an
unauthenticated GET /auth/time, since a host clock a few seconds off would get
every call rejected; the measured drift is cached per endpoint for an hour.
- OVH only applies zone changes once the zone is explicitly refreshed, so every
successful create, update and delete is followed by POST /domain/zone/{zone}
/refresh.
- The record update payload carries no fieldType, so changing a record's type
replaces the record (DELETE then POST) and returns the new id.
The record listing endpoint returns ids only, so each record is fetched
individually with the fan-out capped at 8 concurrent requests.
Also fills in the missing Porkbun label in show-dns-providers.tsx, which fell
back to displaying the raw enum value.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Verified against a live Infomaniak account: the API returns `source: "."` for
apex records, not "" as assumed.
Reading them back produced a doubled dot ("..example.com"), and writing "" meant
an apex upsert never matched the existing record, so it would have created a
duplicate apex record instead of updating it.
toSource now emits "." for the apex and toFqdn accepts ".", "" and "@" so a
hand-written record still round-trips.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
toSource always writes the apex as ".", but listRecords already accepted "" and "@" as apex spellings on read. The upsert lookup compared sources strictly, so a record stored under one of the other spellings would not have matched and the upsert would have created a duplicate apex record instead of updating it. Normalize the candidate's source before comparing, so read and match agree. Reported by Greptile on #5257. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Changing a record's type deletes the record then recreates it with the new type, because OVH's update payload carries no fieldType. If the creation failed the name was left with nothing and no rollback. The delete still has to come first, since OVH rejects a CNAME that would sit alongside other data on the same name. So on a failed creation the original record is put back from the copy already fetched before the delete, and the original error is rethrown. If the restore fails too, the error names the record that has to be recreated by hand. Reported by Greptile on #5258. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
listZones used /1/product, which lego uses but the API docs don't: it is the legacy singular route, it returns no pagination metadata, and it 401s for at least some tokens. The documented /1/products returns `total`, `pages`, `items_per_page` and `page`, and defaults to 15 domains per page, so an account with more domains than that would silently lose zones. Switch to the plural endpoint and walk every page. Verified against a live account: forcing per_page=2 collects all 5 domains across 3 pages with no duplicates. Also inline the single-use createdId helper. Both reported by @narcisonunez on #5257. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
OVH matches access rules per exact path: a `GET /domain/zone/*` rule grants the
subtree but not the bare `GET /domain/zone` that listZones and testConnection
call. Verified against a live account with a consumer key carrying that single
wildcard rule:
GET /domain/zone -> 403 This call has not been granted
GET /domain/zone/ -> 200
GET /domain/zone/{zone}/record -> 200
The form only asked for rights on `/domain/zone/*`, so a token created by
following it could not list zones at all, and the failure surfaced as a bare
"This call has not been granted" that points nowhere.
The hint now lists the five rights verbatim, and a token missing the root one
gets an error that names it instead of echoing OVH's message.
Reported by @narcisonunez on #5258.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- Sanitize customCss in _document.tsx to prevent XSS breakouts by stripping </style> tags. - Remove SSR favicon fetching to prevent SSRF and internal network scanning, falling back to client-side fetching.
canary landed its own 0190 (0190_nappy_anita_blake), which collides with this branch's 0190_perpetual_red_skull. Renaming would not have been enough: drizzle applies migrations by comparing timestamps against the last applied one, so this branch's older `when` would have been silently skipped on any deployment that had already run canary's 0190, leaving the enum without its new value. Regenerated as 0191_cool_christian_walker with a current timestamp.
canary landed its own 0190 (0190_nappy_anita_blake), which collides with this branch's 0190_even_mastermind. Renaming would not have been enough: drizzle applies migrations by comparing timestamps against the last applied one, so this branch's older `when` would have been silently skipped on any deployment that had already run canary's 0190, leaving the enum without its new value. Regenerated as 0191_elite_ultragirl with a current timestamp.
Fixes #5279. The Domains table (and grid) view mounts one AddDomain instance per row for the edit action. Its 4 queries (domain.one, application.one/compose.one, domain.canGenerateTraefikMeDomains, compose.loadServices) ran unconditionally on mount instead of only when the edit dialog is open, so any table interaction that causes a re-render (typing in the host filter, sorting, toggling columns) fired all 4 queries for every domain row again.
…sc-bugs fix(domains): stop AddDomain queries flooding the API in table view
better-auth's account-linking guard requires either the IdP asserting email_verified or the sso_provider row being domainVerified before it will link an SSO login to an existing local user with the same email. Entra ID never asserts email_verified (neither via its OIDC userinfo endpoint nor via SAML attributes), and Dokploy never persisted domainVerified at all, so linking was permanently impossible for any Entra-backed provider (OIDC or SAML) regardless of the local user's own emailVerified state. Add the domainVerified column, defaulting to true — Dokploy already scopes providers to an admin-configured domain and gates registration behind enterprise/admin permissions, so that domain match (still enforced by better-auth's validateEmailDomain check) is trust enough. Fixes #5099
fix(sso): trust admin-configured SSO providers for account linking
| )}&subDomain=${encodeURIComponent(subDomain)}`, | ||
| ); | ||
|
|
||
| const existingId = existing[0]; |
Contributor
There was a problem hiding this comment.
Create overwrites existing records
The create-record flow calls upsertRecord, but this code selects the first record matching only the type and subdomain. If a name already has an A or TXT record, creating another value silently updates that existing record instead of adding a new one. The Infomaniak implementation has the same behavior by matching only type and source, so both new providers can replace existing DNS data during a create operation.
Contributor
There was a problem hiding this comment.
@narcisonunez
the same overwrite behavior exists in cloudflare and porkbun too, not just ovh/infomaniak, PR incoming
… existing records Previously, upsertRecord matched only by type and name, silently overwriting any existing record of the same type/name with different content. This caused data loss when users had multiple records of the same type (e.g. multiple TXT records for SPF + site verification). Now upsertRecord also checks the record content/target before deciding to update. If the content differs, a new record is created alongside the existing one instead of replacing it. Affected providers: Cloudflare, Porkbun, Infomaniak, OVH. Tests updated accordingly.
3 tasks
…d SRV/CAA records
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
* feat: add dynamic open graph metadata for enterprise whitelabeling
perf(dns): filter Infomaniak records server-side when upserting
…eserve-existing-records # Conflicts: # packages/server/src/utils/dns/infomaniak.ts
…-records fix(dns): match record content in upsertRecord to prevent overwriting existing records
…ferences fix(vault): expand Infisical secret references when listing secrets
An Infisical provider is pinned to one non-recursive `secretPath`, so reading
two folders means two providers, two machine identities and two sets of
credentials to rotate. This lets a reference name the folder instead:
${{vault.my-provider.external/sentry:SENTRY_DSN}}
`<path>:<KEY>` mirrors the HashiCorp client in this directory, which already
documents that exact format. A relative path resolves against the provider's
`secretPath`, a leading slash is absolute, and a ref without a colon keeps its
current meaning — the whole ref is the secret name at the provider's own path.
A dot cannot be the separator here: Infisical accepts dots inside secret names
(`A.B.C` is a valid key), so `provider.a.b.C` cannot be split unambiguously
and would silently break anyone using such a name.
Refs are grouped by resolved path so each path is listed once, and the login
happens once per batch rather than once per path.
Tests cover the bare ref, relative and absolute paths, a provider at `/`,
grouping with a single login, the error naming the path, and a malformed ref.
feat(vault): address an Infisical folder from the reference
/etc/docker/daemon.json isn't mounted into the dokploy container, only docker.sock is, so cat-ing it always failed silently. Read the effective config over the already-mounted socket instead. Fixes #5383
fix(server-health): detect custom default-address-pools via docker info
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.
This PR promotes changes from
canarytomainfor version v0.30.6.🔍 Changes Include:
✅ Pre-merge Checklist:
Greptile Summary
This release promotes the v0.30.6 canary changes to main. It includes:
Confidence Score: 4/5
The PR should not merge until creating DNS records no longer risks overwriting existing values for the new providers.
The new OVHcloud and Infomaniak create paths identify existing records using only name and type, so a valid attempt to add another A or TXT value can silently replace existing DNS data.
Files Needing Attention: packages/server/src/utils/dns/ovh.ts, packages/server/src/utils/dns/infomaniak.ts
Reviews (1): Last reviewed commit: "Merge pull request #5380 from Dokploy/fi..." | Re-trigger Greptile