mirror of
https://github.com/stablyai/orca.git
synced 2026-09-21 16:02:20 +00:00
fix(memory): bound cloud session cache
This commit is contained in:
@@ -136,6 +136,17 @@ describe('Orca cloud session store', () => {
|
||||
}
|
||||
})
|
||||
|
||||
it('bounds memory-session cache churn', async () => {
|
||||
const store = await loadSessionStore()
|
||||
const session = makeSession()
|
||||
|
||||
for (let index = 0; index < store.MAX_MEMORY_CLOUD_SESSIONS + 4; index += 1) {
|
||||
store.saveOrcaCloudSession(`profile-${index}`, userDataPath, session)
|
||||
}
|
||||
|
||||
expect(store.getOrcaCloudMemorySessionCountForTests()).toBe(store.MAX_MEMORY_CLOUD_SESSIONS)
|
||||
})
|
||||
|
||||
it('writes explicit dev plaintext only when the dev escape hatch is enabled', async () => {
|
||||
safeStorageMock.isEncryptionAvailable.mockReturnValue(false)
|
||||
vi.stubEnv('ORCA_CLOUD_ALLOW_PLAINTEXT_SESSION', '1')
|
||||
|
||||
@@ -55,6 +55,19 @@ type CachedOrcaCloudSession = {
|
||||
}
|
||||
|
||||
const memorySessions = new Map<string, CachedOrcaCloudSession>()
|
||||
export const MAX_MEMORY_CLOUD_SESSIONS = 64
|
||||
|
||||
function rememberMemorySession(key: string, session: CachedOrcaCloudSession): void {
|
||||
memorySessions.delete(key)
|
||||
memorySessions.set(key, session)
|
||||
while (memorySessions.size > MAX_MEMORY_CLOUD_SESSIONS) {
|
||||
const oldest = memorySessions.keys().next()
|
||||
if (oldest.done || oldest.value === key) {
|
||||
break
|
||||
}
|
||||
memorySessions.delete(oldest.value)
|
||||
}
|
||||
}
|
||||
|
||||
function sessionCacheKey(profileId: string, userDataPath: string): string {
|
||||
return `${userDataPath}\0${profileId}`
|
||||
@@ -119,7 +132,7 @@ export function saveOrcaCloudSession(
|
||||
ciphertext: safeStorage.encryptString(JSON.stringify(session)).toString('base64')
|
||||
}
|
||||
writeSecureJsonFile(getOrcaCloudSessionPath(profileId, userDataPath), encrypted)
|
||||
memorySessions.set(cacheKey, { session, persistence: 'encrypted' })
|
||||
rememberMemorySession(cacheKey, { session, persistence: 'encrypted' })
|
||||
return 'encrypted'
|
||||
}
|
||||
|
||||
@@ -131,13 +144,13 @@ export function saveOrcaCloudSession(
|
||||
session
|
||||
}
|
||||
writeSecureJsonFile(getOrcaCloudSessionPath(profileId, userDataPath), plaintext)
|
||||
memorySessions.set(cacheKey, { session, persistence: 'dev-plaintext' })
|
||||
rememberMemorySession(cacheKey, { session, persistence: 'dev-plaintext' })
|
||||
return 'dev-plaintext'
|
||||
}
|
||||
|
||||
// Why: Orca account refresh tokens must not silently fall back to plaintext
|
||||
// in production. Memory-only keeps cloud features usable until restart.
|
||||
memorySessions.set(cacheKey, { session, persistence: 'memory-only' })
|
||||
rememberMemorySession(cacheKey, { session, persistence: 'memory-only' })
|
||||
return 'memory-only'
|
||||
}
|
||||
|
||||
@@ -177,6 +190,8 @@ export function readOrcaCloudSession(
|
||||
const cacheKey = sessionCacheKey(profileId, userDataPath)
|
||||
const memorySession = memorySessions.get(cacheKey)
|
||||
if (memorySession) {
|
||||
memorySessions.delete(cacheKey)
|
||||
memorySessions.set(cacheKey, memorySession)
|
||||
return {
|
||||
status: 'found',
|
||||
session: memorySession.session,
|
||||
@@ -209,14 +224,14 @@ export function readOrcaCloudSession(
|
||||
if (!isOrcaCloudSession(session)) {
|
||||
return { status: 'decrypt-failed', persistence: 'none', error: 'Invalid saved session.' }
|
||||
}
|
||||
memorySessions.set(cacheKey, { session, persistence: 'encrypted' })
|
||||
rememberMemorySession(cacheKey, { session, persistence: 'encrypted' })
|
||||
return { status: 'found', session, persistence: 'encrypted' }
|
||||
}
|
||||
if (parsed.format === 'dev-plaintext-v1' && allowsPlaintextOrcaCloudSession()) {
|
||||
if (!isOrcaCloudSession(parsed.session)) {
|
||||
return { status: 'decrypt-failed', persistence: 'none', error: 'Invalid saved session.' }
|
||||
}
|
||||
memorySessions.set(cacheKey, { session: parsed.session, persistence: 'dev-plaintext' })
|
||||
rememberMemorySession(cacheKey, { session: parsed.session, persistence: 'dev-plaintext' })
|
||||
return { status: 'found', session: parsed.session, persistence: 'dev-plaintext' }
|
||||
}
|
||||
return { status: 'decrypt-failed', persistence: 'none', error: 'Unsafe session format.' }
|
||||
@@ -240,3 +255,7 @@ export function clearOrcaCloudSession(profileId: string, userDataPath: string):
|
||||
memorySessions.delete(sessionCacheKey(profileId, userDataPath))
|
||||
rmSync(getOrcaCloudSessionPath(profileId, userDataPath), { force: true })
|
||||
}
|
||||
|
||||
export function getOrcaCloudMemorySessionCountForTests(): number {
|
||||
return memorySessions.size
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user