fix: harden session cache + heartbeat restore
Co-authored-by: Ronak Guliani <ronak-guliani@users.noreply.github.com>
This commit is contained in:
@@ -76,6 +76,32 @@ describe("Session Store Cache", () => {
|
||||
readSpy.mockRestore();
|
||||
});
|
||||
|
||||
it("should not allow cached session mutations to leak across loads", async () => {
|
||||
const testStore: Record<string, SessionEntry> = {
|
||||
"session:1": {
|
||||
sessionId: "id-1",
|
||||
updatedAt: Date.now(),
|
||||
cliSessionIds: { openai: "sess-1" },
|
||||
skillsSnapshot: {
|
||||
prompt: "skills",
|
||||
skills: [{ name: "alpha" }],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
await saveSessionStore(storePath, testStore);
|
||||
|
||||
const loaded1 = loadSessionStore(storePath);
|
||||
loaded1["session:1"].cliSessionIds = { openai: "mutated" };
|
||||
if (loaded1["session:1"].skillsSnapshot?.skills?.length) {
|
||||
loaded1["session:1"].skillsSnapshot!.skills[0].name = "mutated";
|
||||
}
|
||||
|
||||
const loaded2 = loadSessionStore(storePath);
|
||||
expect(loaded2["session:1"].cliSessionIds?.openai).toBe("sess-1");
|
||||
expect(loaded2["session:1"].skillsSnapshot?.skills?.[0]?.name).toBe("alpha");
|
||||
});
|
||||
|
||||
it("should refresh cache when store file changes on disk", async () => {
|
||||
const testStore: Record<string, SessionEntry> = {
|
||||
"session:1": {
|
||||
|
||||
@@ -52,8 +52,8 @@ export function loadSessionStore(storePath: string): Record<string, SessionEntry
|
||||
if (cached && isSessionStoreCacheValid(cached)) {
|
||||
const currentMtimeMs = getFileMtimeMs(storePath);
|
||||
if (currentMtimeMs === cached.mtimeMs) {
|
||||
// Return a shallow copy to prevent external mutations affecting cache
|
||||
return { ...cached.store };
|
||||
// Return a deep copy to prevent external mutations affecting cache
|
||||
return structuredClone(cached.store);
|
||||
}
|
||||
invalidateSessionStoreCache(storePath);
|
||||
}
|
||||
@@ -90,14 +90,14 @@ export function loadSessionStore(storePath: string): Record<string, SessionEntry
|
||||
// Cache the result if caching is enabled
|
||||
if (isSessionStoreCacheEnabled()) {
|
||||
SESSION_STORE_CACHE.set(storePath, {
|
||||
store: { ...store }, // Store a copy to prevent external mutations
|
||||
store: structuredClone(store), // Store a copy to prevent external mutations
|
||||
loadedAt: Date.now(),
|
||||
storePath,
|
||||
mtimeMs,
|
||||
});
|
||||
}
|
||||
|
||||
return store;
|
||||
return structuredClone(store);
|
||||
}
|
||||
|
||||
async function saveSessionStoreUnlocked(
|
||||
|
||||
Reference in New Issue
Block a user