← Community
bugopen

Saving a module-scoped credential permanently strips its own Add-credential form fields on next load

Muhammad Akif JanjuaMuhammad Akif Janjua#41h ago · 2 views
affected: station-v1.5.8

Reproduction steps:

  1. Install a module whose credential_spec.provider collides with an existing

provider (Station auto-namespaces it as "<module-slug>::<provider>").

  1. Go to Studio → Integrations → find that namespaced provider card — the

Add-credential form correctly shows all fields (e.g. Label + API key) on
first load.

  1. Successfully save a credential for it once (even if the save appears to

fail — see linked bug re: filename crash, which still writes the credential
before crashing).

  1. Reopen "Add credential" for that same provider again.

Expected: Form still shows all declared credential fields (Label, API key, etc.)

Actual: Form only shows "Label" — the API key (and any other declared) field
never appears again, permanently, for that provider.

Root cause: /api/integrations/list (integrations_list()) builds its result in
two passes. Pass 1 iterates the static integrations.json file and emits a thin
entry (id, name, category, status, risk, read_write) with no credential_specs
field. Pass 2 iterates _module_credential_specs() (computed fresh from loaded
module manifests) and emits a rich entry that DOES include credential_specs —
but only if the provider id isn't already in Pass 1's seen_ids set.

Separately, _handle_credential_save calls _mirror_integrations_json_flip(iid)
on every successful save, which writes a thin snapshot directly into
integrations.json's "Modules" category (id/name/status/risk/read_write/
saved_at/source).

So: before any save, the namespaced provider has no integrations.json entry,
Pass 2 wins, form renders correctly. The moment any save succeeds (even one
that later crashes on the receipt-writing step), a thin entry gets
permanently planted in integrations.json. From then on, Pass 1 claims the id
first, Pass 2 skips it as already-seen, and credential_specs never reaches
the frontend again.

Verified directly via GET /api/integrations/list for the affected id: response
keys are [action_class, available, category, env_vars, id, name,
named_credential_count, named_default_id, rank, read_write, resolved_via,
risk, search, status, vault_key_present, verb] — missing credential_specs,
source, declared_provider, auto_namespaced, all of which the Pass-2 path
would include.

Impact: Breaks the Add-credential form for any module-scoped/namespaced
provider, permanently, after the first successful save — independent of OS,
and independent of the separate Windows filename-crash bug (this happens even
if the save fully succeeds with no crash).

Module slug + version: muhammad-akif-janjua/notion-guard (dev build)

0 replies

Sign in to reply.