diff --git a/.watch/baseline.txt b/.watch/baseline.txt deleted file mode 100644 index 197eab891..000000000 --- a/.watch/baseline.txt +++ /dev/null @@ -1,54 +0,0 @@ -pr5154.state=OPEN -pr5154.mergeable=CONFLICTING -pr5154.decision=CHANGES_REQUESTED -pr5154.merged=no -pr5154.closed=no -pr5154.head=b0c7790b2 -pr5154.commits=6 -pr5154.ci= -pr5154.labels=size:L -pr5154.updated=2026-09-02T12:18:19Z -pr5154.reviews=2 -pr5154.inline=1 -pr5154.comments=4 -pr5154.lastactor=mitc-gjuge -pr5257.state=MERGED -pr5257.mergeable=UNKNOWN -pr5257.decision=APPROVED -pr5257.merged=2026-09-04T21:44:12Z -pr5257.closed=2026-09-04T21:44:12Z -pr5257.head=ea9a466c0 -pr5257.commits=6 -pr5257.ci=Greptile Review:SUCCESS,cherry-pick:SKIPPED,format:SUCCESS,pr-check (build):SUCCESS,pr-check (test):SUCCESS,pr-check (typecheck):SUCCESS -pr5257.labels=enhancement,requested-changes -pr5257.updated=2026-09-04T21:44:12Z -pr5257.reviews=6 -pr5257.inline=6 -pr5257.comments=6 -pr5257.lastactor=narcisonunez -pr5258.state=OPEN -pr5258.mergeable=CONFLICTING -pr5258.decision=CHANGES_REQUESTED -pr5258.merged=no -pr5258.closed=no -pr5258.head=28f71e727 -pr5258.commits=6 -pr5258.ci=Greptile Review:SUCCESS,format:SUCCESS,pr-check (build):SUCCESS,pr-check (test):SUCCESS,pr-check (typecheck):SUCCESS -pr5258.labels=requested-changes -pr5258.updated=2026-09-04T19:19:05Z -pr5258.reviews=11 -pr5258.inline=12 -pr5258.comments=6 -pr5258.lastactor=narcisonunez -issue5344.state=OPEN -issue5344.updated=2026-09-04T10:08:24Z -issue5344.labels= -issue5344.comments=1 -issue5344.lastactor=linear-code[bot] -issue5256.state=OPEN -issue5256.updated=2026-09-01T18:41:26Z -issue5256.labels=enhancement -issue5256.comments=1 -issue5256.lastactor=linear-code[bot] -canary.head=d7884c7ce -canary.lastmigration=0191_cool_christian_walker diff --git a/.watch/check.sh b/.watch/check.sh deleted file mode 100755 index f4cb8227e..000000000 --- a/.watch/check.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash -# Un seul instantané sert à la fois au diff ET à la baseline : rien ne peut être -# absorbé silencieusement entre les deux. -cd "$(dirname "$0")/.." -./.watch/snapshot.sh > /tmp/watch-now.txt 2>&1 -if diff -q .watch/baseline.txt /tmp/watch-now.txt >/dev/null; then - echo "aucun changement" -else - echo "=== DIFF ===" - diff .watch/baseline.txt /tmp/watch-now.txt - cp /tmp/watch-now.txt .watch/baseline.txt # exactement le fichier qui a servi au diff -fi diff --git a/.watch/reponse-5257.md b/.watch/reponse-5257.md deleted file mode 100644 index 62e9e6a09..000000000 --- a/.watch/reponse-5257.md +++ /dev/null @@ -1,38 +0,0 @@ -Yes — tested manually against a real Infomaniak account, screenshots below. - -![Providers](1-providers-list.jpg) -*Infomaniak in the provider selector, with its icon and label.* - -![Zones](2-zones.jpg) -*The five zones the account manages, with record counts.* - -![Records](3-records-olidian-io.jpg) -*The records of one zone.* - -That third one is the one worth looking at: apex records render as `olidian.io`, not `..olidian.io`, and the TXT reads `v=spf1 -all` unquoted even though Infomaniak stores it as `"v=spf1 -all"`. Those are the two bugs the live testing turned up and that `be4a5da` fixes. - -## On the Greptile summary in the description - -It predates the fixes. It was generated on 2026-09-01T14:25 and Greptile hasn't re-run since, so the block still names the apex alias mismatch as blocking. That was fixed the same day in `be4a5da` — `normalizeSource` on the upsert lookup, plus a parametrized test over `"."`, `""` and `"@"` — and I replied on its thread at the time. GitHub marks both of your own threads on this PR as `outdated` for the same reason: the code moved past them. - -Your two points were fixed in `59a7484`: the plural `/1/products` endpoint with pagination, and the single-use helper inlined. - -## On "it's not working with a real account" - -I'd really like to know what you saw, because I can't reproduce it: which provider, which step, and the exact error message would help a lot. - -One strong candidate, and it isn't this PR. `canary` currently breaks self-hosted instances at login. `2e2e0c8c2` added the onboarding wizard, and `pages/dashboard/home.tsx` statically imports `onboarding-wizard.tsx`, which statically imports `steps/plan-step.tsx`, which calls at module scope: - -```ts -const stripePromise = loadStripe(process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY!); -``` - -The `isCloud` check inside the wizard only filters which steps render — the module is imported either way. Without `NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY` set, opening the dashboard throws: - -``` -IntegrationError: Missing value for Stripe(): apiKey should be a string -``` - -It hit our own instance this morning and blocked login until we set a placeholder key. Since I merged `canary` into both DNS branches on 2026-09-03, anyone checking them out inherits it — and it fires before you can reach Settings → DNS Providers. That would also explain why the same symptom appears on both PRs, which otherwise share no code. - -Happy to open a separate issue for that if it's useful. diff --git a/.watch/reponse-5258.md b/.watch/reponse-5258.md deleted file mode 100644 index 82da0477e..000000000 --- a/.watch/reponse-5258.md +++ /dev/null @@ -1,72 +0,0 @@ -Yes — tested manually against a real OVHcloud account (24 zones). Screenshots below, and the detailed results were already on this PR, though spread across review threads rather than in one place — summarising both here. - -![Add provider](1-providers-list.jpg) -*OVHcloud in the provider selector, and the corrected permission hint from `f83097b` listing the five rights.* - -![Zones](2-zones.jpg) -*The 24 zones the credentials can manage.* - -![Records](3-records-moninfraprivee.jpg) -*One zone's records: apex, CNAME, A, MX, TXT, NS — and an `SPF` record, see the note below.* - -## What was verified against the live API - -Full cycle through the Dokploy UI's endpoints, with **every mutation confirmed by `dig` against the zone's authoritative nameserver** rather than trusting the API's own response: - -| Step | Result | -|---|---| -| `testConnection` / `listZones` | 24 zones — request signing and the server-clock timestamp work | -| `listRecords` | apex, subdomains and wildcards (`*.lab0.…`) mapped correctly | -| create | new record, resolves via `dig` | -| create again, same name and type | **same id returned** — no duplicate | -| update | content and TTL changed, `dig` confirms | -| type change A → CNAME | **new id** returned, i.e. the delete-and-recreate path ran; `dig` resolves the CNAME | -| delete | `NXDOMAIN` on the authoritative nameserver, zone left with its original records | - -Two failure paths were exercised deliberately rather than only mocked: - -- **Rollback on a failed type change** — I forced the replacement `POST` to fail (type change to `AAAA` while keeping an IPv4 target, which OVH rejects on its own validation). The original error surfaces, the record comes back with its type, name, TTL and target intact, and `dig` resolves it again, which also proves the `/refresh` inside the restore path. Detail worth knowing: the restore recreates the record, so **OVH assigns it a new id** — that's unavoidable through this API, and losing the record seemed clearly worse. -- **The permission problem you spotted** — I created a consumer key carrying exactly one rule, `GET /domain/zone/*`, and confirmed via `/auth/currentCredential` that was really all it had: - - ``` - GET /domain/zone -> 403 This call has not been granted - GET /domain/zone/ -> 200 (24 zones) - GET /domain/zone/{zone}/record -> 200 - ``` - - You were right, and it was worse than a documentation gap: a token created by following the form's old hint literally could not list zones at all. Fixed in `f83097b` — the hint now lists the five rights verbatim, and a 403 on that call names the missing one instead of echoing OVH's message. - -Two things the screenshots make visible. - -Loading a zone's records is noticeably slower than for the other providers. That's inherent to the API — `GET /domain/zone/{zone}/record` returns ids only, so each record needs its own request. The fan-out is capped at 8 concurrent requests to stay within OVH's rate limits. - -And the `SPF` row is worth a look: OVH still exposes record types that Dokploy's `dnsRecordTypes` doesn't include. I flagged this in the PR description as a limitation, but I described it imprecisely — I said editing one is rejected by the shared zod enum. In practice `show-dns-records.tsx` already gates the edit action on `DNS_RECORD_TYPES.includes(record.type)`, so the pencil simply isn't offered on that row while delete still is. The existing UI handles it more gracefully than I gave it credit for; the record is listed truthfully and can't be edited into an invalid state. I'll correct the description. - -## On the Greptile summary in the description - -It predates the fixes. It was generated on 2026-09-01T14:25 and Greptile hasn't re-run since, so the block still lists both findings as blocking. Since then, on its own threads: - -- the failed-type-replacement rollback was fixed in `80a6baf`, and Greptile confirmed: *"This live verification addresses the concern […] no further change is needed for this comment."* -- the multi-value RRset finding it **withdrew**: *"You're right — this is a deliberate and defensible trade-off, not an OVH-specific correctness bug […] I'll withdraw this finding; no change is needed here."* - -GitHub marks those threads `outdated` for the same reason — the code moved past them. - -## On "it's not working with a real account" - -I'd really like to know what you saw, because I can't reproduce it: which step, and the exact error message would help a lot. - -One strong candidate, and it isn't this PR. `canary` currently breaks self-hosted instances at login. `2e2e0c8c2` added the onboarding wizard, and `pages/dashboard/home.tsx` statically imports `onboarding-wizard.tsx`, which statically imports `steps/plan-step.tsx`, which calls at module scope: - -```ts -const stripePromise = loadStripe(process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY!); -``` - -The `isCloud` check inside the wizard only filters which steps render — the module is imported either way. Without `NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY` set, opening the dashboard throws: - -``` -IntegrationError: Missing value for Stripe(): apiKey should be a string -``` - -It hit our own instance this morning and blocked login until we set a placeholder key. Since I merged `canary` into both DNS branches on 2026-09-03, anyone checking them out inherits it — and it fires before you can reach Settings → DNS Providers. That would also explain why the same symptom appears on this PR and on #5257, which otherwise share no code. - -Happy to open a separate issue for that if it's useful. diff --git a/.watch/shots-ovh/1-providers-list.jpg b/.watch/shots-ovh/1-providers-list.jpg deleted file mode 100644 index 028007aa6..000000000 Binary files a/.watch/shots-ovh/1-providers-list.jpg and /dev/null differ diff --git a/.watch/shots-ovh/1-providers-list.original.jpg b/.watch/shots-ovh/1-providers-list.original.jpg deleted file mode 100644 index bcac085f2..000000000 Binary files a/.watch/shots-ovh/1-providers-list.original.jpg and /dev/null differ diff --git a/.watch/shots-ovh/2-zones.jpg b/.watch/shots-ovh/2-zones.jpg deleted file mode 100644 index f52f112bc..000000000 Binary files a/.watch/shots-ovh/2-zones.jpg and /dev/null differ diff --git a/.watch/shots-ovh/3-records-moninfraprivee.jpg b/.watch/shots-ovh/3-records-moninfraprivee.jpg deleted file mode 100644 index 86a4446fb..000000000 Binary files a/.watch/shots-ovh/3-records-moninfraprivee.jpg and /dev/null differ diff --git a/.watch/shots/1-providers-list.jpg b/.watch/shots/1-providers-list.jpg deleted file mode 100644 index 1f713935a..000000000 Binary files a/.watch/shots/1-providers-list.jpg and /dev/null differ diff --git a/.watch/shots/1-providers-list.original.jpg b/.watch/shots/1-providers-list.original.jpg deleted file mode 100644 index 64cb54bb4..000000000 Binary files a/.watch/shots/1-providers-list.original.jpg and /dev/null differ diff --git a/.watch/shots/2-zones.jpg b/.watch/shots/2-zones.jpg deleted file mode 100644 index 66ff3d8c7..000000000 Binary files a/.watch/shots/2-zones.jpg and /dev/null differ diff --git a/.watch/shots/3-records-olidian-io.jpg b/.watch/shots/3-records-olidian-io.jpg deleted file mode 100644 index 4627b06e3..000000000 Binary files a/.watch/shots/3-records-olidian-io.jpg and /dev/null differ diff --git a/.watch/snapshot.sh b/.watch/snapshot.sh deleted file mode 100755 index f376fe9bc..000000000 --- a/.watch/snapshot.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/bash -# Instantané de l'état des 3 PR Dokploy suivies + de canary. -R=dokploy/dokploy -for n in 5154 5257 5258; do - gh pr view "$n" --repo "$R" --json number,state,mergeable,reviewDecision,mergedAt,closedAt,commits,statusCheckRollup,labels,updatedAt \ - --jq '"pr\(.number).state=\(.state) -pr\(.number).mergeable=\(.mergeable) -pr\(.number).decision=\(.reviewDecision // "none") -pr\(.number).merged=\(.mergedAt // "no") -pr\(.number).closed=\(.closedAt // "no") -pr\(.number).head=\(.commits[-1].oid[0:9]) -pr\(.number).commits=\(.commits|length) -pr\(.number).ci=\([.statusCheckRollup[]? | "\(.name // .context):\(.conclusion // .state)"] | sort | join(",")) -pr\(.number).labels=\([.labels[]?.name] | sort | join(",")) -pr\(.number).updated=\(.updatedAt)"' - echo "pr$n.reviews=$(gh api "repos/$R/pulls/$n/reviews" --jq 'length')" - echo "pr$n.inline=$(gh api "repos/$R/pulls/$n/comments" --jq 'length')" - echo "pr$n.comments=$(gh api "repos/$R/issues/$n/comments" --jq 'length')" - echo "pr$n.lastactor=$(gh api "repos/$R/issues/$n/comments" --jq '[.[].user.login] | last // "none"')" -done -# Issues suivies : #5344 (bug Stripe canary), #5256 (feature request OVH, se -# fermera au merge de #5258). Les commentaires y sont invisibles côté PR. -for i in 5344 5256; do - gh issue view "$i" --repo "$R" --json number,state,updatedAt,labels \ - --jq '"issue\(.number).state=\(.state) -issue\(.number).updated=\(.updatedAt) -issue\(.number).labels=\([.labels[]?.name] | sort | join(","))"' - echo "issue$i.comments=$(gh api "repos/$R/issues/$i/comments" --jq 'length')" - echo "issue$i.lastactor=$(gh api "repos/$R/issues/$i/comments" --jq '[.[].user.login] | last // "none"')" -done -echo "canary.head=$(gh api "repos/$R/commits/canary" --jq '.sha[0:9]')" -echo "canary.lastmigration=$(gh api "repos/$R/contents/apps/dokploy/drizzle/meta/_journal.json?ref=canary" --jq '.content' | base64 -d | python3 -c 'import json,sys; print(json.load(sys.stdin)["entries"][-1]["tag"])')"