diff --git a/packages/bruno-converters/src/openapi/openapi-to-bruno.js b/packages/bruno-converters/src/openapi/openapi-to-bruno.js index adca4e795..85f031c0f 100644 --- a/packages/bruno-converters/src/openapi/openapi-to-bruno.js +++ b/packages/bruno-converters/src/openapi/openapi-to-bruno.js @@ -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] }; }; diff --git a/tests/import/openapi/fixtures/openapi-with-security-schemes.json b/tests/import/openapi/fixtures/openapi-with-security-schemes.json new file mode 100644 index 000000000..80f8104b5 --- /dev/null +++ b/tests/import/openapi/fixtures/openapi-with-security-schemes.json @@ -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" + } + } + } + } + } + } + } + } + } + } +} diff --git a/tests/import/openapi/fixtures/openapi-without-security-schemes.json b/tests/import/openapi/fixtures/openapi-without-security-schemes.json new file mode 100644 index 000000000..4a1b54d9d --- /dev/null +++ b/tests/import/openapi/fixtures/openapi-without-security-schemes.json @@ -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" + } + } + } + } + } +} diff --git a/tests/import/openapi/security-schemes-import.spec.ts b/tests/import/openapi/security-schemes-import.spec.ts new file mode 100644 index 000000000..5c760bc44 --- /dev/null +++ b/tests/import/openapi/security-schemes-import.spec.ts @@ -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' + }); + }); +});