Skip to content

Static api-key providers have no vault lane: migrating their keys into custody breaks quota reading (deepseek, synthetic) #15

Description

@iceteaSA

Static api-key providers have no vault lane, so migrating their keys into custody breaks their quota reading

Observed today on this host. The credential vault's migrate-opencode moved two static keys out of ~/.local/share/opencode/auth.json into custody, leaving a pointer string in the key field. Insula's quota lanes for those providers sent the pointer as the bearer and got a permanent 401:

synthetic   credential_rejected  HTTP 401   18:45:34Z → 19:14:42Z
deepseek    credential_rejected  HTTP 401   18:55:47Z → 19:14:50Z

Both recovered on the first fetch after the keys were restored to the file. Model traffic through the vault was unaffected throughout — only insula's reading of the quota was.

Why there was no fallback

deepseek.rs:176–181 and synthetic.rs:526 resolve the key as env var → opencode_auth::read_provider(...), and stop there. vault_handles.rs providers_for_id maps chatgpt:openai, oauth:anthropic, oauth:xai, oauth:google, antigravity:google, kimi-for-coding and the cookie: families; an apikey:<provider> id falls to "ignored ids outside supported vault mapping". So a vault handle for apikey:deepseek is accepted by the file loader and does nothing. (Two such handles existed here until 2026-08-26 and were revoked on exactly that finding — insula could not consume them.)

The consequence is that for api-key providers, custody and quota reading are mutually exclusive today: the key is readable by insula or it is in the vault, not both.

Ask

An apikey:<provider> vault family, served through the same CredentialSource path the OAuth lanes use — credential.get returning the key as the payload, report_auth_failure on 401 as today. Loader side is the mapping arm plus the provider's handles() preferring a vault handle over the local read when one is configured, which is the precedence the cookie lane already expresses (cookie_vault.rs handles: an explicit deposit takes the provider vault-only). Static keys do not rotate, so none of the identity/flux machinery is exercised; account_id can stay None for a single-key provider.

Not asking for the migration tool to know about insula — the fix belongs on the consumer that reads the file.

Base: insula d2f065a. Line numbers against it.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions