Merge pull request #23998 from aramissennyeydd/openapi-tooling/search-reserved

fix: allow reserved characters in all parameters
This commit is contained in:
Patrik Oldsberg
2024-04-15 16:09:23 +02:00
committed by GitHub
9 changed files with 57 additions and 4 deletions
+18
View File
@@ -0,0 +1,18 @@
---
'@backstage/repo-tools': minor
---
Adds a lint rule to `repo schema openapi lint` to enforce `allowReserved` for all parameters. To fix this, simply add `allowReserved: true` to your parameters, like so
```diff
/v1/todos:
get:
operationId: ListTodos
# ...
parameters:
- name: entity
in: query
+ allowReserved: true
schema:
type: string
```
+6
View File
@@ -0,0 +1,6 @@
---
'@backstage/plugin-search-backend': patch
'@backstage/plugin-todo-backend': patch
---
Allow reserved characters in requests.
@@ -26,6 +26,7 @@ import fs from 'fs-extra';
import chalk from 'chalk';
import { runner } from '../../../../lib/runner';
import { oas } from '@stoplight/spectral-rulesets';
import { truthy } from '@stoplight/spectral-functions';
import { DiagnosticSeverity } from '@stoplight/types';
import { pretty } from '@stoplight/spectral-formatters';
import { getPathToOpenApiSpec } from '../../../../lib/openapi/helpers';
@@ -47,6 +48,16 @@ async function lint(directoryPath: string, config?: { strict: boolean }) {
const backstageRuleset = new Ruleset(
{
extends: [oas, ruleset],
rules: {
'allow-reserved-in-params': {
given: '$.paths..parameters[*]',
then: {
field: 'allowReserved',
function: truthy,
},
severity: 'error',
},
},
overrides: [
{
files: ['*'],
@@ -63,8 +74,8 @@ async function lint(directoryPath: string, config?: { strict: boolean }) {
} as RulesetDefinition,
{ source: openapiPath },
);
spectral.setRuleset(backstageRuleset);
// we lint our document using the ruleset we passed to the Spectral object
const result = await spectral.run(document);
const errors = result.filter(e => e.severity === DiagnosticSeverity.Error);
+1
View File
@@ -37,6 +37,7 @@ export async function runner(
port: options.startingPort,
stopPort: options.startingPort + 1_000,
}));
const resultsList = await Promise.all(
packages.map(pkg =>
limit(async () => {
@@ -1,5 +1,5 @@
/*
* Copyright 2023 The Backstage Authors
* Copyright 2024 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -197,6 +197,7 @@ export const spec = {
name: 'term',
in: 'query',
required: false,
allowReserved: true,
schema: {
type: 'string',
default: '',
@@ -208,6 +209,7 @@ export const spec = {
required: false,
style: 'deepObject',
explode: true,
allowReserved: true,
schema: {
$ref: '#/components/schemas/JsonObject',
},
@@ -216,6 +218,7 @@ export const spec = {
name: 'types',
in: 'query',
required: false,
allowReserved: true,
schema: {
type: 'array',
items: {
@@ -227,6 +230,7 @@ export const spec = {
name: 'pageCursor',
in: 'query',
required: false,
allowReserved: true,
schema: {
type: 'string',
},
@@ -235,6 +239,7 @@ export const spec = {
name: 'pageLimit',
in: 'query',
required: false,
allowReserved: true,
schema: {
type: 'integer',
},
@@ -132,6 +132,7 @@ paths:
- name: term
in: query
required: false
allowReserved: true
schema:
type: string
default: ''
@@ -140,6 +141,7 @@ paths:
required: false
style: deepObject
explode: true
allowReserved: true
schema:
# JsonObject is used here instead of the full ZOD schema definition as
# resolution of recursive schemas isn't possible with the library we're using
@@ -148,6 +150,7 @@ paths:
- name: types
in: query
required: false
allowReserved: true
schema:
type: array
items:
@@ -155,10 +158,12 @@ paths:
- name: pageCursor
in: query
required: false
allowReserved: true
schema:
type: string
- name: pageLimit
in: query
required: false
allowReserved: true
schema:
type: integer
@@ -99,7 +99,6 @@ describe('createRouter', () => {
mockSearchEngine.query.mockRejectedValueOnce(error);
const response = await request(app).get('/query');
console.log((response as any).text);
expect(response.status).toEqual(500);
expect(response.body).toMatchObject(
@@ -127,6 +126,8 @@ describe('createRouter', () => {
'types[0]=first-type&types[1]=second-type',
'filters[prop]=value',
'pageCursor=foo',
// https://github.com/backstage/backstage/issues/23973
'term=foo+bar',
])('accepts valid query string "%s"', async queryString => {
const response = await request(app).get(`/query?${queryString}`);
@@ -1,5 +1,5 @@
/*
* Copyright 2023 The Backstage Authors
* Copyright 2024 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -162,6 +162,7 @@ export const spec = {
name: 'orderBy',
in: 'query',
required: false,
allowReserved: true,
schema: {
type: 'string',
pattern: '^(text|tag|author|viewUrl|repoFilePath)=(asc|desc)$',
@@ -188,6 +189,7 @@ export const spec = {
name: 'offset',
in: 'query',
required: false,
allowReserved: true,
schema: {
type: 'integer',
minimum: 0,
@@ -198,6 +200,7 @@ export const spec = {
name: 'limit',
in: 'query',
required: false,
allowReserved: true,
schema: {
type: 'integer',
minimum: 1,
@@ -104,6 +104,7 @@ paths:
- name: orderBy
in: query
required: false
allowReserved: true
schema:
type: string
pattern: '^(text|tag|author|viewUrl|repoFilePath)=(asc|desc)$'
@@ -121,6 +122,7 @@ paths:
- name: offset
in: query
required: false
allowReserved: true
schema:
type: integer
minimum: 0
@@ -128,6 +130,7 @@ paths:
- name: limit
in: query
required: false
allowReserved: true
schema:
type: integer
minimum: 1