feat: add OpenAI OAuth, strict model overrides, and Gmail pull mode

This commit is contained in:
William Valentin
2026-02-13 14:55:40 -08:00
parent 8f644d5e25
commit 955b9e28e0
50 changed files with 5955 additions and 160 deletions
+69
View File
@@ -163,6 +163,75 @@ automation:
expect(gmailCheck?.detail).toContain('flynn gmail-auth');
});
it('reports PASS for Gmail when enabled (poll only)', async () => {
mkdirSync(testDir, { recursive: true });
const configPath = join(testDir, 'config.yaml');
const credsPath = join(testDir, 'gmail-creds.json');
const tokenPath = join(testDir, 'gmail-token.json');
writeFileSync(credsPath, JSON.stringify({ installed: { project_id: 'test-project' } }));
writeFileSync(tokenPath, JSON.stringify({ refresh_token: 'x' }));
writeFileSync(configPath, `
telegram:
bot_token: "test-token"
allowed_chat_ids: [123]
models:
default:
provider: anthropic
model: claude-sonnet
automation:
gmail:
enabled: true
credentials_file: "${credsPath}"
token_file: "${tokenPath}"
output:
channel: telegram
peer: "123"
`);
const ctx: DoctorContext = { configPath, dataDir: testDir };
const results = await runChecks(ctx);
const gmailCheck = results.find(r => r.label.includes('Gmail configured'));
expect(gmailCheck?.status).toBe('pass');
expect(gmailCheck?.detail).toContain('poll');
});
it('reports WARN for Gmail when pubsub_topic shorthand used without project_id', async () => {
mkdirSync(testDir, { recursive: true });
const configPath = join(testDir, 'config.yaml');
const credsPath = join(testDir, 'gmail-creds.json');
const tokenPath = join(testDir, 'gmail-token.json');
writeFileSync(credsPath, '{}');
writeFileSync(tokenPath, JSON.stringify({ refresh_token: 'x' }));
writeFileSync(configPath, `
telegram:
bot_token: "test-token"
allowed_chat_ids: [123]
models:
default:
provider: anthropic
model: claude-sonnet
automation:
gmail:
enabled: true
credentials_file: "${credsPath}"
token_file: "${tokenPath}"
pubsub_topic: gmail-push
output:
channel: telegram
peer: "123"
`);
const ctx: DoctorContext = { configPath, dataDir: testDir };
const results = await runChecks(ctx);
const gmailCheck = results.find(r => r.label.includes('Gmail configured'));
expect(gmailCheck?.status).toBe('warn');
expect(gmailCheck?.detail).toContain('pubsub_topic shorthand');
});
it('skips downstream checks when config is invalid', async () => {
const ctx: DoctorContext = { configPath: '/nonexistent/config.yaml', dataDir: testDir };
const results = await runChecks(ctx);