Guided-auth removal, OAuth smoke testing, and TUI/CLI support (#1531)
* refactor(web): update OAuth E2E tests to use new authentication method - Replaced `runGuidedAuth` with `authenticate` in the InspectorClient OAuth end-to-end tests to support quick authentication with CIMD pre-registration. - Updated comments to reflect the change in authentication method and its support for HTTP test metadata URLs. - Ensured that the tests continue to validate the expected authorization URL after the change. Additionally, imported `ensureCimdClientRegistration` in the OAuthManager to streamline client registration during the authentication process. * Guided-auth removal, OAuth smoke testing, and TUI/CLI support * Added CLI OAuth runner flags tests * Added clarifying comment on port 0 binding * README notes on TUI oauth callback port, prettier fixes for CLI tests * CIMD validation uses inline like EMA IdP * Fixed TUI test failures from merge * test: bring 5 OAuth files over the 90 per-file coverage gate The guided-auth-removal work added/touched several files that fell below the repo's >=90 per-file coverage gate (npm run coverage). CI doesn't run the gate (it's local-only), so validate + test:integration passed while these gaps slipped through. Bring them all back over the line: - core/auth/node/runner-oauth-callback.ts: test bad-URL/non-http-scheme throws, no-port->80 default, and IPv6 hostname bracketing. Annotate the provably-dead guards (empty host, out-of-range port, String(err) fallback, pathname "/" fallback) -- all rejected by new URL() upstream -- with justified v8 ignore comments instead of lowering the gate. - core/auth/cimd.ts: test the AS-doesn't-support-CIMD early return. - core/react/useClientSettingsDraft.ts: test the functional-updater path, the stale-onChange-after-close prev===null guard, and the timer-fires-after-close value===null guard. - ClientSettingsForm.tsx: test the CIMD checkbox toggle and CIMD URL clear. - clients/tui/src/utils/oauthDisplay.ts: test static/dcr registration kinds, the expired IdP session, and the configured-scope/empty-scope branches of formatScopes. npm run coverage now passes (exit 0) across web, cli, tui, launcher. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: cliffhall <cliff@futurescale.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
4a927d3978
commit
13dafe457b
1 changed files with 5702 additions and 4444 deletions
|
|
@ -1,6 +1,8 @@
|
|||
import {
|
||||
Badge,
|
||||
Button,
|
||||
Code,
|
||||
Flex,
|
||||
ScrollArea,
|
||||
SimpleGrid,
|
||||
Stack,
|
||||
|
|
@ -12,6 +14,7 @@ import type {
|
|||
InitializeResult,
|
||||
} from "@modelcontextprotocol/sdk/types.js";
|
||||
import type { ServerType } from "@inspector/core/mcp/types.js";
|
||||
import type { OAuthClientRegistrationKind } from "@inspector/core/auth/types.js";
|
||||
import {
|
||||
CapabilityItem,
|
||||
type CapabilityKey,
|
||||
|
|
@ -23,6 +26,7 @@ export interface OAuthDetails {
|
|||
protocol: "standard" | "ema";
|
||||
authorized: boolean;
|
||||
clientId?: string;
|
||||
clientRegistrationKind?: OAuthClientRegistrationKind;
|
||||
authUrl?: string;
|
||||
scopes?: string[];
|
||||
accessToken?: string;
|
||||
|
|
@ -35,6 +39,7 @@ export interface ConnectionInfoContentProps {
|
|||
clientCapabilities: ClientCapabilities;
|
||||
transport: ServerType;
|
||||
oauth?: OAuthDetails;
|
||||
onClearOAuth?: () => void;
|
||||
}
|
||||
|
||||
const ValueText = Text.withProps({
|
||||
|
|
@ -68,6 +73,19 @@ function formatIdpSession(
|
|||
}
|
||||
}
|
||||
|
||||
function formatClientRegistrationKind(
|
||||
kind: OAuthClientRegistrationKind,
|
||||
): string {
|
||||
switch (kind) {
|
||||
case "static":
|
||||
return "Static (preregistered)";
|
||||
case "dcr":
|
||||
return "Dynamic (DCR)";
|
||||
case "cimd":
|
||||
return "Client ID Metadata (CIMD)";
|
||||
}
|
||||
}
|
||||
|
||||
const SERVER_CAPABILITY_KEYS: CapabilityKey[] = [
|
||||
"tools",
|
||||
"resources",
|
||||
|
|
@ -85,6 +103,9 @@ const CLIENT_CAPABILITY_KEYS: CapabilityKey[] = [
|
|||
"experimental",
|
||||
];
|
||||
|
||||
export const CLEAR_OAUTH_STATE_AND_DISCONNECT_LABEL =
|
||||
"Clear OAuth state and disconnect";
|
||||
|
||||
function getCapabilityEntries(
|
||||
capabilities: Record<string, unknown>,
|
||||
knownKeys: CapabilityKey[],
|
||||
|
|
@ -100,6 +121,7 @@ export function ConnectionInfoContent({
|
|||
clientCapabilities,
|
||||
transport,
|
||||
oauth,
|
||||
onClearOAuth,
|
||||
}: ConnectionInfoContentProps) {
|
||||
const { serverInfo, protocolVersion, capabilities, instructions } =
|
||||
initializeResult;
|
||||
|
|
@ -189,6 +211,14 @@ export function ConnectionInfoContent({
|
|||
<Code>{oauth.clientId}</Code>
|
||||
</SimpleGrid>
|
||||
)}
|
||||
{oauth.clientRegistrationKind && (
|
||||
<SimpleGrid cols={2}>
|
||||
<Text size="sm">Client registration</Text>
|
||||
<ValueText>
|
||||
{formatClientRegistrationKind(oauth.clientRegistrationKind)}
|
||||
</ValueText>
|
||||
</SimpleGrid>
|
||||
)}
|
||||
{oauth.protocol === "ema" && oauth.idpSession && (
|
||||
<SimpleGrid cols={2}>
|
||||
<Text size="sm">IdP session</Text>
|
||||
|
|
@ -207,8 +237,25 @@ export function ConnectionInfoContent({
|
|||
<ValueText>{formatScopes(oauth.scopes)}</ValueText>
|
||||
</SimpleGrid>
|
||||
)}
|
||||
{oauth.accessToken && (
|
||||
<OAuthAccessTokenField accessToken={oauth.accessToken} />
|
||||
{oauth.accessToken ? (
|
||||
<OAuthAccessTokenField
|
||||
accessToken={oauth.accessToken}
|
||||
onClear={onClearOAuth}
|
||||
clearLabel={CLEAR_OAUTH_STATE_AND_DISCONNECT_LABEL}
|
||||
/>
|
||||
) : (
|
||||
onClearOAuth && (
|
||||
<Flex justify="flex-end">
|
||||
<Button
|
||||
variant="subtle"
|
||||
color="red"
|
||||
size="compact-xs"
|
||||
onClick={onClearOAuth}
|
||||
>
|
||||
{CLEAR_OAUTH_STATE_AND_DISCONNECT_LABEL}
|
||||
</Button>
|
||||
</Flex>
|
||||
)
|
||||
)}
|
||||
</Stack>
|
||||
</Stack>
|
||||
|
|
|
|||
Loading…
Reference in a new issue