-
Notifications
You must be signed in to change notification settings - Fork 15
CLOUDP-306576: IPA-119: Multi-Cloud Support by Default #643
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
571c2dd
cb8bb83
bf8fd9e
c3a38a2
cf09c3b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,185 @@ | ||
| import testRule from './__helpers__/testRule'; | ||
| import { DiagnosticSeverity } from '@stoplight/types'; | ||
|
|
||
| testRule('xgen-IPA-119-no-default-for-cloud-providers', [ | ||
| { | ||
| name: 'valid when no default in cloud provider field', | ||
| document: { | ||
| components: { | ||
| schemas: { | ||
| Schema: { | ||
| properties: { | ||
| cloudProvider: { | ||
| type: 'string', | ||
| enum: ['AWS', 'GCP', 'AZURE'], | ||
| }, | ||
| }, | ||
| }, | ||
| }, | ||
| }, | ||
| }, | ||
| errors: [], | ||
| }, | ||
| { | ||
| name: 'invalid when cloud provider field has default value', | ||
| document: { | ||
| components: { | ||
| schemas: { | ||
| Schema: { | ||
| properties: { | ||
| cloudProvider: { | ||
| type: 'string', | ||
| enum: ['AWS', 'GCP', 'AZURE'], | ||
| default: 'AWS', | ||
| }, | ||
| }, | ||
| }, | ||
| }, | ||
| }, | ||
| }, | ||
| errors: [ | ||
| { | ||
| code: 'xgen-IPA-119-no-default-for-cloud-providers', | ||
| message: 'When using a provider field or param, API producers should not define a default value.', | ||
| path: ['components', 'schemas', 'Schema', 'properties', 'cloudProvider'], | ||
| severity: DiagnosticSeverity.Warning, | ||
| }, | ||
| ], | ||
| }, | ||
| { | ||
| name: 'invalid when cloud provider field has default value', | ||
| document: { | ||
| components: { | ||
| schemas: { | ||
| Schema: { | ||
| properties: { | ||
| provider: { | ||
| type: 'string', | ||
| enum: ['AWS', 'GCP', 'AZURE'], | ||
| default: 'AWS', | ||
| }, | ||
| }, | ||
| }, | ||
| }, | ||
| }, | ||
| }, | ||
| errors: [ | ||
| { | ||
| code: 'xgen-IPA-119-no-default-for-cloud-providers', | ||
| message: 'When using a provider field or param, API producers should not define a default value.', | ||
| path: ['components', 'schemas', 'Schema', 'properties', 'provider'], | ||
| severity: DiagnosticSeverity.Warning, | ||
| }, | ||
| ], | ||
| }, | ||
| { | ||
| name: 'valid when non-provider field has default value', | ||
| document: { | ||
| components: { | ||
| schemas: { | ||
| Schema: { | ||
| properties: { | ||
| region: { | ||
| type: 'string', | ||
| default: 'us-east-1', | ||
| }, | ||
| }, | ||
| }, | ||
| }, | ||
| }, | ||
| }, | ||
| errors: [], | ||
| }, | ||
| { | ||
| name: 'field with provider in name has exception', | ||
| document: { | ||
| components: { | ||
| schemas: { | ||
| Schema: { | ||
| properties: { | ||
| cloudProvider: { | ||
| type: 'string', | ||
| enum: ['AWS', 'GCP', 'AZURE'], | ||
| default: 'AWS', | ||
| 'x-xgen-IPA-exception': { | ||
| 'xgen-IPA-119-no-default-for-cloud-providers': 'Reason', | ||
| }, | ||
| }, | ||
| }, | ||
| }, | ||
| }, | ||
| }, | ||
| }, | ||
| errors: [], | ||
| }, | ||
| { | ||
| name: 'parameters with provider in name', | ||
| document: { | ||
| paths: { | ||
| '/resources': { | ||
| get: { | ||
| parameters: [ | ||
| { | ||
| name: 'cloudProvider', | ||
| in: 'query', | ||
| schema: { | ||
| type: 'string', | ||
| default: 'AWS', | ||
| }, | ||
| }, | ||
| ], | ||
| }, | ||
| }, | ||
| }, | ||
| }, | ||
| errors: [ | ||
| { | ||
| code: 'xgen-IPA-119-no-default-for-cloud-providers', | ||
| message: 'When using a provider field or param, API producers should not define a default value.', | ||
| path: ['paths', '/resources', 'get', 'parameters', '0'], | ||
| severity: DiagnosticSeverity.Warning, | ||
| }, | ||
| ], | ||
| }, | ||
| { | ||
| name: 'parameters with provider in name - exceptions', | ||
| document: { | ||
| paths: { | ||
| '/resources': { | ||
| get: { | ||
| parameters: [ | ||
| { | ||
| name: 'cloudProvider', | ||
| in: 'query', | ||
| schema: { | ||
| type: 'string', | ||
| default: 'AWS', | ||
| }, | ||
| 'x-xgen-IPA-exception': { | ||
| 'xgen-IPA-119-no-default-for-cloud-providers': 'Reason', | ||
| }, | ||
| }, | ||
| ], | ||
| }, | ||
| }, | ||
| }, | ||
| components: { | ||
| schemas: { | ||
| Schema: { | ||
| properties: { | ||
| provider: { | ||
| type: 'string', | ||
| enum: ['AWS', 'GCP', 'AZURE'], | ||
| default: 'AWS', | ||
| 'x-xgen-IPA-exception': { | ||
| 'xgen-IPA-119-no-default-for-cloud-providers': 'Reason', | ||
| }, | ||
| }, | ||
| }, | ||
| }, | ||
| }, | ||
| }, | ||
| }, | ||
| errors: [], | ||
| }, | ||
| ]); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| # IPA-119: Multi-Cloud Support by Default | ||
| # http://go/ipa/119 | ||
|
|
||
| functions: | ||
| - IPA119NoDefaultForCloudProviders | ||
| rules: | ||
| xgen-IPA-119-no-default-for-cloud-providers: | ||
| description: | | ||
| When using a provider field or parameter, API producers should not define a default value. | ||
| This rule checks fields and parameters named "cloudProvider" and ensures they do not have a default value. | ||
| It also checks enum fields that might contain cloud provider values. | ||
| All cloudProviderEnumValues should be listed in the enum array. | ||
| severity: warn | ||
| message: '{{error}} https://mdb.link/mongodb-atlas-openapi-validation#xgen-IPA-119-no-default-for-cloud-providers' | ||
| given: | ||
| # Target properties with "cloudProvider" in their name | ||
| - '$.paths[*][get,put,post,delete,options,head,patch,trace].parameters' | ||
| - '$.paths[*][get,put,post,delete,options,head,patch,trace]..content..properties' | ||
| - '$.components.schemas..properties' | ||
| then: | ||
| field: '@key' | ||
| function: IPA119NoDefaultForCloudProviders | ||
| functionOptions: | ||
| propertyNameToLookFor: 'cloudProvider' | ||
| cloudProviderEnumValues: | ||
| - 'AWS' | ||
| - 'GCP' | ||
| - 'AZURE' | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,104 @@ | ||
| import { hasException } from './utils/exceptions.js'; | ||
| import { | ||
| collectAdoption, | ||
| collectAndReturnViolation, | ||
| collectException, | ||
| handleInternalError, | ||
| } from './utils/collectionUtils.js'; | ||
| import { resolveObject } from './utils/componentUtils.js'; | ||
|
|
||
| const RULE_NAME = 'xgen-IPA-119-no-default-for-cloud-providers'; | ||
| const ERROR_MESSAGE = 'When using a provider field or param, API producers should not define a default value.'; | ||
| export default (input, { propertyNameToLookFor, cloudProviderEnumValues }, { path, documentInventory }) => { | ||
| const oas = documentInventory.resolved; | ||
| const propertyObject = resolveObject(oas, path); | ||
| const fieldType = path[path.length - 2]; | ||
|
|
||
| if (fieldType === 'parameters' && !propertyObject.schema) { | ||
| return; | ||
| } | ||
|
|
||
| if (hasException(propertyObject, RULE_NAME)) { | ||
| collectException(propertyObject, RULE_NAME, path); | ||
| return; | ||
| } | ||
|
|
||
| const errors = checkViolationsAndReturnErrors( | ||
| input, | ||
| propertyObject, | ||
| path, | ||
| propertyNameToLookFor, | ||
| fieldType, | ||
| cloudProviderEnumValues | ||
| ); | ||
| if (errors.length !== 0) { | ||
| return collectAndReturnViolation(path, RULE_NAME, errors); | ||
| } | ||
| collectAdoption(path, RULE_NAME); | ||
| }; | ||
|
|
||
| function checkViolationsAndReturnErrors( | ||
| propertyName, | ||
| propertyObject, | ||
| path, | ||
| propertyNameToLookFor, | ||
| fieldType, | ||
| cloudProviderEnumValues | ||
| ) { | ||
| try { | ||
| if (fieldType === 'properties') { | ||
| if (propertyName === propertyNameToLookFor && propertyObject.default !== undefined) { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Q: If there are no properties with the name
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, that's a good point! Let me open a PR for it |
||
| return [ | ||
| { | ||
| path, | ||
| message: ERROR_MESSAGE, | ||
| }, | ||
| ]; | ||
| } | ||
|
|
||
| if (Array.isArray(propertyObject.enum) && propertyObject.enum.length > 0) { | ||
| const enumValues = propertyObject.enum; | ||
| const hasCloudProviderEnumValue = cloudProviderEnumValues.every((cloudProviderValue) => | ||
| enumValues.includes(cloudProviderValue) | ||
| ); | ||
| if (hasCloudProviderEnumValue && propertyObject.default !== undefined) { | ||
| return [ | ||
| { | ||
| path, | ||
| message: ERROR_MESSAGE, | ||
| }, | ||
| ]; | ||
| } | ||
| } | ||
| } else if (fieldType === 'parameters') { | ||
| if (propertyObject.name === propertyNameToLookFor && propertyObject.schema.default !== undefined) { | ||
| return [ | ||
| { | ||
| path, | ||
| message: ERROR_MESSAGE, | ||
| }, | ||
| ]; | ||
| } | ||
|
|
||
| if (Array.isArray(propertyObject.schema.enum) && propertyObject.schema.enum.length > 0) { | ||
| const enumValues = propertyObject.schema.enum; | ||
| const hasCloudProviderEnumValue = cloudProviderEnumValues.every((cloudProviderValue) => | ||
| enumValues.includes(cloudProviderValue) | ||
| ); | ||
|
|
||
| if (hasCloudProviderEnumValue && propertyObject.schema.default !== undefined) { | ||
| return [ | ||
| { | ||
| path, | ||
| message: ERROR_MESSAGE, | ||
| }, | ||
| ]; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| return []; | ||
| } catch (e) { | ||
| handleInternalError(RULE_NAME, path, e); | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I saw some examples of
providerNameis the spec as well, perhaps these can be included as well?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, the enum check will capture the
providerNameparameters. For example:paths//api/atlas/v2/groups/{groupId}/containers/get/parameters/6