Skip to content
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
import testRule from './__helpers__/testRule';
import { DiagnosticSeverity } from '@stoplight/types';

testRule('xgen-IPA-132-operation-must-be-a-read-only-resource', [
{
name: 'valid read-only Operations endpoints',
document: {
paths: {
'/api/atlas/v2/resourceName/operations': {
get: {},
},
'/api/atlas/v2/resourceName/operations/{operationId}': {
get: {},
},
'/api/atlas/v2/resourceName/{pathParam}/operations': {
get: {},
},
'/api/atlas/v2/resourceName/{pathParam}/operations/{operationId}': {
get: {},
},
},
},
errors: [],
},
{
name: 'paths that are not Operations endpoints are ignored',
document: {
paths: {
'/api/atlas/v2/resourceName': {
post: {},
},
'/api/atlas/v2/resourceName/{pathParam}': {
put: {},
patch: {},
delete: {},
},
},
},
errors: [],
},
{
name: 'invalid Operations endpoints with mutating methods',
document: {
paths: {
'/api/atlas/v2/resourceName/operations': {
get: {},
post: {},
},
'/api/atlas/v2/resourceName/operations/{operationId}': {
Comment thread
yelizhenden-mdb marked this conversation as resolved.
get: {},
put: {},
patch: {},
delete: {},
},
},
},
errors: [
{
code: 'xgen-IPA-132-operation-must-be-a-read-only-resource',
message: 'Operations endpoints are read-only and do not allow the post method.',
path: ['paths', '/api/atlas/v2/resourceName/operations', 'post'],
severity: DiagnosticSeverity.Error,
},
{
code: 'xgen-IPA-132-operation-must-be-a-read-only-resource',
message: 'Operations endpoints are read-only and do not allow the put method.',
path: ['paths', '/api/atlas/v2/resourceName/operations/{operationId}', 'put'],
severity: DiagnosticSeverity.Error,
},
{
code: 'xgen-IPA-132-operation-must-be-a-read-only-resource',
message: 'Operations endpoints are read-only and do not allow the patch method.',
path: ['paths', '/api/atlas/v2/resourceName/operations/{operationId}', 'patch'],
severity: DiagnosticSeverity.Error,
},
{
code: 'xgen-IPA-132-operation-must-be-a-read-only-resource',
message: 'Operations endpoints are read-only and do not allow the delete method.',
path: ['paths', '/api/atlas/v2/resourceName/operations/{operationId}', 'delete'],
severity: DiagnosticSeverity.Error,
},
],
},
{
name: 'invalid custom method attached to an Operations endpoint',
document: {
paths: {
'/api/atlas/v2/resourceName/operations/{operationId}:cancel': {
post: {},
},
},
},
errors: [
{
code: 'xgen-IPA-132-operation-must-be-a-read-only-resource',
message: 'Operations endpoints are read-only and do not allow the post method.',
path: ['paths', '/api/atlas/v2/resourceName/operations/{operationId}:cancel', 'post'],
severity: DiagnosticSeverity.Error,
},
],
},
{
name: 'invalid Operations endpoints with exceptions',
document: {
paths: {
'/api/atlas/v2/resourceName/operations': {
get: {},
post: {},
'x-xgen-IPA-exception': {
'xgen-IPA-132-operation-must-be-a-read-only-resource': 'reason',
},
},
},
},
errors: [],
},
{
name: 'read-only Operations endpoints do not need an exception',
document: {
paths: {
'/api/atlas/v2/resourceName/operations': {
get: {},
'x-xgen-IPA-exception': {
'xgen-IPA-132-operation-must-be-a-read-only-resource': 'reason',
},
},
},
},
errors: [
{
code: 'xgen-IPA-132-operation-must-be-a-read-only-resource',
message: 'This component adopts the rule and does not need an exception. Please remove the exception.',
path: [
'paths',
'/api/atlas/v2/resourceName/operations',
'x-xgen-IPA-exception',
'xgen-IPA-132-operation-must-be-a-read-only-resource',
],
severity: DiagnosticSeverity.Error,
},
],
},
]);
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import testRule from './__helpers__/testRule';
import { DiagnosticSeverity } from '@stoplight/types';

const ERROR_MESSAGE =
'Operations endpoints must be leaf resources. An `operations` segment may only be followed by a single operation identifier path parameter.';

testRule('xgen-IPA-132-operations-endpoint-must-be-a-leaf-resource', [
{
name: 'valid leaf Operations endpoints',
document: {
paths: {
'/api/atlas/v2/resourceName/operations': {},
'/api/atlas/v2/resourceName/operations/{operationId}': {},
'/api/atlas/v2/resourceName/{pathParam}/operations': {},
'/api/atlas/v2/resourceName/{pathParam}/operations/{operationId}': {},
// Root-level Operations endpoints are leaves, their nesting is covered by
// xgen-IPA-132-operations-endpoint-must-not-be-global
'/api/atlas/v2/operations': {},
// Custom method suffixes are ignored, their methods are covered by
// xgen-IPA-132-operation-must-be-a-read-only-resource
'/api/atlas/v2/resourceName/operations/{operationId}:cancel': {},
},
},
errors: [],
},
{
name: 'paths without an operations segment are ignored',
document: {
paths: {
'/api/atlas/v2/resourceName': {},
'/api/atlas/v2/resourceName/{pathParam}': {},
'/api/atlas/v2/resourceName/{pathParam}/childResource': {},
},
},
errors: [],
},
{
name: 'invalid paths nested below Operations endpoints',
document: {
paths: {
'/api/atlas/v2/resourceName/operations/subresource': {},
'/api/atlas/v2/resourceName/operations/{operationId}/subresource': {},
'/api/atlas/v2/resourceName/operations/{operationId}/{anotherId}': {},
},
},
errors: [
{
code: 'xgen-IPA-132-operations-endpoint-must-be-a-leaf-resource',
message: ERROR_MESSAGE,
path: ['paths', '/api/atlas/v2/resourceName/operations/subresource'],
severity: DiagnosticSeverity.Error,
},
{
code: 'xgen-IPA-132-operations-endpoint-must-be-a-leaf-resource',
message: ERROR_MESSAGE,
path: ['paths', '/api/atlas/v2/resourceName/operations/{operationId}/subresource'],
severity: DiagnosticSeverity.Error,
},
{
code: 'xgen-IPA-132-operations-endpoint-must-be-a-leaf-resource',
message: ERROR_MESSAGE,
path: ['paths', '/api/atlas/v2/resourceName/operations/{operationId}/{anotherId}'],
severity: DiagnosticSeverity.Error,
},
],
},
{
name: 'invalid paths with exceptions',
document: {
paths: {
'/api/atlas/v2/resourceName/operations/{operationId}/subresource': {
'x-xgen-IPA-exception': {
'xgen-IPA-132-operations-endpoint-must-be-a-leaf-resource': 'reason',
},
},
},
},
errors: [],
},
{
name: 'leaf Operations endpoints do not need an exception',
document: {
paths: {
'/api/atlas/v2/resourceName/operations/{operationId}': {
'x-xgen-IPA-exception': {
'xgen-IPA-132-operations-endpoint-must-be-a-leaf-resource': 'reason',
},
},
},
},
errors: [
{
code: 'xgen-IPA-132-operations-endpoint-must-be-a-leaf-resource',
message: 'This component adopts the rule and does not need an exception. Please remove the exception.',
path: [
'paths',
'/api/atlas/v2/resourceName/operations/{operationId}',
'x-xgen-IPA-exception',
'xgen-IPA-132-operations-endpoint-must-be-a-leaf-resource',
],
severity: DiagnosticSeverity.Error,
},
],
},
]);
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import testRule from './__helpers__/testRule';
import { DiagnosticSeverity } from '@stoplight/types';

const ERROR_MESSAGE =
'Operations endpoints must not be standalone, global endpoints with no parent resource in their path.';

testRule('xgen-IPA-132-operations-endpoint-must-not-be-global', [
{
name: 'valid nested Operations endpoints',
document: {
paths: {
// Collection-scoped Operations endpoints, nested directly under the parent collection
'/api/atlas/v2/resourceName/operations': {},
'/api/atlas/v2/resourceName/operations/{operationId}': {},
'/api/atlas/v2/resourceName1/{pathParam}/resourceName2/operations': {},
'/api/atlas/v2/resourceName1/{pathParam}/resourceName2/operations/{operationId}': {},
'/api/atlas/v2/unauth/resourceName/operations': {},
'/api/atlas/v2/unauth/resourceName/operations/{operationId}': {},
// Instance-scoped Operations endpoints, nested under the parent resource instance
'/api/atlas/v2/resourceName/{pathParam}/operations': {},
'/api/atlas/v2/resourceName/{pathParam}/operations/{operationId}': {},
},
},
errors: [],
},
{
name: 'paths that are not Operations endpoints are ignored',
document: {
paths: {
'/api/atlas/v2/resourceName': {},
'/api/atlas/v2/resourceName/{pathParam}': {},
'/api/atlas/v2/resourceName/{pathParam}:customMethod': {},
// Not a well-formed Operations endpoint, covered by xgen-IPA-132-operations-endpoint-must-be-a-leaf-resource
'/api/atlas/v2/resourceName/operations/subresource': {},
},
},
errors: [],
},
{
name: 'invalid root-level Operations endpoints',
document: {
paths: {
'/api/atlas/v2/operations': {},
'/api/atlas/v2/operations/{operationId}': {},
'/api/atlas/v2/unauth/operations': {},
},
},
errors: [
{
code: 'xgen-IPA-132-operations-endpoint-must-not-be-global',
message: ERROR_MESSAGE,
path: ['paths', '/api/atlas/v2/operations'],
severity: DiagnosticSeverity.Error,
},
{
code: 'xgen-IPA-132-operations-endpoint-must-not-be-global',
message: ERROR_MESSAGE,
path: ['paths', '/api/atlas/v2/operations/{operationId}'],
severity: DiagnosticSeverity.Error,
},
{
code: 'xgen-IPA-132-operations-endpoint-must-not-be-global',
message: ERROR_MESSAGE,
path: ['paths', '/api/atlas/v2/unauth/operations'],
severity: DiagnosticSeverity.Error,
},
],
},
{
name: 'invalid root-level Operations endpoints with exceptions',
document: {
paths: {
'/api/atlas/v2/operations': {
'x-xgen-IPA-exception': {
'xgen-IPA-132-operations-endpoint-must-not-be-global': 'reason',
},
},
},
},
errors: [],
},
{
name: 'nested Operations endpoints do not need an exception',
Comment thread
yelizhenden-mdb marked this conversation as resolved.
Outdated
document: {
paths: {
'/api/atlas/v2/resourceName/operations': {
'x-xgen-IPA-exception': {
'xgen-IPA-132-operations-endpoint-must-not-be-global': 'reason',
},
},
},
},
errors: [
{
code: 'xgen-IPA-132-operations-endpoint-must-not-be-global',
message: 'This component adopts the rule and does not need an exception. Please remove the exception.',
path: [
'paths',
'/api/atlas/v2/resourceName/operations',
'x-xgen-IPA-exception',
'xgen-IPA-132-operations-endpoint-must-not-be-global',
],
severity: DiagnosticSeverity.Error,
},
],
},
]);
Loading
Loading