Skip to content

feat(credentials): saved credentials for 21 token-and-host blocks on one host-aware check factory - #9849

Merged
waleedlatif1 merged 11 commits into
stagingfrom
feat/saved-credentials-batch-3
Nov 10, 2026
Merged

waleedlatif1 merged 11 commits into
stagingfrom
feat/saved-credentials-batch-3

Conversation

@waleedlatif1

@waleedlatif1 waleedlatif1 commented Nov 10, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

  • 21 more blocks get a saved credential and a credential-only version. This time the connection is a token plus its host, region, or account ID: Algolia, Azure DevOps, Convex, Devin, Dynatrace, Email Bison, Grafana, Infisical, Jotform, Jupyter (jupyter_v3), Logfire, Mailgun, New Relic, Okta, Plane, Supabase, Thrive, Tinybird, Twilio SMS and Twilio Voice (one shared Twilio credential), and Upstash.

  • One check factory for every vendor. tokenCheckValidator gains:

    • domain and workspaceId normalizers: the normalized domain is what the credential stores and what runs use;
    • an egress profile, which sends checks to a user-chosen host through the same SSRF-guarded egress the tools use (no redirects, size cap, ENOTFOUND → site_not_found);
    • errorBodyEchoesToken, which keeps a vendor's token-echoing error body out of logs (Tinybird);
    • acceptsBody can name the credential from the verified reply.

    Shared normalizeHttpBaseUrl, allowedDomain and refuseUrlCredentials helpers replace the per-vendor URL and region rules.

    GitLab moves onto it, so every token check is a short declaration in validators/token-checks.ts.

  • Every host-deciding param comes from the credential.

    • A typed host is normalized the way the tools build their URLs, then verified at that host.
    • A region or account ID is checked before any request, so a value that could steer the host or path is refused before the key is sent.
    • The registry contract check enforces this for every successor.
  • The connect form sends URL-shaped domains as typed. Instance and deployment URLs keep their scheme and path, and the server check normalizes them. Before this, it stripped them to a bare host, which broke Convex and dropped Jupyter and Grafana sub-paths.

  • Azure DevOps URLs are traversal-safe. Every project-scoped URL goes through one builder that runs the organization, project and ids through safeUrlPathSegment, so a project like ../../other-org can't carry a saved token into another organization. A legitimate name, including one with spaces or pasted already encoded, builds the same URL as before.

  • Integration skills teach the pattern. add-integration, add-block, add-tools and validate-integration now describe token credentials (descriptor, check declaration, the shared policy mapping every host-deciding param) and credential-only successors for blocks that take a secret inline.

  • New credentials default to a name with their domain or account ID (e.g. "Azure DevOps (contoso)"), and the audit log records it.

  • Databricks keyless tokens last up to an hour. Databricks gives its access token the same expiry as Sim's subject token, so long Genie polls no longer lose auth. The issuer caps any requested lifetime at an hour.

Release-audit fixes (credentials as a whole)

  • No stray host in user params. A policy that maps credential fields owns them, so the generic domain/instanceUrl/apiDomain/cloudId fills no longer write a stored host into a same-named param. Before this, Thrive create/update user sent its region host as the user's domain.
  • Agent tool schema. With a saved credential selected, the model is neither asked for nor allowed to send what the credential supplies (Azure DevOps organization, Infisical base URL).
  • Mistyped host under Bun. ENOTFOUND is read from the error or its cause, so a mistyped host or account id gives site_not_found under Bun too, not a retryable outage.
  • Saved secrets need a bound tool. A service-account secret is released only to a tool bound to its provider. The token route refuses a bare credential ID.
  • Unsafe typed URLs refused. The connect check refuses a typed instance URL with a non-http(s) scheme or embedded credentials (Email Bison, Jupyter, Logfire).
  • Docs and copy. Successor docs (Jotform, Dynatrace, Logfire, Plane, Infisical, Fathom, Supabase), self-hosting, the AWS keyless step, and ElevenLabs/Instantly/Okta copy.

Existing workflows don't change

  • Legacy blocks only gain hideFromToolbar: true and sunset; jupyter_v2 becomes legacy for jupyter_v3, and jupyter (v1) now points at jupyter_v3.
  • A parity run dumped every block and tool at staging and at this branch, using the real registries, and compared them:
    • Blocks: builder output for every operation, serializer output, and missing-field errors.
    • Tools: request URL, method, headers and body.
    • Everything is identical except the new successors, the legacy flags, the added oauth (required: false) on these tools, and Azure DevOps URLs (below).
  • All 74 existing tokenCheckValidator validators were run through 11 reply scenarios at both revisions: 814 cases, no differences.

Held back

Each of these doesn't fit the pattern cleanly:

  • Optional key or keyless servers: Dagster, Temporal, Qdrant (its operation values don't match its tool IDs either).
  • Two secrets or multiple auth modes: Splunk, PostHog, Zendesk, Elasticsearch.
  • No side-effect-free check: Google AppSheet, RevenueCat.
  • A2A: no reliable key check.
  • Host or IDs that don't fit: LogRocket (key plus two IDs and a host), Pinecone (host chosen per call).
  • PitchBook: its check may cost credits; unverified.
  • Downdetector: the auth model is unclear.
  • GitHub: it already has OAuth repository and app-installation connections, so a token credential needs a design pass of its own.

Type of Change

  • New feature

Testing

  • New tests:

    • Factory: guarded egress at the normalized host, normalizer refusal before any request, site_not_found, no token in error details.
    • A table of vendors that refuse a host, region or account ID that could steer the request.
    • Every user-chosen-host vendor refuses credentials embedded in the URL before any request.
    • Azure DevOps anonymous-identity refusal.
    • GitLab display name and audit domain.
    • Issuer lifetime cap.
    • Serializer contract rows for all 21 blocks.

    Each guard was reverted to watch its test go red.

  • Targeted Vitest (99 files, 1,760 tests), test:scripts, bun run lint, type-check, check-block-registry.ts origin/staging (incl. the saved-credential contract), and the canvas-sentences, docs, integration-catalog, deployment-config, block-successors, tool-metadata, boundaries, client-boundary, tool-registry-boundary, react-query, test-pattern, test-types, comment, utils, explicit-any, file-names, source-conventions and unused-exports audits.

  • Parallel audits: per block (all 21), the factory and every existing validator, backwards compatibility (parity dump), and a coverage sweep of every block that still takes an inline secret. Fake keys were sent to each public vendor endpoint to confirm it rejects them.

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)

@vercel

vercel Bot commented Nov 10, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
docs Ready Ready Preview Nov 10, 2026 9:18pm UTC

Request Review

@greptile-apps

greptile-apps Bot commented Nov 10, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 5/5

[High impact] The reviewed changes appear safe to merge; no blocking issue was found.

Summary

Adds saved credentials and credential-only successors for 21 blocks, using one host-aware token-check factory.

  • More integration blocks can use a saved token and connection.
  • Azure DevOps project URLs keep names inside their intended path segments.
  • Databricks keyless tokens can last longer during extended runs.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  A[Token and connection fields] --> B[Normalize and check]
  B --> C[Save credential]
  C --> D[Authorize credential for tool]
  D --> E[Fill declared tool fields]
  E --> F[Run tool at saved host]
Loading

Reviews (6) · Last reviewed commit: "fix(credentials): refuse non-http scheme..." · Reviewed by Greptile

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 504 files

Note: This PR contains a large number of files. cubic selects up to 200 of the highest-priority eligible files for this review, so some files may not have been reviewed.

Turn on auto-fix | Re-trigger cubic

@waleedlatif1
waleedlatif1 force-pushed the feat/saved-credentials-batch-3 branch from fb59722 to c5b0bbc Compare November 10, 2026 20:19
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cubic-dev-ai review this PR

@cubic-dev-ai

cubic-dev-ai Bot commented Nov 10, 2026

Copy link
Copy Markdown
Contributor

@cubic-dev-ai review this PR

@waleedlatif1 I have started the AI code review. It will take a few minutes to complete.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 506 files

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.

Note: This PR contains a large number of files. cubic selects up to 200 of the highest-priority eligible files for this review, so some files may not have been reviewed.

Turn on auto-fix | Re-trigger cubic

…r factory

tokenCheckValidator now takes a domain normalizer (stored as the credential's
domain), an account-id normalizer, an SSRF-guarded egress profile for hosts
the user chose, and a flag that keeps token-echoing error bodies out of logs.
GitLab becomes a declaration on it, so every token check reads the same way.
Algolia, Azure DevOps, Convex, Devin, Dynatrace, Email Bison, Grafana,
Infisical, Jotform, Jupyter (v3), Logfire, Mailgun, New Relic, Okta, Plane,
Supabase, Tinybird, Twilio SMS and Voice (one shared Twilio credential), and
Upstash get a credential that carries the token plus its host, region, or
account id, and a credential-only successor. Every host-deciding param comes
from the credential; a typed host is normalized as the tools do it and
verified through the guarded egress, a region or account id is checked
before any request, and Databricks subject tokens last up to an hour so
long Genie polls keep their token.
…it findings

Thrive gets a credential holding its key, tenant id, and region host (one of
its four API hosts). Audit fixes: the connect form sends URL-shaped domains
as typed so the provider check keeps their scheme and path; credentials
default to a name with their domain or account id (GitLab keeps its token
name) and record it in the audit log; Upstash accepts http and a read-only
token refused PING; Infisical keeps http and a proxy path; Devin, Dynatrace,
and Logfire refuse dot segments, non-http schemes, and mistyped regions.
…ecks

One normalizeHttpBaseUrl and one allowedDomain replace five URL normalizers
and four region checks (fixing Grafana and Tinybird treating a non-http
scheme as a host); region tables come from the tools; acceptsBody can name
the credential (GitLab); Email Bison and Jupyter refuse credentials in the
URL instead of dropping them; the Supabase public-URL policy is inlined; the
Databricks token lifetime uses the issuer's cap.
Azure DevOps tools build every project-scoped URL through one traversal-safe
helper, so a project or build id can't climb into another organization with a
saved token; Tinybird and Upstash restricted-token replies are covered by
tests.
An Azure DevOps project or organization pasted already encoded is decoded
once before the traversal-safe segment, so it isn't encoded twice; a base
URL with a single-slash scheme is refused; Upstash accepts a proxy path like
the legacy block; a Thrive tenant id must be printable ASCII.
@waleedlatif1
waleedlatif1 force-pushed the feat/saved-credentials-batch-3 branch from c5b0bbc to e02e8d9 Compare November 10, 2026 20:41
…tion skills

add-integration, add-block, add-tools, and validate-integration now describe
the token credential (descriptor, tokenCheckValidator declaration with its
host and account normalizers, shared policy mapping every host-deciding
param) and credential-only successors for blocks that take a secret inline.
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cubic-dev-ai review this PR

@cubic-dev-ai

cubic-dev-ai Bot commented Nov 10, 2026

Copy link
Copy Markdown
Contributor

@cubic-dev-ai review this PR

@waleedlatif1 I have started the AI code review. It will take a few minutes to complete.

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

4 issues found across 510 files

Confidence score: 4/5

  • In .agents/skills/add-tools/SKILL.md, the example uses a nonexistent SERVICE_CREDENTIAL_OAUTH factory, so copying it can fail to compile. Point readers to tokenCredentialOAuth instead.
  • In .agents/skills/validate-integration/SKILL.md, the checklist requires tokenCredentialOAuth even for ordinary browser-OAuth integrations. Limit that requirement to token-credential integrations.
  • In .agents/skills/add-integration/SKILL.md, requiring AuthMode.OAuth for token credentials conflicts with the token-only AuthMode.ApiKey path. Make the auth-mode choice conditional.
  • In .agents/skills/validate-integration/SKILL.md, the check applies to legacy blocks that intentionally keep inline password inputs. Scope it to credential-only successor blocks.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name=".agents/skills/validate-integration/SKILL.md">

<violation number="1" location=".agents/skills/validate-integration/SKILL.md:221">
P3: This checklist item applies to every block, but legacy blocks keep their inline `password` inputs by design. Scope it explicitly to credential-only successor blocks, e.g. 'For a credential-only successor, a pasted key comes from a saved token credential...', so auditors don't flag legacy blocks.</violation>

<violation number="2" location=".agents/skills/validate-integration/SKILL.md:224">
P2: This checklist unconditionally requires `tokenCredentialOAuth` for every tool, including ordinary browser-OAuth integrations. Qualify it as a requirement for token-credential integrations so the normal `oauth: { required: true, provider }` contract remains valid.</violation>
</file>

<file name=".agents/skills/add-tools/SKILL.md">

<violation number="1" location=".agents/skills/add-tools/SKILL.md:93">
P2: `SERVICE_CREDENTIAL_OAUTH` does not exist in `tools/shared/saved-credentials.ts`, so copying this snippet fails to compile. Point readers to the real factory, `tokenCredentialOAuth('{service}', { apiKey: 'accessToken' })`, and say the mapping keys are the tool's own token/host/account params.</violation>
</file>

<file name=".agents/skills/add-integration/SKILL.md">

<violation number="1" location=".agents/skills/add-integration/SKILL.md:94">
P2: This step unconditionally requires `AuthMode.OAuth` for token credentials, contradicting the later token-only `AuthMode.ApiKey` path and its required availability registration. Make the auth-mode choice conditional on the credential flow, so token-only services retain the documented API-key path.</violation>
</file>

Note: This PR contains a large number of files. cubic selects up to 200 of the highest-priority eligible files for this review, so some files may not have been reviewed.

Turn on auto-fix | Re-trigger cubic

Comment thread .agents/skills/add-tools/SKILL.md Resolved
Comment thread .agents/skills/add-integration/SKILL.md Resolved
Comment thread apps/sim/tools/emailbison/utils.ts Resolved
The token-credential skill steps name the real tokenCredentialOAuth factory,
scope the checklist to token-credential and successor blocks, and keep the
AuthMode.ApiKey path for token-only blocks; normalizeEmailBisonBaseUrl gains
its TSDoc.
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cubic-dev-ai review this PR

@cubic-dev-ai

cubic-dev-ai Bot commented Nov 10, 2026

Copy link
Copy Markdown
Contributor

@cubic-dev-ai review this PR

@waleedlatif1 I have started the AI code review. It will take a few minutes to complete.

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 510 files

Note: This PR contains a large number of files. cubic selects up to 200 of the highest-priority eligible files for this review, so some files may not have been reviewed.

Turn on auto-fix | Re-trigger cubic

Comment thread apps/sim/tools/emailbison/utils.ts Resolved
…ps scheme

normalizeEmailBisonBaseUrl now keeps any typed scheme, so ftp://host is
refused instead of becoming a host named ftp.
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cubic-dev-ai review this PR

@cubic-dev-ai

cubic-dev-ai Bot commented Nov 10, 2026

Copy link
Copy Markdown
Contributor

@cubic-dev-ai review this PR

@waleedlatif1 I have started the AI code review. It will take a few minutes to complete.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 510 files

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.

Note: This PR contains a large number of files. cubic selects up to 200 of the highest-priority eligible files for this review, so some files may not have been reviewed.
You've manually re-run cubic several times on this PR. Each manual re-review checks the full PR again and counts toward your usage quota. To preserve your usage limits, we recommend letting cubic automatically review new commits.

Turn on auto-fix | Re-trigger cubic

…l executor

- A policy that maps credential fields owns them: the generic domain,
  instanceUrl, apiDomain and cloudId fills no longer write a stored host
  into a same-named user param (Thrive create/update user sent its region
  host as the user's domain).
- An agent tool with a saved credential selected is neither asked for nor
  allowed to send the params the credential supplies (Azure DevOps
  organization, Infisical base URL).
- ENOTFOUND is read from the error or its cause, so a mistyped host or
  account id is site_not_found under Bun as well as Node.
- A service-account secret is released only to a tool bound to its
  provider; a bare credential ID is refused.
…s and copy

- One refuseUnsafeTypedUrl guard refuses a typed instance URL with
  credentials or a non-http(s) scheme, for Email Bison, Jupyter and
  Logfire, before their normalizers can read the scheme as a host. The
  Email Bison tool normalizer is back to its staging behavior; the check
  lives in the credential validator, so legacy blocks are unchanged.
- Docs for successor users: Jotform region, Dynatrace scopes, Logfire
  host, Plane instance, Infisical, Fathom and Supabase now point at the
  saved credential; self-hosting no longer says API keys live in blocks;
  the AWS keyless step names the dialog's Issuer.
- ElevenLabs and Instantly copy no longer asks for a permission their
  checks don't need; Okta lists trexcloud.com.
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cubic-dev-ai review this PR

@cubic-dev-ai

cubic-dev-ai Bot commented Nov 10, 2026

Copy link
Copy Markdown
Contributor

@cubic-dev-ai review this PR

@waleedlatif1 I have started the AI code review. It will take a few minutes to complete.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 519 files

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.

Note: This PR contains a large number of files. cubic selects up to 200 of the highest-priority eligible files for this review, so some files may not have been reviewed.
You've manually re-run cubic several times on this PR. Each manual re-review checks the full PR again and counts toward your usage quota. To preserve your usage limits, we recommend letting cubic automatically review new commits.

Turn on auto-fix | Re-trigger cubic

This branch was successfully deployed

1 active deployment
Preview — 914e5199 Deployed Nov 10, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant