auth: add OpenAI API key storage

This commit is contained in:
William Valentin
2026-02-15 10:26:19 -08:00
parent 9755487793
commit bcf6c377d5
3 changed files with 184 additions and 6 deletions
+66 -2
View File
@@ -1,6 +1,9 @@
import { describe, it, expect } from 'vitest';
import { mkdtempSync, statSync } from 'fs';
import { tmpdir } from 'os';
import { join } from 'path';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { parseJwtClaims, extractAccountId } from './openai.js';
import { extractAccountId, parseJwtClaims } from './openai.js';
function base64UrlEncode(obj: unknown): string {
return Buffer.from(JSON.stringify(obj)).toString('base64url');
@@ -41,3 +44,64 @@ describe('OpenAI OAuth helpers', () => {
expect(extractAccountId(tokens)).toBe('org_1');
});
});
describe('auth/openai api key storage', () => {
const originalHome = process.env.HOME;
const originalEnvKey = process.env.OPENAI_API_KEY;
let homeDir: string;
beforeEach(() => {
homeDir = mkdtempSync(join(tmpdir(), 'flynn-auth-openai-'));
process.env.HOME = homeDir;
delete process.env.OPENAI_API_KEY;
vi.resetModules();
});
afterEach(() => {
process.env.HOME = originalHome;
if (originalEnvKey) {
process.env.OPENAI_API_KEY = originalEnvKey;
} else {
delete process.env.OPENAI_API_KEY;
}
});
it('stores, loads, and clears OpenAI API key (preserves OAuth entry)', async () => {
const mod = await import('./openai.js');
expect(mod.loadStoredOpenAIApiKey()).toBeNull();
expect(mod.loadStoredOpenAIAuth()).toBeNull();
mod.storeOpenAIApiKey('sk-test');
expect(mod.loadStoredOpenAIApiKey()).toBe('sk-test');
const authFile = join(homeDir, '.config/flynn/auth.json');
const mode = statSync(authFile).mode & 0o777;
expect(mode).toBe(0o600);
const oauth = {
access_token: 'at',
refresh_token: 'rt',
expires_at: Date.now() + 60_000,
created_at: new Date().toISOString(),
};
mod.storeOpenAIAuth(oauth);
expect(mod.loadStoredOpenAIAuth()?.access_token).toBe('at');
expect(mod.loadStoredOpenAIApiKey()).toBe('sk-test');
mod.clearOpenAIAuth();
expect(mod.loadStoredOpenAIAuth()).toBeNull();
expect(mod.loadStoredOpenAIApiKey()).toBe('sk-test');
mod.clearOpenAIApiKey();
expect(mod.loadStoredOpenAIApiKey()).toBeNull();
});
it('getOpenAIApiKey prefers environment variable', async () => {
process.env.OPENAI_API_KEY = 'sk-env';
const mod = await import('./openai.js');
expect(mod.getOpenAIApiKey()).toBe('sk-env');
});
});