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
@@ -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[*][get,put,post,delete,options,head,patch,trace]'
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