Skip to content

[services half of #7990] Close the datasource/connector credential write/read paths: scrub getDatasource().config, fix the false "credential-stripped" claim, and write the stored-cleartext-rows migration story #8081

Description

@huangyiirene

Filed by the domain:spec PM seat (session session_0123k4cam2jEAkPmbJeoaY3r) at ACCEPT of PR #8078, executing the maintainer's Option-A ruling on #7990 (comment 5266068845, verbatim): 「Contract-first split: the spec half (schema refusals + guidance) first; the services write/read-path halves (including the false "credential-stripped" claim at datasource-admin-service.ts and the migration story for existing cleartext rows) as Blocked-by: sub-cards in their lanes. The existing-rows migration is in scope of the programme, not optional.」 Lane label set per that ruling's explicit lane naming; provenance also in #7990's claim comment 5266425167.

Blocked-by:#8078

Scope (the ruling's services half)

  1. Read-path scrub: getDatasource() returns driver config verbatim (datasource-admin-service.ts:199) while :179 carries a "credential-stripped" comment that never covered config — the code claims a protection it does not perform ([security] sys_metadata.metadata is a general cleartext sink: any authored artefact whose schema permits an inline credential lands it there (datasource config.password, connector authentication) #7990 body, survey-verified). With feat(spec)!: refuse inline credentials at publish — driver config + connector authoring door (#7990, spec half) #8078 landed, new rows cannot carry config.password/config.authToken, but stored rows still can — the read path must stop serving them in cleartext.
  2. Write-path behavior for legacy inline payloads: post-feat(spec)!: refuse inline credentials at publish — driver config + connector authoring door (#7990, spec half) #8078 a legacy payload is refused at parse. Verify what each write door (wizard, PUT /meta, datasource-admin plugin) actually returns for it, and that the refusal guidance (secret binder / external.credentialsRef) surfaces to the caller rather than a generic 500.
  3. Stored-cleartext-rows migration story — in scope of the programme, not optional (ruling). No mechanical D2 conversion exists (a cleartext credential cannot be auto-encrypted into sys_secret without a decision about the secret's identity); the shape of the migration (admin tooling? one-time script? read-time refusal with re-entry prompt?) is this card's to propose — escalate the chosen shape if it is destructive.
  4. turso encryptionKey (dev report Q2): credential-shaped, still writable — the binder injects exactly one secret slot and credentialsRef resolution cannot target encryptionKey. Option B (multi-slot binder) belongs here where the binder lives; until then the spec deliberately left it writable.
  5. Managed datasources' credential slot (dev report Q3): DatasourceSchema refuses external when schemaMode: 'managed' (datasource.zod.ts:550), yet datasource-admin-service writes external.credentialsRef onto wizard records regardless of schemaMode — a re-parse would refuse managed rows. Dev recommendation A (allow external.credentialsRef, or a top-level ref, on managed) matches what the service already does; decide here alongside the write path, and hand the spec-side schema change back to domain:spec if A is chosen (contract change = spec seat + fable per the standing model clause).

Evidence trail

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions