Skip to content

Commit 9147aa3

Browse files
committed
Normalize OWASP cheat sheet references
1 parent 949bd17 commit 9147aa3

3 files changed

Lines changed: 143 additions & 8 deletions

File tree

application/tests/cheatsheets_parser_test.py

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,15 +42,44 @@ class Repo:
4242
)
4343
expected = defs.Standard(
4444
name="OWASP Cheat Sheets",
45-
hyperlink="https://github.com/foo/bar/tree/master/cs.md",
45+
hyperlink="https://cheatsheetseries.owasp.org/cheatsheets/cs.html",
4646
section="Secrets Management Cheat Sheet",
4747
links=[defs.Link(document=cre, ltype=defs.LinkTypes.LinkedTo)],
4848
)
4949
self.maxDiff = None
5050
for name, nodes in entries.results.items():
5151
self.assertEqual(name, cheatsheets_parser.Cheatsheets().name)
52-
self.assertEqual(len(nodes), 1)
53-
self.assertCountEqual(expected.todict(), nodes[0].todict())
52+
sections = {node.section for node in nodes}
53+
self.assertIn("Secrets Management Cheat Sheet", sections)
54+
secret_entry = [
55+
node
56+
for node in nodes
57+
if node.section == "Secrets Management Cheat Sheet"
58+
][0]
59+
self.assertCountEqual(expected.todict(), secret_entry.todict())
60+
61+
def test_register_supplemental_cheatsheets(self) -> None:
62+
for cre_id, name in [
63+
("118-110", "API/web services"),
64+
("724-770", "Technical application access control"),
65+
("623-550", "Denial Of Service protection"),
66+
]:
67+
self.collection.add_cre(defs.CRE(name=name, id=cre_id))
68+
69+
entries = cheatsheets_parser.Cheatsheets().register_supplemental_cheatsheets(
70+
cache=self.collection
71+
)
72+
rest = [
73+
entry for entry in entries if entry.section == "REST Security Cheat Sheet"
74+
][0]
75+
self.assertEqual(
76+
"https://cheatsheetseries.owasp.org/cheatsheets/REST_Security_Cheat_Sheet.html",
77+
rest.hyperlink,
78+
)
79+
self.assertEqual(
80+
["118-110", "724-770", "623-550"],
81+
[link.document.id for link in rest.links],
82+
)
5483

5584
cheatsheets_md = """ # Secrets Management Cheat Sheet
5685
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: 64 additions & 5 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,
@@ -14,6 +17,13 @@
1417

1518
class Cheatsheets(ParserInterface):
1619
name = "OWASP Cheat Sheets"
20+
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__)
1727

1828
def cheatsheet(
1929
self, section: str, hyperlink: str, tags: List[str]
@@ -25,13 +35,29 @@ def cheatsheet(
2535
hyperlink=hyperlink,
2636
)
2737

38+
def official_cheatsheet_url(self, markdown_filename: str) -> str:
39+
html_name = os.path.splitext(markdown_filename)[0] + ".html"
40+
return f"{self.cheatsheetseries_base_url}/{html_name}"
41+
2842
def parse(self, cache: db.Node_collection, ph: prompt_client.PromptHandler):
2943
c_repo = "https://github.com/OWASP/CheatSheetSeries.git"
3044
cheatsheets_path = "cheatsheets/"
31-
repo = git.clone(c_repo)
32-
cheatsheets = self.register_cheatsheets(
33-
repo=repo, cache=cache, cheatsheets_path=cheatsheets_path, repo_path=c_repo
34-
)
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)
3561
return ParseResult(results={self.name: cheatsheets})
3662

3763
def register_cheatsheets(
@@ -55,7 +81,7 @@ def register_cheatsheets(
5581
name = title.group("title")
5682
cre_id = cre.group("cre")
5783
cres = cache.get_CREs(external_id=cre_id)
58-
hyperlink = f"{repo_path.replace('.git','')}/tree/master/{cheatsheets_path}{mdfile}"
84+
hyperlink = self.official_cheatsheet_url(mdfile)
5985
cs = self.cheatsheet(section=name, hyperlink=hyperlink, tags=[])
6086
for cre in cres:
6187
cs.add_link(
@@ -65,3 +91,36 @@ def register_cheatsheets(
6591
)
6692
standard_entries.append(cs)
6793
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)