From cbaf505a61aafde51ffdf288e4676fb17174b0e9 Mon Sep 17 00:00:00 2001 From: Sophia Marie Terry Date: Thu, 3 Jul 2025 18:21:26 +0100 Subject: [PATCH 01/25] 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 eba00105148cbc6e2c0110b02e5fb27fc21d3f8d Mon Sep 17 00:00:00 2001 From: Sophia Marie Terry Date: Fri, 4 Jul 2025 14:49:57 +0100 Subject: [PATCH 02/25] CLOUDP-328959: Added helper method for stripping custom method names --- .../ipa/rulesets/functions/utils/resourceEvaluation.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/spectral/ipa/rulesets/functions/utils/resourceEvaluation.js b/tools/spectral/ipa/rulesets/functions/utils/resourceEvaluation.js index e872646ee1..ede0257308 100644 --- a/tools/spectral/ipa/rulesets/functions/utils/resourceEvaluation.js +++ b/tools/spectral/ipa/rulesets/functions/utils/resourceEvaluation.js @@ -57,6 +57,10 @@ export function getCustomMethodName(path) { return path.split(':')[1]; } +export function stripCustomMethodName(path){ + return path.substring(0, path.indexOf(':')); +} + export function isPathParam(string) { return string.startsWith('{') && string.endsWith('}'); } From 06d1ca1f18f397fb472c53a48d7c1c8a431cfa92 Mon Sep 17 00:00:00 2001 From: Sophia Marie Terry Date: Fri, 4 Jul 2025 14:53:05 +0100 Subject: [PATCH 03/25] CLOUDP-328959: Implemented basic Operation ID Validation for create operations --- .../functions/IPA106ValidOperationID.js | 34 +++++++++++++++++++ .../functions/utils/resourceEvaluation.js | 2 +- 2 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 tools/spectral/ipa/rulesets/functions/IPA106ValidOperationID.js diff --git a/tools/spectral/ipa/rulesets/functions/IPA106ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA106ValidOperationID.js new file mode 100644 index 0000000000..315b399571 --- /dev/null +++ b/tools/spectral/ipa/rulesets/functions/IPA106ValidOperationID.js @@ -0,0 +1,34 @@ +import { hasException } from './utils/exceptions.js'; +import { collectAdoption, collectAndReturnViolation } from './utils/collectionUtils.js'; +import { isCustomMethodIdentifier, getCustomMethodName, stripCustomMethodName } from './utils/resourceEvaluation.js'; +import { generateOperationID } from './utils/operationIdGeneration.js'; + +const RULE_NAME = 'xgen-IPA-106-valid-operation-id'; +const ERROR_MESSAGE = 'Invalid OperationID'; + +export default (input, _, { path, documentInventory }) => { + let resourcePath = path[1]; + const oas = documentInventory.resolved; + let methodName = 'create'; + + // TODO detect exceptions + + if (isCustomMethodIdentifier(resourcePath)) { + methodName = getCustomMethodName(resourcePath); + resourcePath = stripCustomMethodName(resourcePath); + } + + let errors = []; + const expectedOperationID = generateOperationID(methodName, resourcePath); + if (expectedOperationID != input.operationId) { + errors.push({ + path: path, + message: `${ERROR_MESSAGE} Found ${input.operationId} expected ${expectedOperationID}.`, + }); + } + + if (errors.length !== 0) { + return collectAndReturnViolation(path, RULE_NAME, errors); + } + collectAdoption(path, RULE_NAME); +}; diff --git a/tools/spectral/ipa/rulesets/functions/utils/resourceEvaluation.js b/tools/spectral/ipa/rulesets/functions/utils/resourceEvaluation.js index ede0257308..9d6888b8fd 100644 --- a/tools/spectral/ipa/rulesets/functions/utils/resourceEvaluation.js +++ b/tools/spectral/ipa/rulesets/functions/utils/resourceEvaluation.js @@ -57,7 +57,7 @@ export function getCustomMethodName(path) { return path.split(':')[1]; } -export function stripCustomMethodName(path){ +export function stripCustomMethodName(path) { return path.substring(0, path.indexOf(':')); } From f6ff5dd487d7802c2964eeec47c7a4d9c8ee7203 Mon Sep 17 00:00:00 2001 From: Sophia Marie Terry Date: Fri, 4 Jul 2025 15:09:36 +0100 Subject: [PATCH 04/25] CLOUDP-328959: Implemented basic Operation ID Validation for delete operations --- .../functions/IPA108ValidOperationID.js | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js diff --git a/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js new file mode 100644 index 0000000000..69ad0bfac1 --- /dev/null +++ b/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js @@ -0,0 +1,34 @@ +import { hasException } from './utils/exceptions.js'; +import { collectAdoption, collectAndReturnViolation } from './utils/collectionUtils.js'; +import { isCustomMethodIdentifier, getCustomMethodName, stripCustomMethodName } from './utils/resourceEvaluation.js'; +import { generateOperationID } from './utils/operationIdGeneration.js'; + +const RULE_NAME = 'xgen-IPA-108-valid-operation-id'; +const ERROR_MESSAGE = 'Invalid OperationID'; + +export default (input, _, { path, documentInventory }) => { + let resourcePath = path[1]; + const oas = documentInventory.resolved; + let methodName = 'delete'; + + // TODO detect exceptions + + if (isCustomMethodIdentifier(resourcePath)) { + methodName = getCustomMethodName(resourcePath); + resourcePath = stripCustomMethodName(resourcePath); + } + + let errors = []; + const expectedOperationID = generateOperationID(methodName, resourcePath); + if (expectedOperationID != input.operationId) { + errors.push({ + path: path, + message: `${ERROR_MESSAGE} Found ${input.operationId} expected ${expectedOperationID}.`, + }); + } + + if (errors.length !== 0) { + return collectAndReturnViolation(path, RULE_NAME, errors); + } + collectAdoption(path, RULE_NAME); +}; From 53692d855ca2c1305323b2493b89ce52dcf5c42b Mon Sep 17 00:00:00 2001 From: Sophia Marie Terry Date: Fri, 4 Jul 2025 15:16:40 +0100 Subject: [PATCH 05/25] CLOUDP-328959: Implemented basic Operation ID Validation for update operations --- .../functions/IPA107ValidOperationID.js | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js diff --git a/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js new file mode 100644 index 0000000000..3180f354c1 --- /dev/null +++ b/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js @@ -0,0 +1,34 @@ +import { hasException } from './utils/exceptions.js'; +import { collectAdoption, collectAndReturnViolation } from './utils/collectionUtils.js'; +import { isCustomMethodIdentifier, getCustomMethodName, stripCustomMethodName } from './utils/resourceEvaluation.js'; +import { generateOperationID } from './utils/operationIdGeneration.js'; + +const RULE_NAME = 'xgen-IPA-107-valid-operation-id'; +const ERROR_MESSAGE = 'Invalid OperationID'; + +export default (input, _, { path, documentInventory }) => { + let resourcePath = path[1]; + const oas = documentInventory.resolved; + let methodName = 'update'; + + // TODO detect exceptions + + if (isCustomMethodIdentifier(resourcePath)) { + methodName = getCustomMethodName(resourcePath); + resourcePath = stripCustomMethodName(resourcePath); + } + + let errors = []; + const expectedOperationID = generateOperationID(methodName, resourcePath); + if (expectedOperationID != input.operationId) { + errors.push({ + path: path, + message: `${ERROR_MESSAGE} Found ${input.operationId} expected ${expectedOperationID}.`, + }); + } + + if (errors.length !== 0) { + return collectAndReturnViolation(path, RULE_NAME, errors); + } + collectAdoption(path, RULE_NAME); +}; From 98cc8a18708018808f68d03e42c7c367006ed943 Mon Sep 17 00:00:00 2001 From: Sophia Terry <157913563+sphterry@users.noreply.github.com> Date: Mon, 7 Jul 2025 14:20:55 +0100 Subject: [PATCH 06/25] Update tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js Co-authored-by: Matt Condon --- .../rulesets/functions/IPA108ValidOperationID.js | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js index 69ad0bfac1..0a41bb44c3 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js @@ -18,17 +18,15 @@ export default (input, _, { path, documentInventory }) => { resourcePath = stripCustomMethodName(resourcePath); } - let errors = []; - const expectedOperationID = generateOperationID(methodName, resourcePath); - if (expectedOperationID != input.operationId) { - errors.push({ - path: path, - message: `${ERROR_MESSAGE} Found ${input.operationId} expected ${expectedOperationID}.`, - }); - } - if (errors.length !== 0) { + const expectedOperationID = generateOperationID(methodName, 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); }; From 6360e10d829c3fb4c7ed25fd6508c6253f4206eb Mon Sep 17 00:00:00 2001 From: Sophia Marie Terry Date: Mon, 7 Jul 2025 14:54:04 +0100 Subject: [PATCH 07/25] CLOUDP-328959: Fixed error handling pattern --- .../functions/IPA106ValidOperationID.js | 17 ++++++++--------- .../functions/IPA107ValidOperationID.js | 17 ++++++++--------- .../functions/IPA108ValidOperationID.js | 13 +++++++------ 3 files changed, 23 insertions(+), 24 deletions(-) diff --git a/tools/spectral/ipa/rulesets/functions/IPA106ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA106ValidOperationID.js index 315b399571..143c965721 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA106ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA106ValidOperationID.js @@ -18,17 +18,16 @@ export default (input, _, { path, documentInventory }) => { resourcePath = stripCustomMethodName(resourcePath); } - let errors = []; const expectedOperationID = generateOperationID(methodName, resourcePath); - if (expectedOperationID != input.operationId) { - errors.push({ - path: path, - message: `${ERROR_MESSAGE} Found ${input.operationId} expected ${expectedOperationID}.`, - }); - } - - if (errors.length !== 0) { + 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); }; diff --git a/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js index 3180f354c1..5519fa9e96 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js @@ -18,17 +18,16 @@ export default (input, _, { path, documentInventory }) => { resourcePath = stripCustomMethodName(resourcePath); } - let errors = []; const expectedOperationID = generateOperationID(methodName, resourcePath); - if (expectedOperationID != input.operationId) { - errors.push({ - path: path, - message: `${ERROR_MESSAGE} Found ${input.operationId} expected ${expectedOperationID}.`, - }); - } - - if (errors.length !== 0) { + 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); }; diff --git a/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js index 0a41bb44c3..5a529b4cf8 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js @@ -18,13 +18,14 @@ export default (input, _, { path, documentInventory }) => { resourcePath = stripCustomMethodName(resourcePath); } - - const expectedOperationID = generateOperationID(methodName, resourcePath);  + const expectedOperationID = generateOperationID(methodName, resourcePath); if (expectedOperationID !== input.operationId) { - const errors = [{ - path, - message: `${ERROR_MESSAGE} Found ${input.operationId}, expected ${expectedOperationID}.`, - }]; + const errors = [ + { + path, + message: `${ERROR_MESSAGE} Found ${input.operationId}, expected ${expectedOperationID}.`, + }, + ]; return collectAndReturnViolation(path, RULE_NAME, errors); } From f47ef0a7b131ebb283aae67588d24c62a4283cf7 Mon Sep 17 00:00:00 2001 From: Sophia Marie Terry Date: Mon, 7 Jul 2025 15:02:36 +0100 Subject: [PATCH 08/25] CLOUDP-328959: Added more verbose error messages --- .../spectral/ipa/rulesets/functions/IPA106ValidOperationID.js | 3 ++- .../spectral/ipa/rulesets/functions/IPA107ValidOperationID.js | 3 ++- .../spectral/ipa/rulesets/functions/IPA108ValidOperationID.js | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/tools/spectral/ipa/rulesets/functions/IPA106ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA106ValidOperationID.js index 143c965721..e2eb9fe2b3 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA106ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA106ValidOperationID.js @@ -4,7 +4,8 @@ import { isCustomMethodIdentifier, getCustomMethodName, stripCustomMethodName } import { generateOperationID } from './utils/operationIdGeneration.js'; const RULE_NAME = 'xgen-IPA-106-valid-operation-id'; -const ERROR_MESSAGE = 'Invalid OperationID'; +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'; export default (input, _, { path, documentInventory }) => { let resourcePath = path[1]; diff --git a/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js index 5519fa9e96..e983d374e8 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js @@ -4,7 +4,8 @@ import { isCustomMethodIdentifier, getCustomMethodName, stripCustomMethodName } import { generateOperationID } from './utils/operationIdGeneration.js'; const RULE_NAME = 'xgen-IPA-107-valid-operation-id'; -const ERROR_MESSAGE = 'Invalid OperationID'; +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.'; export default (input, _, { path, documentInventory }) => { let resourcePath = path[1]; diff --git a/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js index 5a529b4cf8..98c85f26de 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js @@ -4,7 +4,8 @@ import { isCustomMethodIdentifier, getCustomMethodName, stripCustomMethodName } import { generateOperationID } from './utils/operationIdGeneration.js'; const RULE_NAME = 'xgen-IPA-108-valid-operation-id'; -const ERROR_MESSAGE = 'Invalid OperationID'; +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.'; export default (input, _, { path, documentInventory }) => { let resourcePath = path[1]; From 5e7a26edbc1516ce9c46a77146dbf716c2f57715 Mon Sep 17 00:00:00 2001 From: Sophia Marie Terry Date: Mon, 7 Jul 2025 15:41:34 +0100 Subject: [PATCH 09/25] CLOUDP-328959: Added exception handling and removed used variables --- .../ipa/rulesets/functions/IPA106ValidOperationID.js | 10 +++++++--- .../ipa/rulesets/functions/IPA107ValidOperationID.js | 8 ++++++-- .../ipa/rulesets/functions/IPA108ValidOperationID.js | 8 ++++++-- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/tools/spectral/ipa/rulesets/functions/IPA106ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA106ValidOperationID.js index e2eb9fe2b3..479410acf7 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA106ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA106ValidOperationID.js @@ -5,14 +5,18 @@ 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'; + '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.'; export default (input, _, { path, documentInventory }) => { let resourcePath = path[1]; - const oas = documentInventory.resolved; let methodName = 'create'; - // TODO detect exceptions + if (hasException(createMethodResponse, RULE_NAME)) { + collectException(createMethodResponse, RULE_NAME, path); + return; + } + + // TODO detect custom method extension - CLOUDP-306294 if (isCustomMethodIdentifier(resourcePath)) { methodName = getCustomMethodName(resourcePath); diff --git a/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js index e983d374e8..50b4aa5972 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js @@ -9,10 +9,14 @@ const ERROR_MESSAGE = export default (input, _, { path, documentInventory }) => { let resourcePath = path[1]; - const oas = documentInventory.resolved; let methodName = 'update'; - // TODO detect exceptions + if (hasException(createMethodResponse, RULE_NAME)) { + collectException(createMethodResponse, RULE_NAME, path); + return; + } + + // TODO detect custom method extension - CLOUDP-306294 if (isCustomMethodIdentifier(resourcePath)) { methodName = getCustomMethodName(resourcePath); diff --git a/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js index 98c85f26de..2ce1eb9894 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js @@ -9,10 +9,14 @@ const ERROR_MESSAGE = export default (input, _, { path, documentInventory }) => { let resourcePath = path[1]; - const oas = documentInventory.resolved; let methodName = 'delete'; - // TODO detect exceptions + if (hasException(createMethodResponse, RULE_NAME)) { + collectException(createMethodResponse, RULE_NAME, path); + return; + } + + // TODO detect custom method extension - CLOUDP-306294 if (isCustomMethodIdentifier(resourcePath)) { methodName = getCustomMethodName(resourcePath); From ff9eb081a79317f1c4805a32a9826daf2825120f Mon Sep 17 00:00:00 2001 From: Sophia Marie Terry Date: Mon, 7 Jul 2025 15:48:58 +0100 Subject: [PATCH 10/25] CLOUDP-328959: 'prettier' new line --- .../ipa/rulesets/functions/IPA106ValidOperationID.js | 2 +- .../ipa/rulesets/functions/IPA107ValidOperationID.js | 12 ++++++------ .../ipa/rulesets/functions/IPA108ValidOperationID.js | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tools/spectral/ipa/rulesets/functions/IPA106ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA106ValidOperationID.js index 479410acf7..f29aa5cc26 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA106ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA106ValidOperationID.js @@ -15,7 +15,7 @@ export default (input, _, { path, documentInventory }) => { collectException(createMethodResponse, RULE_NAME, path); return; } - + // TODO detect custom method extension - CLOUDP-306294 if (isCustomMethodIdentifier(resourcePath)) { diff --git a/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js index 50b4aa5972..b515d6cff8 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js @@ -11,12 +11,12 @@ export default (input, _, { path, documentInventory }) => { let resourcePath = path[1]; let methodName = 'update'; - if (hasException(createMethodResponse, RULE_NAME)) { - collectException(createMethodResponse, RULE_NAME, path); - return; - } - - // TODO detect custom method extension - CLOUDP-306294 + if (hasException(createMethodResponse, RULE_NAME)) { + collectException(createMethodResponse, RULE_NAME, path); + return; + } + + // TODO detect custom method extension - CLOUDP-306294 if (isCustomMethodIdentifier(resourcePath)) { methodName = getCustomMethodName(resourcePath); diff --git a/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js index 2ce1eb9894..6bbd3f7218 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js @@ -15,7 +15,7 @@ export default (input, _, { path, documentInventory }) => { collectException(createMethodResponse, RULE_NAME, path); return; } - + // TODO detect custom method extension - CLOUDP-306294 if (isCustomMethodIdentifier(resourcePath)) { From d17c7b66ca4a781c89c2bcb412a9b14fdb43294a Mon Sep 17 00:00:00 2001 From: Sophia Marie Terry Date: Mon, 7 Jul 2025 15:56:36 +0100 Subject: [PATCH 11/25] CLOUDP-328959: Fixed exceptions and imports --- .../ipa/rulesets/functions/IPA106ValidOperationID.js | 8 ++++---- .../ipa/rulesets/functions/IPA107ValidOperationID.js | 8 ++++---- .../ipa/rulesets/functions/IPA108ValidOperationID.js | 8 ++++---- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/tools/spectral/ipa/rulesets/functions/IPA106ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA106ValidOperationID.js index f29aa5cc26..fb74ae261f 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA106ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA106ValidOperationID.js @@ -1,5 +1,5 @@ import { hasException } from './utils/exceptions.js'; -import { collectAdoption, collectAndReturnViolation } from './utils/collectionUtils.js'; +import { collectAdoption, collectException, collectAndReturnViolation } from './utils/collectionUtils.js'; import { isCustomMethodIdentifier, getCustomMethodName, stripCustomMethodName } from './utils/resourceEvaluation.js'; import { generateOperationID } from './utils/operationIdGeneration.js'; @@ -7,12 +7,12 @@ 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.'; -export default (input, _, { path, documentInventory }) => { +export default (input, _, { path, _ }) => { let resourcePath = path[1]; let methodName = 'create'; - if (hasException(createMethodResponse, RULE_NAME)) { - collectException(createMethodResponse, RULE_NAME, path); + if (hasException(input, RULE_NAME)) { + collectException(input, RULE_NAME, path); return; } diff --git a/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js index b515d6cff8..d9e82a5587 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js @@ -1,5 +1,5 @@ import { hasException } from './utils/exceptions.js'; -import { collectAdoption, collectAndReturnViolation } from './utils/collectionUtils.js'; +import { collectAdoption, collectException, collectAndReturnViolation } from './utils/collectionUtils.js'; import { isCustomMethodIdentifier, getCustomMethodName, stripCustomMethodName } from './utils/resourceEvaluation.js'; import { generateOperationID } from './utils/operationIdGeneration.js'; @@ -7,12 +7,12 @@ 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.'; -export default (input, _, { path, documentInventory }) => { +export default (input, _, { path, _ }) => { let resourcePath = path[1]; let methodName = 'update'; - if (hasException(createMethodResponse, RULE_NAME)) { - collectException(createMethodResponse, RULE_NAME, path); + if (hasException(input, RULE_NAME)) { + collectException(input, RULE_NAME, path); return; } diff --git a/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js index 6bbd3f7218..275096b441 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js @@ -1,5 +1,5 @@ import { hasException } from './utils/exceptions.js'; -import { collectAdoption, collectAndReturnViolation } from './utils/collectionUtils.js'; +import { collectAdoption, collectException, collectAndReturnViolation } from './utils/collectionUtils.js'; import { isCustomMethodIdentifier, getCustomMethodName, stripCustomMethodName } from './utils/resourceEvaluation.js'; import { generateOperationID } from './utils/operationIdGeneration.js'; @@ -7,12 +7,12 @@ 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.'; -export default (input, _, { path, documentInventory }) => { +export default (input, _, { path, _ }) => { let resourcePath = path[1]; let methodName = 'delete'; - if (hasException(createMethodResponse, RULE_NAME)) { - collectException(createMethodResponse, RULE_NAME, path); + if (hasException(input, RULE_NAME)) { + collectException(input, RULE_NAME, path); return; } From 60197ca673c995889950f14dc841676fc7aac514 Mon Sep 17 00:00:00 2001 From: Sophia Marie Terry Date: Mon, 7 Jul 2025 18:01:42 +0100 Subject: [PATCH 12/25] CLOUDP-328959: Added opID validation yaml for IPA106 and fixed lint error --- tools/spectral/ipa/rulesets/IPA-106.yaml | 15 +++++++++++++++ .../rulesets/functions/IPA106ValidOperationID.js | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/tools/spectral/ipa/rulesets/IPA-106.yaml b/tools/spectral/ipa/rulesets/IPA-106.yaml index 4d0be2b13b..c59a45e27b 100644 --- a/tools/spectral/ipa/rulesets/IPA-106.yaml +++ b/tools/spectral/ipa/rulesets/IPA-106.yaml @@ -8,6 +8,7 @@ functions: - IPA106CreateMethodRequestHasNoReadonlyFields - IPA106CreateMethodResponseCodeIs201Created - IPA106CreateMethodResponseIsGetMethodResponse + - IPA106ValidOperationID aliases: CreateOperationObject: @@ -112,3 +113,17 @@ rules: then: field: '@key' function: 'IPA106CreateMethodResponseIsGetMethodResponse' + xgen-IPA-106-valid-operation-id: + description: | + OperationID should be compliant with IPA-106 Naming guidelines. + + ##### Implementation details + Rule checks for the following conditions: + - Applies only to POST methods on resource collection paths + - 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-106-valid-operation-id' + severity: off + given: '#CreateOperationObject' + then: + function: 'IPA106ValidOperationID' diff --git a/tools/spectral/ipa/rulesets/functions/IPA106ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA106ValidOperationID.js index fb74ae261f..688241b41e 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA106ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA106ValidOperationID.js @@ -7,7 +7,7 @@ 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.'; -export default (input, _, { path, _ }) => { +export default (input, _, { path }) => { let resourcePath = path[1]; let methodName = 'create'; From 769a4a08a71218ab2fd4a328658a717e3abe5be6 Mon Sep 17 00:00:00 2001 From: Sophia Marie Terry Date: Mon, 7 Jul 2025 18:05:41 +0100 Subject: [PATCH 13/25] CLOUDP-328959: Added opID validation yaml for IPA107 and fixed lint error --- tools/spectral/ipa/rulesets/IPA-107.yaml | 15 +++++++++++++++ .../rulesets/functions/IPA107ValidOperationID.js | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/tools/spectral/ipa/rulesets/IPA-107.yaml b/tools/spectral/ipa/rulesets/IPA-107.yaml index eae2d30d91..b94c390c46 100644 --- a/tools/spectral/ipa/rulesets/IPA-107.yaml +++ b/tools/spectral/ipa/rulesets/IPA-107.yaml @@ -8,6 +8,7 @@ functions: - IPA107UpdateMethodRequestHasNoReadonlyFields - IPA107UpdateMethodRequestBodyIsGetResponse - IPA107UpdateMethodRequestBodyIsUpdateRequestSuffixedObject + - IPA107ValidOperationID aliases: UpdateOperationObject: @@ -112,3 +113,17 @@ rules: then: field: '@key' function: 'IPA107UpdateMethodRequestBodyIsUpdateRequestSuffixedObject' + xgen-IPA-107-valid-operation-id: + description: | + OperationID should be compliant with IPA-107 Naming guidelines. + + ##### Implementation details + Rule checks for the following conditions: + - Validation checks the PATCH/PUT methods for single resource paths and [singleton resources](https://go/ipa/113). + - 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-107-valid-operation-id' + severity: error + given: '#UpdateOperationObject' + then: + function: 'IPA107ValidOperationID' diff --git a/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js index d9e82a5587..98a18b1ee9 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js @@ -7,7 +7,7 @@ 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.'; -export default (input, _, { path, _ }) => { +export default (input, _, { path }) => { let resourcePath = path[1]; let methodName = 'update'; From 11f4aab253df63a983c55cf55b86483fde96c40a Mon Sep 17 00:00:00 2001 From: Sophia Marie Terry Date: Mon, 7 Jul 2025 18:09:14 +0100 Subject: [PATCH 14/25] CLOUDP-328959: Added opID validation yaml for IPA108 and fixed lint error --- tools/spectral/ipa/rulesets/IPA-107.yaml | 2 +- tools/spectral/ipa/rulesets/IPA-108.yaml | 15 +++++++++++++++ .../rulesets/functions/IPA108ValidOperationID.js | 2 +- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/tools/spectral/ipa/rulesets/IPA-107.yaml b/tools/spectral/ipa/rulesets/IPA-107.yaml index b94c390c46..b07dec78bf 100644 --- a/tools/spectral/ipa/rulesets/IPA-107.yaml +++ b/tools/spectral/ipa/rulesets/IPA-107.yaml @@ -123,7 +123,7 @@ rules: - 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-107-valid-operation-id' - severity: error + severity: off given: '#UpdateOperationObject' then: function: 'IPA107ValidOperationID' diff --git a/tools/spectral/ipa/rulesets/IPA-108.yaml b/tools/spectral/ipa/rulesets/IPA-108.yaml index b0efe908a6..0aeb566eee 100644 --- a/tools/spectral/ipa/rulesets/IPA-108.yaml +++ b/tools/spectral/ipa/rulesets/IPA-108.yaml @@ -55,8 +55,23 @@ rules: given: '#DeleteOperationObject' then: function: IPA108DeleteMethodNoRequestBody + xgen-IPA-108-valid-operation-id: + description: | + OperationID should be compliant with IPA-108 Naming guidelines. + + ##### Implementation details + Rule checks for the following conditions: + - Applies to all DELETE methods for single resource endpoints (with path parameters) + - 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-108-valid-operation-id' + severity: off + given: '#DeleteOperationObject' + then: + function: 'IPA108ValidOperationID' functions: - IPA108DeleteMethodResponseShouldNotHaveSchema - IPA108DeleteMethod204Response - IPA108DeleteMethodNoRequestBody + - IPA108ValidOperationID diff --git a/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js index 275096b441..752a83cd49 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js @@ -7,7 +7,7 @@ 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.'; -export default (input, _, { path, _ }) => { +export default (input, _, { path }) => { let resourcePath = path[1]; let methodName = 'delete'; From ae54d57aa2688bf17c3e6c5ed2d524fe832658b1 Mon Sep 17 00:00:00 2001 From: Sophia Marie Terry Date: Mon, 7 Jul 2025 18:11:40 +0100 Subject: [PATCH 15/25] CLOUDP-328959: Updated docs --- tools/spectral/ipa/rulesets/README.md | 33 +++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/tools/spectral/ipa/rulesets/README.md b/tools/spectral/ipa/rulesets/README.md index 3112cde4dc..a3727029a4 100644 --- a/tools/spectral/ipa/rulesets/README.md +++ b/tools/spectral/ipa/rulesets/README.md @@ -273,6 +273,17 @@ Rule checks for the following conditions: - Ignores resources without a Get method - Paths with `x-xgen-IPA-exception` for this rule are excluded from validation +#### xgen-IPA-106-valid-operation-id + + `off` +OperationID should be compliant with IPA-106 Naming guidelines. + +##### Implementation details +Rule checks for the following conditions: + - Applies only to POST methods on resource collection paths + - Generates the expected OperationId given the resource identifier + - Compares the generated IPA Compliant OperationId with the existing OperationId + ### IPA-107 @@ -344,6 +355,17 @@ Rule checks for the following conditions: - Validation only applies to schema references to a predefined schema (not inline) - Confirms the referenced schema name ends with "Request" suffix +#### xgen-IPA-107-valid-operation-id + + `off` +OperationID should be compliant with IPA-107 Naming guidelines. + +##### Implementation details +Rule checks for the following conditions: + - Validation checks the PATCH/PUT methods for single resource paths and [singleton resources](https://go/ipa/113). + - Generates the expected OperationId given the resource identifier + - Compares the generated IPA Compliant OperationId with the existing OperationId + ### IPA-108 @@ -388,6 +410,17 @@ Rule checks for the following conditions: - Fails if any requestBody is defined for the DELETE method - Skips validation for collection endpoints (without path parameters) +#### xgen-IPA-108-valid-operation-id + + `off` +OperationID should be compliant with IPA-108 Naming guidelines. + +##### Implementation details +Rule checks for the following conditions: + - Applies to all DELETE methods for single resource endpoints (with path parameters) + - Generates the expected OperationId given the resource identifier + - Compares the generated IPA Compliant OperationId with the existing OperationId + ### IPA-109 From ff7df80fc7cb5cfc5528ee156ed1f36d2e221126 Mon Sep 17 00:00:00 2001 From: Sophia Marie Terry Date: Tue, 8 Jul 2025 15:16:42 +0100 Subject: [PATCH 16/25] CLOUDP-328959: Added tests for validating IPA106 valid operationIds --- .../__tests__/IPA106ValidOperationID.test.js | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 tools/spectral/ipa/__tests__/IPA106ValidOperationID.test.js diff --git a/tools/spectral/ipa/__tests__/IPA106ValidOperationID.test.js b/tools/spectral/ipa/__tests__/IPA106ValidOperationID.test.js new file mode 100644 index 0000000000..6fae5af1ac --- /dev/null +++ b/tools/spectral/ipa/__tests__/IPA106ValidOperationID.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-106-valid-operation-id', [ + { + name: 'valid methods', + document: { + components: componentSchemas, + paths: { + '/groups/{groupId}/clusters': { + post: { + operationId: 'createGroupCluster', + }, + }, + }, + }, + errors: [], + }, + // This test will be enable when the xgen-IPA-106-valid-operation-id is set to warning severity - CLOUDP-329722 + /* { + name: 'invalid methods', + document: { + components: componentSchemas, + paths: { + '/api/atlas/v2/groups/{groupId}/access': { + post: { + operationId: 'addUserToProject', + }, + }, + '/api/atlas/v2/groups/{groupId}/invites': { + post: { + operationId: 'createProjectInvitation', + }, + }, + }, + }, + errors: [ + { + code: 'xgen-IPA-106-valid-operation-id', + 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. ', + path: ['paths', '/api/atlas/v2/groups/{groupId}/access', 'post'], + severity: DiagnosticSeverity.Warning, + }, + { + code: 'xgen-IPA-106-valid-operation-id', + 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. ', + path: ['paths', '/api/atlas/v2/groups/{groupId}/invites', 'post'], + severity: DiagnosticSeverity.Warning, + }, + ], + }, */ + { + name: 'invalid methods with exceptions', + document: { + components: componentSchemas, + paths: { + '/api/atlas/v2/groups/{groupId}/clusters/{clusterName}/index ': { + post: { + operationId: 'createRollingIndex', + 'x-xgen-IPA-exception': { + 'xgen-IPA-106-valid-operation-id': 'Reason', + }, + }, + }, + }, + }, + errors: [], + }, +]); From 277cb19ca0a1ea1b3ad3f84cf0ec0a0c5b7f8765 Mon Sep 17 00:00:00 2001 From: Sophia Marie Terry Date: Tue, 8 Jul 2025 15:38:41 +0100 Subject: [PATCH 17/25] CLOUDP-328959: Added tests for validating IPA108 valid operationIds --- .../__tests__/IPA108ValidOperationID.test.js | 83 +++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 tools/spectral/ipa/__tests__/IPA108ValidOperationID.test.js diff --git a/tools/spectral/ipa/__tests__/IPA108ValidOperationID.test.js b/tools/spectral/ipa/__tests__/IPA108ValidOperationID.test.js new file mode 100644 index 0000000000..36db33917e --- /dev/null +++ b/tools/spectral/ipa/__tests__/IPA108ValidOperationID.test.js @@ -0,0 +1,83 @@ +import testRule from './__helpers__/testRule'; +import { DiagnosticSeverity } from '@stoplight/types'; + +// 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-108-valid-operation-id', [ + { + name: 'valid methods', + document: { + components: componentSchemas, + paths: { + '/groups/{groupId}/clusters/{clusterName}': { + delete: { + operationId: 'deleteGroupCluster', + }, + }, + }, + }, + errors: [], + }, + // This test will be enable when the xgen-IPA-108-valid-operation-id is set to warning severity - CLOUDP-329722 + { + name: 'invalid methods', + document: { + components: componentSchemas, + paths: { + '/api/atlas/v2/groups/{groupId}/apiKeys/{apiUserId}': { + delete: { + operationId: 'removeProjectApiKey', + }, + }, + '/api/atlas/v2/groups/{groupId}': { + delete: { + operationId: 'deleteProject', + }, + }, + }, + }, + errors: [ + { + code: 'xgen-IPA-108-valid-operation-id', + 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. ', + path: ['paths', '/api/atlas/v2/groups/{groupId}/apiKeys/{apiUserId}', 'delete'], + severity: DiagnosticSeverity.Warning, + }, + { + code: 'xgen-IPA-108-valid-operation-id', + 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. ', + path: ['paths', '/api/atlas/v2/groups/{groupId}', 'delete'], + severity: DiagnosticSeverity.Warning, + }, + ], + }, + { + name: 'invalid methods with exceptions', + document: { + components: componentSchemas, + paths: { + '/api/atlas/v2/groups/{groupId}/clusters/{clusterName}/index ': { + post: { + operationId: 'deleteRollingIndex', + 'x-xgen-IPA-exception': { + 'xgen-IPA-108-valid-operation-id': 'Reason', + }, + }, + }, + }, + }, + errors: [], + }, +]); From bb78336a230269c73558b4e78dbe8f6485a02a3d Mon Sep 17 00:00:00 2001 From: Sophia Marie Terry Date: Tue, 8 Jul 2025 15:39:53 +0100 Subject: [PATCH 18/25] CLOUDP-328959: comment out unlaunched test --- tools/spectral/ipa/__tests__/IPA108ValidOperationID.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/spectral/ipa/__tests__/IPA108ValidOperationID.test.js b/tools/spectral/ipa/__tests__/IPA108ValidOperationID.test.js index 36db33917e..100af8c485 100644 --- a/tools/spectral/ipa/__tests__/IPA108ValidOperationID.test.js +++ b/tools/spectral/ipa/__tests__/IPA108ValidOperationID.test.js @@ -29,7 +29,7 @@ testRule('xgen-IPA-108-valid-operation-id', [ errors: [], }, // This test will be enable when the xgen-IPA-108-valid-operation-id is set to warning severity - CLOUDP-329722 - { + /* { name: 'invalid methods', document: { components: componentSchemas, @@ -62,7 +62,7 @@ testRule('xgen-IPA-108-valid-operation-id', [ severity: DiagnosticSeverity.Warning, }, ], - }, + }, */ { name: 'invalid methods with exceptions', document: { From fcef3e410510b55367fb133bbb3137d85676192f Mon Sep 17 00:00:00 2001 From: Sophia Marie Terry Date: Tue, 8 Jul 2025 15:50:52 +0100 Subject: [PATCH 19/25] CLOUDP-328959: Added tests for validating IPA107 valid operationIds --- .../__tests__/IPA107ValidOperationID.test.js | 88 +++++++++++++++++++ .../__tests__/IPA108ValidOperationID.test.js | 1 - 2 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 tools/spectral/ipa/__tests__/IPA107ValidOperationID.test.js diff --git a/tools/spectral/ipa/__tests__/IPA107ValidOperationID.test.js b/tools/spectral/ipa/__tests__/IPA107ValidOperationID.test.js new file mode 100644 index 0000000000..a169e4da0f --- /dev/null +++ b/tools/spectral/ipa/__tests__/IPA107ValidOperationID.test.js @@ -0,0 +1,88 @@ +import testRule from './__helpers__/testRule'; +import { DiagnosticSeverity } from '@stoplight/types'; + +// 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-107-valid-operation-id', [ + { + name: 'valid methods', + document: { + components: componentSchemas, + paths: { + 'groups/{groupId}/clusters/{clusterName}': { + put: { + operationId: 'updateGroupCluster', + }, + }, + '/groups/{groupId}/settings': { + put: { + operationId: 'updateGroupSettings', + }, + }, + }, + }, + errors: [], + }, + // This test will be enable when the xgen-IPA-107-valid-operation-id is set to warning severity - CLOUDP-329722 + /* { + name: 'invalid methods', + document: { + components: componentSchemas, + paths: { + '/api/atlas/v2/groups/{groupId}/limits/{limitName}': { + patch: { + operationId: 'setProjectLimit', + }, + }, + '/api/atlas/v2/groups/{groupId}/settings': { + put: { + operationId: 'updateProjectSettings', + }, + }, + }, + }, + errors: [ + { + code: 'xgen-IPA-107-valid-operation-id', + 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.', + path: ['paths', '/api/atlas/v2/groups/{groupId}/limits/{limitName}', 'patch'], + severity: DiagnosticSeverity.Warning, + }, + { + code: 'xgen-IPA-107-valid-operation-id', + 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.', + path: ['paths', '/api/atlas/v2/groups/{groupId}/settings', 'put'], + severity: DiagnosticSeverity.Warning, + }, + ], + }, */ + { + name: 'invalid methods with exceptions', + document: { + components: componentSchemas, + paths: { + '/api/atlas/v2/groups/{groupId}/clusters/{clusterName}/index ': { + post: { + operationId: 'updateRollingIndex', + 'x-xgen-IPA-exception': { + 'xgen-IPA-107-valid-operation-id': 'Reason', + }, + }, + }, + }, + }, + errors: [], + }, +]); diff --git a/tools/spectral/ipa/__tests__/IPA108ValidOperationID.test.js b/tools/spectral/ipa/__tests__/IPA108ValidOperationID.test.js index 100af8c485..0e0b5c2287 100644 --- a/tools/spectral/ipa/__tests__/IPA108ValidOperationID.test.js +++ b/tools/spectral/ipa/__tests__/IPA108ValidOperationID.test.js @@ -1,5 +1,4 @@ import testRule from './__helpers__/testRule'; -import { DiagnosticSeverity } from '@stoplight/types'; // TODO: add tests for xgen-custom-method extension - CLOUDP-306294 // TOOD: enable tests for invalid methods (after rules are upgraded to warning) - CLOUDP-329722 From 50fa6db2abf4237dc6a79998e1c59bf5a00be2eb Mon Sep 17 00:00:00 2001 From: Sophia Marie Terry Date: Tue, 8 Jul 2025 16:22:29 +0100 Subject: [PATCH 20/25] CLOUDP-328959: Added early returns and removed reference to custom methods --- .../functions/IPA106ValidOperationID.js | 20 +++++++++-------- .../functions/IPA107ValidOperationID.js | 22 +++++++++++-------- .../functions/IPA108ValidOperationID.js | 17 +++++++------- 3 files changed, 32 insertions(+), 27 deletions(-) diff --git a/tools/spectral/ipa/rulesets/functions/IPA106ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA106ValidOperationID.js index 688241b41e..16ad2921a4 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA106ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA106ValidOperationID.js @@ -1,15 +1,22 @@ import { hasException } from './utils/exceptions.js'; import { collectAdoption, collectException, collectAndReturnViolation } from './utils/collectionUtils.js'; -import { isCustomMethodIdentifier, getCustomMethodName, stripCustomMethodName } from './utils/resourceEvaluation.js'; +import { isCustomMethodIdentifier, isResourceCollectionIdentifier, isSingletonResource, getResourcePathItems } from './utils/resourceEvaluation.js'; 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.'; -export default (input, _, { path }) => { - let resourcePath = path[1]; - let methodName = 'create'; +export default (input, _, { path, documentInventory }) => { + const resourcePath = path[1]; + const oas = documentInventory.resolved; + const resourcePaths = getResourcePathItems(resourcePath, oas.paths); + const methodName = 'create'; + + const isResourceCollection = isResourceCollectionIdentifier(resourcePath) && !isSingletonResource(resourcePaths); + if (isCustomMethodIdentifier(resourcePath) || !isResourceCollection) { + return; + } if (hasException(input, RULE_NAME)) { collectException(input, RULE_NAME, path); @@ -18,11 +25,6 @@ export default (input, _, { path }) => { // TODO detect custom method extension - CLOUDP-306294 - if (isCustomMethodIdentifier(resourcePath)) { - methodName = getCustomMethodName(resourcePath); - resourcePath = stripCustomMethodName(resourcePath); - } - const expectedOperationID = generateOperationID(methodName, resourcePath); if (expectedOperationID !== input.operationId) { const errors = [ diff --git a/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js index 98a18b1ee9..ab576ecfed 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js @@ -1,15 +1,24 @@ import { hasException } from './utils/exceptions.js'; import { collectAdoption, collectException, collectAndReturnViolation } from './utils/collectionUtils.js'; -import { isCustomMethodIdentifier, getCustomMethodName, stripCustomMethodName } from './utils/resourceEvaluation.js'; +import { isSingleResourceIdentifier, isResourceCollectionIdentifier, isSingletonResource, getResourcePathItems } from './utils/resourceEvaluation.js'; 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.'; -export default (input, _, { path }) => { - let resourcePath = path[1]; - let methodName = 'update'; +export default (input, _, { path, documentInventory }) => { + const resourcePath = path[1]; + const oas = documentInventory.resolved; + const resourcePaths = getResourcePathItems(resourcePath, oas.paths); + const methodName = 'update'; + + if ( + !isSingleResourceIdentifier(resourcePath) && + !(isResourceCollectionIdentifier(resourcePath) && isSingletonResource(resourcePaths)) + ) { + return; + } if (hasException(input, RULE_NAME)) { collectException(input, RULE_NAME, path); @@ -18,11 +27,6 @@ export default (input, _, { path }) => { // TODO detect custom method extension - CLOUDP-306294 - if (isCustomMethodIdentifier(resourcePath)) { - methodName = getCustomMethodName(resourcePath); - resourcePath = stripCustomMethodName(resourcePath); - } - const expectedOperationID = generateOperationID(methodName, resourcePath); if (expectedOperationID !== input.operationId) { const errors = [ diff --git a/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js index 752a83cd49..c9803c08b6 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js @@ -1,15 +1,19 @@ import { hasException } from './utils/exceptions.js'; import { collectAdoption, collectException, collectAndReturnViolation } from './utils/collectionUtils.js'; -import { isCustomMethodIdentifier, getCustomMethodName, stripCustomMethodName } from './utils/resourceEvaluation.js'; +import { isSingleResourceIdentifier } from './utils/resourceEvaluation.js'; 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.'; -export default (input, _, { path }) => { - let resourcePath = path[1]; - let methodName = 'delete'; +export default (input, _, { path, }) => { + const resourcePath = path[1]; + const methodName = 'delete'; + + if (!isSingleResourceIdentifier(resourcePath)) { + return; + } if (hasException(input, RULE_NAME)) { collectException(input, RULE_NAME, path); @@ -18,11 +22,6 @@ export default (input, _, { path }) => { // TODO detect custom method extension - CLOUDP-306294 - if (isCustomMethodIdentifier(resourcePath)) { - methodName = getCustomMethodName(resourcePath); - resourcePath = stripCustomMethodName(resourcePath); - } - const expectedOperationID = generateOperationID(methodName, resourcePath); if (expectedOperationID !== input.operationId) { const errors = [ From 5262142bdd1098dbbf994ca93bdb404cb3c7f5aa Mon Sep 17 00:00:00 2001 From: Sophia Marie Terry Date: Wed, 9 Jul 2025 10:28:01 +0100 Subject: [PATCH 21/25] CLOUDP-328959: Edits --- tools/spectral/ipa/rulesets/IPA-106.yaml | 2 +- tools/spectral/ipa/rulesets/IPA-107.yaml | 2 +- tools/spectral/ipa/rulesets/IPA-108.yaml | 2 +- tools/spectral/ipa/rulesets/functions/IPA106ValidOperationID.js | 2 -- tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js | 2 -- tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js | 2 -- 6 files changed, 3 insertions(+), 9 deletions(-) diff --git a/tools/spectral/ipa/rulesets/IPA-106.yaml b/tools/spectral/ipa/rulesets/IPA-106.yaml index c59a45e27b..b8df97f666 100644 --- a/tools/spectral/ipa/rulesets/IPA-106.yaml +++ b/tools/spectral/ipa/rulesets/IPA-106.yaml @@ -115,7 +115,7 @@ rules: function: 'IPA106CreateMethodResponseIsGetMethodResponse' xgen-IPA-106-valid-operation-id: description: | - OperationID should be compliant with IPA-106 Naming guidelines. + Confirms that the existing operationId is compliant with generated IPA Compliant OperationId. ##### Implementation details Rule checks for the following conditions: diff --git a/tools/spectral/ipa/rulesets/IPA-107.yaml b/tools/spectral/ipa/rulesets/IPA-107.yaml index b07dec78bf..6304acaea1 100644 --- a/tools/spectral/ipa/rulesets/IPA-107.yaml +++ b/tools/spectral/ipa/rulesets/IPA-107.yaml @@ -115,7 +115,7 @@ rules: function: 'IPA107UpdateMethodRequestBodyIsUpdateRequestSuffixedObject' xgen-IPA-107-valid-operation-id: description: | - OperationID should be compliant with IPA-107 Naming guidelines. + Confirms that the existing operationId is compliant with generated IPA Compliant OperationId. ##### Implementation details Rule checks for the following conditions: diff --git a/tools/spectral/ipa/rulesets/IPA-108.yaml b/tools/spectral/ipa/rulesets/IPA-108.yaml index 0aeb566eee..50ae63c2df 100644 --- a/tools/spectral/ipa/rulesets/IPA-108.yaml +++ b/tools/spectral/ipa/rulesets/IPA-108.yaml @@ -57,7 +57,7 @@ rules: function: IPA108DeleteMethodNoRequestBody xgen-IPA-108-valid-operation-id: description: | - OperationID should be compliant with IPA-108 Naming guidelines. + Confirms that the existing operationId is compliant with generated IPA Compliant OperationId. ##### Implementation details Rule checks for the following conditions: diff --git a/tools/spectral/ipa/rulesets/functions/IPA106ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA106ValidOperationID.js index 16ad2921a4..a80cbfb473 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA106ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA106ValidOperationID.js @@ -23,8 +23,6 @@ export default (input, _, { path, documentInventory }) => { return; } - // TODO detect custom method extension - CLOUDP-306294 - const expectedOperationID = generateOperationID(methodName, resourcePath); if (expectedOperationID !== input.operationId) { const errors = [ diff --git a/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js index ab576ecfed..72c08e73f6 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js @@ -25,8 +25,6 @@ export default (input, _, { path, documentInventory }) => { return; } - // TODO detect custom method extension - CLOUDP-306294 - const expectedOperationID = generateOperationID(methodName, resourcePath); if (expectedOperationID !== input.operationId) { const errors = [ diff --git a/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js index c9803c08b6..2c6bf880df 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js @@ -20,8 +20,6 @@ export default (input, _, { path, }) => { return; } - // TODO detect custom method extension - CLOUDP-306294 - const expectedOperationID = generateOperationID(methodName, resourcePath); if (expectedOperationID !== input.operationId) { const errors = [ From ecb2e28fed55e983637bca5e14a599ee38b27525 Mon Sep 17 00:00:00 2001 From: Sophia Marie Terry Date: Wed, 9 Jul 2025 10:50:31 +0100 Subject: [PATCH 22/25] CLOUDP-328959: prettier --- .../ipa/rulesets/functions/IPA106ValidOperationID.js | 7 ++++++- .../ipa/rulesets/functions/IPA107ValidOperationID.js | 7 ++++++- .../ipa/rulesets/functions/IPA108ValidOperationID.js | 2 +- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/tools/spectral/ipa/rulesets/functions/IPA106ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA106ValidOperationID.js index a80cbfb473..3b72923881 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA106ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA106ValidOperationID.js @@ -1,6 +1,11 @@ import { hasException } from './utils/exceptions.js'; import { collectAdoption, collectException, collectAndReturnViolation } from './utils/collectionUtils.js'; -import { isCustomMethodIdentifier, isResourceCollectionIdentifier, isSingletonResource, getResourcePathItems } from './utils/resourceEvaluation.js'; +import { + isCustomMethodIdentifier, + isResourceCollectionIdentifier, + isSingletonResource, + getResourcePathItems, +} from './utils/resourceEvaluation.js'; import { generateOperationID } from './utils/operationIdGeneration.js'; const RULE_NAME = 'xgen-IPA-106-valid-operation-id'; diff --git a/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js index 72c08e73f6..4337c3e78c 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js @@ -1,6 +1,11 @@ import { hasException } from './utils/exceptions.js'; import { collectAdoption, collectException, collectAndReturnViolation } from './utils/collectionUtils.js'; -import { isSingleResourceIdentifier, isResourceCollectionIdentifier, isSingletonResource, getResourcePathItems } from './utils/resourceEvaluation.js'; +import { + isSingleResourceIdentifier, + isResourceCollectionIdentifier, + isSingletonResource, + getResourcePathItems, +} from './utils/resourceEvaluation.js'; import { generateOperationID } from './utils/operationIdGeneration.js'; const RULE_NAME = 'xgen-IPA-107-valid-operation-id'; diff --git a/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js index 2c6bf880df..f25294c403 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js @@ -7,7 +7,7 @@ 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.'; -export default (input, _, { path, }) => { +export default (input, _, { path }) => { const resourcePath = path[1]; const methodName = 'delete'; From 3f4fc95f43240c25869df976a1b0e840ad9d5125 Mon Sep 17 00:00:00 2001 From: Sophia Marie Terry Date: Wed, 9 Jul 2025 10:53:20 +0100 Subject: [PATCH 23/25] CLOUDP-328959: doc update --- tools/spectral/ipa/rulesets/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/spectral/ipa/rulesets/README.md b/tools/spectral/ipa/rulesets/README.md index a3727029a4..2bfb41e4c4 100644 --- a/tools/spectral/ipa/rulesets/README.md +++ b/tools/spectral/ipa/rulesets/README.md @@ -276,7 +276,7 @@ Rule checks for the following conditions: #### xgen-IPA-106-valid-operation-id `off` -OperationID should be compliant with IPA-106 Naming guidelines. +Confirms that the existing operationId is compliant with generated IPA Compliant OperationId. ##### Implementation details Rule checks for the following conditions: @@ -358,7 +358,7 @@ Rule checks for the following conditions: #### xgen-IPA-107-valid-operation-id `off` -OperationID should be compliant with IPA-107 Naming guidelines. +Confirms that the existing operationId is compliant with generated IPA Compliant OperationId. ##### Implementation details Rule checks for the following conditions: @@ -413,7 +413,7 @@ Rule checks for the following conditions: #### xgen-IPA-108-valid-operation-id `off` -OperationID should be compliant with IPA-108 Naming guidelines. +Confirms that the existing operationId is compliant with generated IPA Compliant OperationId. ##### Implementation details Rule checks for the following conditions: From 29c55c4ff45909cd964f88281ab28c2897fee13c Mon Sep 17 00:00:00 2001 From: Sophia Marie Terry Date: Wed, 9 Jul 2025 10:57:57 +0100 Subject: [PATCH 24/25] CLOUDP-328959: Added methodName to functionOptions --- tools/spectral/ipa/rulesets/IPA-106.yaml | 2 ++ tools/spectral/ipa/rulesets/IPA-107.yaml | 2 ++ tools/spectral/ipa/rulesets/IPA-108.yaml | 2 ++ .../spectral/ipa/rulesets/functions/IPA106ValidOperationID.js | 3 +-- .../spectral/ipa/rulesets/functions/IPA107ValidOperationID.js | 3 +-- .../spectral/ipa/rulesets/functions/IPA108ValidOperationID.js | 3 +-- 6 files changed, 9 insertions(+), 6 deletions(-) diff --git a/tools/spectral/ipa/rulesets/IPA-106.yaml b/tools/spectral/ipa/rulesets/IPA-106.yaml index b8df97f666..9367c52071 100644 --- a/tools/spectral/ipa/rulesets/IPA-106.yaml +++ b/tools/spectral/ipa/rulesets/IPA-106.yaml @@ -127,3 +127,5 @@ rules: given: '#CreateOperationObject' then: function: 'IPA106ValidOperationID' + functionOptions: + methodName: 'create' diff --git a/tools/spectral/ipa/rulesets/IPA-107.yaml b/tools/spectral/ipa/rulesets/IPA-107.yaml index 6304acaea1..6614bb4ef9 100644 --- a/tools/spectral/ipa/rulesets/IPA-107.yaml +++ b/tools/spectral/ipa/rulesets/IPA-107.yaml @@ -127,3 +127,5 @@ rules: given: '#UpdateOperationObject' then: function: 'IPA107ValidOperationID' + functionOptions: + methodName: 'update' diff --git a/tools/spectral/ipa/rulesets/IPA-108.yaml b/tools/spectral/ipa/rulesets/IPA-108.yaml index 50ae63c2df..f27ee92f1b 100644 --- a/tools/spectral/ipa/rulesets/IPA-108.yaml +++ b/tools/spectral/ipa/rulesets/IPA-108.yaml @@ -69,6 +69,8 @@ rules: given: '#DeleteOperationObject' then: function: 'IPA108ValidOperationID' + functionOptions: + methodName: 'delete' functions: - IPA108DeleteMethodResponseShouldNotHaveSchema diff --git a/tools/spectral/ipa/rulesets/functions/IPA106ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA106ValidOperationID.js index 3b72923881..c50a5c6cdd 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA106ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA106ValidOperationID.js @@ -12,11 +12,10 @@ 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.'; -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); - const methodName = 'create'; const isResourceCollection = isResourceCollectionIdentifier(resourcePath) && !isSingletonResource(resourcePaths); if (isCustomMethodIdentifier(resourcePath) || !isResourceCollection) { diff --git a/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js index 4337c3e78c..24fbe0f1e3 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js @@ -12,11 +12,10 @@ 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.'; -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); - const methodName = 'update'; if ( !isSingleResourceIdentifier(resourcePath) && diff --git a/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js index f25294c403..135d79ff2c 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js @@ -7,9 +7,8 @@ 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.'; -export default (input, _, { path }) => { +export default (input, { methodName }, { path }) => { const resourcePath = path[1]; - const methodName = 'delete'; if (!isSingleResourceIdentifier(resourcePath)) { return; From 6a9a67def6ea262a755a45109e533959b413ed33 Mon Sep 17 00:00:00 2001 From: Sophia Marie Terry Date: Wed, 9 Jul 2025 12:13:44 +0100 Subject: [PATCH 25/25] CLOUDP-328959: Update docs, remove unused schema, add customMethod check --- .../ipa/__tests__/IPA106ValidOperationID.test.js | 12 ------------ .../ipa/__tests__/IPA107ValidOperationID.test.js | 13 ------------- .../ipa/__tests__/IPA108ValidOperationID.test.js | 12 ------------ tools/spectral/ipa/rulesets/IPA-106.yaml | 5 +++-- tools/spectral/ipa/rulesets/IPA-107.yaml | 6 ++++-- tools/spectral/ipa/rulesets/IPA-108.yaml | 5 +++-- tools/spectral/ipa/rulesets/README.md | 16 ++++++++++------ .../rulesets/functions/IPA107ValidOperationID.js | 9 +++++++-- .../rulesets/functions/IPA108ValidOperationID.js | 4 ++-- 9 files changed, 29 insertions(+), 53 deletions(-) diff --git a/tools/spectral/ipa/__tests__/IPA106ValidOperationID.test.js b/tools/spectral/ipa/__tests__/IPA106ValidOperationID.test.js index 6fae5af1ac..4d03acc02b 100644 --- a/tools/spectral/ipa/__tests__/IPA106ValidOperationID.test.js +++ b/tools/spectral/ipa/__tests__/IPA106ValidOperationID.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-106-valid-operation-id', [ { name: 'valid methods', document: { - components: componentSchemas, paths: { '/groups/{groupId}/clusters': { post: { @@ -31,7 +21,6 @@ testRule('xgen-IPA-106-valid-operation-id', [ /* { name: 'invalid methods', document: { - components: componentSchemas, paths: { '/api/atlas/v2/groups/{groupId}/access': { post: { @@ -65,7 +54,6 @@ testRule('xgen-IPA-106-valid-operation-id', [ { name: 'invalid methods with exceptions', document: { - components: componentSchemas, paths: { '/api/atlas/v2/groups/{groupId}/clusters/{clusterName}/index ': { post: { diff --git a/tools/spectral/ipa/__tests__/IPA107ValidOperationID.test.js b/tools/spectral/ipa/__tests__/IPA107ValidOperationID.test.js index a169e4da0f..a157366ba2 100644 --- a/tools/spectral/ipa/__tests__/IPA107ValidOperationID.test.js +++ b/tools/spectral/ipa/__tests__/IPA107ValidOperationID.test.js @@ -1,23 +1,12 @@ import testRule from './__helpers__/testRule'; -import { DiagnosticSeverity } from '@stoplight/types'; // 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-107-valid-operation-id', [ { name: 'valid methods', document: { - components: componentSchemas, paths: { 'groups/{groupId}/clusters/{clusterName}': { put: { @@ -37,7 +26,6 @@ testRule('xgen-IPA-107-valid-operation-id', [ /* { name: 'invalid methods', document: { - components: componentSchemas, paths: { '/api/atlas/v2/groups/{groupId}/limits/{limitName}': { patch: { @@ -71,7 +59,6 @@ testRule('xgen-IPA-107-valid-operation-id', [ { name: 'invalid methods with exceptions', document: { - components: componentSchemas, paths: { '/api/atlas/v2/groups/{groupId}/clusters/{clusterName}/index ': { post: { diff --git a/tools/spectral/ipa/__tests__/IPA108ValidOperationID.test.js b/tools/spectral/ipa/__tests__/IPA108ValidOperationID.test.js index 0e0b5c2287..7a311e0f65 100644 --- a/tools/spectral/ipa/__tests__/IPA108ValidOperationID.test.js +++ b/tools/spectral/ipa/__tests__/IPA108ValidOperationID.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-108-valid-operation-id', [ { name: 'valid methods', document: { - components: componentSchemas, paths: { '/groups/{groupId}/clusters/{clusterName}': { delete: { @@ -31,7 +21,6 @@ testRule('xgen-IPA-108-valid-operation-id', [ /* { name: 'invalid methods', document: { - components: componentSchemas, paths: { '/api/atlas/v2/groups/{groupId}/apiKeys/{apiUserId}': { delete: { @@ -65,7 +54,6 @@ testRule('xgen-IPA-108-valid-operation-id', [ { name: 'invalid methods with exceptions', document: { - components: componentSchemas, paths: { '/api/atlas/v2/groups/{groupId}/clusters/{clusterName}/index ': { post: { diff --git a/tools/spectral/ipa/rulesets/IPA-106.yaml b/tools/spectral/ipa/rulesets/IPA-106.yaml index 9367c52071..e65406b618 100644 --- a/tools/spectral/ipa/rulesets/IPA-106.yaml +++ b/tools/spectral/ipa/rulesets/IPA-106.yaml @@ -115,13 +115,14 @@ rules: function: 'IPA106CreateMethodResponseIsGetMethodResponse' xgen-IPA-106-valid-operation-id: description: | - Confirms that the existing operationId is compliant with generated IPA Compliant 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. ##### Implementation details Rule checks for the following conditions: - Applies only to POST methods on resource collection paths - 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-106-valid-operation-id' severity: off given: '#CreateOperationObject' diff --git a/tools/spectral/ipa/rulesets/IPA-107.yaml b/tools/spectral/ipa/rulesets/IPA-107.yaml index 6614bb4ef9..1901f6acc8 100644 --- a/tools/spectral/ipa/rulesets/IPA-107.yaml +++ b/tools/spectral/ipa/rulesets/IPA-107.yaml @@ -115,13 +115,15 @@ rules: function: 'IPA107UpdateMethodRequestBodyIsUpdateRequestSuffixedObject' xgen-IPA-107-valid-operation-id: description: | - Confirms that the existing operationId is compliant with generated IPA Compliant 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. + 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: - Validation checks the PATCH/PUT methods for single resource paths and [singleton resources](https://go/ipa/113). - 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-107-valid-operation-id' severity: off given: '#UpdateOperationObject' diff --git a/tools/spectral/ipa/rulesets/IPA-108.yaml b/tools/spectral/ipa/rulesets/IPA-108.yaml index f27ee92f1b..7918c85a22 100644 --- a/tools/spectral/ipa/rulesets/IPA-108.yaml +++ b/tools/spectral/ipa/rulesets/IPA-108.yaml @@ -57,13 +57,14 @@ rules: function: IPA108DeleteMethodNoRequestBody xgen-IPA-108-valid-operation-id: description: | - Confirms that the existing operationId is compliant with generated IPA Compliant 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. ##### Implementation details Rule checks for the following conditions: - Applies to all DELETE methods for single resource endpoints (with path parameters) - 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-108-valid-operation-id' severity: off given: '#DeleteOperationObject' diff --git a/tools/spectral/ipa/rulesets/README.md b/tools/spectral/ipa/rulesets/README.md index 2bfb41e4c4..7d452db1eb 100644 --- a/tools/spectral/ipa/rulesets/README.md +++ b/tools/spectral/ipa/rulesets/README.md @@ -276,13 +276,14 @@ Rule checks for the following conditions: #### xgen-IPA-106-valid-operation-id `off` -Confirms that the existing operationId is compliant with generated IPA Compliant 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. ##### Implementation details Rule checks for the following conditions: - Applies only to POST methods on resource collection paths - 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 @@ -358,13 +359,15 @@ Rule checks for the following conditions: #### xgen-IPA-107-valid-operation-id `off` -Confirms that the existing operationId is compliant with generated IPA Compliant 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. +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: - Validation checks the PATCH/PUT methods for single resource paths and [singleton resources](https://go/ipa/113). - 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 @@ -413,13 +416,14 @@ Rule checks for the following conditions: #### xgen-IPA-108-valid-operation-id `off` -Confirms that the existing operationId is compliant with generated IPA Compliant 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. ##### Implementation details Rule checks for the following conditions: - Applies to all DELETE methods for single resource endpoints (with path parameters) - 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/IPA107ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js index 24fbe0f1e3..526b2a4660 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js @@ -5,6 +5,7 @@ import { isResourceCollectionIdentifier, isSingletonResource, getResourcePathItems, + isCustomMethodIdentifier, } from './utils/resourceEvaluation.js'; import { generateOperationID } from './utils/operationIdGeneration.js'; @@ -18,8 +19,9 @@ export default (input, { methodName }, { path, documentInventory }) => { const resourcePaths = getResourcePathItems(resourcePath, oas.paths); if ( - !isSingleResourceIdentifier(resourcePath) && - !(isResourceCollectionIdentifier(resourcePath) && isSingletonResource(resourcePaths)) + isCustomMethodIdentifier(resourcePath) || + (!isSingleResourceIdentifier(resourcePath) && + !(isResourceCollectionIdentifier(resourcePath) && isSingletonResource(resourcePaths))) ) { return; } @@ -31,6 +33,9 @@ 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, diff --git a/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js index 135d79ff2c..03aa2eab2c 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js @@ -1,6 +1,6 @@ import { hasException } from './utils/exceptions.js'; import { collectAdoption, collectException, collectAndReturnViolation } from './utils/collectionUtils.js'; -import { isSingleResourceIdentifier } from './utils/resourceEvaluation.js'; +import { isCustomMethodIdentifier, isSingleResourceIdentifier } from './utils/resourceEvaluation.js'; import { generateOperationID } from './utils/operationIdGeneration.js'; const RULE_NAME = 'xgen-IPA-108-valid-operation-id'; @@ -10,7 +10,7 @@ const ERROR_MESSAGE = export default (input, { methodName }, { path }) => { const resourcePath = path[1]; - if (!isSingleResourceIdentifier(resourcePath)) { + if (isCustomMethodIdentifier(resourcePath) || !isSingleResourceIdentifier(resourcePath)) { return; }