feat: add OpenAI OAuth, strict model overrides, and Gmail pull mode
This commit is contained in:
+55
-2
@@ -137,7 +137,8 @@ const checkModelConnectivity: Check = async (ctx) => {
|
||||
|
||||
// Check if API key is present for providers that need one
|
||||
const needsKey = ['anthropic', 'openai', 'gemini', 'openrouter'];
|
||||
if (needsKey.includes(model.provider) && !model.api_key && !model.auth_token) {
|
||||
const openaiUsingOAuth = model.provider === 'openai' && Boolean((model as unknown as { use_oauth?: boolean }).use_oauth);
|
||||
if (needsKey.includes(model.provider) && !openaiUsingOAuth && !model.api_key && !model.auth_token) {
|
||||
const envVarMap: Record<string, string> = {
|
||||
anthropic: 'ANTHROPIC_API_KEY',
|
||||
openai: 'OPENAI_API_KEY',
|
||||
@@ -256,12 +257,64 @@ const checkGmail: Check = async (ctx) => {
|
||||
return { status: 'fail', label: 'Gmail configured', detail: `credentials file not found: ${credentialsPath}` };
|
||||
}
|
||||
|
||||
let googleProjectId: string | undefined;
|
||||
try {
|
||||
const creds = JSON.parse(readFileSync(credentialsPath, 'utf-8')) as Record<string, unknown>;
|
||||
const installed = (creds.installed as Record<string, unknown> | undefined) ?? (creds.web as Record<string, unknown> | undefined);
|
||||
const projectId = installed?.project_id;
|
||||
if (typeof projectId === 'string' && projectId.trim()) {
|
||||
googleProjectId = projectId.trim();
|
||||
}
|
||||
} catch {
|
||||
// Ignore JSON parse errors; doctor will still validate token and output.
|
||||
}
|
||||
|
||||
const tokenPath = expandPath(gmail.token_file ?? '~/.config/flynn/gmail-token.json');
|
||||
if (!existsSync(tokenPath)) {
|
||||
return { status: 'warn', label: 'Gmail configured', detail: 'run `flynn gmail-auth` to authenticate' };
|
||||
}
|
||||
|
||||
return { status: 'pass', label: 'Gmail configured', detail: `(output: ${gmail.output.channel}/${gmail.output.peer})` };
|
||||
const modes: string[] = [];
|
||||
const warnings: string[] = [];
|
||||
|
||||
const topicRaw = (gmail.pubsub_topic ?? process.env.FLYNN_GMAIL_PUBSUB_TOPIC ?? '').trim();
|
||||
const pushEnabled = Boolean(topicRaw) && !gmail.disable_push;
|
||||
if (pushEnabled) {
|
||||
modes.push('push');
|
||||
if (topicRaw.includes('/')) {
|
||||
const ok = /^projects\/[^/]+\/topics\/[^/]+$/.test(topicRaw);
|
||||
if (!ok) {
|
||||
warnings.push('pubsub_topic format invalid (expected projects/<project>/topics/<topic>)');
|
||||
}
|
||||
} else if (!googleProjectId) {
|
||||
warnings.push('pubsub_topic shorthand requires project_id in Gmail credentials');
|
||||
}
|
||||
|
||||
if (ctx.config.server?.tailscale?.serve) {
|
||||
warnings.push('push requires a public HTTPS endpoint; Tailscale Serve is typically tailnet-only');
|
||||
}
|
||||
} else if (gmail.disable_push && topicRaw) {
|
||||
warnings.push('push disabled (disable_push=true)');
|
||||
}
|
||||
|
||||
const subRaw = (gmail.pubsub_subscription_id ?? '').trim();
|
||||
if (subRaw) {
|
||||
modes.push('pull');
|
||||
if (subRaw.includes('/')) {
|
||||
const ok = /^projects\/[^/]+\/subscriptions\/[^/]+$/.test(subRaw);
|
||||
if (!ok) {
|
||||
warnings.push('pubsub_subscription_id format invalid (expected projects/<project>/subscriptions/<sub>)');
|
||||
}
|
||||
} else if (!googleProjectId) {
|
||||
warnings.push('pubsub_subscription_id shorthand requires project_id in Gmail credentials');
|
||||
}
|
||||
}
|
||||
|
||||
modes.push('poll');
|
||||
const detail = `(${modes.join(' + ')} -> ${gmail.output.channel}/${gmail.output.peer})`;
|
||||
const withWarnings = warnings.length > 0 ? `${detail} — ${warnings.join('; ')}` : detail;
|
||||
|
||||
return { status: warnings.length > 0 ? 'warn' : 'pass', label: 'Gmail configured', detail: withWarnings };
|
||||
};
|
||||
|
||||
const allChecks: Check[] = [
|
||||
|
||||
Reference in New Issue
Block a user