Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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: [],
},
]);
1 change: 1 addition & 0 deletions tools/spectral/ipa/ipa-spectral.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ extends:
- ./rulesets/IPA-114.yaml
- ./rulesets/IPA-117.yaml
- ./rulesets/IPA-118.yaml
- ./rulesets/IPA-119.yaml
- ./rulesets/IPA-123.yaml
- ./rulesets/IPA-125.yaml

Expand Down
28 changes: 28 additions & 0 deletions tools/spectral/ipa/rulesets/IPA-119.yaml
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
Copy link
Collaborator

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 providerName is the spec as well, perhaps these can be included as well?

Copy link
Collaborator Author

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 providerName parameters. For example: paths//api/atlas/v2/groups/{groupId}/containers/get/parameters/6

- '$.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'
14 changes: 14 additions & 0 deletions tools/spectral/ipa/rulesets/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -788,6 +788,20 @@ This rule checks all nested schemas, but only parent schemas can be marked for e



### IPA-119

Rules are based on [http://go/ipa/IPA-119](http://go/ipa/IPA-119).

#### xgen-IPA-119-no-default-for-cloud-providers

![warn](https://img.shields.io/badge/warning-yellow)
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.



### IPA-123

Rules are based on [http://go/ipa/IPA-123](http://go/ipa/IPA-123).
Expand Down
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) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Q: If there are no properties with the name cloudProvider, will this collect an adoption? Perhaps we should filter these out before the collectAndReturnViolation

Copy link
Collaborator Author

Choose a reason for hiding this comment

The 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);
}
}
Loading