Merge pull request #23998 from aramissennyeydd/openapi-tooling/search-reserved
fix: allow reserved characters in all parameters
This commit is contained in:
@@ -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
|
||||
```
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user