From 372fc954ac644dfade295ee3acb86360f876f3bd Mon Sep 17 00:00:00 2001 From: Yeliz Henden Date: Wed, 19 Mar 2025 10:55:32 +0000 Subject: [PATCH 1/5] CLOUDP-272001: IPA-112: Disallow usages of project in the api --- .../IPA112AvoidProjectFieldNames.test.js | 312 ++++++++++++++++++ tools/spectral/ipa/ipa-spectral.yaml | 1 + tools/spectral/ipa/rulesets/IPA-112.yaml | 23 ++ .../functions/IPA112AvoidProjectFieldNames.js | 46 +++ 4 files changed, 382 insertions(+) create mode 100644 tools/spectral/ipa/__tests__/IPA112AvoidProjectFieldNames.test.js create mode 100644 tools/spectral/ipa/rulesets/IPA-112.yaml create mode 100644 tools/spectral/ipa/rulesets/functions/IPA112AvoidProjectFieldNames.js diff --git a/tools/spectral/ipa/__tests__/IPA112AvoidProjectFieldNames.test.js b/tools/spectral/ipa/__tests__/IPA112AvoidProjectFieldNames.test.js new file mode 100644 index 0000000000..78614daaed --- /dev/null +++ b/tools/spectral/ipa/__tests__/IPA112AvoidProjectFieldNames.test.js @@ -0,0 +1,312 @@ +import testRule from './__helpers__/testRule'; +import { DiagnosticSeverity } from '@stoplight/types'; + +testRule('xgen-IPA-112-avoid-project-field-names', [ + { + name: 'valid schema - no project field names', + document: { + components: { + schemas: { + SchemaName: { + properties: { + group: { type: 'string' }, + groupId: { type: 'string' }, + otherField: { type: 'number' } + } + } + } + } + }, + errors: [] + }, + { + name: 'invalid schema - with project field name', + document: { + components: { + schemas: { + SchemaName: { + properties: { + project: { type: 'string' } + } + } + } + } + }, + errors: [ + { + code: 'xgen-IPA-112-avoid-project-field-names', + message: 'Field name "project" should be avoided. Consider using "group", "groups", or "groupId" instead.', + path: ['components', 'schemas', 'SchemaName', 'properties', 'project'], + severity: DiagnosticSeverity.Warning + } + ] + }, + { + name: 'invalid schema - with projects field name', + document: { + components: { + schemas: { + SchemaName: { + properties: { + projects: { type: 'array' } + } + } + } + } + }, + errors: [ + { + code: 'xgen-IPA-112-avoid-project-field-names', + message: 'Field name "projects" should be avoided. Consider using "group", "groups", or "groupId" instead.', + path: ['components', 'schemas', 'SchemaName', 'properties', 'projects'], + severity: DiagnosticSeverity.Warning + } + ] + }, + { + name: 'invalid schema - with projectId field name', + document: { + components: { + schemas: { + SchemaName: { + properties: { + projectId: { type: 'string' } + } + } + } + } + }, + errors: [ + { + code: 'xgen-IPA-112-avoid-project-field-names', + message: 'Field name "projectId" should be avoided. Consider using "group", "groups", or "groupId" instead.', + path: ['components', 'schemas', 'SchemaName', 'properties', 'projectId'], + severity: DiagnosticSeverity.Warning + } + ] + }, + { + name: 'invalid schema - with different case variants', + document: { + components: { + schemas: { + SchemaName: { + properties: { + Project: { type: 'string' }, + PROJECTID: { type: 'string' } + } + } + } + } + }, + errors: [ + { + code: 'xgen-IPA-112-avoid-project-field-names', + message: 'Field name "Project" should be avoided. Consider using "group", "groups", or "groupId" instead.', + path: ['components', 'schemas', 'SchemaName', 'properties', 'Project'], + severity: DiagnosticSeverity.Warning + }, + { + code: 'xgen-IPA-112-avoid-project-field-names', + message: 'Field name "PROJECTID" should be avoided. Consider using "group", "groups", or "groupId" instead.', + path: ['components', 'schemas', 'SchemaName', 'properties', 'PROJECTID'], + severity: DiagnosticSeverity.Warning + } + ] + }, + { + name: 'invalid schema with exception - project field name with exception', + document: { + components: { + schemas: { + SchemaName: { + properties: { + project: { + type: 'string', + 'x-xgen-IPA-exception': { + 'xgen-IPA-112-avoid-project-field-names': 'reason' + } + } + } + } + } + } + }, + errors: [] + }, + { + name: 'paths with project field name', + document: { + paths: { + '/api/resource': { + post: { + requestBody: { + content: { + 'application/json': { + schema: { + properties: { + project: { type: 'string' } + } + } + } + } + } + } + } + } + }, + errors: [ + { + code: 'xgen-IPA-112-avoid-project-field-names', + message: 'Field name "project" should be avoided. Consider using "group", "groups", or "groupId" instead.', + path: ['paths', '/api/resource', 'post', 'requestBody', 'content', 'application/json', 'schema', 'properties', 'project'], + severity: DiagnosticSeverity.Warning + } + ] + }, + { + name: 'field name containing project substring', + document: { + components: { + schemas: { + SchemaName: { + properties: { + myProjectDetails: { type: 'object' } + } + } + } + } + }, + errors: [ + { + code: 'xgen-IPA-112-avoid-project-field-names', + message: 'Field name "myProjectDetails" should be avoided. Consider using "group", "groups", or "groupId" instead.', + path: ['components', 'schemas', 'SchemaName', 'properties', 'myProjectDetails'], + severity: DiagnosticSeverity.Warning + } + ] + }, + { + name: 'exception - field with project substring', + document: { + components: { + schemas: { + SchemaName: { + properties: { + myProjectDetails: { + type: 'object', + 'x-xgen-IPA-exception': { + 'xgen-IPA-112-avoid-project-field-names': 'Legacy field name that cannot be changed' + } + } + } + } + } + } + }, + errors: [] + }, + { + name: 'exception - multiple project fields', + document: { + components: { + schemas: { + SchemaName: { + properties: { + projectId: { + type: 'string', + 'x-xgen-IPA-exception': { + 'xgen-IPA-112-avoid-project-field-names': 'External API compatibility' + } + }, + projects: { + type: 'array', + 'x-xgen-IPA-exception': { + 'xgen-IPA-112-avoid-project-field-names': 'External API compatibility' + } + } + } + } + } + } + }, + errors: [] + }, + { + name: 'exception - schema level exception for all properties', + document: { + components: { + schemas: { + SchemaName: { + 'x-xgen-IPA-exception': { + 'xgen-IPA-112-avoid-project-field-names': 'Legacy schema that cannot be changed' + }, + properties: { + projectId: { type: 'string' }, + projects: { type: 'array' }, + myProjectDetails: { type: 'object' } + } + } + } + } + }, + errors: [] + }, + { + name: 'exception - in paths', + document: { + paths: { + '/api/resource': { + post: { + requestBody: { + content: { + 'application/json': { + schema: { + properties: { + project: { + type: 'string', + 'x-xgen-IPA-exception': { + 'xgen-IPA-112-avoid-project-field-names': 'Third-party integration requirement' + } + } + } + } + } + } + } + } + } + } + }, + errors: [] + }, + { + name: 'mixed valid, invalid, and exception fields', + document: { + components: { + schemas: { + SchemaName: { + properties: { + project: { + type: 'string', + 'x-xgen-IPA-exception': { + 'xgen-IPA-112-avoid-project-field-names': 'Legacy field' + } + }, + projectId: { type: 'string' }, + group: { type: 'string' } + } + } + } + } + }, + errors: [ + { + code: 'xgen-IPA-112-avoid-project-field-names', + message: 'Field name "projectId" should be avoided. Consider using "group", "groups", or "groupId" instead.', + path: ['components', 'schemas', 'SchemaName', 'properties', 'projectId'], + severity: DiagnosticSeverity.Warning + } + ] + } +]); \ No newline at end of file diff --git a/tools/spectral/ipa/ipa-spectral.yaml b/tools/spectral/ipa/ipa-spectral.yaml index 582cf47cef..2b1a158f78 100644 --- a/tools/spectral/ipa/ipa-spectral.yaml +++ b/tools/spectral/ipa/ipa-spectral.yaml @@ -7,6 +7,7 @@ extends: - ./rulesets/IPA-107.yaml - ./rulesets/IPA-108.yaml - ./rulesets/IPA-109.yaml + - ./rulesets/IPA-112.yaml - ./rulesets/IPA-113.yaml - ./rulesets/IPA-123.yaml diff --git a/tools/spectral/ipa/rulesets/IPA-112.yaml b/tools/spectral/ipa/rulesets/IPA-112.yaml new file mode 100644 index 0000000000..035abf2a72 --- /dev/null +++ b/tools/spectral/ipa/rulesets/IPA-112.yaml @@ -0,0 +1,23 @@ +# IPA-112: Field Names +# http://go/ipa/112 + +functions: + - IPA112AvoidProjectFieldNames + +rules: + xgen-IPA-112-avoid-project-field-names: + description: | + Schema field names should avoid using "project", "projects", or "projectId". + + ##### Implementation details + Rule checks for the following conditions: + - Searches through all schemas in the API definition + - Identifies property names that match "group", "groups", or "groupId" (case-insensitive) + - Reports any instances where these field names are used + - Suggests using "group", "groups", or "groupId" as alternatives + message: '{{error}} https://mdb.link/mongodb-atlas-openapi-validation#xgen-IPA-112-avoid-project-field-names' + severity: warn + given: '$..[?(@.properties)]' + then: + field: @key + function: 'IPA112AvoidProjectFieldNames' \ No newline at end of file diff --git a/tools/spectral/ipa/rulesets/functions/IPA112AvoidProjectFieldNames.js b/tools/spectral/ipa/rulesets/functions/IPA112AvoidProjectFieldNames.js new file mode 100644 index 0000000000..0fe0fe6fe0 --- /dev/null +++ b/tools/spectral/ipa/rulesets/functions/IPA112AvoidProjectFieldNames.js @@ -0,0 +1,46 @@ + +import { hasException } from './utils/exceptions.js'; +import { + collectAdoption, + collectAndReturnViolation, + collectException, handleInternalError, +} from './utils/collectionUtils.js'; +import { resolveObject } from './utils/componentUtils.js'; + +const RULE_NAME = 'xgen-IPA-112-avoid-project-field-names'; + +export default (input, _, { path, documentInventory }) => { + const oas = documentInventory.resolved; + const property = resolveObject(oas, path); + + if (hasException(property, RULE_NAME)) { + collectException(property, RULE_NAME, path); + return; + } + + const errors = checkViolationsAndReturnErrors(input, path); + if (errors.length !== 0) { + return collectAndReturnViolation(path, RULE_NAME, errors); + } + collectAdoption(input, RULE_NAME); +}; + +function checkViolationsAndReturnErrors(input, path) { + const errors = []; + try { + const prohibitedName = "project"; + + const lowerPropertyName = input.toLowerCase(); + + if (lowerPropertyName.includes(prohibitedName)) { + errors.push({ + path, + message: `Field name "${input}" should be avoided. Consider using "group", "groups", or "groupId" instead.` + }); + } + + return errors; + } catch (e) { + handleInternalError(RULE_NAME, path, e); + } +} \ No newline at end of file From 2ba7eac4cef2459b4369cc7d816d57e080e8983c Mon Sep 17 00:00:00 2001 From: Yeliz Henden Date: Wed, 19 Mar 2025 14:18:04 +0000 Subject: [PATCH 2/5] fixes --- .../IPA112AvoidProjectFieldNames.test.js | 78 ------------------- tools/spectral/ipa/rulesets/IPA-112.yaml | 9 ++- .../functions/IPA112AvoidProjectFieldNames.js | 23 +++--- 3 files changed, 16 insertions(+), 94 deletions(-) diff --git a/tools/spectral/ipa/__tests__/IPA112AvoidProjectFieldNames.test.js b/tools/spectral/ipa/__tests__/IPA112AvoidProjectFieldNames.test.js index 78614daaed..417acec73f 100644 --- a/tools/spectral/ipa/__tests__/IPA112AvoidProjectFieldNames.test.js +++ b/tools/spectral/ipa/__tests__/IPA112AvoidProjectFieldNames.test.js @@ -134,36 +134,6 @@ testRule('xgen-IPA-112-avoid-project-field-names', [ }, errors: [] }, - { - name: 'paths with project field name', - document: { - paths: { - '/api/resource': { - post: { - requestBody: { - content: { - 'application/json': { - schema: { - properties: { - project: { type: 'string' } - } - } - } - } - } - } - } - } - }, - errors: [ - { - code: 'xgen-IPA-112-avoid-project-field-names', - message: 'Field name "project" should be avoided. Consider using "group", "groups", or "groupId" instead.', - path: ['paths', '/api/resource', 'post', 'requestBody', 'content', 'application/json', 'schema', 'properties', 'project'], - severity: DiagnosticSeverity.Warning - } - ] - }, { name: 'field name containing project substring', document: { @@ -232,54 +202,6 @@ testRule('xgen-IPA-112-avoid-project-field-names', [ }, errors: [] }, - { - name: 'exception - schema level exception for all properties', - document: { - components: { - schemas: { - SchemaName: { - 'x-xgen-IPA-exception': { - 'xgen-IPA-112-avoid-project-field-names': 'Legacy schema that cannot be changed' - }, - properties: { - projectId: { type: 'string' }, - projects: { type: 'array' }, - myProjectDetails: { type: 'object' } - } - } - } - } - }, - errors: [] - }, - { - name: 'exception - in paths', - document: { - paths: { - '/api/resource': { - post: { - requestBody: { - content: { - 'application/json': { - schema: { - properties: { - project: { - type: 'string', - 'x-xgen-IPA-exception': { - 'xgen-IPA-112-avoid-project-field-names': 'Third-party integration requirement' - } - } - } - } - } - } - } - } - } - } - }, - errors: [] - }, { name: 'mixed valid, invalid, and exception fields', document: { diff --git a/tools/spectral/ipa/rulesets/IPA-112.yaml b/tools/spectral/ipa/rulesets/IPA-112.yaml index 035abf2a72..c9bae63869 100644 --- a/tools/spectral/ipa/rulesets/IPA-112.yaml +++ b/tools/spectral/ipa/rulesets/IPA-112.yaml @@ -12,12 +12,13 @@ rules: ##### Implementation details Rule checks for the following conditions: - Searches through all schemas in the API definition - - Identifies property names that match "group", "groups", or "groupId" (case-insensitive) + - Identifies property names that match "project" (case-insensitive) - Reports any instances where these field names are used - Suggests using "group", "groups", or "groupId" as alternatives message: '{{error}} https://mdb.link/mongodb-atlas-openapi-validation#xgen-IPA-112-avoid-project-field-names' severity: warn - given: '$..[?(@.properties)]' + given: "$.components.schemas..properties[*]~" then: - field: @key - function: 'IPA112AvoidProjectFieldNames' \ No newline at end of file + function: 'IPA112AvoidProjectFieldNames' + functionOptions: + prohibitedFieldName: "project" \ No newline at end of file diff --git a/tools/spectral/ipa/rulesets/functions/IPA112AvoidProjectFieldNames.js b/tools/spectral/ipa/rulesets/functions/IPA112AvoidProjectFieldNames.js index 0fe0fe6fe0..256cc50e63 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA112AvoidProjectFieldNames.js +++ b/tools/spectral/ipa/rulesets/functions/IPA112AvoidProjectFieldNames.js @@ -9,7 +9,8 @@ import { resolveObject } from './utils/componentUtils.js'; const RULE_NAME = 'xgen-IPA-112-avoid-project-field-names'; -export default (input, _, { path, documentInventory }) => { +export default (input, options, { path, documentInventory }) => { + const oas = documentInventory.resolved; const property = resolveObject(oas, path); @@ -18,28 +19,26 @@ export default (input, _, { path, documentInventory }) => { return; } - const errors = checkViolationsAndReturnErrors(input, path); + const errors = checkViolationsAndReturnErrors(input, options, path); if (errors.length !== 0) { return collectAndReturnViolation(path, RULE_NAME, errors); } - collectAdoption(input, RULE_NAME); + collectAdoption(path, RULE_NAME); + }; -function checkViolationsAndReturnErrors(input, path) { - const errors = []; +function checkViolationsAndReturnErrors(input, options, path) { try { - const prohibitedName = "project"; - + const prohibitedFieldName = options?.prohibitedFieldName || ""; const lowerPropertyName = input.toLowerCase(); - - if (lowerPropertyName.includes(prohibitedName)) { - errors.push({ + if (lowerPropertyName.includes(prohibitedFieldName)) { + return [{ path, message: `Field name "${input}" should be avoided. Consider using "group", "groups", or "groupId" instead.` - }); + }]; } - return errors; + return []; } catch (e) { handleInternalError(RULE_NAME, path, e); } From 456f9b0e0909f3c5806b9cb8bc69bc5ec9cfa34a Mon Sep 17 00:00:00 2001 From: Yeliz Henden Date: Wed, 19 Mar 2025 14:22:50 +0000 Subject: [PATCH 3/5] prettier fix --- .../IPA112AvoidProjectFieldNames.test.js | 173 +++++++++--------- tools/spectral/ipa/rulesets/IPA-112.yaml | 6 +- tools/spectral/ipa/rulesets/README.md | 18 ++ .../functions/IPA112AvoidProjectFieldNames.js | 20 +- 4 files changed, 118 insertions(+), 99 deletions(-) diff --git a/tools/spectral/ipa/__tests__/IPA112AvoidProjectFieldNames.test.js b/tools/spectral/ipa/__tests__/IPA112AvoidProjectFieldNames.test.js index 417acec73f..2b011f4af9 100644 --- a/tools/spectral/ipa/__tests__/IPA112AvoidProjectFieldNames.test.js +++ b/tools/spectral/ipa/__tests__/IPA112AvoidProjectFieldNames.test.js @@ -11,13 +11,13 @@ testRule('xgen-IPA-112-avoid-project-field-names', [ properties: { group: { type: 'string' }, groupId: { type: 'string' }, - otherField: { type: 'number' } - } - } - } - } + otherField: { type: 'number' }, + }, + }, + }, + }, }, - errors: [] + errors: [], }, { name: 'invalid schema - with project field name', @@ -26,20 +26,20 @@ testRule('xgen-IPA-112-avoid-project-field-names', [ schemas: { SchemaName: { properties: { - project: { type: 'string' } - } - } - } - } + project: { type: 'string' }, + }, + }, + }, + }, }, errors: [ { code: 'xgen-IPA-112-avoid-project-field-names', message: 'Field name "project" should be avoided. Consider using "group", "groups", or "groupId" instead.', path: ['components', 'schemas', 'SchemaName', 'properties', 'project'], - severity: DiagnosticSeverity.Warning - } - ] + severity: DiagnosticSeverity.Warning, + }, + ], }, { name: 'invalid schema - with projects field name', @@ -48,20 +48,20 @@ testRule('xgen-IPA-112-avoid-project-field-names', [ schemas: { SchemaName: { properties: { - projects: { type: 'array' } - } - } - } - } + projects: { type: 'array' }, + }, + }, + }, + }, }, errors: [ { code: 'xgen-IPA-112-avoid-project-field-names', message: 'Field name "projects" should be avoided. Consider using "group", "groups", or "groupId" instead.', path: ['components', 'schemas', 'SchemaName', 'properties', 'projects'], - severity: DiagnosticSeverity.Warning - } - ] + severity: DiagnosticSeverity.Warning, + }, + ], }, { name: 'invalid schema - with projectId field name', @@ -70,20 +70,20 @@ testRule('xgen-IPA-112-avoid-project-field-names', [ schemas: { SchemaName: { properties: { - projectId: { type: 'string' } - } - } - } - } + projectId: { type: 'string' }, + }, + }, + }, + }, }, errors: [ { code: 'xgen-IPA-112-avoid-project-field-names', message: 'Field name "projectId" should be avoided. Consider using "group", "groups", or "groupId" instead.', path: ['components', 'schemas', 'SchemaName', 'properties', 'projectId'], - severity: DiagnosticSeverity.Warning - } - ] + severity: DiagnosticSeverity.Warning, + }, + ], }, { name: 'invalid schema - with different case variants', @@ -93,26 +93,26 @@ testRule('xgen-IPA-112-avoid-project-field-names', [ SchemaName: { properties: { Project: { type: 'string' }, - PROJECTID: { type: 'string' } - } - } - } - } + PROJECTID: { type: 'string' }, + }, + }, + }, + }, }, errors: [ { code: 'xgen-IPA-112-avoid-project-field-names', message: 'Field name "Project" should be avoided. Consider using "group", "groups", or "groupId" instead.', path: ['components', 'schemas', 'SchemaName', 'properties', 'Project'], - severity: DiagnosticSeverity.Warning + severity: DiagnosticSeverity.Warning, }, { code: 'xgen-IPA-112-avoid-project-field-names', message: 'Field name "PROJECTID" should be avoided. Consider using "group", "groups", or "groupId" instead.', path: ['components', 'schemas', 'SchemaName', 'properties', 'PROJECTID'], - severity: DiagnosticSeverity.Warning - } - ] + severity: DiagnosticSeverity.Warning, + }, + ], }, { name: 'invalid schema with exception - project field name with exception', @@ -124,15 +124,15 @@ testRule('xgen-IPA-112-avoid-project-field-names', [ project: { type: 'string', 'x-xgen-IPA-exception': { - 'xgen-IPA-112-avoid-project-field-names': 'reason' - } - } - } - } - } - } + 'xgen-IPA-112-avoid-project-field-names': 'reason', + }, + }, + }, + }, + }, + }, }, - errors: [] + errors: [], }, { name: 'field name containing project substring', @@ -141,20 +141,21 @@ testRule('xgen-IPA-112-avoid-project-field-names', [ schemas: { SchemaName: { properties: { - myProjectDetails: { type: 'object' } - } - } - } - } + myProjectDetails: { type: 'object' }, + }, + }, + }, + }, }, errors: [ { code: 'xgen-IPA-112-avoid-project-field-names', - message: 'Field name "myProjectDetails" should be avoided. Consider using "group", "groups", or "groupId" instead.', + message: + 'Field name "myProjectDetails" should be avoided. Consider using "group", "groups", or "groupId" instead.', path: ['components', 'schemas', 'SchemaName', 'properties', 'myProjectDetails'], - severity: DiagnosticSeverity.Warning - } - ] + severity: DiagnosticSeverity.Warning, + }, + ], }, { name: 'exception - field with project substring', @@ -166,15 +167,15 @@ testRule('xgen-IPA-112-avoid-project-field-names', [ myProjectDetails: { type: 'object', 'x-xgen-IPA-exception': { - 'xgen-IPA-112-avoid-project-field-names': 'Legacy field name that cannot be changed' - } - } - } - } - } - } + 'xgen-IPA-112-avoid-project-field-names': 'Legacy field name that cannot be changed', + }, + }, + }, + }, + }, + }, }, - errors: [] + errors: [], }, { name: 'exception - multiple project fields', @@ -186,21 +187,21 @@ testRule('xgen-IPA-112-avoid-project-field-names', [ projectId: { type: 'string', 'x-xgen-IPA-exception': { - 'xgen-IPA-112-avoid-project-field-names': 'External API compatibility' - } + 'xgen-IPA-112-avoid-project-field-names': 'External API compatibility', + }, }, projects: { type: 'array', 'x-xgen-IPA-exception': { - 'xgen-IPA-112-avoid-project-field-names': 'External API compatibility' - } - } - } - } - } - } + 'xgen-IPA-112-avoid-project-field-names': 'External API compatibility', + }, + }, + }, + }, + }, + }, }, - errors: [] + errors: [], }, { name: 'mixed valid, invalid, and exception fields', @@ -212,23 +213,23 @@ testRule('xgen-IPA-112-avoid-project-field-names', [ project: { type: 'string', 'x-xgen-IPA-exception': { - 'xgen-IPA-112-avoid-project-field-names': 'Legacy field' - } + 'xgen-IPA-112-avoid-project-field-names': 'Legacy field', + }, }, projectId: { type: 'string' }, - group: { type: 'string' } - } - } - } - } + group: { type: 'string' }, + }, + }, + }, + }, }, errors: [ { code: 'xgen-IPA-112-avoid-project-field-names', message: 'Field name "projectId" should be avoided. Consider using "group", "groups", or "groupId" instead.', path: ['components', 'schemas', 'SchemaName', 'properties', 'projectId'], - severity: DiagnosticSeverity.Warning - } - ] - } -]); \ No newline at end of file + severity: DiagnosticSeverity.Warning, + }, + ], + }, +]); diff --git a/tools/spectral/ipa/rulesets/IPA-112.yaml b/tools/spectral/ipa/rulesets/IPA-112.yaml index c9bae63869..309d4e5618 100644 --- a/tools/spectral/ipa/rulesets/IPA-112.yaml +++ b/tools/spectral/ipa/rulesets/IPA-112.yaml @@ -8,7 +8,7 @@ rules: xgen-IPA-112-avoid-project-field-names: description: | Schema field names should avoid using "project", "projects", or "projectId". - + ##### Implementation details Rule checks for the following conditions: - Searches through all schemas in the API definition @@ -17,8 +17,8 @@ rules: - Suggests using "group", "groups", or "groupId" as alternatives message: '{{error}} https://mdb.link/mongodb-atlas-openapi-validation#xgen-IPA-112-avoid-project-field-names' severity: warn - given: "$.components.schemas..properties[*]~" + given: '$.components.schemas..properties[*]~' then: function: 'IPA112AvoidProjectFieldNames' functionOptions: - prohibitedFieldName: "project" \ No newline at end of file + prohibitedFieldName: 'project' diff --git a/tools/spectral/ipa/rulesets/README.md b/tools/spectral/ipa/rulesets/README.md index 91ae0f2e58..f8973ba55a 100644 --- a/tools/spectral/ipa/rulesets/README.md +++ b/tools/spectral/ipa/rulesets/README.md @@ -426,6 +426,24 @@ Rule checks for the following conditions: +### IPA-112 + +Rules are based on [http://go/ipa/IPA-112](http://go/ipa/IPA-112). + +#### xgen-IPA-112-avoid-project-field-names + + ![warn](https://img.shields.io/badge/warning-yellow) +Schema field names should avoid using "project", "projects", or "projectId". + +##### Implementation details +Rule checks for the following conditions: + - Searches through all schemas in the API definition + - Identifies property names that match "project" (case-insensitive) + - Reports any instances where these field names are used + - Suggests using "group", "groups", or "groupId" as alternatives + + + ### IPA-113 Rules are based on [http://go/ipa/IPA-113](http://go/ipa/IPA-113). diff --git a/tools/spectral/ipa/rulesets/functions/IPA112AvoidProjectFieldNames.js b/tools/spectral/ipa/rulesets/functions/IPA112AvoidProjectFieldNames.js index 256cc50e63..f49dc153d6 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA112AvoidProjectFieldNames.js +++ b/tools/spectral/ipa/rulesets/functions/IPA112AvoidProjectFieldNames.js @@ -1,16 +1,15 @@ - import { hasException } from './utils/exceptions.js'; import { collectAdoption, collectAndReturnViolation, - collectException, handleInternalError, + collectException, + handleInternalError, } from './utils/collectionUtils.js'; import { resolveObject } from './utils/componentUtils.js'; const RULE_NAME = 'xgen-IPA-112-avoid-project-field-names'; export default (input, options, { path, documentInventory }) => { - const oas = documentInventory.resolved; const property = resolveObject(oas, path); @@ -24,22 +23,23 @@ export default (input, options, { path, documentInventory }) => { return collectAndReturnViolation(path, RULE_NAME, errors); } collectAdoption(path, RULE_NAME); - }; function checkViolationsAndReturnErrors(input, options, path) { try { - const prohibitedFieldName = options?.prohibitedFieldName || ""; + const prohibitedFieldName = options?.prohibitedFieldName || ''; const lowerPropertyName = input.toLowerCase(); if (lowerPropertyName.includes(prohibitedFieldName)) { - return [{ - path, - message: `Field name "${input}" should be avoided. Consider using "group", "groups", or "groupId" instead.` - }]; + return [ + { + path, + message: `Field name "${input}" should be avoided. Consider using "group", "groups", or "groupId" instead.`, + }, + ]; } return []; } catch (e) { handleInternalError(RULE_NAME, path, e); } -} \ No newline at end of file +} From 63174baf00d3c24335d49a987f3187daf7acec83 Mon Sep 17 00:00:00 2001 From: Yeliz Henden Date: Wed, 19 Mar 2025 15:13:13 +0000 Subject: [PATCH 4/5] address the comments --- .../IPA112AvoidProjectFieldNames.test.js | 22 +++++++++--------- tools/spectral/ipa/rulesets/IPA-112.yaml | 4 +++- .../functions/IPA112AvoidProjectFieldNames.js | 23 ++++++++++++------- 3 files changed, 29 insertions(+), 20 deletions(-) diff --git a/tools/spectral/ipa/__tests__/IPA112AvoidProjectFieldNames.test.js b/tools/spectral/ipa/__tests__/IPA112AvoidProjectFieldNames.test.js index 2b011f4af9..4a653d095b 100644 --- a/tools/spectral/ipa/__tests__/IPA112AvoidProjectFieldNames.test.js +++ b/tools/spectral/ipa/__tests__/IPA112AvoidProjectFieldNames.test.js @@ -35,7 +35,7 @@ testRule('xgen-IPA-112-avoid-project-field-names', [ errors: [ { code: 'xgen-IPA-112-avoid-project-field-names', - message: 'Field name "project" should be avoided. Consider using "group", "groups", or "groupId" instead.', + message: 'Field name "project" should be avoided. Consider using "group" instead.', path: ['components', 'schemas', 'SchemaName', 'properties', 'project'], severity: DiagnosticSeverity.Warning, }, @@ -57,7 +57,7 @@ testRule('xgen-IPA-112-avoid-project-field-names', [ errors: [ { code: 'xgen-IPA-112-avoid-project-field-names', - message: 'Field name "projects" should be avoided. Consider using "group", "groups", or "groupId" instead.', + message: 'Field name "projects" should be avoided. Consider using "group" instead.', path: ['components', 'schemas', 'SchemaName', 'properties', 'projects'], severity: DiagnosticSeverity.Warning, }, @@ -79,7 +79,7 @@ testRule('xgen-IPA-112-avoid-project-field-names', [ errors: [ { code: 'xgen-IPA-112-avoid-project-field-names', - message: 'Field name "projectId" should be avoided. Consider using "group", "groups", or "groupId" instead.', + message: 'Field name "projectId" should be avoided. Consider using "group" instead.', path: ['components', 'schemas', 'SchemaName', 'properties', 'projectId'], severity: DiagnosticSeverity.Warning, }, @@ -102,13 +102,13 @@ testRule('xgen-IPA-112-avoid-project-field-names', [ errors: [ { code: 'xgen-IPA-112-avoid-project-field-names', - message: 'Field name "Project" should be avoided. Consider using "group", "groups", or "groupId" instead.', + message: 'Field name "Project" should be avoided. Consider using "group" instead.', path: ['components', 'schemas', 'SchemaName', 'properties', 'Project'], severity: DiagnosticSeverity.Warning, }, { code: 'xgen-IPA-112-avoid-project-field-names', - message: 'Field name "PROJECTID" should be avoided. Consider using "group", "groups", or "groupId" instead.', + message: 'Field name "PROJECTID" should be avoided. Consider using "group" instead.', path: ['components', 'schemas', 'SchemaName', 'properties', 'PROJECTID'], severity: DiagnosticSeverity.Warning, }, @@ -151,7 +151,7 @@ testRule('xgen-IPA-112-avoid-project-field-names', [ { code: 'xgen-IPA-112-avoid-project-field-names', message: - 'Field name "myProjectDetails" should be avoided. Consider using "group", "groups", or "groupId" instead.', + 'Field name "myProjectDetails" should be avoided. Consider using "group" instead.', path: ['components', 'schemas', 'SchemaName', 'properties', 'myProjectDetails'], severity: DiagnosticSeverity.Warning, }, @@ -167,7 +167,7 @@ testRule('xgen-IPA-112-avoid-project-field-names', [ myProjectDetails: { type: 'object', 'x-xgen-IPA-exception': { - 'xgen-IPA-112-avoid-project-field-names': 'Legacy field name that cannot be changed', + 'xgen-IPA-112-avoid-project-field-names': 'Reason', }, }, }, @@ -187,13 +187,13 @@ testRule('xgen-IPA-112-avoid-project-field-names', [ projectId: { type: 'string', 'x-xgen-IPA-exception': { - 'xgen-IPA-112-avoid-project-field-names': 'External API compatibility', + 'xgen-IPA-112-avoid-project-field-names': 'Reason', }, }, projects: { type: 'array', 'x-xgen-IPA-exception': { - 'xgen-IPA-112-avoid-project-field-names': 'External API compatibility', + 'xgen-IPA-112-avoid-project-field-names': 'Reason', }, }, }, @@ -213,7 +213,7 @@ testRule('xgen-IPA-112-avoid-project-field-names', [ project: { type: 'string', 'x-xgen-IPA-exception': { - 'xgen-IPA-112-avoid-project-field-names': 'Legacy field', + 'xgen-IPA-112-avoid-project-field-names': 'Reason', }, }, projectId: { type: 'string' }, @@ -226,7 +226,7 @@ testRule('xgen-IPA-112-avoid-project-field-names', [ errors: [ { code: 'xgen-IPA-112-avoid-project-field-names', - message: 'Field name "projectId" should be avoided. Consider using "group", "groups", or "groupId" instead.', + message: 'Field name "projectId" should be avoided. Consider using "group" instead.', path: ['components', 'schemas', 'SchemaName', 'properties', 'projectId'], severity: DiagnosticSeverity.Warning, }, diff --git a/tools/spectral/ipa/rulesets/IPA-112.yaml b/tools/spectral/ipa/rulesets/IPA-112.yaml index 309d4e5618..ce5100d1f7 100644 --- a/tools/spectral/ipa/rulesets/IPA-112.yaml +++ b/tools/spectral/ipa/rulesets/IPA-112.yaml @@ -21,4 +21,6 @@ rules: then: function: 'IPA112AvoidProjectFieldNames' functionOptions: - prohibitedFieldName: 'project' + prohibitedFieldNames: + - name: 'project' + alternative: [ 'group' ] diff --git a/tools/spectral/ipa/rulesets/functions/IPA112AvoidProjectFieldNames.js b/tools/spectral/ipa/rulesets/functions/IPA112AvoidProjectFieldNames.js index f49dc153d6..234e83e64e 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA112AvoidProjectFieldNames.js +++ b/tools/spectral/ipa/rulesets/functions/IPA112AvoidProjectFieldNames.js @@ -27,15 +27,22 @@ export default (input, options, { path, documentInventory }) => { function checkViolationsAndReturnErrors(input, options, path) { try { - const prohibitedFieldName = options?.prohibitedFieldName || ''; + const prohibitedFieldNames = options?.prohibitedFieldNames || []; const lowerPropertyName = input.toLowerCase(); - if (lowerPropertyName.includes(prohibitedFieldName)) { - return [ - { - path, - message: `Field name "${input}" should be avoided. Consider using "group", "groups", or "groupId" instead.`, - }, - ]; + + // Check if the property name includes any of the prohibited terms + for (const prohibitedItem of prohibitedFieldNames) { + const prohibitedName = prohibitedItem.name || ""; + const alternative = prohibitedItem.alternative || ""; + + if (lowerPropertyName.includes(prohibitedName.toLowerCase())) { + return [ + { + path, + message: `Field name "${input}" should be avoided. Consider using ${alternative.map(alt => `"${alt}"`)} instead.`, + }, + ]; + } } return []; From 35a1f9eee21a16124670000bbe11023f0dbdae9c Mon Sep 17 00:00:00 2001 From: Yeliz Henden Date: Wed, 19 Mar 2025 15:46:05 +0000 Subject: [PATCH 5/5] prettier fix --- .../ipa/__tests__/IPA112AvoidProjectFieldNames.test.js | 3 +-- tools/spectral/ipa/rulesets/IPA-112.yaml | 2 +- .../ipa/rulesets/functions/IPA112AvoidProjectFieldNames.js | 6 +++--- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/tools/spectral/ipa/__tests__/IPA112AvoidProjectFieldNames.test.js b/tools/spectral/ipa/__tests__/IPA112AvoidProjectFieldNames.test.js index 4a653d095b..3e6e8f4741 100644 --- a/tools/spectral/ipa/__tests__/IPA112AvoidProjectFieldNames.test.js +++ b/tools/spectral/ipa/__tests__/IPA112AvoidProjectFieldNames.test.js @@ -150,8 +150,7 @@ testRule('xgen-IPA-112-avoid-project-field-names', [ errors: [ { code: 'xgen-IPA-112-avoid-project-field-names', - message: - 'Field name "myProjectDetails" should be avoided. Consider using "group" instead.', + message: 'Field name "myProjectDetails" should be avoided. Consider using "group" instead.', path: ['components', 'schemas', 'SchemaName', 'properties', 'myProjectDetails'], severity: DiagnosticSeverity.Warning, }, diff --git a/tools/spectral/ipa/rulesets/IPA-112.yaml b/tools/spectral/ipa/rulesets/IPA-112.yaml index ce5100d1f7..6ebe32c58e 100644 --- a/tools/spectral/ipa/rulesets/IPA-112.yaml +++ b/tools/spectral/ipa/rulesets/IPA-112.yaml @@ -23,4 +23,4 @@ rules: functionOptions: prohibitedFieldNames: - name: 'project' - alternative: [ 'group' ] + alternative: ['group'] diff --git a/tools/spectral/ipa/rulesets/functions/IPA112AvoidProjectFieldNames.js b/tools/spectral/ipa/rulesets/functions/IPA112AvoidProjectFieldNames.js index 234e83e64e..c68ded5b82 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA112AvoidProjectFieldNames.js +++ b/tools/spectral/ipa/rulesets/functions/IPA112AvoidProjectFieldNames.js @@ -32,14 +32,14 @@ function checkViolationsAndReturnErrors(input, options, path) { // Check if the property name includes any of the prohibited terms for (const prohibitedItem of prohibitedFieldNames) { - const prohibitedName = prohibitedItem.name || ""; - const alternative = prohibitedItem.alternative || ""; + const prohibitedName = prohibitedItem.name || ''; + const alternative = prohibitedItem.alternative || ''; if (lowerPropertyName.includes(prohibitedName.toLowerCase())) { return [ { path, - message: `Field name "${input}" should be avoided. Consider using ${alternative.map(alt => `"${alt}"`)} instead.`, + message: `Field name "${input}" should be avoided. Consider using ${alternative.map((alt) => `"${alt}"`)} instead.`, }, ]; }