Skip to content

Commit

Permalink
fix(openapi): Take into account that security is at the root level of…
Browse files Browse the repository at this point in the history
… your OpenAPI specification. (#5603)

* Fix CKV_OPENAPI_5 to take into account that security is at the root level of your OpenAPI specification.

* fix indentation

* add a test for the CKV_OPENAPI_5

* fix failing check

* fix logic

* fix test cases and logic

---------

Co-authored-by: gruebel <[email protected]>
  • Loading branch information
SimOnPanw and gruebel authored Oct 4, 2023
1 parent 7ba67b6 commit 37743fa
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 8 deletions.
16 changes: 11 additions & 5 deletions checkov/openapi/checks/resource/generic/SecurityOperations.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,12 @@ def __init__(self) -> None:
block_type=BlockType.DOCUMENT)

def scan_entity_conf(self, conf: dict[str, Any], entity_type: str) -> tuple[CheckResult, dict[str, Any]]: # type:ignore[override] # return type is different than the base class
self.evaluated_keys = ['paths']
self.evaluated_keys = ['security', 'paths']

# Check if security field is present and not empty at the root level
root_security = conf.get('security')

# If security field is not present or empty at the root level, check within each operation
paths = conf.get('paths', {}) or {}
if isinstance(paths, dict):
for path, http_method in paths.items():
Expand All @@ -30,12 +34,14 @@ def scan_entity_conf(self, conf: dict[str, Any], entity_type: str) -> tuple[Chec
self.evaluated_keys = ['security']
if not isinstance(op_val, dict):
continue
if 'security' not in op_val:
op_security = op_val.get("security")
if op_security is not None and not op_security:
# fails when security field is set as empty list
return CheckResult.FAILED, conf

security = op_val['security']
if not security:
return CheckResult.FAILED, paths
if op_security is None and not root_security:
# no security field for the operation and not in the root
return CheckResult.FAILED, conf

return CheckResult.PASSED, conf

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"swagger": "2.0",
"openapi": "3.0.0",
"info": {
"title": "example",
"version": "1.0.0",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
swagger: "2.0"
openapi: 3.0.0
info:
title: example
version: 1.0.0
Expand Down Expand Up @@ -27,4 +27,4 @@ paths:
type: string
required:
- code
- message
- message
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
{
"openapi": "3.0.3",
"info": {
"title": "example",
"version": "1.0.0",
"contact": {
"name": "contact",
"url": "https://www.google.com/",
"email": "[email protected]"
}
},
"security": [
{
"ApiKeyAuth": []
}
],
"paths": {
"/": {
"get": {
"operationId": "id",
"summary": "example",
"responses": {
"200": {
"description": "200 response",
"schema": {
"type": "object",
"properties": {
"code": {
"type": "integer",
"format": "int32"
},
"message": {
"type": "string"
}
},
"required": [
"code",
"message"
]
}
}
}
}
}
},
"components": {
"securitySchemes": {
"ApiKeyAuth": {
"type": "apiKey",
"in": "header",
"name": "X-API-KEY"
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
openapi: "3.0.3"
info:
title: example
version: 1.0.0
contact:
name: contact
url: https://www.google.com/
email: [email protected]
security:
- ApiKeyAuth: []
paths:
"/":
get:
operationId: id
summary: example
responses:
"200":
description: 200 response
schema:
type: object
properties:
code:
type: integer
format: int32
message:
type: string
required:
- code
- message
components:
securitySchemes:
ApiKeyAuth:
type: apiKey
in: header
name: X-API-KEY
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ def test_summary(self):
"/pass1.json",
"/pass2.yaml",
"/pass2.json",
"/pass3.yaml",
"/pass3.json",
}
failing_resources = {
"/fail1.yaml",
Expand Down

0 comments on commit 37743fa

Please sign in to comment.