From dcc403ee38730f66eddc53b041ee8d16ec6f751d Mon Sep 17 00:00:00 2001 From: Lovisa Berggren Date: Tue, 11 Mar 2025 10:52:49 +0000 Subject: [PATCH 1/3] CLOUDP-271993: Add rule xgen-IPA-105-list-method-no-request-body --- .../listMethodHasNoRequestBody.test.js | 117 ++++++++++++++++++ tools/spectral/ipa/rulesets/IPA-105.yaml | 8 ++ tools/spectral/ipa/rulesets/README.md | 7 +- .../functions/listMethodHasNoRequestBody.js | 41 ++++++ 4 files changed, 170 insertions(+), 3 deletions(-) create mode 100644 tools/spectral/ipa/__tests__/listMethodHasNoRequestBody.test.js create mode 100644 tools/spectral/ipa/rulesets/functions/listMethodHasNoRequestBody.js diff --git a/tools/spectral/ipa/__tests__/listMethodHasNoRequestBody.test.js b/tools/spectral/ipa/__tests__/listMethodHasNoRequestBody.test.js new file mode 100644 index 0000000000..ba3e270294 --- /dev/null +++ b/tools/spectral/ipa/__tests__/listMethodHasNoRequestBody.test.js @@ -0,0 +1,117 @@ +import testRule from './__helpers__/testRule'; +import { DiagnosticSeverity } from '@stoplight/types'; + +testRule('xgen-IPA-105-list-method-no-request-body', [ + { + name: 'valid list without body', + document: { + paths: { + '/resource': { + get: { + responses: { + 200: {}, + }, + }, + }, + }, + }, + errors: [], + }, + { + name: 'rule ignores singleton and Get', + document: { + paths: { + '/resource': { + get: { + responses: { + 200: {}, + }, + }, + }, + '/resource/{id}': { + get: { + responses: { + 200: {}, + }, + requestBody: { + content: { + 'application/vnd.atlas.2024-08-05+json': { + schema: { type: 'object' }, + }, + }, + }, + }, + }, + '/resource/{id}/singleton': { + get: { + responses: { + 200: {}, + }, + requestBody: { + content: { + 'application/vnd.atlas.2024-08-05+json': { + schema: { type: 'object' }, + }, + }, + }, + }, + }, + }, + }, + errors: [], + }, + { + name: 'invalid list with body', + document: { + paths: { + '/resource': { + get: { + responses: { + 200: {}, + }, + requestBody: { + content: { + 'application/vnd.atlas.2024-08-05+json': { + schema: { type: 'object' }, + }, + }, + }, + }, + }, + }, + }, + errors: [ + { + code: 'xgen-IPA-105-list-method-no-request-body', + message: 'The List method must not include a request body. http://go/ipa/105', + path: ['paths', '/resource', 'get'], + severity: DiagnosticSeverity.Warning, + }, + ], + }, + { + name: 'invalid with exception', + document: { + paths: { + '/resource': { + get: { + 'x-xgen-IPA-exception': { + 'xgen-IPA-105-list-method-no-request-body': 'reason', + }, + responses: { + 200: {}, + }, + requestBody: { + content: { + 'application/vnd.atlas.2024-08-05+json': { + schema: { type: 'object' }, + }, + }, + }, + }, + }, + }, + }, + errors: [], + }, +]); diff --git a/tools/spectral/ipa/rulesets/IPA-105.yaml b/tools/spectral/ipa/rulesets/IPA-105.yaml index 1669c1eb60..b5ad1259c1 100644 --- a/tools/spectral/ipa/rulesets/IPA-105.yaml +++ b/tools/spectral/ipa/rulesets/IPA-105.yaml @@ -3,6 +3,7 @@ functions: - listResponseCodeShouldBe200OK + - listMethodHasNoRequestBody rules: xgen-IPA-105-list-method-response-code-is-200: @@ -12,3 +13,10 @@ rules: given: '$.paths[*].get' then: function: 'listResponseCodeShouldBe200OK' + xgen-IPA-105-list-method-no-request-body: + description: 'The List method request must not include a body. http://go/ipa/105' + message: '{{error}} http://go/ipa/105' + severity: warn + given: '$.paths[*].get' + then: + function: 'listMethodHasNoRequestBody' diff --git a/tools/spectral/ipa/rulesets/README.md b/tools/spectral/ipa/rulesets/README.md index 60f7eb3756..c473cee187 100644 --- a/tools/spectral/ipa/rulesets/README.md +++ b/tools/spectral/ipa/rulesets/README.md @@ -42,9 +42,10 @@ For rule definitions, see [IPA-104.yaml](https://github.com/mongodb/openapi/blob For rule definitions, see [IPA-105.yaml](https://github.com/mongodb/openapi/blob/main/tools/spectral/ipa/rulesets/IPA-105.yaml). -| Rule Name | Description | Severity | -| --------------------------------------------- | ---------------------------------------------------------------- | -------- | -| xgen-IPA-105-list-method-response-code-is-200 | The List method must return a 200 OK response. http://go/ipa/105 | warn | +| Rule Name | Description | Severity | +| --------------------------------------------- | ------------------------------------------------------------------ | -------- | +| xgen-IPA-105-list-method-response-code-is-200 | The List method must return a 200 OK response. http://go/ipa/105 | warn | +| xgen-IPA-105-list-method-no-request-body | The List method request must not include a body. http://go/ipa/105 | warn | ### IPA-106 diff --git a/tools/spectral/ipa/rulesets/functions/listMethodHasNoRequestBody.js b/tools/spectral/ipa/rulesets/functions/listMethodHasNoRequestBody.js new file mode 100644 index 0000000000..f2efc90116 --- /dev/null +++ b/tools/spectral/ipa/rulesets/functions/listMethodHasNoRequestBody.js @@ -0,0 +1,41 @@ +import { hasException } from './utils/exceptions.js'; +import { collectAdoption, collectAndReturnViolation, collectException } from './utils/collectionUtils.js'; +import { + getResourcePathItems, + isResourceCollectionIdentifier, + isSingletonResource, +} from './utils/resourceEvaluation.js'; + +const RULE_NAME = 'xgen-IPA-105-list-method-no-request-body'; +const ERROR_MESSAGE = 'The List method must not include a request body.'; + +export default (input, _, { path, documentInventory }) => { + const resourcePath = path[1]; + const oas = documentInventory.resolved; + + if ( + !isResourceCollectionIdentifier(resourcePath) || + (isResourceCollectionIdentifier(resourcePath) && isSingletonResource(getResourcePathItems(resourcePath, oas.paths))) + ) { + return; + } + + if (hasException(input, RULE_NAME)) { + collectException(input, RULE_NAME, path); + return; + } + + const errors = checkViolationsAndReturnErrors(input, path); + + if (errors.length !== 0) { + return collectAndReturnViolation(path, RULE_NAME, errors); + } + collectAdoption(path, RULE_NAME); +}; + +function checkViolationsAndReturnErrors(getOperationObject, path) { + if (getOperationObject.requestBody) { + return [{ path, message: ERROR_MESSAGE }]; + } + return []; +} From eb3bda5306adbef0a967a9af644abf392992c888 Mon Sep 17 00:00:00 2001 From: Lovisa Berggren Date: Tue, 11 Mar 2025 11:00:17 +0000 Subject: [PATCH 2/3] CLOUDP-271993: Add line to contributing --- CONTRIBUTING.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6cdd7ba5aa..e2b15d9d9b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -35,6 +35,7 @@ This will install Husky, which manages Git hooks for the project. The hooks ensu This project uses the following Git hooks: - **pre-commit**: Automatically formats your code using Prettier and runs tests for staged JavaScript files to ensure code quality before each commit. + - If you get the message `hint: The '.husky/pre-commit' hook was ignored because it's not set as executable.` during the commit, you can run `chmod ug+x .husky/*` to make it executable. ### Available Scripts From 5bbb538ea0ecbd6b7b667de84ae9e01dacf3ce86 Mon Sep 17 00:00:00 2001 From: Lovisa Berggren Date: Tue, 11 Mar 2025 11:00:47 +0000 Subject: [PATCH 3/3] CLOUDP-271993: Fix --- .husky/pre-commit | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 .husky/pre-commit diff --git a/.husky/pre-commit b/.husky/pre-commit old mode 100644 new mode 100755