diff --git a/tools/spectral/ipa/__tests__/IPA123EnumValuesShouldNotExceed20.test.js b/tools/spectral/ipa/__tests__/IPA123EnumValuesShouldNotExceed20.test.js new file mode 100644 index 0000000000..7669c78f40 --- /dev/null +++ b/tools/spectral/ipa/__tests__/IPA123EnumValuesShouldNotExceed20.test.js @@ -0,0 +1,367 @@ +import testRule from './__helpers__/testRule.js'; +import { DiagnosticSeverity } from '@stoplight/types'; + +testRule('xgen-IPA-123-allowable-enum-values-should-not-exceed-20', [ + { + name: 'valid when enum has exactly 20 values', + document: { + components: { + schemas: { + TestSchema: { + properties: { + status: { + type: 'string', + enum: [ + 'VALUE_1', + 'VALUE_2', + 'VALUE_3', + 'VALUE_4', + 'VALUE_5', + 'VALUE_6', + 'VALUE_7', + 'VALUE_8', + 'VALUE_9', + 'VALUE_10', + 'VALUE_11', + 'VALUE_12', + 'VALUE_13', + 'VALUE_14', + 'VALUE_15', + 'VALUE_16', + 'VALUE_17', + 'VALUE_18', + 'VALUE_19', + 'VALUE_20', + ], + }, + }, + }, + }, + }, + }, + errors: [], + }, + { + name: 'valid when enum has fewer than 20 values', + document: { + components: { + schemas: { + TestSchema: { + properties: { + status: { + type: 'string', + enum: ['PENDING', 'ACTIVE', 'COMPLETE', 'FAILED'], + }, + }, + }, + }, + }, + }, + errors: [], + }, + { + name: 'invalid when enum has more than 20 values', + document: { + components: { + schemas: { + TestSchema: { + properties: { + status: { + type: 'string', + enum: [ + 'VALUE_1', + 'VALUE_2', + 'VALUE_3', + 'VALUE_4', + 'VALUE_5', + 'VALUE_6', + 'VALUE_7', + 'VALUE_8', + 'VALUE_9', + 'VALUE_10', + 'VALUE_11', + 'VALUE_12', + 'VALUE_13', + 'VALUE_14', + 'VALUE_15', + 'VALUE_16', + 'VALUE_17', + 'VALUE_18', + 'VALUE_19', + 'VALUE_20', + 'VALUE_21', + ], + }, + }, + }, + }, + }, + }, + errors: [ + { + code: 'xgen-IPA-123-allowable-enum-values-should-not-exceed-20', + message: 'Inline enum arrays should not exceed 20 values. Current count: 21', + path: ['components', 'schemas', 'TestSchema', 'properties', 'status', 'enum'], + severity: DiagnosticSeverity.Warning, + }, + ], + }, + { + name: 'exception on schema', + document: { + components: { + schemas: { + TestSchema: { + properties: { + status: { + type: 'string', + enum: [ + 'VALUE_1', + 'VALUE_2', + 'VALUE_3', + 'VALUE_4', + 'VALUE_5', + 'VALUE_6', + 'VALUE_7', + 'VALUE_8', + 'VALUE_9', + 'VALUE_10', + 'VALUE_11', + 'VALUE_12', + 'VALUE_13', + 'VALUE_14', + 'VALUE_15', + 'VALUE_16', + 'VALUE_17', + 'VALUE_18', + 'VALUE_19', + 'VALUE_20', + 'VALUE_21', + 'VALUE_22', + 'VALUE_23', + 'VALUE_24', + 'VALUE_25', + ], + 'x-xgen-IPA-exception': { + 'xgen-IPA-123-allowable-enum-values-should-not-exceed-20': 'Legacy enum with more than 20 values', + }, + }, + }, + }, + }, + }, + }, + errors: [], + }, + { + name: 'invalid with integer enum values exceeding limit', + document: { + components: { + schemas: { + TestSchema: { + properties: { + priority: { + type: 'integer', + enum: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21], + }, + }, + }, + }, + }, + }, + errors: [ + { + code: 'xgen-IPA-123-allowable-enum-values-should-not-exceed-20', + message: 'Inline enum arrays should not exceed 20 values. Current count: 21', + path: ['components', 'schemas', 'TestSchema', 'properties', 'priority', 'enum'], + severity: DiagnosticSeverity.Warning, + }, + ], + }, + { + name: 'valid for parameters in path operation', + document: { + paths: { + '/resources': { + get: { + parameters: [ + { + name: 'status', + in: 'query', + schema: { + type: 'string', + enum: ['ACTIVE', 'INACTIVE', 'PENDING'], + }, + }, + ], + }, + }, + }, + }, + errors: [], + }, + { + name: 'invalid for parameters in path operation exceeding limit', + document: { + paths: { + '/resources': { + get: { + parameters: [ + { + name: 'status', + in: 'query', + schema: { + type: 'string', + enum: [ + 'VAL_1', + 'VAL_2', + 'VAL_3', + 'VAL_4', + 'VAL_5', + 'VAL_6', + 'VAL_7', + 'VAL_8', + 'VAL_9', + 'VAL_10', + 'VAL_11', + 'VAL_12', + 'VAL_13', + 'VAL_14', + 'VAL_15', + 'VAL_16', + 'VAL_17', + 'VAL_18', + 'VAL_19', + 'VAL_20', + 'VAL_21', + ], + }, + }, + ], + }, + }, + }, + }, + errors: [ + { + code: 'xgen-IPA-123-allowable-enum-values-should-not-exceed-20', + message: 'Inline enum arrays should not exceed 20 values. Current count: 21', + path: ['paths', '/resources', 'get', 'parameters', '0', 'schema', 'enum'], + severity: DiagnosticSeverity.Warning, + }, + ], + }, + { + name: 'exception on parameter schema', + document: { + paths: { + '/resources': { + get: { + parameters: [ + { + name: 'status', + in: 'query', + schema: { + type: 'string', + enum: [ + 'VAL_1', + 'VAL_2', + 'VAL_3', + 'VAL_4', + 'VAL_5', + 'VAL_6', + 'VAL_7', + 'VAL_8', + 'VAL_9', + 'VAL_10', + 'VAL_11', + 'VAL_12', + 'VAL_13', + 'VAL_14', + 'VAL_15', + 'VAL_16', + 'VAL_17', + 'VAL_18', + 'VAL_19', + 'VAL_20', + 'VAL_21', + 'VAL_22', + 'VAL_23', + 'VAL_24', + 'VAL_25', + ], + 'x-xgen-IPA-exception': { + 'xgen-IPA-123-allowable-enum-values-should-not-exceed-20': 'Parameter with many possible values', + }, + }, + }, + ], + }, + }, + }, + }, + errors: [], + }, + { + name: 'valid on with reusable schemas', + document: { + paths: { + '/resources': { + get: { + parameters: [ + { + name: 'status', + in: 'query', + schema: { + $ref: '#/components/schemas/StatusEnum', + }, + }, + ], + }, + }, + }, + components: { + schemas: { + StatusEnum: { + type: 'string', + enum: [ + 'VAL_1', + 'VAL_2', + 'VAL_3', + 'VAL_4', + 'VAL_5', + 'VAL_6', + 'VAL_7', + 'VAL_8', + 'VAL_9', + 'VAL_10', + 'VAL_11', + 'VAL_12', + 'VAL_13', + 'VAL_14', + 'VAL_15', + 'VAL_16', + 'VAL_17', + 'VAL_18', + 'VAL_19', + 'VAL_20', + 'VAL_21', + 'VAL_22', + 'VAL_23', + 'VAL_24', + 'VAL_25', + ], + }, + TestSchema: { + properties: { + status: { + $ref: '#/components/schemas/StatusEnum', + }, + }, + }, + }, + }, + }, + errors: [], + }, +]); diff --git a/tools/spectral/ipa/rulesets/IPA-123.yaml b/tools/spectral/ipa/rulesets/IPA-123.yaml index e8635ed9ab..61b0fc8bef 100644 --- a/tools/spectral/ipa/rulesets/IPA-123.yaml +++ b/tools/spectral/ipa/rulesets/IPA-123.yaml @@ -3,6 +3,7 @@ functions: - IPA123EachEnumValueMustBeUpperSnakeCase + - IPA123EnumValuesShouldNotExceed20 rules: xgen-IPA-123-enum-values-must-be-upper-snake-case: @@ -17,6 +18,25 @@ rules: - Skips validation if the schema has an exception defined for this rule message: '{{error}} https://mdb.link/mongodb-atlas-openapi-validation#xgen-IPA-123-enum-values-must-be-upper-snake-case' severity: error + resolved: false given: '$..enum' then: function: 'IPA123EachEnumValueMustBeUpperSnakeCase' + xgen-IPA-123-allowable-enum-values-should-not-exceed-20: + description: | + Allowable enum values should not exceed 20 entries. + + ##### Implementation details + Rule checks for the following conditions: + - Applies to inline enum values + - Validates that each enum array has 20 or fewer values + - Reusable enum schemas will be ignored + - Skips validation if the schema has an exception defined for this rule + message: '{{error}} https://mdb.link/mongodb-atlas-openapi-validation#xgen-IPA-123-allowable-enum-values-should-not-exceed-20' + severity: warn + resolved: false + given: '$..enum' + then: + function: 'IPA123EnumValuesShouldNotExceed20' + functionOptions: + maxEnumValues: 20 diff --git a/tools/spectral/ipa/rulesets/README.md b/tools/spectral/ipa/rulesets/README.md index ff9890bda9..e828145239 100644 --- a/tools/spectral/ipa/rulesets/README.md +++ b/tools/spectral/ipa/rulesets/README.md @@ -830,6 +830,18 @@ Rule checks for the following conditions: - Validates each enum value individually against the UPPER_SNAKE_CASE pattern - Skips validation if the schema has an exception defined for this rule +#### xgen-IPA-123-allowable-enum-values-should-not-exceed-20 + + ![warn](https://img.shields.io/badge/warning-yellow) +Allowable enum values should not exceed 20 entries. + +##### Implementation details +Rule checks for the following conditions: + - Applies to inline enum values + - Validates that each enum array has 20 or fewer values + - Reusable enum schemas will be ignored + - Skips validation if the schema has an exception defined for this rule + ### IPA-125 diff --git a/tools/spectral/ipa/rulesets/functions/IPA123EnumValuesShouldNotExceed20.js b/tools/spectral/ipa/rulesets/functions/IPA123EnumValuesShouldNotExceed20.js new file mode 100644 index 0000000000..06aa15bf1a --- /dev/null +++ b/tools/spectral/ipa/rulesets/functions/IPA123EnumValuesShouldNotExceed20.js @@ -0,0 +1,39 @@ +import { hasException } from './utils/exceptions.js'; +import { collectAdoption, collectAndReturnViolation, collectException } from './utils/collectionUtils.js'; +import { getSchemaPathFromEnumPath } from './utils/schemaUtils.js'; +import { resolveObject } from './utils/componentUtils.js'; + +const RULE_NAME = 'xgen-IPA-123-allowable-enum-values-should-not-exceed-20'; +const ERROR_MESSAGE = 'Inline enum arrays should not exceed 20 values. Current count: '; + +export default (input, { maxEnumValues }, { path, documentInventory }) => { + const oas = documentInventory.resolved; + const schemaPath = getSchemaPathFromEnumPath(path); + const schemaObject = resolveObject(oas, schemaPath); + + //Ignore if the schemaObject belongs to a reusable enum + if (!schemaPath.includes('properties') && !schemaPath.includes('parameters')) { + return; + } + + // Check for exceptions + if (hasException(schemaObject, RULE_NAME)) { + collectException(schemaObject, RULE_NAME, path); + return; + } + + if (!Array.isArray(input)) { + return; + } + + if (input.length > maxEnumValues) { + return collectAndReturnViolation(path, RULE_NAME, [ + { + path, + message: `${ERROR_MESSAGE}${input.length}`, + }, + ]); + } + + collectAdoption(path, RULE_NAME); +};