From f3b0d42742d99d73099b6dde873879473c33e2ad Mon Sep 17 00:00:00 2001 From: "@daniel-lxs" <57051444+daniel-lxs@users.noreply.github.com> Date: Mon, 7 Sep 2026 00:48:56 +0000 Subject: [PATCH] fix: warn about whitespace-only doctor auth credentials --- apps/dev/src/__tests__/doctor.test.ts | 34 +++++++++++++++++++++++++++ apps/dev/src/doctor.ts | 2 +- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/apps/dev/src/__tests__/doctor.test.ts b/apps/dev/src/__tests__/doctor.test.ts index 806680ff5..af4a3b436 100644 --- a/apps/dev/src/__tests__/doctor.test.ts +++ b/apps/dev/src/__tests__/doctor.test.ts @@ -640,6 +640,40 @@ describe('runDoctor', () => { ); }); + it.each([ + 'R_SLACK_CLIENT_ID', + 'R_SLACK_CLIENT_SECRET', + 'R_MICROSOFT_CLIENT_ID', + 'R_MICROSOFT_CLIENT_SECRET', + 'R_MICROSOFT_TENANT_ID', + ])('warns when %s contains only whitespace', async (key) => { + const isSlack = key.startsWith('R_SLACK_'); + mockExeca({ + includeDefaultAuth: false, + extraWebEnv: { + ...(isSlack + ? { + R_SLACK_CLIENT_ID: 'slack-client-id', + R_SLACK_CLIENT_SECRET: 'slack-client-secret', + } + : { + R_MICROSOFT_CLIENT_ID: 'microsoft-client-id', + R_MICROSOFT_CLIENT_SECRET: 'microsoft-client-secret', + R_MICROSOFT_TENANT_ID: 'microsoft-tenant-id', + }), + [key]: ' \t\n ', + }, + }); + + expect(await runDoctor()).toContainEqual({ + name: 'Auth providers', + status: 'warn', + detail: isSlack + ? 'incomplete Slack client ID/secret pair' + : 'incomplete Microsoft Teams client ID/secret/tenant set', + }); + }); + it('fails when an HTTP health endpoint returns a non-2xx response', async () => { mockFetch(503); diff --git a/apps/dev/src/doctor.ts b/apps/dev/src/doctor.ts index 1a106bf9b..f47d4bf6e 100644 --- a/apps/dev/src/doctor.ts +++ b/apps/dev/src/doctor.ts @@ -467,7 +467,7 @@ function checkAuthProviders( const configuredProviders: string[] = []; const incompleteProviders: string[] = []; const configEnv = Object.keys(env).length > 0 ? env : process.env; - const hasValue = (key: string) => Boolean(configEnv[key]); + const hasValue = (key: string) => Boolean(configEnv[key]?.trim()); const checkProvider = ({ name, requiredKeyGroups,