Skip to content

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
mainfrom
fix/destatis-genesis-post-header-auth
Open

fix(adapters): Destatis GENESIS connector broken since June 2025 — migrate to POST/header auth, add API token support#481
mirkopoloni wants to merge 3 commits into
mainfrom
fix/destatis-genesis-post-header-auth

Conversation

@mirkopoloni

@mirkopoloni mirkopoloni commented Aug 12, 2026

Copy link
Copy Markdown
Collaborator

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:

„Zur Verbesserung des Schutzes Ihrer Nutzerdaten, wird die bisher angebotene Möglichkeit der API Nutzung mittels GET Requests am 30. Juni 2025 endgültig abgeschaltet. Nach diesem Termin ist die Genesis-API ausschließlich mit der POST Methode erreichbar. Dabei werden die Zugangsdaten im Header der Anfrage gesendet und können damit nicht in Logfiles gelangen oder beim Transport abgegriffen werden."

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 placeholderAdaptersService.resolveString() used credentials[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 from requiredEnvVars and 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 declare optionalEnvVars — 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:

Before After
Auth QUERY_AUTH (credentials in URL) API_KEY, headerName: "username" + extraHeaders.password
Method GET × 4 tools POST × 5 tools
Parameters queryParams bodyMapping + bodyEncoding: "form-urlencoded"
Base URL www-genesis.destatis.de genesis.destatis.de (the old host now 307s)
Credentials DESTATIS_USERNAME + DESTATIS_PASSWORD, both required DESTATIS_USERNAME_OR_TOKEN required, DESTATIS_PASSWORD optional

Destatis expects header fields named literally username / passwordnot Authorization: Basic. Token support follows their model exactly: the token replaces the username and needs no password, so one field accepts either. Also adds a destatis_login_check tool and instructions covering 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 — existing installs keep working once credentials are re-entered.

Guides updated in en / de / it.

Type

  • Bug fix
  • Documentation
  • New feature
  • Refactoring
  • Performance improvement
  • Other

Testing

  • Added/updated unit tests
  • Tested manually (described below)

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=…) asserting Status.Code === 0 per endpoint and Username !== 'GAST'.

Verified live against the real API with curl:

  • POST + header credentials → 200 + valid JSON. The mechanism is accepted (dummy credentials correctly rejected).
  • GET → returns the GENESIS HTML web UI. Confirms the endpoint is gone, not merely deprecated.
  • find/find as the guest account → Code: 0, with the response echoing back the parsed Parameter block (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.

⚠️ One trap worth knowing about

While verifying, I found that unauthenticated find/find does not fail. It answers Code: 0 / "erfolgreich" as the GAST guest account with every result list nullindistinguishable from a genuine no-hits search. The data and metadata services are stricter and fail loudly with Code: 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 why destatis_login_check exists.

Not addressed here

Two of the three remaining endpoints are credential-gated and unverified end-to-end. data/table, metadata/table and catalogue/statistics return Code: 15 without 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 and find/find confirms the framework parses body params uniformly, but this deserves one smoke test with a real token before it ships. Free registration: https://genesis.destatis.de

The live spec cannot currently run, for a pre-existing reason unrelated to this PR: importing RestEngine pulls in connectors/engines/unblocker-proxy-agent.ts, which fails to type-check because root node_modules resolves https-proxy-agent@5.0.1 while packages/backend/package.json declares ^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.ts fails identically on untouched main), so I deliberately left it alone rather than rewriting correct code to match the wrong version. Worth its own issue. Until then, verify with curl or via the connector's tools in the UI.

No unit test for the resolveString fix — every spec importing adapters.service.ts already fails to compile on main (stale generated Prisma client, missing useProxy), so a test there would silently never run. I preferred to flag that over adding a test that does not execute.

Checklist

  • My code follows the existing code style
  • I have tested my changes locally
  • I have updated documentation (if applicable)
  • All existing tests pass (npm test) — 3,236 pass, 0 failures; the 46 suites that fail to compile do so identically on main
  • This PR has a descriptive title

Related 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 new optionalEnvVars field.

🤖 Generated with Claude Code

mirkopoloni and others added 3 commits August 12, 2026 13:04
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>
@github-actions

Copy link
Copy Markdown


Thank you for your submission, we really appreciate it. Like many open-source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution. You can sign the CLA by just posting a Pull Request Comment same as the below format.


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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant