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,218 @@
import testRule from './__helpers__/testRule';
import { DiagnosticSeverity } from '@stoplight/types';

const componentSchemas = {
schemas: {
ValidSchemaResponse: {
type: 'object',
properties: {
id: {
type: 'string',
readOnly: true,
},
name: {
type: 'string',
},
},
},
InvalidSchemaResponse: {
type: 'object',
properties: {
id: {
type: 'string',
readOnly: true,
},
name: {
type: 'string',
writeOnly: true,
},
},
},
},
};

testRule('xgen-IPA-104-get-method-response-has-no-input-fields', [
{
name: 'valid get responses',
document: {
paths: {
'/resource/{id}': {
get: {
responses: {
200: {
content: {
'application/vnd.atlas.2024-08-05+json': {
schema: {
$ref: '#/components/schemas/ValidSchemaResponse',
},
},
},
},
},
},
},
'/resource/{id}/singleton': {
get: {
responses: {
200: {
content: {
'application/vnd.atlas.2024-08-05+json': {
schema: {
type: 'object',
properties: {
id: {
type: 'string',
readOnly: true,
},
name: {
type: 'string',
},
},
},
},
},
},
},
},
},
},
components: componentSchemas,
},
errors: [],
},
{
name: 'invalid GET with body',
document: {
paths: {
'/resource/{id}': {
get: {
responses: {
200: {
content: {
'application/vnd.atlas.2024-08-05+json': {
schema: {
$ref: '#/components/schemas/InvalidSchemaResponse',
},
},
},
},
},
},
},
'/resource/{id}/singleton': {
get: {
responses: {
200: {
content: {
'application/vnd.atlas.2024-08-05+json': {
schema: {
type: 'object',
properties: {
id: {
type: 'string',
readOnly: true,
},
name: {
type: 'string',
writeOnly: true,
},
},
},
},
},
},
},
},
},
},
components: componentSchemas,
},
errors: [
{
code: 'xgen-IPA-104-get-method-response-has-no-input-fields',
message:
'The get method response object must not include output fields (writeOnly properties). http://go/ipa/104',
path: [
'paths',
'/resource/{id}',
'get',
'responses',
'200',
'content',
'application/vnd.atlas.2024-08-05+json',
],
severity: DiagnosticSeverity.Warning,
},
{
code: 'xgen-IPA-104-get-method-response-has-no-input-fields',
message:
'The get method response object must not include output fields (writeOnly properties). http://go/ipa/104',
path: [
'paths',
'/resource/{id}/singleton',
'get',
'responses',
'200',
'content',
'application/vnd.atlas.2024-08-05+json',
],
severity: DiagnosticSeverity.Warning,
},
],
},
{
name: 'invalid with exception',
document: {
paths: {
'/resource/{id}': {
get: {
responses: {
200: {
content: {
'application/vnd.atlas.2024-08-05+json': {
'x-xgen-IPA-exception': {
'xgen-IPA-104-get-method-response-has-no-input-fields': 'reason',
},
schema: {
$ref: '#/components/schemas/InvalidSchemaResponse',
},
},
},
},
},
},
},
'/resource/{id}/singleton': {
get: {
responses: {
200: {
content: {
'application/vnd.atlas.2024-08-05+json': {
'x-xgen-IPA-exception': {
'xgen-IPA-104-get-method-response-has-no-input-fields': 'reason',
},
schema: {
type: 'object',
properties: {
id: {
type: 'string',
readOnly: true,
},
name: {
type: 'string',
writeOnly: true,
},
},
},
},
},
},
},
},
},
},
components: componentSchemas,
},
errors: [],
},
]);
9 changes: 9 additions & 0 deletions tools/spectral/ipa/rulesets/IPA-104.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ functions:
- getMethodReturnsSingleResource
- getMethodReturnsResponseSuffixedObject
- getResponseCodeShouldBe200OK
- getMethodResponseHasNoInputFields

rules:
xgen-IPA-104-resource-has-GET:
Expand Down Expand Up @@ -38,3 +39,11 @@ rules:
then:
field: '@key'
function: 'getMethodReturnsResponseSuffixedObject'
xgen-IPA-104-get-method-response-has-no-input-fields:
description: 'The get method response object must not include fields available only on creation or update, ie output fields. http://go/ipa/104'
message: '{{error}} http://go/ipa/104'
severity: warn
given: '$.paths[*].get.responses[*].content'
then:
field: '@key'
function: 'getMethodResponseHasNoInputFields'
13 changes: 7 additions & 6 deletions tools/spectral/ipa/rulesets/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,13 @@ For rule definitions, see [IPA-102.yaml](https://github.com/mongodb/openapi/blob

For rule definitions, see [IPA-104.yaml](https://github.com/mongodb/openapi/blob/main/tools/spectral/ipa/rulesets/IPA-104.yaml).

| Rule Name | Description | Severity |
| -------------------------------------------------------- | ------------------------------------------------------------------------------------------ | -------- |
| xgen-IPA-104-resource-has-GET | APIs must provide a Get method for resources. http://go/ipa/104 | warn |
| xgen-IPA-104-get-method-returns-single-resource | The purpose of the Get method is to return data from a single resource. http://go/ipa/104 | warn |
| xgen-IPA-104-get-method-response-code-is-200 | The Get method must return a 200 OK response. http://go/ipa/104 | warn |
| xgen-IPA-104-get-method-returns-response-suffixed-object | The Get method of a resource should return a "Response" suffixed object. http://go/ipa/104 | warn |
| Rule Name | Description | Severity |
| -------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | -------- |
| xgen-IPA-104-resource-has-GET | APIs must provide a Get method for resources. http://go/ipa/104 | warn |
| xgen-IPA-104-get-method-returns-single-resource | The purpose of the Get method is to return data from a single resource. http://go/ipa/104 | warn |
| xgen-IPA-104-get-method-response-code-is-200 | The Get method must return a 200 OK response. http://go/ipa/104 | warn |
| xgen-IPA-104-get-method-returns-response-suffixed-object | The Get method of a resource should return a "Response" suffixed object. http://go/ipa/104 | warn |
| xgen-IPA-104-get-method-response-has-no-input-fields | The get method response object must not include fields available only on creation or update, ie output fields. http://go/ipa/104 | warn |

### IPA-106

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { hasException } from './utils/exceptions.js';
import { collectAdoption, collectAndReturnViolation, collectException } from './utils/collectionUtils.js';
import {
getResourcePathItems,
isResourceCollectionIdentifier,
isSingleResourceIdentifier,
isSingletonResource,
} from './utils/resourceEvaluation.js';
import { resolveObject } from './utils/componentUtils.js';

const RULE_NAME = 'xgen-IPA-104-get-method-response-has-no-input-fields';
const ERROR_MESSAGE = 'The get method response object must not include output fields (writeOnly properties).';

export default (input, _, { path, documentInventory }) => {
const resourcePath = path[1];
const responseCode = path[4];
const oas = documentInventory.resolved;
const resourcePaths = getResourcePathItems(resourcePath, oas.paths);
const contentPerMediaType = resolveObject(oas, path);

if (
!contentPerMediaType.schema ||
!responseCode.startsWith('2') ||
!input.endsWith('json') ||
(!isSingleResourceIdentifier(resourcePath) &&
!(isResourceCollectionIdentifier(resourcePath) && isSingletonResource(resourcePaths)))
) {
return;
}

if (hasException(contentPerMediaType, RULE_NAME)) {
collectException(contentPerMediaType, RULE_NAME, path);
return;
}

const errors = checkViolationsAndReturnErrors(contentPerMediaType, path);

if (errors.length !== 0) {
return collectAndReturnViolation(path, RULE_NAME, errors);
}
return collectAdoption(path, RULE_NAME);
};

function checkViolationsAndReturnErrors(contentPerMediaType, path) {
const schema = contentPerMediaType.schema;
const properties = schema.properties;
if (properties) {
for (const [value] of Object.entries(properties)) {
if (properties[value].writeOnly) {
return [{ path, message: ERROR_MESSAGE }];
}
}
}
return [];
}
Loading