Skip to content

Commit be928d6

Browse files
authored
CLOUDP 328960: OperationID Validation function for :action custom methods (#815)
1 parent a900250 commit be928d6

File tree

9 files changed

+167
-12
lines changed

9 files changed

+167
-12
lines changed

tools/spectral/ipa/__tests__/IPA104ValidOperationID.test.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,14 @@ testRule('xgen-IPA-104-valid-operation-id', [
3838
{
3939
code: 'xgen-IPA-104-valid-operation-id',
4040
message:
41-
'Invalid OperationID. The Operation ID must start with the verb “get” and should be followed by a noun or compound noun. The noun(s) should be the collection identifiers from the resource identifier in singular form.',
41+
'Invalid OperationID. ',
4242
path: ['paths', '/api/atlas/v2/groups/{groupId}/accessList/{entryValue}/status', 'get'],
4343
severity: DiagnosticSeverity.Warning,
4444
},
4545
{
4646
code: 'xgen-IPA-104-valid-operation-id',
4747
message:
48-
'Invalid OperationID. The Operation ID must start with the verb “get” and should be followed by a noun or compound noun. The noun(s) should be the collection identifiers from the resource identifier in singular form.',
48+
'Invalid OperationID. ',
4949
path: ['paths', '/api/atlas/v2/groups/{groupId}/dataFederation/{tenantName}/limits/{limitName}', 'get'],
5050
severity: DiagnosticSeverity.Warning,
5151
},

tools/spectral/ipa/__tests__/IPA105ValidOperationID.test.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,14 @@ testRule('xgen-IPA-105-valid-operation-id', [
3838
{
3939
code: 'xgen-IPA-105-valid-operation-id',
4040
message:
41-
'Invalid OperationID. The Operation ID must start with the verb “list” and should be followed by a noun or compound noun. The noun(s) should be the collection identifiers from the resource identifier in singular form, where the last noun is in plural form.',
41+
'Invalid OperationID. ',
4242
path: ['paths', '/api/atlas/v2/groups/{groupId}/databaseUsers/{username}/certs', 'get'],
4343
severity: DiagnosticSeverity.Warning,
4444
},
4545
{
4646
code: 'xgen-IPA-105-valid-operation-id',
4747
message:
48-
'Invalid OperationID. The Operation ID must start with the verb “list” and should be followed by a noun or compound noun. The noun(s) should be the collection identifiers from the resource identifier in singular form, where the last noun is in plural form.',
48+
'Invalid OperationID. ',
4949
path: ['paths', '/api/atlas/v2/orgs/{orgId}/events', 'get'],
5050
severity: DiagnosticSeverity.Warning,
5151
},

tools/spectral/ipa/__tests__/IPA106ValidOperationID.test.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,14 @@ testRule('xgen-IPA-106-valid-operation-id', [
3838
{
3939
code: 'xgen-IPA-106-valid-operation-id',
4040
message:
41-
'Invalid OperationID. The Operation ID must start with the verb “create” and should be followed by a noun or compound noun. The noun(s) in the Operation ID should be the collection identifiers from the resource identifier in singular form. ',
41+
'Invalid OperationID. ',
4242
path: ['paths', '/api/atlas/v2/groups/{groupId}/access', 'post'],
4343
severity: DiagnosticSeverity.Warning,
4444
},
4545
{
4646
code: 'xgen-IPA-106-valid-operation-id',
4747
message:
48-
'Invalid OperationID. The Operation ID must start with the verb “create” and should be followed by a noun or compound noun. The noun(s) in the Operation ID should be the collection identifiers from the resource identifier in singular form. ',
48+
'Invalid OperationID. ',
4949
path: ['paths', '/api/atlas/v2/groups/{groupId}/invites', 'post'],
5050
severity: DiagnosticSeverity.Warning,
5151
},

tools/spectral/ipa/__tests__/IPA107ValidOperationID.test.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,14 @@ testRule('xgen-IPA-107-valid-operation-id', [
4343
{
4444
code: 'xgen-IPA-107-valid-operation-id',
4545
message:
46-
'Invalid OperationID. The Operation ID must start with the verb “update” and should be followed by a noun or compound noun. The noun(s) in the Operation ID should be the collection identifiers from the resource identifier in singular form. For singleton resources - the last noun may be in plural form.',
46+
'Invalid OperationID. ',
4747
path: ['paths', '/api/atlas/v2/groups/{groupId}/limits/{limitName}', 'patch'],
4848
severity: DiagnosticSeverity.Warning,
4949
},
5050
{
5151
code: 'xgen-IPA-107-valid-operation-id',
5252
message:
53-
'Invalid OperationID. The Operation ID must start with the verb “update” and should be followed by a noun or compound noun. The noun(s) in the Operation ID should be the collection identifiers from the resource identifier in singular form. For singleton resources - the last noun may be in plural form.',
53+
'Invalid OperationID. ',
5454
path: ['paths', '/api/atlas/v2/groups/{groupId}/settings', 'put'],
5555
severity: DiagnosticSeverity.Warning,
5656
},

tools/spectral/ipa/__tests__/IPA108ValidOperationID.test.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,13 @@ testRule('xgen-IPA-108-valid-operation-id', [
3737
errors: [
3838
{
3939
code: 'xgen-IPA-108-valid-operation-id',
40-
message:
41-
'Invalid OperationID. The Operation ID must start with the verb “delete” and should be followed by a noun or compound noun. The noun(s) in the Operation ID should be the collection identifiers from the resource identifier in singular form. ',
40+
message: 'Invalid OperationID. ',
4241
path: ['paths', '/api/atlas/v2/groups/{groupId}/apiKeys/{apiUserId}', 'delete'],
4342
severity: DiagnosticSeverity.Warning,
4443
},
4544
{
4645
code: 'xgen-IPA-108-valid-operation-id',
47-
message:
48-
'Invalid OperationID. The Operation ID must start with the verb “delete” and should be followed by a noun or compound noun. The noun(s) in the Operation ID should be the collection identifiers from the resource identifier in singular form. ',
46+
message: 'Invalid OperationID. ',
4947
path: ['paths', '/api/atlas/v2/groups/{groupId}', 'delete'],
5048
severity: DiagnosticSeverity.Warning,
5149
},
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import testRule from './__helpers__/testRule';
2+
3+
// TODO: add tests for xgen-custom-method extension - CLOUDP-306294
4+
// TOOD: enable tests for invalid methods (after rules are upgraded to warning) - CLOUDP-329722
5+
6+
testRule('xgen-IPA-109-valid-operation-id', [
7+
{
8+
name: 'valid methods',
9+
document: {
10+
paths: {
11+
'/groups/{groupId}/clusters/{clusterName}:pause': {
12+
post: {
13+
operationId: 'pauseGroupCluster',
14+
},
15+
},
16+
'/groups/{groupId}/clusters/{clusterName}:addNode': {
17+
post: {
18+
operationId: 'addGroupClusterNode',
19+
},
20+
},
21+
},
22+
},
23+
errors: [],
24+
},
25+
// This test will be enable when the xgen-IPA-109-valid-operation-id is set to warning severity - CLOUDP-329722
26+
/* {
27+
name: 'invalid methods',
28+
document: {
29+
paths: {
30+
'/api/atlas/v2/groups/{groupId}/clusters:search': {
31+
post: {
32+
operationId: 'searchClusters',
33+
},
34+
},
35+
'/api/atlas/v2/groups/{groupId}:migrate': {
36+
post: {
37+
operationId: 'migrateProjectToAnotherOrg',
38+
},
39+
},
40+
},
41+
},
42+
errors: [
43+
{
44+
code: 'xgen-IPA-109-valid-operation-id',
45+
message:
46+
'Invalid OperationID. ',
47+
path: ['paths', '/api/atlas/v2/groups/{groupId}/clusters:search'],
48+
severity: DiagnosticSeverity.Warning,
49+
},
50+
{
51+
code: 'xgen-IPA-109-valid-operation-id',
52+
message:
53+
'Invalid OperationID. ',
54+
path: ['paths', '/api/atlas/v2/groups/{groupId}:migrate'],
55+
severity: DiagnosticSeverity.Warning,
56+
},
57+
],
58+
}, */
59+
{
60+
name: 'invalid methods with exceptions',
61+
document: {
62+
paths: {
63+
'/api/atlas/v2/orgs/{orgId}/users/{userId}:addRole': {
64+
post: {
65+
operationId: 'addOrgRole',
66+
'x-xgen-IPA-exception': {
67+
'xgen-IPA-109-valid-operation-id': 'Reason',
68+
},
69+
},
70+
},
71+
},
72+
},
73+
errors: [],
74+
},
75+
]);

tools/spectral/ipa/rulesets/IPA-109.yaml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ functions:
55
- IPA109EachCustomMethodMustBeGetOrPost
66
- IPA109EachCustomMethodMustUseCamelCase
77
- IPA109CustomMethodIdentifierFormat
8+
- IPA109ValidOperationID
89

910
rules:
1011
xgen-IPA-109-custom-method-must-be-GET-or-POST:
@@ -56,3 +57,22 @@ rules:
5657
given: '$.paths[*]'
5758
then:
5859
function: 'IPA109CustomMethodIdentifierFormat'
60+
xgen-IPA-109-valid-operation-id:
61+
description: |
62+
The Operation ID must start with the custom method verb (the custom method path section delimited by the colon (:) character) and should be followed by a noun or compound noun.
63+
If the custom Operation ID has a verb + noun, the Operation ID should end with the noun.
64+
The noun(s) in the Operation ID should be the collection identifiers from the resource identifier.
65+
The noun(s) in the Operation ID should be the collection identifiers from the resource identifier in singular form, where the last noun:
66+
- Is in plural form if the method applies to a collection of resources
67+
- Is in singular form if the method applies to a single resource
68+
69+
##### Implementation details
70+
Rule checks for the following conditions:
71+
- Applies only to paths containing custom method identifiers (with colon format)
72+
- Generates the expected OperationId given the resource identifier and the method name portion following the colon
73+
- Confirms that the existing operationId is compliant with generated IPA Compliant OperationId
74+
message: '{{error}} https://mdb.link/mongodb-atlas-openapi-validation#xgen-IPA-109-valid-operation-id'
75+
severity: off
76+
given: '$.paths[*]'
77+
then:
78+
function: 'IPA109ValidOperationID'

tools/spectral/ipa/rulesets/README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,22 @@ Rule checks for the following conditions:
496496
- Fails if multiple colons appear in the path
497497
- Fails if other than an alphabetical character or a closing curly brace appears before a colon
498498

499+
#### xgen-IPA-109-valid-operation-id
500+
501+
`off`
502+
The Operation ID must start with the custom method verb (the custom method path section delimited by the colon (:) character) and should be followed by a noun or compound noun.
503+
If the custom Operation ID has a verb + noun, the Operation ID should end with the noun.
504+
The noun(s) in the Operation ID should be the collection identifiers from the resource identifier.
505+
The noun(s) in the Operation ID should be the collection identifiers from the resource identifier in singular form, where the last noun:
506+
- Is in plural form if the method applies to a collection of resources
507+
- Is in singular form if the method applies to a single resource
508+
509+
##### Implementation details
510+
Rule checks for the following conditions:
511+
- Applies only to paths containing custom method identifiers (with colon format)
512+
- Generates the expected OperationId given the resource identifier and the method name portion following the colon
513+
- Confirms that the existing operationId is compliant with generated IPA Compliant OperationId
514+
499515

500516

501517
### IPA-110
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { hasException } from './utils/exceptions.js';
2+
import { collectAdoption, collectException, collectAndReturnViolation } from './utils/collectionUtils.js';
3+
import { isCustomMethodIdentifier, getCustomMethodName, stripCustomMethodName } from './utils/resourceEvaluation.js';
4+
import { generateOperationID } from './utils/operationIdGeneration.js';
5+
6+
const RULE_NAME = 'xgen-IPA-109-valid-operation-id';
7+
const ERROR_MESSAGE = 'Invalid OperationID.';
8+
9+
export default (input, _, { path }) => {
10+
let resourcePath = path[1];
11+
const methodName = getCustomMethodName(resourcePath);
12+
13+
if (!isCustomMethodIdentifier(resourcePath)) {
14+
return;
15+
}
16+
17+
// TODO detect custom method extension - CLOUDP-306294
18+
19+
let obj;
20+
if (input.post) {
21+
obj = input.post;
22+
} else if (input.get) {
23+
obj = input.get;
24+
} else {
25+
return;
26+
}
27+
28+
if (hasException(obj, RULE_NAME)) {
29+
collectException(obj, RULE_NAME, path);
30+
return;
31+
}
32+
33+
const operationId = obj.operationId;
34+
const expectedOperationID = generateOperationID(methodName, stripCustomMethodName(resourcePath));
35+
if (expectedOperationID !== operationId) {
36+
const errors = [
37+
{
38+
path,
39+
message: `${ERROR_MESSAGE} Found ${operationId}, expected ${expectedOperationID}.`,
40+
},
41+
];
42+
return collectAndReturnViolation(path, RULE_NAME, errors);
43+
}
44+
45+
collectAdoption(path, RULE_NAME);
46+
};

0 commit comments

Comments
 (0)