feat(credentials): saved credentials and credential-only block versions, with keyless AWS/Databricks OIDC

Merged
WA
1d ago
+16517-3926

Summary

  • 79 blocks that took secrets typed into the block now have a credential-only version that signs in with a saved, shareable credential instead: all 19 AWS blocks, Databricks, and 59 single-token services (Tavily, Mem0, Zep, Discord, Cloudflare, Intercom, …). A block that already had a _v2 moves to _v3.
  • AWS and Databricks credentials can be keyless: Sim runs its own OIDC issuer (/oidc/workload), so a credential assumes a customer's AWS role (AssumeRoleWithWebIdentity) or federates into a Databricks service principal (RFC 8693) with no stored secret. Key and secret modes remain (AWS access keys, access keys that assume a role; Databricks PAT, service principal secret).
  • Each token service gets a credential type with a cheap vendor check on save (tokenCheckValidator), a policy that maps the credential onto the tools' inline params, and a connect form.

Existing workflows don't change

  • Legacy blocks are identical to staging apart from hideFromToolbar: true and sunset: { status: 'legacy', replacedBy }. Placed blocks keep running and editing as before, with an upgrade badge. Nothing is migrated or rewritten.
  • Where a legacy params builder validated or trimmed the secret, it was extracted into a function the legacy block still calls with its original checks (blocks/legacy-builders.test.ts pins the same errors and pass-through).
  • serializer/saved-credentials.test.ts checks every legacy block still serializes and requires its inline secret, and every successor serializes per operation with only a credential.
  • Without an authorized credential, AWS operations receive the identical request; S3 get_object inline signatures are byte-identical to staging (golden test).
  • Without WORKLOAD_IDENTITY_SIGNING_KEY (or with a malformed one), the issuer returns 404 and the dialogs don't offer keyless.

How successors are built

  • A successor spreads its legacy block; withSavedCredential swaps the secret fields for a credential picker in the same place (inheriting the secret's condition and required), points dependent fields and selectors at the credential, and leaves trigger fields alone. Its replaced fields come from the same SAVED_CREDENTIAL_OAUTH table the tools use.
  • Tools declare oauth.credentialSuppliedParams (and credentialParams for token credentials). The executor overwrites mapped params only after authorizing the credential and fails closed; serializer validation, agent tool-input fields, and v2 execute skip credential-supplied params by the one shared rule.
  • check-block-registry enforces the contract for every successor: provider and kind match the picker, every supplied param is filled, and every param that steers the request host is filled by the credential (probed against each tool's real URL builder), so a shared credential can't be sent to a host the caller picks.
  • The docs generator resolves multi-level spreads and same-file params builders; other blocks' docs are unchanged.

Security

  • Keyless subjects are per credential and HMAC-signed for the preparing user and workspace. Saving a keyless AWS role is refused unless the role denies a random subject, so a trust policy that skips sub can't be assumed from another workspace.
  • The credential reaches AWS operations through trusted operation context, never tool input, and is re-bound to the run's workspace. Tokens last 5 minutes, carry a per-relying-party audience, and never reach outputs or the model.
  • Validators refuse redirects and cap response bodies; a 403 counts as a scoped-but-valid key only where the vendor uses it that way, and never when the body names a bad key.

Deploy notes

  • Set WORKLOAD_IDENTITY_SIGNING_KEY (RSA PKCS#8 PEM) per environment, including Trigger workers. Rotate by moving the old key to WORKLOAD_IDENTITY_PREVIOUS_KEY.
  • The issuer defaults to <NEXT_PUBLIC_APP_URL>/oidc/workload; customer trust policies pin it, so set WORKLOAD_IDENTITY_ISSUER explicitly before anyone relies on it.

Known limits / follow-ups

  • Keyless modes are workspace-only; organization credentials offer key/secret modes.
  • AWS role assumption and Databricks token exchange run per tool call (no caching); very large parallel loops could approach STS limits.
  • Reconnecting a key-based AWS/Databricks credential opens on the keyless mode by default; the server rejects a keyless save with no stored subject.
  • s3_get_object signs its own request, so the executor resolves its session directly; every other AWS tool runs through its operation family.

Type of Change

  • New feature

Testing

  • New and updated suites: workload-identity issuer and subject, AWS and Databricks credential setup (subject pinning, host allowlist), AWS executor signing and refusals, token validators (incl. Brex and Flint), host-steering probe, serializer per-operation coverage for every legacy and successor block, legacy params builders, withSavedCredential, S3 signing goldens. Each new guard was reverted to watch its tests go red.
  • Targeted Vitest runs over the touched areas (1,724 tests), bun run lint, type-check (pre-push), check-block-registry.ts origin/staging, and the docs, catalog, manifest, successor, tool-metadata, deployment-config, React Query, boundary, client-boundary, api-validation:strict, test-pattern, comment, utils and unused-export audits. Full check:audits and the full suite run in CI.
  • Sent fake keys to every token-check endpoint to confirm each rejects a bad key; S3 saved access keys checked end to end against a real bucket.

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing (new tests pass the test-audit authoring gate)
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)