Skip to content

feat(appkit): surface caller expiry and support local OBO - #597

Open
MarioCadenas wants to merge 2 commits into
execution-standalone-userfrom
execution-identity-lifecycle
Open

MarioCadenas wants to merge 2 commits into
execution-standalone-userfrom
execution-identity-lifecycle

Conversation

@MarioCadenas

@MarioCadenas MarioCadenas commented Sep 23, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Long-running caller operations now expose credential rejection as IdentityExpiredError (IDENTITY_EXPIRED) instead of opaque failures. HTTP and SSE agent responses carry the stable error code. The error retains only the existing token fingerprint, never the original credential-bearing upstream error.

This is layer 4 of the stack, based on #595 (execution-standalone-user). Design: design-docs/execution-identity-e2e.md, section 5.1.4. Cache partitioning landed in #594.

  • AppKit-managed spans record appkit.execution.principal, appkit.execution.principal_id, and the initiating user's appkit.execution.actor_id when present, including cache, tool, and connector spans. Tokens are not span attributes.
  • appkit dev-obo --profile <chosen-user-profile> --target http://127.0.0.1:3000 provides opt-in local user execution through a loopback proxy. It injects forwarded user headers, keeps credentials in memory, refreshes them, and fails closed on refresh failure. No profile is selected implicitly.
  • The proxy rejects non-loopback targets, untrusted browser origins/hosts, production, and deployed Apps. It supports HTTP/SSE, not WebSocket upgrades, and is for trusted local apps only. It does not emulate platform consent or provisioning.
  • SP stays the default, group stays deferred, and the marked DEV_OBO_FALLBACK remains when local user injection is not used.

Behavior note

Caller-scope downstream 401s surface typed expiry information. Plugin execute() preserves the existing failed-result envelope and adds an optional typed error field, so result-based consumers continue to work. Throwing and streaming APIs expose IdentityExpiredError. Non-401 failures, local missing-token errors, and SP execution retain their existing behavior. Consumers can reauthenticate rather than retry expired credentials.

Verification

  • pnpm -r typecheck
  • Full monorepo unit suite: 5,254 tests passed, one existing skip
  • Original dev-playground OBO tests remain unchanged and pass
  • Rebased on the backward-compatible, fail-closed feat(appkit): establish ambient user execution scopes #594 fix
  • Build, documentation build, formatting/lint, and unused-code checks
  • Tests cover structured 401s and wrapped causes, token-free serialization, deferred stream failures, HTTP/SSE agent errors, span identity under concurrency, local proxy header injection and refresh, and rejection boundaries.
  • No live Databricks profile or token was used. CLI credential commands are verified with fake responses; loopback HTTP integration uses fake credentials.

@MarioCadenas
MarioCadenas requested a review from a team as a code owner September 23, 2026 18:22
@MarioCadenas
MarioCadenas requested review from calvarjorge and removed request for a team September 23, 2026 18:22
@MarioCadenas
MarioCadenas added this pull request to stack #602 September 24, 2026 08:14
@github-actions

github-actions Bot commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

📦 Bundle size report

Compared against bundle-size-baseline.json (main).

@databricks/appkit

npm tarball (packed): 1.2 MB (+16 KB) — gzipped download (dist + bin; excludes release-only docs/NOTICE).

dist raw gzip
JS (runtime) 1.2 MB (+16 KB) 431 KB (+6.3 KB)
Type declarations 450 KB (+6.3 KB) 163 KB (+2.4 KB)
Source maps 2.4 MB (+29 KB) 809 KB (+11 KB)
Other 11 KB 3.7 KB
Total 4.0 MB (+52 KB) 1.4 MB (+20 KB)
Per-entry composition (own code — deps external (as shipped))
Entry Initial (gz) Lazy (gz) Total (gz) node_modules (min) Own code (min)
. 97 KB (+1.7 KB) 2.5 KB 100 KB (+1.7 KB) external 319 KB (+5.2 KB)
./beta 94 KB (+1.4 KB) 439 B (-18 B) 95 KB (+1.4 KB) external 286 KB (+4.6 KB)
./testing 40 KB (+1.8 KB) 30 KB (-18 B) 71 KB (+1.8 KB) external 205 KB (+4.3 KB)
./tsdown 520 B 0 B 520 B external 813 B
./type-generator 23 KB 0 B 23 KB external 65 KB

Chunks:

Entry Chunk Load Size (gz)
. index.js initial 93 KB
. utils.js initial 4.0 KB
. remote-tunnel-manager.js lazy 2.5 KB
./beta beta.js initial 78 KB
./beta stream-manager.js initial 5.9 KB
./beta service-context.js initial 4.1 KB
./beta wide-event-emitter.js initial 3.2 KB
./beta databricks.js initial 3.1 KB
./beta client.js initial 542 B
./beta index.js initial 20 B
./beta supervisor-api.js lazy 192 B
./beta databricks.js lazy 132 B
./beta index.js lazy 115 B
./testing manifest.js initial 27 KB
./testing index.js initial 10 KB
./testing wide-event-emitter.js initial 2.9 KB
./testing index.js lazy 26 KB
./testing remote-tunnel-manager.js lazy 2.5 KB
./testing utils.js lazy 1.2 KB
./tsdown index.js initial 520 B
./type-generator index.js initial 23 KB

@databricks/appkit-ui

npm tarball (packed): 350 KB (-4 B) — gzipped download (dist + bin; excludes release-only docs/NOTICE).

dist raw gzip
JS (runtime) 395 KB 132 KB
Type declarations 229 KB 84 KB (-1 B)
Source maps 766 KB 253 KB (+1 B)
CSS 16 KB 3.2 KB
Total 1.4 MB 472 KB
Per-entry composition (consumer bundle — deps bundled, peerDeps external)
Entry Initial (gz) Lazy (gz) Total (gz) node_modules (min) Own code (min)
./js 5.3 KB 49 KB 55 KB 208 KB 14 KB
./js/beta 20 B 0 B 20 B 0 B 0 B
./react 432 KB 49 KB 481 KB 1.3 MB 177 KB
./react/beta 1.0 KB 0 B 1.0 KB 0 B 1.9 KB

Chunks:

Entry Chunk Load Size (gz)
./js index.js initial 5.2 KB
./js chunk initial 120 B
./js apache-arrow lazy 49 KB
./js/beta beta.js initial 20 B
./react index.js initial 430 KB
./react tslib initial 2.1 KB
./react apache-arrow lazy 49 KB
./react/beta beta.js initial 1.0 KB

@github-actions

github-actions Bot commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

🤖 AppKit PR bot

🔬 Run evals

Start an eval for this PR from the evals-monitor app: Go to Evals Monitor →

📦 Try this PR's app template

Scaffolds a new app from this PR's SDK build. Run it in any folder (requires the GitHub CLI — gh auth login — and the Databricks CLI):

gh run download 36113876176 -R databricks/appkit -n appkit-template-0.78.0-pr.c8e5928-execution-identity-lifecycle-597 -D appkit-pr-597 \
  && unzip -o "appkit-pr-597/appkit-template-0.78.0-pr.c8e5928-execution-identity-lifecycle-597.zip" -d "appkit-pr-597" \
  && databricks apps init --template "appkit-pr-597"

The template pins @databricks/appkit and @databricks/appkit-ui to tarballs built from this branch, so the scaffolded app runs against this PR's code.

@MarioCadenas
MarioCadenas force-pushed the execution-identity-lifecycle branch from 2790860 to 25ecd06 Compare September 24, 2026 13:42
@MarioCadenas
MarioCadenas force-pushed the execution-identity-lifecycle branch from 25ecd06 to 45d2d28 Compare September 24, 2026 16:26
Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
Use plain punctuation in the inherited error comment so generated pages follow repository style.

Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
@MarioCadenas
MarioCadenas force-pushed the execution-identity-lifecycle branch from 45d2d28 to 81ff9a7 Compare September 25, 2026 08:36

This branch has not been deployed

No deployments
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