Skip to content

Commit f26c78e

Browse files
committed
Normalize OWASP cheat sheet references
1 parent 0e56453 commit f26c78e

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
@@ -69,8 +69,37 @@ class Repo:
6969
self.maxDiff = None
7070
for name, nodes in entries.results.items():
7171
self.assertEqual(name, parser.name)
72-
self.assertEqual(len(nodes), 1)
73-
self.assertEqual(expected.todict(), nodes[0].todict())
72+
sections = {node.section for node in nodes}
73+
self.assertIn("Secrets Management Cheat Sheet", sections)
74+
secret_entry = [
75+
node
76+
for node in nodes
77+
if node.section == "Secrets Management Cheat Sheet"
78+
][0]
79+
self.assertEqual(expected.todict(), secret_entry.todict())
80+
81+
def test_register_supplemental_cheatsheets(self) -> None:
82+
for cre_id, name in [
83+
("118-110", "API/web services"),
84+
("724-770", "Technical application access control"),
85+
("623-550", "Denial Of Service protection"),
86+
]:
87+
self.collection.add_cre(defs.CRE(name=name, id=cre_id))
88+
89+
entries = cheatsheets_parser.Cheatsheets().register_supplemental_cheatsheets(
90+
cache=self.collection
91+
)
92+
rest = [
93+
entry for entry in entries if entry.section == "REST Security Cheat Sheet"
94+
][0]
95+
self.assertEqual(
96+
"https://cheatsheetseries.owasp.org/cheatsheets/REST_Security_Cheat_Sheet.html",
97+
rest.hyperlink,
98+
)
99+
self.assertEqual(
100+
["118-110", "724-770", "623-550"],
101+
[link.document.id for link in rest.links],
102+
)
74103

75104
cheatsheets_md = """ # Secrets Management Cheat Sheet
76105
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
@@ -6,6 +6,9 @@
66
import os
77
import re
88
from application.utils.external_project_parsers import base_parser_defs
9+
import json
10+
from pathlib import Path
11+
import logging
912
from application.utils.external_project_parsers.base_parser_defs import (
1013
ParserInterface,
1114
ParseResult,
@@ -16,6 +19,12 @@
1619
class Cheatsheets(ParserInterface):
1720
name = "OWASP Cheat Sheets"
1821
cheatsheetseries_base_url = "https://cheatsheetseries.owasp.org/cheatsheets"
22+
supplement_data_file = (
23+
Path(__file__).resolve().parent.parent
24+
/ "data"
25+
/ "owasp_cheatsheets_supplement.json"
26+
)
27+
logger = logging.getLogger(__name__)
1928

2029
def cheatsheet(
2130
self, section: str, hyperlink: str, tags: List[str]
@@ -41,10 +50,22 @@ def official_cheatsheet_url(self, markdown_filename: str) -> str:
4150
def parse(self, cache: db.Node_collection, ph: prompt_client.PromptHandler):
4251
c_repo = "https://github.com/OWASP/CheatSheetSeries.git"
4352
cheatsheets_path = "cheatsheets/"
44-
repo = git.clone(c_repo, sparse_paths=["cheatsheets"], sparse_cone=True)
45-
cheatsheets = self.register_cheatsheets(
46-
repo=repo, cache=cache, cheatsheets_path=cheatsheets_path, repo_path=c_repo
47-
)
53+
cheatsheets = []
54+
try:
55+
repo = git.clone(c_repo, sparse_paths=["cheatsheets"], sparse_cone=True)
56+
cheatsheets = self.register_cheatsheets(
57+
repo=repo,
58+
cache=cache,
59+
cheatsheets_path=cheatsheets_path,
60+
repo_path=c_repo,
61+
)
62+
except Exception as exc:
63+
self.logger.warning(
64+
"Unable to clone OWASP CheatSheetSeries, continuing with supplemental cheat sheets only: %s",
65+
exc,
66+
)
67+
cheatsheets.extend(self.register_supplemental_cheatsheets(cache=cache))
68+
cheatsheets = self.deduplicate_entries(cheatsheets)
4869
results = {self.name: cheatsheets}
4970
base_parser_defs.validate_classification_tags(results)
5071
return ParseResult(results=results)
@@ -80,3 +101,36 @@ def register_cheatsheets(
80101
)
81102
standard_entries.append(cs)
82103
return standard_entries
104+
105+
def register_supplemental_cheatsheets(self, cache: db.Node_collection):
106+
with self.supplement_data_file.open("r", encoding="utf-8") as handle:
107+
supplement_entries = json.load(handle)
108+
109+
standard_entries = []
110+
for entry in supplement_entries:
111+
cs = self.cheatsheet(
112+
section=entry["section"],
113+
hyperlink=entry["hyperlink"],
114+
tags=[],
115+
)
116+
for cre_id in entry.get("cre_ids", []):
117+
cres = cache.get_CREs(external_id=cre_id)
118+
for cre in cres:
119+
try:
120+
cs.add_link(
121+
defs.Link(
122+
document=cre.shallow_copy(),
123+
ltype=defs.LinkTypes.AutomaticallyLinkedTo,
124+
)
125+
)
126+
except Exception:
127+
continue
128+
if cs.links:
129+
standard_entries.append(cs)
130+
return standard_entries
131+
132+
def deduplicate_entries(self, entries: List[defs.Standard]) -> List[defs.Standard]:
133+
deduped = {}
134+
for entry in entries:
135+
deduped[(entry.section, entry.hyperlink)] = entry
136+
return list(deduped.values())

0 commit comments

Comments
 (0)