Generic user-extensible SecretProvider (mint short-lived secrets in the manifest) #355

Open
opened 2026-07-13 12:09:44 -04:00 by didericis-claude · 0 comments
Collaborator

Summary

Generalize the existing DeployKeyProvisioner (PRD 0048 — bot_bottle/deploy_key_provisioner.py, contrib impl bot_bottle/contrib/gitea/deploy_key_provisioner.py) into a generic SecretProvider that can be referenced anywhere in a manifest a raw token/secret value can be set, minting short-lived, scoped credentials where the upstream supports it instead of embedding a long-lived static value.

Motivation

Directly reduces the long-lived-credential concentration flagged in PRD 0070's (#351) security review: where an upstream can issue short-lived derived creds (GitHub App installation tokens, OAuth/STS token exchange, Gitea/forge deploy tokens), the bottle/sidecar should hold an expiring, narrowly-scoped credential minted at start (or per request), not a permanent secret. A compromise then leaks short-lived material, not the crown jewels. For upstreams stuck on static keys, a provider can still pass the raw value through, so the manifest surface is uniform.

Shape

  • Core ABC SecretProvider (mirrors DeployKeyProvisioner): mint(context) -> Secret (+ lifecycle/revoke where applicable). DeployKeyProvisioner becomes one implementation of it (or its narrower cousin).
  • Manifest integration: anywhere a raw value is accepted (egress route tokens, git remotes/deploy creds, env secrets), also accept a provider reference — e.g. { provider: <name>, ... } — resolved at bottle start / per request to a concrete (ideally short-lived) value. Unknown provider → fail at parse time (consistent with existing manifest strictness).
  • User-extensible, same as agent providers: discover ~/.bot-bottle/contrib/<name>/secret_provider.py via the AgentProvider._load_user_plugin mechanism (user dir checked first, can shadow built-ins). Rationale: maintaining every possible forge/cloud/OAuth provider in-tree is untenable — let users bring their own exactly as they bring their own agent providers. Built-ins stay minimal (gitea to start).

Relationship

  • PRD 0070 (#351): this is the recommended secret-handling mechanism for the orchestrator's vault-as-separate-trust-domain — the vault mints via SecretProviders and hands the data plane short-lived derived creds. But this issue is shippable independently of the orchestrator (today's per-bottle sidecars can use it too).
  • PRD 0048: generalizes the deploy-key provisioner rather than replacing it.

Open questions

  • Per-bottle-start vs per-request minting (per-request needs the vault process from 0070; per-bottle-start works today).
  • Cache/TTL/renewal for short-lived creds; who renews before expiry.
  • Manifest schema for "provider ref vs raw value" without weakening the trust-boundary-at-$HOME rules.
  • Trust domain of the minting process (should be the 0070 vault, separate from the byte-parsing data plane).
## Summary Generalize the existing `DeployKeyProvisioner` (PRD 0048 — `bot_bottle/deploy_key_provisioner.py`, contrib impl `bot_bottle/contrib/gitea/deploy_key_provisioner.py`) into a generic **`SecretProvider`** that can be referenced **anywhere in a manifest a raw token/secret value can be set**, minting **short-lived, scoped** credentials where the upstream supports it instead of embedding a long-lived static value. ## Motivation Directly reduces the long-lived-credential concentration flagged in PRD 0070's (#351) security review: where an upstream can issue short-lived derived creds (GitHub App installation tokens, OAuth/STS token exchange, Gitea/forge deploy tokens), the bottle/sidecar should hold an expiring, narrowly-scoped credential minted at start (or per request), not a permanent secret. A compromise then leaks short-lived material, not the crown jewels. For upstreams stuck on static keys, a provider can still pass the raw value through, so the manifest surface is uniform. ## Shape - Core ABC `SecretProvider` (mirrors `DeployKeyProvisioner`): `mint(context) -> Secret` (+ lifecycle/revoke where applicable). `DeployKeyProvisioner` becomes one implementation of it (or its narrower cousin). - **Manifest integration:** anywhere a raw value is accepted (egress route tokens, git remotes/deploy creds, env secrets), also accept a provider reference — e.g. `{ provider: <name>, ... }` — resolved at bottle start / per request to a concrete (ideally short-lived) value. Unknown provider → fail at parse time (consistent with existing manifest strictness). - **User-extensible, same as agent providers:** discover `~/.bot-bottle/contrib/<name>/secret_provider.py` via the `AgentProvider._load_user_plugin` mechanism (user dir checked first, can shadow built-ins). Rationale: maintaining every possible forge/cloud/OAuth provider in-tree is untenable — let users bring their own exactly as they bring their own agent providers. Built-ins stay minimal (gitea to start). ## Relationship - **PRD 0070 (#351):** this is the recommended secret-handling mechanism for the orchestrator's vault-as-separate-trust-domain — the vault mints via `SecretProvider`s and hands the data plane short-lived derived creds. But this issue is **shippable independently** of the orchestrator (today's per-bottle sidecars can use it too). - **PRD 0048:** generalizes the deploy-key provisioner rather than replacing it. ## Open questions - Per-bottle-start vs per-request minting (per-request needs the vault process from 0070; per-bottle-start works today). - Cache/TTL/renewal for short-lived creds; who renews before expiry. - Manifest schema for "provider ref vs raw value" without weakening the trust-boundary-at-$HOME rules. - Trust domain of the minting process (should be the 0070 vault, separate from the byte-parsing data plane).
didericis added the Kind/Feature label 2026-07-14 03:40:34 -04:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: didericis/bot-bottle#355