api-quality-spectral-ruleset 1.6.0-beta.1 → 1.6.0
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
CHANGED
|
@@ -53,9 +53,7 @@ functions:
|
|
|
53
53
|
- apq-wso2-auth-type-required
|
|
54
54
|
- apq-response-content-required
|
|
55
55
|
- apq-tags-consistency
|
|
56
|
-
|
|
57
|
-
- spectral:asyncapi
|
|
58
|
-
- spectral:oas
|
|
56
|
+
- apq-forbidden-title-pattern
|
|
59
57
|
rules:
|
|
60
58
|
apiq:OAR001:
|
|
61
59
|
description: "For security reasons and as a REST best practice, the HTTPS protocol is mandatory."
|
|
@@ -625,8 +623,6 @@ rules:
|
|
|
625
623
|
message: "OAR048: An operation can have at most one body parameter"
|
|
626
624
|
documentationUrl: "https://github.com/apiaddicts/apquality-spectral/blob/main/docs/resources/OAR048.md"
|
|
627
625
|
severity: error
|
|
628
|
-
formats:
|
|
629
|
-
- oas2
|
|
630
626
|
given: "$.paths[*][*]"
|
|
631
627
|
then:
|
|
632
628
|
field: parameters
|
|
@@ -854,6 +850,10 @@ rules:
|
|
|
854
850
|
given:
|
|
855
851
|
- "$.paths[*][*].parameters[*]"
|
|
856
852
|
- "$.paths[*].parameters[*]"
|
|
853
|
+
- "$.paths[*].additionalOperations[*].parameters[*]"
|
|
854
|
+
- "$.webhooks[*][*].parameters[*]"
|
|
855
|
+
- "$.webhooks[*].parameters[*]"
|
|
856
|
+
- "$.webhooks[*].additionalOperations[*].parameters[*]"
|
|
857
857
|
- "$.components.parameters[*]"
|
|
858
858
|
- "$.parameters[*]"
|
|
859
859
|
then:
|
|
@@ -991,6 +991,7 @@ rules:
|
|
|
991
991
|
description: "The $ref of a request body must end with the suffix Body."
|
|
992
992
|
message: "OAR089: The $ref of a request body must end with the suffix Body."
|
|
993
993
|
severity: "warn"
|
|
994
|
+
resolved: false
|
|
994
995
|
given: "$..requestBody.$ref"
|
|
995
996
|
then:
|
|
996
997
|
function: pattern
|
|
@@ -1214,4 +1215,14 @@ rules:
|
|
|
1214
1215
|
then:
|
|
1215
1216
|
function: apq-path-pattern
|
|
1216
1217
|
functionOptions:
|
|
1217
|
-
pattern: "^/"
|
|
1218
|
+
pattern: "^/"
|
|
1219
|
+
apiq:OAR117:
|
|
1220
|
+
description: "The API title must not match the configured forbidden regular expression."
|
|
1221
|
+
message: "{{error}}"
|
|
1222
|
+
documentationUrl: "https://github.com/apiaddicts/apquality-spectral/blob/main/docs/resources/OAR117.md"
|
|
1223
|
+
severity: error
|
|
1224
|
+
given: "$.info.title"
|
|
1225
|
+
then:
|
|
1226
|
+
function: apq-forbidden-title-pattern
|
|
1227
|
+
functionOptions:
|
|
1228
|
+
forbidden-pattern: "(?!)"
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
const INLINE_FLAGS_REGEX = /^\(\?([a-zA-Z]+)\)/;
|
|
2
|
+
const SUPPORTED_INLINE_FLAGS = 'imsu';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @param {string} pattern configured regular expression
|
|
6
|
+
* @returns {RegExp|null} the matcher, or null when the pattern is empty or not valid
|
|
7
|
+
*/
|
|
8
|
+
function buildRegex(pattern) {
|
|
9
|
+
let source = pattern;
|
|
10
|
+
let flags = '';
|
|
11
|
+
|
|
12
|
+
const inline = INLINE_FLAGS_REGEX.exec(source);
|
|
13
|
+
if (inline) {
|
|
14
|
+
const requested = inline[1].toLowerCase();
|
|
15
|
+
if ([...requested].every((flag) => SUPPORTED_INLINE_FLAGS.includes(flag))) {
|
|
16
|
+
flags = [...new Set(requested)].join('');
|
|
17
|
+
source = source.slice(inline[0].length);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (source === '') {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
return new RegExp(source, flags);
|
|
27
|
+
} catch (e) {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* @param {unknown} targetVal value of `info.title`
|
|
34
|
+
* @param {object} options
|
|
35
|
+
* @param {string} options['forbidden-pattern'] regular expression that raises an issue when it
|
|
36
|
+
* matches the title
|
|
37
|
+
* @param {import('@stoplight/spectral-core').RulesetFunctionContext} context
|
|
38
|
+
* @returns {Array<{message: string, path: Array}>}
|
|
39
|
+
*/
|
|
40
|
+
module.exports = (targetVal, options, context) => {
|
|
41
|
+
if (typeof targetVal !== 'string') {
|
|
42
|
+
return [];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const patternStr = options && options['forbidden-pattern'];
|
|
46
|
+
if (typeof patternStr !== 'string' || patternStr === '') {
|
|
47
|
+
return [];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const regex = buildRegex(patternStr);
|
|
51
|
+
if (regex === null || !regex.test(targetVal)) {
|
|
52
|
+
return [];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return [
|
|
56
|
+
{
|
|
57
|
+
message: `OAR117: Title '${targetVal}' matches the forbidden pattern: ${patternStr}`,
|
|
58
|
+
path: (context && context.path) || []
|
|
59
|
+
}
|
|
60
|
+
];
|
|
61
|
+
};
|
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
const DEFAULT_INTEGRITY = 'minLength,maxLength,pattern,enum';
|
|
2
2
|
|
|
3
|
+
const SELF_CONSTRAINED_FORMATS = new Set([
|
|
4
|
+
'date', 'date-time', 'uuid', 'ipv4', 'ipv6',
|
|
5
|
+
]);
|
|
6
|
+
|
|
3
7
|
function isStringType(type) {
|
|
4
8
|
return type === 'string' || (Array.isArray(type) && type.indexOf('string') > -1);
|
|
5
9
|
}
|
|
6
10
|
|
|
11
|
+
function hasSelfConstrainedFormat(format) {
|
|
12
|
+
return typeof format === 'string' && SELF_CONSTRAINED_FORMATS.has(format.trim().toLowerCase());
|
|
13
|
+
}
|
|
14
|
+
|
|
7
15
|
/**
|
|
8
16
|
* @param {object} targetVal a Parameter Object
|
|
9
17
|
* @param {object} options
|
|
@@ -20,6 +28,8 @@ module.exports = (targetVal, options, context) => {
|
|
|
20
28
|
|
|
21
29
|
if (!isStringType(container.type)) return [];
|
|
22
30
|
|
|
31
|
+
if (hasSelfConstrainedFormat(container.format)) return [];
|
|
32
|
+
|
|
23
33
|
const raw = options && options.parameter_integrity !== undefined && options.parameter_integrity !== null
|
|
24
34
|
? String(options.parameter_integrity)
|
|
25
35
|
: DEFAULT_INTEGRITY;
|