feat: choose the upstream credentials an assistant's turns use

Merged
DA
5d ago
+10411-1584

AIM-598 (1 of 2)

Stacked on #8042.

Summary

  • Configurable execution profiles. Profiles already decide a turn's credential per assistant, root trigger and execution context, but only from an unambiguous server configuration. A server with several fitting credentials stayed a gap. Admins can now set a server's choice to an auth client, to no upstream authentication, or back to automatic.
    • executionprofiles.SetChoice writes a new version that copies every other choice. Turns already running keep the version they bound, and the next turn binds the new one. Bind still only fills servers that have no choice, so nothing changes silently.
    • Choices are validated with the shared CheckConfiguredChoice. Userless profiles take shared credentials only (personal and EMA are refused). A server the assistant does not reach through a proxy is refused.
    • Changes require the profile's expected_version, so a stale read is a conflict, never an overwrite. Each change is audited as assistant:update_execution_profile, with before and after choices, in the same transaction.
    • Choosing grants nothing: the typed resolver's live mcp:auth checks still run on every request.
  • API
    • assistants.listExecutionProfiles (assistant read): each trigger × context, with each server's choice and its source (admin, issuance, backfill, or automatic for the choice the next turn would make). Servers with no choice show their gap reason, and every server lists the options its context can choose.
    • assistants.setExecutionProfileChoice (assistant write).
  • Dashboard: assistant → Identity → Upstream credentials. One card per trigger and context, with a select per server. Gaps are explained, and the selects are read-only without assistant write.
  • Platform MCP: new choose_assistant_upstream_credential, next to select_assistant_runtime. It previews with confirmed:false, and confirmed:true needs the exact trigger, context, server, choice and expected_version. External audience only, org admin plus assistant:write, with bounded refusals. Managed assistants cannot change their own credentials.
  • Demo seed: the identity-bound assistant reaches Linear, and an admin-chosen version has its person-backed dashboard turns use the shared token. Postflight checks it.
  • Next PR: personal connections for person-backed turns resolve as the authorizing user, and recovery links reach only that user.

Motivation

RFC section 7.8: assistant turns cannot see a consent picker, so ambiguous servers need an explicit, versioned choice that an admin can make and audit without changing turns that are already running.

Gutternote review steps

  1. Setup: the seeded demo data covers it.
  2. Sidebar → Assistants → Identity-bound assistant → the Identity tab.
  3. Under Upstream credentials, the dashboard trigger has two cards. When acting for a person shows Linear using Engineering automation token, the seeded admin choice. When acting for nobody shows Linear as Not chosen, with "No credential chosen yet. Choose one."
  4. Open the Linear select in the person-free card. It offers only Engineering automation token, because a personal account cannot serve a turn that acts for nobody. Choose it. A toast confirms the save, and the audit log shows "changed the upstream credentials of assistant".
  5. Switch it back to Automatic. The card returns to Not chosen.