From 4ef072b52745e1e57ad7bd18c58d0329bb8d7f3c Mon Sep 17 00:00:00 2001 From: Yeliz Henden Date: Tue, 17 Dec 2024 14:11:52 +0000 Subject: [PATCH 1/6] CLOUDP-271988: IPA-102: Validate paths follow expected format --- ...tesBetweenResourceNameAndPathParam.test.js | 213 ++++++++++++++++++ tools/spectral/ipa/ipa-spectral.yaml | 1 + tools/spectral/ipa/rulesets/IPA-102.yaml | 15 ++ tools/spectral/ipa/rulesets/IPA-104.yaml | 2 +- ...ternatesBetweenResourceNameAndPathParam.js | 37 +++ .../ipa/rulesets/functions/utils/pathUtils.js | 5 + 6 files changed, 272 insertions(+), 1 deletion(-) create mode 100644 tools/spectral/ipa/__tests__/eachPathAlternatesBetweenResourceNameAndPathParam.test.js create mode 100644 tools/spectral/ipa/rulesets/IPA-102.yaml create mode 100644 tools/spectral/ipa/rulesets/functions/eachPathAlternatesBetweenResourceNameAndPathParam.js create mode 100644 tools/spectral/ipa/rulesets/functions/utils/pathUtils.js diff --git a/tools/spectral/ipa/__tests__/eachPathAlternatesBetweenResourceNameAndPathParam.test.js b/tools/spectral/ipa/__tests__/eachPathAlternatesBetweenResourceNameAndPathParam.test.js new file mode 100644 index 0000000000..37e5ac7089 --- /dev/null +++ b/tools/spectral/ipa/__tests__/eachPathAlternatesBetweenResourceNameAndPathParam.test.js @@ -0,0 +1,213 @@ +import testRule from './__helpers__/testRule'; +import { DiagnosticSeverity } from '@stoplight/types'; + +testRule('xgen-IPA-102-path-alternate-resource-name-path-param', [ + { + name: 'valid paths - api/atlas/v2', + document: { + paths: { + '/api/atlas/v2/resourceName': { + post: {}, + get: {}, + }, + '/api/atlas/v2/resourceName/{pathParam}': { + get: {}, + patch: {}, + delete: {}, + }, + '/api/atlas/v2/resourceName1/{pathParam}/resourceName2': { + post: {}, + get: {}, + }, + '/api/atlas/v2/resourceName1/{pathParam1p}/resourceName2/{pathParam2}': { + get: {}, + patch: {}, + delete: {}, + }, + '/api/atlas/v2/resourceName/{pathParam}:method': { + post: {}, + }, + '/api/atlas/v2/custom:method': { + post: {}, + }, + '/api/atlas/v2': { + post: {}, + } + }, + }, + errors: [], + }, + { + name: 'valid paths - api/atlas/v2/unauth', + document: { + paths: { + '/api/atlas/v2/unauth/resourceName': { + post: {}, + get: {}, + }, + '/api/atlas/v2/unauth/resourceName/{pathParam}': { + get: {}, + patch: {}, + delete: {}, + }, + '/api/atlas/v2/unauth/resourceName1/{pathParam}/resourceName2': { + post: {}, + get: {}, + }, + '/api/atlas/v2/unauth/resourceName1/{pathParam1p}/resourceName2/{pathParam2}': { + get: {}, + patch: {}, + delete: {}, + }, + '/api/atlas/v2/unauth/resourceName/{pathParam}:method': { + post: {}, + }, + '/api/atlas/v2/unauth/custom:method': { + post: {}, + }, + '/api/atlas/v2/unauth': { + post: {}, + } + }, + }, + errors: [], + }, + { + name: 'invalid paths - api/atlas/v2', + document: { + paths: { + '/api/atlas/v2/resourceName1/resourceName2': { + post: {}, + get: {}, + }, + '/api/atlas/v2/resourceName/{pathParam1}/{pathParam2}': { + patch: {}, + delete: {}, + }, + '/api/atlas/v2/resourceName1/{pathParam1}/resourceName2/resourceName3': { + patch: {}, + delete: {}, + }, + '/api/atlas/v2/resourceName1/{pathParam1}/resourceName2/{pathParam2}/{pathParam3}': { + patch: {}, + delete: {}, + }, + '/api/atlas/v2/{pathParam}': { + post: {}, + get: {}, + }, + '/api/atlas/v2/{pathParam1}/{pathParam2}': { + post: {}, + get: {}, + } + }, + }, + errors: [ + { + code: 'xgen-IPA-102-path-alternate-resource-name-path-param', + message: 'API paths must alternate between resource name and path params. http://go/ipa/117', + path: ['paths', '/api/atlas/v2/resourceName1/resourceName2'], + severity: DiagnosticSeverity.Warning, + }, + { + code: 'xgen-IPA-102-path-alternate-resource-name-path-param', + message: 'API paths must alternate between resource name and path params. http://go/ipa/117', + path: ['paths', '/api/atlas/v2/resourceName/{pathParam1}/{pathParam2}'], + severity: DiagnosticSeverity.Warning, + }, + { + code: 'xgen-IPA-102-path-alternate-resource-name-path-param', + message: 'API paths must alternate between resource name and path params. http://go/ipa/117', + path: ['paths', '/api/atlas/v2/resourceName1/{pathParam1}/resourceName2/resourceName3'], + severity: DiagnosticSeverity.Warning, + }, + { + code: 'xgen-IPA-102-path-alternate-resource-name-path-param', + message: 'API paths must alternate between resource name and path params. http://go/ipa/117', + path: ['paths', '/api/atlas/v2/resourceName1/{pathParam1}/resourceName2/{pathParam2}/{pathParam3}'], + severity: DiagnosticSeverity.Warning, + }, + { + code: 'xgen-IPA-102-path-alternate-resource-name-path-param', + message: 'API paths must alternate between resource name and path params. http://go/ipa/117', + path: ['paths', '/api/atlas/v2/{pathParam}'], + severity: DiagnosticSeverity.Warning, + }, + { + code: 'xgen-IPA-102-path-alternate-resource-name-path-param', + message: 'API paths must alternate between resource name and path params. http://go/ipa/117', + path: ['paths', '/api/atlas/v2/{pathParam1}/{pathParam2}'], + severity: DiagnosticSeverity.Warning, + }, + ] + }, + { + name: 'invalid paths - api/atlas/v2/unauth', + document: { + paths: { + '/api/atlas/v2/unauth/resourceName1/resourceName2': { + post: {}, + get: {}, + }, + '/api/atlas/v2/unauth/resourceName/{pathParam1}/{pathParam2}': { + patch: {}, + delete: {}, + }, + '/api/atlas/v2/unauth/resourceName1/{pathParam1}/resourceName2/resourceName3': { + patch: {}, + delete: {}, + }, + '/api/atlas/v2/unauth/resourceName1/{pathParam1}/resourceName2/{pathParam2}/{pathParam3}': { + patch: {}, + delete: {}, + }, + '/api/atlas/v2/unauth/{pathParam}': { + post: {}, + get: {}, + }, + '/api/atlas/v2/unauth/{pathParam1}/{pathParam2}': { + post: {}, + get: {}, + } + }, + }, + errors: [ + { + code: 'xgen-IPA-102-path-alternate-resource-name-path-param', + message: 'API paths must alternate between resource name and path params. http://go/ipa/117', + path: ['paths', '/api/atlas/v2/unauth/resourceName1/resourceName2'], + severity: DiagnosticSeverity.Warning, + }, + { + code: 'xgen-IPA-102-path-alternate-resource-name-path-param', + message: 'API paths must alternate between resource name and path params. http://go/ipa/117', + path: ['paths', '/api/atlas/v2/unauth/resourceName/{pathParam1}/{pathParam2}'], + severity: DiagnosticSeverity.Warning, + }, + { + code: 'xgen-IPA-102-path-alternate-resource-name-path-param', + message: 'API paths must alternate between resource name and path params. http://go/ipa/117', + path: ['paths', '/api/atlas/v2/unauth/resourceName1/{pathParam1}/resourceName2/resourceName3'], + severity: DiagnosticSeverity.Warning, + }, + { + code: 'xgen-IPA-102-path-alternate-resource-name-path-param', + message: 'API paths must alternate between resource name and path params. http://go/ipa/117', + path: ['paths', '/api/atlas/v2/unauth/resourceName1/{pathParam1}/resourceName2/{pathParam2}/{pathParam3}'], + severity: DiagnosticSeverity.Warning, + }, + { + code: 'xgen-IPA-102-path-alternate-resource-name-path-param', + message: 'API paths must alternate between resource name and path params. http://go/ipa/117', + path: ['paths', '/api/atlas/v2/unauth/{pathParam}'], + severity: DiagnosticSeverity.Warning, + }, + { + code: 'xgen-IPA-102-path-alternate-resource-name-path-param', + message: 'API paths must alternate between resource name and path params. http://go/ipa/117', + path: ['paths', '/api/atlas/v2/unauth/{pathParam1}/{pathParam2}'], + severity: DiagnosticSeverity.Warning, + }, + ], + }, +]); diff --git a/tools/spectral/ipa/ipa-spectral.yaml b/tools/spectral/ipa/ipa-spectral.yaml index 893169f21d..9e5e2b3ab7 100644 --- a/tools/spectral/ipa/ipa-spectral.yaml +++ b/tools/spectral/ipa/ipa-spectral.yaml @@ -1,2 +1,3 @@ extends: + - ./rulesets/IPA-102.yaml - ./rulesets/IPA-104.yaml diff --git a/tools/spectral/ipa/rulesets/IPA-102.yaml b/tools/spectral/ipa/rulesets/IPA-102.yaml new file mode 100644 index 0000000000..f9c9517019 --- /dev/null +++ b/tools/spectral/ipa/rulesets/IPA-102.yaml @@ -0,0 +1,15 @@ +# IPA-102: Resource Identifiers +# http://go/ipa/102 + +functions: + - eachPathAlternatesBetweenResourceNameAndPathParam + +rules: + xgen-IPA-102-path-alternate-resource-name-path-param: + description: "Paths should alternate between resource names and path params. http://go/ipa/102" + message: "{{error}} http://go/ipa/102" + severity: warn + given: "$.paths" + then: + field: "@key" + function: "eachPathAlternatesBetweenResourceNameAndPathParam" \ No newline at end of file diff --git a/tools/spectral/ipa/rulesets/IPA-104.yaml b/tools/spectral/ipa/rulesets/IPA-104.yaml index 47bd8649c2..1c0da30943 100644 --- a/tools/spectral/ipa/rulesets/IPA-104.yaml +++ b/tools/spectral/ipa/rulesets/IPA-104.yaml @@ -7,7 +7,7 @@ functions: rules: xgen-IPA-104-resource-has-GET: description: "APIs must provide a get method for resources. http://go/ipa/104" - message: "{{error}} http://go/ipa/117" + message: "{{error}} http://go/ipa/104" severity: warn given: "$.paths" then: diff --git a/tools/spectral/ipa/rulesets/functions/eachPathAlternatesBetweenResourceNameAndPathParam.js b/tools/spectral/ipa/rulesets/functions/eachPathAlternatesBetweenResourceNameAndPathParam.js new file mode 100644 index 0000000000..7b0da80306 --- /dev/null +++ b/tools/spectral/ipa/rulesets/functions/eachPathAlternatesBetweenResourceNameAndPathParam.js @@ -0,0 +1,37 @@ +import { isPathParam } from './utils/pathUtils'; + +const ERROR_MESSAGE = 'API paths must alternate between resource name and path params.'; +const ERROR_RESULT = [{ message: ERROR_MESSAGE }]; +const AUTH_PREFIX = "/api/atlas/v2"; +const UNAUTH_PREFIX = "/api/atlas/v2/unauth" + +const getPrefix = (path) => { + if (path.includes(UNAUTH_PREFIX)) return UNAUTH_PREFIX; + if (path.includes(AUTH_PREFIX)) return AUTH_PREFIX; + return null; +}; + +const validatePathStructure = (elements) => { + return elements.every((element, index) => { + const isEvenIndex = index % 2 === 0; + return isEvenIndex + ? !isPathParam(element) + : isPathParam(element); + }); +}; + +// eslint-disable-next-line no-unused-vars +export default (input, _0, _1) => { + const prefix = getPrefix(input); + if (!prefix) return []; + + let suffixWithLeadingSlash = input.slice(prefix.length); + if(suffixWithLeadingSlash.length === 0) { + return []; + } + + let suffix = suffixWithLeadingSlash.slice(1); + let elements = suffix.split("/"); + return validatePathStructure(elements) ? [] : ERROR_RESULT; + +} diff --git a/tools/spectral/ipa/rulesets/functions/utils/pathUtils.js b/tools/spectral/ipa/rulesets/functions/utils/pathUtils.js new file mode 100644 index 0000000000..dc571c5d8e --- /dev/null +++ b/tools/spectral/ipa/rulesets/functions/utils/pathUtils.js @@ -0,0 +1,5 @@ +export function isPathParam(str) { + const pathParamRegEx = new RegExp(`^{[a-z][a-zA-Z0-9]*}$`); + const pathParamWithCustomMethodRegEx = new RegExp(`^{[a-z][a-zA-Z0-9]*}:[a-z][a-zA-Z0-9]*$`); + return pathParamRegEx.test(str) || pathParamWithCustomMethodRegEx.test(str); +} \ No newline at end of file From 9a1e37c025a267373b0ca4b8665961f4d932b25a Mon Sep 17 00:00:00 2001 From: Yeliz Henden Date: Tue, 17 Dec 2024 14:32:51 +0000 Subject: [PATCH 2/6] fix --- .../ipa/__tests__/eachResourceHasGetMethod.test.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/spectral/ipa/__tests__/eachResourceHasGetMethod.test.js b/tools/spectral/ipa/__tests__/eachResourceHasGetMethod.test.js index dc03a39a57..64df503f92 100644 --- a/tools/spectral/ipa/__tests__/eachResourceHasGetMethod.test.js +++ b/tools/spectral/ipa/__tests__/eachResourceHasGetMethod.test.js @@ -95,31 +95,31 @@ testRule('xgen-IPA-104-resource-has-GET', [ errors: [ { code: 'xgen-IPA-104-resource-has-GET', - message: 'APIs must provide a get method for resources. http://go/ipa/117', + message: 'APIs must provide a get method for resources. http://go/ipa/104', path: ['paths', '/standard'], severity: DiagnosticSeverity.Warning, }, { code: 'xgen-IPA-104-resource-has-GET', - message: 'APIs must provide a get method for resources. http://go/ipa/117', + message: 'APIs must provide a get method for resources. http://go/ipa/104', path: ['paths', '/standard/{exampleId}/nested'], severity: DiagnosticSeverity.Warning, }, { code: 'xgen-IPA-104-resource-has-GET', - message: 'APIs must provide a get method for resources. http://go/ipa/117', + message: 'APIs must provide a get method for resources. http://go/ipa/104', path: ['paths', '/standard/{exampleId}/nestedSingleton'], severity: DiagnosticSeverity.Warning, }, { code: 'xgen-IPA-104-resource-has-GET', - message: 'APIs must provide a get method for resources. http://go/ipa/117', + message: 'APIs must provide a get method for resources. http://go/ipa/104', path: ['paths', '/custom'], severity: DiagnosticSeverity.Warning, }, { code: 'xgen-IPA-104-resource-has-GET', - message: 'APIs must provide a get method for resources. http://go/ipa/117', + message: 'APIs must provide a get method for resources. http://go/ipa/104', path: ['paths', '/singleton'], severity: DiagnosticSeverity.Warning, }, From 81a2d233e670f471375b5766a24427e9af256a67 Mon Sep 17 00:00:00 2001 From: Yeliz Henden Date: Tue, 17 Dec 2024 14:33:35 +0000 Subject: [PATCH 3/6] fix --- ...tesBetweenResourceNameAndPathParam.test.js | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/tools/spectral/ipa/__tests__/eachPathAlternatesBetweenResourceNameAndPathParam.test.js b/tools/spectral/ipa/__tests__/eachPathAlternatesBetweenResourceNameAndPathParam.test.js index 37e5ac7089..9c1b25a964 100644 --- a/tools/spectral/ipa/__tests__/eachPathAlternatesBetweenResourceNameAndPathParam.test.js +++ b/tools/spectral/ipa/__tests__/eachPathAlternatesBetweenResourceNameAndPathParam.test.js @@ -105,37 +105,37 @@ testRule('xgen-IPA-102-path-alternate-resource-name-path-param', [ errors: [ { code: 'xgen-IPA-102-path-alternate-resource-name-path-param', - message: 'API paths must alternate between resource name and path params. http://go/ipa/117', + message: 'API paths must alternate between resource name and path params. http://go/ipa/102', path: ['paths', '/api/atlas/v2/resourceName1/resourceName2'], severity: DiagnosticSeverity.Warning, }, { code: 'xgen-IPA-102-path-alternate-resource-name-path-param', - message: 'API paths must alternate between resource name and path params. http://go/ipa/117', + message: 'API paths must alternate between resource name and path params. http://go/ipa/102', path: ['paths', '/api/atlas/v2/resourceName/{pathParam1}/{pathParam2}'], severity: DiagnosticSeverity.Warning, }, { code: 'xgen-IPA-102-path-alternate-resource-name-path-param', - message: 'API paths must alternate between resource name and path params. http://go/ipa/117', + message: 'API paths must alternate between resource name and path params. http://go/ipa/102', path: ['paths', '/api/atlas/v2/resourceName1/{pathParam1}/resourceName2/resourceName3'], severity: DiagnosticSeverity.Warning, }, { code: 'xgen-IPA-102-path-alternate-resource-name-path-param', - message: 'API paths must alternate between resource name and path params. http://go/ipa/117', + message: 'API paths must alternate between resource name and path params. http://go/ipa/102', path: ['paths', '/api/atlas/v2/resourceName1/{pathParam1}/resourceName2/{pathParam2}/{pathParam3}'], severity: DiagnosticSeverity.Warning, }, { code: 'xgen-IPA-102-path-alternate-resource-name-path-param', - message: 'API paths must alternate between resource name and path params. http://go/ipa/117', + message: 'API paths must alternate between resource name and path params. http://go/ipa/102', path: ['paths', '/api/atlas/v2/{pathParam}'], severity: DiagnosticSeverity.Warning, }, { code: 'xgen-IPA-102-path-alternate-resource-name-path-param', - message: 'API paths must alternate between resource name and path params. http://go/ipa/117', + message: 'API paths must alternate between resource name and path params. http://go/ipa/102', path: ['paths', '/api/atlas/v2/{pathParam1}/{pathParam2}'], severity: DiagnosticSeverity.Warning, }, @@ -174,37 +174,37 @@ testRule('xgen-IPA-102-path-alternate-resource-name-path-param', [ errors: [ { code: 'xgen-IPA-102-path-alternate-resource-name-path-param', - message: 'API paths must alternate between resource name and path params. http://go/ipa/117', + message: 'API paths must alternate between resource name and path params. http://go/ipa/102', path: ['paths', '/api/atlas/v2/unauth/resourceName1/resourceName2'], severity: DiagnosticSeverity.Warning, }, { code: 'xgen-IPA-102-path-alternate-resource-name-path-param', - message: 'API paths must alternate between resource name and path params. http://go/ipa/117', + message: 'API paths must alternate between resource name and path params. http://go/ipa/102', path: ['paths', '/api/atlas/v2/unauth/resourceName/{pathParam1}/{pathParam2}'], severity: DiagnosticSeverity.Warning, }, { code: 'xgen-IPA-102-path-alternate-resource-name-path-param', - message: 'API paths must alternate between resource name and path params. http://go/ipa/117', + message: 'API paths must alternate between resource name and path params. http://go/ipa/102', path: ['paths', '/api/atlas/v2/unauth/resourceName1/{pathParam1}/resourceName2/resourceName3'], severity: DiagnosticSeverity.Warning, }, { code: 'xgen-IPA-102-path-alternate-resource-name-path-param', - message: 'API paths must alternate between resource name and path params. http://go/ipa/117', + message: 'API paths must alternate between resource name and path params. http://go/ipa/102', path: ['paths', '/api/atlas/v2/unauth/resourceName1/{pathParam1}/resourceName2/{pathParam2}/{pathParam3}'], severity: DiagnosticSeverity.Warning, }, { code: 'xgen-IPA-102-path-alternate-resource-name-path-param', - message: 'API paths must alternate between resource name and path params. http://go/ipa/117', + message: 'API paths must alternate between resource name and path params. http://go/ipa/102', path: ['paths', '/api/atlas/v2/unauth/{pathParam}'], severity: DiagnosticSeverity.Warning, }, { code: 'xgen-IPA-102-path-alternate-resource-name-path-param', - message: 'API paths must alternate between resource name and path params. http://go/ipa/117', + message: 'API paths must alternate between resource name and path params. http://go/ipa/102', path: ['paths', '/api/atlas/v2/unauth/{pathParam1}/{pathParam2}'], severity: DiagnosticSeverity.Warning, }, From dafe953a78099757af136229b9c82cc4d5bf0220 Mon Sep 17 00:00:00 2001 From: Yeliz Henden Date: Tue, 17 Dec 2024 14:35:07 +0000 Subject: [PATCH 4/6] prettier fix --- ...ernatesBetweenResourceNameAndPathParam.test.js | 10 +++++----- tools/spectral/ipa/rulesets/IPA-102.yaml | 10 +++++----- tools/spectral/ipa/rulesets/IPA-104.yaml | 10 +++++----- ...thAlternatesBetweenResourceNameAndPathParam.js | 15 ++++++--------- .../ipa/rulesets/functions/utils/pathUtils.js | 2 +- 5 files changed, 22 insertions(+), 25 deletions(-) diff --git a/tools/spectral/ipa/__tests__/eachPathAlternatesBetweenResourceNameAndPathParam.test.js b/tools/spectral/ipa/__tests__/eachPathAlternatesBetweenResourceNameAndPathParam.test.js index 9c1b25a964..c4639680a1 100644 --- a/tools/spectral/ipa/__tests__/eachPathAlternatesBetweenResourceNameAndPathParam.test.js +++ b/tools/spectral/ipa/__tests__/eachPathAlternatesBetweenResourceNameAndPathParam.test.js @@ -32,7 +32,7 @@ testRule('xgen-IPA-102-path-alternate-resource-name-path-param', [ }, '/api/atlas/v2': { post: {}, - } + }, }, }, errors: [], @@ -67,7 +67,7 @@ testRule('xgen-IPA-102-path-alternate-resource-name-path-param', [ }, '/api/atlas/v2/unauth': { post: {}, - } + }, }, }, errors: [], @@ -99,7 +99,7 @@ testRule('xgen-IPA-102-path-alternate-resource-name-path-param', [ '/api/atlas/v2/{pathParam1}/{pathParam2}': { post: {}, get: {}, - } + }, }, }, errors: [ @@ -139,7 +139,7 @@ testRule('xgen-IPA-102-path-alternate-resource-name-path-param', [ path: ['paths', '/api/atlas/v2/{pathParam1}/{pathParam2}'], severity: DiagnosticSeverity.Warning, }, - ] + ], }, { name: 'invalid paths - api/atlas/v2/unauth', @@ -168,7 +168,7 @@ testRule('xgen-IPA-102-path-alternate-resource-name-path-param', [ '/api/atlas/v2/unauth/{pathParam1}/{pathParam2}': { post: {}, get: {}, - } + }, }, }, errors: [ diff --git a/tools/spectral/ipa/rulesets/IPA-102.yaml b/tools/spectral/ipa/rulesets/IPA-102.yaml index f9c9517019..e2e2176137 100644 --- a/tools/spectral/ipa/rulesets/IPA-102.yaml +++ b/tools/spectral/ipa/rulesets/IPA-102.yaml @@ -6,10 +6,10 @@ functions: rules: xgen-IPA-102-path-alternate-resource-name-path-param: - description: "Paths should alternate between resource names and path params. http://go/ipa/102" - message: "{{error}} http://go/ipa/102" + description: 'Paths should alternate between resource names and path params. http://go/ipa/102' + message: '{{error}} http://go/ipa/102' severity: warn - given: "$.paths" + given: '$.paths' then: - field: "@key" - function: "eachPathAlternatesBetweenResourceNameAndPathParam" \ No newline at end of file + field: '@key' + function: 'eachPathAlternatesBetweenResourceNameAndPathParam' diff --git a/tools/spectral/ipa/rulesets/IPA-104.yaml b/tools/spectral/ipa/rulesets/IPA-104.yaml index 1c0da30943..f0ef7eed24 100644 --- a/tools/spectral/ipa/rulesets/IPA-104.yaml +++ b/tools/spectral/ipa/rulesets/IPA-104.yaml @@ -6,10 +6,10 @@ functions: rules: xgen-IPA-104-resource-has-GET: - description: "APIs must provide a get method for resources. http://go/ipa/104" - message: "{{error}} http://go/ipa/104" + description: 'APIs must provide a get method for resources. http://go/ipa/104' + message: '{{error}} http://go/ipa/104' severity: warn - given: "$.paths" + given: '$.paths' then: - field: "@key" - function: "eachResourceHasGetMethod" + field: '@key' + function: 'eachResourceHasGetMethod' diff --git a/tools/spectral/ipa/rulesets/functions/eachPathAlternatesBetweenResourceNameAndPathParam.js b/tools/spectral/ipa/rulesets/functions/eachPathAlternatesBetweenResourceNameAndPathParam.js index 7b0da80306..93b15f6c37 100644 --- a/tools/spectral/ipa/rulesets/functions/eachPathAlternatesBetweenResourceNameAndPathParam.js +++ b/tools/spectral/ipa/rulesets/functions/eachPathAlternatesBetweenResourceNameAndPathParam.js @@ -2,8 +2,8 @@ import { isPathParam } from './utils/pathUtils'; const ERROR_MESSAGE = 'API paths must alternate between resource name and path params.'; const ERROR_RESULT = [{ message: ERROR_MESSAGE }]; -const AUTH_PREFIX = "/api/atlas/v2"; -const UNAUTH_PREFIX = "/api/atlas/v2/unauth" +const AUTH_PREFIX = '/api/atlas/v2'; +const UNAUTH_PREFIX = '/api/atlas/v2/unauth'; const getPrefix = (path) => { if (path.includes(UNAUTH_PREFIX)) return UNAUTH_PREFIX; @@ -14,9 +14,7 @@ const getPrefix = (path) => { const validatePathStructure = (elements) => { return elements.every((element, index) => { const isEvenIndex = index % 2 === 0; - return isEvenIndex - ? !isPathParam(element) - : isPathParam(element); + return isEvenIndex ? !isPathParam(element) : isPathParam(element); }); }; @@ -26,12 +24,11 @@ export default (input, _0, _1) => { if (!prefix) return []; let suffixWithLeadingSlash = input.slice(prefix.length); - if(suffixWithLeadingSlash.length === 0) { + if (suffixWithLeadingSlash.length === 0) { return []; } let suffix = suffixWithLeadingSlash.slice(1); - let elements = suffix.split("/"); + let elements = suffix.split('/'); return validatePathStructure(elements) ? [] : ERROR_RESULT; - -} +}; diff --git a/tools/spectral/ipa/rulesets/functions/utils/pathUtils.js b/tools/spectral/ipa/rulesets/functions/utils/pathUtils.js index dc571c5d8e..da1dd817c8 100644 --- a/tools/spectral/ipa/rulesets/functions/utils/pathUtils.js +++ b/tools/spectral/ipa/rulesets/functions/utils/pathUtils.js @@ -2,4 +2,4 @@ export function isPathParam(str) { const pathParamRegEx = new RegExp(`^{[a-z][a-zA-Z0-9]*}$`); const pathParamWithCustomMethodRegEx = new RegExp(`^{[a-z][a-zA-Z0-9]*}:[a-z][a-zA-Z0-9]*$`); return pathParamRegEx.test(str) || pathParamWithCustomMethodRegEx.test(str); -} \ No newline at end of file +} From 3eceba0a14aad2c799a8e3c7143428361fff4387 Mon Sep 17 00:00:00 2001 From: Yeliz Henden Date: Tue, 17 Dec 2024 14:59:39 +0000 Subject: [PATCH 5/6] address the comments --- .../eachPathAlternatesBetweenResourceNameAndPathParam.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tools/spectral/ipa/rulesets/functions/eachPathAlternatesBetweenResourceNameAndPathParam.js b/tools/spectral/ipa/rulesets/functions/eachPathAlternatesBetweenResourceNameAndPathParam.js index 93b15f6c37..5aa3725238 100644 --- a/tools/spectral/ipa/rulesets/functions/eachPathAlternatesBetweenResourceNameAndPathParam.js +++ b/tools/spectral/ipa/rulesets/functions/eachPathAlternatesBetweenResourceNameAndPathParam.js @@ -18,8 +18,7 @@ const validatePathStructure = (elements) => { }); }; -// eslint-disable-next-line no-unused-vars -export default (input, _0, _1) => { +export default (input) => { const prefix = getPrefix(input); if (!prefix) return []; From 1c6cfa29ed3ed0f6d938cb400a3b52f4a9515e4d Mon Sep 17 00:00:00 2001 From: Yeliz Henden Date: Tue, 17 Dec 2024 15:49:51 +0000 Subject: [PATCH 6/6] address the comments --- .prettierignore | 1 + ...tesBetweenResourceNameAndPathParam.test.js | 128 ++++-------------- ...ternatesBetweenResourceNameAndPathParam.js | 8 +- .../ipa/rulesets/functions/utils/pathUtils.js | 9 ++ 4 files changed, 41 insertions(+), 105 deletions(-) diff --git a/.prettierignore b/.prettierignore index 317beb2aa0..dc246e01d9 100644 --- a/.prettierignore +++ b/.prettierignore @@ -4,3 +4,4 @@ *.yaml *.yml *.html +!/tools/spectral/ipa/**/*.yaml \ No newline at end of file diff --git a/tools/spectral/ipa/__tests__/eachPathAlternatesBetweenResourceNameAndPathParam.test.js b/tools/spectral/ipa/__tests__/eachPathAlternatesBetweenResourceNameAndPathParam.test.js index c4639680a1..e78401cbf8 100644 --- a/tools/spectral/ipa/__tests__/eachPathAlternatesBetweenResourceNameAndPathParam.test.js +++ b/tools/spectral/ipa/__tests__/eachPathAlternatesBetweenResourceNameAndPathParam.test.js @@ -6,33 +6,13 @@ testRule('xgen-IPA-102-path-alternate-resource-name-path-param', [ name: 'valid paths - api/atlas/v2', document: { paths: { - '/api/atlas/v2/resourceName': { - post: {}, - get: {}, - }, - '/api/atlas/v2/resourceName/{pathParam}': { - get: {}, - patch: {}, - delete: {}, - }, - '/api/atlas/v2/resourceName1/{pathParam}/resourceName2': { - post: {}, - get: {}, - }, - '/api/atlas/v2/resourceName1/{pathParam1p}/resourceName2/{pathParam2}': { - get: {}, - patch: {}, - delete: {}, - }, - '/api/atlas/v2/resourceName/{pathParam}:method': { - post: {}, - }, - '/api/atlas/v2/custom:method': { - post: {}, - }, - '/api/atlas/v2': { - post: {}, - }, + '/api/atlas/v2/resourceName': {}, + '/api/atlas/v2/resourceName/{pathParam}': {}, + '/api/atlas/v2/resourceName1/{pathParam}/resourceName2': {}, + '/api/atlas/v2/resourceName1/{pathParam1p}/resourceName2/{pathParam2}': {}, + '/api/atlas/v2/resourceName/{pathParam}:method': {}, + '/api/atlas/v2/custom:method': {}, + '/api/atlas/v2': {}, }, }, errors: [], @@ -41,33 +21,13 @@ testRule('xgen-IPA-102-path-alternate-resource-name-path-param', [ name: 'valid paths - api/atlas/v2/unauth', document: { paths: { - '/api/atlas/v2/unauth/resourceName': { - post: {}, - get: {}, - }, - '/api/atlas/v2/unauth/resourceName/{pathParam}': { - get: {}, - patch: {}, - delete: {}, - }, - '/api/atlas/v2/unauth/resourceName1/{pathParam}/resourceName2': { - post: {}, - get: {}, - }, - '/api/atlas/v2/unauth/resourceName1/{pathParam1p}/resourceName2/{pathParam2}': { - get: {}, - patch: {}, - delete: {}, - }, - '/api/atlas/v2/unauth/resourceName/{pathParam}:method': { - post: {}, - }, - '/api/atlas/v2/unauth/custom:method': { - post: {}, - }, - '/api/atlas/v2/unauth': { - post: {}, - }, + '/api/atlas/v2/unauth/resourceName': {}, + '/api/atlas/v2/unauth/resourceName/{pathParam}': {}, + '/api/atlas/v2/unauth/resourceName1/{pathParam}/resourceName2': {}, + '/api/atlas/v2/unauth/resourceName1/{pathParam1p}/resourceName2/{pathParam2}': {}, + '/api/atlas/v2/unauth/resourceName/{pathParam}:method': {}, + '/api/atlas/v2/unauth/custom:method': {}, + '/api/atlas/v2/unauth': {}, }, }, errors: [], @@ -76,30 +36,12 @@ testRule('xgen-IPA-102-path-alternate-resource-name-path-param', [ name: 'invalid paths - api/atlas/v2', document: { paths: { - '/api/atlas/v2/resourceName1/resourceName2': { - post: {}, - get: {}, - }, - '/api/atlas/v2/resourceName/{pathParam1}/{pathParam2}': { - patch: {}, - delete: {}, - }, - '/api/atlas/v2/resourceName1/{pathParam1}/resourceName2/resourceName3': { - patch: {}, - delete: {}, - }, - '/api/atlas/v2/resourceName1/{pathParam1}/resourceName2/{pathParam2}/{pathParam3}': { - patch: {}, - delete: {}, - }, - '/api/atlas/v2/{pathParam}': { - post: {}, - get: {}, - }, - '/api/atlas/v2/{pathParam1}/{pathParam2}': { - post: {}, - get: {}, - }, + '/api/atlas/v2/resourceName1/resourceName2': {}, + '/api/atlas/v2/resourceName/{pathParam1}/{pathParam2}': {}, + '/api/atlas/v2/resourceName1/{pathParam1}/resourceName2/resourceName3': {}, + '/api/atlas/v2/resourceName1/{pathParam1}/resourceName2/{pathParam2}/{pathParam3}': {}, + '/api/atlas/v2/{pathParam}': {}, + '/api/atlas/v2/{pathParam1}/{pathParam2}': {}, }, }, errors: [ @@ -145,30 +87,12 @@ testRule('xgen-IPA-102-path-alternate-resource-name-path-param', [ name: 'invalid paths - api/atlas/v2/unauth', document: { paths: { - '/api/atlas/v2/unauth/resourceName1/resourceName2': { - post: {}, - get: {}, - }, - '/api/atlas/v2/unauth/resourceName/{pathParam1}/{pathParam2}': { - patch: {}, - delete: {}, - }, - '/api/atlas/v2/unauth/resourceName1/{pathParam1}/resourceName2/resourceName3': { - patch: {}, - delete: {}, - }, - '/api/atlas/v2/unauth/resourceName1/{pathParam1}/resourceName2/{pathParam2}/{pathParam3}': { - patch: {}, - delete: {}, - }, - '/api/atlas/v2/unauth/{pathParam}': { - post: {}, - get: {}, - }, - '/api/atlas/v2/unauth/{pathParam1}/{pathParam2}': { - post: {}, - get: {}, - }, + '/api/atlas/v2/unauth/resourceName1/resourceName2': {}, + '/api/atlas/v2/unauth/resourceName/{pathParam1}/{pathParam2}': {}, + '/api/atlas/v2/unauth/resourceName1/{pathParam1}/resourceName2/resourceName3': {}, + '/api/atlas/v2/unauth/resourceName1/{pathParam1}/resourceName2/{pathParam2}/{pathParam3}': {}, + '/api/atlas/v2/unauth/{pathParam}': {}, + '/api/atlas/v2/unauth/{pathParam1}/{pathParam2}': {}, }, }, errors: [ diff --git a/tools/spectral/ipa/rulesets/functions/eachPathAlternatesBetweenResourceNameAndPathParam.js b/tools/spectral/ipa/rulesets/functions/eachPathAlternatesBetweenResourceNameAndPathParam.js index 5aa3725238..6fd1f96398 100644 --- a/tools/spectral/ipa/rulesets/functions/eachPathAlternatesBetweenResourceNameAndPathParam.js +++ b/tools/spectral/ipa/rulesets/functions/eachPathAlternatesBetweenResourceNameAndPathParam.js @@ -20,14 +20,16 @@ const validatePathStructure = (elements) => { export default (input) => { const prefix = getPrefix(input); - if (!prefix) return []; + if (!prefix) return; let suffixWithLeadingSlash = input.slice(prefix.length); if (suffixWithLeadingSlash.length === 0) { - return []; + return; } let suffix = suffixWithLeadingSlash.slice(1); let elements = suffix.split('/'); - return validatePathStructure(elements) ? [] : ERROR_RESULT; + if (!validatePathStructure(elements)) { + return ERROR_RESULT; + } }; diff --git a/tools/spectral/ipa/rulesets/functions/utils/pathUtils.js b/tools/spectral/ipa/rulesets/functions/utils/pathUtils.js index da1dd817c8..34d1910175 100644 --- a/tools/spectral/ipa/rulesets/functions/utils/pathUtils.js +++ b/tools/spectral/ipa/rulesets/functions/utils/pathUtils.js @@ -1,3 +1,12 @@ +/** + * Checks if a string belongs to a path parameter or a path parameter with a custom method. + * + * A path parameter has the format: `{paramName}` + * A path parameter with a custom method has the format: `{paramName}:customMethod` + * + * @param {string} str - A string extracted from a path split by slashes. + * @returns {boolean} True if the string matches the expected formats, false otherwise. + */ export function isPathParam(str) { const pathParamRegEx = new RegExp(`^{[a-z][a-zA-Z0-9]*}$`); const pathParamWithCustomMethodRegEx = new RegExp(`^{[a-z][a-zA-Z0-9]*}:[a-z][a-zA-Z0-9]*$`);