Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import testRule from './__helpers__/testRule';
import { DiagnosticSeverity } from '@stoplight/types';

testRule('xgen-IPA-113-singleton-must-not-have-delete-method', [
{
name: 'valid resources',
document: {
paths: {
'/resource': {
post: {},
get: {},
},
'/resource/{exampleId}': {
get: {},
patch: {},
delete: {},
},
'/resource/{exampleId}/singleton': {
get: {},
patch: {},
},
},
},
errors: [],
},
{
name: 'invalid resource',
document: {
paths: {
'/resource/{exampleId}/singleton': {
delete: {},
},
},
},
errors: [
{
code: 'xgen-IPA-113-singleton-must-not-have-delete-method',
message:
'Singleton resources must not define the Delete standard method. If this is not a singleton resource, please implement all CRUDL methods.',
path: ['paths', '/resource/{exampleId}/singleton'],
severity: DiagnosticSeverity.Warning,
},
],
},
{
name: 'invalid resources with exceptions',
document: {
paths: {
'/resource/{exampleId}/singleton': {
delete: {},
'x-xgen-IPA-exception': {
'xgen-IPA-113-singleton-must-not-have-delete-method': 'reason',
},
},
},
},
errors: [],
},
]);
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import testRule from './__helpers__/testRule';
import { DiagnosticSeverity } from '@stoplight/types';

testRule('xgen-IPA-113-singleton-should-have-update-method', [
{
name: 'valid resources',
document: {
paths: {
'/resource/{exampleId}/singletonOne': {
patch: {},
},
'/resource/{exampleId}/singletonTwo': {
put: {},
},
'/resource/{exampleId}/singletonThree': {
patch: {},
put: {},
},
},
},
errors: [],
},
{
name: 'invalid resource',
document: {
paths: {
'/resource/{exampleId}/singletonOne': {
get: {},
},
'/resource/{exampleId}/singletonTwo': {},
},
},
errors: [
{
code: 'xgen-IPA-113-singleton-should-have-update-method',
message:
'Singleton resources should define the Update method. If this is not a singleton resource, please implement all CRUDL methods.',
path: ['paths', '/resource/{exampleId}/singletonOne'],
severity: DiagnosticSeverity.Warning,
},
{
code: 'xgen-IPA-113-singleton-should-have-update-method',
message:
'Singleton resources should define the Update method. If this is not a singleton resource, please implement all CRUDL methods.',
path: ['paths', '/resource/{exampleId}/singletonTwo'],
severity: DiagnosticSeverity.Warning,
},
],
},
{
name: 'invalid resources with exceptions',
document: {
paths: {
'/resource/{exampleId}/singletonOne': {
get: {},
'x-xgen-IPA-exception': {
'xgen-IPA-113-singleton-should-have-update-method': 'reason',
},
},
'/resource/{exampleId}/singletonTwo': {
'x-xgen-IPA-exception': {
'xgen-IPA-113-singleton-should-have-update-method': 'reason',
},
},
},
},
errors: [],
},
]);
28 changes: 28 additions & 0 deletions tools/spectral/ipa/rulesets/IPA-113.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

functions:
- IPA113SingletonHasNoId
- IPA113SingletonHasNoDeleteMethod
- IPA113SingletonHasUpdateMethod

rules:
xgen-IPA-113-singleton-must-not-have-id:
Expand All @@ -21,3 +23,29 @@ rules:
given: '$.paths[*]'
then:
function: 'IPA113SingletonHasNoId'
xgen-IPA-113-singleton-must-not-have-delete-method:
description: |
Singleton resources must not define the Delete standard method.

##### Implementation details
Rule checks for the following conditions:
- Applies only to singleton resources
- Checks that the resource does not have a DELETE method defined
message: '{{error}} https://mdb.link/mongodb-atlas-openapi-validation#xgen-IPA-113-singleton-must-not-have-delete-method'
severity: warn
given: '$.paths[*]'
then:
function: 'IPA113SingletonHasNoDeleteMethod'
xgen-IPA-113-singleton-should-have-update-method:
description: |
Singleton resources should define the Update method. Validation for the presence of Get method is covered by IPA-104 (see [xgen-IPA-104-resource-has-GET](https://mdb.link/mongodb-atlas-openapi-validation#xgen-IPA-104-resource-has-GET)).

##### Implementation details
Rule checks for the following conditions:
- Applies only to singleton resources
- Checks that the resource has the PUT and/or PATCH methods defined
message: '{{error}} https://mdb.link/mongodb-atlas-openapi-validation#xgen-IPA-113-singleton-should-have-update-method'
severity: warn
given: '$.paths[*]'
then:
function: 'IPA113SingletonHasUpdateMethod'
20 changes: 20 additions & 0 deletions tools/spectral/ipa/rulesets/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,26 @@ Rule checks for the following conditions:
- Verifies that no schema contains 'id' or '_id' properties in their object definitions
- Fails if any response schema contains these identifier properties

#### xgen-IPA-113-singleton-must-not-have-delete-method

![warn](https://img.shields.io/badge/warning-yellow)
Singleton resources must not define the Delete standard method.

##### Implementation details
Rule checks for the following conditions:
- Applies only to singleton resources
- Checks that the resource does not have a DELETE method defined

#### xgen-IPA-113-singleton-should-have-update-method

![warn](https://img.shields.io/badge/warning-yellow)
Singleton resources should define the Update method. Validation for the presence of Get method is covered by IPA-104 (see [xgen-IPA-104-resource-has-GET](https://mdb.link/mongodb-atlas-openapi-validation#xgen-IPA-104-resource-has-GET)).

##### Implementation details
Rule checks for the following conditions:
- Applies only to singleton resources
- Checks that the resource has the PUT and/or PATCH methods defined



### IPA-123
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import {
getResourcePathItems,
isSingletonResource,
isResourceCollectionIdentifier,
hasDeleteMethod,
} from './utils/resourceEvaluation.js';
import { hasException } from './utils/exceptions.js';
import {
collectAdoption,
collectAndReturnViolation,
collectException,
handleInternalError,
} from './utils/collectionUtils.js';

const RULE_NAME = 'xgen-IPA-113-singleton-must-not-have-delete-method';
const ERROR_MESSAGE =
'Singleton resources must not define the Delete standard method. If this is not a singleton resource, please implement all CRUDL methods.';

export default (input, opts, { path, documentInventory }) => {
const oas = documentInventory.resolved;
const resourcePath = path[1];
const resourcePathItems = getResourcePathItems(resourcePath, oas.paths);

if (!(isResourceCollectionIdentifier(resourcePath) && isSingletonResource(resourcePathItems))) {
return;
}

if (hasException(input, RULE_NAME)) {
collectException(input, RULE_NAME, path);
return;
}

const errors = checkViolationsAndReturnErrors(input, path);
if (errors.length !== 0) {
return collectAndReturnViolation(path, RULE_NAME, errors);
}
collectAdoption(path, RULE_NAME);
};

function checkViolationsAndReturnErrors(input, path) {
try {
if (hasDeleteMethod(input)) {
return [{ path, message: ERROR_MESSAGE }];
}
return [];
} catch (e) {
handleInternalError(RULE_NAME, path, e);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import {
getResourcePathItems,
isSingletonResource,
isResourceCollectionIdentifier,
hasPutMethod,
hasPatchMethod,
} from './utils/resourceEvaluation.js';
import { hasException } from './utils/exceptions.js';
import {
collectAdoption,
collectAndReturnViolation,
collectException,
handleInternalError,
} from './utils/collectionUtils.js';

const RULE_NAME = 'xgen-IPA-113-singleton-should-have-update-method';
const ERROR_MESSAGE =
'Singleton resources should define the Update method. If this is not a singleton resource, please implement all CRUDL methods.';

export default (input, opts, { path, documentInventory }) => {
const oas = documentInventory.resolved;
const resourcePath = path[1];
const resourcePathItems = getResourcePathItems(resourcePath, oas.paths);

if (!(isResourceCollectionIdentifier(resourcePath) && isSingletonResource(resourcePathItems))) {
return;
}

if (hasException(input, RULE_NAME)) {
collectException(input, RULE_NAME, path);
return;
}

const errors = checkViolationsAndReturnErrors(input, path);
if (errors.length !== 0) {
return collectAndReturnViolation(path, RULE_NAME, errors);
}
collectAdoption(path, RULE_NAME);
};

function checkViolationsAndReturnErrors(input, path) {
try {
if (!(hasPutMethod(input) || hasPatchMethod(input))) {
return [{ path, message: ERROR_MESSAGE }];
}
return [];
} catch (e) {
handleInternalError(RULE_NAME, path, e);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,36 @@ export function hasPostMethod(pathObject) {
return Object.keys(pathObject).includes('post');
}

/**
* Checks if a path object has a DELETE method
*
* @param pathObject the path object to evaluate
* @returns {boolean}
*/
export function hasDeleteMethod(pathObject) {
return Object.keys(pathObject).includes('delete');
}

/**
* Checks if a path object has a PUT method
*
* @param pathObject the path object to evaluate
* @returns {boolean}
*/
export function hasPutMethod(pathObject) {
return Object.keys(pathObject).includes('put');
}

/**
* Checks if a path object has a PATCH method
*
* @param pathObject the path object to evaluate
* @returns {boolean}
*/
export function hasPatchMethod(pathObject) {
return Object.keys(pathObject).includes('patch');
}

/**
* Get all path items for a resource based on the path for the resource collection
* For example, resource collection path '/resource' may return path items for ['/resource', '/resource{id}', '/resource{id}:customMethod']
Expand Down
Loading