Skip to content

Commit 857861c

Browse files
CLOUDP-306577: IPA121: Datetime
1 parent 5f83dac commit 857861c

File tree

5 files changed

+328
-0
lines changed

5 files changed

+328
-0
lines changed
Lines changed: 261 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,261 @@
1+
import testRule from './__helpers__/testRule.js';
2+
import { DiagnosticSeverity } from '@stoplight/types';
3+
4+
testRule('xgen-IPA-121-date-time-fields-mention-iso-8601', [
5+
{
6+
name: 'valid when date-time format mentions ISO 8601 in description',
7+
document: {
8+
components: {
9+
schemas: {
10+
TestSchema: {
11+
properties: {
12+
createdAt: {
13+
type: 'string',
14+
format: 'date-time',
15+
description: 'The creation timestamp in ISO 8601 format.',
16+
},
17+
updatedOn: {
18+
type: 'string',
19+
format: 'date-time',
20+
description: 'When the resource was last updated. Uses ISO 8601 datetime format.',
21+
},
22+
},
23+
},
24+
},
25+
parameters: {
26+
TestParameter: {
27+
name: 'createdAt',
28+
in: 'query',
29+
schema: {
30+
type: 'string',
31+
format: 'date-time',
32+
description: 'The creation timestamp in ISO 8601 format.',
33+
},
34+
},
35+
},
36+
},
37+
},
38+
errors: [],
39+
},
40+
{
41+
name: 'valid with non-date-time format',
42+
document: {
43+
components: {
44+
schemas: {
45+
TestSchema: {
46+
properties: {
47+
username: {
48+
type: 'string',
49+
description: 'The username for login.',
50+
},
51+
age: {
52+
type: 'integer',
53+
description: 'Age in years.',
54+
},
55+
},
56+
},
57+
},
58+
},
59+
},
60+
errors: [],
61+
},
62+
{
63+
name: 'invalid when date-time format has no description',
64+
document: {
65+
components: {
66+
schemas: {
67+
TestSchema: {
68+
properties: {
69+
createdAt: {
70+
type: 'string',
71+
format: 'date-time',
72+
},
73+
modifiedAt: {
74+
type: 'string',
75+
format: 'date-time',
76+
description: 'The modification timestamp.',
77+
},
78+
},
79+
},
80+
},
81+
parameters: {
82+
TestParameter: {
83+
name: 'createdAt',
84+
in: 'query',
85+
schema: {
86+
type: 'string',
87+
format: 'date-time',
88+
description: 'The creation timestamp',
89+
},
90+
},
91+
},
92+
},
93+
paths: {
94+
'/resources': {
95+
post: {
96+
requestBody: {
97+
content: {
98+
'application/json': {
99+
schema: {
100+
properties: {
101+
$ref: '#/components/schemas/TestSchema',
102+
},
103+
},
104+
},
105+
},
106+
},
107+
},
108+
},
109+
},
110+
},
111+
errors: [
112+
{
113+
code: 'xgen-IPA-121-date-time-fields-mention-iso-8601',
114+
message:
115+
'API producers must use ISO 8601 date-time format in UTC for all timestamps. Fields must note ISO 8601 in their description.',
116+
path: ['components', 'schemas', 'TestSchema', 'properties', 'createdAt'],
117+
severity: DiagnosticSeverity.Warning,
118+
},
119+
{
120+
code: 'xgen-IPA-121-date-time-fields-mention-iso-8601',
121+
message:
122+
'API producers must use ISO 8601 date-time format in UTC for all timestamps. Fields must note ISO 8601 in their description.',
123+
path: ['components', 'schemas', 'TestSchema', 'properties', 'modifiedAt'],
124+
severity: DiagnosticSeverity.Warning,
125+
},
126+
{
127+
code: 'xgen-IPA-121-date-time-fields-mention-iso-8601',
128+
message:
129+
'API producers must use ISO 8601 date-time format in UTC for all timestamps. Fields must note ISO 8601 in their description.',
130+
path: ['components', 'parameters', 'TestParameter', 'schema'],
131+
severity: DiagnosticSeverity.Warning,
132+
},
133+
],
134+
},
135+
{
136+
name: 'exception',
137+
document: {
138+
components: {
139+
schemas: {
140+
TestSchema: {
141+
properties: {
142+
createdAt: {
143+
type: 'string',
144+
format: 'date-time',
145+
description: 'The creation timestamp.',
146+
'x-xgen-IPA-exception': {
147+
'xgen-IPA-121-date-time-fields-mention-iso-8601': 'Legacy field format',
148+
},
149+
},
150+
},
151+
},
152+
},
153+
parameters: {
154+
TestParameter: {
155+
name: 'createdAt',
156+
in: 'query',
157+
schema: {
158+
type: 'string',
159+
format: 'date-time',
160+
description: 'The creation timestamp',
161+
'x-xgen-IPA-exception': {
162+
'xgen-IPA-121-date-time-fields-mention-iso-8601': 'Legacy field format',
163+
},
164+
},
165+
},
166+
},
167+
},
168+
},
169+
errors: [],
170+
},
171+
{
172+
name: 'test with parameters in path operation',
173+
document: {
174+
paths: {
175+
'/resources': {
176+
get: {
177+
parameters: [
178+
{
179+
name: 'since',
180+
in: 'query',
181+
schema: {
182+
type: 'string',
183+
format: 'date-time',
184+
description: 'Filter resources created since this ISO 8601 timestamp',
185+
},
186+
},
187+
{
188+
name: 'until',
189+
in: 'query',
190+
schema: {
191+
type: 'string',
192+
format: 'date-time',
193+
description: 'Filter resources created until this timestamp', // Missing ISO 8601
194+
},
195+
},
196+
],
197+
},
198+
},
199+
},
200+
},
201+
errors: [
202+
{
203+
code: 'xgen-IPA-121-date-time-fields-mention-iso-8601',
204+
message:
205+
'API producers must use ISO 8601 date-time format in UTC for all timestamps. Fields must note ISO 8601 in their description.',
206+
path: ['paths', '/resources', 'get', 'parameters', '1', 'schema'],
207+
severity: DiagnosticSeverity.Warning,
208+
},
209+
],
210+
},
211+
{
212+
name: 'test with requestBody properties',
213+
document: {
214+
paths: {
215+
'/resources': {
216+
post: {
217+
requestBody: {
218+
content: {
219+
'application/json': {
220+
schema: {
221+
properties: {
222+
scheduledFor: {
223+
type: 'string',
224+
format: 'date-time',
225+
description: 'When to schedule the job using ISO 8601 format.',
226+
},
227+
expiresAt: {
228+
type: 'string',
229+
format: 'date-time',
230+
description: 'When this resource expires.', // Missing ISO 8601
231+
},
232+
},
233+
},
234+
},
235+
},
236+
},
237+
},
238+
},
239+
},
240+
},
241+
errors: [
242+
{
243+
code: 'xgen-IPA-121-date-time-fields-mention-iso-8601',
244+
message:
245+
'API producers must use ISO 8601 date-time format in UTC for all timestamps. Fields must note ISO 8601 in their description.',
246+
path: [
247+
'paths',
248+
'/resources',
249+
'post',
250+
'requestBody',
251+
'content',
252+
'application/json',
253+
'schema',
254+
'properties',
255+
'expiresAt',
256+
],
257+
severity: DiagnosticSeverity.Warning,
258+
},
259+
],
260+
},
261+
]);

tools/spectral/ipa/ipa-spectral.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ extends:
1414
- ./rulesets/IPA-117.yaml
1515
- ./rulesets/IPA-118.yaml
1616
- ./rulesets/IPA-119.yaml
17+
- ./rulesets/IPA-121.yaml
1718
- ./rulesets/IPA-123.yaml
1819
- ./rulesets/IPA-125.yaml
1920

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# IPA-121: Datetime
2+
# http://go/ipa/121
3+
4+
functions:
5+
- IPA121DateTimeFieldsMentionISO8601
6+
7+
rules:
8+
xgen-IPA-121-date-time-fields-mention-iso-8601:
9+
description: |
10+
Fields with format="date-time" should mention ISO 8601 in their description.
11+
message: '{{error}} https://mdb.link/mongodb-atlas-openapi-validation#xgen-IPA-121-date-time-fields-mention-iso-8601'
12+
given:
13+
- $.paths..parameters[*].schema
14+
- $.components.parameters.*.schema
15+
- $.components.schemas..properties[*]
16+
- $.paths..requestBody..schema..properties[*]
17+
- $.paths..responses..schema..properties[*]
18+
severity: warn
19+
then:
20+
function: IPA121DateTimeFieldsMentionISO8601

tools/spectral/ipa/rulesets/README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -802,6 +802,17 @@ All cloudProviderEnumValues should be listed in the enum array.
802802

803803

804804

805+
### IPA-121
806+
807+
Rules are based on [http://go/ipa/IPA-121](http://go/ipa/IPA-121).
808+
809+
#### xgen-IPA-121-date-time-fields-mention-iso-8601
810+
811+
![warn](https://img.shields.io/badge/warning-yellow)
812+
Fields with format="date-time" should mention ISO 8601 in their description.
813+
814+
815+
805816
### IPA-123
806817

807818
Rules are based on [http://go/ipa/IPA-123](http://go/ipa/IPA-123).
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { hasException } from './utils/exceptions.js';
2+
import { collectAdoption, collectAndReturnViolation, collectException } from './utils/collectionUtils.js';
3+
import { resolveObject } from './utils/componentUtils.js';
4+
5+
const RULE_NAME = 'xgen-IPA-121-date-time-fields-mention-iso-8601';
6+
const ERROR_MESSAGE =
7+
'API producers must use ISO 8601 date-time format in UTC for all timestamps. Fields must note ISO 8601 in their description.';
8+
9+
export default (input, options, { path, documentInventory }) => {
10+
const oas = documentInventory.unresolved;
11+
const propertyObject = resolveObject(oas, path);
12+
13+
// Not to duplicate the check for referenced schemas
14+
if (!propertyObject) {
15+
return;
16+
}
17+
18+
if (hasException(input, RULE_NAME)) {
19+
collectException(input, RULE_NAME, path);
20+
return;
21+
}
22+
23+
if (input.format === 'date-time') {
24+
if (!input.description?.includes('ISO 8601')) {
25+
return collectAndReturnViolation(path, RULE_NAME, [
26+
{
27+
path,
28+
message: ERROR_MESSAGE,
29+
},
30+
]);
31+
}
32+
33+
collectAdoption(path, RULE_NAME);
34+
}
35+
};

0 commit comments

Comments
 (0)