Skip to content

Commit 901c9a0

Browse files
committed
Normalize OWASP cheat sheet references
1 parent 9390511 commit 901c9a0

3 files changed

Lines changed: 136 additions & 6 deletions

File tree

application/tests/cheatsheets_parser_test.py

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,37 @@ class Repo:
5959
self.maxDiff = None
6060
for name, nodes in entries.results.items():
6161
self.assertEqual(name, cheatsheets_parser.Cheatsheets().name)
62-
self.assertEqual(len(nodes), 1)
63-
self.assertEqual(expected.todict(), nodes[0].todict())
62+
sections = {node.section for node in nodes}
63+
self.assertIn("Secrets Management Cheat Sheet", sections)
64+
secret_entry = [
65+
node
66+
for node in nodes
67+
if node.section == "Secrets Management Cheat Sheet"
68+
][0]
69+
self.assertEqual(expected.todict(), secret_entry.todict())
70+
71+
def test_register_supplemental_cheatsheets(self) -> None:
72+
for cre_id, name in [
73+
("118-110", "API/web services"),
74+
("724-770", "Technical application access control"),
75+
("623-550", "Denial Of Service protection"),
76+
]:
77+
self.collection.add_cre(defs.CRE(name=name, id=cre_id))
78+
79+
entries = cheatsheets_parser.Cheatsheets().register_supplemental_cheatsheets(
80+
cache=self.collection
81+
)
82+
rest = [
83+
entry for entry in entries if entry.section == "REST Security Cheat Sheet"
84+
][0]
85+
self.assertEqual(
86+
"https://cheatsheetseries.owasp.org/cheatsheets/REST_Security_Cheat_Sheet.html",
87+
rest.hyperlink,
88+
)
89+
self.assertEqual(
90+
["118-110", "724-770", "623-550"],
91+
[link.document.id for link in rest.links],
92+
)
6493

6594
cheatsheets_md = """ # Secrets Management Cheat Sheet
6695
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
[
2+
{
3+
"section": "Authorization Cheat Sheet",
4+
"hyperlink": "https://cheatsheetseries.owasp.org/cheatsheets/Authorization_Cheat_Sheet.html",
5+
"cre_ids": ["128-128", "117-371"]
6+
},
7+
{
8+
"section": "REST Security Cheat Sheet",
9+
"hyperlink": "https://cheatsheetseries.owasp.org/cheatsheets/REST_Security_Cheat_Sheet.html",
10+
"cre_ids": ["118-110", "724-770", "623-550"]
11+
},
12+
{
13+
"section": "Server Side Request Forgery Prevention Cheat Sheet",
14+
"hyperlink": "https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html",
15+
"cre_ids": ["028-728", "657-084"]
16+
},
17+
{
18+
"section": "Docker Security Cheat Sheet",
19+
"hyperlink": "https://cheatsheetseries.owasp.org/cheatsheets/Docker_Security_Cheat_Sheet.html",
20+
"cre_ids": ["233-748", "486-813"]
21+
},
22+
{
23+
"section": "Kubernetes Security Cheat Sheet",
24+
"hyperlink": "https://cheatsheetseries.owasp.org/cheatsheets/Kubernetes_Security_Cheat_Sheet.html",
25+
"cre_ids": ["467-784", "233-748", "486-813"]
26+
},
27+
{
28+
"section": "Secure Cloud Architecture Cheat Sheet",
29+
"hyperlink": "https://cheatsheetseries.owasp.org/cheatsheets/Secure_Cloud_Architecture_Cheat_Sheet.html",
30+
"cre_ids": ["155-155", "467-784"]
31+
},
32+
{
33+
"section": "LLM Prompt Injection Prevention Cheat Sheet",
34+
"hyperlink": "https://cheatsheetseries.owasp.org/cheatsheets/LLM_Prompt_Injection_Prevention_Cheat_Sheet.html",
35+
"cre_ids": ["161-451", "760-764"]
36+
},
37+
{
38+
"section": "AI Agent Security Cheat Sheet",
39+
"hyperlink": "https://cheatsheetseries.owasp.org/cheatsheets/AI_Agent_Security_Cheat_Sheet.html",
40+
"cre_ids": ["117-371", "650-560", "126-668"]
41+
},
42+
{
43+
"section": "Secure AI Model Ops Cheat Sheet",
44+
"hyperlink": "https://cheatsheetseries.owasp.org/cheatsheets/Secure_AI_Model_Ops_Cheat_Sheet.html",
45+
"cre_ids": ["148-853", "613-285", "613-287"]
46+
}
47+
]

application/utils/external_project_parsers/parsers/cheatsheets_parser.py

Lines changed: 58 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
from application.defs import cre_defs as defs
66
import os
77
import re
8+
import json
9+
from pathlib import Path
10+
import logging
811
from application.utils.external_project_parsers.base_parser_defs import (
912
ParserInterface,
1013
ParseResult,
@@ -15,6 +18,12 @@
1518
class Cheatsheets(ParserInterface):
1619
name = "OWASP Cheat Sheets"
1720
cheatsheetseries_base_url = "https://cheatsheetseries.owasp.org/cheatsheets"
21+
supplement_data_file = (
22+
Path(__file__).resolve().parent.parent
23+
/ "data"
24+
/ "owasp_cheatsheets_supplement.json"
25+
)
26+
logger = logging.getLogger(__name__)
1827

1928
def cheatsheet(
2029
self, section: str, hyperlink: str, tags: List[str]
@@ -33,10 +42,22 @@ def official_cheatsheet_url(self, markdown_filename: str) -> str:
3342
def parse(self, cache: db.Node_collection, ph: prompt_client.PromptHandler):
3443
c_repo = "https://github.com/OWASP/CheatSheetSeries.git"
3544
cheatsheets_path = "cheatsheets/"
36-
repo = git.clone(c_repo)
37-
cheatsheets = self.register_cheatsheets(
38-
repo=repo, cache=cache, cheatsheets_path=cheatsheets_path, repo_path=c_repo
39-
)
45+
cheatsheets = []
46+
try:
47+
repo = git.clone(c_repo)
48+
cheatsheets = self.register_cheatsheets(
49+
repo=repo,
50+
cache=cache,
51+
cheatsheets_path=cheatsheets_path,
52+
repo_path=c_repo,
53+
)
54+
except Exception as exc:
55+
self.logger.warning(
56+
"Unable to clone OWASP CheatSheetSeries, continuing with supplemental cheat sheets only: %s",
57+
exc,
58+
)
59+
cheatsheets.extend(self.register_supplemental_cheatsheets(cache=cache))
60+
cheatsheets = self.deduplicate_entries(cheatsheets)
4061
return ParseResult(results={self.name: cheatsheets})
4162

4263
def register_cheatsheets(
@@ -70,3 +91,36 @@ def register_cheatsheets(
7091
)
7192
standard_entries.append(cs)
7293
return standard_entries
94+
95+
def register_supplemental_cheatsheets(self, cache: db.Node_collection):
96+
with self.supplement_data_file.open("r", encoding="utf-8") as handle:
97+
supplement_entries = json.load(handle)
98+
99+
standard_entries = []
100+
for entry in supplement_entries:
101+
cs = self.cheatsheet(
102+
section=entry["section"],
103+
hyperlink=entry["hyperlink"],
104+
tags=[],
105+
)
106+
for cre_id in entry.get("cre_ids", []):
107+
cres = cache.get_CREs(external_id=cre_id)
108+
for cre in cres:
109+
try:
110+
cs.add_link(
111+
defs.Link(
112+
document=cre.shallow_copy(),
113+
ltype=defs.LinkTypes.AutomaticallyLinkedTo,
114+
)
115+
)
116+
except Exception:
117+
continue
118+
if cs.links:
119+
standard_entries.append(cs)
120+
return standard_entries
121+
122+
def deduplicate_entries(self, entries: List[defs.Standard]) -> List[defs.Standard]:
123+
deduped = {}
124+
for entry in entries:
125+
deduped[(entry.section, entry.hyperlink)] = entry
126+
return list(deduped.values())

0 commit comments

Comments
 (0)