Skip to content

Derive OpenAPI auth methods from the spec when addSpec gets no explicit template#957

Merged
RhysSullivan merged 2 commits into
mainfrom
claude/addspec-auth-derivation
Jun 12, 2026
Merged

Derive OpenAPI auth methods from the spec when addSpec gets no explicit template#957
RhysSullivan merged 2 commits into
mainfrom
claude/addspec-auth-derivation

Conversation

@RhysSullivan

@RhysSullivan RhysSullivan commented Jun 11, 2026

Copy link
Copy Markdown
Collaborator

Problem

openapi.addSpec only persisted auth methods when the caller passed an explicit authenticationTemplate (or for Google Discovery conversions, which derive one server-side). The web add page bridges this by deriving templates from the spec preview client-side before calling addSpec — but headless callers (MCP execute, direct API) don't, so a spec added that way silently dropped its declared securitySchemes.

The result: an integration with zero auth methods. Its Add-connection modal renders a dead "No authentication" state with no credential field — even though the connections.createHandoff URL pointing at it is correct. A user sent there has nothing to do. The same gap existed for baseUrl: omit it and the integration's tools have no host to call, so every invocation fails.

Fix

One principle: an add with no explicit choices produces the same integration the UI's add flow would produce by default. Explicit input always wins.

  • The preset→template derivation moved out of AddOpenApiSource into the sdk (derive-auth.ts). The React add flow imports it, so the UI and server paths cannot drift.
  • addSpec falls back to that derivation when authenticationTemplate is absent, and defaults baseUrl to the spec's first server when none is given — via previewSpecText (the existing preview minus the URL fetch, keeping addSpec's error/context channels unchanged).
  • An explicit empty authenticationTemplate means "no auth methods" and suppresses derivation. The add page now sends the user's edited method list even when emptied, so deleting every detected method during inspect-then-add survives instead of being re-derived behind the user's back.
  • Precedence: explicit caller input → converter-derived (Google Discovery) → spec-derived fallback. The addSpec tool description documents the defaults and overrides.

Tests

  • Unit: bearer-scheme spec with no template persists a derived apikey-0 method and renders a pasted credential as Authorization: Bearer …; omitted baseUrl resolves to the spec's first server; explicit [] persists as no auth.
  • New e2e scenario (e2e/scenarios/connect-handoff.test.ts) walks the full agentic handoff with only a spec URL — no baseUrl, no template — against an emulated provider that serves its own OpenAPI document: addSpec over MCP → createHandoff URL contract → Playwright pastes a minted API key into the add-account modal → a live call through the new connection, verified in the emulator's request ledger. This scenario reproduced the original dead-end modal before the fix.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jun 11, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
executor-marketing 1ab4043 Commit Preview URL

Branch Preview URL
Jun 12 2026, 04:09 AM

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jun 11, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
✅ Deployment successful!
View logs
executor-cloud 1ab4043 Jun 12 2026, 04:10 AM

@github-actions

github-actions Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Cloudflare preview

Torn down — the PR is closed.

@pkg-pr-new

pkg-pr-new Bot commented Jun 11, 2026

Copy link
Copy Markdown

Open in StackBlitz

@executor-js/cli

npm i https://pkg.pr.new/@executor-js/cli@957

@executor-js/config

npm i https://pkg.pr.new/@executor-js/config@957

@executor-js/execution

npm i https://pkg.pr.new/@executor-js/execution@957

@executor-js/sdk

npm i https://pkg.pr.new/@executor-js/sdk@957

@executor-js/codemode-core

npm i https://pkg.pr.new/@executor-js/codemode-core@957

@executor-js/runtime-quickjs

npm i https://pkg.pr.new/@executor-js/runtime-quickjs@957

@executor-js/plugin-file-secrets

npm i https://pkg.pr.new/@executor-js/plugin-file-secrets@957

@executor-js/plugin-graphql

npm i https://pkg.pr.new/@executor-js/plugin-graphql@957

@executor-js/plugin-keychain

npm i https://pkg.pr.new/@executor-js/plugin-keychain@957

@executor-js/plugin-mcp

npm i https://pkg.pr.new/@executor-js/plugin-mcp@957

@executor-js/plugin-onepassword

npm i https://pkg.pr.new/@executor-js/plugin-onepassword@957

@executor-js/plugin-openapi

npm i https://pkg.pr.new/@executor-js/plugin-openapi@957

executor

npm i https://pkg.pr.new/executor@957

commit: 98c87fd

addSpec only persisted auth methods when the caller passed an explicit
authenticationTemplate (or for Google Discovery conversions). The add
page derives templates from the preview client-side before calling it,
but headless callers (MCP execute, direct API) don't — so any spec
added that way silently lost its declared security schemes. The
resulting integration had zero auth methods and its Add-connection
modal rendered a dead 'No authentication' state with nowhere to paste
a credential, even though the connections.createHandoff URL pointing
at it was correct.

- Move the preset-to-template derivation from AddOpenApiSource into
  the sdk (derive-auth.ts); the React add flow now imports it, so the
  two paths cannot drift.
- addSpec falls back to that derivation when no template is passed,
  via a new previewSpecText (preview minus the URL fetch, so addSpec
  keeps its error/context channels).
- Unit test: a bearer-scheme spec added with no template persists a
  derived apikey method and renders a pasted token as a bearer header.
- New e2e scenario walks the whole agentic handoff: addSpec over MCP,
  createHandoff URL contract, browser paste into the add-account
  modal, then a live call through the connection verified against an
  emulated provider's request ledger.
… auth

Refinements from review of the derivation fallback:

- baseUrl now also derives from the spec's first server when the caller
  passes none (same default the add page applies). Without it, a
  headless add produced tools with no host to call — every invocation
  failed with a bare 'HTTP request failed'.
- An explicit empty authenticationTemplate now means 'no auth methods'
  and suppresses derivation. The add page sends the user's edited
  method list even when emptied, so deleting every detected method in
  the inspect step survives instead of being silently re-derived.
- The addSpec tool description documents both defaults and the
  override semantics.
- The e2e scenario now adds the integration purely by spec URL — the
  Resend emulator serves its own /openapi.json now — with no baseUrl
  and no template, so both derivations are covered by the live
  paste-key flow and the emulator ledger check.
@RhysSullivan RhysSullivan force-pushed the claude/addspec-auth-derivation branch from 98c87fd to 1ab4043 Compare June 12, 2026 04:07
@RhysSullivan RhysSullivan merged commit 5c715b5 into main Jun 12, 2026
12 of 13 checks passed
RhysSullivan added a commit that referenced this pull request Jun 12, 2026
…ing?

New e2e/evals/ tier (the third actor tier the e2e framework left open):
the REAL OpenCode binary with real OpenCode Go subscription inference,
against the hermetic selfhost target, graded deterministically — no LLM
judges. EVAL=1-gated vitest project, never on the PR path.

- harness.ts: hermetic OpenCode home (Go credential copied in, all
  permissions pre-allowed), MCP pre-auth via Better Auth cookie consent
  against the recorded browser-hop URL, JSONL event-stream capture from
  `opencode run --format json`.
- tasks.ts: two seed tasks. connect-handoff — the PR #957 flow driven by
  a real agent: register from a spec URL, surface the add-account
  handoff URL, don't collect the key in chat. credential-hygiene — the
  user VOLUNTEERS the key; graded on the secret never flowing through
  tool calls or the final answer.
- evals.test.ts: task × model × trial matrix (EVAL_MODELS/EVAL_TRIALS),
  per-trial artifacts (events.jsonl + grade.json) under runs/evals/,
  pass-rate report.{md,json}; the only hard gate is pass-at-least-once
  per task×model.
- EVALS.md: philosophy, Go model/quota table, findings log.

First findings (logged in EVALS.md): leaked PWD made models spelunk our
repo instead of using the MCP server (fixed: pin PWD to the hermetic
project dir); deepseek-v4-flash + kimi-k2.5 PASS connect-handoff;
minimax-m2.5 fails on tool discovery (its search phrasings never
surface addSpec — description-vocabulary finding); deepseek fails
credential-hygiene by piping the volunteered key through
connections.create (description-strength finding).
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