diff --git a/src/plugins/validation/2and3/semantic-validators/security-definitions-ibm.js b/src/plugins/validation/2and3/semantic-validators/security-definitions-ibm.js index 3391f6c60..401fc03c6 100644 --- a/src/plugins/validation/2and3/semantic-validators/security-definitions-ibm.js +++ b/src/plugins/validation/2and3/semantic-validators/security-definitions-ibm.js @@ -4,28 +4,28 @@ const each = require('lodash/each'); -module.exports.validate = function({ jsSpec, isOAS3 }, config) { +module.exports.validate = function({ resolvedSpec, isOAS3 }, config) { const result = {}; result.error = []; result.warning = []; config = config.security_definitions; - const usedSchemes = {}; - const usedScopes = {}; + const definedSchemes = {}; + const definedScopes = {}; // collect the security requirements and all relevant scopes const securityDefinitions = isOAS3 - ? jsSpec.components && jsSpec.components.securitySchemes - : jsSpec.securityDefinitions; + ? resolvedSpec.components && resolvedSpec.components.securitySchemes + : resolvedSpec.securityDefinitions; each(securityDefinitions, (scheme, name) => { if (name.slice(0, 2) === 'x-') return; - usedSchemes[name] = {}; - usedSchemes[name].used = false; - usedSchemes[name].type = scheme.type; + definedSchemes[name] = {}; + definedSchemes[name].used = false; + definedSchemes[name].type = scheme.type; // collect scopes in oauth2 schemes if (scheme.type.toLowerCase() === 'oauth2') { @@ -34,19 +34,19 @@ module.exports.validate = function({ jsSpec, isOAS3 }, config) { each(scheme.flows, (flow, flowType) => { if (flow.scopes) { Object.keys(flow.scopes).forEach(scope => { - usedScopes[scope] = {}; - usedScopes[scope].used = false; - usedScopes[scope].scheme = name; - usedScopes[scope].flow = flowType; + definedScopes[scope] = {}; + definedScopes[scope].used = false; + definedScopes[scope].scheme = name; + definedScopes[scope].flow = flowType; }); } }); } } else { Object.keys(scheme.scopes).forEach(scope => { - usedScopes[scope] = {}; - usedScopes[scope].used = false; - usedScopes[scope].scheme = name; + definedScopes[scope] = {}; + definedScopes[scope].used = false; + definedScopes[scope].scheme = name; }); } } @@ -56,12 +56,12 @@ module.exports.validate = function({ jsSpec, isOAS3 }, config) { // security objects can exist at either: // 1) the top level of the spec (global definition) - if (jsSpec.security) { - flagUsedDefinitions(jsSpec.security); + if (resolvedSpec.security) { + flagUsedDefinitions(resolvedSpec.security); } // 2) within operations objects - const paths = jsSpec.paths; + const paths = resolvedSpec.paths; each(paths, (operations, pathName) => { if (pathName.slice(0, 2) === 'x-') return; each(operations, (operation, opName) => { @@ -78,16 +78,16 @@ module.exports.validate = function({ jsSpec, isOAS3 }, config) { const name = Object.keys(scheme)[0]; // make sure this scheme was in the security definitions, then label as used - if (usedSchemes[name]) { - usedSchemes[name].used = true; + if (definedSchemes[name]) { + definedSchemes[name].used = true; - const type = usedSchemes[name].type; + const type = definedSchemes[name].type; const scopesArray = scheme[name]; if (type.toLowerCase() === 'oauth2') { scopesArray.forEach(scope => { - if (usedScopes[scope]) { - usedScopes[scope].used = true; + if (definedScopes[scope]) { + definedScopes[scope].used = true; } }); } @@ -96,7 +96,7 @@ module.exports.validate = function({ jsSpec, isOAS3 }, config) { } // check what has been used and what has not been - each(usedSchemes, (info, name) => { + each(definedSchemes, (info, name) => { if (info.used === false) { const checkStatus = config.unused_security_schemes; if (checkStatus !== 'off') { @@ -111,7 +111,7 @@ module.exports.validate = function({ jsSpec, isOAS3 }, config) { } }); - each(usedScopes, (info, name) => { + each(definedScopes, (info, name) => { if (info.used === false) { const checkStatus = config.unused_security_scopes; if (checkStatus !== 'off') { diff --git a/test/plugins/validation/2and3/security-definitions-ibm.js b/test/plugins/validation/2and3/security-definitions-ibm.js index ada7d8301..90bab6f48 100644 --- a/test/plugins/validation/2and3/security-definitions-ibm.js +++ b/test/plugins/validation/2and3/security-definitions-ibm.js @@ -1,4 +1,5 @@ const expect = require('expect'); +const resolver = require('json-schema-ref-parser'); const { validate } = require('../../../../src/plugins/validation/2and3/semantic-validators/security-definitions-ibm'); @@ -51,7 +52,7 @@ describe('validation plugin - semantic - security-definitions-ibm', function() { } }; - const res = validate({ jsSpec: spec }, config); + const res = validate({ resolvedSpec: spec }, config); expect(res.errors.length).toEqual(0); expect(res.warnings.length).toEqual(1); expect(res.warnings[0].message).toEqual( @@ -92,7 +93,7 @@ describe('validation plugin - semantic - security-definitions-ibm', function() { } }; - const res = validate({ jsSpec: spec }, config); + const res = validate({ resolvedSpec: spec }, config); expect(res.errors.length).toEqual(0); expect(res.warnings.length).toEqual(1); expect(res.warnings[0].message).toEqual( @@ -115,13 +116,40 @@ describe('validation plugin - semantic - security-definitions-ibm', function() { } }; - const res = validate({ jsSpec: spec }, config); + const res = validate({ resolvedSpec: spec }, config); expect(res.errors.length).toEqual(0); expect(res.warnings.length).toEqual(0); }); }); describe('OpenAPI 3', function() { + it('should follow references to security schemes', async function() { + const spec = { + components: { + schemas: { + SecuritySchemeModel: { + type: 'http', + scheme: 'basic', + descriptions: 'example text for def with unused security def' + } + }, + securitySchemes: { + scheme1: { + $ref: '#/components/schemas/SecuritySchemeModel' + } + } + } + }; + + const resolvedSpec = await resolver.dereference(spec); + + const res = validate({ resolvedSpec, isOAS3: true }, config); + expect(res.errors.length).toEqual(0); + expect(res.warnings.length).toEqual(1); + expect(res.warnings[0].message).toEqual( + 'A security scheme is defined but never used: scheme1' + ); + }); it('should warn about an unused security definition', function() { const spec = { components: { @@ -158,7 +186,7 @@ describe('validation plugin - semantic - security-definitions-ibm', function() { } }; - const res = validate({ jsSpec: spec, isOAS3: true }, config); + const res = validate({ resolvedSpec: spec, isOAS3: true }, config); expect(res.errors.length).toEqual(0); expect(res.warnings.length).toEqual(1); expect(res.warnings[0].message).toEqual( @@ -208,7 +236,7 @@ describe('validation plugin - semantic - security-definitions-ibm', function() { } }; - const res = validate({ jsSpec: spec, isOAS3: true }, config); + const res = validate({ resolvedSpec: spec, isOAS3: true }, config); expect(res.errors.length).toEqual(0); expect(res.warnings.length).toEqual(1); expect(res.warnings[0].message).toEqual( @@ -258,7 +286,7 @@ describe('validation plugin - semantic - security-definitions-ibm', function() { } }; - const res = validate({ jsSpec: spec, isOAS3: true }, config); + const res = validate({ resolvedSpec: spec, isOAS3: true }, config); expect(res.errors.length).toEqual(0); expect(res.warnings.length).toEqual(0); });