Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -254,4 +254,85 @@ testRule('xgen-IPA-102-collection-identifier-camelCase', [
},
],
},
{
name: 'child paths inherit parent exceptions',
document: {
paths: {
'/resource_groups': {
'x-xgen-IPA-exception': {
'xgen-IPA-102-collection-identifier-camelCase': 'Legacy API path that cannot be changed',
},
},
'/resource_groups/{id}': {},
'/resource_groups/{id}/User-Profiles': {},
'/resource_groups/{id}/User-Profiles/{profileId}': {},
},
},
errors: [],
},
{
name: 'child paths have exceptions along with parent exceptions',
document: {
paths: {
'/resource_groups': {
'x-xgen-IPA-exception': {
'xgen-IPA-102-collection-identifier-camelCase': 'Legacy API path that cannot be changed',
},
},
'/resource_groups/{id}': {
'x-xgen-IPA-exception': {
'xgen-IPA-102-collection-identifier-camelCase': 'Legacy API path that cannot be changed',
},
},
'/resource_groups/{id}/User-Profiles': {
'x-xgen-IPA-exception': {
'xgen-IPA-102-collection-identifier-camelCase': 'Legacy API path that cannot be changed',
},
},
'/resource_groups/{id}/User-Profiles/{profileId}': {
'x-xgen-IPA-exception': {
'xgen-IPA-102-collection-identifier-camelCase': 'Legacy API path that cannot be changed',
},
},
},
},
errors: [
{
code: 'xgen-IPA-102-collection-identifier-camelCase',
message:
'This component adopts the rule and does not need an exception. Please remove the exception. https://mdb.link/mongodb-atlas-openapi-validation#xgen-IPA-102-collection-identifier-camelCase',
path: [
'paths',
'/resource_groups/{id}',
'x-xgen-IPA-exception',
'xgen-IPA-102-collection-identifier-camelCase',
],
severity: DiagnosticSeverity.Error,
},
{
code: 'xgen-IPA-102-collection-identifier-camelCase',
message:
'This component adopts the rule and does not need an exception. Please remove the exception. https://mdb.link/mongodb-atlas-openapi-validation#xgen-IPA-102-collection-identifier-camelCase',
path: [
'paths',
'/resource_groups/{id}/User-Profiles',
'x-xgen-IPA-exception',
'xgen-IPA-102-collection-identifier-camelCase',
],
severity: DiagnosticSeverity.Error,
},
{
code: 'xgen-IPA-102-collection-identifier-camelCase',
message:
'This component adopts the rule and does not need an exception. Please remove the exception. https://mdb.link/mongodb-atlas-openapi-validation#xgen-IPA-102-collection-identifier-camelCase',
path: [
'paths',
'/resource_groups/{id}/User-Profiles/{profileId}',
'x-xgen-IPA-exception',
'xgen-IPA-102-collection-identifier-camelCase',
],
severity: DiagnosticSeverity.Error,
},
],
},
]);
Original file line number Diff line number Diff line change
Expand Up @@ -89,4 +89,80 @@ testRule('xgen-IPA-102-collection-identifier-pattern', [
},
errors: [],
},
{
name: 'child paths inherit parent exceptions',
document: {
paths: {
'/resource-groups': {
'x-xgen-IPA-exception': {
'xgen-IPA-102-collection-identifier-pattern': 'Legacy API path that cannot be changed',
},
},
'/resource-groups/{id}': {},
'/resource-groups/{id}/sub_resources': {},
'/resource-groups/{id}/sub_resources/{subId}': {},
},
},
errors: [],
},
{
name: 'child paths have exceptions along with parent exceptions',
document: {
paths: {
'/resource-groups': {
'x-xgen-IPA-exception': {
'xgen-IPA-102-collection-identifier-pattern': 'Legacy API path that cannot be changed',
},
},
'/resource-groups/{id}': {
'x-xgen-IPA-exception': {
'xgen-IPA-102-collection-identifier-pattern': 'Legacy API path that cannot be changed',
},
},
'/resource-groups/{id}/sub_resources': {
'x-xgen-IPA-exception': {
'xgen-IPA-102-collection-identifier-pattern': 'Legacy API path that cannot be changed',
},
},
'/resource-groups/{id}/sub_resources/{subId}': {
'x-xgen-IPA-exception': {
'xgen-IPA-102-collection-identifier-pattern': 'Legacy API path that cannot be changed',
},
},
},
},
errors: [
{
code: 'xgen-IPA-102-collection-identifier-pattern',
message:
'This component adopts the rule and does not need an exception. Please remove the exception. https://mdb.link/mongodb-atlas-openapi-validation#xgen-IPA-102-collection-identifier-pattern',
path: ['paths', '/resource-groups/{id}', 'x-xgen-IPA-exception', 'xgen-IPA-102-collection-identifier-pattern'],
severity: DiagnosticSeverity.Error,
},
{
code: 'xgen-IPA-102-collection-identifier-pattern',
message:
'This component adopts the rule and does not need an exception. Please remove the exception. https://mdb.link/mongodb-atlas-openapi-validation#xgen-IPA-102-collection-identifier-pattern',
path: [
'paths',
'/resource-groups/{id}/sub_resources',
'x-xgen-IPA-exception',
'xgen-IPA-102-collection-identifier-pattern',
],
severity: DiagnosticSeverity.Error,
},
{
code: 'xgen-IPA-102-collection-identifier-pattern',
message:
'This component adopts the rule and does not need an exception. Please remove the exception. https://mdb.link/mongodb-atlas-openapi-validation#xgen-IPA-102-collection-identifier-pattern',
path: [
'paths',
'/resource-groups/{id}/sub_resources/{subId}',
'x-xgen-IPA-exception',
'xgen-IPA-102-collection-identifier-pattern',
],
severity: DiagnosticSeverity.Error,
},
],
},
]);
Original file line number Diff line number Diff line change
Expand Up @@ -152,4 +152,67 @@ testRule('xgen-IPA-102-path-alternate-resource-name-path-param', [
},
errors: [],
},
{
name: 'child paths inherit parent exceptions',
document: {
paths: {
'/api/atlas/v2/resourceName1/resourceName2': {
'x-xgen-IPA-exception': {
'xgen-IPA-102-path-alternate-resource-name-path-param': 'parent exception reason',
},
},
'/api/atlas/v2/resourceName1/resourceName2/child': {},
'/api/atlas/v2/resourceName1/resourceName2/child/{id}': {},
},
},
errors: [],
},
{
name: 'child paths have exceptions along with parent exceptions',
document: {
paths: {
'/api/atlas/v2/resourceName1/resourceName2': {
'x-xgen-IPA-exception': {
'xgen-IPA-102-path-alternate-resource-name-path-param': 'parent exception reason',
},
},
'/api/atlas/v2/resourceName1/resourceName2/child': {
'x-xgen-IPA-exception': {
'xgen-IPA-102-path-alternate-resource-name-path-param': 'child exception reason',
},
},
'/api/atlas/v2/resourceName1/resourceName2/child/{id}': {
'x-xgen-IPA-exception': {
'xgen-IPA-102-path-alternate-resource-name-path-param': 'child exception reason',
},
},
},
},
errors: [
{
code: 'xgen-IPA-102-path-alternate-resource-name-path-param',
message:
'This component adopts the rule and does not need an exception. Please remove the exception. https://mdb.link/mongodb-atlas-openapi-validation#xgen-IPA-102-path-alternate-resource-name-path-param',
path: [
'paths',
'/api/atlas/v2/resourceName1/resourceName2/child',
'x-xgen-IPA-exception',
'xgen-IPA-102-path-alternate-resource-name-path-param',
],
severity: DiagnosticSeverity.Error,
},
{
code: 'xgen-IPA-102-path-alternate-resource-name-path-param',
message:
'This component adopts the rule and does not need an exception. Please remove the exception. https://mdb.link/mongodb-atlas-openapi-validation#xgen-IPA-102-path-alternate-resource-name-path-param',
path: [
'paths',
'/api/atlas/v2/resourceName1/resourceName2/child/{id}',
'x-xgen-IPA-exception',
'xgen-IPA-102-path-alternate-resource-name-path-param',
],
severity: DiagnosticSeverity.Error,
},
],
},
]);
2 changes: 0 additions & 2 deletions tools/spectral/ipa/__tests__/utils/collectionUtils.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,6 @@ describe('tools/spectral/ipa/rulesets/functions/utils/collectionUtils.js', () =>
expect(result[0].message).toEqual(
'This component adopts the rule and does not need an exception. Please remove the exception.'
);
expect(collector.add).toHaveBeenCalledTimes(1);
expect(collector.add).toHaveBeenCalledWith(TEST_ENTRY_TYPE.VIOLATION, testPath, testRuleName);
});
});

Expand Down
39 changes: 38 additions & 1 deletion tools/spectral/ipa/ipa-spectral.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ overrides:
- '**#/paths/~1rest~1unauth~1version' # external reference, to be covered by CLOUDP-309694
rules:
xgen-IPA-114-error-responses-refer-to-api-error: 'off'
- files:
- files: # To be removed in CLOUDP-338425
- '**#/paths/~1api~1atlas~1v2~1groups~1%7BgroupId%7D~1clusters~1%7BclusterName%7D~1%7BclusterView%7D~1%7BdatabaseName%7D~1%7BcollectionName%7D~1collStats~1measurements' # reference to support future investigation - CLOUDP-310775
- '**#/paths/~1api~1atlas~1v2~1groups~1%7BgroupId%7D~1processes~1%7BprocessId%7D~1%7BdatabaseName%7D~1%7BcollectionName%7D~1collStats~1measurements' # reference to support future investigation - CLOUDP-310775
- '**#/components/schemas/HostMetricValue' # reference to support future investigation - CLOUDP-310775
Expand Down Expand Up @@ -177,3 +177,40 @@ overrides:
- '**#/components/schemas/NewRelic'
rules:
xgen-IPA-117-description-must-not-use-html: 'off'
- files: # To be removed in CLOUDP-338425
- '**#/paths/~1api~1atlas~1v2~1groups~1%7BgroupId%7D~1backup~1exportBuckets~1%7BexportBucketId%7D'
- '**#/paths/~1api~1atlas~1v2~1groups~1%7BgroupId%7D~1clusters~1%7BclusterName%7D~1backup~1exports~1%7BexportId%7D'
- '**#/paths/~1api~1atlas~1v2~1groups~1%7BgroupId%7D~1clusters~1%7BclusterName%7D~1backup~1restoreJobs~1%7BrestoreJobId%7D'
- '**#/paths/~1api~1atlas~1v2~1groups~1%7BgroupId%7D~1clusters~1%7BclusterName%7D~1backup~1snapshots~1%7BsnapshotId%7D'
- '**#/paths/~1api~1atlas~1v2~1groups~1%7BgroupId%7D~1clusters~1%7BclusterName%7D~1backup~1snapshots~1shardedCluster~1%7BsnapshotId%7D'
- '**#/paths/~1api~1atlas~1v2~1groups~1%7BgroupId%7D~1clusters~1%7BclusterName%7D~1backup~1snapshots~1shardedClusters'
- '**#/paths/~1api~1atlas~1v2~1groups~1%7BgroupId%7D~1clusters~1%7BclusterName%7D~1backup~1tenant~1restores~1%7BrestoreId%7D'
- '**#/paths/~1api~1atlas~1v2~1groups~1%7BgroupId%7D~1clusters~1%7BclusterName%7D~1backup~1tenant~1snapshots~1%7BsnapshotId%7D'
- '**#/paths/~1api~1atlas~1v2~1groups~1%7BgroupId%7D~1clusters~1%7BclusterName%7D~1fts~1indexes~1%7BdatabaseName%7D~1%7BcollectionName%7D'
- '**#/paths/~1api~1atlas~1v2~1groups~1%7BgroupId%7D~1clusters~1%7BclusterName%7D~1fts~1indexes~1%7BindexId%7D'
- '**#/paths/~1api~1atlas~1v2~1groups~1%7BgroupId%7D~1clusters~1%7BclusterName%7D~1search~1indexes~1%7BdatabaseName%7D~1%7BcollectionName%7D'
- '**#/paths/~1api~1atlas~1v2~1groups~1%7BgroupId%7D~1clusters~1%7BclusterName%7D~1search~1indexes~1%7BdatabaseName%7D~1%7BcollectionName%7D~1%7BindexName%7D'
- '**#/paths/~1api~1atlas~1v2~1groups~1%7BgroupId%7D~1clusters~1%7BclusterName%7D~1search~1indexes~1%7BindexId%7D'
- '**#/paths/~1api~1atlas~1v2~1groups~1%7BgroupId%7D~1customDBRoles~1roles~1%7BroleName%7D'
- '**#/paths/~1api~1atlas~1v2~1groups~1%7BgroupId%7D~1flexClusters~1%7Bname%7D~1backup~1restoreJobs~1%7BrestoreJobId%7D'
- '**#/paths/~1api~1atlas~1v2~1groups~1%7BgroupId%7D~1flexClusters~1%7Bname%7D~1backup~1snapshots~1%7BsnapshotId%7D'
- '**#/paths/~1api~1atlas~1v2~1groups~1%7BgroupId%7D~1hosts~1%7BprocessId%7D~1fts~1metrics~1measurements'
- '**#/paths/~1api~1atlas~1v2~1groups~1%7BgroupId%7D~1privateEndpoint~1serverless~1instance~1%7BinstanceName%7D~1endpoint~1%7BendpointId%7D'
- '**#/paths/~1api~1atlas~1v2~1groups~1%7BgroupId%7D~1privateNetworkSettings~1endpointIds~1%7BendpointId%7D'
- '**#/paths/~1api~1atlas~1v2~1groups~1%7BgroupId%7D~1serverless~1%7BclusterName%7D~1backup~1restoreJobs~1%7BrestoreJobId%7D'
- '**#/paths/~1api~1atlas~1v2~1groups~1%7BgroupId%7D~1serverless~1%7BclusterName%7D~1backup~1snapshots~1%7BsnapshotId%7D'
- '**#/paths/~1api~1atlas~1v2~1groups~1%7BgroupId%7D~1streams~1privateLinkConnections~1%7BconnectionId%7D'
- '**#/paths/~1api~1atlas~1v2~1groups~1%7BgroupId%7D~1streams~1vpcPeeringConnections~1%7Bid%7D'
- '**#/paths/~1api~1atlas~1v2~1groups~1%7BgroupId%7D~1streams~1vpcPeeringConnections~1%7Bid%7D%3Aaccept'
- '**#/paths/~1api~1atlas~1v2~1groups~1%7BgroupId%7D~1streams~1vpcPeeringConnections~1%7Bid%7D%3Areject'
- '**#/paths/~1api~1atlas~1v2~1groups~1%7BgroupId%7D~1userSecurity~1ldap~1verify~1%7BrequestId%7D'
- '**#/paths/~1api~1atlas~1v2~1orgs~1%7BorgId%7D~1billing~1costExplorer~1usage~1%7Btoken%7D'
- '**#/paths/~1api~1atlas~1v2~1groups~1%7BgroupId%7D~1hosts~1%7BprocessId%7D~1fts~1metrics~1indexes~1%7BdatabaseName%7D~1%7BcollectionName%7D~1measurements'
- '**#/paths/~1api~1atlas~1v2~1groups~1%7BgroupId%7D~1hosts~1%7BprocessId%7D~1fts~1metrics~1indexes~1%7BdatabaseName%7D~1%7BcollectionName%7D~1%7BindexName%7D~1measurements'
- '**#/paths/~1api~1atlas~1v2~1groups~1%7BgroupId%7D~1liveMigrations~1validate~1%7BvalidationId%7D'
rules:
xgen-IPA-102-path-alternate-resource-name-path-param: 'off'
- files: # To be removed in CLOUDP-338425
- '**#/paths/~1api~1atlas~1v2~1groups~1%7BgroupId%7D~1customDBRoles~1roles~1%7BroleName%7D'
rules:
xgen-IPA-102-collection-identifier-camelCase: 'off'
4 changes: 4 additions & 0 deletions tools/spectral/ipa/rulesets/IPA-102.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ rules:
argument to the rule
- Paths with `x-xgen-IPA-exception` for this rule are excluded from validation
- Double slashes (//) are not allowed in paths
- If any parent path has an exception for this rule, the exception will be inherited.

message: '{{error}} https://mdb.link/mongodb-atlas-openapi-validation#xgen-IPA-102-collection-identifier-camelCase'
severity: error
Expand All @@ -38,6 +39,8 @@ rules:
- Even-indexed path segments should be resource names (not path parameters)
- Odd-indexed path segments should be path parameters
- Paths with `x-xgen-IPA-exception` for this rule are excluded from validation
- If any parent path has an exception for this rule, the exception will be inherited.

message: '{{error}} https://mdb.link/mongodb-atlas-openapi-validation#xgen-IPA-102-path-alternate-resource-name-path-param'
severity: error
given: '$.paths'
Expand All @@ -57,6 +60,7 @@ rules:
- Custom methods (segments containing colons) are excluded from validation
- Paths with `x-xgen-IPA-exception` for this rule are excluded from validation
- Each non-parameter path segment must start with a lowercase letter followed by any combination of ASCII letters and numbers
- If any parent path has an exception for this rule, the exception will be inherited.

message: '{{error}} https://mdb.link/mongodb-atlas-openapi-validation#xgen-IPA-102-collection-identifier-pattern'
severity: error
Expand Down
3 changes: 3 additions & 0 deletions tools/spectral/ipa/rulesets/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ Collection identifiers must be in camelCase.
argument to the rule
- Paths with `x-xgen-IPA-exception` for this rule are excluded from validation
- Double slashes (//) are not allowed in paths
- If any parent path has an exception for this rule, the exception will be inherited.

#### xgen-IPA-102-path-alternate-resource-name-path-param

Expand All @@ -57,6 +58,7 @@ Rule checks for the following conditions:
- Even-indexed path segments should be resource names (not path parameters)
- Odd-indexed path segments should be path parameters
- Paths with `x-xgen-IPA-exception` for this rule are excluded from validation
- If any parent path has an exception for this rule, the exception will be inherited.

#### xgen-IPA-102-collection-identifier-pattern

Expand All @@ -71,6 +73,7 @@ Rule checks for the following conditions:
- Custom methods (segments containing colons) are excluded from validation
- Paths with `x-xgen-IPA-exception` for this rule are excluded from validation
- Each non-parameter path segment must start with a lowercase letter followed by any combination of ASCII letters and numbers
- If any parent path has an exception for this rule, the exception will be inherited.



Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import { evaluateAndCollectAdoptionStatus, handleInternalError } from './utils/collectionUtils.js';
import { isPathParam } from './utils/componentUtils.js';
import { casing } from '@stoplight/spectral-functions';
import { findExceptionInPathHierarchy } from './utils/exceptions.js';

const RULE_NAME = 'xgen-IPA-102-collection-identifier-camelCase';
const ERROR_MESSAGE = 'Collection identifiers must be in camelCase.';

/**
* Checks if collection identifiers in paths follow camelCase convention
*
* The function checks the entire path hierarchy. If any parent path has an exception, the exception will be inherited.
*
* @param {object} input - The path key from the OpenAPI spec
* @param {object} options - Rule configuration options
* @param {object} context - The context object containing the path and documentInventory
Expand All @@ -21,7 +24,14 @@ export default (input, options, { path, documentInventory }) => {

const violations = checkViolations(pathKey, path, ignoredValues);

return evaluateAndCollectAdoptionStatus(violations, RULE_NAME, oas.paths[input], path);
// Check for exceptions in path hierarchy
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you update the rule descriptions for these to clarify the exception behaviour?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rule documentation updated 👍

const result = findExceptionInPathHierarchy(oas, pathKey, RULE_NAME, path);
if (result?.error) {
return result.error;
}
const objectToCheckForException = result ? oas.paths[result.parentPath] : oas.paths[input];

return evaluateAndCollectAdoptionStatus(violations, RULE_NAME, objectToCheckForException, path);
};

function checkViolations(pathKey, path, ignoredValues = []) {
Expand Down
Loading
Loading