Skip to content

fix(web): send the API key on direct fetches; fix Playground replay and View run - #1169

Closed
santoshkumarradha wants to merge 2 commits into
mainfrom
fix/web-direct-fetch-auth
Closed

santoshkumarradha wants to merge 2 commits into
mainfrom
fix/web-direct-fetch-auth

Conversation

@santoshkumarradha

Copy link
Copy Markdown
Member

Summary

With API key auth on, several UI screens fail with a 401 because they call fetch directly and never send X-API-Key. Separately, the Playground's replay and "View run" are broken.

 services/api.ts
+  authHeaders()              // X-API-Key from the key the app signed in with

 pages/IntegrationsPage.tsx          fetch(…)  + ...authHeaders()
 pages/TriggersPage.tsx              fetch(…)  + ...authHeaders()
 components/triggers/TriggerSheet    fetch(…)  + ...authHeaders()
 components/triggers/NewTriggerDialog fetch(…) + ...authHeaders()
 components/triggers/EventDetailPanel replay   + ...authHeaders()
 components/execution/ExecutionRetryPanel      + ...authHeaders()
 services/vcApi.ts  resolution-bundle/download + { headers: authHeaders() }
-components/StepDetail          localStorage.getItem("agentfield_api_key")   // never written
-components/WorkflowDAG/NodeDetailSidebar  sessionStorage.getItem("apiKey") // never written
+  both                          ...authHeaders()

Playground:

 replay / recent run → input box
-  {"input": {"ticket_id": …}}         // stored request body, envelope included
+  {"ticket_id": …}                    // envelope removed
 Execute
-  POST {input: {input: {...}}}        // reasoner: "Missing required field: ticket_id"
+  POST {input: {...}}
 View run
-  /runs/<execution_id>                // 404
+  /runs/<run_id>

Type of change

  • Bug fix

Evidence

  • Before: Integrations page shows HTTP 401: {"error":"unauthorized", … "invalid or missing API key"}. Replaying a triage_ticket run in the Playground and pressing Execute returns agent error (422): Missing required field: ticket_id. View run after a Playground execution shows HTTP error! status: 404.
    After: Integrations lists all providers; Replay → Execute on the same run returns succeeded (driven end to end in a headless browser against a control plane with API key auth on); View run opens the run.
  • StepDetail.test.tsx "submits approval actions" previously passed only because it stubbed localStorage.getItem to return the key from the never-written slot; it now sets the key the way the app does (setGlobalApiKey) and asserts the same header.

Test plan

  • cd control-plane/web/client && npx tsc --noEmit -p tsconfig.app.json
  • npx vitest run (141 files, 837 tests pass)
  • npm run build
  • Manual: control plane with AGENTFIELD_API_KEY set → Integrations, Triggers, Playground replay + Execute + View run

Merge Danger

Door: two-way

Frontend only; no API or storage change. Revert restores the previous behaviour.

Blast Radius: small

Requests that already worked are unchanged (the header is only added where it was missing, and authHeaders() is empty when no key is set). The Playground only unwraps an object whose single key is input holding an object; a reasoner whose own schema is exactly one field named input (an object) would now have that field unwrapped when replayed or pasted.

…und input

Several UI calls use fetch directly instead of the shared client and never send X-API-Key, so with API key auth on they fail with 401: the Integrations and Triggers pages, the trigger sheet, new-trigger dialog and event replay, step approval actions, the workflow graph's step details, execution retry, and the DID resolution bundle download. Two of them read the key from storage slots the app never writes (localStorage agentfield_api_key, sessionStorage apiKey). They now use one authHeaders() helper backed by the key the app signed in with.

Replaying a run in the Playground pre-filled the stored request body, which is the whole {"input": {...}} envelope; Execute wrapped it again, so the reasoner received input.input and rejected the call with missing required fields. The envelope is now removed when the box is filled from a replay or a recent run, and before execute.
The execute response carries both execution_id and run_id; the Playground preferred execution_id, so View run went to /runs/<execution id>, which is a 404. It now prefers run_id.
@santoshkumarradha
santoshkumarradha requested review from a team and AbirAbbas as code owners November 9, 2026 13:56
@github-actions

github-actions Bot commented Nov 9, 2026

Copy link
Copy Markdown
Contributor

📊 Coverage gate

Thresholds from .coverage-gate.toml: per-surface ≥ 84%, aggregate ≥ 85%, max per-surface regression ≤ 1.0 pp, max aggregate regression ≤ 0.50 pp.

Surface Current Baseline Δ
control-plane 88.20% 87.40% ↑ +0.80 pp 🟡
sdk-go 93.80% 92.00% ↑ +1.80 pp 🟢
sdk-python 94.73% 93.73% ↑ +1.00 pp 🟢
sdk-typescript 92.44% 90.42% ↑ +2.02 pp 🟢
web-ui 84.89% 84.79% ↑ +0.10 pp 🟡
aggregate 86.11% 85.75% ↑ +0.36 pp 🟡

✅ Gate passed

No surface regressed past the allowed threshold and the aggregate stayed above the floor.

@github-actions

github-actions Bot commented Nov 9, 2026

Copy link
Copy Markdown
Contributor

📐 Patch coverage gate

Threshold: 80% on lines this PR touches vs origin/main (from .coverage-gate.toml:thresholds.min_patch).

Surface Touched lines Patch coverage Status
control-plane 0 — ➖ no changes
sdk-go 0 — ➖ no changes
sdk-python 0 — ➖ no changes
sdk-typescript 0 — ➖ no changes
web-ui 16 75.00% ❌

❌ Patch gate failed

web-ui — 75.00% on 16 touched lines (4 uncovered):

File Patch coverage Missing lines
control-plane/web/client/src/pages/PlaygroundPage.tsx 71.4% 104, 105, 107, 114
control-plane/web/client/src/services/vcApi.ts 100.0%
control-plane/web/client/src/services/api.ts 100.0%

How to fix

  1. For each file listed above, add tests that exercise the missing line numbers in this same PR.
  2. Re-run locally: ./scripts/coverage-summary.sh && ./scripts/patch-coverage-gate.sh.
  3. Do not lower min_patch in .coverage-gate.toml to silence this — the floor is the contract.

@santoshkumarradha santoshkumarradha mentioned this pull request Nov 9, 2026
19 of 22 tasks
@santoshkumarradha

Copy link
Copy Markdown
Member Author

Folded into #1171 so all fixes get one review; commits unchanged.

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.

2 participants