fix(adapters): Destatis GENESIS connector broken since June 2025 — migrate to POST/header auth, add API token support - #481
Open
mirkopoloni wants to merge 3 commits into
Open
Conversation
resolveString() used `credentials[key] || '{{key}}'`, so an
explicitly-supplied empty credential fell back to the literal
placeholder instead of resolving. Any API that needs a credential
header to be present but blank would receive the raw string
"{{VAR_NAME}}" as its value.
Only an *absent* key now keeps its placeholder, so the existing
"import without credentials, fill them in later" flow is unchanged.
Surfaced by the Destatis GENESIS connector, which expects
`password: ""` when identifying via a personal API token.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The install modal derived its fields from requiredEnvVars and disabled
"Import with credentials" while any of them was blank. An adapter whose
credential is legitimately optional could therefore not be installed:
the only way past the gate was to type something into a field that has
to stay empty.
Adapters can now declare `optionalEnvVars`. These are prompted with an
"(optional)" label but never gate submission, and they are seeded to ''
so an untouched optional field still reaches the backend as an empty
value — without the key, {{VAR}} would survive resolution and be sent
to the target API verbatim.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Destatis permanently shut down GET requests carrying credentials as URL
parameters on 30 June 2025. Since then the GENESIS API is reachable only
via POST, with credentials as HTTP header fields and all other
parameters in an application/x-www-form-urlencoded body.
The adapter was still configured for the old mechanism (QUERY_AUTH +
GET), so every tool was broken: a GET now returns the GENESIS HTML web
interface instead of JSON. The marketplace label "Query Param Auth" was
accurate — the configuration behind it was what had gone stale.
Changes:
- authType QUERY_AUTH -> API_KEY with headerName "username" plus an
extraHeaders password field (Destatis expects header fields named
literally `username` / `password`, not Authorization: Basic).
- All tools: GET + queryParams -> POST + bodyMapping with
bodyEncoding "form-urlencoded".
- baseUrl -> https://genesis.destatis.de/... (the www-genesis host
now answers with a 307).
- Personal API token support: the token replaces the username and
needs no password, so DESTATIS_USERNAME becomes
DESTATIS_USERNAME_OR_TOKEN (required) and DESTATIS_PASSWORD becomes
optional.
- New destatis_login_check tool + instructions documenting the token's
read-only limitation (job=true needs a password), the 3-parallel-
request cap and Code 98 on oversized tables.
Tool names are unchanged, so existing installs keep working once
credentials are re-entered.
Also documents a trap found while verifying: unauthenticated find/find
does not fail. It answers Code 0 as the GAST guest account with every
result list null — indistinguishable from a genuine no-hits search. The
data and metadata services fail loudly with Code 15 instead.
Tests: destatis-genesis.spec.ts adds 7 always-on static guards pinning
POST + header auth + form-urlencoded bodies + the canonical host (5 of
them fail against the previous configuration). destatis-genesis.live.spec.ts
adds opt-in live coverage via RUN_DESTATIS_LIVE.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
I have read the CLA Document and I hereby sign the CLA You can retrigger this bot by commenting recheck in this Pull Request. Posted by the CLA Assistant Lite bot. |
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
A customer evaluating the Destatis GENESIS connector reported that our marketplace page advertises "Query Param Auth" while Destatis shut that mechanism down. They were right — and the problem is worse than a stale label: the connector is broken, and has been since 30 June 2025.
Destatis permanently disabled GET requests carrying credentials as URL parameters on that date. From their own migration guide:
The adapter was still on
QUERY_AUTH+GET, so all four tools returned the GENESIS HTML web interface instead of JSON. The"Query Param Auth"label was accurate — the configuration behind it was what had gone stale.The customer also asked whether we support GENESIS' personal API token. We did not. We do now.
Fixing this surfaced two latent platform bugs that blocked the token path, so this PR is three commits.
Changes
fix(adapters): resolve empty credentials to empty, not placeholder—AdaptersService.resolveString()usedcredentials[key] || '{{key}}', so an explicitly-supplied empty credential fell back to the literal placeholder. Any API needing a header present-but-blank would receive the raw string"{{VAR_NAME}}"as its value. Only an absent key now keeps its placeholder, so the "import now, add credentials later" flow is untouched. Affects all adapters — latent until an API needed a deliberately-blank credential.feat(adapters): support optionalEnvVars in the install modal— the modal derived fields fromrequiredEnvVarsand disabled Import while any was blank, so an adapter with a legitimately-optional credential could not be installed: the only way past the gate was to type something into a field that must stay empty. Adapters can now declareoptionalEnvVars— prompted with an "(optional)" label, never gating submission, and seeded to''so an untouched field still reaches the backend as an empty value.fix(adapters): migrate Destatis GENESIS to POST/header auth— the actual connector fix:QUERY_AUTH(credentials in URL)API_KEY,headerName: "username"+extraHeaders.passwordGET× 4 toolsPOST× 5 toolsqueryParamsbodyMapping+bodyEncoding: "form-urlencoded"www-genesis.destatis.degenesis.destatis.de(the old host now 307s)DESTATIS_USERNAME+DESTATIS_PASSWORD, both requiredDESTATIS_USERNAME_OR_TOKENrequired,DESTATIS_PASSWORDoptionalDestatis expects header fields named literally
username/password— notAuthorization: Basic. Token support follows their model exactly: the token replaces the username and needs no password, so one field accepts either. Also adds adestatis_login_checktool and instructions covering the token's read-only limitation (job=trueneeds a password), the 3-parallel-request cap, andCode 98on oversized tables.Tool names are unchanged — existing installs keep working once credentials are re-entered.
Guides updated in en / de / it.
Type
Testing
destatis-genesis.spec.ts— 7 always-on static guards pinning POST + header auth + form-urlencoded bodies + the canonical host, and asserting no credential ever appears in a tool body or path. These earn their keep: run against the previous adapter JSON, 5 of the 7 fail.destatis-genesis.live.spec.ts— opt-in live coverage (RUN_DESTATIS_LIVE=1 DESTATIS_USERNAME_OR_TOKEN=…) assertingStatus.Code === 0per endpoint andUsername !== 'GAST'.Verified live against the real API with
curl:200+ valid JSON. The mechanism is accepted (dummy credentials correctly rejected).find/findas the guest account →Code: 0, with the response echoing back the parsedParameterblock (term,category,language). This confirms body-field mapping is accepted, not just header auth.Suite status: validator 187/187 adapters pass; backend 3,236 tests pass, 0 failures; ESLint clean on all touched files.
While verifying, I found that unauthenticated
find/finddoes not fail. It answersCode: 0/"erfolgreich"as theGASTguest account with every result listnull— indistinguishable from a genuine no-hits search. The data and metadata services are stricter and fail loudly withCode: 15. So a misconfigured connector reports "no results found" rather than "not authenticated". That asymmetry is documented in the adapter instructions and all three guides, and is whydestatis_login_checkexists.Not addressed here
Two of the three remaining endpoints are credential-gated and unverified end-to-end.
data/table,metadata/tableandcatalogue/statisticsreturnCode: 15without real credentials, so their parameter-in-body mapping is inferred from the official documentation rather than proven by a passing request. The docs are unambiguous andfind/findconfirms the framework parses body params uniformly, but this deserves one smoke test with a real token before it ships. Free registration: https://genesis.destatis.deThe live spec cannot currently run, for a pre-existing reason unrelated to this PR: importing
RestEnginepulls inconnectors/engines/unblocker-proxy-agent.ts, which fails to type-check because rootnode_modulesresolveshttps-proxy-agent@5.0.1whilepackages/backend/package.jsondeclares^7.0.6. The source is correct for v7 — this is a hoisting/lockfile issue that breaks 46 test suites repo-wide (oxomi.live.spec.tsfails identically on untouchedmain), so I deliberately left it alone rather than rewriting correct code to match the wrong version. Worth its own issue. Until then, verify withcurlor via the connector's tools in the UI.No unit test for the
resolveStringfix — every spec importingadapters.service.tsalready fails to compile onmain(stale generated Prisma client, missinguseProxy), so a test there would silently never run. I preferred to flag that over adding a test that does not execute.Checklist
npm test) — 3,236 pass, 0 failures; the 46 suites that fail to compile do so identically onmainRelated Issues
No tracking issue — reported directly via customer support. Per CODEOWNERS,
/packages/backend/src/adapters/is co-owned by @D3nisty, who may want a look at the adapter JSON and the newoptionalEnvVarsfield.🤖 Generated with Claude Code