Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
@@ -0,0 +1,161 @@
import testRule from './__helpers__/testRule';
import { DiagnosticSeverity } from '@stoplight/types';

testRule('xgen-IPA-114-authenticated-endpoints-have-auth-errors', [
{
name: 'valid authenticated endpoint with 401 and 403 responses',
document: {
paths: {
'/resources': {
get: {
responses: {
200: { description: 'Success' },
401: { description: 'Unauthorized' },
403: { description: 'Forbidden' },
},
},
},
},
},
errors: [],
},
{
name: 'invalid authenticated endpoint missing both auth error responses',
document: {
paths: {
'/resources': {
get: {
responses: {
200: { description: 'Success' },
},
},
},
},
},
errors: [
{
code: 'xgen-IPA-114-authenticated-endpoints-have-auth-errors',
message: 'Authenticated endpoint must define a 401 response.',
path: ['paths', '/resources', 'get'],
severity: DiagnosticSeverity.Warning,
},
{
code: 'xgen-IPA-114-authenticated-endpoints-have-auth-errors',
message: 'Authenticated endpoint must define a 403 response.',
path: ['paths', '/resources', 'get'],
severity: DiagnosticSeverity.Warning,
},
],
},
{
name: 'invalid authenticated endpoint missing 401 response',
document: {
paths: {
'/resources': {
get: {
responses: {
200: { description: 'Success' },
403: { description: 'Forbidden' },
},
},
},
},
},
errors: [
{
code: 'xgen-IPA-114-authenticated-endpoints-have-auth-errors',
message: 'Authenticated endpoint must define a 401 response.',
path: ['paths', '/resources', 'get'],
severity: DiagnosticSeverity.Warning,
},
],
},
{
name: 'invalid authenticated endpoint missing 403 response',
document: {
paths: {
'/resources': {
get: {
responses: {
200: { description: 'Success' },
401: { description: 'Unauthorized' },
},
},
},
},
},
errors: [
{
code: 'xgen-IPA-114-authenticated-endpoints-have-auth-errors',
message: 'Authenticated endpoint must define a 403 response.',
path: ['paths', '/resources', 'get'],
severity: DiagnosticSeverity.Warning,
},
],
},
{
name: 'unauthenticated endpoint with empty security array',
document: {
paths: {
'/resources': {
get: {
security: [],
responses: {
200: { description: 'Success' },
},
},
},
},
},
errors: [],
},
{
name: 'unauthenticated endpoint with /unauth in path',
document: {
paths: {
'/unauth/resources': {
get: {
responses: {
200: { description: 'Success' },
},
},
},
},
},
errors: [],
},
{
name: 'unauthenticated endpoint with both /unauth and empty security',
document: {
paths: {
'/unauth/resources': {
get: {
security: [],
responses: {
200: { description: 'Success' },
},
},
},
},
},
errors: [],
},
{
name: 'edge case with no responses object',
document: {
paths: {
'/resources': {
get: {},
},
},
},
errors: [
{
code: 'xgen-IPA-114-authenticated-endpoints-have-auth-errors',
message: 'Authenticated endpoint must define a 401 and 403 responses.',
path: ['paths', '/resources', 'get'],
severity: DiagnosticSeverity.Warning,
},
],
},
]);
13 changes: 13 additions & 0 deletions tools/spectral/ipa/rulesets/IPA-114.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
functions:
- IPA114ErrorResponsesReferToApiError
- IPA114ApiErrorHasBadRequestDetail
- IPA114AuthenticatedEndpointsHaveAuthErrors

rules:
xgen-IPA-114-error-responses-refer-to-api-error:
Expand Down Expand Up @@ -32,3 +33,15 @@ rules:
given: $.components.schemas.ApiError
then:
function: 'IPA114ApiErrorHasBadRequestDetail'
xgen-IPA-114-authenticated-endpoints-have-auth-errors:
description: |
Authenticated endpoints must define 401 and 403 responses.

##### Implementation details
This rule checks that all authenticated endpoints (those without explicit 'security: []'
and not containing '/unauth' in the path) include 401 and 403 responses.
message: '{{error}} https://mdb.link/mongodb-atlas-openapi-validation#xgen-IPA-114-authenticated-endpoints-have-auth-errors'
severity: warn
given: '$.paths[*][*]'
Copy link
Collaborator

@lovisaberggren lovisaberggren Mar 31, 2025

Choose a reason for hiding this comment

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

Suggested change
given: '$.paths[*][*]'
given: '$.paths[*][put,patch,get,delete...]'

I think you need to add the methods explicitly here (similarly to a few of the IPA 117 rules), otherwise it will validate extensions as well. I can see in the results:

warning  xgen-IPA-114-authenticated-endpoints-have-auth-errors  Authenticated endpoint must define a 401 and 403 responses. https://mdb.link/mongodb-atlas-openapi-validation#xgen-IPA-114-authenticated-endpoints-have-auth-errors                                                                                                        paths./api/atlas/v2/alertConfigs/matchers/fieldNames.x-xgen-IPA-exception

For: paths./api/atlas/v2/alertConfigs/matchers/fieldNames.x-xgen-IPA-exception

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Nice catch, addressed 👍 507 violations 🥲

Copy link
Collaborator

Choose a reason for hiding this comment

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

:hidethepainharold:

then:
function: 'IPA114AuthenticatedEndpointsHaveAuthErrors'
9 changes: 9 additions & 0 deletions tools/spectral/ipa/rulesets/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -627,6 +627,15 @@ Rule checks that:
- Each field must include description and field properties
- This rule does not allow exceptions

#### xgen-IPA-114-authenticated-endpoints-have-auth-errors

![warn](https://img.shields.io/badge/warning-yellow)
Authenticated endpoints must define 401 and 403 responses.

##### Implementation details
This rule checks that all authenticated endpoints (those without explicit 'security: []'
and not containing '/unauth' in the path) include 401 and 403 responses.



### IPA-117
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { hasException } from './utils/exceptions.js';
import {
collectAdoption,
collectAndReturnViolation,
collectException,
handleInternalError,
} from './utils/collectionUtils.js';

const RULE_NAME = 'xgen-IPA-114-authenticated-endpoints-have-auth-errors';

/**
* Validates that authenticated endpoints have 401 and 403 responses defined
*
* Endpoints are considered authenticated unless:
* 1. They have explicit "security: []" set
* 2. They contain "/unauth" in the path
*
* @param {object} input - The operation object to check
* @param {object} _ - Rule options (unused)
* @param {object} context - The context object containing path and document information
*/
export default (input, _, { path }) => {
// Path components: [paths, pathName, methodName, ...]
const pathName = path[1];

// Skip validation if the path contains 'unauth'
if (pathName.includes('/unauth/')) {
return;
}

// Skip validation if security is explicitly set to empty array
if (Array.isArray(input.security) && input.security.length === 0) {
return;
}

// Check for exception at operation level
if (hasException(input, RULE_NAME)) {
collectException(input, RULE_NAME, path);
return;
}

const errors = checkViolationsAndReturnErrors(input.responses, path);
if (errors.length > 0) {
return collectAndReturnViolation(path, RULE_NAME, errors);
}

collectAdoption(path, RULE_NAME);
};

function checkViolationsAndReturnErrors(responses, path) {
try {
const errors = [];

if (!responses) {
return [
{
path,
message: `Authenticated endpoint must define a 401 and 403 responses.`,
},
];
}
// Check for 401 Unauthorized response
if (!responses['401']) {
errors.push({
path,
message: `Authenticated endpoint must define a 401 response.`,
});
}

// Check for 403 Forbidden response
if (!responses['403']) {
errors.push({
path,
message: `Authenticated endpoint must define a 403 response.`,
});
}

return errors;
} catch (e) {
handleInternalError(RULE_NAME, path, e);
}
}
Loading