From 04493ba9339e68ceaa22917e8f14452ae9680162 Mon Sep 17 00:00:00 2001 From: adamsosterics Date: Fri, 29 Aug 2025 17:09:50 +0200 Subject: [PATCH] feat: show sets of required scopes correctly It is possible to define alternative required scopes for an operation and in the security header of the operation it is rendered correctly. However, in the "Required scopes" part it looks like that all these scopes are required. With these changes, the "Required scopes" part shows the required scopes per set. See: https://github.com/OAI/OpenAPI-Specification/discussions/3001#discussioncomment-3456275 --- .../SecurityRequirement/RequiredScopesRow.tsx | 17 ++++++++++++----- .../SecurityRequirement/SecurityRequirement.tsx | 10 +++++----- .../SecurityRequirement.test.tsx.snap | 8 +++++--- .../fixtures/simple-security-fixture.json | 6 +++++- 4 files changed, 27 insertions(+), 14 deletions(-) diff --git a/src/components/SecurityRequirement/RequiredScopesRow.tsx b/src/components/SecurityRequirement/RequiredScopesRow.tsx index 8f899b60..c802f730 100644 --- a/src/components/SecurityRequirement/RequiredScopesRow.tsx +++ b/src/components/SecurityRequirement/RequiredScopesRow.tsx @@ -1,15 +1,22 @@ import * as React from 'react'; -export const RequiredScopesRow = ({ scopes }: { scopes: string[] }): JSX.Element | null => { - if (!scopes.length) return null; +export const RequiredScopesRow = ({ scopeSets }: { scopeSets: string[][] }): JSX.Element | null => { + if (!scopeSets.length) return null; return (
Required scopes: - {scopes.map((scope, idx) => { + {scopeSets.map((scopeSet, ssIdx) => { return ( - - {scope}{' '} + + {scopeSet.map((scope, idx) => { + return ( + + {scope}{' '} + + ); + })} + {ssIdx + 1 < scopeSets.length && ' or '} ); })} diff --git a/src/components/SecurityRequirement/SecurityRequirement.tsx b/src/components/SecurityRequirement/SecurityRequirement.tsx index d578284e..7cb38f62 100644 --- a/src/components/SecurityRequirement/SecurityRequirement.tsx +++ b/src/components/SecurityRequirement/SecurityRequirement.tsx @@ -65,7 +65,7 @@ export function SecurityRequirements(props: SecurityRequirementsProps) { key={scheme.id} scheme={scheme} RequiredScopes={ - + } /> @@ -83,8 +83,8 @@ const LockIcon = () => ( ); -function getRequiredScopes(id: string, securities: SecurityRequirementModel[]): string[] { - const allScopes: string[] = []; +function getRequiredScopeSets(id: string, securities: SecurityRequirementModel[]): string[][] { + const allScopes: string[][] = []; let securitiesLength = securities.length; while (securitiesLength--) { @@ -92,8 +92,8 @@ function getRequiredScopes(id: string, securities: SecurityRequirementModel[]): let schemesLength = security.schemes.length; while (schemesLength--) { const scheme = security.schemes[schemesLength]; - if (scheme.id === id && Array.isArray(scheme.scopes)) { - allScopes.push(...scheme.scopes); + if (scheme.id === id && Array.isArray(scheme.scopes) && scheme.scopes.length) { + allScopes.unshift(scheme.scopes); } } } diff --git a/src/components/__tests__/__snapshots__/SecurityRequirement.test.tsx.snap b/src/components/__tests__/__snapshots__/SecurityRequirement.test.tsx.snap index cfea66c7..1f47ea95 100644 --- a/src/components/__tests__/__snapshots__/SecurityRequirement.test.tsx.snap +++ b/src/components/__tests__/__snapshots__/SecurityRequirement.test.tsx.snap @@ -5,18 +5,20 @@ exports[`SecurityRequirement should render SecurityDefs 1`] = ` OAuth2 is also a safer and more secure way to give you access.

Security Scheme Type: OAuth2
Flow type: implicit
Scopes:
  • write:pets -

    modify pets in your account

  • read:pets -

    read your pets

    +
  • update:pets -

    update your pets

GitLab_PersonalAccessToken

GitLab Personal Access Token description

Security Scheme Type: API Key
Header parameter name: PRIVATE-TOKEN

GitLab_OpenIdConnect

GitLab OpenIdConnect description

Security Scheme Type: OpenID Connect

basicAuth

Security Scheme Type: HTTP
HTTP Authorization Scheme: basic
" `; -exports[`SecurityRequirement should render authDefinition 1`] = `"
Authorizations:
(API Key: GitLab_PersonalAccessTokenOpenID Connect: GitLab_OpenIdConnectHTTP: basicAuth) OAuth2: petstore_auth
,"`; +exports[`SecurityRequirement should render authDefinition 1`] = `"
Authorizations:
(API Key: GitLab_PersonalAccessTokenOpenID Connect: GitLab_OpenIdConnectHTTP: basicAuth) OAuth2: petstore_authOAuth2: petstore_auth
,"`; exports[`SecurityRequirement should render authDefinition 2`] = ` -"
Authorizations:
(API Key: GitLab_PersonalAccessTokenOpenID Connect: GitLab_OpenIdConnectHTTP: basicAuth) OAuth2: petstore_auth (write:petsread:pets)
OAuth2: petstore_auth

Get access to data while protecting your account credentials. +"

Authorizations:
(API Key: GitLab_PersonalAccessTokenOpenID Connect: GitLab_OpenIdConnectHTTP: basicAuth) OAuth2: petstore_auth (write:petsread:pets) OAuth2: petstore_auth (update:pets)
OAuth2: petstore_auth

Get access to data while protecting your account credentials. OAuth2 is also a safer and more secure way to give you access.

-
Flow type: implicit
Required scopes: write:pets read:pets
Scopes:
  • write:pets -

    modify pets in your account

    +
    Flow type: implicit
    Required scopes: write:pets read:pets or update:pets
    Scopes:
    • write:pets -

      modify pets in your account

    • read:pets -

      read your pets

      +
    • update:pets -

      update your pets

API Key: GitLab_PersonalAccessToken

GitLab Personal Access Token description

Header parameter name: PRIVATE-TOKEN
OpenID Connect: GitLab_OpenIdConnect

GitLab OpenIdConnect description

HTTP: basicAuth
HTTP Authorization Scheme: basic
," diff --git a/src/components/__tests__/fixtures/simple-security-fixture.json b/src/components/__tests__/fixtures/simple-security-fixture.json index 084ef84a..536525d9 100644 --- a/src/components/__tests__/fixtures/simple-security-fixture.json +++ b/src/components/__tests__/fixtures/simple-security-fixture.json @@ -23,6 +23,9 @@ }, { "petstore_auth": ["write:pets", "read:pets"] + }, + { + "petstore_auth": ["update:pets"] } ] } @@ -39,7 +42,8 @@ "authorizationUrl": "http://petstore.swagger.io/api/oauth/dialog", "scopes": { "write:pets": "modify pets in your account", - "read:pets": "read your pets" + "read:pets": "read your pets", + "update:pets": "update your pets" } } }