api-quality-spectral-ruleset 1.4.0 → 1.4.1-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/apq-spectral.yaml +34 -37
- package/functions/apq-binary-format-check.js +4 -0
- package/functions/apq-forbidden-characters.js +5 -3
- package/functions/apq-numeric-parameter-integrity.js +31 -0
- package/functions/apq-path-depth.js +5 -2
- package/functions/apq-path-param-query-conflict.js +14 -18
- package/functions/apq-schema-format.js +6 -0
- package/functions/apq-security-required-response.js +20 -9
- package/functions/apq-valid-openapi-version.js +1 -1
- package/package.json +5 -5
package/apq-spectral.yaml
CHANGED
|
@@ -29,6 +29,7 @@ functions:
|
|
|
29
29
|
- apq-paged-response-check
|
|
30
30
|
- apq-status-endpoint-check
|
|
31
31
|
- apq-validate-structure
|
|
32
|
+
- apq-numeric-parameter-integrity
|
|
32
33
|
extends:
|
|
33
34
|
- spectral:asyncapi
|
|
34
35
|
- spectral:oas
|
|
@@ -65,7 +66,7 @@ rules:
|
|
|
65
66
|
message: "Scope must define a 'description' attribute."
|
|
66
67
|
apiq:OAR004:
|
|
67
68
|
description: "A role with forbidden characters may cause problems in some applications."
|
|
68
|
-
message: "
|
|
69
|
+
message: "{{error}}"
|
|
69
70
|
documentationUrl: "https://github.com/apiaddicts/apquality-spectral/blob/main/docs/resources/OAR004.md"
|
|
70
71
|
severity: "error"
|
|
71
72
|
given: "$.x-wso2-security.apim.x-wso2-scopes[*].roles"
|
|
@@ -166,7 +167,7 @@ rules:
|
|
|
166
167
|
function: truthy
|
|
167
168
|
apiq:OAR014:
|
|
168
169
|
description: "Resources depth level should be below the non-suggested range."
|
|
169
|
-
message: "
|
|
170
|
+
message: "{{error}}"
|
|
170
171
|
documentationUrl: "https://github.com/apiaddicts/apquality-spectral/blob/main/docs/resources/OAR014.md"
|
|
171
172
|
severity: warn
|
|
172
173
|
given: "$.paths.*~"
|
|
@@ -179,13 +180,13 @@ rules:
|
|
|
179
180
|
- me
|
|
180
181
|
apiq:OAR015:
|
|
181
182
|
description: "Resources depth level should be smaller than 5."
|
|
182
|
-
message: "
|
|
183
|
+
message: "{{error}}"
|
|
183
184
|
severity: error
|
|
184
185
|
given: "$.paths.*~"
|
|
185
186
|
then:
|
|
186
187
|
function: apq-path-depth
|
|
187
188
|
functionOptions:
|
|
188
|
-
|
|
189
|
+
max-level-allowed: 5
|
|
189
190
|
ignoreSegments:
|
|
190
191
|
- me
|
|
191
192
|
apiq:OAR016:
|
|
@@ -193,7 +194,7 @@ rules:
|
|
|
193
194
|
message: "OAR016: Numeric types must use a valid format for their type."
|
|
194
195
|
documentationUrl: "https://github.com/apiaddicts/apquality-spectral/blob/main/docs/resources/OAR016.md"
|
|
195
196
|
severity: error
|
|
196
|
-
given: "$..[?(@.type=='number' || @.type=='integer')]"
|
|
197
|
+
given: "$..[?(@ && (@.type=='number' || @.type=='integer'))]"
|
|
197
198
|
then:
|
|
198
199
|
function: schema
|
|
199
200
|
functionOptions:
|
|
@@ -492,11 +493,13 @@ rules:
|
|
|
492
493
|
paging-schema: '{"type":"object","properties":{"numPages":{"type":"integer"},"total":{"type":"integer"},"start":{"type":"integer"},"limit":{"type":"integer"},"links":{"type":"object","properties":{"next":{"type":"object","properties":{"href":{"type":"string"}}},"previous":{"type":"object","properties":{"href":{"type":"string"}}},"last":{"type":"object","properties":{"href":{"type":"string"}}},"self":{"type":"object","properties":{"href":{"type":"string"}}},"first":{"type":"object","properties":{"href":{"type":"string"}}}},"required":["self","previous","next"]}},"required":["start","limit","links"],"pagingPropertyName":"paging"}'
|
|
493
494
|
apiq:OAR035:
|
|
494
495
|
description: "Response code 401 must be defined for operations with security schemes defined."
|
|
495
|
-
message: "
|
|
496
|
+
message: "{{error}}"
|
|
496
497
|
severity: "error"
|
|
497
498
|
given: "$.paths[*][*]"
|
|
498
499
|
then:
|
|
499
500
|
function: apq-security-required-response
|
|
501
|
+
functionOptions:
|
|
502
|
+
expected-codes: "401"
|
|
500
503
|
apiq:OAR036:
|
|
501
504
|
description: "Cookie use is forbidden as a session mechanism."
|
|
502
505
|
message: "OAR036: Cookie use is forbidden as a session mechanism."
|
|
@@ -514,7 +517,7 @@ rules:
|
|
|
514
517
|
message: "OAR037: String schemas must specify a valid format (date, date-time, password, byte, binary, email, uuid, uri, hostname, ipv4, ipv6, HEX, HEX(16), json, xml, or base64), or a valid pattern when no format is defined."
|
|
515
518
|
severity: error
|
|
516
519
|
resolved: false
|
|
517
|
-
given: "$..[?(@.type=='string')]"
|
|
520
|
+
given: "$..[?(@ && @.type=='string')]"
|
|
518
521
|
then:
|
|
519
522
|
function: apq-schema-format
|
|
520
523
|
apiq:OAR038:
|
|
@@ -566,13 +569,13 @@ rules:
|
|
|
566
569
|
;patch:^/[^/{}]+/(\{[^/{}]+\}|\bme\b)/[^/{}]+/(\{[^/{}]+\}|\bme\b)/[^/{}]+/(\{[^/{}]+\}|\bme\b)$:200,404,400,415,500,503
|
|
567
570
|
apiq:OAR040:
|
|
568
571
|
description: "A scope name non-compliant with the standard may cause problems at application level."
|
|
569
|
-
message: "
|
|
572
|
+
message: "{{error}}"
|
|
570
573
|
severity: "error"
|
|
571
574
|
given: "$.x-wso2-security.apim.x-wso2-scopes[*].name"
|
|
572
575
|
then:
|
|
573
|
-
function:
|
|
576
|
+
function: apq-forbidden-characters
|
|
574
577
|
functionOptions:
|
|
575
|
-
|
|
578
|
+
pattern: "^[a-zA-Z]{4,}_(SC|sc)_[a-zA-Z0-9]{1,}$"
|
|
576
579
|
apiq:OAR041:
|
|
577
580
|
description: Available scopes must be defined at the end of the document, at the root level, inside `x-wso2-security`.
|
|
578
581
|
message: "OAR041:Scopes must be defined in `x-wso2-security` at the end of the document, before the paths."
|
|
@@ -618,7 +621,7 @@ rules:
|
|
|
618
621
|
then:
|
|
619
622
|
function: pattern
|
|
620
623
|
functionOptions:
|
|
621
|
-
match:
|
|
624
|
+
match: '^(\*|[a-zA-Z0-9][a-zA-Z0-9.!#$&^_+\-]*)/(\*|[a-zA-Z0-9][a-zA-Z0-9.!#$&^_+\-]*)(?:[ \t]*;[ \t]*[a-zA-Z0-9!#$%&''*+\-.^_`|~]+=(?:[a-zA-Z0-9!#$%&''*+\-.^_`|~]+|"(?:[^"\\]|\\.)*"))*$'
|
|
622
625
|
apiq:OAR045:
|
|
623
626
|
description: "Response schema is required for responses with status codes 201 and others that return content."
|
|
624
627
|
message: "OAR045: Response schema is required for status code '{{property}}'."
|
|
@@ -715,7 +718,7 @@ rules:
|
|
|
715
718
|
message: "OAR052: Numeric types requires a format"
|
|
716
719
|
documentationUrl: "https://github.com/apiaddicts/apquality-spectral/blob/main/docs/resources/OAR052.md"
|
|
717
720
|
severity: warn
|
|
718
|
-
given: "$..[?(@.type == 'integer' || @.type == 'number')]"
|
|
721
|
+
given: "$..[?(@ && (@.type == 'integer' || @.type == 'number'))]"
|
|
719
722
|
then:
|
|
720
723
|
field: format
|
|
721
724
|
function: truthy
|
|
@@ -853,8 +856,8 @@ rules:
|
|
|
853
856
|
functionOptions:
|
|
854
857
|
type: pascal
|
|
855
858
|
apiq:OAR069:
|
|
856
|
-
description: "
|
|
857
|
-
message: "OAR069:
|
|
859
|
+
description: "Any param in PATH or QUERY should have a Bad Request (400) response."
|
|
860
|
+
message: "OAR069: Any param in PATH or QUERY should have a Bad Request (400) response."
|
|
858
861
|
severity: "error"
|
|
859
862
|
given: "$.paths"
|
|
860
863
|
then:
|
|
@@ -900,26 +903,20 @@ rules:
|
|
|
900
903
|
field: "429"
|
|
901
904
|
function: truthy
|
|
902
905
|
apiq:OAR074:
|
|
903
|
-
description: "Numeric parameters should
|
|
904
|
-
message: "OAR074: Numeric parameter
|
|
906
|
+
description: "Numeric parameters should define minimum and maximum, or a format restriction."
|
|
907
|
+
message: "OAR074: Numeric parameter should define both 'minimum' and 'maximum', or a 'format' restriction."
|
|
905
908
|
severity: error
|
|
906
|
-
|
|
909
|
+
resolved: false
|
|
910
|
+
given:
|
|
911
|
+
- "$..[?(@ && @.in && @.schema && (@.schema.type == 'integer' || @.schema.type == 'number'))].schema"
|
|
912
|
+
- "$..[?(@ && @.in && (@.type == 'integer' || @.type == 'number'))]"
|
|
907
913
|
then:
|
|
908
|
-
function:
|
|
909
|
-
functionOptions:
|
|
910
|
-
schema:
|
|
911
|
-
type: object
|
|
912
|
-
properties:
|
|
913
|
-
schema:
|
|
914
|
-
anyOf:
|
|
915
|
-
- required: ["minimum"]
|
|
916
|
-
- required: ["maximum"]
|
|
917
|
-
- required: ["format"]
|
|
914
|
+
function: apq-numeric-parameter-integrity
|
|
918
915
|
apiq:OAR075:
|
|
919
916
|
description: "String parameters should have minLength, maxLength, pattern (regular expression), or enum restriction."
|
|
920
917
|
message: "OAR075: String parameters should have minLength, maxLength, pattern, or enum restriction."
|
|
921
918
|
severity: error
|
|
922
|
-
given: "$.paths[*][get,post,put,patch,delete].parameters[?(@.schema.type == 'string' && @.in == 'path')]"
|
|
919
|
+
given: "$.paths[*][get,post,put,patch,delete].parameters[?(@ && @.schema && @.schema.type == 'string' && @.in == 'path')]"
|
|
923
920
|
then:
|
|
924
921
|
function: schema
|
|
925
922
|
functionOptions:
|
|
@@ -937,7 +934,7 @@ rules:
|
|
|
937
934
|
message: "OAR076: Schema should use well-defined type and format."
|
|
938
935
|
documentationUrl: "https://github.com/apiaddicts/apquality-spectral/blob/main/docs/resources/OAR076.md"
|
|
939
936
|
severity: error
|
|
940
|
-
given: "$..[?(@.type=='number' || @.type=='integer')]"
|
|
937
|
+
given: "$..[?(@ && (@.type=='number' || @.type=='integer'))]"
|
|
941
938
|
then:
|
|
942
939
|
function: schema
|
|
943
940
|
functionOptions:
|
|
@@ -1009,7 +1006,7 @@ rules:
|
|
|
1009
1006
|
description: "The string properties 'product', 'line', and 'price' must define a byte or binary format."
|
|
1010
1007
|
message: "{{error}}"
|
|
1011
1008
|
severity: error
|
|
1012
|
-
given: "$..[?(@.properties)]"
|
|
1009
|
+
given: "$..[?(@ && @.properties)]"
|
|
1013
1010
|
then:
|
|
1014
1011
|
function: apq-binary-format-check
|
|
1015
1012
|
functionOptions:
|
|
@@ -1035,7 +1032,7 @@ rules:
|
|
|
1035
1032
|
functionOptions:
|
|
1036
1033
|
notMatch: "^password$"
|
|
1037
1034
|
apiq:OAR085:
|
|
1038
|
-
description: "The OpenAPI version must be one of: 2.0, 3.0.0, 3.0.1, 3.0.2, 3.0.3, 3.1.0."
|
|
1035
|
+
description: "The OpenAPI version must be one of: 2.0, 3.0.0, 3.0.1, 3.0.2, 3.0.3, 3.1.0, 3.2.0."
|
|
1039
1036
|
message: "{{error}}"
|
|
1040
1037
|
severity: warn
|
|
1041
1038
|
given:
|
|
@@ -1044,7 +1041,7 @@ rules:
|
|
|
1044
1041
|
then:
|
|
1045
1042
|
function: apq-valid-openapi-version
|
|
1046
1043
|
functionOptions:
|
|
1047
|
-
valid-versions: "2.0,3.0.0,3.0.1,3.0.2,3.0.3,3.1.0"
|
|
1044
|
+
valid-versions: "2.0,3.0.0,3.0.1,3.0.2,3.0.3,3.1.0,3.2.0"
|
|
1048
1045
|
apiq:OAR086:
|
|
1049
1046
|
description: "Descriptions must begin with a capital letter, end with a period, and not be empty."
|
|
1050
1047
|
message: "OAR086: Descriptions must begin with a capital letter, end with a period, and not be empty."
|
|
@@ -1124,13 +1121,13 @@ rules:
|
|
|
1124
1121
|
function: falsy
|
|
1125
1122
|
apiq:OAR096:
|
|
1126
1123
|
description: "Response code 403 must be defined for operations with security schemes defined."
|
|
1127
|
-
message: "
|
|
1124
|
+
message: "{{error}}"
|
|
1128
1125
|
severity: "error"
|
|
1129
|
-
given: "$.paths[*][*]
|
|
1126
|
+
given: "$.paths[*][*]"
|
|
1130
1127
|
then:
|
|
1131
|
-
function:
|
|
1132
|
-
|
|
1133
|
-
|
|
1128
|
+
function: apq-security-required-response
|
|
1129
|
+
functionOptions:
|
|
1130
|
+
expected-codes: "403"
|
|
1134
1131
|
apiq:OAR097:
|
|
1135
1132
|
description: "The base path must contain at least two parts."
|
|
1136
1133
|
message: "OAR097: Path has too few parts."
|
|
@@ -4,14 +4,16 @@
|
|
|
4
4
|
* @param {import('@stoplight/spectral-core').RulesetFunctionContext} context
|
|
5
5
|
*/
|
|
6
6
|
module.exports = (targetVal, options, context) => {
|
|
7
|
-
const
|
|
7
|
+
const patternStr = (options && options.pattern) || '^[a-zA-Z0-9_\\-., ]+$';
|
|
8
|
+
const pattern = new RegExp(patternStr);
|
|
8
9
|
const errors = [];
|
|
9
10
|
const basePath = context.path || [];
|
|
11
|
+
const buildMessage = (value) => `Value '${value}' does not match the required pattern: ${patternStr}.`;
|
|
10
12
|
|
|
11
13
|
if (typeof targetVal === 'string') {
|
|
12
14
|
if (!pattern.test(targetVal)) {
|
|
13
15
|
errors.push({
|
|
14
|
-
message:
|
|
16
|
+
message: buildMessage(targetVal),
|
|
15
17
|
path: basePath
|
|
16
18
|
});
|
|
17
19
|
}
|
|
@@ -19,7 +21,7 @@ module.exports = (targetVal, options, context) => {
|
|
|
19
21
|
targetVal.forEach((role, index) => {
|
|
20
22
|
if (typeof role === 'string' && !pattern.test(role)) {
|
|
21
23
|
errors.push({
|
|
22
|
-
message:
|
|
24
|
+
message: buildMessage(role),
|
|
23
25
|
path: [...basePath, index]
|
|
24
26
|
});
|
|
25
27
|
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @param {object} node
|
|
3
|
+
* @param {object} options
|
|
4
|
+
* @param {import('@stoplight/spectral-core').RulesetFunctionContext} context
|
|
5
|
+
*/
|
|
6
|
+
module.exports = (node, options, context) => {
|
|
7
|
+
const results = [];
|
|
8
|
+
|
|
9
|
+
if (!node || typeof node !== 'object') return results;
|
|
10
|
+
|
|
11
|
+
const { type } = node;
|
|
12
|
+
if (type !== 'integer' && type !== 'number') return results;
|
|
13
|
+
|
|
14
|
+
const has = (field) => Object.prototype.hasOwnProperty.call(node, field);
|
|
15
|
+
const hasMin = has('minimum');
|
|
16
|
+
const hasMax = has('maximum');
|
|
17
|
+
const hasFormat = has('format');
|
|
18
|
+
|
|
19
|
+
const hasBothBounds = hasMin && hasMax;
|
|
20
|
+
const formatAlone = hasFormat && !hasMin && !hasMax;
|
|
21
|
+
|
|
22
|
+
if (hasBothBounds || formatAlone) return results;
|
|
23
|
+
|
|
24
|
+
const ruleCode = context.rule.name.split(':').pop();
|
|
25
|
+
results.push({
|
|
26
|
+
message: `${ruleCode}: Numeric parameter should define both 'minimum' and 'maximum', or a 'format' restriction.`,
|
|
27
|
+
path: [...context.path, 'type'],
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
return results;
|
|
31
|
+
};
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
module.exports = (targetVal, options, context) => {
|
|
7
7
|
const minDepth = options['min-level'] ?? options.minDepth ?? null
|
|
8
|
-
const maxDepth = options['max-level'] ?? options.maxDepth ?? 3
|
|
8
|
+
const maxDepth = options['max-level'] ?? options['max-level-allowed'] ?? options.maxDepth ?? 3
|
|
9
9
|
const ignore = options.ignoreSegments ?? []
|
|
10
10
|
const segments = targetVal
|
|
11
11
|
.split('/')
|
|
@@ -20,8 +20,11 @@ module.exports = (targetVal, options, context) => {
|
|
|
20
20
|
: depth > maxDepth
|
|
21
21
|
|
|
22
22
|
if (isOutOfRange) {
|
|
23
|
+
const message = minDepth != null
|
|
24
|
+
? `OAR014: Path depth (${depth}) must not fall within the non-suggested range ${minDepth}-${maxDepth}.`
|
|
25
|
+
: `OAR015: Path depth (${depth}) exceeds the maximum allowed level of ${maxDepth}.`
|
|
23
26
|
return [
|
|
24
|
-
{ message
|
|
27
|
+
{ message }
|
|
25
28
|
]
|
|
26
29
|
}
|
|
27
30
|
}
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Validates that path parameters don't appear as query parameters
|
|
3
|
-
* This prevents ambiguity and design issues
|
|
4
2
|
*
|
|
5
|
-
* @param {object} given - The paths object
|
|
6
|
-
* @param {object} options - Function options
|
|
3
|
+
* @param {object} given - The paths object ($.paths)
|
|
4
|
+
* @param {object} options - Function options (unused)
|
|
7
5
|
* @param {import('@stoplight/spectral-core').RulesetFunctionContext} context
|
|
8
6
|
*/
|
|
9
7
|
module.exports = (given, options, context) => {
|
|
@@ -26,27 +24,25 @@ module.exports = (given, options, context) => {
|
|
|
26
24
|
continue;
|
|
27
25
|
}
|
|
28
26
|
|
|
29
|
-
const parameters = operation.parameters
|
|
30
|
-
|
|
27
|
+
const parameters = operation.parameters;
|
|
31
28
|
if (!Array.isArray(parameters)) {
|
|
32
29
|
continue;
|
|
33
30
|
}
|
|
34
31
|
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
)
|
|
38
|
-
|
|
39
|
-
if (!hasPathOrQueryParams) {
|
|
32
|
+
const responses = operation.responses || {};
|
|
33
|
+
const has400 = Boolean(responses['400']);
|
|
34
|
+
if (has400) {
|
|
40
35
|
continue;
|
|
41
36
|
}
|
|
42
37
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
38
|
+
parameters.forEach((param, index) => {
|
|
39
|
+
if (param && (param.in === 'path' || param.in === 'query')) {
|
|
40
|
+
errors.push({
|
|
41
|
+
message: context.rule.message,
|
|
42
|
+
path: [...context.path, pathKey, operationKey, 'parameters', index]
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
});
|
|
50
46
|
}
|
|
51
47
|
}
|
|
52
48
|
|
|
@@ -15,6 +15,7 @@ function isValidPattern(pattern) {
|
|
|
15
15
|
|
|
16
16
|
module.exports = (targetVal, _options, context) => {
|
|
17
17
|
const typePath = [...context.path, 'type'];
|
|
18
|
+
|
|
18
19
|
const format = targetVal.format;
|
|
19
20
|
if (format !== undefined && format !== null) {
|
|
20
21
|
if (!VALID_FORMATS.has(String(format).toLowerCase())) {
|
|
@@ -23,6 +24,11 @@ module.exports = (targetVal, _options, context) => {
|
|
|
23
24
|
return [];
|
|
24
25
|
}
|
|
25
26
|
|
|
27
|
+
const enumValues = targetVal.enum;
|
|
28
|
+
if (Array.isArray(enumValues) && enumValues.length > 0) {
|
|
29
|
+
return [];
|
|
30
|
+
}
|
|
31
|
+
|
|
26
32
|
const pattern = targetVal.pattern;
|
|
27
33
|
if (pattern !== undefined && pattern !== null && String(pattern).length > 0 && isValidPattern(String(pattern))) {
|
|
28
34
|
return [];
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* @param {object}
|
|
4
|
-
* @param {object} options - Function options
|
|
2
|
+
* @param {object} given - The operation node ($.paths[*][*])
|
|
3
|
+
* @param {object} options - Function options ({ 'expected-codes': '401' | '403' | '401,403' | ... })
|
|
5
4
|
* @param {import('@stoplight/spectral-core').RulesetFunctionContext} context
|
|
6
5
|
*/
|
|
7
6
|
module.exports = (given, options, context) => {
|
|
@@ -16,6 +15,11 @@ module.exports = (given, options, context) => {
|
|
|
16
15
|
return results;
|
|
17
16
|
}
|
|
18
17
|
|
|
18
|
+
const raw = (options && options['expected-codes']) || '401';
|
|
19
|
+
const expectedCodes = (Array.isArray(raw) ? raw : String(raw).split(','))
|
|
20
|
+
.map((code) => String(code).trim())
|
|
21
|
+
.filter(Boolean);
|
|
22
|
+
|
|
19
23
|
// Check if this operation has security defined
|
|
20
24
|
const operationHasSecurity = given.security &&
|
|
21
25
|
Array.isArray(given.security) &&
|
|
@@ -32,15 +36,22 @@ module.exports = (given, options, context) => {
|
|
|
32
36
|
// Ignore errors accessing root security
|
|
33
37
|
}
|
|
34
38
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
39
|
+
if (!(operationHasSecurity || globalHasSecurity)) {
|
|
40
|
+
return results;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const ruleName = (context.rule && context.rule.name) || '';
|
|
44
|
+
const oarId = ruleName.includes(':') ? ruleName.split(':').pop() : ruleName;
|
|
45
|
+
const prefix = oarId ? `${oarId}: ` : '';
|
|
46
|
+
|
|
47
|
+
expectedCodes.forEach((code) => {
|
|
48
|
+
if (!responses[code]) {
|
|
38
49
|
results.push({
|
|
39
|
-
message:
|
|
40
|
-
path: [...context.path, 'responses']
|
|
50
|
+
message: `${prefix}Response code ${code} must be defined for operations with security schemes defined.`,
|
|
51
|
+
path: [...context.path, 'responses'],
|
|
41
52
|
});
|
|
42
53
|
}
|
|
43
|
-
}
|
|
54
|
+
});
|
|
44
55
|
|
|
45
56
|
return results;
|
|
46
57
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "api-quality-spectral-ruleset",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.1-beta.2",
|
|
4
4
|
"description": "Spectral ruleset by API Quality",
|
|
5
5
|
"main": "apq-spectral.yaml",
|
|
6
6
|
"files": [
|
|
@@ -25,10 +25,10 @@
|
|
|
25
25
|
"url": "https://github.com/apiaddicts/apquality-spectral"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
|
-
"@stoplight/spectral-core": "
|
|
29
|
-
"@stoplight/spectral-functions": "^1.
|
|
30
|
-
"@stoplight/spectral-ruleset-migrator": "^1.
|
|
31
|
-
"@stoplight/spectral-rulesets": "
|
|
28
|
+
"@stoplight/spectral-core": "1.23.0",
|
|
29
|
+
"@stoplight/spectral-functions": "^1.10.5",
|
|
30
|
+
"@stoplight/spectral-ruleset-migrator": "^1.12.1",
|
|
31
|
+
"@stoplight/spectral-rulesets": "1.22.2",
|
|
32
32
|
"@types/jest": "^29.5.14",
|
|
33
33
|
"coverage-badges-cli": "^2.1.0",
|
|
34
34
|
"jest": "^29.7.0"
|