Skip to content

Commit 659e9ca

Browse files
authored
CLOUDP 328955: OperationID Validation functions for Get and List methods (#814)
1 parent a6e2853 commit 659e9ca

File tree

10 files changed

+295
-9
lines changed

10 files changed

+295
-9
lines changed
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
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-104-valid-operation-id', [
7+
{
8+
name: 'valid methods',
9+
document: {
10+
paths: {
11+
'/groups/{groupId}/cluster/{clusterName}': {
12+
get: {
13+
operationId: 'getGroupCluster',
14+
},
15+
},
16+
},
17+
},
18+
errors: [],
19+
},
20+
// This test will be enable when the xgen-IPA-104-valid-operation-id is set to warning severity - CLOUDP-329722
21+
/* {
22+
name: 'invalid methods',
23+
document: {
24+
paths: {
25+
'/api/atlas/v2/groups/{groupId}/accessList/{entryValue}/status': {
26+
get: {
27+
operationId: 'getProjectIpAccessListStatus',
28+
},
29+
},
30+
'/api/atlas/v2/groups/{groupId}/dataFederation/{tenantName}/limits/{limitName}': {
31+
get: {
32+
operationId: 'returnFederatedDatabaseQueryLimit',
33+
},
34+
},
35+
},
36+
},
37+
errors: [
38+
{
39+
code: 'xgen-IPA-104-valid-operation-id',
40+
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.',
42+
path: ['paths', '/api/atlas/v2/groups/{groupId}/accessList/{entryValue}/status', 'get'],
43+
severity: DiagnosticSeverity.Warning,
44+
},
45+
{
46+
code: 'xgen-IPA-104-valid-operation-id',
47+
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.',
49+
path: ['paths', '/api/atlas/v2/groups/{groupId}/dataFederation/{tenantName}/limits/{limitName}', 'get'],
50+
severity: DiagnosticSeverity.Warning,
51+
},
52+
],
53+
}, */
54+
{
55+
name: 'invalid methods with exceptions',
56+
document: {
57+
paths: {
58+
'/api/atlas/v2/groups/{groupId}/clusters/{clusterName}/index ': {
59+
get: {
60+
operationId: 'getRollingIndex',
61+
'x-xgen-IPA-exception': {
62+
'xgen-IPA-104-valid-operation-id': 'Reason',
63+
},
64+
},
65+
},
66+
},
67+
},
68+
errors: [],
69+
},
70+
]);
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
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-105-valid-operation-id', [
7+
{
8+
name: 'valid methods',
9+
document: {
10+
paths: {
11+
'/groups/{groupId}/clusters': {
12+
get: {
13+
operationId: 'listGroupClusters',
14+
},
15+
},
16+
},
17+
},
18+
errors: [],
19+
},
20+
// This test will be enable when the xgen-IPA-105-valid-operation-id is set to warning severity - CLOUDP-329722
21+
/* {
22+
name: 'invalid methods',
23+
document: {
24+
paths: {
25+
'/api/atlas/v2/orgs/{orgId}/teams/{teamId}/users': {
26+
get: {
27+
operationId: 'listTeamUsers',
28+
},
29+
},
30+
'/api/atlas/v2/orgs/{orgId}/events': {
31+
get: {
32+
operationId: 'listOrganizationEvents',
33+
},
34+
},
35+
},
36+
},
37+
errors: [
38+
{
39+
code: 'xgen-IPA-105-valid-operation-id',
40+
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.',
42+
path: ['paths', '/api/atlas/v2/groups/{groupId}/databaseUsers/{username}/certs', 'get'],
43+
severity: DiagnosticSeverity.Warning,
44+
},
45+
{
46+
code: 'xgen-IPA-105-valid-operation-id',
47+
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.',
49+
path: ['paths', '/api/atlas/v2/orgs/{orgId}/events', 'get'],
50+
severity: DiagnosticSeverity.Warning,
51+
},
52+
],
53+
}, */
54+
{
55+
name: 'invalid methods with exceptions',
56+
document: {
57+
paths: {
58+
'/api/atlas/v2/groups/{groupId}/clusters/{clusterName}/outageSimulation': {
59+
get: {
60+
operationId: 'getOutageSimulation',
61+
'x-xgen-IPA-exception': {
62+
'xgen-IPA-105-valid-operation-id': 'Reason',
63+
},
64+
},
65+
},
66+
},
67+
},
68+
errors: [],
69+
},
70+
]);

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

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ functions:
88
- IPA104GetResponseCodeShouldBe200OK
99
- IPA104GetMethodResponseHasNoInputFields
1010
- IPA104GetMethodHasNoRequestBody
11+
- IPA104ValidOperationID
1112

1213
aliases:
1314
GetOperationObject:
@@ -97,3 +98,21 @@ rules:
9798
given: '#GetOperationObject'
9899
then:
99100
function: 'IPA104GetMethodHasNoRequestBody'
101+
xgen-IPA-104-valid-operation-id:
102+
description: |
103+
The Operation ID must start with the verb “get” and should be followed by a noun or compound noun.
104+
The noun(s) in the Operation ID should be the collection identifiers from the resource identifier in singular form.
105+
If the resource is a singleton resource, the last noun may be the plural form of the collection identifier.
106+
107+
##### Implementation details
108+
Rule checks for the following conditions:
109+
- Applies only to GET methods on single resources or singleton resources
110+
- Generates the expected OperationId given the resource identifier
111+
- Confirms that the existing operationId is compliant with generated IPA Compliant OperationId
112+
message: '{{error}} https://mdb.link/mongodb-atlas-openapi-validation#xgen-IPA-104-valid-operation-id'
113+
severity: off
114+
given: '#GetOperationObject'
115+
then:
116+
function: 'IPA104ValidOperationID'
117+
functionOptions:
118+
methodName: 'get'

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

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ functions:
66
- IPA105ListMethodHasNoRequestBody
77
- IPA105EachResourceHasListMethod
88
- IPA105ListMethodResponseIsGetMethodResponse
9+
- IPA105ValidOperationID
910

1011
aliases:
1112
GetOperationObject:
@@ -77,3 +78,21 @@ rules:
7778
then:
7879
field: '@key'
7980
function: 'IPA105ListMethodResponseIsGetMethodResponse'
81+
xgen-IPA-105-valid-operation-id:
82+
description: |
83+
The Operation ID must start with the verb “list” and should be followed by a noun or compound noun.
84+
The noun(s) in the Operation ID should be the collection identifiers from the resource identifier in singular form, where the last noun is in plural form.
85+
86+
##### Implementation details
87+
Rule checks for the following conditions:
88+
- Applies only to GET methods on resource collection paths
89+
- Ignores singleton resources
90+
- Generates the expected OperationId given the resource identifier
91+
- Confirms that the existing operationId is compliant with generated IPA Compliant OperationId
92+
message: '{{error}} https://mdb.link/mongodb-atlas-openapi-validation#xgen-IPA-105-valid-operation-id'
93+
severity: off
94+
given: '#GetOperationObject'
95+
then:
96+
function: 'IPA105ValidOperationID'
97+
functionOptions:
98+
methodName: 'list'

tools/spectral/ipa/rulesets/README.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,19 @@ Rule checks for the following conditions:
139139
- Applies only to GET methods on single resources or singleton resources
140140
- Verifies that the operation object does not contain a requestBody property
141141

142+
#### xgen-IPA-104-valid-operation-id
143+
144+
`off`
145+
The Operation ID must start with the verb “get” and should be followed by a noun or compound noun.
146+
The noun(s) in the Operation ID should be the collection identifiers from the resource identifier in singular form.
147+
If the resource is a singleton resource, the last noun may be the plural form of the collection identifier.
148+
149+
##### Implementation details
150+
Rule checks for the following conditions:
151+
- Applies only to GET methods on single resources or singleton resources
152+
- Generates the expected OperationId given the resource identifier
153+
- Confirms that the existing operationId is compliant with generated IPA Compliant OperationId
154+
142155

143156

144157
### IPA-105
@@ -193,6 +206,19 @@ The response body of the List method should consist of the same resource object
193206
- Fails if the Get method doesn't have a schema reference or if the schemas don't match
194207
- Validation ignores resources without a Get method
195208
- Paths with `x-xgen-IPA-exception` for this rule are excluded from validation
209+
#### xgen-IPA-105-valid-operation-id
210+
211+
`off`
212+
The Operation ID must start with the verb “list” and should be followed by a noun or compound noun.
213+
The noun(s) in the Operation ID should be the collection identifiers from the resource identifier in singular form, where the last noun is in plural form.
214+
215+
##### Implementation details
216+
Rule checks for the following conditions:
217+
- Applies only to GET methods on resource collection paths
218+
- Ignores singleton resources
219+
- Generates the expected OperationId given the resource identifier
220+
- Confirms that the existing operationId is compliant with generated IPA Compliant OperationId
221+
196222

197223

198224
### IPA-106
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { generateOperationID } from './utils/operationIdGeneration.js';
2+
import { collectAdoption, collectAndReturnViolation, collectException } from './utils/collectionUtils.js';
3+
import { hasException } from './utils/exceptions.js';
4+
import {
5+
isSingleResourceIdentifier,
6+
isResourceCollectionIdentifier,
7+
isSingletonResource,
8+
getResourcePathItems,
9+
isCustomMethodIdentifier,
10+
} from './utils/resourceEvaluation.js';
11+
12+
const RULE_NAME = 'xgen-IPA-104-valid-operation-id';
13+
const ERROR_MESSAGE = 'Invalid OperationID.';
14+
15+
export default (input, { methodName }, { path, documentInventory }) => {
16+
const resourcePath = path[1];
17+
const oas = documentInventory.resolved;
18+
const resourcePaths = getResourcePathItems(resourcePath, oas.paths);
19+
20+
if (
21+
isCustomMethodIdentifier(resourcePath) ||
22+
(!isSingleResourceIdentifier(resourcePath) &&
23+
!(isResourceCollectionIdentifier(resourcePath) && isSingletonResource(resourcePaths)))
24+
) {
25+
return;
26+
}
27+
28+
if (hasException(input, RULE_NAME)) {
29+
collectException(input, RULE_NAME, path);
30+
return;
31+
}
32+
33+
const expectedOperationId = generateOperationID(methodName, resourcePath);
34+
if (expectedOperationId !== input.operationId) {
35+
const errors = [
36+
{
37+
path,
38+
message: `${ERROR_MESSAGE} Found ${input.operationId}, expected ${expectedOperationId}.`,
39+
},
40+
];
41+
return collectAndReturnViolation(path, RULE_NAME, errors);
42+
}
43+
44+
return collectAdoption(path, RULE_NAME);
45+
};
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { hasException } from './utils/exceptions.js';
2+
import { collectAdoption, collectAndReturnViolation, collectException } from './utils/collectionUtils.js';
3+
import {
4+
getResourcePathItems,
5+
isCustomMethodIdentifier,
6+
isResourceCollectionIdentifier,
7+
isSingletonResource,
8+
} from './utils/resourceEvaluation.js';
9+
import { generateOperationID } from './utils/operationIdGeneration.js';
10+
11+
const RULE_NAME = 'xgen-IPA-105-valid-operation-id';
12+
const ERROR_MESSAGE = 'Invalid OperationID.';
13+
14+
export default (input, { methodName }, { path, documentInventory }) => {
15+
const resourcePath = path[1];
16+
const oas = documentInventory.resolved;
17+
18+
if (
19+
isCustomMethodIdentifier(resourcePath) ||
20+
!isResourceCollectionIdentifier(resourcePath) ||
21+
isSingletonResource(getResourcePathItems(resourcePath, oas.paths))
22+
) {
23+
return;
24+
}
25+
26+
if (hasException(input, RULE_NAME)) {
27+
collectException(input, RULE_NAME, path);
28+
return;
29+
}
30+
31+
const expectedOperationId = generateOperationID(methodName, resourcePath);
32+
if (expectedOperationId !== input.operationId) {
33+
const errors = [
34+
{
35+
path,
36+
message: `${ERROR_MESSAGE} Found ${input.operationId}, expected ${expectedOperationId}.`,
37+
},
38+
];
39+
return collectAndReturnViolation(path, RULE_NAME, errors);
40+
}
41+
42+
return collectAdoption(path, RULE_NAME);
43+
};

tools/spectral/ipa/rulesets/functions/IPA106ValidOperationID.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,7 @@ import {
99
import { generateOperationID } from './utils/operationIdGeneration.js';
1010

1111
const RULE_NAME = 'xgen-IPA-106-valid-operation-id';
12-
const ERROR_MESSAGE =
13-
'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.';
12+
const ERROR_MESSAGE = 'Invalid OperationID.';
1413

1514
export default (input, { methodName }, { path, documentInventory }) => {
1615
const resourcePath = path[1];

tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@ import {
1010
import { generateOperationID } from './utils/operationIdGeneration.js';
1111

1212
const RULE_NAME = 'xgen-IPA-107-valid-operation-id';
13-
const ERROR_MESSAGE =
14-
'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.';
13+
const ERROR_MESSAGE = 'Invalid OperationID.';
1514

1615
export default (input, { methodName }, { path, documentInventory }) => {
1716
const resourcePath = path[1];
@@ -33,9 +32,6 @@ export default (input, { methodName }, { path, documentInventory }) => {
3332

3433
const expectedOperationID = generateOperationID(methodName, resourcePath);
3534
if (expectedOperationID !== input.operationId) {
36-
console.log(
37-
`${input.operationId}, ${expectedOperationID}, ${resourcePath}, ${input.deprecated ? 'TRUE' : 'FALSE'}, ${(resourcePath, input['x-xgen-owner-team'])}`
38-
);
3935
const errors = [
4036
{
4137
path,

tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@ import { isCustomMethodIdentifier, isSingleResourceIdentifier } from './utils/re
44
import { generateOperationID } from './utils/operationIdGeneration.js';
55

66
const RULE_NAME = 'xgen-IPA-108-valid-operation-id';
7-
const ERROR_MESSAGE =
8-
'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.';
7+
const ERROR_MESSAGE = 'Invalid OperationID.';
98

109
export default (input, { methodName }, { path }) => {
1110
const resourcePath = path[1];

0 commit comments

Comments
 (0)