Add az-operation-security rule

This commit is contained in:
Mike Kistler 2022-05-29 10:31:16 -05:00
Родитель 7f4abc93e0
Коммит 15bdf3f67f
4 изменённых файлов: 166 добавлений и 0 удалений

Просмотреть файл

@ -119,6 +119,10 @@ The `Verb` of the `operationId` should be or contain a specific value depending
| patch | "Update" | could be "CreateOrUpdate" |
| delete | "Delete" | |
### az-operation-security
Every operation should have a security requirement (may be defined globally).
### az-operation-summary-or-description
Operation should have a summary or description.

Просмотреть файл

@ -0,0 +1,27 @@
// Check API definition to ensure conformance to Azure security schemes guidelines.
// Check:
// - Operation (input) has a `security`, or there is a global `security`.
// @param input - an operation
module.exports = (input, options, context) => {
if (input === null || typeof input !== 'object') {
return [];
}
// If there is a global `security`, no need to check the operation.
if (context.document.data.security) {
return [];
}
const path = context.path || [];
if (!input.security) {
return [{
message: 'Operation should have a security requirement.',
path: [...path, 'security'],
}];
}
return [];
};

Просмотреть файл

@ -7,6 +7,7 @@ functions:
- has-header
- operation-id
- pagination-parameters
- operation-security
- pagination-response
- param-names
- param-names-unique
@ -183,6 +184,15 @@ rules:
then:
function: operation-id
az-operation-security:
description: Operation should have a security requirement or globally.
message: Operation should have a security requirement.
severity: warn
formats: ['oas2', 'oas3']
given: $.paths.*[get,put,post,patch,delete,options,head]
then:
function: operation-security
az-operation-summary-or-description:
description: Operation should have a summary or description.
message: Operation should have a summary or description.

Просмотреть файл

@ -0,0 +1,125 @@
const { linterForRule } = require('./utils');
let linter;
beforeAll(async () => {
linter = await linterForRule('az-operation-security');
return linter;
});
test('az-operation-security should find operations without security', () => {
const oasDoc = {
swagger: '2.0',
paths: {
'/test1': {
get: {
operationId: 'notNounVerb',
},
post: {
operationId: 'fooBarBaz',
},
},
},
};
return linter.run(oasDoc).then((results) => {
expect(results).toHaveLength(2);
expect(results[0].path.join('.')).toBe('paths./test1.get');
expect(results[1].path.join('.')).toBe('paths./test1.post');
results.forEach((result) => expect(result.message).toContain(
'Operation should have a security requirement.',
));
});
});
test('az-operation-security should find operations without security', () => {
const oasDoc = {
openapi: '3.0',
paths: {
'/test1': {
get: {
operationId: 'notNounVerb',
},
post: {
operationId: 'fooBarBaz',
},
},
},
};
return linter.run(oasDoc).then((results) => {
expect(results).toHaveLength(2);
expect(results[0].path.join('.')).toBe('paths./test1.get');
expect(results[1].path.join('.')).toBe('paths./test1.post');
results.forEach((result) => expect(result.message).toContain(
'Operation should have a security requirement.',
));
});
});
test('az-operation-security should find no errors', () => {
const oasDoc = {
swagger: '2.0',
paths: {
'/test1': {
get: {
operationId: 'Noun_Get',
security: [{
apiKey: [],
}],
},
put: {
operationId: 'Noun_Create',
security: [{
apiKey: [],
}],
},
},
},
};
return linter.run(oasDoc).then((results) => {
expect(results.length).toBe(0);
});
});
test('az-operation-security should find no errors', () => {
const oasDoc = {
swagger: '2.0',
security: [{
apiKey: [],
}],
paths: {
'/test1': {
get: {
operationId: 'Noun_Get',
},
put: {
operationId: 'Noun_Create',
},
},
},
};
return linter.run(oasDoc).then((results) => {
expect(results.length).toBe(0);
});
});
test('az-operation-security should find no errors', () => {
const oasDoc = {
openapi: '3.0',
security: [{
apiKey: [],
}],
paths: {
'/test1': {
get: {
operationId: 'Noun_Get',
},
put: {
operationId: 'Noun_Create',
},
},
},
};
return linter.run(oasDoc).then((results) => {
expect(results.length).toBe(0);
});
});