Skip to content

Commit

Permalink
fix: update redocly.yaml validation (#1259)
Browse files Browse the repository at this point in the history
  • Loading branch information
tatomyr authored Sep 14, 2023
1 parent 58a567e commit 0ea1b59
Show file tree
Hide file tree
Showing 7 changed files with 435 additions and 328 deletions.
6 changes: 6 additions & 0 deletions .changeset/long-rabbits-camp.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@redocly/openapi-core': patch
'@redocly/cli': patch
---

Updated Redocly config validation.
2 changes: 2 additions & 0 deletions __tests__/lint/deprecated-apiDefinitions/snapshot.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ Warning was generated by the configuration spec rule.
Property \`lint\` is not expected here.
Did you mean: env ?
1 | apiDefinitions:
2 | main: ./openapi.yaml
3 | lint:
Expand Down
2 changes: 2 additions & 0 deletions __tests__/lint/deprecated-lint/snapshot.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ exports[`E2E lint deprecated-lint 1`] = `
Property \`lint\` is not expected here.
Did you mean: env ?
5 | rules:
6 | operation-4xx-response: error
7 | lint:
Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/__tests__/lint.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ describe('lint', () => {
"severity": "error",
"suggest": Array [
"theme",
"env",
"seo",
"sso",
],
Expand Down Expand Up @@ -178,6 +179,7 @@ describe('lint', () => {
"apis",
"seo",
"sso",
"env",
],
},
]
Expand Down
343 changes: 343 additions & 0 deletions packages/core/src/types/portal-config-schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,343 @@
import {
ApigeeDevOnboardingIntegrationAuthType,
AuthProviderType,
DEFAULT_TEAM_CLAIM_NAME,
} from '../config';

const oidcIssuerMetadataSchema = {
type: 'object',
properties: {
end_session_endpoint: { type: 'string' },
token_endpoint: { type: 'string' },
authorization_endpoint: { type: 'string' },
jwks_uri: { type: 'string' },
},
required: ['token_endpoint', 'authorization_endpoint'],
additionalProperties: true,
} as const;

const oidcProviderConfigSchema = {
type: 'object',
properties: {
type: { type: 'string', const: AuthProviderType.OIDC },
title: { type: 'string' },
configurationUrl: { type: 'string', minLength: 1 },
configuration: oidcIssuerMetadataSchema,
clientId: { type: 'string', minLength: 1 },
clientSecret: { type: 'string', minLength: 1 },
teamsClaimName: { type: 'string' },
teamsClaimMap: { type: 'object', additionalProperties: { type: 'string' } },
defaultTeams: { type: 'array', items: { type: 'string' } },
scopes: { type: 'array', items: { type: 'string' } },
tokenExpirationTime: { type: 'number' },
authorizationRequestCustomParams: { type: 'object', additionalProperties: { type: 'string' } },
tokenRequestCustomParams: { type: 'object', additionalProperties: { type: 'string' } },
audience: { type: 'array', items: { type: 'string' } },
},
required: ['type', 'clientId', 'clientSecret'],
oneOf: [{ required: ['configurationUrl'] }, { required: ['configuration'] }],
additionalProperties: false,
} as const;

const saml2ProviderConfigSchema = {
type: 'object',
properties: {
type: { type: 'string', const: AuthProviderType.SAML2 },
title: { type: 'string' },
issuerId: { type: 'string' },
entityId: { type: 'string' },
ssoUrl: { type: 'string' },
x509PublicCert: { type: 'string' },
teamsAttributeName: { type: 'string', default: DEFAULT_TEAM_CLAIM_NAME },
teamsAttributeMap: { type: 'object', additionalProperties: { type: 'string' } },
defaultTeams: { type: 'array', items: { type: 'string' } },
},
additionalProperties: false,
required: ['type', 'issuerId', 'ssoUrl', 'x509PublicCert'],
} as const;

const basicAuthProviderConfigSchema = {
type: 'object',
properties: {
type: { type: 'string', const: AuthProviderType.BASIC },
title: { type: 'string' },
credentials: {
type: 'array',
items: {
type: 'object',
properties: {
username: { type: 'string' },
password: { type: 'string' },
passwordHash: { type: 'string' },
teams: { type: 'array', items: { type: 'string' } },
},
required: ['username'],
additionalProperties: false,
},
},
},
required: ['type', 'credentials'],
additionalProperties: false,
} as const;

const authProviderConfigSchema = {
oneOf: [oidcProviderConfigSchema, saml2ProviderConfigSchema, basicAuthProviderConfigSchema],
discriminator: { propertyName: 'type' },
} as const;

export const ssoConfigSchema = {
type: 'object',
additionalProperties: authProviderConfigSchema,
} as const;

const redirectConfigSchema = {
type: 'object',
properties: {
to: { type: 'string' },
type: { type: 'number', default: 301 },
},
required: ['to'],
additionalProperties: false,
} as const;

export const apiConfigSchema = {
type: 'object',
properties: {
root: { type: 'string' },
rbac: { type: 'object', additionalProperties: true },
theme: {
type: 'object',
properties: {
openapi: { type: 'object', additionalProperties: true },
},
additionalProperties: false,
},
title: { type: 'string' },
metadata: { type: 'object', additionalProperties: true },
},
additionalProperties: true,
required: ['root'],
} as const;

const metadataConfigSchema = {
type: 'object',
additionalProperties: true,
} as const;

const seoConfigSchema = {
type: 'object',
properties: {
title: { type: 'string' },
description: { type: 'string' },
siteUrl: { type: 'string' },
image: { type: 'string' },
keywords: { type: 'array', items: { type: 'string' } },
lang: { type: 'string' },
jsonLd: { type: 'object' },
meta: {
type: 'array',
items: {
type: 'object',
properties: {
name: { type: 'string' },
content: { type: 'string' },
},
required: ['name', 'content'],
additionalProperties: false,
},
},
},
additionalProperties: false,
} as const;

const rbacScopeItemsSchema = { type: 'object', additionalProperties: { type: 'string' } } as const;

const rbacConfigSchema = {
type: 'object',
properties: {
defaults: rbacScopeItemsSchema,
},
additionalProperties: rbacScopeItemsSchema,
} as const;

const graviteeAdapterConfigSchema = {
type: 'object',
properties: {
type: { type: 'string', const: 'GRAVITEE' },
apiBaseUrl: { type: 'string' },
env: { type: 'string' },
allowApiProductsOutsideCatalog: { type: 'boolean', default: false },
stage: { type: 'string', default: 'non-production' },

auth: { type: 'object', properties: { static: { type: 'string' } } },
},
additionalProperties: false,
required: ['type', 'apiBaseUrl'],
} as const;

const apigeeAdapterAuthOauth2Schema = {
type: 'object',
properties: {
type: { type: 'string', const: ApigeeDevOnboardingIntegrationAuthType.OAUTH2 },
tokenEndpoint: { type: 'string' },
clientId: { type: 'string' },
clientSecret: { type: 'string' },
},
additionalProperties: false,
required: ['type', 'tokenEndpoint', 'clientId', 'clientSecret'],
} as const;

const apigeeAdapterAuthServiceAccountSchema = {
type: 'object',
properties: {
type: { type: 'string', const: ApigeeDevOnboardingIntegrationAuthType.SERVICE_ACCOUNT },
serviceAccountEmail: { type: 'string' },
serviceAccountPrivateKey: { type: 'string' },
},
additionalProperties: false,
required: ['type', 'serviceAccountEmail', 'serviceAccountPrivateKey'],
} as const;

const apigeeXAdapterConfigSchema = {
type: 'object',
properties: {
type: { type: 'string', const: 'APIGEE_X' },
apiUrl: { type: 'string' },
stage: { type: 'string', default: 'non-production' },
organizationName: { type: 'string' },
ignoreApiProducts: { type: 'array', items: { type: 'string' } },
allowApiProductsOutsideCatalog: { type: 'boolean', default: false },
auth: {
type: 'object',
oneOf: [apigeeAdapterAuthOauth2Schema, apigeeAdapterAuthServiceAccountSchema],
discriminator: { propertyName: 'type' },
},
},
additionalProperties: false,
required: ['type', 'organizationName', 'auth'],
} as const;

const apigeeEdgeAdapterConfigSchema = {
...apigeeXAdapterConfigSchema,
properties: {
...apigeeXAdapterConfigSchema.properties,
type: { type: 'string', const: 'APIGEE_EDGE' },
},
} as const;

const devOnboardingAdapterConfigSchema = {
type: 'object',
oneOf: [apigeeXAdapterConfigSchema, apigeeEdgeAdapterConfigSchema, graviteeAdapterConfigSchema],
discriminator: { propertyName: 'type' },
} as const;

const devOnboardingConfigSchema = {
type: 'object',
required: ['adapters'],
additionalProperties: false,
properties: {
adapters: {
type: 'array',
items: devOnboardingAdapterConfigSchema,
},
},
} as const;

const responseHeaderSchema = {
type: 'object',
properties: {
name: { type: 'string' },
value: { type: 'string' },
},
additionalProperties: false,
required: ['name', 'value'],
} as const;

export const redoclyConfigSchema = {
type: 'object',
properties: {
licenseKey: { type: 'string' },
theme: { type: 'object', default: {} }, // ThemeConfig
redirects: { type: 'object', additionalProperties: redirectConfigSchema, default: {} },
seo: seoConfigSchema,
rbac: rbacConfigSchema,
responseHeaders: {
type: 'object',
additionalProperties: {
type: 'array',
items: responseHeaderSchema,
},
},
mockServer: {
type: 'object',
properties: {
off: { type: 'boolean', default: false },
position: { type: 'string', enum: ['first', 'last', 'replace', 'off'], default: 'first' },
strictExamples: { type: 'boolean', default: false },
errorIfForcedExampleNotFound: { type: 'boolean', default: false },
description: { type: 'string' },
},
},
apis: {
type: 'object',
additionalProperties: apiConfigSchema,
},
sso: ssoConfigSchema,
developerOnboarding: devOnboardingConfigSchema,
i18n: {
type: 'object',
properties: {
defaultLocale: {
type: 'string',
},
locales: {
type: 'array',
items: {
type: 'object',
properties: {
code: {
type: 'string',
},
name: {
type: 'string',
},
},
required: ['code'],
},
},
},
additionalProperties: false,
required: ['defaultLocale', 'locales'],
},
metadata: metadataConfigSchema,
},
default: {},
additionalProperties: true,
} as const;

export const environmentSchema = {
oneOf: [
{ ...redoclyConfigSchema, additionalProperties: false },
{
type: 'object',
properties: {
$ref: { type: 'string' },
},
required: ['$ref'],
additionalProperties: false,
},
],
} as const;

export const rootRedoclyConfigSchema = {
...redoclyConfigSchema,
properties: {
...redoclyConfigSchema.properties,
env: {
type: 'object',
additionalProperties: environmentSchema,
},
},
default: {},
required: ['redirects'],
} as const;
Loading

1 comment on commit 0ea1b59

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Coverage report

St.
Category Percentage Covered / Total
🟡 Statements 75.44% 3793/5028
🟡 Branches 66.3% 2103/3172
🟡 Functions 68.6% 638/930
🟡 Lines 75.59% 3543/4687

Test suite run success

625 tests passing in 91 suites.

Report generated by 🧪jest coverage report action from 0ea1b59

Please sign in to comment.