Skip to content

Commit ed93697

Browse files
CLOUDP-283086: Restructuring and experiment with exceptions
1 parent 24bf86c commit ed93697

File tree

4 files changed

+118
-76
lines changed

4 files changed

+118
-76
lines changed

openapi/v2.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47360,6 +47360,9 @@ paths:
4736047360
- Service Accounts
4736147361
x-xgen-owner-team: apix
4736247362
/api/atlas/v2/groups/{groupId}/serviceAccounts/{clientId}/accessList:
47363+
x-xgen-IPA-exception:
47364+
xgen-IPA-104-resource-has-GET:
47365+
reason: "Testing"
4736347366
get:
4736447367
description: Returns all access list entries that you configured for the specified Service Account for the project. Available as a preview feature.
4736547368
operationId: listProjectServiceAccountAccessList
@@ -47485,6 +47488,9 @@ paths:
4748547488
- Service Accounts
4748647489
x-xgen-owner-team: apix
4748747490
/api/atlas/v2/groups/{groupId}/serviceAccounts/{clientId}/secrets:
47491+
x-xgen-IPA-exception:
47492+
xgen-IPA-104-resource-has-GET:
47493+
reason: "Testing"
4748847494
post:
4748947495
description: Create a secret for the specified Service Account in the specified Project. Available as a preview feature.
4749047496
operationId: createProjectServiceAccountSecret
@@ -51065,6 +51071,9 @@ paths:
5106551071
- Service Accounts
5106651072
x-xgen-owner-team: apix
5106751073
/api/atlas/v2/orgs/{orgId}/serviceAccounts/{clientId}/accessList:
51074+
x-xgen-IPA-exception:
51075+
xgen-IPA-104-resource-has-GET:
51076+
reason: "Testing"
5106851077
get:
5106951078
description: Returns all access list entries that you configured for the specified Service Account for the organization. Available as a preview feature.
5107051079
operationId: listServiceAccountAccessList
@@ -51226,6 +51235,9 @@ paths:
5122651235
- Service Accounts
5122751236
x-xgen-owner-team: apix
5122851237
/api/atlas/v2/orgs/{orgId}/serviceAccounts/{clientId}/secrets:
51238+
x-xgen-IPA-exception:
51239+
xgen-IPA-104-resource-has-GET:
51240+
reason: "Testing"
5122951241
post:
5123051242
description: Create a secret for the specified Service Account. Available as a preview feature.
5123151243
operationId: createServiceAccountSecret
Lines changed: 28 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,95 +1,47 @@
1-
const ERROR_MESSAGE = "APIs must provide a get method for resources."
1+
import { hasExemption } from './utils/exemptions.js';
2+
import {
3+
hasGetMethod,
4+
isChild,
5+
isCustomMethod,
6+
isStandardResource,
7+
isSingletonResource,
8+
getResourcePaths,
9+
} from './utils/resourceEvaluation.js';
10+
11+
const RULE_NAME = 'xgen-IPA-104-resource-has-GET';
12+
const ERROR_MESSAGE = 'APIs must provide a get method for resources.';
213

314
export default (input, _, context) => {
415
if (isChild(input) || isCustomMethod(input)) {
5-
return
16+
return;
617
}
718

8-
const oas = context.documentInventory.resolved
19+
const oas = context.documentInventory.resolved;
20+
const resourceObject = oas.paths[input];
921

10-
const resourcePaths = getResourcePaths(input, Object.keys(oas.paths))
22+
if (hasExemption(RULE_NAME, resourceObject)) {
23+
return;
24+
}
25+
26+
const resourcePaths = getResourcePaths(input, Object.keys(oas.paths));
1127

1228
if (isSingletonResource(resourcePaths)) {
1329
// Singleton resource, may have custom methods
1430
if (!hasGetMethod(oas.paths[resourcePaths[0]])) {
1531
return [
1632
{
17-
message: ERROR_MESSAGE
18-
}
19-
]
33+
message: ERROR_MESSAGE,
34+
},
35+
];
2036
}
21-
} else if (isNormalResource(resourcePaths)) {
37+
} else if (isStandardResource(resourcePaths)) {
2238
// Normal resource, may have custom methods
2339
if (!hasGetMethod(oas.paths[resourcePaths[1]])) {
2440
return [
2541
{
26-
message: ERROR_MESSAGE
27-
}
28-
]
42+
message: ERROR_MESSAGE,
43+
},
44+
];
2945
}
3046
}
31-
}
32-
33-
function isChild(path) {
34-
return path.endsWith("}")
35-
}
36-
37-
function isCustomMethod(path) {
38-
return path.includes(":")
39-
}
40-
41-
/**
42-
* Get all paths for a resource based on the parent path
43-
*
44-
* @param parent the parent path string
45-
* @param allPaths all paths as an array of strings
46-
* @returns {*} a string array of all paths for a resource, including the parent
47-
*/
48-
function getResourcePaths(parent, allPaths) {
49-
const childPathPattern = new RegExp(`^${parent}/{[a-zA-Z]+}$`);
50-
const customMethodPattern = new RegExp(`^${parent}/{[a-zA-Z]+}:+[a-zA-Z]+$`);
51-
return allPaths.filter(p => parent === p || childPathPattern.test(p) || customMethodPattern.test(p));
52-
}
53-
54-
/**
55-
* Checks if a resource is a singleton resource based on the paths for the
56-
* resource. The resource may have custom methods.
57-
*
58-
* @param resourcePaths all paths for the resource as an array of strings
59-
* @returns {boolean}
60-
*/
61-
function isSingletonResource(resourcePaths) {
62-
if (resourcePaths.length === 1) {
63-
return true
64-
}
65-
const additionalPaths = resourcePaths.slice(1)
66-
return !additionalPaths.some((p) => !isCustomMethod(p))
67-
}
68-
69-
/**
70-
* Checks if a resource is a normal resource based on the paths for the
71-
* resource. The resource may have custom methods.
72-
*
73-
* @param resourcePaths all paths for the resource as an array of strings
74-
* @returns {boolean}
75-
*/
76-
function isNormalResource(resourcePaths) {
77-
if (resourcePaths.length === 2 && isChild(resourcePaths[1])) {
78-
return true
79-
}
80-
if (resourcePaths.length < 3 || !isChild(resourcePaths[1])) {
81-
return false
82-
}
83-
const additionalPaths = resourcePaths.slice(2)
84-
return !additionalPaths.some((p) => !isCustomMethod(p))
85-
}
86-
87-
/**
88-
* Checks if a path object has a GET method
89-
*
90-
* @param pathObject the path object to evaluate
91-
* @returns {boolean}
92-
*/
93-
function hasGetMethod(pathObject) {
94-
return Object.keys(pathObject).some((o) => o === "get")
95-
}
47+
};
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
const EXEMPTION_EXTENSION = 'x-xgen-IPA-exception';
2+
3+
/**
4+
* Checks if the object has an exemption set for the passed rule name by checking
5+
* if the object has a field "x-xgen-IPA-exception" containing the rule as a
6+
* field.
7+
*
8+
* @param ruleName the name of the exemption
9+
* @param object the object to evaluate
10+
* @returns {boolean}
11+
*/
12+
export function hasExemption(ruleName, object) {
13+
const exemptions = object[EXEMPTION_EXTENSION];
14+
return exemptions !== undefined && Object.keys(exemptions).includes(ruleName);
15+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
export function isChild(path) {
2+
return path.endsWith('}');
3+
}
4+
5+
export function isCustomMethod(path) {
6+
return path.includes(':');
7+
}
8+
9+
/**
10+
* Checks if a resource is a singleton resource based on the paths for the
11+
* resource. The resource may have custom methods.
12+
*
13+
* @param resourcePaths all paths for the resource as an array of strings
14+
* @returns {boolean}
15+
*/
16+
export function isSingletonResource(resourcePaths) {
17+
if (resourcePaths.length === 1) {
18+
return true;
19+
}
20+
const additionalPaths = resourcePaths.slice(1);
21+
return !additionalPaths.some((p) => !isCustomMethod(p));
22+
}
23+
24+
/**
25+
* Checks if a resource is a standard resource based on the paths for the
26+
* resource. The resource may have custom methods.
27+
*
28+
* @param resourcePaths all paths for the resource as an array of strings
29+
* @returns {boolean}
30+
*/
31+
export function isStandardResource(resourcePaths) {
32+
if (resourcePaths.length === 2 && isChild(resourcePaths[1])) {
33+
return true;
34+
}
35+
if (resourcePaths.length < 3 || !isChild(resourcePaths[1])) {
36+
return false;
37+
}
38+
const additionalPaths = resourcePaths.slice(2);
39+
return !additionalPaths.some((p) => !isCustomMethod(p));
40+
}
41+
42+
/**
43+
* Checks if a path object has a GET method
44+
*
45+
* @param pathObject the path object to evaluate
46+
* @returns {boolean}
47+
*/
48+
export function hasGetMethod(pathObject) {
49+
return Object.keys(pathObject).some((o) => o === 'get');
50+
}
51+
52+
/**
53+
* Get all paths for a resource based on the parent path
54+
*
55+
* @param parent the parent path string
56+
* @param allPaths all paths as an array of strings
57+
* @returns {*} a string array of all paths for a resource, including the parent
58+
*/
59+
export function getResourcePaths(parent, allPaths) {
60+
const childPathPattern = new RegExp(`^${parent}/{[a-zA-Z]+}$`);
61+
const customMethodPattern = new RegExp(`^${parent}/{[a-zA-Z]+}:+[a-zA-Z]+$`);
62+
return allPaths.filter((p) => parent === p || childPathPattern.test(p) || customMethodPattern.test(p));
63+
}

0 commit comments

Comments
 (0)