From 839f2ee884680eadaaf24c3bf05b1832707c669f Mon Sep 17 00:00:00 2001 From: Lovisa Berggren Date: Wed, 19 Mar 2025 14:52:30 +0000 Subject: [PATCH] CLOUDP-307341: Include singleton in IPA 107 rules --- ...dateMethodRequestBodyIsGetResponse.test.js | 40 ++++++++++++++ ...teMethodRequestHasNoReadonlyFields.test.js | 52 +++++++++++++++++++ ...eMethodResponseIsGetMethodResponse.test.js | 42 +++++++++++++++ tools/spectral/ipa/rulesets/IPA-107.yaml | 8 +-- tools/spectral/ipa/rulesets/README.md | 8 +-- ...107UpdateMethodRequestBodyIsGetResponse.js | 16 ++++-- ...7UpdateMethodRequestHasNoReadonlyFields.js | 14 ++++- ...UpdateMethodResponseIsGetMethodResponse.js | 14 ++++- 8 files changed, 179 insertions(+), 15 deletions(-) diff --git a/tools/spectral/ipa/__tests__/IPA107UpdateMethodRequestBodyIsGetResponse.test.js b/tools/spectral/ipa/__tests__/IPA107UpdateMethodRequestBodyIsGetResponse.test.js index c75f790c90..bd921b4878 100644 --- a/tools/spectral/ipa/__tests__/IPA107UpdateMethodRequestBodyIsGetResponse.test.js +++ b/tools/spectral/ipa/__tests__/IPA107UpdateMethodRequestBodyIsGetResponse.test.js @@ -402,6 +402,32 @@ testRule('xgen-IPA-107-update-method-request-body-is-get-method-response', [ }, }, }, + '/resource/{id}/singleton': { + get: { + responses: { + 200: { + content: { + 'application/vnd.atlas.2023-01-01+json': { + schema: { + $ref: '#/components/schemas/SchemaOne', + }, + }, + }, + }, + }, + }, + patch: { + requestBody: { + content: { + 'application/vnd.atlas.2023-01-01+json': { + schema: { + $ref: '#/components/schemas/SchemaThree', + }, + }, + }, + }, + }, + }, }, }, errors: [ @@ -517,6 +543,20 @@ testRule('xgen-IPA-107-update-method-request-body-is-get-method-response', [ ], severity: DiagnosticSeverity.Warning, }, + { + code: 'xgen-IPA-107-update-method-request-body-is-get-method-response', + message: + 'The request body schema properties of the Update method must match the response body schema properties of the Get method.', + path: [ + 'paths', + '/resource/{id}/singleton', + 'patch', + 'requestBody', + 'content', + 'application/vnd.atlas.2023-01-01+json', + ], + severity: DiagnosticSeverity.Warning, + }, ], }, { diff --git a/tools/spectral/ipa/__tests__/IPA107UpdateMethodRequestHasNoReadonlyFields.test.js b/tools/spectral/ipa/__tests__/IPA107UpdateMethodRequestHasNoReadonlyFields.test.js index 9dd3838725..3e7d7cedb0 100644 --- a/tools/spectral/ipa/__tests__/IPA107UpdateMethodRequestHasNoReadonlyFields.test.js +++ b/tools/spectral/ipa/__tests__/IPA107UpdateMethodRequestHasNoReadonlyFields.test.js @@ -151,6 +151,30 @@ testRule('xgen-IPA-107-update-method-request-has-no-readonly-fields', [ }, }, }, + '/resource/{id}/singleton': { + patch: { + requestBody: { + content: { + 'application/vnd.atlas.2023-01-01+json': { + schema: { + $ref: '#/components/schemas/SchemaWithReadOnly', + }, + }, + }, + }, + }, + put: { + requestBody: { + content: { + 'application/vnd.atlas.2023-01-01+json': { + schema: { + $ref: '#/components/schemas/SchemaWithReadOnly', + }, + }, + }, + }, + }, + }, }, }, errors: [ @@ -182,6 +206,34 @@ testRule('xgen-IPA-107-update-method-request-has-no-readonly-fields', [ path: ['paths', '/resource/{id}', 'put', 'requestBody', 'content', 'application/vnd.atlas.2024-01-01+json'], severity: DiagnosticSeverity.Warning, }, + { + code: 'xgen-IPA-107-update-method-request-has-no-readonly-fields', + message: + 'The Update method request object must not include input fields (readOnly properties). Found readOnly property at: id. ', + path: [ + 'paths', + '/resource/{id}/singleton', + 'patch', + 'requestBody', + 'content', + 'application/vnd.atlas.2023-01-01+json', + ], + severity: DiagnosticSeverity.Warning, + }, + { + code: 'xgen-IPA-107-update-method-request-has-no-readonly-fields', + message: + 'The Update method request object must not include input fields (readOnly properties). Found readOnly property at: id. ', + path: [ + 'paths', + '/resource/{id}/singleton', + 'put', + 'requestBody', + 'content', + 'application/vnd.atlas.2023-01-01+json', + ], + severity: DiagnosticSeverity.Warning, + }, ], }, { diff --git a/tools/spectral/ipa/__tests__/IPA107UpdateMethodResponseIsGetMethodResponse.test.js b/tools/spectral/ipa/__tests__/IPA107UpdateMethodResponseIsGetMethodResponse.test.js index 8a1eae3e41..13c5837aa5 100644 --- a/tools/spectral/ipa/__tests__/IPA107UpdateMethodResponseIsGetMethodResponse.test.js +++ b/tools/spectral/ipa/__tests__/IPA107UpdateMethodResponseIsGetMethodResponse.test.js @@ -312,6 +312,34 @@ testRule('xgen-IPA-107-update-method-response-is-get-method-response', [ }, }, }, + '/resourceFour/{id}/singleton': { + get: { + responses: { + 200: { + content: { + 'application/vnd.atlas.2024-01-05+json': { + schema: { + $ref: '#/components/schemas/ResourceSchema', + }, + }, + }, + }, + }, + }, + patch: { + responses: { + 200: { + content: { + 'application/vnd.atlas.2024-01-05+json': { + schema: { + $ref: '#/components/schemas/OtherSchema', + }, + }, + }, + }, + }, + }, + }, }, components: componentSchemas, }, @@ -375,6 +403,20 @@ testRule('xgen-IPA-107-update-method-response-is-get-method-response', [ ], severity: DiagnosticSeverity.Warning, }, + { + code: 'xgen-IPA-107-update-method-response-is-get-method-response', + message: 'The schema in the Update method response must be the same schema as the response of the Get method.', + path: [ + 'paths', + '/resourceFour/{id}/singleton', + 'patch', + 'responses', + '200', + 'content', + 'application/vnd.atlas.2024-01-05+json', + ], + severity: DiagnosticSeverity.Warning, + }, ], }, { diff --git a/tools/spectral/ipa/rulesets/IPA-107.yaml b/tools/spectral/ipa/rulesets/IPA-107.yaml index a221a7fc5c..af321157a7 100644 --- a/tools/spectral/ipa/rulesets/IPA-107.yaml +++ b/tools/spectral/ipa/rulesets/IPA-107.yaml @@ -15,7 +15,7 @@ rules: ##### Implementation details - Validation checks the PATCH/PUT methods for single resource paths and singleton resources. + Validation checks the PATCH/PUT methods for single resource paths and [singleton resources](https://go/ipa/113). - Query parameters `envelope` and `pretty` are exempt from this rule - Operation objects with `x-xgen-IPA-exception` for this rule are excluded from validation @@ -46,7 +46,7 @@ rules: ##### Implementation details Rule checks for the following conditions: - - Applies only to single resource paths with JSON content types + - Applies only to single resource paths and singleton resources with JSON content types - Ignores singleton resources and responses without a schema - Validation ignores resources without a Get method - Fails if the Get method doesn't have a schema reference or if the schemas don't match @@ -63,7 +63,7 @@ rules: ##### Implementation details Rule checks for the following conditions: - - Applies only to Update methods on single resource paths + - Applies only to Update methods on single resource paths or singleton resources - Applies only to JSON content types - Searches through the request schema to find any properties marked with readOnly attribute - Fails if any readOnly properties are found in the request schema @@ -79,7 +79,7 @@ rules: ##### Implementation details - Validation checks the PATCH/PUT methods for single resource paths. + Validation checks the PATCH/PUT methods for single resource paths and singleton resources. - Validation ignores resources without a Get method. - `readOnly:true` properties of Get method response will be ignored. - `writeOnly:true` properties of Update method request will be ignored. diff --git a/tools/spectral/ipa/rulesets/README.md b/tools/spectral/ipa/rulesets/README.md index 81f73824df..b9e03bf6b3 100644 --- a/tools/spectral/ipa/rulesets/README.md +++ b/tools/spectral/ipa/rulesets/README.md @@ -284,7 +284,7 @@ Rules are based on [http://go/ipa/IPA-107](http://go/ipa/IPA-107). ![warn](https://img.shields.io/badge/warning-yellow) Update operations must not accept query parameters. ##### Implementation details -Validation checks the PATCH/PUT methods for single resource paths and singleton resources. +Validation checks the PATCH/PUT methods for single resource paths and [singleton resources](https://go/ipa/113). - Query parameters `envelope` and `pretty` are exempt from this rule - Operation objects with `x-xgen-IPA-exception` for this rule are excluded from validation @@ -301,7 +301,7 @@ Validation checks the PATCH/PUT methods for single resource paths and [singleton ![warn](https://img.shields.io/badge/warning-yellow) The response body of the Update method should consist of the same resource object returned by the Get method. ##### Implementation details Rule checks for the following conditions: - - Applies only to single resource paths with JSON content types + - Applies only to single resource paths and singleton resources with JSON content types - Ignores singleton resources and responses without a schema - Validation ignores resources without a Get method - Fails if the Get method doesn't have a schema reference or if the schemas don't match @@ -313,7 +313,7 @@ Update method Request object must not include fields with readOnly:true. ##### Implementation details Rule checks for the following conditions: - - Applies only to Update methods on single resource paths + - Applies only to Update methods on single resource paths or singleton resources - Applies only to JSON content types - Searches through the request schema to find any properties marked with readOnly attribute - Fails if any readOnly properties are found in the request schema @@ -325,7 +325,7 @@ The request body must contain the resource being updated, i.e. the resource or p ##### Implementation details -Validation checks the PATCH/PUT methods for single resource paths. +Validation checks the PATCH/PUT methods for single resource paths and singleton resources. - Validation ignores resources without a Get method. - `readOnly:true` properties of Get method response will be ignored. - `writeOnly:true` properties of Update method request will be ignored. diff --git a/tools/spectral/ipa/rulesets/functions/IPA107UpdateMethodRequestBodyIsGetResponse.js b/tools/spectral/ipa/rulesets/functions/IPA107UpdateMethodRequestBodyIsGetResponse.js index 29438459b4..69a0e73f38 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA107UpdateMethodRequestBodyIsGetResponse.js +++ b/tools/spectral/ipa/rulesets/functions/IPA107UpdateMethodRequestBodyIsGetResponse.js @@ -1,4 +1,9 @@ -import { isSingleResourceIdentifier } from './utils/resourceEvaluation.js'; +import { + getResourcePathItems, + isResourceCollectionIdentifier, + isSingleResourceIdentifier, + isSingletonResource, +} from './utils/resourceEvaluation.js'; import { resolveObject } from './utils/componentUtils.js'; import { hasException } from './utils/exceptions.js'; import { collectAdoption, collectAndReturnViolation, collectException } from './utils/collectionUtils.js'; @@ -20,9 +25,14 @@ export default (input, _, { path, documentInventory }) => { const oas = documentInventory.resolved; const unresolvedOas = documentInventory.unresolved; const resourcePath = path[1]; - let mediaType = input; + const mediaType = input; + const resourcePathItems = getResourcePathItems(resourcePath, oas.paths); - if (!isSingleResourceIdentifier(resourcePath) || !mediaType.endsWith('json')) { + if ( + !input.endsWith('json') || + (!isSingleResourceIdentifier(resourcePath) && + !(isResourceCollectionIdentifier(resourcePath) && isSingletonResource(resourcePathItems))) + ) { return; } diff --git a/tools/spectral/ipa/rulesets/functions/IPA107UpdateMethodRequestHasNoReadonlyFields.js b/tools/spectral/ipa/rulesets/functions/IPA107UpdateMethodRequestHasNoReadonlyFields.js index 71f399b2c2..e1b4490ca5 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA107UpdateMethodRequestHasNoReadonlyFields.js +++ b/tools/spectral/ipa/rulesets/functions/IPA107UpdateMethodRequestHasNoReadonlyFields.js @@ -1,4 +1,9 @@ -import { isSingleResourceIdentifier } from './utils/resourceEvaluation.js'; +import { + getResourcePathItems, + isResourceCollectionIdentifier, + isSingleResourceIdentifier, + isSingletonResource, +} from './utils/resourceEvaluation.js'; import { resolveObject } from './utils/componentUtils.js'; import { hasException } from './utils/exceptions.js'; import { collectAdoption, collectAndReturnViolation, collectException } from './utils/collectionUtils.js'; @@ -17,8 +22,13 @@ const ERROR_MESSAGE = 'The Update method request object must not include input f export default (input, _, { path, documentInventory }) => { const resourcePath = path[1]; const oas = documentInventory.resolved; + const resourcePathItems = getResourcePathItems(resourcePath, oas.paths); - if (!isSingleResourceIdentifier(resourcePath) || !input.endsWith('json')) { + if ( + !input.endsWith('json') || + (!isSingleResourceIdentifier(resourcePath) && + !(isResourceCollectionIdentifier(resourcePath) && isSingletonResource(resourcePathItems))) + ) { return; } diff --git a/tools/spectral/ipa/rulesets/functions/IPA107UpdateMethodResponseIsGetMethodResponse.js b/tools/spectral/ipa/rulesets/functions/IPA107UpdateMethodResponseIsGetMethodResponse.js index 8423124913..3d395e3b05 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA107UpdateMethodResponseIsGetMethodResponse.js +++ b/tools/spectral/ipa/rulesets/functions/IPA107UpdateMethodResponseIsGetMethodResponse.js @@ -1,4 +1,9 @@ -import { isSingleResourceIdentifier } from './utils/resourceEvaluation.js'; +import { + getResourcePathItems, + isResourceCollectionIdentifier, + isSingleResourceIdentifier, + isSingletonResource, +} from './utils/resourceEvaluation.js'; import { resolveObject } from './utils/componentUtils.js'; import { hasException } from './utils/exceptions.js'; import { @@ -24,8 +29,13 @@ export default (input, _, { path, documentInventory }) => { const oas = documentInventory.unresolved; const resourcePath = path[1]; const mediaType = input; + const resourcePathItems = getResourcePathItems(resourcePath, oas.paths); - if (!mediaType.endsWith('json') || !isSingleResourceIdentifier(resourcePath)) { + if ( + !mediaType.endsWith('json') || + (!isSingleResourceIdentifier(resourcePath) && + !(isResourceCollectionIdentifier(resourcePath) && isSingletonResource(resourcePathItems))) + ) { return; }