Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/afraid-streets-like.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@redocly/openapi-core": patch
---

Fixed an issue where the `no-invalid-schema-examples` rule was incorrectly linting the `exclusiveMinimum` and `exclusiveMaximum` properties in OpenAPI 3.0.
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
openapi: 3.0.2
info:
title: Example OpenAPI 3 definition.
version: 1.0.0

paths:
/pet:
get:
parameters:
- $ref: '#/components/parameters/validExample'
responses:
'200':
description: Response description
content:
application/json:
schema: {}

components:
parameters:
validExample:
in: header
name: Test
schema:
type: integer
minimum: 10
exclusiveMinimum: true
example: 11
notValidExampleWithExclusiveMaximum:
in: query
name: anotherTest
schema:
type: integer
minimum: 5
exclusiveMaximum: true
example: 10
notValidExample:
in: query
name: yetAnotherTest
schema:
type: integer
minimum: 0
exclusiveMinimum: true
example: 0
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
apis:
main:
root: ./openapi.yaml

rules:
no-invalid-schema-examples: error
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
[1] openapi.yaml:32:9 at #/components/parameters/notValidExampleWithExclusiveMaximum/schema/schema

Example validation errored: exclusiveMaximum can only be used with maximum.

30 | name: anotherTest
31 | schema:
32 | type: integer
| ^^^^^^^^^^^^^
33 | minimum: 5
| ^^^^^^^^^^
34 | exclusiveMaximum: true
| ^^^^^^^^^^^^^^^^^^^^^^
35 | example: 10
| ^^^^^^^^^^^
36 | notValidExample:
37 | in: query

referenced from openapi.yaml:32:9 at #/components/parameters/notValidExampleWithExclusiveMaximum/schema

Error was generated by the no-invalid-schema-examples rule.


[2] openapi.yaml:43:18 at #/components/parameters/notValidExample/schema/example

Example value must conform to the schema: must be > 0.

41 | minimum: 0
42 | exclusiveMinimum: true
43 | example: 0
| ^
44 |

referenced from openapi.yaml:40:9 at #/components/parameters/notValidExample/schema

Error was generated by the no-invalid-schema-examples rule.



validating openapi.yaml using lint rules for api 'main'...
openapi.yaml: validated in <test>ms

❌ Validation failed with 2 errors.
run `redocly lint --generate-ignore-file` to add all problems to the ignore file.

53 changes: 53 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
"dependencies": {
"@redocly/ajv": "^8.11.2",
"@redocly/config": "^0.31.0",
"ajv-draft-04": "^1.0.0",
"ajv-formats": "^2.1.1",
"colorette": "^1.2.0",
"js-levenshtein": "^1.1.6",
Expand Down
53 changes: 51 additions & 2 deletions packages/core/src/rules/ajv.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
import addFormats from 'ajv-formats';
import Ajv from '@redocly/ajv/dist/2020.js';
import AjvDraft04 from 'ajv-draft-04';
import { escapePointer } from '../ref-utils.js';

import type { Location } from '../ref-utils.js';
import type { ValidateFunction, ErrorObject } from '@redocly/ajv/dist/2020.js';
import type { ResolveFn } from '../walk.js';

let ajvInstance: Ajv | null = null;
let ajvDraft04Instance: AjvDraft04 | null = null;

export function releaseAjvInstance() {
ajvInstance = null;
ajvDraft04Instance = null;
}

function getAjv(resolve: ResolveFn, allowAdditionalProperties: boolean) {
Expand Down Expand Up @@ -37,6 +40,32 @@
return ajvInstance;
}

function getAjvDraft04(resolve: ResolveFn, allowAdditionalProperties: boolean) {
if (!ajvDraft04Instance) {
ajvDraft04Instance = new AjvDraft04({
schemaId: 'id',
meta: false,
allErrors: true,
strictSchema: false,
inlineRefs: true,
validateSchema: false,
discriminator: true,
allowUnionTypes: true,
validateFormats: true,
logger: false,
defaultAdditionalProperties: allowAdditionalProperties,
loadSchemaSync(base, $ref, id) {

Check failure on line 57 in packages/core/src/rules/ajv.ts

View workflow job for this annotation

GitHub Actions / run-smoke-rebilly

Parameter 'id' implicitly has an 'any' type.

Check failure on line 57 in packages/core/src/rules/ajv.ts

View workflow job for this annotation

GitHub Actions / run-smoke-rebilly

Parameter '$ref' implicitly has an 'any' type.

Check failure on line 57 in packages/core/src/rules/ajv.ts

View workflow job for this annotation

GitHub Actions / run-smoke-rebilly

Parameter 'base' implicitly has an 'any' type.

Check failure on line 57 in packages/core/src/rules/ajv.ts

View workflow job for this annotation

GitHub Actions / require-changeset-or-label

Parameter 'id' implicitly has an 'any' type.

Check failure on line 57 in packages/core/src/rules/ajv.ts

View workflow job for this annotation

GitHub Actions / require-changeset-or-label

Parameter '$ref' implicitly has an 'any' type.

Check failure on line 57 in packages/core/src/rules/ajv.ts

View workflow job for this annotation

GitHub Actions / require-changeset-or-label

Parameter 'base' implicitly has an 'any' type.

Check failure on line 57 in packages/core/src/rules/ajv.ts

View workflow job for this annotation

GitHub Actions / cli-package-test

Parameter 'id' implicitly has an 'any' type.

Check failure on line 57 in packages/core/src/rules/ajv.ts

View workflow job for this annotation

GitHub Actions / cli-package-test

Parameter '$ref' implicitly has an 'any' type.

Check failure on line 57 in packages/core/src/rules/ajv.ts

View workflow job for this annotation

GitHub Actions / cli-package-test

Parameter 'base' implicitly has an 'any' type.

Check failure on line 57 in packages/core/src/rules/ajv.ts

View workflow job for this annotation

GitHub Actions / build-and-unit

Parameter 'id' implicitly has an 'any' type.

Check failure on line 57 in packages/core/src/rules/ajv.ts

View workflow job for this annotation

GitHub Actions / build-and-unit

Parameter '$ref' implicitly has an 'any' type.

Check failure on line 57 in packages/core/src/rules/ajv.ts

View workflow job for this annotation

GitHub Actions / build-and-unit

Parameter 'base' implicitly has an 'any' type.

Check failure on line 57 in packages/core/src/rules/ajv.ts

View workflow job for this annotation

GitHub Actions / latest-vs-next

Parameter 'id' implicitly has an 'any' type.

Check failure on line 57 in packages/core/src/rules/ajv.ts

View workflow job for this annotation

GitHub Actions / latest-vs-next

Parameter '$ref' implicitly has an 'any' type.

Check failure on line 57 in packages/core/src/rules/ajv.ts

View workflow job for this annotation

GitHub Actions / latest-vs-next

Parameter 'base' implicitly has an 'any' type.

Check failure on line 57 in packages/core/src/rules/ajv.ts

View workflow job for this annotation

GitHub Actions / code-style-check

Parameter 'id' implicitly has an 'any' type.

Check failure on line 57 in packages/core/src/rules/ajv.ts

View workflow job for this annotation

GitHub Actions / code-style-check

Parameter '$ref' implicitly has an 'any' type.

Check failure on line 57 in packages/core/src/rules/ajv.ts

View workflow job for this annotation

GitHub Actions / code-style-check

Parameter 'base' implicitly has an 'any' type.

Check failure on line 57 in packages/core/src/rules/ajv.ts

View workflow job for this annotation

GitHub Actions / prepare-smoke-plugins

Parameter 'id' implicitly has an 'any' type.

Check failure on line 57 in packages/core/src/rules/ajv.ts

View workflow job for this annotation

GitHub Actions / prepare-smoke-plugins

Parameter '$ref' implicitly has an 'any' type.

Check failure on line 57 in packages/core/src/rules/ajv.ts

View workflow job for this annotation

GitHub Actions / prepare-smoke-plugins

Parameter 'base' implicitly has an 'any' type.

Check failure on line 57 in packages/core/src/rules/ajv.ts

View workflow job for this annotation

GitHub Actions / prepare-smoke

Parameter 'id' implicitly has an 'any' type.

Check failure on line 57 in packages/core/src/rules/ajv.ts

View workflow job for this annotation

GitHub Actions / prepare-smoke

Parameter '$ref' implicitly has an 'any' type.

Check failure on line 57 in packages/core/src/rules/ajv.ts

View workflow job for this annotation

GitHub Actions / prepare-smoke

Parameter 'base' implicitly has an 'any' type.
const resolvedRef = resolve({ $ref }, base.split('#')[0]);
if (!resolvedRef || !resolvedRef.location) return false;
return { $id: resolvedRef.location.source.absoluteRef + '#' + id, ...resolvedRef.node };
},
});
addFormats(ajvDraft04Instance as any);
}

return ajvDraft04Instance;
}

function getAjvValidator(
schema: any,
loc: Location,
Expand All @@ -52,15 +81,35 @@
return ajv.getSchema(loc.absolutePointer);
}

function getAjvDraft04Validator(
schema: any,
loc: Location,
resolve: ResolveFn,
allowAdditionalProperties: boolean
): ValidateFunction | undefined {
const ajv = getAjvDraft04(resolve, allowAdditionalProperties);

if (!ajv.getSchema(loc.absolutePointer)) {

Check failure on line 92 in packages/core/src/rules/ajv.ts

View workflow job for this annotation

GitHub Actions / run-smoke-rebilly

Property 'getSchema' does not exist on type 'Ajv'.

Check failure on line 92 in packages/core/src/rules/ajv.ts

View workflow job for this annotation

GitHub Actions / require-changeset-or-label

Property 'getSchema' does not exist on type 'Ajv'.

Check failure on line 92 in packages/core/src/rules/ajv.ts

View workflow job for this annotation

GitHub Actions / cli-package-test

Property 'getSchema' does not exist on type 'Ajv'.

Check failure on line 92 in packages/core/src/rules/ajv.ts

View workflow job for this annotation

GitHub Actions / build-and-unit

Property 'getSchema' does not exist on type 'Ajv'.

Check failure on line 92 in packages/core/src/rules/ajv.ts

View workflow job for this annotation

GitHub Actions / latest-vs-next

Property 'getSchema' does not exist on type 'Ajv'.

Check failure on line 92 in packages/core/src/rules/ajv.ts

View workflow job for this annotation

GitHub Actions / code-style-check

Property 'getSchema' does not exist on type 'Ajv'.

Check failure on line 92 in packages/core/src/rules/ajv.ts

View workflow job for this annotation

GitHub Actions / prepare-smoke-plugins

Property 'getSchema' does not exist on type 'Ajv'.

Check failure on line 92 in packages/core/src/rules/ajv.ts

View workflow job for this annotation

GitHub Actions / prepare-smoke

Property 'getSchema' does not exist on type 'Ajv'.
ajv.addSchema({ $id: loc.absolutePointer, ...schema }, loc.absolutePointer);

Check failure on line 93 in packages/core/src/rules/ajv.ts

View workflow job for this annotation

GitHub Actions / run-smoke-rebilly

Property 'addSchema' does not exist on type 'Ajv'.

Check failure on line 93 in packages/core/src/rules/ajv.ts

View workflow job for this annotation

GitHub Actions / require-changeset-or-label

Property 'addSchema' does not exist on type 'Ajv'.

Check failure on line 93 in packages/core/src/rules/ajv.ts

View workflow job for this annotation

GitHub Actions / cli-package-test

Property 'addSchema' does not exist on type 'Ajv'.

Check failure on line 93 in packages/core/src/rules/ajv.ts

View workflow job for this annotation

GitHub Actions / build-and-unit

Property 'addSchema' does not exist on type 'Ajv'.

Check failure on line 93 in packages/core/src/rules/ajv.ts

View workflow job for this annotation

GitHub Actions / latest-vs-next

Property 'addSchema' does not exist on type 'Ajv'.

Check failure on line 93 in packages/core/src/rules/ajv.ts

View workflow job for this annotation

GitHub Actions / code-style-check

Property 'addSchema' does not exist on type 'Ajv'.

Check failure on line 93 in packages/core/src/rules/ajv.ts

View workflow job for this annotation

GitHub Actions / prepare-smoke-plugins

Property 'addSchema' does not exist on type 'Ajv'.

Check failure on line 93 in packages/core/src/rules/ajv.ts

View workflow job for this annotation

GitHub Actions / prepare-smoke

Property 'addSchema' does not exist on type 'Ajv'.
}

return ajv.getSchema(loc.absolutePointer);

Check failure on line 96 in packages/core/src/rules/ajv.ts

View workflow job for this annotation

GitHub Actions / run-smoke-rebilly

Property 'getSchema' does not exist on type 'Ajv'.

Check failure on line 96 in packages/core/src/rules/ajv.ts

View workflow job for this annotation

GitHub Actions / require-changeset-or-label

Property 'getSchema' does not exist on type 'Ajv'.

Check failure on line 96 in packages/core/src/rules/ajv.ts

View workflow job for this annotation

GitHub Actions / cli-package-test

Property 'getSchema' does not exist on type 'Ajv'.

Check failure on line 96 in packages/core/src/rules/ajv.ts

View workflow job for this annotation

GitHub Actions / build-and-unit

Property 'getSchema' does not exist on type 'Ajv'.

Check failure on line 96 in packages/core/src/rules/ajv.ts

View workflow job for this annotation

GitHub Actions / latest-vs-next

Property 'getSchema' does not exist on type 'Ajv'.

Check failure on line 96 in packages/core/src/rules/ajv.ts

View workflow job for this annotation

GitHub Actions / code-style-check

Property 'getSchema' does not exist on type 'Ajv'.

Check failure on line 96 in packages/core/src/rules/ajv.ts

View workflow job for this annotation

GitHub Actions / prepare-smoke-plugins

Property 'getSchema' does not exist on type 'Ajv'.

Check failure on line 96 in packages/core/src/rules/ajv.ts

View workflow job for this annotation

GitHub Actions / prepare-smoke

Property 'getSchema' does not exist on type 'Ajv'.
}

export function validateJsonSchema(
data: any,
schema: any,
schemaLoc: Location,
instancePath: string,
resolve: ResolveFn,
allowAdditionalProperties: boolean
allowAdditionalProperties: boolean,
specVersion: string = 'oas3_1'
): { valid: boolean; errors: (ErrorObject & { suggest?: string[] })[] } {
const validate = getAjvValidator(schema, schemaLoc, resolve, allowAdditionalProperties);
const validate =
specVersion === 'oas3_0' || specVersion === 'oas2'
Copy link
Collaborator

Choose a reason for hiding this comment

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

Coud you add a comment with the link to a document which clarifies the JSON Schema drafts usage for these OAS versions?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Draft-04 handles only validation of exclusiveMinimum and exclusiveMaximum for boolean, and all other validations it handles using types/functions/library/vocabulary from basic AJV.

? getAjvDraft04Validator(schema, schemaLoc, resolve, allowAdditionalProperties)
: getAjvValidator(schema, schemaLoc, resolve, allowAdditionalProperties);

if (!validate) return { valid: true, errors: [] }; // unresolved refs are reported

const valid = validate(data, {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,14 @@ export const NoInvalidSchemaExamples: Oas3Rule | Oas2Rule = (opts: any) => {
return;
}

validateExample(schema.example, schema, ctx.location.child('example'), ctx, true);
validateExample(
schema.example,
schema,
ctx.location.child('example'),
ctx,
true,
ctx.specVersion
);
}
},
},
Expand Down
6 changes: 4 additions & 2 deletions packages/core/src/rules/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,8 @@ export function validateExample(
schema: Referenced<Oas3Schema | Oas3_1Schema>,
dataLoc: Location,
{ resolve, location, report }: UserContext,
allowAdditionalProperties: boolean
allowAdditionalProperties: boolean,
specVersion?: string
) {
try {
const { valid, errors } = validateJsonSchema(
Expand All @@ -143,7 +144,8 @@ export function validateExample(
location.child('schema'),
dataLoc.pointer,
resolve,
allowAdditionalProperties
allowAdditionalProperties,
specVersion
);
if (!valid) {
for (const error of errors) {
Expand Down
Loading