feat(cursor): harden live probe and runtime contracts

This commit is contained in:
Tam Nhu Tran committed 2026-04-12 01:51:26 -04:00
1 parent 2eaf760d20
commit e1049e38d4
23 files changed
+2186 -306

No files matched your search

+101 -1
View File
@@ -280,9 +280,10 @@ describe('Cursor Routes Logic', () => {
});
expect(res.status).toBe(404);
const json = (await res.json()) as { error?: string };
const json = (await res.json()) as { error?: string; reason?: string };
expect(typeof json.error).toBe('string');
expect(json.error?.length).toBeGreaterThan(0);
expect(json.reason).toBe('db_not_found');
} finally {
if (originalHome !== undefined) {
process.env.HOME = originalHome;
@@ -344,6 +345,82 @@ describe('Cursor Routes Logic', () => {
}
});
it('POST /api/cursor/auth/auto-detect returns 503 when sqlite3 is unavailable', async () => {
if (process.platform === 'win32') {
return;
}
const originalHome = process.env.HOME;
const originalPath = process.env.PATH;
const originalSqliteBin = process.env.CCS_CURSOR_SQLITE_BIN;
const fakeHome = path.join(tempDir, 'sqlite-missing-home');
process.env.HOME = fakeHome;
process.env.CCS_CURSOR_SQLITE_BIN = 'definitely-missing-sqlite3';
try {
const dbPath = getTokenStoragePath();
fs.mkdirSync(path.dirname(dbPath), { recursive: true });
fs.writeFileSync(dbPath, '');
const res = await fetch(`${baseUrl}/api/cursor/auth/auto-detect`, {
method: 'POST',
});
expect(res.status).toBe(503);
const json = (await res.json()) as { reason?: string; db_path?: string };
expect(json.reason).toBe('sqlite_unavailable');
expect(json.db_path).toBeUndefined();
} finally {
if (originalHome !== undefined) {
process.env.HOME = originalHome;
} else {
delete process.env.HOME;
}
if (originalPath !== undefined) {
process.env.PATH = originalPath;
} else {
delete process.env.PATH;
}
if (originalSqliteBin !== undefined) {
process.env.CCS_CURSOR_SQLITE_BIN = originalSqliteBin;
} else {
delete process.env.CCS_CURSOR_SQLITE_BIN;
}
}
});
it('POST /api/cursor/auth/auto-detect returns 500 when the database exists but cannot be queried', async () => {
if (process.platform === 'win32') {
return;
}
const originalHome = process.env.HOME;
const fakeHome = path.join(tempDir, 'query-failed-home');
process.env.HOME = fakeHome;
try {
const dbPath = getTokenStoragePath();
fs.mkdirSync(path.dirname(dbPath), { recursive: true });
fs.writeFileSync(dbPath, 'not-a-sqlite-database');
const res = await fetch(`${baseUrl}/api/cursor/auth/auto-detect`, {
method: 'POST',
});
expect(res.status).toBe(500);
const json = (await res.json()) as { reason?: string; db_path?: string };
expect(json.reason).toBe('db_query_failed');
expect(json.db_path).toBeUndefined();
} finally {
if (originalHome !== undefined) {
process.env.HOME = originalHome;
} else {
delete process.env.HOME;
}
}
});
it('POST /api/cursor/daemon/start returns 400 when integration is disabled', async () => {
seedCursorConfig({ enabled: false });
seedCredentials(false);
@@ -412,5 +489,28 @@ describe('Cursor Routes Logic', () => {
expect(json.models.length).toBeGreaterThan(0);
expect(json.current).toBe('gpt-5.3-codex');
});
it('POST /api/cursor/probe returns auth failure when credentials are missing', async () => {
const res = await fetch(`${baseUrl}/api/cursor/probe`, { method: 'POST' });
expect(res.status).toBe(401);
const json = (await res.json()) as { ok?: boolean; stage?: string; error_type?: string };
expect(json.ok).toBe(false);
expect(json.stage).toBe('auth');
expect(json.error_type).toBe('authentication_error');
});
it('POST /api/cursor/probe returns daemon failure when daemon is down and auto_start is false', async () => {
seedCursorConfig({ enabled: true, auto_start: false });
seedCredentials(false);
const res = await fetch(`${baseUrl}/api/cursor/probe`, { method: 'POST' });
expect(res.status).toBe(503);
const json = (await res.json()) as { ok?: boolean; stage?: string; error_type?: string };
expect(json.ok).toBe(false);
expect(json.stage).toBe('daemon');
expect(json.error_type).toBe('daemon_not_running');
});
});
});