workos 0.13.4 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +39 -3
- package/dist/bin.js +129 -13
- package/dist/bin.js.map +1 -1
- package/dist/commands/api/catalog.d.ts +23 -0
- package/dist/commands/api/catalog.js +97 -0
- package/dist/commands/api/catalog.js.map +1 -0
- package/dist/commands/api/format.d.ts +5 -0
- package/dist/commands/api/format.js +46 -0
- package/dist/commands/api/format.js.map +1 -0
- package/dist/commands/api/index.d.ts +15 -0
- package/dist/commands/api/index.js +200 -0
- package/dist/commands/api/index.js.map +1 -0
- package/dist/commands/api/interactive.d.ts +3 -0
- package/dist/commands/api/interactive.js +127 -0
- package/dist/commands/api/interactive.js.map +1 -0
- package/dist/commands/api/request.d.ts +14 -0
- package/dist/commands/api/request.js +38 -0
- package/dist/commands/api/request.js.map +1 -0
- package/dist/commands/claim.js +21 -2
- package/dist/commands/claim.js.map +1 -1
- package/dist/commands/connection.js +5 -3
- package/dist/commands/connection.js.map +1 -1
- package/dist/commands/debug.js +5 -4
- package/dist/commands/debug.js.map +1 -1
- package/dist/commands/directory.js +5 -3
- package/dist/commands/directory.js.map +1 -1
- package/dist/commands/env.js +13 -3
- package/dist/commands/env.js.map +1 -1
- package/dist/commands/login.js +20 -4
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/migrations.d.ts +2 -0
- package/dist/commands/migrations.js +44 -0
- package/dist/commands/migrations.js.map +1 -0
- package/dist/doctor/checks/auth-patterns.js +12 -1
- package/dist/doctor/checks/auth-patterns.js.map +1 -1
- package/dist/doctor/checks/host-execution.d.ts +2 -0
- package/dist/doctor/checks/host-execution.js +21 -0
- package/dist/doctor/checks/host-execution.js.map +1 -0
- package/dist/doctor/index.js +9 -1
- package/dist/doctor/index.js.map +1 -1
- package/dist/doctor/issues.d.ts +5 -0
- package/dist/doctor/issues.js +12 -0
- package/dist/doctor/issues.js.map +1 -1
- package/dist/doctor/output.d.ts +2 -0
- package/dist/doctor/output.js +42 -0
- package/dist/doctor/output.js.map +1 -1
- package/dist/doctor/types.d.ts +16 -0
- package/dist/doctor/types.js.map +1 -1
- package/dist/lib/config-store.js +51 -7
- package/dist/lib/config-store.js.map +1 -1
- package/dist/lib/credential-proxy.js +14 -1
- package/dist/lib/credential-proxy.js.map +1 -1
- package/dist/lib/credential-store.js +51 -7
- package/dist/lib/credential-store.js.map +1 -1
- package/dist/lib/ensure-auth.d.ts +0 -10
- package/dist/lib/ensure-auth.js +27 -9
- package/dist/lib/ensure-auth.js.map +1 -1
- package/dist/lib/host-probe.d.ts +28 -0
- package/dist/lib/host-probe.js +154 -0
- package/dist/lib/host-probe.js.map +1 -0
- package/dist/lib/run-with-core.js +26 -7
- package/dist/lib/run-with-core.js.map +1 -1
- package/dist/utils/cli-symbols.d.ts +1 -1
- package/dist/utils/command-invocation.d.ts +2 -0
- package/dist/utils/command-invocation.js +9 -0
- package/dist/utils/command-invocation.js.map +1 -1
- package/dist/utils/debug.d.ts +1 -0
- package/dist/utils/debug.js +10 -2
- package/dist/utils/debug.js.map +1 -1
- package/dist/utils/environment.d.ts +6 -0
- package/dist/utils/environment.js +8 -16
- package/dist/utils/environment.js.map +1 -1
- package/dist/utils/exit-codes.d.ts +9 -5
- package/dist/utils/exit-codes.js +10 -2
- package/dist/utils/exit-codes.js.map +1 -1
- package/dist/utils/help-json.d.ts +7 -0
- package/dist/utils/help-json.js +120 -0
- package/dist/utils/help-json.js.map +1 -1
- package/dist/utils/interaction-mode.d.ts +25 -0
- package/dist/utils/interaction-mode.js +102 -0
- package/dist/utils/interaction-mode.js.map +1 -0
- package/dist/utils/output.d.ts +20 -12
- package/dist/utils/output.js +16 -4
- package/dist/utils/output.js.map +1 -1
- package/dist/utils/recovery-hints.d.ts +37 -0
- package/dist/utils/recovery-hints.js +80 -0
- package/dist/utils/recovery-hints.js.map +1 -0
- package/package.json +7 -5
package/dist/commands/login.js
CHANGED
|
@@ -10,7 +10,10 @@ import { getConfig, saveConfig } from '../lib/config-store.js';
|
|
|
10
10
|
import { formatWorkOSCommand } from '../utils/command-invocation.js';
|
|
11
11
|
import { autoInstallSkills } from './install-skill.js';
|
|
12
12
|
import { isJsonMode } from '../utils/output.js';
|
|
13
|
+
import { isAgentMode, isCiMode } from '../utils/interaction-mode.js';
|
|
14
|
+
import { exitWithAuthRequired } from '../utils/exit-codes.js';
|
|
13
15
|
import { requestDeviceCode, pollForToken, DeviceAuthTimeoutError } from '../lib/device-auth.js';
|
|
16
|
+
import { observeHostFailure } from '../lib/host-probe.js';
|
|
14
17
|
/**
|
|
15
18
|
* Best-effort skill install after a successful auth-login.
|
|
16
19
|
*
|
|
@@ -103,6 +106,9 @@ export async function runLogin() {
|
|
|
103
106
|
// Refresh failed, proceed with fresh login
|
|
104
107
|
}
|
|
105
108
|
}
|
|
109
|
+
if (isCiMode()) {
|
|
110
|
+
exitWithAuthRequired('Browser authentication is not available in CI mode. Set WORKOS_API_KEY or configure credentials before running in CI.');
|
|
111
|
+
}
|
|
106
112
|
const authkitDomain = getAuthkitDomain();
|
|
107
113
|
clack.log.step('Starting authentication...');
|
|
108
114
|
let deviceAuth;
|
|
@@ -118,11 +124,21 @@ export async function runLogin() {
|
|
|
118
124
|
console.log(` ${deviceAuth.verification_uri}`);
|
|
119
125
|
console.log(`\nEnter code: ${deviceAuth.user_code}\n`);
|
|
120
126
|
try {
|
|
121
|
-
open(deviceAuth.verification_uri_complete);
|
|
122
|
-
|
|
127
|
+
await open(deviceAuth.verification_uri_complete, { wait: false });
|
|
128
|
+
if (isAgentMode()) {
|
|
129
|
+
clack.log.info('Browser launch attempted. If it did not open on the host, use the manual URL and code above.');
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
clack.log.info('Browser opened automatically');
|
|
133
|
+
}
|
|
123
134
|
}
|
|
124
|
-
catch {
|
|
125
|
-
|
|
135
|
+
catch (error) {
|
|
136
|
+
observeHostFailure('browser-launch', error, {
|
|
137
|
+
operation: 'open',
|
|
138
|
+
target: deviceAuth.verification_uri_complete,
|
|
139
|
+
label: 'auth login browser',
|
|
140
|
+
});
|
|
141
|
+
clack.log.info('Could not open browser — open the URL above manually.');
|
|
126
142
|
}
|
|
127
143
|
const spinner = clack.spinner();
|
|
128
144
|
spinner.start('Waiting for authentication...');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"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","sourcesContent":["import open from 'opn';\nimport chalk from 'chalk';\nimport clack from '../utils/clack.js';\nimport { saveCredentials, getCredentials, getAccessToken, isTokenExpired, updateTokens } from '../lib/credentials.js';\nimport { getCliAuthClientId, getAuthkitDomain } from '../lib/settings.js';\nimport { refreshAccessToken } from '../lib/token-refresh-client.js';\nimport { logInfo, logError } from '../utils/debug.js';\nimport { fetchStagingCredentials } from '../lib/staging-api.js';\nimport { getConfig, saveConfig } from '../lib/config-store.js';\nimport type { CliConfig } from '../lib/config-store.js';\nimport { formatWorkOSCommand } from '../utils/command-invocation.js';\nimport { autoInstallSkills } from './install-skill.js';\nimport { isJsonMode } from '../utils/output.js';\nimport { requestDeviceCode, pollForToken, DeviceAuthTimeoutError } from '../lib/device-auth.js';\n\n/**\n * Best-effort skill install after a successful auth-login.\n *\n * Mirrors the install.ts hook copy, but wraps `autoInstallSkills` in its own\n * try/catch AND a 30s timeout so a skill install hang (e.g. blocked filesystem\n * call) never blocks login completion. Login already succeeded by the time\n * this runs — the user having a working session is the contract that must hold.\n *\n * Extracted from runLogin so it can be unit-tested without standing up the\n * device-auth polling loop.\n */\nexport const SKILL_INSTALL_TIMEOUT_MS = 30 * 1000;\n\nexport async function installSkillsAfterLogin(): Promise<void> {\n let timeoutHandle: ReturnType<typeof setTimeout> | undefined;\n try {\n const timeout = new Promise<null>((resolve) => {\n timeoutHandle = setTimeout(() => resolve(null), SKILL_INSTALL_TIMEOUT_MS);\n // Don't keep the event loop alive on this timer — process should exit\n // immediately if everything else has resolved.\n timeoutHandle.unref?.();\n });\n const result = await Promise.race([autoInstallSkills(), timeout]);\n if (result && !isJsonMode()) {\n const skillWord = result.skills.length === 1 ? 'skill' : 'skills';\n clack.log.info(`Installed ${result.skills.length} WorkOS ${skillWord} for ${result.agents.join(', ')}.`);\n }\n } catch {\n // Skill install must never fail login.\n } finally {\n if (timeoutHandle) clearTimeout(timeoutHandle);\n }\n}\n\n/**\n * Auto-provision a staging environment after login.\n *\n * Fetches staging credentials using the access token, then saves them\n * as a \"staging\" environment in the config store. Non-fatal — logs a\n * hint on failure instead of throwing.\n */\nexport async function provisionStagingEnvironment(accessToken: string): Promise<boolean> {\n try {\n const staging = await fetchStagingCredentials(accessToken);\n\n const config: CliConfig = getConfig() ?? { environments: {} };\n const isFirst = Object.keys(config.environments).length === 0;\n\n config.environments['staging'] = {\n name: 'staging',\n type: 'sandbox',\n apiKey: staging.apiKey,\n clientId: staging.clientId,\n };\n\n if (isFirst || !config.activeEnvironment) {\n config.activeEnvironment = 'staging';\n }\n\n saveConfig(config);\n logInfo('[login] Staging environment auto-provisioned');\n return true;\n } catch (error) {\n logError('[login] Failed to auto-provision staging environment:', error instanceof Error ? error.message : error);\n return false;\n }\n}\n\nexport async function runLogin(): Promise<void> {\n const clientId = getCliAuthClientId();\n\n // Check if already logged in with valid token\n if (getAccessToken()) {\n const creds = getCredentials();\n console.log(chalk.green(`Already logged in as ${creds?.email ?? 'unknown'}`));\n console.log(chalk.dim(`Run \\`${formatWorkOSCommand('auth logout')}\\` to log out`));\n return;\n }\n\n // Try to refresh if we have expired credentials with a refresh token\n const existingCreds = getCredentials();\n if (existingCreds?.refreshToken && isTokenExpired(existingCreds)) {\n try {\n const authkitDomain = getAuthkitDomain();\n const result = await refreshAccessToken(authkitDomain, clientId);\n if (result.accessToken && result.expiresAt) {\n updateTokens(result.accessToken, result.expiresAt, result.refreshToken);\n logInfo('[login] Session refreshed via refresh token');\n console.log(chalk.green(`Already logged in as ${existingCreds.email ?? 'unknown'}`));\n console.log(chalk.dim(`Run \\`${formatWorkOSCommand('auth logout')}\\` to log out`));\n return;\n }\n } catch {\n // Refresh failed, proceed with fresh login\n }\n }\n\n const authkitDomain = getAuthkitDomain();\n\n clack.log.step('Starting authentication...');\n\n let deviceAuth;\n try {\n deviceAuth = await requestDeviceCode({ clientId, authkitDomain });\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error);\n clack.log.error(`Failed to start authentication: ${msg}`);\n process.exit(1);\n }\n\n clack.log.info(`\\nOpen this URL in your browser:\\n`);\n console.log(` ${deviceAuth.verification_uri}`);\n console.log(`\\nEnter code: ${deviceAuth.user_code}\\n`);\n\n try {\n open(deviceAuth.verification_uri_complete);\n clack.log.info('Browser opened automatically');\n } catch {\n // User can open manually\n }\n\n const spinner = clack.spinner();\n spinner.start('Waiting for authentication...');\n\n try {\n const result = await pollForToken(deviceAuth.device_code, {\n clientId,\n authkitDomain,\n interval: deviceAuth.interval,\n });\n\n const expiresInSec = Math.round((result.expiresAt - Date.now()) / 1000);\n\n saveCredentials({\n accessToken: result.accessToken,\n expiresAt: result.expiresAt,\n userId: result.userId,\n email: result.email,\n refreshToken: result.refreshToken,\n });\n\n spinner.stop('Authentication successful!');\n clack.log.success(`Logged in as ${result.email || result.userId}`);\n clack.log.info(`Token expires in ${expiresInSec} seconds`);\n\n const provisioned = await provisionStagingEnvironment(result.accessToken);\n if (provisioned) {\n clack.log.success('Staging environment configured automatically');\n } else {\n clack.log.info(chalk.dim('Run `workos env add` to configure an environment manually'));\n }\n\n await installSkillsAfterLogin();\n } catch (error) {\n if (error instanceof DeviceAuthTimeoutError) {\n spinner.stop('Authentication timed out');\n clack.log.error('Authentication timed out. Please try again.');\n } else {\n spinner.stop('Authentication failed');\n const msg = error instanceof Error ? error.message : String(error);\n clack.log.error(`Authentication error: ${msg}`);\n }\n process.exit(1);\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"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","sourcesContent":["import open from 'opn';\nimport chalk from 'chalk';\nimport clack from '../utils/clack.js';\nimport { saveCredentials, getCredentials, getAccessToken, isTokenExpired, updateTokens } from '../lib/credentials.js';\nimport { getCliAuthClientId, getAuthkitDomain } from '../lib/settings.js';\nimport { refreshAccessToken } from '../lib/token-refresh-client.js';\nimport { logInfo, logError } from '../utils/debug.js';\nimport { fetchStagingCredentials } from '../lib/staging-api.js';\nimport { getConfig, saveConfig } from '../lib/config-store.js';\nimport type { CliConfig } from '../lib/config-store.js';\nimport { formatWorkOSCommand } from '../utils/command-invocation.js';\nimport { autoInstallSkills } from './install-skill.js';\nimport { isJsonMode } from '../utils/output.js';\nimport { isAgentMode, isCiMode } from '../utils/interaction-mode.js';\nimport { exitWithAuthRequired } from '../utils/exit-codes.js';\nimport { requestDeviceCode, pollForToken, DeviceAuthTimeoutError } from '../lib/device-auth.js';\nimport { observeHostFailure } from '../lib/host-probe.js';\n\n/**\n * Best-effort skill install after a successful auth-login.\n *\n * Mirrors the install.ts hook copy, but wraps `autoInstallSkills` in its own\n * try/catch AND a 30s timeout so a skill install hang (e.g. blocked filesystem\n * call) never blocks login completion. Login already succeeded by the time\n * this runs — the user having a working session is the contract that must hold.\n *\n * Extracted from runLogin so it can be unit-tested without standing up the\n * device-auth polling loop.\n */\nexport const SKILL_INSTALL_TIMEOUT_MS = 30 * 1000;\n\nexport async function installSkillsAfterLogin(): Promise<void> {\n let timeoutHandle: ReturnType<typeof setTimeout> | undefined;\n try {\n const timeout = new Promise<null>((resolve) => {\n timeoutHandle = setTimeout(() => resolve(null), SKILL_INSTALL_TIMEOUT_MS);\n // Don't keep the event loop alive on this timer — process should exit\n // immediately if everything else has resolved.\n timeoutHandle.unref?.();\n });\n const result = await Promise.race([autoInstallSkills(), timeout]);\n if (result && !isJsonMode()) {\n const skillWord = result.skills.length === 1 ? 'skill' : 'skills';\n clack.log.info(`Installed ${result.skills.length} WorkOS ${skillWord} for ${result.agents.join(', ')}.`);\n }\n } catch {\n // Skill install must never fail login.\n } finally {\n if (timeoutHandle) clearTimeout(timeoutHandle);\n }\n}\n\n/**\n * Auto-provision a staging environment after login.\n *\n * Fetches staging credentials using the access token, then saves them\n * as a \"staging\" environment in the config store. Non-fatal — logs a\n * hint on failure instead of throwing.\n */\nexport async function provisionStagingEnvironment(accessToken: string): Promise<boolean> {\n try {\n const staging = await fetchStagingCredentials(accessToken);\n\n const config: CliConfig = getConfig() ?? { environments: {} };\n const isFirst = Object.keys(config.environments).length === 0;\n\n config.environments['staging'] = {\n name: 'staging',\n type: 'sandbox',\n apiKey: staging.apiKey,\n clientId: staging.clientId,\n };\n\n if (isFirst || !config.activeEnvironment) {\n config.activeEnvironment = 'staging';\n }\n\n saveConfig(config);\n logInfo('[login] Staging environment auto-provisioned');\n return true;\n } catch (error) {\n logError('[login] Failed to auto-provision staging environment:', error instanceof Error ? error.message : error);\n return false;\n }\n}\n\nexport async function runLogin(): Promise<void> {\n const clientId = getCliAuthClientId();\n\n // Check if already logged in with valid token\n if (getAccessToken()) {\n const creds = getCredentials();\n console.log(chalk.green(`Already logged in as ${creds?.email ?? 'unknown'}`));\n console.log(chalk.dim(`Run \\`${formatWorkOSCommand('auth logout')}\\` to log out`));\n return;\n }\n\n // Try to refresh if we have expired credentials with a refresh token\n const existingCreds = getCredentials();\n if (existingCreds?.refreshToken && isTokenExpired(existingCreds)) {\n try {\n const authkitDomain = getAuthkitDomain();\n const result = await refreshAccessToken(authkitDomain, clientId);\n if (result.accessToken && result.expiresAt) {\n updateTokens(result.accessToken, result.expiresAt, result.refreshToken);\n logInfo('[login] Session refreshed via refresh token');\n console.log(chalk.green(`Already logged in as ${existingCreds.email ?? 'unknown'}`));\n console.log(chalk.dim(`Run \\`${formatWorkOSCommand('auth logout')}\\` to log out`));\n return;\n }\n } catch {\n // Refresh failed, proceed with fresh login\n }\n }\n\n if (isCiMode()) {\n exitWithAuthRequired(\n 'Browser authentication is not available in CI mode. Set WORKOS_API_KEY or configure credentials before running in CI.',\n );\n }\n\n const authkitDomain = getAuthkitDomain();\n\n clack.log.step('Starting authentication...');\n\n let deviceAuth;\n try {\n deviceAuth = await requestDeviceCode({ clientId, authkitDomain });\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error);\n clack.log.error(`Failed to start authentication: ${msg}`);\n process.exit(1);\n }\n\n clack.log.info(`\\nOpen this URL in your browser:\\n`);\n console.log(` ${deviceAuth.verification_uri}`);\n console.log(`\\nEnter code: ${deviceAuth.user_code}\\n`);\n\n try {\n await open(deviceAuth.verification_uri_complete, { wait: false });\n if (isAgentMode()) {\n clack.log.info('Browser launch attempted. If it did not open on the host, use the manual URL and code above.');\n } else {\n clack.log.info('Browser opened automatically');\n }\n } catch (error) {\n observeHostFailure('browser-launch', error, {\n operation: 'open',\n target: deviceAuth.verification_uri_complete,\n label: 'auth login browser',\n });\n clack.log.info('Could not open browser — open the URL above manually.');\n }\n\n const spinner = clack.spinner();\n spinner.start('Waiting for authentication...');\n\n try {\n const result = await pollForToken(deviceAuth.device_code, {\n clientId,\n authkitDomain,\n interval: deviceAuth.interval,\n });\n\n const expiresInSec = Math.round((result.expiresAt - Date.now()) / 1000);\n\n saveCredentials({\n accessToken: result.accessToken,\n expiresAt: result.expiresAt,\n userId: result.userId,\n email: result.email,\n refreshToken: result.refreshToken,\n });\n\n spinner.stop('Authentication successful!');\n clack.log.success(`Logged in as ${result.email || result.userId}`);\n clack.log.info(`Token expires in ${expiresInSec} seconds`);\n\n const provisioned = await provisionStagingEnvironment(result.accessToken);\n if (provisioned) {\n clack.log.success('Staging environment configured automatically');\n } else {\n clack.log.info(chalk.dim('Run `workos env add` to configure an environment manually'));\n }\n\n await installSkillsAfterLogin();\n } catch (error) {\n if (error instanceof DeviceAuthTimeoutError) {\n spinner.stop('Authentication timed out');\n clack.log.error('Authentication timed out. Please try again.');\n } else {\n spinner.stop('Authentication failed');\n const msg = error instanceof Error ? error.message : String(error);\n clack.log.error(`Authentication error: ${msg}`);\n }\n process.exit(1);\n }\n}\n"]}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
const workosOnlyMigrationsFlags = new Map([
|
|
2
|
+
['--api-key', true],
|
|
3
|
+
['--insecure-storage', false],
|
|
4
|
+
['--json', false],
|
|
5
|
+
['--mode', true],
|
|
6
|
+
]);
|
|
7
|
+
export function getMigrationsPassthroughArgs(rawArgs) {
|
|
8
|
+
let migrationsIdx = rawArgs.indexOf('migrations');
|
|
9
|
+
for (let i = 0; i < rawArgs.length; i++) {
|
|
10
|
+
const arg = rawArgs[i];
|
|
11
|
+
const key = arg.split('=')[0];
|
|
12
|
+
const takesValue = workosOnlyMigrationsFlags.get(key);
|
|
13
|
+
if (takesValue !== undefined) {
|
|
14
|
+
if (takesValue && !arg.includes('='))
|
|
15
|
+
i++;
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
if (arg === 'migrations') {
|
|
19
|
+
migrationsIdx = i;
|
|
20
|
+
break;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
const after = rawArgs.slice(migrationsIdx + 1);
|
|
24
|
+
const passthrough = [];
|
|
25
|
+
for (let i = 0; i < after.length; i++) {
|
|
26
|
+
const arg = after[i];
|
|
27
|
+
const key = arg.split('=')[0];
|
|
28
|
+
const takesValue = workosOnlyMigrationsFlags.get(key);
|
|
29
|
+
if (takesValue !== undefined) {
|
|
30
|
+
if (takesValue && !arg.includes('='))
|
|
31
|
+
i++;
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
passthrough.push(arg);
|
|
35
|
+
}
|
|
36
|
+
return passthrough;
|
|
37
|
+
}
|
|
38
|
+
export async function runMigrations(args, apiKey) {
|
|
39
|
+
process.env.WORKOS_SECRET_KEY = apiKey;
|
|
40
|
+
const { program } = (await import('@workos/migrations/dist/cli/index.js'));
|
|
41
|
+
program.name('workos migrations');
|
|
42
|
+
await program.parseAsync(args, { from: 'user' });
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=migrations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migrations.js","sourceRoot":"","sources":["../../src/commands/migrations.ts"],"names":[],"mappings":"AAAA,MAAM,yBAAyB,GAAG,IAAI,GAAG,CAAC;IACxC,CAAC,WAAW,EAAE,IAAI,CAAC;IACnB,CAAC,oBAAoB,EAAE,KAAK,CAAC;IAC7B,CAAC,QAAQ,EAAE,KAAK,CAAC;IACjB,CAAC,QAAQ,EAAE,IAAI,CAAC;CACjB,CAAC,CAAC;AAEH,MAAM,UAAU,4BAA4B,CAAC,OAAiB;IAC5D,IAAI,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IAElD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACxC,MAAM,GAAG,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;QACvB,MAAM,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAC9B,MAAM,UAAU,GAAG,yBAAyB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAEtD,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;YAC7B,IAAI,UAAU,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC;gBAAE,CAAC,EAAE,CAAC;YAC1C,SAAS;QACX,CAAC;QAED,IAAI,GAAG,KAAK,YAAY,EAAE,CAAC;YACzB,aAAa,GAAG,CAAC,CAAC;YAClB,MAAM;QACR,CAAC;IACH,CAAC;IAED,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,aAAa,GAAG,CAAC,CAAC,CAAC;IAC/C,MAAM,WAAW,GAAa,EAAE,CAAC;IAEjC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACrB,MAAM,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAC9B,MAAM,UAAU,GAAG,yBAAyB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAEtD,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;YAC7B,IAAI,UAAU,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC;gBAAE,CAAC,EAAE,CAAC;YAC1C,SAAS;QACX,CAAC;QAED,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACxB,CAAC;IAED,OAAO,WAAW,CAAC;AACrB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,IAAc,EAAE,MAAc;IAChE,OAAO,CAAC,GAAG,CAAC,iBAAiB,GAAG,MAAM,CAAC;IAEvC,MAAM,EAAE,OAAO,EAAE,GAAG,CAAC,MAAM,MAAM,CAAC,sCAAsC,CAAC,CAKxE,CAAC;IAEF,OAAO,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;IAClC,MAAM,OAAO,CAAC,UAAU,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;AACnD,CAAC","sourcesContent":["const workosOnlyMigrationsFlags = new Map([\n ['--api-key', true],\n ['--insecure-storage', false],\n ['--json', false],\n ['--mode', true],\n]);\n\nexport function getMigrationsPassthroughArgs(rawArgs: string[]): string[] {\n let migrationsIdx = rawArgs.indexOf('migrations');\n\n for (let i = 0; i < rawArgs.length; i++) {\n const arg = rawArgs[i];\n const key = arg.split('=')[0];\n const takesValue = workosOnlyMigrationsFlags.get(key);\n\n if (takesValue !== undefined) {\n if (takesValue && !arg.includes('=')) i++;\n continue;\n }\n\n if (arg === 'migrations') {\n migrationsIdx = i;\n break;\n }\n }\n\n const after = rawArgs.slice(migrationsIdx + 1);\n const passthrough: string[] = [];\n\n for (let i = 0; i < after.length; i++) {\n const arg = after[i];\n const key = arg.split('=')[0];\n const takesValue = workosOnlyMigrationsFlags.get(key);\n\n if (takesValue !== undefined) {\n if (takesValue && !arg.includes('=')) i++;\n continue;\n }\n\n passthrough.push(arg);\n }\n\n return passthrough;\n}\n\nexport async function runMigrations(args: string[], apiKey: string): Promise<void> {\n process.env.WORKOS_SECRET_KEY = apiKey;\n\n const { program } = (await import('@workos/migrations/dist/cli/index.js')) as {\n program: {\n name(str: string): unknown;\n parseAsync(argv: string[], options?: { from: 'user' }): Promise<unknown>;\n };\n };\n\n program.name('workos migrations');\n await program.parseAsync(args, { from: 'user' });\n}\n"]}
|
|
@@ -415,11 +415,22 @@ function checkMissingApiHostname(ctx) {
|
|
|
415
415
|
}
|
|
416
416
|
// --- Cross-language checks (run for ALL projects, not just JS/AuthKit) ---
|
|
417
417
|
const SOURCE_EXTENSIONS = /\.(ts|tsx|js|jsx|py|rb|go|java|kt|php|cs|swift|dart)$/;
|
|
418
|
+
const SECRET_SOURCE_IGNORED_SEGMENTS = new Set(['__fixtures__', '__tests__', 'evals', 'fixtures', 'test', 'tests']);
|
|
419
|
+
function isIgnoredSecretSourcePath(relativePath) {
|
|
420
|
+
const normalized = relativePath.replace(/\\/g, '/');
|
|
421
|
+
const parts = normalized.split('/');
|
|
422
|
+
if (parts.some((part) => SECRET_SOURCE_IGNORED_SEGMENTS.has(part)))
|
|
423
|
+
return true;
|
|
424
|
+
return /\.(spec|test)\.[^.]+$/.test(normalized);
|
|
425
|
+
}
|
|
418
426
|
function checkApiKeyInSource(ctx) {
|
|
419
427
|
const API_KEY_PATTERN = /sk_(test|live)_[A-Za-z0-9]{10,}/;
|
|
420
428
|
const sourceFiles = findFilesShallow(ctx.installDir, SOURCE_EXTENSIONS, 4);
|
|
421
429
|
const findings = [];
|
|
422
430
|
for (const file of sourceFiles) {
|
|
431
|
+
const relativePath = relative(ctx.installDir, file);
|
|
432
|
+
if (isIgnoredSecretSourcePath(relativePath))
|
|
433
|
+
continue;
|
|
423
434
|
const content = readFileSafe(file);
|
|
424
435
|
if (!content)
|
|
425
436
|
continue;
|
|
@@ -428,7 +439,7 @@ function checkApiKeyInSource(ctx) {
|
|
|
428
439
|
code: 'API_KEY_IN_SOURCE',
|
|
429
440
|
severity: 'error',
|
|
430
441
|
message: `WorkOS API key hardcoded in source file`,
|
|
431
|
-
filePath:
|
|
442
|
+
filePath: relativePath,
|
|
432
443
|
remediation: 'Move the API key to an environment variable (WORKOS_API_KEY) and load it from .env or your secret manager.',
|
|
433
444
|
});
|
|
434
445
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth-patterns.js","sourceRoot":"","sources":["../../../src/doctor/checks/auth-patterns.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, readFileSync, readdirSync } from 'node:fs';\nimport { join, relative } from 'node:path';\nimport type {\n AuthPatternFinding,\n AuthPatternInfo,\n FrameworkInfo,\n EnvironmentInfo,\n SdkInfo,\n DoctorOptions,\n} from '../types.js';\n\n// --- Helpers ---\n\n/** Return the first path that exists, or null */\nfunction findFile(paths: string[]): string | null {\n for (const p of paths) {\n if (existsSync(p)) return p;\n }\n return null;\n}\n\n/** Read file content safely, return null on any error */\nfunction readFileSafe(filePath: string): string | null {\n try {\n return readFileSync(filePath, 'utf-8');\n } catch {\n return null;\n }\n}\n\n/** Test if a file exists and its content matches a regex */\nfunction fileContains(filePath: string, pattern: RegExp): boolean {\n const content = readFileSafe(filePath);\n if (!content) return false;\n return pattern.test(content);\n}\n\nconst SKIP_DIRS = new Set(['node_modules', '.next', '.turbo', 'dist', '.git', 'coverage']);\n\n/**\n * Find files matching a name pattern in a directory tree, limited to maxDepth levels.\n * Skips node_modules, .next, dist, etc.\n */\nfunction findFilesShallow(dir: string, namePattern: RegExp, maxDepth = 3): string[] {\n const results: string[] = [];\n if (!existsSync(dir)) return results;\n\n function walk(currentDir: string, depth: number) {\n if (depth > maxDepth) return;\n try {\n const dirents = readdirSync(currentDir, { withFileTypes: true });\n for (const dirent of dirents) {\n const fullPath = join(currentDir, dirent.name);\n if (dirent.isDirectory()) {\n if (!SKIP_DIRS.has(dirent.name)) {\n walk(fullPath, depth + 1);\n }\n } else if (dirent.isFile() && namePattern.test(dirent.name)) {\n results.push(fullPath);\n }\n }\n } catch {\n // Directory unreadable\n }\n }\n\n walk(dir, 0);\n return results;\n}\n\nfunction parseEnvFile(content: string): Record<string, string> {\n const result: Record<string, string> = {};\n for (const line of content.split('\\n')) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('#')) continue;\n const entry = trimmed.startsWith('export ') ? trimmed.slice(7) : trimmed;\n const eqIndex = entry.indexOf('=');\n if (eqIndex === -1) continue;\n const key = entry.slice(0, eqIndex).trim();\n let value = entry.slice(eqIndex + 1).trim();\n if ((value.startsWith('\"') && value.endsWith('\"')) || (value.startsWith(\"'\") && value.endsWith(\"'\"))) {\n value = value.slice(1, -1);\n }\n result[key] = value;\n }\n return result;\n}\n\n/** Load all env vars from .env and .env.local files */\nfunction loadProjectEnvRaw(installDir: string): Record<string, string> {\n const env: Record<string, string> = {};\n for (const file of ['.env', '.env.local']) {\n const content = readFileSafe(join(installDir, file));\n if (content) Object.assign(env, parseEnvFile(content));\n }\n return env;\n}\n\n// --- Check Context ---\n\ninterface CheckContext {\n framework: FrameworkInfo;\n environment: EnvironmentInfo;\n sdk: SdkInfo;\n installDir: string;\n}\n\n// --- Individual Checks ---\n\n/** Resolve the app directory root (app/ or src/app/) for Next.js */\nfunction resolveAppDir(installDir: string): string | null {\n const srcApp = join(installDir, 'src', 'app');\n if (existsSync(srcApp)) return srcApp;\n const app = join(installDir, 'app');\n if (existsSync(app)) return app;\n return null;\n}\n\nfunction checkSignoutGetHandler(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'Next.js') return [];\n const appDir = resolveAppDir(ctx.installDir);\n if (!appDir) return [];\n\n const routeFiles = findFilesShallow(appDir, /^route\\.(ts|tsx|js|jsx)$/);\n const signoutRoutes = routeFiles.filter((f) => /[/\\\\](sign-?out|logout)[/\\\\]/.test(f));\n\n const findings: AuthPatternFinding[] = [];\n const GET_EXPORT = /export\\s+(async\\s+)?function\\s+GET|export\\s+const\\s+GET/;\n\n for (const route of signoutRoutes) {\n if (fileContains(route, GET_EXPORT)) {\n findings.push({\n code: 'SIGNOUT_GET_HANDLER',\n severity: 'error',\n message: 'Signout/logout route uses GET handler — vulnerable to CSRF and prefetch-triggered logouts',\n filePath: relative(ctx.installDir, route),\n remediation:\n 'Convert to a POST server action. GET routes with side effects are vulnerable to CSRF and will be triggered by Next.js link prefetching.',\n docsUrl: 'https://workos.com/docs/authkit/sign-out',\n });\n }\n }\n return findings;\n}\n\nfunction checkSignoutLinkPrefetch(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'Next.js') return [];\n const appDir = resolveAppDir(ctx.installDir);\n if (!appDir) return [];\n\n const tsxFiles = findFilesShallow(appDir, /\\.(tsx|jsx)$/);\n // Match <Link>, <NextLink>, or other common aliases\n const LINK_PATTERN = /<(?:Next)?Link\\s[^>]*href\\s*=\\s*[\"'{`/]*(\\/sign-?out|\\/logout)/;\n\n const findings: AuthPatternFinding[] = [];\n for (const file of tsxFiles) {\n if (fileContains(file, LINK_PATTERN)) {\n findings.push({\n code: 'SIGNOUT_LINK_PREFETCH',\n severity: 'warning',\n message:\n 'Link component points to signout/logout — Next.js will prefetch this in production, potentially triggering logouts',\n filePath: relative(ctx.installDir, file),\n remediation:\n 'Use a <form> with a server action or <button> with onClick handler instead of <Link> for signout.',\n });\n }\n }\n return findings;\n}\n\nfunction checkMissingMiddleware(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'Next.js') return [];\n\n const middlewarePaths = [\n 'middleware.ts',\n 'middleware.js',\n 'proxy.ts',\n 'proxy.js',\n 'src/middleware.ts',\n 'src/middleware.js',\n 'src/proxy.ts',\n 'src/proxy.js',\n ].map((p) => join(ctx.installDir, p));\n\n if (findFile(middlewarePaths)) return [];\n\n return [\n {\n code: 'MISSING_MIDDLEWARE',\n severity: 'error',\n message: 'No middleware.ts or proxy.ts found — AuthKit session handling requires middleware',\n remediation: 'Create middleware.ts at the project root with authkitMiddleware() from @workos-inc/authkit-nextjs.',\n docsUrl: 'https://workos.com/docs/authkit/nextjs/middleware',\n },\n ];\n}\n\nfunction checkMiddlewareWrongLocation(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'Next.js') return [];\n\n const wrongPaths = ['app/middleware.ts', 'app/middleware.js', 'src/app/middleware.ts', 'src/app/middleware.js'].map(\n (p) => join(ctx.installDir, p),\n );\n\n const found = findFile(wrongPaths);\n if (!found) return [];\n\n return [\n {\n code: 'MIDDLEWARE_WRONG_LOCATION',\n severity: 'warning',\n message: 'middleware.ts found inside app/ directory — must be at project root or src/',\n filePath: relative(ctx.installDir, found),\n remediation: 'Move middleware.ts to the project root (or src/ if using src/ directory).',\n docsUrl: 'https://workos.com/docs/authkit/nextjs/middleware',\n },\n ];\n}\n\nfunction checkMissingAuthKitProvider(ctx: CheckContext): AuthPatternFinding[] {\n const layoutPaths: string[] = [];\n\n if (ctx.framework.name === 'Next.js') {\n layoutPaths.push(\n join(ctx.installDir, 'app', 'layout.tsx'),\n join(ctx.installDir, 'app', 'layout.jsx'),\n join(ctx.installDir, 'src', 'app', 'layout.tsx'),\n join(ctx.installDir, 'src', 'app', 'layout.jsx'),\n );\n } else if (ctx.framework.name === 'React Router' && ctx.framework.variant === 'declarative') {\n layoutPaths.push(\n join(ctx.installDir, 'src', 'App.tsx'),\n join(ctx.installDir, 'src', 'App.jsx'),\n join(ctx.installDir, 'app', 'root.tsx'),\n join(ctx.installDir, 'app', 'root.jsx'),\n );\n } else {\n return [];\n }\n\n const layoutFile = findFile(layoutPaths);\n if (!layoutFile) return []; // Can't check if layout doesn't exist\n\n if (fileContains(layoutFile, /AuthKitProvider/)) return [];\n\n return [\n {\n code: 'MISSING_AUTHKIT_PROVIDER',\n severity: 'warning',\n message: 'AuthKitProvider not found in root layout — required for AuthKit session management',\n filePath: relative(ctx.installDir, layoutFile),\n remediation: 'Wrap your app with <AuthKitProvider> in the root layout.',\n docsUrl: 'https://workos.com/docs/authkit/nextjs/setup',\n },\n ];\n}\n\n/** Extract callback path from redirect URI env vars or framework default */\nfunction resolveCallbackPath(ctx: CheckContext): string | null {\n // Check env vars for actual redirect URI (including NEXT_PUBLIC_ variant)\n const projectEnv = loadProjectEnvRaw(ctx.installDir);\n const redirectUri =\n projectEnv.WORKOS_REDIRECT_URI ?? projectEnv.NEXT_PUBLIC_WORKOS_REDIRECT_URI ?? ctx.environment.redirectUri;\n\n if (redirectUri) {\n try {\n return new URL(redirectUri).pathname;\n } catch {\n // Invalid URL, fall through to framework default\n }\n }\n\n return ctx.framework.expectedCallbackPath ?? null;\n}\n\nfunction checkCallbackRouteMissing(ctx: CheckContext): AuthPatternFinding[] {\n const callbackPath = resolveCallbackPath(ctx);\n if (!callbackPath) return [];\n\n // Build expected route file paths based on framework\n const possiblePaths: string[] = [];\n\n if (ctx.framework.name === 'Next.js') {\n // app/auth/callback/route.ts (or src/app/)\n const routeDir = callbackPath.replace(/^\\//, ''); // 'auth/callback'\n for (const prefix of ['app', 'src/app']) {\n for (const ext of ['ts', 'tsx', 'js', 'jsx']) {\n possiblePaths.push(join(ctx.installDir, prefix, routeDir, `route.${ext}`));\n }\n }\n } else if (ctx.framework.name === 'React Router') {\n // Flat: app/routes/auth.callback.tsx Nested: app/routes/auth/callback.tsx\n const segments = callbackPath.replace(/^\\//, '').split('/');\n const flat = segments.join('.');\n const nested = segments.join('/');\n for (const ext of ['tsx', 'jsx', 'ts', 'js']) {\n possiblePaths.push(join(ctx.installDir, 'app', 'routes', `${flat}.${ext}`));\n possiblePaths.push(join(ctx.installDir, 'app', 'routes', nested + `.${ext}`));\n }\n } else if (ctx.framework.name === 'TanStack Start') {\n // Flat: routes/api.auth.callback.tsx Nested: routes/api/auth/callback.tsx\n // Both conventions work in both src/ and app/ directories\n const segments = callbackPath.replace(/^\\//, '').split('/');\n const flat = segments.join('.');\n const nested = segments.join('/');\n for (const prefix of ['src', 'app']) {\n for (const ext of ['tsx', 'jsx', 'ts', 'js']) {\n possiblePaths.push(join(ctx.installDir, prefix, 'routes', `${flat}.${ext}`));\n possiblePaths.push(join(ctx.installDir, prefix, 'routes', nested + `.${ext}`));\n }\n }\n }\n\n if (possiblePaths.length === 0) return [];\n if (findFile(possiblePaths)) return [];\n\n return [\n {\n code: 'CALLBACK_ROUTE_MISSING',\n severity: 'error',\n message: `No callback route found at expected path ${callbackPath}`,\n remediation: `Create the callback route handler at the path matching your WORKOS_REDIRECT_URI.`,\n docsUrl: 'https://workos.com/docs/authkit/redirect-uri',\n },\n ];\n}\n\nconst CLIENT_ENV_PREFIXES = ['NEXT_PUBLIC_', 'VITE_', 'REACT_APP_', 'EXPO_PUBLIC_'];\n\nfunction checkApiKeyLeakedToClient(ctx: CheckContext): AuthPatternFinding[] {\n const projectEnv = loadProjectEnvRaw(ctx.installDir);\n const findings: AuthPatternFinding[] = [];\n\n for (const [key, value] of Object.entries(projectEnv)) {\n const hasClientPrefix = CLIENT_ENV_PREFIXES.some((prefix) => key.startsWith(prefix));\n if (!hasClientPrefix) continue;\n\n const isApiKey = key.includes('WORKOS_API_KEY');\n const isSecretValue = value?.startsWith('sk_test_') || value?.startsWith('sk_live_');\n\n if (isApiKey || isSecretValue) {\n findings.push({\n code: 'API_KEY_LEAKED_TO_CLIENT',\n severity: 'error',\n message: `Secret API key exposed via client-accessible env var ${key}`,\n remediation: `Remove the client prefix. WORKOS_API_KEY must be server-only (no NEXT_PUBLIC_, VITE_, REACT_APP_, or EXPO_PUBLIC_ prefix).`,\n });\n }\n }\n return findings;\n}\n\nfunction checkWrongCallbackLoader(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'React Router') return [];\n const callbackPath = ctx.framework.expectedCallbackPath;\n if (!callbackPath) return [];\n\n const segments = callbackPath.replace(/^\\//, '').split('/');\n const flat = segments.join('.');\n const nested = segments.join('/');\n\n const possiblePaths: string[] = [];\n for (const ext of ['tsx', 'jsx', 'ts', 'js']) {\n possiblePaths.push(join(ctx.installDir, 'app', 'routes', `${flat}.${ext}`));\n possiblePaths.push(join(ctx.installDir, 'app', 'routes', nested + `.${ext}`));\n }\n\n const callbackFile = findFile(possiblePaths);\n if (!callbackFile) return []; // No callback route to check\n\n // authkitLoader is for regular routes; authLoader is for the callback\n if (fileContains(callbackFile, /authkitLoader/) && !fileContains(callbackFile, /authLoader/)) {\n return [\n {\n code: 'WRONG_CALLBACK_LOADER',\n severity: 'warning',\n message: 'Callback route uses authkitLoader instead of authLoader',\n filePath: relative(ctx.installDir, callbackFile),\n remediation:\n 'Use authLoader (not authkitLoader) for the callback route. authkitLoader is for regular routes that need auth context.',\n },\n ];\n }\n return [];\n}\n\nfunction checkMissingRootAuthLoader(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'React Router') return [];\n\n const rootPaths = ['app/root.tsx', 'app/root.jsx', 'app/routes/_index.tsx', 'app/routes/_index.jsx'].map((p) =>\n join(ctx.installDir, p),\n );\n\n const rootFile = findFile(rootPaths);\n if (!rootFile) return [];\n\n if (fileContains(rootFile, /authkitLoader/)) return [];\n\n return [\n {\n code: 'MISSING_ROOT_AUTH_LOADER',\n severity: 'warning',\n message: 'Root route does not use authkitLoader — child routes will not have auth context',\n filePath: relative(ctx.installDir, rootFile),\n remediation: 'Add authkitLoader to your root route so child routes can access auth state.',\n },\n ];\n}\n\nfunction checkMissingAuthkitMiddleware(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'TanStack Start') return [];\n\n const startPaths = ['src/start.ts', 'src/start.tsx', 'app/start.ts', 'app/start.tsx'].map((p) =>\n join(ctx.installDir, p),\n );\n\n const startFile = findFile(startPaths);\n if (!startFile) return []; // Can't check if start file doesn't exist\n\n if (fileContains(startFile, /authkitMiddleware/)) return [];\n\n return [\n {\n code: 'MISSING_AUTHKIT_MIDDLEWARE',\n severity: 'warning',\n message: 'start.ts does not reference authkitMiddleware — AuthKit session handling requires it',\n filePath: relative(ctx.installDir, startFile),\n remediation:\n 'Add authkitMiddleware to requestMiddleware in src/start.ts:\\n' +\n ' import { authkitMiddleware } from \"@workos/authkit-tanstack-react-start\";\\n' +\n ' export default createStart({ requestMiddleware: [authkitMiddleware()] });',\n },\n ];\n}\n\nfunction checkCookiePasswordTooShort(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'React Router' && ctx.framework.name !== 'TanStack Start') return [];\n\n const projectEnv = loadProjectEnvRaw(ctx.installDir);\n const password = projectEnv.WORKOS_COOKIE_PASSWORD;\n\n // Only warn if password is set but too short; missing password is a separate concern\n if (!password || password.length >= 32) return [];\n\n return [\n {\n code: 'COOKIE_PASSWORD_TOO_SHORT',\n severity: 'warning',\n message: `WORKOS_COOKIE_PASSWORD is ${password.length} characters — minimum 32 required for secure encryption`,\n remediation: 'Set WORKOS_COOKIE_PASSWORD to a random string of at least 32 characters.',\n },\n ];\n}\n\nconst REACT_SPA_SDKS = new Set(['@workos-inc/authkit-react']);\n\nfunction checkMissingApiHostname(ctx: CheckContext): AuthPatternFinding[] {\n if (!ctx.sdk.name || !REACT_SPA_SDKS.has(ctx.sdk.name)) return [];\n\n const sourceFiles = findFilesShallow(ctx.installDir, /\\.(tsx|jsx|ts|js)$/, 4);\n const providerFiles = sourceFiles.filter((f) => fileContains(f, /AuthKitProvider/));\n if (providerFiles.length === 0) return [];\n\n const hasApiHostname = providerFiles.some((f) => fileContains(f, /apiHostname/));\n if (hasApiHostname) return [];\n\n return [\n {\n code: 'MISSING_API_HOSTNAME',\n severity: 'warning',\n message: 'AuthKitProvider does not specify apiHostname — authorize requests will route through api.workos.com',\n filePath: relative(ctx.installDir, providerFiles[0]),\n remediation:\n 'Set the apiHostname prop on AuthKitProvider to your custom Authentication API domain (e.g. auth.example.com) to avoid routing through api.workos.com.',\n docsUrl: 'https://workos.com/docs/custom-domains',\n },\n ];\n}\n\n// --- Cross-language checks (run for ALL projects, not just JS/AuthKit) ---\n\nconst SOURCE_EXTENSIONS = /\\.(ts|tsx|js|jsx|py|rb|go|java|kt|php|cs|swift|dart)$/;\n\nfunction checkApiKeyInSource(ctx: CheckContext): AuthPatternFinding[] {\n const API_KEY_PATTERN = /sk_(test|live)_[A-Za-z0-9]{10,}/;\n const sourceFiles = findFilesShallow(ctx.installDir, SOURCE_EXTENSIONS, 4);\n const findings: AuthPatternFinding[] = [];\n\n for (const file of sourceFiles) {\n const content = readFileSafe(file);\n if (!content) continue;\n if (API_KEY_PATTERN.test(content)) {\n findings.push({\n code: 'API_KEY_IN_SOURCE',\n severity: 'error',\n message: `WorkOS API key hardcoded in source file`,\n filePath: relative(ctx.installDir, file),\n remediation:\n 'Move the API key to an environment variable (WORKOS_API_KEY) and load it from .env or your secret manager.',\n });\n }\n }\n return findings;\n}\n\nfunction checkEnvFileNotGitignored(ctx: CheckContext): AuthPatternFinding[] {\n const envFiles = ['.env', '.env.local'].filter((f) => existsSync(join(ctx.installDir, f)));\n if (envFiles.length === 0) return [];\n\n const gitignorePath = join(ctx.installDir, '.gitignore');\n const gitignore = readFileSafe(gitignorePath);\n\n const findings: AuthPatternFinding[] = [];\n for (const envFile of envFiles) {\n const isIgnored =\n gitignore !== null &&\n gitignore.split('\\n').some((line) => {\n const trimmed = line.trim();\n if (trimmed.startsWith('#') || trimmed === '') return false;\n return trimmed === envFile || trimmed === '.env*' || trimmed === '.env.*' || trimmed === '.env';\n });\n\n if (!isIgnored) {\n findings.push({\n code: 'ENV_FILE_NOT_GITIGNORED',\n severity: 'warning',\n message: `${envFile} is not in .gitignore — secrets may be committed to version control`,\n filePath: envFile,\n remediation: `Add ${envFile} to your .gitignore file.`,\n });\n }\n }\n return findings;\n}\n\nfunction checkMixedEnvironmentCredentials(ctx: CheckContext): AuthPatternFinding[] {\n const projectEnv = loadProjectEnvRaw(ctx.installDir);\n const apiKey = projectEnv.WORKOS_API_KEY;\n const redirectUri = projectEnv.WORKOS_REDIRECT_URI ?? projectEnv.NEXT_PUBLIC_WORKOS_REDIRECT_URI;\n\n if (!apiKey || !redirectUri) return [];\n\n const isTestKey = apiKey.startsWith('sk_test_');\n const isLiveKey = apiKey.startsWith('sk_live_');\n\n let isProductionUri = false;\n try {\n const url = new URL(redirectUri);\n isProductionUri = url.hostname !== 'localhost' && !url.hostname.startsWith('127.0.0.');\n } catch {\n return [];\n }\n\n if (isTestKey && isProductionUri) {\n return [\n {\n code: 'MIXED_ENVIRONMENT',\n severity: 'warning',\n message: 'Staging API key (sk_test_) used with a production redirect URI',\n remediation:\n 'Use sk_live_ API key for production redirect URIs, or change the redirect URI to localhost for staging.',\n },\n ];\n }\n\n if (isLiveKey && !isProductionUri) {\n return [\n {\n code: 'MIXED_ENVIRONMENT',\n severity: 'warning',\n message: 'Production API key (sk_live_) used with a localhost redirect URI',\n remediation:\n 'Use sk_test_ API key for localhost development, or update the redirect URI to your production domain.',\n },\n ];\n }\n\n return [];\n}\n\n// --- Main Entry Point ---\n\ntype CheckFn = (ctx: CheckContext) => AuthPatternFinding[];\n\nconst CROSS_FRAMEWORK_CHECKS: CheckFn[] = [\n checkApiKeyLeakedToClient,\n checkApiKeyInSource,\n checkEnvFileNotGitignored,\n checkMixedEnvironmentCredentials,\n checkMissingApiHostname,\n];\n\nconst NEXTJS_CHECKS: CheckFn[] = [\n checkSignoutGetHandler,\n checkSignoutLinkPrefetch,\n checkMissingMiddleware,\n checkMiddlewareWrongLocation,\n checkMissingAuthKitProvider,\n checkCallbackRouteMissing,\n];\n\nconst REACT_ROUTER_CHECKS: CheckFn[] = [\n checkWrongCallbackLoader,\n checkMissingRootAuthLoader,\n checkMissingAuthKitProvider,\n checkCallbackRouteMissing,\n checkCookiePasswordTooShort,\n];\n\nconst TANSTACK_CHECKS: CheckFn[] = [\n checkMissingAuthkitMiddleware,\n checkCallbackRouteMissing,\n checkCookiePasswordTooShort,\n];\n\nexport async function checkAuthPatterns(\n options: DoctorOptions,\n framework: FrameworkInfo,\n environment: EnvironmentInfo,\n sdk: SdkInfo,\n): Promise<AuthPatternInfo> {\n const ctx: CheckContext = {\n framework,\n environment,\n sdk,\n installDir: options.installDir,\n };\n\n const checks: CheckFn[] = [...CROSS_FRAMEWORK_CHECKS];\n\n switch (framework.name) {\n case 'Next.js':\n checks.push(...NEXTJS_CHECKS);\n break;\n case 'React Router':\n checks.push(...REACT_ROUTER_CHECKS);\n break;\n case 'TanStack Start':\n checks.push(...TANSTACK_CHECKS);\n break;\n }\n\n const findings: AuthPatternFinding[] = [];\n for (const check of checks) {\n findings.push(...check(ctx));\n }\n\n return {\n checksRun: checks.length,\n findings,\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"auth-patterns.js","sourceRoot":"","sources":["../../../src/doctor/checks/auth-patterns.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, readFileSync, readdirSync } from 'node:fs';\nimport { join, relative } from 'node:path';\nimport type {\n AuthPatternFinding,\n AuthPatternInfo,\n FrameworkInfo,\n EnvironmentInfo,\n SdkInfo,\n DoctorOptions,\n} from '../types.js';\n\n// --- Helpers ---\n\n/** Return the first path that exists, or null */\nfunction findFile(paths: string[]): string | null {\n for (const p of paths) {\n if (existsSync(p)) return p;\n }\n return null;\n}\n\n/** Read file content safely, return null on any error */\nfunction readFileSafe(filePath: string): string | null {\n try {\n return readFileSync(filePath, 'utf-8');\n } catch {\n return null;\n }\n}\n\n/** Test if a file exists and its content matches a regex */\nfunction fileContains(filePath: string, pattern: RegExp): boolean {\n const content = readFileSafe(filePath);\n if (!content) return false;\n return pattern.test(content);\n}\n\nconst SKIP_DIRS = new Set(['node_modules', '.next', '.turbo', 'dist', '.git', 'coverage']);\n\n/**\n * Find files matching a name pattern in a directory tree, limited to maxDepth levels.\n * Skips node_modules, .next, dist, etc.\n */\nfunction findFilesShallow(dir: string, namePattern: RegExp, maxDepth = 3): string[] {\n const results: string[] = [];\n if (!existsSync(dir)) return results;\n\n function walk(currentDir: string, depth: number) {\n if (depth > maxDepth) return;\n try {\n const dirents = readdirSync(currentDir, { withFileTypes: true });\n for (const dirent of dirents) {\n const fullPath = join(currentDir, dirent.name);\n if (dirent.isDirectory()) {\n if (!SKIP_DIRS.has(dirent.name)) {\n walk(fullPath, depth + 1);\n }\n } else if (dirent.isFile() && namePattern.test(dirent.name)) {\n results.push(fullPath);\n }\n }\n } catch {\n // Directory unreadable\n }\n }\n\n walk(dir, 0);\n return results;\n}\n\nfunction parseEnvFile(content: string): Record<string, string> {\n const result: Record<string, string> = {};\n for (const line of content.split('\\n')) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('#')) continue;\n const entry = trimmed.startsWith('export ') ? trimmed.slice(7) : trimmed;\n const eqIndex = entry.indexOf('=');\n if (eqIndex === -1) continue;\n const key = entry.slice(0, eqIndex).trim();\n let value = entry.slice(eqIndex + 1).trim();\n if ((value.startsWith('\"') && value.endsWith('\"')) || (value.startsWith(\"'\") && value.endsWith(\"'\"))) {\n value = value.slice(1, -1);\n }\n result[key] = value;\n }\n return result;\n}\n\n/** Load all env vars from .env and .env.local files */\nfunction loadProjectEnvRaw(installDir: string): Record<string, string> {\n const env: Record<string, string> = {};\n for (const file of ['.env', '.env.local']) {\n const content = readFileSafe(join(installDir, file));\n if (content) Object.assign(env, parseEnvFile(content));\n }\n return env;\n}\n\n// --- Check Context ---\n\ninterface CheckContext {\n framework: FrameworkInfo;\n environment: EnvironmentInfo;\n sdk: SdkInfo;\n installDir: string;\n}\n\n// --- Individual Checks ---\n\n/** Resolve the app directory root (app/ or src/app/) for Next.js */\nfunction resolveAppDir(installDir: string): string | null {\n const srcApp = join(installDir, 'src', 'app');\n if (existsSync(srcApp)) return srcApp;\n const app = join(installDir, 'app');\n if (existsSync(app)) return app;\n return null;\n}\n\nfunction checkSignoutGetHandler(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'Next.js') return [];\n const appDir = resolveAppDir(ctx.installDir);\n if (!appDir) return [];\n\n const routeFiles = findFilesShallow(appDir, /^route\\.(ts|tsx|js|jsx)$/);\n const signoutRoutes = routeFiles.filter((f) => /[/\\\\](sign-?out|logout)[/\\\\]/.test(f));\n\n const findings: AuthPatternFinding[] = [];\n const GET_EXPORT = /export\\s+(async\\s+)?function\\s+GET|export\\s+const\\s+GET/;\n\n for (const route of signoutRoutes) {\n if (fileContains(route, GET_EXPORT)) {\n findings.push({\n code: 'SIGNOUT_GET_HANDLER',\n severity: 'error',\n message: 'Signout/logout route uses GET handler — vulnerable to CSRF and prefetch-triggered logouts',\n filePath: relative(ctx.installDir, route),\n remediation:\n 'Convert to a POST server action. GET routes with side effects are vulnerable to CSRF and will be triggered by Next.js link prefetching.',\n docsUrl: 'https://workos.com/docs/authkit/sign-out',\n });\n }\n }\n return findings;\n}\n\nfunction checkSignoutLinkPrefetch(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'Next.js') return [];\n const appDir = resolveAppDir(ctx.installDir);\n if (!appDir) return [];\n\n const tsxFiles = findFilesShallow(appDir, /\\.(tsx|jsx)$/);\n // Match <Link>, <NextLink>, or other common aliases\n const LINK_PATTERN = /<(?:Next)?Link\\s[^>]*href\\s*=\\s*[\"'{`/]*(\\/sign-?out|\\/logout)/;\n\n const findings: AuthPatternFinding[] = [];\n for (const file of tsxFiles) {\n if (fileContains(file, LINK_PATTERN)) {\n findings.push({\n code: 'SIGNOUT_LINK_PREFETCH',\n severity: 'warning',\n message:\n 'Link component points to signout/logout — Next.js will prefetch this in production, potentially triggering logouts',\n filePath: relative(ctx.installDir, file),\n remediation:\n 'Use a <form> with a server action or <button> with onClick handler instead of <Link> for signout.',\n });\n }\n }\n return findings;\n}\n\nfunction checkMissingMiddleware(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'Next.js') return [];\n\n const middlewarePaths = [\n 'middleware.ts',\n 'middleware.js',\n 'proxy.ts',\n 'proxy.js',\n 'src/middleware.ts',\n 'src/middleware.js',\n 'src/proxy.ts',\n 'src/proxy.js',\n ].map((p) => join(ctx.installDir, p));\n\n if (findFile(middlewarePaths)) return [];\n\n return [\n {\n code: 'MISSING_MIDDLEWARE',\n severity: 'error',\n message: 'No middleware.ts or proxy.ts found — AuthKit session handling requires middleware',\n remediation: 'Create middleware.ts at the project root with authkitMiddleware() from @workos-inc/authkit-nextjs.',\n docsUrl: 'https://workos.com/docs/authkit/nextjs/middleware',\n },\n ];\n}\n\nfunction checkMiddlewareWrongLocation(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'Next.js') return [];\n\n const wrongPaths = ['app/middleware.ts', 'app/middleware.js', 'src/app/middleware.ts', 'src/app/middleware.js'].map(\n (p) => join(ctx.installDir, p),\n );\n\n const found = findFile(wrongPaths);\n if (!found) return [];\n\n return [\n {\n code: 'MIDDLEWARE_WRONG_LOCATION',\n severity: 'warning',\n message: 'middleware.ts found inside app/ directory — must be at project root or src/',\n filePath: relative(ctx.installDir, found),\n remediation: 'Move middleware.ts to the project root (or src/ if using src/ directory).',\n docsUrl: 'https://workos.com/docs/authkit/nextjs/middleware',\n },\n ];\n}\n\nfunction checkMissingAuthKitProvider(ctx: CheckContext): AuthPatternFinding[] {\n const layoutPaths: string[] = [];\n\n if (ctx.framework.name === 'Next.js') {\n layoutPaths.push(\n join(ctx.installDir, 'app', 'layout.tsx'),\n join(ctx.installDir, 'app', 'layout.jsx'),\n join(ctx.installDir, 'src', 'app', 'layout.tsx'),\n join(ctx.installDir, 'src', 'app', 'layout.jsx'),\n );\n } else if (ctx.framework.name === 'React Router' && ctx.framework.variant === 'declarative') {\n layoutPaths.push(\n join(ctx.installDir, 'src', 'App.tsx'),\n join(ctx.installDir, 'src', 'App.jsx'),\n join(ctx.installDir, 'app', 'root.tsx'),\n join(ctx.installDir, 'app', 'root.jsx'),\n );\n } else {\n return [];\n }\n\n const layoutFile = findFile(layoutPaths);\n if (!layoutFile) return []; // Can't check if layout doesn't exist\n\n if (fileContains(layoutFile, /AuthKitProvider/)) return [];\n\n return [\n {\n code: 'MISSING_AUTHKIT_PROVIDER',\n severity: 'warning',\n message: 'AuthKitProvider not found in root layout — required for AuthKit session management',\n filePath: relative(ctx.installDir, layoutFile),\n remediation: 'Wrap your app with <AuthKitProvider> in the root layout.',\n docsUrl: 'https://workos.com/docs/authkit/nextjs/setup',\n },\n ];\n}\n\n/** Extract callback path from redirect URI env vars or framework default */\nfunction resolveCallbackPath(ctx: CheckContext): string | null {\n // Check env vars for actual redirect URI (including NEXT_PUBLIC_ variant)\n const projectEnv = loadProjectEnvRaw(ctx.installDir);\n const redirectUri =\n projectEnv.WORKOS_REDIRECT_URI ?? projectEnv.NEXT_PUBLIC_WORKOS_REDIRECT_URI ?? ctx.environment.redirectUri;\n\n if (redirectUri) {\n try {\n return new URL(redirectUri).pathname;\n } catch {\n // Invalid URL, fall through to framework default\n }\n }\n\n return ctx.framework.expectedCallbackPath ?? null;\n}\n\nfunction checkCallbackRouteMissing(ctx: CheckContext): AuthPatternFinding[] {\n const callbackPath = resolveCallbackPath(ctx);\n if (!callbackPath) return [];\n\n // Build expected route file paths based on framework\n const possiblePaths: string[] = [];\n\n if (ctx.framework.name === 'Next.js') {\n // app/auth/callback/route.ts (or src/app/)\n const routeDir = callbackPath.replace(/^\\//, ''); // 'auth/callback'\n for (const prefix of ['app', 'src/app']) {\n for (const ext of ['ts', 'tsx', 'js', 'jsx']) {\n possiblePaths.push(join(ctx.installDir, prefix, routeDir, `route.${ext}`));\n }\n }\n } else if (ctx.framework.name === 'React Router') {\n // Flat: app/routes/auth.callback.tsx Nested: app/routes/auth/callback.tsx\n const segments = callbackPath.replace(/^\\//, '').split('/');\n const flat = segments.join('.');\n const nested = segments.join('/');\n for (const ext of ['tsx', 'jsx', 'ts', 'js']) {\n possiblePaths.push(join(ctx.installDir, 'app', 'routes', `${flat}.${ext}`));\n possiblePaths.push(join(ctx.installDir, 'app', 'routes', nested + `.${ext}`));\n }\n } else if (ctx.framework.name === 'TanStack Start') {\n // Flat: routes/api.auth.callback.tsx Nested: routes/api/auth/callback.tsx\n // Both conventions work in both src/ and app/ directories\n const segments = callbackPath.replace(/^\\//, '').split('/');\n const flat = segments.join('.');\n const nested = segments.join('/');\n for (const prefix of ['src', 'app']) {\n for (const ext of ['tsx', 'jsx', 'ts', 'js']) {\n possiblePaths.push(join(ctx.installDir, prefix, 'routes', `${flat}.${ext}`));\n possiblePaths.push(join(ctx.installDir, prefix, 'routes', nested + `.${ext}`));\n }\n }\n }\n\n if (possiblePaths.length === 0) return [];\n if (findFile(possiblePaths)) return [];\n\n return [\n {\n code: 'CALLBACK_ROUTE_MISSING',\n severity: 'error',\n message: `No callback route found at expected path ${callbackPath}`,\n remediation: `Create the callback route handler at the path matching your WORKOS_REDIRECT_URI.`,\n docsUrl: 'https://workos.com/docs/authkit/redirect-uri',\n },\n ];\n}\n\nconst CLIENT_ENV_PREFIXES = ['NEXT_PUBLIC_', 'VITE_', 'REACT_APP_', 'EXPO_PUBLIC_'];\n\nfunction checkApiKeyLeakedToClient(ctx: CheckContext): AuthPatternFinding[] {\n const projectEnv = loadProjectEnvRaw(ctx.installDir);\n const findings: AuthPatternFinding[] = [];\n\n for (const [key, value] of Object.entries(projectEnv)) {\n const hasClientPrefix = CLIENT_ENV_PREFIXES.some((prefix) => key.startsWith(prefix));\n if (!hasClientPrefix) continue;\n\n const isApiKey = key.includes('WORKOS_API_KEY');\n const isSecretValue = value?.startsWith('sk_test_') || value?.startsWith('sk_live_');\n\n if (isApiKey || isSecretValue) {\n findings.push({\n code: 'API_KEY_LEAKED_TO_CLIENT',\n severity: 'error',\n message: `Secret API key exposed via client-accessible env var ${key}`,\n remediation: `Remove the client prefix. WORKOS_API_KEY must be server-only (no NEXT_PUBLIC_, VITE_, REACT_APP_, or EXPO_PUBLIC_ prefix).`,\n });\n }\n }\n return findings;\n}\n\nfunction checkWrongCallbackLoader(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'React Router') return [];\n const callbackPath = ctx.framework.expectedCallbackPath;\n if (!callbackPath) return [];\n\n const segments = callbackPath.replace(/^\\//, '').split('/');\n const flat = segments.join('.');\n const nested = segments.join('/');\n\n const possiblePaths: string[] = [];\n for (const ext of ['tsx', 'jsx', 'ts', 'js']) {\n possiblePaths.push(join(ctx.installDir, 'app', 'routes', `${flat}.${ext}`));\n possiblePaths.push(join(ctx.installDir, 'app', 'routes', nested + `.${ext}`));\n }\n\n const callbackFile = findFile(possiblePaths);\n if (!callbackFile) return []; // No callback route to check\n\n // authkitLoader is for regular routes; authLoader is for the callback\n if (fileContains(callbackFile, /authkitLoader/) && !fileContains(callbackFile, /authLoader/)) {\n return [\n {\n code: 'WRONG_CALLBACK_LOADER',\n severity: 'warning',\n message: 'Callback route uses authkitLoader instead of authLoader',\n filePath: relative(ctx.installDir, callbackFile),\n remediation:\n 'Use authLoader (not authkitLoader) for the callback route. authkitLoader is for regular routes that need auth context.',\n },\n ];\n }\n return [];\n}\n\nfunction checkMissingRootAuthLoader(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'React Router') return [];\n\n const rootPaths = ['app/root.tsx', 'app/root.jsx', 'app/routes/_index.tsx', 'app/routes/_index.jsx'].map((p) =>\n join(ctx.installDir, p),\n );\n\n const rootFile = findFile(rootPaths);\n if (!rootFile) return [];\n\n if (fileContains(rootFile, /authkitLoader/)) return [];\n\n return [\n {\n code: 'MISSING_ROOT_AUTH_LOADER',\n severity: 'warning',\n message: 'Root route does not use authkitLoader — child routes will not have auth context',\n filePath: relative(ctx.installDir, rootFile),\n remediation: 'Add authkitLoader to your root route so child routes can access auth state.',\n },\n ];\n}\n\nfunction checkMissingAuthkitMiddleware(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'TanStack Start') return [];\n\n const startPaths = ['src/start.ts', 'src/start.tsx', 'app/start.ts', 'app/start.tsx'].map((p) =>\n join(ctx.installDir, p),\n );\n\n const startFile = findFile(startPaths);\n if (!startFile) return []; // Can't check if start file doesn't exist\n\n if (fileContains(startFile, /authkitMiddleware/)) return [];\n\n return [\n {\n code: 'MISSING_AUTHKIT_MIDDLEWARE',\n severity: 'warning',\n message: 'start.ts does not reference authkitMiddleware — AuthKit session handling requires it',\n filePath: relative(ctx.installDir, startFile),\n remediation:\n 'Add authkitMiddleware to requestMiddleware in src/start.ts:\\n' +\n ' import { authkitMiddleware } from \"@workos/authkit-tanstack-react-start\";\\n' +\n ' export default createStart({ requestMiddleware: [authkitMiddleware()] });',\n },\n ];\n}\n\nfunction checkCookiePasswordTooShort(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'React Router' && ctx.framework.name !== 'TanStack Start') return [];\n\n const projectEnv = loadProjectEnvRaw(ctx.installDir);\n const password = projectEnv.WORKOS_COOKIE_PASSWORD;\n\n // Only warn if password is set but too short; missing password is a separate concern\n if (!password || password.length >= 32) return [];\n\n return [\n {\n code: 'COOKIE_PASSWORD_TOO_SHORT',\n severity: 'warning',\n message: `WORKOS_COOKIE_PASSWORD is ${password.length} characters — minimum 32 required for secure encryption`,\n remediation: 'Set WORKOS_COOKIE_PASSWORD to a random string of at least 32 characters.',\n },\n ];\n}\n\nconst REACT_SPA_SDKS = new Set(['@workos-inc/authkit-react']);\n\nfunction checkMissingApiHostname(ctx: CheckContext): AuthPatternFinding[] {\n if (!ctx.sdk.name || !REACT_SPA_SDKS.has(ctx.sdk.name)) return [];\n\n const sourceFiles = findFilesShallow(ctx.installDir, /\\.(tsx|jsx|ts|js)$/, 4);\n const providerFiles = sourceFiles.filter((f) => fileContains(f, /AuthKitProvider/));\n if (providerFiles.length === 0) return [];\n\n const hasApiHostname = providerFiles.some((f) => fileContains(f, /apiHostname/));\n if (hasApiHostname) return [];\n\n return [\n {\n code: 'MISSING_API_HOSTNAME',\n severity: 'warning',\n message: 'AuthKitProvider does not specify apiHostname — authorize requests will route through api.workos.com',\n filePath: relative(ctx.installDir, providerFiles[0]),\n remediation:\n 'Set the apiHostname prop on AuthKitProvider to your custom Authentication API domain (e.g. auth.example.com) to avoid routing through api.workos.com.',\n docsUrl: 'https://workos.com/docs/custom-domains',\n },\n ];\n}\n\n// --- Cross-language checks (run for ALL projects, not just JS/AuthKit) ---\n\nconst SOURCE_EXTENSIONS = /\\.(ts|tsx|js|jsx|py|rb|go|java|kt|php|cs|swift|dart)$/;\nconst SECRET_SOURCE_IGNORED_SEGMENTS = new Set(['__fixtures__', '__tests__', 'evals', 'fixtures', 'test', 'tests']);\n\nfunction isIgnoredSecretSourcePath(relativePath: string): boolean {\n const normalized = relativePath.replace(/\\\\/g, '/');\n const parts = normalized.split('/');\n if (parts.some((part) => SECRET_SOURCE_IGNORED_SEGMENTS.has(part))) return true;\n return /\\.(spec|test)\\.[^.]+$/.test(normalized);\n}\n\nfunction checkApiKeyInSource(ctx: CheckContext): AuthPatternFinding[] {\n const API_KEY_PATTERN = /sk_(test|live)_[A-Za-z0-9]{10,}/;\n const sourceFiles = findFilesShallow(ctx.installDir, SOURCE_EXTENSIONS, 4);\n const findings: AuthPatternFinding[] = [];\n\n for (const file of sourceFiles) {\n const relativePath = relative(ctx.installDir, file);\n if (isIgnoredSecretSourcePath(relativePath)) continue;\n const content = readFileSafe(file);\n if (!content) continue;\n if (API_KEY_PATTERN.test(content)) {\n findings.push({\n code: 'API_KEY_IN_SOURCE',\n severity: 'error',\n message: `WorkOS API key hardcoded in source file`,\n filePath: relativePath,\n remediation:\n 'Move the API key to an environment variable (WORKOS_API_KEY) and load it from .env or your secret manager.',\n });\n }\n }\n return findings;\n}\n\nfunction checkEnvFileNotGitignored(ctx: CheckContext): AuthPatternFinding[] {\n const envFiles = ['.env', '.env.local'].filter((f) => existsSync(join(ctx.installDir, f)));\n if (envFiles.length === 0) return [];\n\n const gitignorePath = join(ctx.installDir, '.gitignore');\n const gitignore = readFileSafe(gitignorePath);\n\n const findings: AuthPatternFinding[] = [];\n for (const envFile of envFiles) {\n const isIgnored =\n gitignore !== null &&\n gitignore.split('\\n').some((line) => {\n const trimmed = line.trim();\n if (trimmed.startsWith('#') || trimmed === '') return false;\n return trimmed === envFile || trimmed === '.env*' || trimmed === '.env.*' || trimmed === '.env';\n });\n\n if (!isIgnored) {\n findings.push({\n code: 'ENV_FILE_NOT_GITIGNORED',\n severity: 'warning',\n message: `${envFile} is not in .gitignore — secrets may be committed to version control`,\n filePath: envFile,\n remediation: `Add ${envFile} to your .gitignore file.`,\n });\n }\n }\n return findings;\n}\n\nfunction checkMixedEnvironmentCredentials(ctx: CheckContext): AuthPatternFinding[] {\n const projectEnv = loadProjectEnvRaw(ctx.installDir);\n const apiKey = projectEnv.WORKOS_API_KEY;\n const redirectUri = projectEnv.WORKOS_REDIRECT_URI ?? projectEnv.NEXT_PUBLIC_WORKOS_REDIRECT_URI;\n\n if (!apiKey || !redirectUri) return [];\n\n const isTestKey = apiKey.startsWith('sk_test_');\n const isLiveKey = apiKey.startsWith('sk_live_');\n\n let isProductionUri = false;\n try {\n const url = new URL(redirectUri);\n isProductionUri = url.hostname !== 'localhost' && !url.hostname.startsWith('127.0.0.');\n } catch {\n return [];\n }\n\n if (isTestKey && isProductionUri) {\n return [\n {\n code: 'MIXED_ENVIRONMENT',\n severity: 'warning',\n message: 'Staging API key (sk_test_) used with a production redirect URI',\n remediation:\n 'Use sk_live_ API key for production redirect URIs, or change the redirect URI to localhost for staging.',\n },\n ];\n }\n\n if (isLiveKey && !isProductionUri) {\n return [\n {\n code: 'MIXED_ENVIRONMENT',\n severity: 'warning',\n message: 'Production API key (sk_live_) used with a localhost redirect URI',\n remediation:\n 'Use sk_test_ API key for localhost development, or update the redirect URI to your production domain.',\n },\n ];\n }\n\n return [];\n}\n\n// --- Main Entry Point ---\n\ntype CheckFn = (ctx: CheckContext) => AuthPatternFinding[];\n\nconst CROSS_FRAMEWORK_CHECKS: CheckFn[] = [\n checkApiKeyLeakedToClient,\n checkApiKeyInSource,\n checkEnvFileNotGitignored,\n checkMixedEnvironmentCredentials,\n checkMissingApiHostname,\n];\n\nconst NEXTJS_CHECKS: CheckFn[] = [\n checkSignoutGetHandler,\n checkSignoutLinkPrefetch,\n checkMissingMiddleware,\n checkMiddlewareWrongLocation,\n checkMissingAuthKitProvider,\n checkCallbackRouteMissing,\n];\n\nconst REACT_ROUTER_CHECKS: CheckFn[] = [\n checkWrongCallbackLoader,\n checkMissingRootAuthLoader,\n checkMissingAuthKitProvider,\n checkCallbackRouteMissing,\n checkCookiePasswordTooShort,\n];\n\nconst TANSTACK_CHECKS: CheckFn[] = [\n checkMissingAuthkitMiddleware,\n checkCallbackRouteMissing,\n checkCookiePasswordTooShort,\n];\n\nexport async function checkAuthPatterns(\n options: DoctorOptions,\n framework: FrameworkInfo,\n environment: EnvironmentInfo,\n sdk: SdkInfo,\n): Promise<AuthPatternInfo> {\n const ctx: CheckContext = {\n framework,\n environment,\n sdk,\n installDir: options.installDir,\n };\n\n const checks: CheckFn[] = [...CROSS_FRAMEWORK_CHECKS];\n\n switch (framework.name) {\n case 'Next.js':\n checks.push(...NEXTJS_CHECKS);\n break;\n case 'React Router':\n checks.push(...REACT_ROUTER_CHECKS);\n break;\n case 'TanStack Start':\n checks.push(...TANSTACK_CHECKS);\n break;\n }\n\n const findings: AuthPatternFinding[] = [];\n for (const check of checks) {\n findings.push(...check(ctx));\n }\n\n return {\n checksRun: checks.length,\n findings,\n };\n}\n"]}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { getInteractionMode } from '../../utils/interaction-mode.js';
|
|
2
|
+
import { runHostProbe } from '../../lib/host-probe.js';
|
|
3
|
+
const HOST_EXECUTION_WARNING = 'This may be a sandboxed run. Re-run the command on the host shell before trusting auth, config, or API failures.';
|
|
4
|
+
export async function checkHostExecution() {
|
|
5
|
+
const interactionMode = getInteractionMode();
|
|
6
|
+
if (interactionMode.mode === 'human') {
|
|
7
|
+
return {
|
|
8
|
+
mode: 'interactive',
|
|
9
|
+
ok: true,
|
|
10
|
+
failures: [],
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
const probe = await runHostProbe();
|
|
14
|
+
return {
|
|
15
|
+
mode: 'non-interactive',
|
|
16
|
+
ok: probe.ok,
|
|
17
|
+
failures: probe.failures,
|
|
18
|
+
warning: probe.ok ? undefined : HOST_EXECUTION_WARNING,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=host-execution.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"host-execution.js","sourceRoot":"","sources":["../../../src/doctor/checks/host-execution.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AACrE,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAGvD,MAAM,sBAAsB,GAC1B,kHAAkH,CAAC;AAErH,MAAM,CAAC,KAAK,UAAU,kBAAkB;IACtC,MAAM,eAAe,GAAG,kBAAkB,EAAE,CAAC;IAE7C,IAAI,eAAe,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;QACrC,OAAO;YACL,IAAI,EAAE,aAAa;YACnB,EAAE,EAAE,IAAI;YACR,QAAQ,EAAE,EAAE;SACb,CAAC;IACJ,CAAC;IAED,MAAM,KAAK,GAAG,MAAM,YAAY,EAAE,CAAC;IACnC,OAAO;QACL,IAAI,EAAE,iBAAiB;QACvB,EAAE,EAAE,KAAK,CAAC,EAAE;QACZ,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,OAAO,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,sBAAsB;KACvD,CAAC;AACJ,CAAC","sourcesContent":["import { getInteractionMode } from '../../utils/interaction-mode.js';\nimport { runHostProbe } from '../../lib/host-probe.js';\nimport type { HostExecutionInfo } from '../types.js';\n\nconst HOST_EXECUTION_WARNING =\n 'This may be a sandboxed run. Re-run the command on the host shell before trusting auth, config, or API failures.';\n\nexport async function checkHostExecution(): Promise<HostExecutionInfo> {\n const interactionMode = getInteractionMode();\n\n if (interactionMode.mode === 'human') {\n return {\n mode: 'interactive',\n ok: true,\n failures: [],\n };\n }\n\n const probe = await runHostProbe();\n return {\n mode: 'non-interactive',\n ok: probe.ok,\n failures: probe.failures,\n warning: probe.ok ? undefined : HOST_EXECUTION_WARNING,\n };\n}\n"]}
|
package/dist/doctor/index.js
CHANGED
|
@@ -4,6 +4,7 @@ import { checkRuntime } from './checks/runtime.js';
|
|
|
4
4
|
import { checkLanguage } from './checks/language.js';
|
|
5
5
|
import { checkEnvironment } from './checks/environment.js';
|
|
6
6
|
import { checkConnectivity } from './checks/connectivity.js';
|
|
7
|
+
import { checkHostExecution } from './checks/host-execution.js';
|
|
7
8
|
import { checkDashboardSettings, compareRedirectUris } from './checks/dashboard.js';
|
|
8
9
|
import { checkAuthPatterns } from './checks/auth-patterns.js';
|
|
9
10
|
import { checkAiAnalysis } from './checks/ai-analysis.js';
|
|
@@ -13,6 +14,7 @@ import { detectIssues } from './issues.js';
|
|
|
13
14
|
import { formatReport } from './output.js';
|
|
14
15
|
import { formatReportAsJson } from './json-output.js';
|
|
15
16
|
import { copyToClipboard } from './clipboard.js';
|
|
17
|
+
import { getInteractionMode } from '../utils/interaction-mode.js';
|
|
16
18
|
import Chalk from 'chalk';
|
|
17
19
|
const DOCTOR_VERSION = '1.0.0';
|
|
18
20
|
/**
|
|
@@ -54,16 +56,18 @@ export async function maybeRefreshSkills(options, skills) {
|
|
|
54
56
|
};
|
|
55
57
|
}
|
|
56
58
|
export async function runDoctor(options) {
|
|
59
|
+
const interactionMode = getInteractionMode();
|
|
57
60
|
// Environment check first - loads project's .env/.env.local files
|
|
58
61
|
// Must run before connectivity so the resolved base URL is available
|
|
59
62
|
const { info: environment, raw: envRaw } = checkEnvironment(options);
|
|
60
63
|
// Run remaining checks concurrently
|
|
61
|
-
const [sdk, framework, runtime, connectivity, language] = await Promise.all([
|
|
64
|
+
const [sdk, framework, runtime, connectivity, language, hostExecution] = await Promise.all([
|
|
62
65
|
checkSdk(options),
|
|
63
66
|
checkFramework(options),
|
|
64
67
|
checkRuntime(options),
|
|
65
68
|
checkConnectivity(options, environment.baseUrl ?? 'https://api.workos.com'),
|
|
66
69
|
checkLanguage(options.installDir),
|
|
70
|
+
checkHostExecution(),
|
|
67
71
|
]);
|
|
68
72
|
let skills = (await checkSkills()) ?? undefined;
|
|
69
73
|
// `--fix`: refresh stale WorkOS skills BEFORE earlyIssues + AI analysis so
|
|
@@ -78,12 +82,14 @@ export async function runDoctor(options) {
|
|
|
78
82
|
const earlyIssues = detectIssues({
|
|
79
83
|
version: DOCTOR_VERSION,
|
|
80
84
|
timestamp: '',
|
|
85
|
+
interactionMode,
|
|
81
86
|
project: { path: options.installDir, packageManager: runtime.packageManager },
|
|
82
87
|
sdk,
|
|
83
88
|
language,
|
|
84
89
|
runtime,
|
|
85
90
|
framework,
|
|
86
91
|
environment,
|
|
92
|
+
hostExecution,
|
|
87
93
|
connectivity,
|
|
88
94
|
skills,
|
|
89
95
|
});
|
|
@@ -106,6 +112,7 @@ export async function runDoctor(options) {
|
|
|
106
112
|
const partialReport = {
|
|
107
113
|
version: DOCTOR_VERSION,
|
|
108
114
|
timestamp: new Date().toISOString(),
|
|
115
|
+
interactionMode,
|
|
109
116
|
project: {
|
|
110
117
|
path: options.installDir,
|
|
111
118
|
packageManager: runtime.packageManager,
|
|
@@ -115,6 +122,7 @@ export async function runDoctor(options) {
|
|
|
115
122
|
runtime,
|
|
116
123
|
framework,
|
|
117
124
|
environment,
|
|
125
|
+
hostExecution,
|
|
118
126
|
connectivity,
|
|
119
127
|
credentialValidation: dashboardResult.credentialValidation,
|
|
120
128
|
dashboardSettings: dashboardResult.settings ?? undefined,
|
package/dist/doctor/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/doctor/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { checkSdk } from './checks/sdk.js';\nimport { checkFramework } from './checks/framework.js';\nimport { checkRuntime } from './checks/runtime.js';\nimport { checkLanguage } from './checks/language.js';\nimport { checkEnvironment } from './checks/environment.js';\nimport { checkConnectivity } from './checks/connectivity.js';\nimport { checkDashboardSettings, compareRedirectUris } from './checks/dashboard.js';\nimport { checkAuthPatterns } from './checks/auth-patterns.js';\nimport { checkAiAnalysis } from './checks/ai-analysis.js';\nimport { checkSkills } from './checks/skills.js';\nimport { refreshWorkOSSkills } from '../commands/install-skill.js';\nimport { detectIssues } from './issues.js';\nimport { formatReport } from './output.js';\nimport { formatReportAsJson } from './json-output.js';\nimport { copyToClipboard } from './clipboard.js';\nimport Chalk from 'chalk';\nimport type { DoctorOptions, DoctorReport, SkillsRefreshResult } from './types.js';\n\nconst DOCTOR_VERSION = '1.0.0';\n\n/**\n * Skills `--fix` is allowed to refresh. Hardcoded — NOT derived from\n * discoverSkills — so future bundled skills require an explicit opt-in here\n * before doctor will write to their target directory. This is the contract's\n * promise that `--fix` only ever touches `workos/` and `workos-widgets/`.\n */\nexport const FIXABLE_SKILLS = ['workos', 'workos-widgets'] as const;\n\n/**\n * Refresh stale WorkOS skills if `--fix` is set and at least one agent is\n * stale or has no marker. Always re-reads `checkSkills()` after a successful\n * refresh so detectIssues sees the post-refresh state and we don't ship a\n * doctor report that simultaneously claims \"fixed\" and \"still stale\".\n *\n * Extracted from runDoctor for unit testability — runDoctor itself depends on\n * eight upstream checks that are expensive to mock.\n */\nexport async function maybeRefreshSkills(\n options: Pick<DoctorOptions, 'fix'>,\n skills: DoctorReport['skills'],\n): Promise<{\n skillsRefresh?: SkillsRefreshResult;\n skills: DoctorReport['skills'];\n}> {\n if (!options.fix || !skills) return { skills };\n\n const stalePresent = skills.agents.some((a) => a.stale || a.installedVersion === null);\n if (!stalePresent) return { skills };\n\n const refresh = await refreshWorkOSSkills({\n // Explicit allowlist — NOT discoverSkills — so the contract's\n // workos/+workos-widgets-only constraint can't drift.\n skills: [...FIXABLE_SKILLS],\n });\n if (!refresh) return { skills };\n\n return {\n skillsRefresh: {\n before: refresh.perAgentBefore,\n after: refresh.perAgentAfter,\n skillsInstalled: refresh.skills,\n },\n skills: (await checkSkills()) ?? undefined,\n };\n}\n\nexport async function runDoctor(options: DoctorOptions): Promise<DoctorReport> {\n // Environment check first - loads project's .env/.env.local files\n // Must run before connectivity so the resolved base URL is available\n const { info: environment, raw: envRaw } = checkEnvironment(options);\n\n // Run remaining checks concurrently\n const [sdk, framework, runtime, connectivity, language] = await Promise.all([\n checkSdk(options),\n checkFramework(options),\n checkRuntime(options),\n checkConnectivity(options, environment.baseUrl ?? 'https://api.workos.com'),\n checkLanguage(options.installDir),\n ]);\n\n let skills = (await checkSkills()) ?? undefined;\n\n // `--fix`: refresh stale WorkOS skills BEFORE earlyIssues + AI analysis so\n // every downstream consumer (issue detection, AI prompt context) sees the\n // post-refresh skill state and doesn't reference a SKILLS_OUTDATED warning\n // that was just resolved.\n const refreshOutcome = await maybeRefreshSkills(options, skills);\n const skillsRefresh = refreshOutcome.skillsRefresh;\n skills = refreshOutcome.skills;\n\n // Dashboard settings + auth patterns + AI analysis (parallel, all need sdk/framework results)\n // AI analysis also receives early issues as context to avoid duplication\n const earlyIssues = detectIssues({\n version: DOCTOR_VERSION,\n timestamp: '',\n project: { path: options.installDir, packageManager: runtime.packageManager },\n sdk,\n language,\n runtime,\n framework,\n environment,\n connectivity,\n skills,\n });\n\n const [dashboardResult, authPatterns, aiAnalysis] = await Promise.all([\n checkDashboardSettings(options, environment.apiKeyType, envRaw),\n checkAuthPatterns(options, framework, environment, sdk),\n checkAiAnalysis(\n { installDir: options.installDir, language, framework, sdk, environment, existingIssues: earlyIssues },\n { skipAi: options.skipAi },\n ),\n ]);\n\n // Compute expected redirect URI from framework detection if not set in env\n const redirectUriSource: 'env' | 'inferred' = environment.redirectUri ? 'env' : 'inferred';\n const expectedRedirectUri =\n environment.redirectUri ??\n (framework.expectedCallbackPath && framework.detectedPort\n ? `http://localhost:${framework.detectedPort}${framework.expectedCallbackPath}`\n : null);\n\n // Compare redirect URIs if we have dashboard data\n const redirectUris = dashboardResult.settings\n ? compareRedirectUris(expectedRedirectUri, dashboardResult.settings.redirectUris, redirectUriSource)\n : undefined;\n\n // Build partial report\n const partialReport = {\n version: DOCTOR_VERSION,\n timestamp: new Date().toISOString(),\n project: {\n path: options.installDir,\n packageManager: runtime.packageManager,\n },\n sdk,\n language,\n runtime,\n framework,\n environment,\n connectivity,\n credentialValidation: dashboardResult.credentialValidation,\n dashboardSettings: dashboardResult.settings ?? undefined,\n dashboardError: dashboardResult.settings ? undefined : dashboardResult.error,\n redirectUris,\n authPatterns,\n aiAnalysis,\n skills,\n skillsRefresh,\n };\n\n // Detect issues based on (post-refresh) data.\n const issues = detectIssues(partialReport);\n\n // Calculate summary\n const errors = issues.filter((i) => i.severity === 'error').length;\n const warnings = issues.filter((i) => i.severity === 'warning').length;\n\n const report: DoctorReport = {\n ...partialReport,\n issues,\n summary: {\n errors,\n warnings,\n healthy: errors === 0,\n },\n };\n\n return report;\n}\n\nexport async function outputReport(report: DoctorReport, options: DoctorOptions): Promise<void> {\n if (options.json) {\n const json = formatReportAsJson(report);\n console.log(json);\n\n if (options.copy) {\n const success = await copyToClipboard(json);\n if (success) {\n console.error('(Copied to clipboard)');\n }\n }\n } else {\n formatReport(report, { verbose: options.verbose });\n\n if (options.copy) {\n const json = formatReportAsJson(report);\n const success = await copyToClipboard(json);\n if (success) {\n console.log(Chalk.dim('Report copied to clipboard'));\n }\n }\n }\n}\n\nexport { formatReport } from './output.js';\nexport { formatReportAsJson } from './json-output.js';\nexport type { DoctorReport, DoctorOptions } from './types.js';\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/doctor/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { checkSdk } from './checks/sdk.js';\nimport { checkFramework } from './checks/framework.js';\nimport { checkRuntime } from './checks/runtime.js';\nimport { checkLanguage } from './checks/language.js';\nimport { checkEnvironment } from './checks/environment.js';\nimport { checkConnectivity } from './checks/connectivity.js';\nimport { checkHostExecution } from './checks/host-execution.js';\nimport { checkDashboardSettings, compareRedirectUris } from './checks/dashboard.js';\nimport { checkAuthPatterns } from './checks/auth-patterns.js';\nimport { checkAiAnalysis } from './checks/ai-analysis.js';\nimport { checkSkills } from './checks/skills.js';\nimport { refreshWorkOSSkills } from '../commands/install-skill.js';\nimport { detectIssues } from './issues.js';\nimport { formatReport } from './output.js';\nimport { formatReportAsJson } from './json-output.js';\nimport { copyToClipboard } from './clipboard.js';\nimport { getInteractionMode } from '../utils/interaction-mode.js';\nimport Chalk from 'chalk';\nimport type { DoctorOptions, DoctorReport, SkillsRefreshResult } from './types.js';\n\nconst DOCTOR_VERSION = '1.0.0';\n\n/**\n * Skills `--fix` is allowed to refresh. Hardcoded — NOT derived from\n * discoverSkills — so future bundled skills require an explicit opt-in here\n * before doctor will write to their target directory. This is the contract's\n * promise that `--fix` only ever touches `workos/` and `workos-widgets/`.\n */\nexport const FIXABLE_SKILLS = ['workos', 'workos-widgets'] as const;\n\n/**\n * Refresh stale WorkOS skills if `--fix` is set and at least one agent is\n * stale or has no marker. Always re-reads `checkSkills()` after a successful\n * refresh so detectIssues sees the post-refresh state and we don't ship a\n * doctor report that simultaneously claims \"fixed\" and \"still stale\".\n *\n * Extracted from runDoctor for unit testability — runDoctor itself depends on\n * eight upstream checks that are expensive to mock.\n */\nexport async function maybeRefreshSkills(\n options: Pick<DoctorOptions, 'fix'>,\n skills: DoctorReport['skills'],\n): Promise<{\n skillsRefresh?: SkillsRefreshResult;\n skills: DoctorReport['skills'];\n}> {\n if (!options.fix || !skills) return { skills };\n\n const stalePresent = skills.agents.some((a) => a.stale || a.installedVersion === null);\n if (!stalePresent) return { skills };\n\n const refresh = await refreshWorkOSSkills({\n // Explicit allowlist — NOT discoverSkills — so the contract's\n // workos/+workos-widgets-only constraint can't drift.\n skills: [...FIXABLE_SKILLS],\n });\n if (!refresh) return { skills };\n\n return {\n skillsRefresh: {\n before: refresh.perAgentBefore,\n after: refresh.perAgentAfter,\n skillsInstalled: refresh.skills,\n },\n skills: (await checkSkills()) ?? undefined,\n };\n}\n\nexport async function runDoctor(options: DoctorOptions): Promise<DoctorReport> {\n const interactionMode = getInteractionMode();\n\n // Environment check first - loads project's .env/.env.local files\n // Must run before connectivity so the resolved base URL is available\n const { info: environment, raw: envRaw } = checkEnvironment(options);\n\n // Run remaining checks concurrently\n const [sdk, framework, runtime, connectivity, language, hostExecution] = await Promise.all([\n checkSdk(options),\n checkFramework(options),\n checkRuntime(options),\n checkConnectivity(options, environment.baseUrl ?? 'https://api.workos.com'),\n checkLanguage(options.installDir),\n checkHostExecution(),\n ]);\n\n let skills = (await checkSkills()) ?? undefined;\n\n // `--fix`: refresh stale WorkOS skills BEFORE earlyIssues + AI analysis so\n // every downstream consumer (issue detection, AI prompt context) sees the\n // post-refresh skill state and doesn't reference a SKILLS_OUTDATED warning\n // that was just resolved.\n const refreshOutcome = await maybeRefreshSkills(options, skills);\n const skillsRefresh = refreshOutcome.skillsRefresh;\n skills = refreshOutcome.skills;\n\n // Dashboard settings + auth patterns + AI analysis (parallel, all need sdk/framework results)\n // AI analysis also receives early issues as context to avoid duplication\n const earlyIssues = detectIssues({\n version: DOCTOR_VERSION,\n timestamp: '',\n interactionMode,\n project: { path: options.installDir, packageManager: runtime.packageManager },\n sdk,\n language,\n runtime,\n framework,\n environment,\n hostExecution,\n connectivity,\n skills,\n });\n\n const [dashboardResult, authPatterns, aiAnalysis] = await Promise.all([\n checkDashboardSettings(options, environment.apiKeyType, envRaw),\n checkAuthPatterns(options, framework, environment, sdk),\n checkAiAnalysis(\n { installDir: options.installDir, language, framework, sdk, environment, existingIssues: earlyIssues },\n { skipAi: options.skipAi },\n ),\n ]);\n\n // Compute expected redirect URI from framework detection if not set in env\n const redirectUriSource: 'env' | 'inferred' = environment.redirectUri ? 'env' : 'inferred';\n const expectedRedirectUri =\n environment.redirectUri ??\n (framework.expectedCallbackPath && framework.detectedPort\n ? `http://localhost:${framework.detectedPort}${framework.expectedCallbackPath}`\n : null);\n\n // Compare redirect URIs if we have dashboard data\n const redirectUris = dashboardResult.settings\n ? compareRedirectUris(expectedRedirectUri, dashboardResult.settings.redirectUris, redirectUriSource)\n : undefined;\n\n // Build partial report\n const partialReport = {\n version: DOCTOR_VERSION,\n timestamp: new Date().toISOString(),\n interactionMode,\n project: {\n path: options.installDir,\n packageManager: runtime.packageManager,\n },\n sdk,\n language,\n runtime,\n framework,\n environment,\n hostExecution,\n connectivity,\n credentialValidation: dashboardResult.credentialValidation,\n dashboardSettings: dashboardResult.settings ?? undefined,\n dashboardError: dashboardResult.settings ? undefined : dashboardResult.error,\n redirectUris,\n authPatterns,\n aiAnalysis,\n skills,\n skillsRefresh,\n };\n\n // Detect issues based on (post-refresh) data.\n const issues = detectIssues(partialReport);\n\n // Calculate summary\n const errors = issues.filter((i) => i.severity === 'error').length;\n const warnings = issues.filter((i) => i.severity === 'warning').length;\n\n const report: DoctorReport = {\n ...partialReport,\n issues,\n summary: {\n errors,\n warnings,\n healthy: errors === 0,\n },\n };\n\n return report;\n}\n\nexport async function outputReport(report: DoctorReport, options: DoctorOptions): Promise<void> {\n if (options.json) {\n const json = formatReportAsJson(report);\n console.log(json);\n\n if (options.copy) {\n const success = await copyToClipboard(json);\n if (success) {\n console.error('(Copied to clipboard)');\n }\n }\n } else {\n formatReport(report, { verbose: options.verbose });\n\n if (options.copy) {\n const json = formatReportAsJson(report);\n const success = await copyToClipboard(json);\n if (success) {\n console.log(Chalk.dim('Report copied to clipboard'));\n }\n }\n }\n}\n\nexport { formatReport } from './output.js';\nexport { formatReportAsJson } from './json-output.js';\nexport type { DoctorReport, DoctorOptions } from './types.js';\n"]}
|
package/dist/doctor/issues.d.ts
CHANGED
|
@@ -54,5 +54,10 @@ export declare const ISSUE_DEFINITIONS: {
|
|
|
54
54
|
remediation: string;
|
|
55
55
|
docsUrl: string;
|
|
56
56
|
};
|
|
57
|
+
HOST_EXECUTION_UNTRUSTED: {
|
|
58
|
+
severity: "warning";
|
|
59
|
+
message: string;
|
|
60
|
+
remediation: string;
|
|
61
|
+
};
|
|
57
62
|
};
|
|
58
63
|
export declare function detectIssues(report: Omit<DoctorReport, 'issues' | 'summary'>): Issue[];
|
package/dist/doctor/issues.js
CHANGED
|
@@ -56,6 +56,11 @@ export const ISSUE_DEFINITIONS = {
|
|
|
56
56
|
remediation: 'Ensure WORKOS_CLIENT_ID matches the environment for your API key',
|
|
57
57
|
docsUrl: 'https://dashboard.workos.com/configuration',
|
|
58
58
|
},
|
|
59
|
+
HOST_EXECUTION_UNTRUSTED: {
|
|
60
|
+
severity: 'warning',
|
|
61
|
+
message: 'Host-only WorkOS state may be unavailable in this shell',
|
|
62
|
+
remediation: 'Agent/CI host execution is untrusted. Re-run this command on the host shell before trusting auth, config, or API failures.',
|
|
63
|
+
},
|
|
59
64
|
};
|
|
60
65
|
export function detectIssues(report) {
|
|
61
66
|
const issues = [];
|
|
@@ -90,6 +95,13 @@ export function detectIssues(report) {
|
|
|
90
95
|
if (report.sdk.isAuthKit && !report.environment.cookieDomain) {
|
|
91
96
|
issues.push({ code: 'COOKIE_DOMAIN_NOT_SET', ...ISSUE_DEFINITIONS.COOKIE_DOMAIN_NOT_SET });
|
|
92
97
|
}
|
|
98
|
+
if (!report.hostExecution.ok) {
|
|
99
|
+
issues.push({
|
|
100
|
+
code: 'HOST_EXECUTION_UNTRUSTED',
|
|
101
|
+
...ISSUE_DEFINITIONS.HOST_EXECUTION_UNTRUSTED,
|
|
102
|
+
details: { failures: report.hostExecution.failures },
|
|
103
|
+
});
|
|
104
|
+
}
|
|
93
105
|
// Connectivity issues
|
|
94
106
|
if (!report.connectivity.apiReachable && !report.connectivity.error?.includes('Skipped')) {
|
|
95
107
|
issues.push({
|