fix(planetscale): forward signed data-plane auth params to branch scrapes#212
Conversation
…apes PlanetScale authenticates the metrics data plane (metrics.psdb.cloud) with a signed, expiring URL — NOT the service token or OAuth bearer. Its Prometheus http_sd response mints per-branch `__param_sig`/`__param_exp` labels, which Prometheus convention promotes to `?sig=&exp=` query params on the scrape URL. The Authorization header (token/bearer) only auths the discovery listing on api.planetscale.com. `subTargetsFromGroup` stripped every `__`-prefixed label except `__scheme__`/`__metrics_path__`, dropping sig/exp and building an unsigned URL, so every branch scrape returned `403 invalid signature` (a 22h+ metrics outage in production). Reconnecting and rotating service tokens couldn't help because the token was never the data-plane credential. Fix: promote `__param_*` labels onto a new `PlanetScaleSubTarget.signedUrl` (base `url` stays param-free so the scraper's per-branch fiber identity + `instance` label don't churn as the signature rotates each 10-min refresh). `ScrapeTargetsService.scrapeForCollector` and `PlanetScaleConnectionService.probeDataPlaneScrape` now fetch `signedUrl`. Verified: the URL built via URLSearchParams is byte-identical to one proven to return HTTP 200 with live branch metrics. apps/api-only deploy; existing targets recover on the next scrape with no reconnect. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Your Pullfrog Router balance is exhausted. You have a card on file but auto-reload is disabled, so runs paused once your balance went past the overdraft buffer. Top up balance → · Enable auto-reload →
|
There was a problem hiding this comment.
Devin Review found 1 potential issue.
🐛 1 issue in files not directly in the diff
🐛 External scraper receives unsigned URLs for PlanetScale targets, causing all scrapes to fail with 403 (apps/api/src/routes/scraper-internal.http.ts:45-51)
The target list served to the external scraper uses the unsigned base URL (subTarget?.url at scraper-internal.http.ts:79) instead of the signed URL that carries the required authentication query params, so every PlanetScale branch scrape by the standalone scraper returns a 403 signature error.
Impact: The standalone Prometheus scraper cannot collect any PlanetScale branch metrics — only the internal collector path works.
Incomplete transformation: signedUrl added to one scraping path but not the other
The PR adds signedUrl to PlanetScaleSubTarget and correctly updates the internal collector path in ScrapeTargetsService.scrapeForCollector (apps/api/src/services/ScrapeTargetsService.ts:863) to use match.signedUrl. However, the external scraper path through scraper-internal.http.ts was not updated:
SubTargetOverrideinterface (scraper-internal.http.ts:45-51) only hasurl,subTargetKey, andlabels— nosignedUrl.toInternalScrapeTargetatscraper-internal.http.ts:79setsurl: subTarget?.url ?? row.url, which maps toPlanetScaleSubTarget.url(the unsigned base URL).InternalScrapeTargetschema (packages/domain/src/http/scraper-internal.ts:15) only has aurlfield.- At
scraper-internal.http.ts:170, thePlanetScaleSubTargetis passed as aSubTargetOverride, and TypeScript's structural typing silently drops thesignedUrlfield.
The external scraper receives InternalScrapeTarget objects whose url lacks the ?sig=…&exp=… params that PlanetScale's metrics data plane requires for authentication.
View 1 additional finding in Devin Review.
|
Re: Devin Review — "External scraper receives unsigned URLs … causing all scrapes to fail with 403" This is a false positive — the standalone scraper never fetches The scraper ( The unsigned 🤖 Addressed by Claude Code |

What & why
PlanetScale branch-metrics scraping was returning
403 invalid signatureon every branch, silently flatlining ingest for 22h+ in production.Root cause: the metrics data plane (
metrics.psdb.cloud) does not authenticate with the service token or the OAuth bearer — it uses a signed, expiring URL. PlanetScale'shttp_sddiscovery response mints per-branch__param_sig/__param_explabels, and Prometheus convention promotes__param_<name>→?<name>=query params on the scrape URL. TheAuthorizationheader (token/bearer) only authenticates the discovery listing onapi.planetscale.com.subTargetsFromGroupstripped every__-prefixed label except__scheme__/__metrics_path__, so it droppedsig/expand built an unsigned URL → 403 on every scrape. Reconnecting and rotating service tokens never helped because the token was never the data-plane credential — this was a misdiagnosis baked into the integration's design.The change
subTargetsFromGrouppromotes__param_*labels onto a newPlanetScaleSubTarget.signedUrl(baseurl+?sig=&exp=).urlandsubTargetKeystay param-free on purpose: the signature rotates each 10-min discovery refresh, so keeping it out of the identity keeps the scraper's per-branch fiber (andinstancelabel) stable — only the server-side fetch picks up the fresh signature.ScrapeTargetsService.scrapeForCollectorandPlanetScaleConnectionService.probeDataPlaneScrapenow fetchsignedUrl.Verification
__param_*→signedUrl,url/subTargetKeystay stable, and sig/exp never leak into metric labels.URLSearchParamsis byte-identical to one proven to returnHTTP 200with live branch metrics (base64%3D%3Dpadding included).Reviewer notes
apps/apionly. The scraper delegates the actual fetch to the API's prometheus-scrape proxy, and itstarget.urlwas already the base URL — no scraper redeploy.probeDataPlaneScrapewill pass for bearer targets and pure-OAuth scraping works end-to-end. Ripping out the manual-token UI +setMetricsTokenis a clean simplification.🤖 Generated with Claude Code