Skip to content

Commit cdc3e8a

Browse files
CLOUDP-306576: IPA-119: Multi-Cloud Support by Default (#643)
1 parent 9a08ffe commit cdc3e8a

File tree

5 files changed

+332
-0
lines changed

5 files changed

+332
-0
lines changed
Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
import testRule from './__helpers__/testRule';
2+
import { DiagnosticSeverity } from '@stoplight/types';
3+
4+
testRule('xgen-IPA-119-no-default-for-cloud-providers', [
5+
{
6+
name: 'valid when no default in cloud provider field',
7+
document: {
8+
components: {
9+
schemas: {
10+
Schema: {
11+
properties: {
12+
cloudProvider: {
13+
type: 'string',
14+
enum: ['AWS', 'GCP', 'AZURE'],
15+
},
16+
},
17+
},
18+
},
19+
},
20+
},
21+
errors: [],
22+
},
23+
{
24+
name: 'invalid when cloud provider field has default value',
25+
document: {
26+
components: {
27+
schemas: {
28+
Schema: {
29+
properties: {
30+
cloudProvider: {
31+
type: 'string',
32+
enum: ['AWS', 'GCP', 'AZURE'],
33+
default: 'AWS',
34+
},
35+
},
36+
},
37+
},
38+
},
39+
},
40+
errors: [
41+
{
42+
code: 'xgen-IPA-119-no-default-for-cloud-providers',
43+
message: 'When using a provider field or param, API producers should not define a default value.',
44+
path: ['components', 'schemas', 'Schema', 'properties', 'cloudProvider'],
45+
severity: DiagnosticSeverity.Warning,
46+
},
47+
],
48+
},
49+
{
50+
name: 'invalid when cloud provider field has default value',
51+
document: {
52+
components: {
53+
schemas: {
54+
Schema: {
55+
properties: {
56+
provider: {
57+
type: 'string',
58+
enum: ['AWS', 'GCP', 'AZURE'],
59+
default: 'AWS',
60+
},
61+
},
62+
},
63+
},
64+
},
65+
},
66+
errors: [
67+
{
68+
code: 'xgen-IPA-119-no-default-for-cloud-providers',
69+
message: 'When using a provider field or param, API producers should not define a default value.',
70+
path: ['components', 'schemas', 'Schema', 'properties', 'provider'],
71+
severity: DiagnosticSeverity.Warning,
72+
},
73+
],
74+
},
75+
{
76+
name: 'valid when non-provider field has default value',
77+
document: {
78+
components: {
79+
schemas: {
80+
Schema: {
81+
properties: {
82+
region: {
83+
type: 'string',
84+
default: 'us-east-1',
85+
},
86+
},
87+
},
88+
},
89+
},
90+
},
91+
errors: [],
92+
},
93+
{
94+
name: 'field with provider in name has exception',
95+
document: {
96+
components: {
97+
schemas: {
98+
Schema: {
99+
properties: {
100+
cloudProvider: {
101+
type: 'string',
102+
enum: ['AWS', 'GCP', 'AZURE'],
103+
default: 'AWS',
104+
'x-xgen-IPA-exception': {
105+
'xgen-IPA-119-no-default-for-cloud-providers': 'Reason',
106+
},
107+
},
108+
},
109+
},
110+
},
111+
},
112+
},
113+
errors: [],
114+
},
115+
{
116+
name: 'parameters with provider in name',
117+
document: {
118+
paths: {
119+
'/resources': {
120+
get: {
121+
parameters: [
122+
{
123+
name: 'cloudProvider',
124+
in: 'query',
125+
schema: {
126+
type: 'string',
127+
default: 'AWS',
128+
},
129+
},
130+
],
131+
},
132+
},
133+
},
134+
},
135+
errors: [
136+
{
137+
code: 'xgen-IPA-119-no-default-for-cloud-providers',
138+
message: 'When using a provider field or param, API producers should not define a default value.',
139+
path: ['paths', '/resources', 'get', 'parameters', '0'],
140+
severity: DiagnosticSeverity.Warning,
141+
},
142+
],
143+
},
144+
{
145+
name: 'parameters with provider in name - exceptions',
146+
document: {
147+
paths: {
148+
'/resources': {
149+
get: {
150+
parameters: [
151+
{
152+
name: 'cloudProvider',
153+
in: 'query',
154+
schema: {
155+
type: 'string',
156+
default: 'AWS',
157+
},
158+
'x-xgen-IPA-exception': {
159+
'xgen-IPA-119-no-default-for-cloud-providers': 'Reason',
160+
},
161+
},
162+
],
163+
},
164+
},
165+
},
166+
components: {
167+
schemas: {
168+
Schema: {
169+
properties: {
170+
provider: {
171+
type: 'string',
172+
enum: ['AWS', 'GCP', 'AZURE'],
173+
default: 'AWS',
174+
'x-xgen-IPA-exception': {
175+
'xgen-IPA-119-no-default-for-cloud-providers': 'Reason',
176+
},
177+
},
178+
},
179+
},
180+
},
181+
},
182+
},
183+
errors: [],
184+
},
185+
]);

tools/spectral/ipa/ipa-spectral.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ extends:
1313
- ./rulesets/IPA-114.yaml
1414
- ./rulesets/IPA-117.yaml
1515
- ./rulesets/IPA-118.yaml
16+
- ./rulesets/IPA-119.yaml
1617
- ./rulesets/IPA-123.yaml
1718
- ./rulesets/IPA-125.yaml
1819

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# IPA-119: Multi-Cloud Support by Default
2+
# http://go/ipa/119
3+
4+
functions:
5+
- IPA119NoDefaultForCloudProviders
6+
rules:
7+
xgen-IPA-119-no-default-for-cloud-providers:
8+
description: |
9+
When using a provider field or parameter, API producers should not define a default value.
10+
This rule checks fields and parameters named "cloudProvider" and ensures they do not have a default value.
11+
It also checks enum fields that might contain cloud provider values.
12+
All cloudProviderEnumValues should be listed in the enum array.
13+
severity: warn
14+
message: '{{error}} https://mdb.link/mongodb-atlas-openapi-validation#xgen-IPA-119-no-default-for-cloud-providers'
15+
given:
16+
# Target properties with "cloudProvider" in their name
17+
- '$.paths[*][get,put,post,delete,options,head,patch,trace].parameters'
18+
- '$.paths[*][get,put,post,delete,options,head,patch,trace]..content..properties'
19+
- '$.components.schemas..properties'
20+
then:
21+
field: '@key'
22+
function: IPA119NoDefaultForCloudProviders
23+
functionOptions:
24+
propertyNameToLookFor: 'cloudProvider'
25+
cloudProviderEnumValues:
26+
- 'AWS'
27+
- 'GCP'
28+
- 'AZURE'

tools/spectral/ipa/rulesets/README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -788,6 +788,20 @@ This rule checks all nested schemas, but only parent schemas can be marked for e
788788

789789

790790

791+
### IPA-119
792+
793+
Rules are based on [http://go/ipa/IPA-119](http://go/ipa/IPA-119).
794+
795+
#### xgen-IPA-119-no-default-for-cloud-providers
796+
797+
![warn](https://img.shields.io/badge/warning-yellow)
798+
When using a provider field or parameter, API producers should not define a default value.
799+
This rule checks fields and parameters named "cloudProvider" and ensures they do not have a default value.
800+
It also checks enum fields that might contain cloud provider values.
801+
All cloudProviderEnumValues should be listed in the enum array.
802+
803+
804+
791805
### IPA-123
792806

793807
Rules are based on [http://go/ipa/IPA-123](http://go/ipa/IPA-123).
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import { hasException } from './utils/exceptions.js';
2+
import {
3+
collectAdoption,
4+
collectAndReturnViolation,
5+
collectException,
6+
handleInternalError,
7+
} from './utils/collectionUtils.js';
8+
import { resolveObject } from './utils/componentUtils.js';
9+
10+
const RULE_NAME = 'xgen-IPA-119-no-default-for-cloud-providers';
11+
const ERROR_MESSAGE = 'When using a provider field or param, API producers should not define a default value.';
12+
export default (input, { propertyNameToLookFor, cloudProviderEnumValues }, { path, documentInventory }) => {
13+
const oas = documentInventory.resolved;
14+
const propertyObject = resolveObject(oas, path);
15+
const fieldType = path[path.length - 2];
16+
17+
if (fieldType === 'parameters' && !propertyObject.schema) {
18+
return;
19+
}
20+
21+
if (hasException(propertyObject, RULE_NAME)) {
22+
collectException(propertyObject, RULE_NAME, path);
23+
return;
24+
}
25+
26+
const errors = checkViolationsAndReturnErrors(
27+
input,
28+
propertyObject,
29+
path,
30+
propertyNameToLookFor,
31+
fieldType,
32+
cloudProviderEnumValues
33+
);
34+
if (errors.length !== 0) {
35+
return collectAndReturnViolation(path, RULE_NAME, errors);
36+
}
37+
collectAdoption(path, RULE_NAME);
38+
};
39+
40+
function checkViolationsAndReturnErrors(
41+
propertyName,
42+
propertyObject,
43+
path,
44+
propertyNameToLookFor,
45+
fieldType,
46+
cloudProviderEnumValues
47+
) {
48+
try {
49+
if (fieldType === 'properties') {
50+
if (propertyName === propertyNameToLookFor && propertyObject.default !== undefined) {
51+
return [
52+
{
53+
path,
54+
message: ERROR_MESSAGE,
55+
},
56+
];
57+
}
58+
59+
if (Array.isArray(propertyObject.enum) && propertyObject.enum.length > 0) {
60+
const enumValues = propertyObject.enum;
61+
const hasCloudProviderEnumValue = cloudProviderEnumValues.every((cloudProviderValue) =>
62+
enumValues.includes(cloudProviderValue)
63+
);
64+
if (hasCloudProviderEnumValue && propertyObject.default !== undefined) {
65+
return [
66+
{
67+
path,
68+
message: ERROR_MESSAGE,
69+
},
70+
];
71+
}
72+
}
73+
} else if (fieldType === 'parameters') {
74+
if (propertyObject.name === propertyNameToLookFor && propertyObject.schema.default !== undefined) {
75+
return [
76+
{
77+
path,
78+
message: ERROR_MESSAGE,
79+
},
80+
];
81+
}
82+
83+
if (Array.isArray(propertyObject.schema.enum) && propertyObject.schema.enum.length > 0) {
84+
const enumValues = propertyObject.schema.enum;
85+
const hasCloudProviderEnumValue = cloudProviderEnumValues.every((cloudProviderValue) =>
86+
enumValues.includes(cloudProviderValue)
87+
);
88+
89+
if (hasCloudProviderEnumValue && propertyObject.schema.default !== undefined) {
90+
return [
91+
{
92+
path,
93+
message: ERROR_MESSAGE,
94+
},
95+
];
96+
}
97+
}
98+
}
99+
100+
return [];
101+
} catch (e) {
102+
handleInternalError(RULE_NAME, path, e);
103+
}
104+
}

0 commit comments

Comments
 (0)