From beaa2808faacb4ea3f1dab66bc76dcda059b921f Mon Sep 17 00:00:00 2001 From: Yeliz Henden Date: Thu, 31 Jul 2025 15:31:39 +0100 Subject: [PATCH] CLOUDP-308270: Validation of parent and child paths with exceptions (PoC for root path exception inheritance) --- openapi/.raw/v2.json | 51 +++++++++++++++++++ ...ternatesBetweenResourceNameAndPathParam.js | 26 ++++++++-- 2 files changed, 74 insertions(+), 3 deletions(-) diff --git a/openapi/.raw/v2.json b/openapi/.raw/v2.json index da604d0d01..9961be62d4 100644 --- a/openapi/.raw/v2.json +++ b/openapi/.raw/v2.json @@ -53063,6 +53063,57 @@ "x-xgen-IPA-exception": { "xgen-IPA-102-path-alternate-resource-name-path-param": "API predates IPA validation" } + }, + "/api/atlas/v2/alertConfigs/matchers/fieldNames/{fieldId}": { + "get": { + "description": "Get all field names that the `matchers.fieldName` parameter accepts when you create or update an Alert Configuration. You can successfully call this endpoint with any assigned role.", + "operationId": "listAlertConfigurationMatchersFieldNames", + "parameters": [ + { + "$ref": "#/components/parameters/envelope" + }, + { + "$ref": "#/components/parameters/pretty" + } + ], + "responses": { + "200": { + "content": { + "application/vnd.atlas.2023-01-01+json": { + "schema": { + "items": { + "$ref": "#/components/schemas/MatcherFieldView" + }, + "type": "array", + "x-xgen-IPA-exception": { + "xgen-IPA-124-array-max-items": "Schema predates IPA validation" + } + }, + "x-xgen-version": "2023-01-01" + } + }, + "description": "OK" + }, + "401": { + "$ref": "#/components/responses/unauthorized" + }, + "403": { + "$ref": "#/components/responses/forbidden" + }, + "404": { + "$ref": "#/components/responses/notFound" + }, + "500": { + "$ref": "#/components/responses/internalServerError" + } + }, + "summary": "Return All Alert Configuration Matchers Field Names", + "tags": [ + "Alert Configurations" + ], + "x-xgen-docs-url": "https://mongodb.com/docs/atlas/reference/api-resources-spec/v2/#tag/Alert-Configurations/operation/listAlertConfigurationMatchersFieldNames", + "x-xgen-owner-team": "CAP" + } }, "/api/atlas/v2/clusters": { "get": { diff --git a/tools/spectral/ipa/rulesets/functions/IPA102EachPathAlternatesBetweenResourceNameAndPathParam.js b/tools/spectral/ipa/rulesets/functions/IPA102EachPathAlternatesBetweenResourceNameAndPathParam.js index ed60186e9d..20663f1cfd 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA102EachPathAlternatesBetweenResourceNameAndPathParam.js +++ b/tools/spectral/ipa/rulesets/functions/IPA102EachPathAlternatesBetweenResourceNameAndPathParam.js @@ -28,6 +28,25 @@ const validatePathStructure = (elements) => { }); }; +const findExceptionInPathHierarchy = (oas, currentPath, ruleName) => { + // Check current path first + if (hasException(oas.paths[currentPath], ruleName)) { + return currentPath; + } + + // Check parent paths by removing segments from the end + const pathSegments = currentPath.split('/').filter(segment => segment !== ''); + + for (let i = pathSegments.length - 1; i > 0; i--) { + const parentPath = '/' + pathSegments.slice(0, i).join('/'); + if (oas.paths[parentPath] && hasException(oas.paths[parentPath], ruleName)) { + return parentPath; + } + } + + return null; +} + export default (input, _, { path, documentInventory }) => { const oas = documentInventory.resolved; @@ -41,8 +60,9 @@ export default (input, _, { path, documentInventory }) => { return; } - if (hasException(oas.paths[input], RULE_NAME)) { - collectException(oas.paths[input], RULE_NAME, path); + const exceptionPath = findExceptionInPathHierarchy(oas, input, RULE_NAME); + if (exceptionPath) { + collectException(oas.paths[exceptionPath], RULE_NAME, path); return; } @@ -64,4 +84,4 @@ function checkViolationsAndReturnErrors(suffixWithLeadingSlash, path) { } catch (e) { handleInternalError(RULE_NAME, path, e); } -} +} \ No newline at end of file