diff --git a/src/core/cli-identity.ts b/src/core/cli-identity.ts index dfc14cce4a..4d58bc2e44 100644 --- a/src/core/cli-identity.ts +++ b/src/core/cli-identity.ts @@ -333,6 +333,15 @@ export function clearSessionIdentity( ): void { try { rmSync(sessionIdentityPath(sessionDataDir, sessionId, tool), { force: true }); } catch { /* best-effort: absence is the desired state */ } + // Before #1543 identities lived directly under cli-identity/. Upgraded + // sessions no longer read or overwrite those files, so remove the exact + // legacy path as well instead of leaving a live token behind indefinitely. + try { + rmSync( + join(sessionIdentityDir(sessionDataDir), `${assertSafeSegment(sessionId)}.${tool}.env`), + { force: true }, + ); + } catch { /* best-effort: absence is the desired state */ } } /** Drop every identity for a session (teardown). */ @@ -340,6 +349,12 @@ export function clearAllSessionIdentities(sessionDataDir: string, sessionId: str for (const tool of Object.keys(IDENTITY_ENV_KEYS) as TriggerUserAuthTool[]) { clearSessionIdentity(sessionDataDir, sessionId, tool); } + try { + rmSync( + join(sessionIdentityDir(sessionDataDir), `${assertSafeSegment(sessionId)}.turn`), + { force: true }, + ); + } catch { /* best-effort: absence is the desired state */ } } /** diff --git a/test/cli-identity.test.ts b/test/cli-identity.test.ts index 589251c955..ff03afaf9a 100644 --- a/test/cli-identity.test.ts +++ b/test/cli-identity.test.ts @@ -150,6 +150,23 @@ describe('clearSessionIdentity', () => { expect(existsSync(sessionIdentityPath(dir, SESSION, 'bytedcli'))).toBe(true); }); + it('removes the matching pre-#1543 identity without disturbing other legacy files', () => { + const identityDir = join(dir, 'cli-identity'); + mkdirSync(identityDir, { recursive: true }); + const stale = join(identityDir, `${SESSION}.lark-cli.env`); + const otherTool = join(identityDir, `${SESSION}.bytedcli.env`); + const otherSession = join(identityDir, 'sess-other.lark-cli.env'); + writeFileSync(stale, 'live-token'); + writeFileSync(otherTool, 'other-tool-token'); + writeFileSync(otherSession, 'other-session-token'); + + clearSessionIdentity(dir, SESSION, 'lark-cli'); + + expect(existsSync(stale)).toBe(false); + expect(existsSync(otherTool)).toBe(true); + expect(existsSync(otherSession)).toBe(true); + }); + it('clears every tool on teardown', () => { writeSessionIdentity(dir, SESSION, { tool: 'lark-cli', appId: 'a', userAccessToken: 'tok' }); writeSessionIdentity(dir, SESSION, { tool: 'bytedcli', cloudJwt: 'jwt' }); @@ -157,6 +174,24 @@ describe('clearSessionIdentity', () => { expect(existsSync(sessionIdentityPath(dir, SESSION, 'lark-cli'))).toBe(false); expect(existsSync(sessionIdentityPath(dir, SESSION, 'bytedcli'))).toBe(false); }); + + it('clears every pre-#1543 identity and turn marker on teardown', () => { + const identityDir = join(dir, 'cli-identity'); + mkdirSync(identityDir, { recursive: true }); + const legacyPaths = [ + join(identityDir, `${SESSION}.lark-cli.env`), + join(identityDir, `${SESSION}.bytedcli.env`), + join(identityDir, `${SESSION}.turn`), + ]; + for (const path of legacyPaths) writeFileSync(path, 'stale'); + const unrelated = join(identityDir, `${SESSION}.unknown.env`); + writeFileSync(unrelated, 'keep'); + + clearAllSessionIdentities(dir, SESSION); + + for (const path of legacyPaths) expect(existsSync(path)).toBe(false); + expect(existsSync(unrelated)).toBe(true); + }); }); // The wrapper is what actually runs, on every CLI call. These tests execute it