fix: OpenAPI import fails when securitySchemes are not defined (#6429)

* feat: enhance OpenAPI security scheme handling

* refactor: revert test changes and update openapi-to-bruno
This commit is contained in:
Sanjai Kumar
2025-12-17 16:52:54 +05:30
committed by GitHub
parent 639c8e573f
commit 395aa4246e
4 changed files with 532 additions and 13 deletions

View File

@@ -925,23 +925,18 @@ const getDefaultUrl = (serverObject) => {
const getSecurity = (apiSpec) => {
let defaultSchemes = apiSpec.security || [];
let securitySchemes = get(apiSpec, 'components.securitySchemes', {});
if (Object.keys(securitySchemes).length === 0) {
return {
supported: []
};
}
const hasSchemes = Object.keys(securitySchemes).length > 0;
return {
supported: defaultSchemes.map((scheme) => {
var schemeName = Object.keys(scheme)[0];
return securitySchemes[schemeName];
}),
supported: hasSchemes
? defaultSchemes
.map((scheme) => securitySchemes[Object.keys(scheme)[0]])
.filter(Boolean)
: [],
schemes: securitySchemes,
getScheme: (schemeName) => {
return securitySchemes[schemeName];
}
getScheme: (schemeName) => securitySchemes[schemeName]
};
};

View File

@@ -0,0 +1,208 @@
{
"openapi": "3.0.0",
"info": {
"title": "API with Security Schemes",
"description": "An API that demonstrates various security schemes",
"version": "1.0.0"
},
"servers": [
{
"url": "https://api.example.com/v1",
"description": "Production server"
}
],
"security": [
{
"bearerAuth": []
}
],
"components": {
"securitySchemes": {
"bearerAuth": {
"type": "http",
"scheme": "bearer",
"description": "Bearer token authentication"
},
"basicAuth": {
"type": "http",
"scheme": "basic",
"description": "Basic authentication"
},
"apiKey": {
"type": "apiKey",
"in": "header",
"name": "X-API-Key",
"description": "API Key authentication"
},
"oauth2": {
"type": "oauth2",
"flows": {
"authorizationCode": {
"authorizationUrl": "https://auth.example.com/oauth/authorize",
"tokenUrl": "https://auth.example.com/oauth/token",
"scopes": {
"read": "Read access",
"write": "Write access",
"admin": "Admin access"
}
}
},
"description": "OAuth 2.0 authentication"
}
}
},
"paths": {
"/users": {
"get": {
"summary": "Get users",
"description": "Retrieve a list of users",
"security": [
{
"bearerAuth": []
}
],
"responses": {
"200": {
"description": "Successful response",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"name": {
"type": "string"
},
"email": {
"type": "string"
}
}
}
}
}
}
}
}
},
"post": {
"summary": "Create user",
"description": "Create a new user",
"security": [
{
"bearerAuth": []
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"email": {
"type": "string"
}
},
"required": ["name", "email"]
}
}
}
},
"responses": {
"201": {
"description": "User created",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"name": {
"type": "string"
},
"email": {
"type": "string"
}
}
}
}
}
}
}
}
},
"/admin/users": {
"get": {
"summary": "Admin get users",
"description": "Retrieve all users (admin only)",
"security": [
{
"oauth2": ["admin"]
}
],
"responses": {
"200": {
"description": "Successful response",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"name": {
"type": "string"
},
"email": {
"type": "string"
}
}
}
}
}
}
}
}
}
},
"/public/data": {
"get": {
"summary": "Get public data",
"description": "Retrieve public data without authentication",
"security": [],
"responses": {
"200": {
"description": "Successful response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"message": {
"type": "string"
},
"timestamp": {
"type": "string"
}
}
}
}
}
}
}
}
}
}
}

View File

@@ -0,0 +1,291 @@
{
"openapi": "3.0.0",
"info": {
"title": "API without Security Schemes",
"description": "An API that has no security schemes defined - should use the getSecurity fallback logic",
"version": "1.0.0"
},
"servers": [
{
"url": "https://api.public-example.com/v1",
"description": "Public API server"
}
],
"paths": {
"/health": {
"get": {
"summary": "Health check",
"description": "Check if the API is healthy",
"responses": {
"200": {
"description": "API is healthy",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"status": {
"type": "string",
"enum": ["ok"]
},
"timestamp": {
"type": "string"
}
}
}
}
}
}
}
}
},
"/public/info": {
"get": {
"summary": "Get public information",
"description": "Retrieve public information that doesn't require authentication",
"responses": {
"200": {
"description": "Successful response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"version": {
"type": "string"
},
"features": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
}
}
}
}
}
},
"/data": {
"get": {
"summary": "Get data",
"description": "Retrieve data from the API",
"parameters": [
{
"name": "limit",
"in": "query",
"description": "Maximum number of items to return",
"schema": {
"type": "integer",
"minimum": 1,
"maximum": 100,
"default": 10
}
}
],
"responses": {
"200": {
"description": "Successful response",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"name": {
"type": "string"
},
"description": {
"type": "string"
}
}
}
}
}
}
}
}
},
"post": {
"summary": "Create data",
"description": "Create new data item",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"description": {
"type": "string"
}
},
"required": ["name"]
}
}
}
},
"responses": {
"201": {
"description": "Data created successfully",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"name": {
"type": "string"
},
"description": {
"type": "string"
},
"created_at": {
"type": "string"
}
}
}
}
}
}
}
}
},
"/data/{id}": {
"get": {
"summary": "Get data by ID",
"description": "Retrieve a specific data item by its ID",
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"description": "ID of the data item",
"schema": {
"type": "integer"
}
}
],
"responses": {
"200": {
"description": "Successful response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"name": {
"type": "string"
},
"description": {
"type": "string"
}
}
}
}
}
},
"404": {
"description": "Data item not found"
}
}
},
"put": {
"summary": "Update data",
"description": "Update an existing data item",
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"description": "ID of the data item",
"schema": {
"type": "integer"
}
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"description": {
"type": "string"
}
}
}
}
}
},
"responses": {
"200": {
"description": "Data updated successfully",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"name": {
"type": "string"
},
"description": {
"type": "string"
},
"updated_at": {
"type": "string"
}
}
}
}
}
}
}
},
"delete": {
"summary": "Delete data",
"description": "Delete a data item",
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"description": "ID of the data item",
"schema": {
"type": "integer"
}
}
],
"responses": {
"204": {
"description": "Data deleted successfully"
},
"404": {
"description": "Data item not found"
}
}
}
}
}
}

View File

@@ -0,0 +1,25 @@
import { test } from '../../../playwright';
import * as path from 'path';
import { closeAllCollections, importCollection } from '../../utils/page';
test.describe('OpenAPI Security Schemes Import', () => {
test.afterEach(async ({ page }) => {
await closeAllCollections(page);
});
test('Import OpenAPI spec with security schemes', async ({ page, createTmpDir }) => {
const openApiFile = path.resolve(__dirname, 'fixtures', 'openapi-with-security-schemes.json');
await importCollection(page, openApiFile, await createTmpDir('openapi-with-security'), {
expectedCollectionName: 'API with Security Schemes'
});
});
test('Import OpenAPI spec without security schemes', async ({ page, createTmpDir }) => {
const openApiFile = path.resolve(__dirname, 'fixtures', 'openapi-without-security-schemes.json');
await importCollection(page, openApiFile, await createTmpDir('openapi-without-security'), {
expectedCollectionName: 'API without Security Schemes'
});
});
});