Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/bin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2407,10 +2407,10 @@ yargs(rawArgs)
}),
async (argv) => {
await applyInsecureStorage(argv.insecureStorage);
const { resolveApiKey } = await import('./lib/api-key.js');
const { resolveOptionalApiKey } = await import('./lib/api-key.js');
const { getMigrationsPassthroughArgs, runMigrations } = await import('./commands/migrations.js');
const passthrough = getMigrationsPassthroughArgs(rawArgs);
await runMigrations(passthrough, resolveApiKey({ apiKey: argv.apiKey }));
await runMigrations(passthrough, resolveOptionalApiKey({ apiKey: argv.apiKey }));
},
)
.command(
Expand Down
6 changes: 6 additions & 0 deletions src/commands/migrations.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ describe('runMigrations', () => {
expect(process.env.WORKOS_SECRET_KEY).toBe('sk_test_123');
});

it('does not require WORKOS_SECRET_KEY when no API key is provided', async () => {
await runMigrations(['wizard']);
expect(process.env.WORKOS_SECRET_KEY).toBeUndefined();
expect(mockParseAsync).toHaveBeenCalledWith(['wizard'], { from: 'user' });
});

it('delegates to Commander parseAsync with correct args', async () => {
await runMigrations(['import', '--csv', 'users.csv'], 'sk_test_123');
expect(mockParseAsync).toHaveBeenCalledWith(['import', '--csv', 'users.csv'], { from: 'user' });
Expand Down
6 changes: 4 additions & 2 deletions src/commands/migrations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,10 @@ export function getMigrationsPassthroughArgs(rawArgs: string[]): string[] {
return passthrough;
}

export async function runMigrations(args: string[], apiKey: string): Promise<void> {
process.env.WORKOS_SECRET_KEY = apiKey;
export async function runMigrations(args: string[], apiKey?: string): Promise<void> {
if (apiKey) {
process.env.WORKOS_SECRET_KEY = apiKey;
}

const { program } = (await import('@workos/migrations/dist/cli/index.js')) as {
program: {
Expand Down
36 changes: 35 additions & 1 deletion src/lib/api-key.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ vi.mock('node:os', async (importOriginal) => {
});

const { saveConfig, setInsecureConfigStorage, clearConfig } = await import('./config-store.js');
const { resolveApiKey, resolveApiBaseUrl } = await import('./api-key.js');
const { resolveApiKey, resolveOptionalApiKey, resolveApiBaseUrl } = await import('./api-key.js');

describe('api-key', () => {
const originalEnv = process.env;
Expand Down Expand Up @@ -117,6 +117,40 @@ describe('api-key', () => {
});
});

describe('resolveOptionalApiKey', () => {
it('returns --api-key flag over env var and stored key', () => {
process.env.WORKOS_API_KEY = 'sk_env_var';
saveConfig({
activeEnvironment: 'prod',
environments: { prod: { name: 'prod', type: 'production', apiKey: 'sk_stored' } },
});
expect(resolveOptionalApiKey({ apiKey: 'sk_flag' })).toBe('sk_flag');
});

it('returns WORKOS_API_KEY env var when no flag provided', () => {
process.env.WORKOS_API_KEY = 'sk_env_var';
saveConfig({
activeEnvironment: 'prod',
environments: { prod: { name: 'prod', type: 'production', apiKey: 'sk_stored' } },
});
expect(resolveOptionalApiKey()).toBe('sk_env_var');
});

it('returns undefined when no API key is available', () => {
mockExitWithError.mockClear();
expect(resolveOptionalApiKey()).toBeUndefined();
expect(mockExitWithError).not.toHaveBeenCalled();
});

it('returns configured API key when available', () => {
saveConfig({
activeEnvironment: 'prod',
environments: { prod: { name: 'prod', type: 'production', apiKey: 'sk_stored' } },
});
expect(resolveOptionalApiKey()).toBe('sk_stored');
});
});
Comment thread
greptile-apps[bot] marked this conversation as resolved.

describe('resolveApiBaseUrl', () => {
it('returns default URL when no config', () => {
expect(resolveApiBaseUrl()).toBe('https://api.workos.com');
Expand Down
15 changes: 11 additions & 4 deletions src/lib/api-key.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,16 @@ export interface ApiKeyOptions {
}

export function resolveApiKey(options?: ApiKeyOptions): string {
const apiKey = resolveOptionalApiKey(options);
if (apiKey) return apiKey;

exitWithError({
code: 'no_api_key',
message: 'No API key configured. Run `workos env add` to configure an environment, or set WORKOS_API_KEY.',
});
}

export function resolveOptionalApiKey(options?: ApiKeyOptions): string | undefined {
if (options?.apiKey) return options.apiKey;

const envVar = process.env.WORKOS_API_KEY;
Expand All @@ -25,10 +35,7 @@ export function resolveApiKey(options?: ApiKeyOptions): string {
const activeEnv = getActiveEnvironment();
if (activeEnv?.apiKey) return activeEnv.apiKey;

exitWithError({
code: 'no_api_key',
message: 'No API key configured. Run `workos env add` to configure an environment, or set WORKOS_API_KEY.',
});
return undefined;
}

export function resolveApiBaseUrl(): string {
Expand Down
Loading