Skip to content

workspace: resolver caches are scoped by tenant+host, not credential — a same-tenant account switch can inherit the previous account's cached link for up to 5 min #1339

Description

@sahrizvi

Problem

resolveBindingOutcome in packages/opencode/src/altimate/workspace/state.ts scopes its per-process caches — lastValidatedAt, serverLookupMissed (via accountScopedKey) — and the on-disk binding cache by tenantKey(), which is {tenant, apiUrl} only. Two accounts on the same tenant and API host therefore share those entries.

Sequence (raised as MAJOR by the multi-model review on #1338; confirmed in the source):

  1. Alice resolves a linked project. lastValidatedAt[tenant|apiUrl|dir] is stamped and the binding is written to the disk cache.
  2. Within REVALIDATE_MS (5 min) the credentials switch to Bob — same tenant, same host, different personal API key.
  3. Bob's resolve sees the fresh stamp and returns Alice's cached binding as bound with no server check. Whatever rides on the binding (skill-sync, memory-sync, the identity line) is attributed to the wrong account for up to five minutes.

This is the layer under the two caches v0.12.1 did scope by credential digest (identity's memo, and pinValidation in resolvePinnedBinding, which set the pattern). Not a warehouse-authorization bypass — that check is server-side — and not a regression: tenantKey/accountScopedKey predate v0.12.x.

Expected

Thread a short credential digest (the sha256(apiKey).slice(0,16) pattern resolvePinnedBinding already uses) through tenantKey(), accountScopedKey() and the disk-cache scope, so a same-tenant account switch never inherits the other account's fast path. Note the migration effect: re-keying the disk cache invalidates every existing cached binding once (one extra server round-trip per project after upgrade), and the sidebar, skill-sync and memory-sync callers read the same scope — review them together.

Priority

Deferred. Switching accounts within one tenant mid-process is not a common workflow; the window is five minutes and the consequence is misattributed sync, not data access. Called out in the v0.12.1 CHANGELOG ("tracked separately").

Related: #1337 (routing ignores the IDE pin — different gap, same file), #1335.

🤖 Generated with Claude Code

https://claude.ai/code/session_012Q51zFUmPg1WwtS5CrGJE6

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions