From c4c8daff221574c65d25abae33771526c2ac210f Mon Sep 17 00:00:00 2001 From: Sophia Marie Terry Date: Thu, 3 Jul 2025 16:50:40 +0100 Subject: [PATCH 01/11] CLOUDP-328955: Attempt to test hack version of new rule w/ ember-inflector --- tools/spectral/ipa/rulesets/IPA-104.yaml | 9 +++++ .../functions/IPA104ValidOperationID.js | 38 +++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 tools/spectral/ipa/rulesets/functions/IPA104ValidOperationID.js diff --git a/tools/spectral/ipa/rulesets/IPA-104.yaml b/tools/spectral/ipa/rulesets/IPA-104.yaml index cc63863991..66211870b4 100644 --- a/tools/spectral/ipa/rulesets/IPA-104.yaml +++ b/tools/spectral/ipa/rulesets/IPA-104.yaml @@ -8,6 +8,7 @@ functions: - IPA104GetResponseCodeShouldBe200OK - IPA104GetMethodResponseHasNoInputFields - IPA104GetMethodHasNoRequestBody + - IPA104ValidOperationID aliases: GetOperationObject: @@ -97,3 +98,11 @@ rules: given: '#GetOperationObject' then: function: 'IPA104GetMethodHasNoRequestBody' + xgen-IPA-104-valid-operation-id: + description: | + Test + message: '{{error}} https://mdb.link/mongodb-atlas-openapi-validation#xgen-IPA-104-get-method-no-request-body' + severity: error + given: '#GetOperationObject' + then: + function: 'IPA104ValidOperationID' diff --git a/tools/spectral/ipa/rulesets/functions/IPA104ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA104ValidOperationID.js new file mode 100644 index 0000000000..33c7dfbe7e --- /dev/null +++ b/tools/spectral/ipa/rulesets/functions/IPA104ValidOperationID.js @@ -0,0 +1,38 @@ +import { generateOperationID } from './utils/operationIdGeneration.js'; +import { collectAdoption, collectAndReturnViolation, collectException } from './utils/collectionUtils.js'; +import { hasException } from './utils/exceptions.js'; + +const RULE_NAME = 'xgen-IPA-104-valid-operation-id'; +const ERROR_MESSAGE = + ''; + +export default (input, _, { path, documentInventory }) => { + //const resourcePath = path[1]; + //const oas = documentInventory.resolved; + + console.log(input.operationId, path[1]); + + const expectedOperationId = generateOperationID("get", path[1]); + if (expectedOperationId === input.operationId) { + return; + } + + if (hasException(input, RULE_NAME)) { + collectException(input, RULE_NAME, path); + return; + } + + const errors = checkViolationsAndReturnErrors(input, path); + + if (errors.length !== 0) { + return collectAndReturnViolation(path, RULE_NAME, errors); + } + collectAdoption(path, RULE_NAME); +}; + +function checkViolationsAndReturnErrors(getOperationObject, path) { + if (getOperationObject.operationId) { + return [{ path, message: ERROR_MESSAGE }]; + } + return []; +} From dad86b1aef1b9c79886458ce5e287fd9a3685aab Mon Sep 17 00:00:00 2001 From: Sophia Marie Terry Date: Thu, 3 Jul 2025 18:21:26 +0100 Subject: [PATCH 02/11] CLOUDP-328955: Switched from ember-inflector to inflection --- package-lock.json | 10 ++++++++++ package.json | 8 +++----- .../rulesets/functions/utils/operationIdGeneration.js | 6 +++--- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 79c92439b4..bf55ad55b6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,7 @@ "dotenv": "^17.0.1", "ember-inflector": "^6.0.0", "eslint-plugin-jest": "^29.0.1", + "inflection": "^3.0.2", "markdown-table": "^3.0.4", "openapi-to-postmanv2": "5.0.0", "parquet-wasm": "^0.6.1" @@ -8373,6 +8374,15 @@ "node": ">=0.8.19" } }, + "node_modules/inflection": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/inflection/-/inflection-3.0.2.tgz", + "integrity": "sha512-+Bg3+kg+J6JUWn8J6bzFmOWkTQ6L/NHfDRSYU+EVvuKHDxUDHAXgqixHfVlzuBQaPOTac8hn43aPhMNk6rMe3g==", + "license": "MIT", + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", diff --git a/package.json b/package.json index 4a1c3a3d81..42232f00f3 100644 --- a/package.json +++ b/package.json @@ -14,9 +14,6 @@ "precommit": "husky install" }, "jest": { - "transformIgnorePatterns": [ - "/node_modules/(?!ember-inflector/)" - ], "transform": { "^.+\\.[t|j]sx?$": "babel-jest" }, @@ -36,6 +33,7 @@ "dotenv": "^17.0.1", "ember-inflector": "^6.0.0", "eslint-plugin-jest": "^29.0.1", + "inflection": "^3.0.2", "markdown-table": "^3.0.4", "openapi-to-postmanv2": "5.0.0", "parquet-wasm": "^0.6.1" @@ -49,14 +47,14 @@ "aws-sdk-client-mock": "^4.1.0", "babel-jest": "^30.0.2", "babel-plugin-transform-import-meta": "^2.3.3", + "brace-expansion": "4.0.1", "eslint": "^9.30.1", "eslint-plugin-require-extensions": "^0.1.3", "globals": "^16.3.0", "husky": "^9.1.7", "jest": "^30.0.3", "lint-staged": "^16.1.2", - "prettier": "3.6.2", - "brace-expansion": "4.0.1" + "prettier": "3.6.2" }, "engineStrict": false, "engines": { diff --git a/tools/spectral/ipa/rulesets/functions/utils/operationIdGeneration.js b/tools/spectral/ipa/rulesets/functions/utils/operationIdGeneration.js index b2ded2a7bc..12ee3cfe98 100644 --- a/tools/spectral/ipa/rulesets/functions/utils/operationIdGeneration.js +++ b/tools/spectral/ipa/rulesets/functions/utils/operationIdGeneration.js @@ -1,4 +1,4 @@ -import { singularize } from 'ember-inflector'; +const inflection = require('inflection'); import { isPathParam, removePrefix, isSingleResourceIdentifier } from './resourceEvaluation.js'; const CAMEL_CASE = /[A-Z]?[a-z]+/g; @@ -29,12 +29,12 @@ export function generateOperationID(method, path) { let opID = verb; for (let i = 0; i < nouns.length - 1; i++) { - opID += singularize(nouns[i]); + opID += inflection.singularize(nouns[i]); } // singularize final noun, dependent on resource identifier if (isSingleResourceIdentifier(resourceIdentifier) || verb === 'create') { - nouns[nouns.length - 1] = singularize(nouns[nouns.length - 1]); + nouns[nouns.length - 1] = inflection.singularize(nouns[nouns.length - 1]); } opID += nouns.pop(); From f1fba85deb06d7c21260ebbd5f1017085a093abc Mon Sep 17 00:00:00 2001 From: Sophia Marie Terry Date: Wed, 9 Jul 2025 10:23:18 +0100 Subject: [PATCH 03/11] CLOUDP-328955: Initial get/list configuration --- tools/spectral/ipa/rulesets/IPA-104.yaml | 4 +- tools/spectral/ipa/rulesets/IPA-105.yaml | 9 ++++ .../functions/IPA104ValidOperationID.js | 47 +++++++++++-------- .../functions/IPA105ValidOperationID.js | 44 +++++++++++++++++ 4 files changed, 82 insertions(+), 22 deletions(-) create mode 100644 tools/spectral/ipa/rulesets/functions/IPA105ValidOperationID.js diff --git a/tools/spectral/ipa/rulesets/IPA-104.yaml b/tools/spectral/ipa/rulesets/IPA-104.yaml index 66211870b4..f44801d843 100644 --- a/tools/spectral/ipa/rulesets/IPA-104.yaml +++ b/tools/spectral/ipa/rulesets/IPA-104.yaml @@ -101,8 +101,8 @@ rules: xgen-IPA-104-valid-operation-id: description: | Test - message: '{{error}} https://mdb.link/mongodb-atlas-openapi-validation#xgen-IPA-104-get-method-no-request-body' - severity: error + message: '{{error}} https://mdb.link/mongodb-atlas-openapi-validation#xgen-IPA-104-valid-operation-id' + severity: off given: '#GetOperationObject' then: function: 'IPA104ValidOperationID' diff --git a/tools/spectral/ipa/rulesets/IPA-105.yaml b/tools/spectral/ipa/rulesets/IPA-105.yaml index 9e5ac87c2d..144395c8c0 100644 --- a/tools/spectral/ipa/rulesets/IPA-105.yaml +++ b/tools/spectral/ipa/rulesets/IPA-105.yaml @@ -6,6 +6,7 @@ functions: - IPA105ListMethodHasNoRequestBody - IPA105EachResourceHasListMethod - IPA105ListMethodResponseIsGetMethodResponse + - IPA105ValidOperationID aliases: GetOperationObject: @@ -77,3 +78,11 @@ rules: then: field: '@key' function: 'IPA105ListMethodResponseIsGetMethodResponse' + xgen-IPA-105-valid-operation-id: + description: | + Test + message: '{{error}} https://mdb.link/mongodb-atlas-openapi-validation#xgen-IPA-105-valid-operation-id' + severity: off + given: '#GetOperationObject' + then: + function: 'IPA105ValidOperationID' diff --git a/tools/spectral/ipa/rulesets/functions/IPA104ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA104ValidOperationID.js index 33c7dfbe7e..fe87eaf7a8 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA104ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA104ValidOperationID.js @@ -1,19 +1,27 @@ import { generateOperationID } from './utils/operationIdGeneration.js'; import { collectAdoption, collectAndReturnViolation, collectException } from './utils/collectionUtils.js'; import { hasException } from './utils/exceptions.js'; +import { + isSingleResourceIdentifier, + isResourceCollectionIdentifier, + isSingletonResource, + getResourcePathItems, + isCustomMethodIdentifier, +} from './utils/resourceEvaluation.js'; const RULE_NAME = 'xgen-IPA-104-valid-operation-id'; -const ERROR_MESSAGE = - ''; +const ERROR_MESSAGE = ''; export default (input, _, { path, documentInventory }) => { - //const resourcePath = path[1]; - //const oas = documentInventory.resolved; - - console.log(input.operationId, path[1]); - - const expectedOperationId = generateOperationID("get", path[1]); - if (expectedOperationId === input.operationId) { + const resourcePath = path[1]; + const oas = documentInventory.resolved; + const resourcePaths = getResourcePathItems(resourcePath, oas.paths); + + if ( + isCustomMethodIdentifier(resourcePath) || + (!isSingleResourceIdentifier(resourcePath) && + !(isResourceCollectionIdentifier(resourcePath) && isSingletonResource(resourcePaths))) + ) { return; } @@ -22,17 +30,16 @@ export default (input, _, { path, documentInventory }) => { return; } - const errors = checkViolationsAndReturnErrors(input, path); - - if (errors.length !== 0) { + const expectedOperationId = generateOperationID('get', resourcePath); + if (expectedOperationId !== input.operationId) { + const errors = [ + { + path, + message: `${ERROR_MESSAGE} Found ${input.operationId}, expected ${expectedOperationId}.`, + }, + ]; return collectAndReturnViolation(path, RULE_NAME, errors); } - collectAdoption(path, RULE_NAME); -}; -function checkViolationsAndReturnErrors(getOperationObject, path) { - if (getOperationObject.operationId) { - return [{ path, message: ERROR_MESSAGE }]; - } - return []; -} + return collectAdoption(path, RULE_NAME); +}; diff --git a/tools/spectral/ipa/rulesets/functions/IPA105ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA105ValidOperationID.js new file mode 100644 index 0000000000..3e41e830a8 --- /dev/null +++ b/tools/spectral/ipa/rulesets/functions/IPA105ValidOperationID.js @@ -0,0 +1,44 @@ +import { hasException } from './utils/exceptions.js'; +import { collectAdoption, collectAndReturnViolation, collectException } from './utils/collectionUtils.js'; +import { + getResourcePathItems, + isCustomMethodIdentifier, + isResourceCollectionIdentifier, + isSingletonResource, +} from './utils/resourceEvaluation.js'; +import { generateOperationID } from './utils/operationIdGeneration.js'; + +const RULE_NAME = 'xgen-IPA-105-valid-operation-id'; +const ERROR_MESSAGE = ''; + +export default (input, _, { path, documentInventory }) => { + const resourcePath = path[1]; + const oas = documentInventory.resolved; + + if ( + isCustomMethodIdentifier(resourcePath) || + !isResourceCollectionIdentifier(resourcePath) || + isSingletonResource(getResourcePathItems(resourcePath, oas.paths)) + ) { + return; + } + + if (hasException(input, RULE_NAME)) { + collectException(input, RULE_NAME, path); + return; + } + + const expectedOperationId = generateOperationID('list', resourcePath); + if (expectedOperationId !== input.operationId) { + console.log( `${input.operationId}, ${expectedOperationId}, ${resourcePath}, ${input.deprecated ? 'TRUE' : 'FALSE'}, ${resourcePath, input['x-xgen-owner-team']}`); + const errors = [ + { + path, + message: `${ERROR_MESSAGE} Found ${input.operationId}, expected ${expectedOperationId}.`, + }, + ]; + return collectAndReturnViolation(path, RULE_NAME, errors); + } + + return collectAdoption(path, RULE_NAME); +}; From 59494696cc74c3830b092827ff269a949a20531b Mon Sep 17 00:00:00 2001 From: Sophia Marie Terry Date: Wed, 9 Jul 2025 11:06:50 +0100 Subject: [PATCH 04/11] CLOUDP-328955: Update error message and methodName function option --- tools/spectral/ipa/rulesets/IPA-104.yaml | 2 ++ tools/spectral/ipa/rulesets/IPA-105.yaml | 2 ++ .../ipa/rulesets/functions/IPA104ValidOperationID.js | 7 ++++--- .../ipa/rulesets/functions/IPA105ValidOperationID.js | 11 +++++++---- 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/tools/spectral/ipa/rulesets/IPA-104.yaml b/tools/spectral/ipa/rulesets/IPA-104.yaml index f44801d843..c88f0f8cd3 100644 --- a/tools/spectral/ipa/rulesets/IPA-104.yaml +++ b/tools/spectral/ipa/rulesets/IPA-104.yaml @@ -106,3 +106,5 @@ rules: given: '#GetOperationObject' then: function: 'IPA104ValidOperationID' + functionOptions: + methodName: 'get' diff --git a/tools/spectral/ipa/rulesets/IPA-105.yaml b/tools/spectral/ipa/rulesets/IPA-105.yaml index 144395c8c0..e6206358f4 100644 --- a/tools/spectral/ipa/rulesets/IPA-105.yaml +++ b/tools/spectral/ipa/rulesets/IPA-105.yaml @@ -86,3 +86,5 @@ rules: given: '#GetOperationObject' then: function: 'IPA105ValidOperationID' + functionOptions: + methodName: 'list' diff --git a/tools/spectral/ipa/rulesets/functions/IPA104ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA104ValidOperationID.js index fe87eaf7a8..af9e063199 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA104ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA104ValidOperationID.js @@ -10,9 +10,10 @@ import { } from './utils/resourceEvaluation.js'; const RULE_NAME = 'xgen-IPA-104-valid-operation-id'; -const ERROR_MESSAGE = ''; +const ERROR_MESSAGE = + 'Invalid OperationID. The Operation ID must start with the verb “get” and should be followed by a noun or compound noun. The noun(s) should be the collection identifiers from the resource identifier in singular form.'; -export default (input, _, { path, documentInventory }) => { +export default (input, { methodName }, { path, documentInventory }) => { const resourcePath = path[1]; const oas = documentInventory.resolved; const resourcePaths = getResourcePathItems(resourcePath, oas.paths); @@ -30,7 +31,7 @@ export default (input, _, { path, documentInventory }) => { return; } - const expectedOperationId = generateOperationID('get', resourcePath); + const expectedOperationId = generateOperationID(methodName, resourcePath); if (expectedOperationId !== input.operationId) { const errors = [ { diff --git a/tools/spectral/ipa/rulesets/functions/IPA105ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA105ValidOperationID.js index 3e41e830a8..1debc00331 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA105ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA105ValidOperationID.js @@ -9,9 +9,10 @@ import { import { generateOperationID } from './utils/operationIdGeneration.js'; const RULE_NAME = 'xgen-IPA-105-valid-operation-id'; -const ERROR_MESSAGE = ''; +const ERROR_MESSAGE = + 'Invalid OperationID. The Operation ID must start with the verb “list” and should be followed by a noun or compound noun. The noun(s) should be the collection identifiers from the resource identifier in singular form, where the last noun is in plural form.'; -export default (input, _, { path, documentInventory }) => { +export default (input, { methodName }, { path, documentInventory }) => { const resourcePath = path[1]; const oas = documentInventory.resolved; @@ -28,9 +29,11 @@ export default (input, _, { path, documentInventory }) => { return; } - const expectedOperationId = generateOperationID('list', resourcePath); + const expectedOperationId = generateOperationID(methodName, resourcePath); if (expectedOperationId !== input.operationId) { - console.log( `${input.operationId}, ${expectedOperationId}, ${resourcePath}, ${input.deprecated ? 'TRUE' : 'FALSE'}, ${resourcePath, input['x-xgen-owner-team']}`); + console.log( + `${input.operationId}, ${expectedOperationId}, ${resourcePath}, ${input.deprecated ? 'TRUE' : 'FALSE'}, ${(resourcePath, input['x-xgen-owner-team'])}` + ); const errors = [ { path, From 9b07f1e16c108fc056635f1266cdaac4af31befd Mon Sep 17 00:00:00 2001 From: Sophia Marie Terry Date: Wed, 9 Jul 2025 11:09:04 +0100 Subject: [PATCH 05/11] CLOUDP-328955: Update docs --- tools/spectral/ipa/rulesets/IPA-104.yaml | 8 +++++++- tools/spectral/ipa/rulesets/IPA-105.yaml | 9 ++++++++- tools/spectral/ipa/rulesets/README.md | 23 +++++++++++++++++++++++ 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/tools/spectral/ipa/rulesets/IPA-104.yaml b/tools/spectral/ipa/rulesets/IPA-104.yaml index c88f0f8cd3..888d94d6c9 100644 --- a/tools/spectral/ipa/rulesets/IPA-104.yaml +++ b/tools/spectral/ipa/rulesets/IPA-104.yaml @@ -100,7 +100,13 @@ rules: function: 'IPA104GetMethodHasNoRequestBody' xgen-IPA-104-valid-operation-id: description: | - Test + Confirms that the existing operationId is compliant with generated IPA Compliant OperationId. + + ##### Implementation details + Rule checks for the following conditions: + - Applies only to GET methods on single resources or singleton resources + - Generates the expected OperationId given the resource identifier + - Compares the generated IPA Compliant OperationId with the existing OperationId message: '{{error}} https://mdb.link/mongodb-atlas-openapi-validation#xgen-IPA-104-valid-operation-id' severity: off given: '#GetOperationObject' diff --git a/tools/spectral/ipa/rulesets/IPA-105.yaml b/tools/spectral/ipa/rulesets/IPA-105.yaml index e6206358f4..330459ecaf 100644 --- a/tools/spectral/ipa/rulesets/IPA-105.yaml +++ b/tools/spectral/ipa/rulesets/IPA-105.yaml @@ -80,7 +80,14 @@ rules: function: 'IPA105ListMethodResponseIsGetMethodResponse' xgen-IPA-105-valid-operation-id: description: | - Test + Confirms that the existing operationId is compliant with generated IPA Compliant OperationId. + + ##### Implementation details + Rule checks for the following conditions: + - Applies only to GET methods on resource collection paths + - Ignores singleton resources + - Generates the expected OperationId given the resource identifier + - Compares the generated IPA Compliant OperationId with the existing OperationId message: '{{error}} https://mdb.link/mongodb-atlas-openapi-validation#xgen-IPA-105-valid-operation-id' severity: off given: '#GetOperationObject' diff --git a/tools/spectral/ipa/rulesets/README.md b/tools/spectral/ipa/rulesets/README.md index 3112cde4dc..46b0cc885f 100644 --- a/tools/spectral/ipa/rulesets/README.md +++ b/tools/spectral/ipa/rulesets/README.md @@ -139,6 +139,17 @@ Rule checks for the following conditions: - Applies only to GET methods on single resources or singleton resources - Verifies that the operation object does not contain a requestBody property +#### xgen-IPA-104-valid-operation-id + + `off` +Confirms that the existing operationId is compliant with generated IPA Compliant OperationId. + +##### Implementation details +Rule checks for the following conditions: + - Applies only to GET methods on single resources or singleton resources + - Generates the expected OperationId given the resource identifier + - Compares the generated IPA Compliant OperationId with the existing OperationId + ### IPA-105 @@ -193,6 +204,18 @@ The response body of the List method should consist of the same resource object - Fails if the Get method doesn't have a schema reference or if the schemas don't match - Validation ignores resources without a Get method - Paths with `x-xgen-IPA-exception` for this rule are excluded from validation +#### xgen-IPA-105-valid-operation-id + + `off` +Confirms that the existing operationId is compliant with generated IPA Compliant OperationId. + +##### Implementation details +Rule checks for the following conditions: + - Applies only to GET methods on resource collection paths + - Ignores singleton resources + - Generates the expected OperationId given the resource identifier + - Compares the generated IPA Compliant OperationId with the existing OperationId + ### IPA-106 From f9f86ab791f74abf2ee3476d125671f2fc6cb8ab Mon Sep 17 00:00:00 2001 From: Sophia Marie Terry Date: Wed, 9 Jul 2025 11:39:13 +0100 Subject: [PATCH 06/11] CLOUDP-328955: Added tests and updated docs for ipa104 opId validation --- tools/spectral/ipa/rulesets/IPA-104.yaml | 8 +++++--- tools/spectral/ipa/rulesets/README.md | 8 +++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/tools/spectral/ipa/rulesets/IPA-104.yaml b/tools/spectral/ipa/rulesets/IPA-104.yaml index 888d94d6c9..447b01b99e 100644 --- a/tools/spectral/ipa/rulesets/IPA-104.yaml +++ b/tools/spectral/ipa/rulesets/IPA-104.yaml @@ -100,15 +100,17 @@ rules: function: 'IPA104GetMethodHasNoRequestBody' xgen-IPA-104-valid-operation-id: description: | - Confirms that the existing operationId is compliant with generated IPA Compliant OperationId. + The Operation ID must start with the verb “get” and should be followed by a noun or compound noun. + The noun(s) in the Operation ID should be the collection identifiers from the resource identifier in singular form. + If the resource is a singleton resource, the last noun may be the plural form of the collection identifier. ##### Implementation details Rule checks for the following conditions: - Applies only to GET methods on single resources or singleton resources - Generates the expected OperationId given the resource identifier - - Compares the generated IPA Compliant OperationId with the existing OperationId + - Confirms that the existing operationId is compliant with generated IPA Compliant OperationId message: '{{error}} https://mdb.link/mongodb-atlas-openapi-validation#xgen-IPA-104-valid-operation-id' - severity: off + severity: warn given: '#GetOperationObject' then: function: 'IPA104ValidOperationID' diff --git a/tools/spectral/ipa/rulesets/README.md b/tools/spectral/ipa/rulesets/README.md index 46b0cc885f..e1cd7b0ff5 100644 --- a/tools/spectral/ipa/rulesets/README.md +++ b/tools/spectral/ipa/rulesets/README.md @@ -141,14 +141,16 @@ Rule checks for the following conditions: #### xgen-IPA-104-valid-operation-id - `off` -Confirms that the existing operationId is compliant with generated IPA Compliant OperationId. + ![warn](https://img.shields.io/badge/warning-yellow) +The Operation ID must start with the verb “get” and should be followed by a noun or compound noun. +The noun(s) in the Operation ID should be the collection identifiers from the resource identifier in singular form. +If the resource is a singleton resource, the last noun may be the plural form of the collection identifier. ##### Implementation details Rule checks for the following conditions: - Applies only to GET methods on single resources or singleton resources - Generates the expected OperationId given the resource identifier - - Compares the generated IPA Compliant OperationId with the existing OperationId + - Confirms that the existing operationId is compliant with generated IPA Compliant OperationId From 7385b31027fddb6faa96bef4f3f530fd3bb061b8 Mon Sep 17 00:00:00 2001 From: Sophia Marie Terry Date: Wed, 9 Jul 2025 11:40:24 +0100 Subject: [PATCH 07/11] CLOUDP-328955: Fixed tests and docs for ipa104 opId validation --- .../__tests__/IPA104ValidOperationID.test.js | 82 +++++++++++++++++++ tools/spectral/ipa/rulesets/IPA-104.yaml | 2 +- tools/spectral/ipa/rulesets/README.md | 2 +- 3 files changed, 84 insertions(+), 2 deletions(-) create mode 100644 tools/spectral/ipa/__tests__/IPA104ValidOperationID.test.js diff --git a/tools/spectral/ipa/__tests__/IPA104ValidOperationID.test.js b/tools/spectral/ipa/__tests__/IPA104ValidOperationID.test.js new file mode 100644 index 0000000000..56db25acbd --- /dev/null +++ b/tools/spectral/ipa/__tests__/IPA104ValidOperationID.test.js @@ -0,0 +1,82 @@ +import testRule from './__helpers__/testRule'; + +// TODO: add tests for xgen-custom-method extension - CLOUDP-306294 +// TOOD: enable tests for invalid methods (after rules are upgraded to warning) - CLOUDP-329722 + +const componentSchemas = { + schemas: { + Schema: { + type: 'object', + }, + }, + operationId: 'string', +}; + +testRule('xgen-IPA-104-valid-operation-id', [ + { + name: 'valid methods', + document: { + components: componentSchemas, + paths: { + '/groups/{groupId}/cluster/{clusterName}': { + post: { + operationId: 'getGroupCluster', + }, + }, + }, + }, + errors: [], + }, + // This test will be enable when the xgen-IPA-104-valid-operation-id is set to warning severity - CLOUDP-329722 + /* { + name: 'invalid methods', + document: { + components: componentSchemas, + paths: { + '/api/atlas/v2/groups/{groupId}/accessList/{entryValue}/status': { + get: { + operationId: 'getProjectIpAccessListStatus', + }, + }, + '/api/atlas/v2/groups/{groupId}/dataFederation/{tenantName}/limits/{limitName}': { + get: { + operationId: 'returnFederatedDatabaseQueryLimit', + }, + }, + }, + }, + errors: [ + { + code: 'xgen-IPA-104-valid-operation-id', + message: + 'Invalid OperationID. The Operation ID must start with the verb “get” and should be followed by a noun or compound noun. The noun(s) should be the collection identifiers from the resource identifier in singular form.', + path: ['paths', '/api/atlas/v2/groups/{groupId}/accessList/{entryValue}/status', 'get'], + severity: DiagnosticSeverity.Warning, + }, + { + code: 'xgen-IPA-104-valid-operation-id', + message: + 'Invalid OperationID. The Operation ID must start with the verb “get” and should be followed by a noun or compound noun. The noun(s) should be the collection identifiers from the resource identifier in singular form.', + path: ['paths', '/api/atlas/v2/groups/{groupId}/dataFederation/{tenantName}/limits/{limitName}', 'get'], + severity: DiagnosticSeverity.Warning, + }, + ], + }, */ + { + name: 'invalid methods with exceptions', + document: { + components: componentSchemas, + paths: { + '/api/atlas/v2/groups/{groupId}/clusters/{clusterName}/index ': { + post: { + operationId: 'getRollingIndex', + 'x-xgen-IPA-exception': { + 'xgen-IPA-104-valid-operation-id': 'Reason', + }, + }, + }, + }, + }, + errors: [], + }, +]); diff --git a/tools/spectral/ipa/rulesets/IPA-104.yaml b/tools/spectral/ipa/rulesets/IPA-104.yaml index 447b01b99e..c365c5ea82 100644 --- a/tools/spectral/ipa/rulesets/IPA-104.yaml +++ b/tools/spectral/ipa/rulesets/IPA-104.yaml @@ -110,7 +110,7 @@ rules: - Generates the expected OperationId given the resource identifier - Confirms that the existing operationId is compliant with generated IPA Compliant OperationId message: '{{error}} https://mdb.link/mongodb-atlas-openapi-validation#xgen-IPA-104-valid-operation-id' - severity: warn + severity: off given: '#GetOperationObject' then: function: 'IPA104ValidOperationID' diff --git a/tools/spectral/ipa/rulesets/README.md b/tools/spectral/ipa/rulesets/README.md index e1cd7b0ff5..0f3635be6c 100644 --- a/tools/spectral/ipa/rulesets/README.md +++ b/tools/spectral/ipa/rulesets/README.md @@ -141,7 +141,7 @@ Rule checks for the following conditions: #### xgen-IPA-104-valid-operation-id - ![warn](https://img.shields.io/badge/warning-yellow) + `off` The Operation ID must start with the verb “get” and should be followed by a noun or compound noun. The noun(s) in the Operation ID should be the collection identifiers from the resource identifier in singular form. If the resource is a singleton resource, the last noun may be the plural form of the collection identifier. From d2d16d5d7df9f3f7848764620a53bc225655c4d9 Mon Sep 17 00:00:00 2001 From: Sophia Marie Terry Date: Wed, 9 Jul 2025 11:51:48 +0100 Subject: [PATCH 08/11] CLOUDP-328955: Update tests and docs --- .../__tests__/IPA104ValidOperationID.test.js | 4 +- .../__tests__/IPA105ValidOperationID.test.js | 82 +++++++++++++++++++ tools/spectral/ipa/rulesets/IPA-105.yaml | 5 +- tools/spectral/ipa/rulesets/README.md | 5 +- .../functions/IPA105ValidOperationID.js | 3 - 5 files changed, 90 insertions(+), 9 deletions(-) create mode 100644 tools/spectral/ipa/__tests__/IPA105ValidOperationID.test.js diff --git a/tools/spectral/ipa/__tests__/IPA104ValidOperationID.test.js b/tools/spectral/ipa/__tests__/IPA104ValidOperationID.test.js index 56db25acbd..32e8863774 100644 --- a/tools/spectral/ipa/__tests__/IPA104ValidOperationID.test.js +++ b/tools/spectral/ipa/__tests__/IPA104ValidOperationID.test.js @@ -19,7 +19,7 @@ testRule('xgen-IPA-104-valid-operation-id', [ components: componentSchemas, paths: { '/groups/{groupId}/cluster/{clusterName}': { - post: { + get: { operationId: 'getGroupCluster', }, }, @@ -68,7 +68,7 @@ testRule('xgen-IPA-104-valid-operation-id', [ components: componentSchemas, paths: { '/api/atlas/v2/groups/{groupId}/clusters/{clusterName}/index ': { - post: { + get: { operationId: 'getRollingIndex', 'x-xgen-IPA-exception': { 'xgen-IPA-104-valid-operation-id': 'Reason', diff --git a/tools/spectral/ipa/__tests__/IPA105ValidOperationID.test.js b/tools/spectral/ipa/__tests__/IPA105ValidOperationID.test.js new file mode 100644 index 0000000000..f30297873e --- /dev/null +++ b/tools/spectral/ipa/__tests__/IPA105ValidOperationID.test.js @@ -0,0 +1,82 @@ +import testRule from './__helpers__/testRule'; + +// TODO: add tests for xgen-custom-method extension - CLOUDP-306294 +// TOOD: enable tests for invalid methods (after rules are upgraded to warning) - CLOUDP-329722 + +const componentSchemas = { + schemas: { + Schema: { + type: 'object', + }, + }, + operationId: 'string', +}; + +testRule('xgen-IPA-105-valid-operation-id', [ + { + name: 'valid methods', + document: { + components: componentSchemas, + paths: { + '/groups/{groupId}/clusters': { + get: { + operationId: 'listGroupClusters', + }, + }, + }, + }, + errors: [], + }, + // This test will be enable when the xgen-IPA-105-valid-operation-id is set to warning severity - CLOUDP-329722 + /* { + name: 'invalid methods', + document: { + components: componentSchemas, + paths: { + '/api/atlas/v2/orgs/{orgId}/teams/{teamId}/users': { + get: { + operationId: 'listTeamUsers', + }, + }, + '/api/atlas/v2/orgs/{orgId}/events': { + get: { + operationId: 'listOrganizationEvents', + }, + }, + }, + }, + errors: [ + { + code: 'xgen-IPA-105-valid-operation-id', + message: + 'Invalid OperationID. The Operation ID must start with the verb “list” and should be followed by a noun or compound noun. The noun(s) should be the collection identifiers from the resource identifier in singular form, where the last noun is in plural form.', + path: ['paths', '/api/atlas/v2/groups/{groupId}/databaseUsers/{username}/certs', 'get'], + severity: DiagnosticSeverity.Warning, + }, + { + code: 'xgen-IPA-105-valid-operation-id', + message: + 'Invalid OperationID. The Operation ID must start with the verb “list” and should be followed by a noun or compound noun. The noun(s) should be the collection identifiers from the resource identifier in singular form, where the last noun is in plural form.', + path: ['paths', '/api/atlas/v2/orgs/{orgId}/events', 'get'], + severity: DiagnosticSeverity.Warning, + }, + ], + }, */ + { + name: 'invalid methods with exceptions', + document: { + components: componentSchemas, + paths: { + '/api/atlas/v2/groups/{groupId}/clusters/{clusterName}/outageSimulation': { + get: { + operationId: 'getOutageSimulation', + 'x-xgen-IPA-exception': { + 'xgen-IPA-105-valid-operation-id': 'Reason', + }, + }, + }, + }, + }, + errors: [], + }, +]); diff --git a/tools/spectral/ipa/rulesets/IPA-105.yaml b/tools/spectral/ipa/rulesets/IPA-105.yaml index 330459ecaf..0b19ddd787 100644 --- a/tools/spectral/ipa/rulesets/IPA-105.yaml +++ b/tools/spectral/ipa/rulesets/IPA-105.yaml @@ -80,14 +80,15 @@ rules: function: 'IPA105ListMethodResponseIsGetMethodResponse' xgen-IPA-105-valid-operation-id: description: | - Confirms that the existing operationId is compliant with generated IPA Compliant OperationId. + The Operation ID must start with the verb “list” and should be followed by a noun or compound noun. + The noun(s) in the Operation ID should be the collection identifiers from the resource identifier in singular form, where the last noun is in plural form. ##### Implementation details Rule checks for the following conditions: - Applies only to GET methods on resource collection paths - Ignores singleton resources - Generates the expected OperationId given the resource identifier - - Compares the generated IPA Compliant OperationId with the existing OperationId + - Confirms that the existing operationId is compliant with generated IPA Compliant OperationId message: '{{error}} https://mdb.link/mongodb-atlas-openapi-validation#xgen-IPA-105-valid-operation-id' severity: off given: '#GetOperationObject' diff --git a/tools/spectral/ipa/rulesets/README.md b/tools/spectral/ipa/rulesets/README.md index 0f3635be6c..ec61112a14 100644 --- a/tools/spectral/ipa/rulesets/README.md +++ b/tools/spectral/ipa/rulesets/README.md @@ -209,14 +209,15 @@ The response body of the List method should consist of the same resource object #### xgen-IPA-105-valid-operation-id `off` -Confirms that the existing operationId is compliant with generated IPA Compliant OperationId. +The Operation ID must start with the verb “list” and should be followed by a noun or compound noun. +The noun(s) in the Operation ID should be the collection identifiers from the resource identifier in singular form, where the last noun is in plural form. ##### Implementation details Rule checks for the following conditions: - Applies only to GET methods on resource collection paths - Ignores singleton resources - Generates the expected OperationId given the resource identifier - - Compares the generated IPA Compliant OperationId with the existing OperationId + - Confirms that the existing operationId is compliant with generated IPA Compliant OperationId diff --git a/tools/spectral/ipa/rulesets/functions/IPA105ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA105ValidOperationID.js index 1debc00331..3bb13e2cb3 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA105ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA105ValidOperationID.js @@ -31,9 +31,6 @@ export default (input, { methodName }, { path, documentInventory }) => { const expectedOperationId = generateOperationID(methodName, resourcePath); if (expectedOperationId !== input.operationId) { - console.log( - `${input.operationId}, ${expectedOperationId}, ${resourcePath}, ${input.deprecated ? 'TRUE' : 'FALSE'}, ${(resourcePath, input['x-xgen-owner-team'])}` - ); const errors = [ { path, From c1efd5b3737cd4c4d4f89906bd1755d0c0c09ab3 Mon Sep 17 00:00:00 2001 From: Sophia Marie Terry Date: Wed, 9 Jul 2025 12:15:42 +0100 Subject: [PATCH 09/11] CLOUDP-328955: Removed unused schema --- .../ipa/__tests__/IPA104ValidOperationID.test.js | 12 ------------ .../ipa/__tests__/IPA105ValidOperationID.test.js | 12 ------------ 2 files changed, 24 deletions(-) diff --git a/tools/spectral/ipa/__tests__/IPA104ValidOperationID.test.js b/tools/spectral/ipa/__tests__/IPA104ValidOperationID.test.js index 32e8863774..cff141067a 100644 --- a/tools/spectral/ipa/__tests__/IPA104ValidOperationID.test.js +++ b/tools/spectral/ipa/__tests__/IPA104ValidOperationID.test.js @@ -3,20 +3,10 @@ import testRule from './__helpers__/testRule'; // TODO: add tests for xgen-custom-method extension - CLOUDP-306294 // TOOD: enable tests for invalid methods (after rules are upgraded to warning) - CLOUDP-329722 -const componentSchemas = { - schemas: { - Schema: { - type: 'object', - }, - }, - operationId: 'string', -}; - testRule('xgen-IPA-104-valid-operation-id', [ { name: 'valid methods', document: { - components: componentSchemas, paths: { '/groups/{groupId}/cluster/{clusterName}': { get: { @@ -31,7 +21,6 @@ testRule('xgen-IPA-104-valid-operation-id', [ /* { name: 'invalid methods', document: { - components: componentSchemas, paths: { '/api/atlas/v2/groups/{groupId}/accessList/{entryValue}/status': { get: { @@ -65,7 +54,6 @@ testRule('xgen-IPA-104-valid-operation-id', [ { name: 'invalid methods with exceptions', document: { - components: componentSchemas, paths: { '/api/atlas/v2/groups/{groupId}/clusters/{clusterName}/index ': { get: { diff --git a/tools/spectral/ipa/__tests__/IPA105ValidOperationID.test.js b/tools/spectral/ipa/__tests__/IPA105ValidOperationID.test.js index f30297873e..eda4656182 100644 --- a/tools/spectral/ipa/__tests__/IPA105ValidOperationID.test.js +++ b/tools/spectral/ipa/__tests__/IPA105ValidOperationID.test.js @@ -3,20 +3,10 @@ import testRule from './__helpers__/testRule'; // TODO: add tests for xgen-custom-method extension - CLOUDP-306294 // TOOD: enable tests for invalid methods (after rules are upgraded to warning) - CLOUDP-329722 -const componentSchemas = { - schemas: { - Schema: { - type: 'object', - }, - }, - operationId: 'string', -}; - testRule('xgen-IPA-105-valid-operation-id', [ { name: 'valid methods', document: { - components: componentSchemas, paths: { '/groups/{groupId}/clusters': { get: { @@ -31,7 +21,6 @@ testRule('xgen-IPA-105-valid-operation-id', [ /* { name: 'invalid methods', document: { - components: componentSchemas, paths: { '/api/atlas/v2/orgs/{orgId}/teams/{teamId}/users': { get: { @@ -65,7 +54,6 @@ testRule('xgen-IPA-105-valid-operation-id', [ { name: 'invalid methods with exceptions', document: { - components: componentSchemas, paths: { '/api/atlas/v2/groups/{groupId}/clusters/{clusterName}/outageSimulation': { get: { From 4e790b480033b6946ec78b9243a3c19c9888ad95 Mon Sep 17 00:00:00 2001 From: Sophia Marie Terry Date: Wed, 9 Jul 2025 16:10:28 +0100 Subject: [PATCH 10/11] Removed rogue print statement oops --- .../spectral/ipa/rulesets/functions/IPA107ValidOperationID.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js index 526b2a4660..bb9c8aa817 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js @@ -33,9 +33,6 @@ export default (input, { methodName }, { path, documentInventory }) => { const expectedOperationID = generateOperationID(methodName, resourcePath); if (expectedOperationID !== input.operationId) { - console.log( - `${input.operationId}, ${expectedOperationID}, ${resourcePath}, ${input.deprecated ? 'TRUE' : 'FALSE'}, ${(resourcePath, input['x-xgen-owner-team'])}` - ); const errors = [ { path, From 2af9621029034ab2f8e6ac893e70302c55c847a2 Mon Sep 17 00:00:00 2001 From: Sophia Marie Terry Date: Wed, 9 Jul 2025 17:19:22 +0100 Subject: [PATCH 11/11] Shortened error messages --- .../spectral/ipa/rulesets/functions/IPA104ValidOperationID.js | 3 +-- .../spectral/ipa/rulesets/functions/IPA105ValidOperationID.js | 3 +-- .../spectral/ipa/rulesets/functions/IPA106ValidOperationID.js | 3 +-- .../spectral/ipa/rulesets/functions/IPA107ValidOperationID.js | 3 +-- .../spectral/ipa/rulesets/functions/IPA108ValidOperationID.js | 3 +-- 5 files changed, 5 insertions(+), 10 deletions(-) diff --git a/tools/spectral/ipa/rulesets/functions/IPA104ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA104ValidOperationID.js index af9e063199..f2583bfbb4 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA104ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA104ValidOperationID.js @@ -10,8 +10,7 @@ import { } from './utils/resourceEvaluation.js'; const RULE_NAME = 'xgen-IPA-104-valid-operation-id'; -const ERROR_MESSAGE = - 'Invalid OperationID. The Operation ID must start with the verb “get” and should be followed by a noun or compound noun. The noun(s) should be the collection identifiers from the resource identifier in singular form.'; +const ERROR_MESSAGE = 'Invalid OperationID.'; export default (input, { methodName }, { path, documentInventory }) => { const resourcePath = path[1]; diff --git a/tools/spectral/ipa/rulesets/functions/IPA105ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA105ValidOperationID.js index 3bb13e2cb3..f35a694631 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA105ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA105ValidOperationID.js @@ -9,8 +9,7 @@ import { import { generateOperationID } from './utils/operationIdGeneration.js'; const RULE_NAME = 'xgen-IPA-105-valid-operation-id'; -const ERROR_MESSAGE = - 'Invalid OperationID. The Operation ID must start with the verb “list” and should be followed by a noun or compound noun. The noun(s) should be the collection identifiers from the resource identifier in singular form, where the last noun is in plural form.'; +const ERROR_MESSAGE = 'Invalid OperationID.'; export default (input, { methodName }, { path, documentInventory }) => { const resourcePath = path[1]; diff --git a/tools/spectral/ipa/rulesets/functions/IPA106ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA106ValidOperationID.js index c50a5c6cdd..0b4c5039ad 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA106ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA106ValidOperationID.js @@ -9,8 +9,7 @@ import { import { generateOperationID } from './utils/operationIdGeneration.js'; const RULE_NAME = 'xgen-IPA-106-valid-operation-id'; -const ERROR_MESSAGE = - 'Invalid OperationID. The Operation ID must start with the verb “create” and should be followed by a noun or compound noun. The noun(s) in the Operation ID should be the collection identifiers from the resource identifier in singular form.'; +const ERROR_MESSAGE = 'Invalid OperationID.'; export default (input, { methodName }, { path, documentInventory }) => { const resourcePath = path[1]; diff --git a/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js index bb9c8aa817..5e95184694 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js @@ -10,8 +10,7 @@ import { import { generateOperationID } from './utils/operationIdGeneration.js'; const RULE_NAME = 'xgen-IPA-107-valid-operation-id'; -const ERROR_MESSAGE = - 'Invalid OperationID. The Operation ID must start with the verb “update” and should be followed by a noun or compound noun. The noun(s) in the Operation ID should be the collection identifiers from the resource identifier in singular form. For singleton resources - the last noun may be in plural form.'; +const ERROR_MESSAGE = 'Invalid OperationID.'; export default (input, { methodName }, { path, documentInventory }) => { const resourcePath = path[1]; diff --git a/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js index 03aa2eab2c..3f4dfef420 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js @@ -4,8 +4,7 @@ import { isCustomMethodIdentifier, isSingleResourceIdentifier } from './utils/re import { generateOperationID } from './utils/operationIdGeneration.js'; const RULE_NAME = 'xgen-IPA-108-valid-operation-id'; -const ERROR_MESSAGE = - 'Invalid OperationID. The Operation ID must start with the verb “delete” and should be followed by a noun or compound noun. The noun(s) in the Operation ID should be the collection identifiers from the resource identifier in singular form.'; +const ERROR_MESSAGE = 'Invalid OperationID.'; export default (input, { methodName }, { path }) => { const resourcePath = path[1];