Skip to content

Commit e792e63

Browse files
committed
feat(rulesets): validate API security in oas-operation-security-defined
1 parent 6b21eb1 commit e792e63

File tree

4 files changed

+254
-8
lines changed

4 files changed

+254
-8
lines changed

packages/rulesets/src/oas/__tests__/oas2-operation-security-defined.test.ts

Lines changed: 105 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ testRule('oas2-operation-security-defined', [
55
{
66
name: 'a correct object (just in body)',
77
document: {
8+
swagger: '2.0',
89
securityDefinitions: {
910
apikey: {},
1011
},
@@ -23,6 +24,27 @@ testRule('oas2-operation-security-defined', [
2324
errors: [],
2425
},
2526

27+
{
28+
name: 'a correct object (API-level security)',
29+
document: {
30+
swagger: '2.0',
31+
securityDefinitions: {
32+
apikey: {},
33+
},
34+
security: [
35+
{
36+
apikey: [],
37+
},
38+
],
39+
paths: {
40+
'/path': {
41+
get: {},
42+
},
43+
},
44+
},
45+
errors: [],
46+
},
47+
2648
{
2749
name: 'invalid object',
2850
document: {
@@ -43,7 +65,89 @@ testRule('oas2-operation-security-defined', [
4365
errors: [
4466
{
4567
message: 'Operation "security" values must match a scheme defined in the "securityDefinitions" object.',
46-
path: ['paths', '/path', 'get', 'security', '0'],
68+
path: ['paths', '/path', 'get', 'security', '0', 'apikey'],
69+
severity: DiagnosticSeverity.Warning,
70+
},
71+
],
72+
},
73+
74+
{
75+
name: 'invalid object (API-level security)',
76+
document: {
77+
swagger: '2.0',
78+
securityDefinitions: {},
79+
security: [
80+
{
81+
apikey: [],
82+
},
83+
],
84+
paths: {
85+
'/path': {
86+
get: {},
87+
},
88+
},
89+
},
90+
errors: [
91+
{
92+
message: 'API "security" values must match a scheme defined in the "securityDefinitions" object.',
93+
path: ['security', '0', 'apikey'],
94+
severity: DiagnosticSeverity.Warning,
95+
},
96+
],
97+
},
98+
99+
{
100+
name: 'valid and invalid object',
101+
document: {
102+
swagger: '2.0',
103+
securityDefinitions: {
104+
apikey: {},
105+
},
106+
paths: {
107+
'/path': {
108+
get: {
109+
security: [
110+
{
111+
apikey: [],
112+
basic: [],
113+
},
114+
],
115+
},
116+
},
117+
},
118+
},
119+
errors: [
120+
{
121+
message: 'Operation "security" values must match a scheme defined in the "securityDefinitions" object.',
122+
path: ['paths', '/path', 'get', 'security', '0', 'basic'],
123+
severity: DiagnosticSeverity.Warning,
124+
},
125+
],
126+
},
127+
128+
{
129+
name: 'valid and invalid object (API-level security)',
130+
document: {
131+
swagger: '2.0',
132+
securityDefinitions: {
133+
apikey: {},
134+
},
135+
security: [
136+
{
137+
apikey: [],
138+
basic: [],
139+
},
140+
],
141+
paths: {
142+
'/path': {
143+
get: {},
144+
},
145+
},
146+
},
147+
errors: [
148+
{
149+
message: 'API "security" values must match a scheme defined in the "securityDefinitions" object.',
150+
path: ['security', '0', 'basic'],
47151
severity: DiagnosticSeverity.Warning,
48152
},
49153
],

packages/rulesets/src/oas/__tests__/oas3-operation-security-defined.test.ts

Lines changed: 109 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,28 @@ testRule('oas3-operation-security-defined', [
2525
},
2626
errors: [],
2727
},
28+
{
29+
name: 'validate a correct object (API-level security)',
30+
document: {
31+
openapi: '3.0.2',
32+
components: {
33+
securitySchemes: {
34+
apikey: {},
35+
},
36+
security: [
37+
{
38+
apikey: [],
39+
},
40+
],
41+
},
42+
paths: {
43+
'/path': {
44+
get: {},
45+
},
46+
},
47+
},
48+
errors: [],
49+
},
2850

2951
{
3052
name: 'return errors on invalid object',
@@ -46,7 +68,93 @@ testRule('oas3-operation-security-defined', [
4668
errors: [
4769
{
4870
message: 'Operation "security" values must match a scheme defined in the "components.securitySchemes" object.',
49-
path: ['paths', '/path', 'get', 'security', '0'],
71+
path: ['paths', '/path', 'get', 'security', '0', 'apikey'],
72+
severity: DiagnosticSeverity.Warning,
73+
},
74+
],
75+
},
76+
77+
{
78+
name: 'return errors on invalid object (API-level)',
79+
document: {
80+
openapi: '3.0.2',
81+
components: {},
82+
security: [
83+
{
84+
apikey: [],
85+
},
86+
],
87+
paths: {
88+
'/path': {
89+
get: {},
90+
},
91+
},
92+
},
93+
errors: [
94+
{
95+
message: 'API "security" values must match a scheme defined in the "components.securitySchemes" object.',
96+
path: ['security', '0', 'apikey'],
97+
severity: DiagnosticSeverity.Warning,
98+
},
99+
],
100+
},
101+
102+
{
103+
name: 'return errors on valid and invalid object',
104+
document: {
105+
openapi: '3.0.2',
106+
components: {
107+
securitySchemes: {
108+
apikey: {},
109+
},
110+
},
111+
paths: {
112+
'/path': {
113+
get: {
114+
security: [
115+
{
116+
apikey: [],
117+
basic: [],
118+
},
119+
],
120+
},
121+
},
122+
},
123+
},
124+
errors: [
125+
{
126+
message: 'Operation "security" values must match a scheme defined in the "components.securitySchemes" object.',
127+
path: ['paths', '/path', 'get', 'security', '0', 'basic'],
128+
severity: DiagnosticSeverity.Warning,
129+
},
130+
],
131+
},
132+
133+
{
134+
name: 'valid and invalid object (API-level security)',
135+
document: {
136+
openapi: '3.0.2',
137+
components: {
138+
securitySchemes: {
139+
apikey: {},
140+
},
141+
},
142+
security: [
143+
{
144+
apikey: [],
145+
basic: [],
146+
},
147+
],
148+
paths: {
149+
'/path': {
150+
get: {},
151+
},
152+
},
153+
},
154+
errors: [
155+
{
156+
message: 'API "security" values must match a scheme defined in the "components.securitySchemes" object.',
157+
path: ['security', '0', 'basic'],
50158
severity: DiagnosticSeverity.Warning,
51159
},
52160
],

packages/rulesets/src/oas/functions/oasOpSecurityDefined.ts

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,17 @@ type Options = {
2020
schemesPath: JsonPath;
2121
};
2222

23-
export default createRulesetFunction<{ paths: Record<string, unknown> }, Options>(
23+
export default createRulesetFunction<{ paths: Record<string, unknown>; security: unknown[] }, Options>(
2424
{
2525
input: {
2626
type: 'object',
2727
properties: {
2828
paths: {
2929
type: 'object',
3030
},
31+
security: {
32+
type: 'array',
33+
},
3134
},
3235
},
3336
options: {
@@ -50,6 +53,31 @@ export default createRulesetFunction<{ paths: Record<string, unknown> }, Options
5053
const schemes = _get(targetVal, schemesPath);
5154
const allDefs = isObject(schemes) ? Object.keys(schemes) : [];
5255

56+
// Check global security requirements
57+
58+
{
59+
const { security } = targetVal;
60+
61+
if (Array.isArray(security)) {
62+
for (const [index, value] of security.entries()) {
63+
if (!isObject(value)) {
64+
continue;
65+
}
66+
67+
const securityKeys = Object.keys(value);
68+
69+
for (const securityKey of securityKeys) {
70+
if (!allDefs.includes(securityKey)) {
71+
results.push({
72+
message: `API "security" values must match a scheme defined in the "${schemesPath.join('.')}" object.`,
73+
path: ['security', index, securityKey],
74+
});
75+
}
76+
}
77+
}
78+
}
79+
}
80+
5381
for (const { path, operation, value } of getAllOperations(paths)) {
5482
if (!isObject(value)) continue;
5583

@@ -66,11 +94,15 @@ export default createRulesetFunction<{ paths: Record<string, unknown> }, Options
6694

6795
const securityKeys = Object.keys(value);
6896

69-
if (securityKeys.length > 0 && !allDefs.includes(securityKeys[0])) {
70-
results.push({
71-
message: 'Operation must not reference an undefined security scheme.',
72-
path: ['paths', path, operation, 'security', index],
73-
});
97+
for (const securityKey of securityKeys) {
98+
if (!allDefs.includes(securityKey)) {
99+
results.push({
100+
message: `Operation "security" values must match a scheme defined in the "${schemesPath.join(
101+
'.',
102+
)}" object.`,
103+
path: ['paths', path, operation, 'security', index, securityKey],
104+
});
105+
}
74106
}
75107
}
76108
}

packages/rulesets/src/oas/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,7 @@ const ruleset = {
449449
},
450450
'oas2-operation-security-defined': {
451451
description: 'Operation "security" values must match a scheme defined in the "securityDefinitions" object.',
452+
message: '{{error}}',
452453
recommended: true,
453454
formats: [oas2],
454455
type: 'validation',
@@ -590,6 +591,7 @@ const ruleset = {
590591
'oas3-operation-security-defined': {
591592
description:
592593
'Operation "security" values must match a scheme defined in the "components.securitySchemes" object.',
594+
message: '{{error}}',
593595
recommended: true,
594596
formats: [oas3],
595597
type: 'validation',

0 commit comments

Comments
 (0)