Skip to content
44 changes: 43 additions & 1 deletion application/cmd/cre_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -730,7 +730,11 @@ def backfill_gap_analysis_only(
if os.environ.get("CRE_NO_NEO4J") != "1":
populate_neo4j_db(db_connection_str)

gap_analysis.backfill_opencre_direct_pairs(collection, refresh=True)
if os.environ.get("OPENCRE_ENV") not in {"heroku", "opencreorg"}:
gap_analysis.backfill_opencre_direct_pairs(collection, refresh=True)
else:
logger.warning("Skipping GA recomputation on production environment")
Comment thread
Bornunique911 marked this conversation as resolved.
return

missing = _missing_ga_pairs(collection)
if max_pairs > 0:
Expand Down Expand Up @@ -911,6 +915,44 @@ def run(args: argparse.Namespace) -> None: # pragma: no cover
BaseParser().register_resource(
secure_headers.SecureHeaders, db_connection_str=args.cache_file
)
if getattr(args, "owasp_top10_2025_in", False):
from application.utils.external_project_parsers.parsers import owasp_top10_2025

BaseParser().register_resource(
owasp_top10_2025.OwaspTop10_2025, db_connection_str=args.cache_file
)
if getattr(args, "owasp_api_top10_2023_in", False):
from application.utils.external_project_parsers.parsers import (
owasp_api_top10_2023,
)

BaseParser().register_resource(
owasp_api_top10_2023.OwaspApiTop10_2023,
db_connection_str=args.cache_file,
)
if getattr(args, "owasp_kubernetes_top10_2022_in", False):
logger.warning(
"--owasp_kubernetes_top10_2022_in requested, but no Kubernetes 2022 parser module is present in this branch; skipping"
)
if getattr(args, "owasp_kubernetes_top10_2025_in", False):
logger.warning(
"--owasp_kubernetes_top10_2025_in requested, but no Kubernetes 2025 parser module is present in this branch; skipping"
)
if getattr(args, "owasp_llm_top10_2025_in", False):
from application.utils.external_project_parsers.parsers import (
owasp_llm_top10_2025,
)

BaseParser().register_resource(
owasp_llm_top10_2025.OwaspLlmTop10_2025,
db_connection_str=args.cache_file,
)
if getattr(args, "owasp_aisvs_in", False):
from application.utils.external_project_parsers.parsers import owasp_aisvs

BaseParser().register_resource(
owasp_aisvs.OwaspAisvs, db_connection_str=args.cache_file
)
if args.pci_dss_4_in:
from application.utils.external_project_parsers.parsers import pci_dss

Expand Down
16 changes: 11 additions & 5 deletions application/tests/cheatsheets_parser_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,13 @@ class Repo:
repo.working_dir = loc
cre = defs.CRE(name="blah", id="223-780")
self.collection.add_cre(cre)
with open(os.path.join(os.path.join(loc, "cheatsheets"), "cs.md"), "w") as mdf:
with open(
os.path.join(
os.path.join(loc, "cheatsheets"),
"Secrets_Management_Cheat_Sheet.md",
),
"w",
) as mdf:
mdf.write(cs)
mock_clone.return_value = repo
entries = cheatsheets_parser.Cheatsheets().parse(
Expand All @@ -45,22 +51,22 @@ class Repo:
# verify the external tagging convention, not just enum wiring.
expected = defs.Standard(
name="OWASP Cheat Sheets",
hyperlink="https://github.com/foo/bar/tree/master/cs.md",
hyperlink="https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html",
section="Secrets Management Cheat Sheet",
links=[defs.Link(document=cre, ltype=defs.LinkTypes.LinkedTo)],
links=[defs.Link(document=cre, ltype=defs.LinkTypes.AutomaticallyLinkedTo)],
tags=[
"family:guidance",
"subtype:cheatsheet",
"source:owasp_cheatsheets",
"audience:developer",
"maturity:stable",
"source:owasp_cheatsheets",
],
)
self.maxDiff = None
for name, nodes in entries.results.items():
self.assertEqual(name, parser.name)
self.assertEqual(len(nodes), 1)
self.assertCountEqual(expected.todict(), nodes[0].todict())
self.assertEqual(expected.todict(), nodes[0].todict())

cheatsheets_md = """ # Secrets Management Cheat Sheet

Expand Down
66 changes: 66 additions & 0 deletions application/tests/owasp_aisvs_parser_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import unittest

from application import create_app, sqla # type: ignore
from application.database import db
from application.defs import cre_defs as defs
from application.prompt_client import prompt_client
from application.utils.external_project_parsers.parsers import owasp_aisvs


class TestOwaspAisvsParser(unittest.TestCase):
def tearDown(self) -> None:
sqla.session.remove()
sqla.drop_all()
self.app_context.pop()

def setUp(self) -> None:
self.app = create_app(mode="test")
self.app_context = self.app.app_context()
self.app_context.push()
sqla.create_all()
self.collection = db.Node_collection()

def test_parse(self) -> None:
for cre_id, name in [
("227-045", "Identify sensitive data and subject it to a policy"),
(
"307-507",
"Allow only trusted sources both build time and runtime; therefore perform integrity checks on all resources and code",
),
(
"162-655",
"Documentation of all components' business or security function",
),
]:
self.collection.add_cre(defs.CRE(id=cre_id, name=name, description=""))

result = owasp_aisvs.OwaspAisvs().parse(
self.collection, prompt_client.PromptHandler(database=self.collection)
)

entries = result.results["OWASP AI Security Verification Standard (AISVS)"]
self.assertEqual(14, len(entries))
self.assertEqual("AISVS1", entries[0].sectionID)
self.assertEqual(
"Training Data Governance & Bias Management", entries[0].section
)
self.assertEqual(
"https://github.com/OWASP/AISVS/blob/main/1.0/en/0x10-C01-Training-Data-Integrity-and-Traceability.md",
entries[0].hyperlink,
)
self.assertEqual(
["227-045", "307-507"],
[link.document.id for link in entries[0].links],
)
Comment thread
coderabbitai[bot] marked this conversation as resolved.
self.assertEqual("AISVS14", entries[-1].sectionID)
self.assertEqual(
"Human Oversight, Accountability & Governance", entries[-1].section
)
self.assertEqual(
"https://github.com/OWASP/AISVS/blob/main/1.0/en/0x10-C14-Human-Oversight.md",
entries[-1].hyperlink,
)
self.assertEqual(
["162-655"],
[link.document.id for link in entries[-1].links],
)
47 changes: 47 additions & 0 deletions application/tests/owasp_api_top10_2023_parser_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import unittest

from application import create_app, sqla # type: ignore
from application.database import db
from application.defs import cre_defs as defs
from application.prompt_client import prompt_client
from application.utils.external_project_parsers.parsers import owasp_api_top10_2023


class TestOwaspApiTop10_2023Parser(unittest.TestCase):
def tearDown(self) -> None:
sqla.session.remove()
sqla.drop_all()
self.app_context.pop()

def setUp(self) -> None:
self.app = create_app(mode="test")
self.app_context = self.app.app_context()
self.app_context.push()
sqla.create_all()
self.collection = db.Node_collection()

def test_parse(self) -> None:
for cre_id, name in [
("304-667", "Protect API against unauthorized access/modification (IDOR)"),
("724-770", "Technical application access control"),
("715-223", "Ensure trusted origin of third party resources"),
]:
self.collection.add_cre(defs.CRE(id=cre_id, name=name, description=""))

result = owasp_api_top10_2023.OwaspApiTop10_2023().parse(
self.collection, prompt_client.PromptHandler(database=self.collection)
)

entries = result.results["OWASP API Security Top 10 2023"]
self.assertEqual(10, len(entries))
self.assertEqual("API1", entries[0].sectionID)
self.assertEqual("Broken Object Level Authorization", entries[0].section)
self.assertEqual(
["304-667", "724-770"],
[link.document.id for link in entries[0].links],
)
self.assertEqual("API10", entries[-1].sectionID)
self.assertEqual(
["715-223"],
[link.document.id for link in entries[-1].links],
)
45 changes: 45 additions & 0 deletions application/tests/owasp_llm_top10_2025_parser_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import unittest

from application import create_app, sqla # type: ignore
from application.database import db
from application.defs import cre_defs as defs
from application.prompt_client import prompt_client
from application.utils.external_project_parsers.parsers import owasp_llm_top10_2025


class TestOwaspLlmTop10_2025Parser(unittest.TestCase):
def tearDown(self) -> None:
sqla.session.remove()
sqla.drop_all()
self.app_context.pop()

def setUp(self) -> None:
self.app = create_app(mode="test")
self.app_context = self.app.app_context()
self.app_context.push()
sqla.create_all()
self.collection = db.Node_collection()

def test_parse(self) -> None:
for cre_id, name in [
("161-451", "Output encoding and injection prevention"),
("064-808", "Encode output context-specifically"),
("760-764", "Injection protection"),
("623-550", "Denial Of Service protection"),
]:
self.collection.add_cre(defs.CRE(id=cre_id, name=name, description=""))

result = owasp_llm_top10_2025.OwaspLlmTop10_2025().parse(
self.collection, prompt_client.PromptHandler(database=self.collection)
)

entries = result.results["OWASP Top 10 for LLM and Gen AI Apps 2025"]
self.assertEqual(10, len(entries))
self.assertEqual("LLM01", entries[0].sectionID)
self.assertEqual("Prompt Injection", entries[0].section)
self.assertEqual(
["161-451", "760-764"], [link.document.id for link in entries[0].links]
)
self.assertEqual(["064-808"], [link.document.id for link in entries[4].links])
self.assertEqual("LLM10", entries[-1].sectionID)
self.assertEqual(["623-550"], [link.document.id for link in entries[-1].links])
80 changes: 80 additions & 0 deletions application/tests/owasp_top10_2025_parser_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import unittest

from application import create_app, sqla # type: ignore
from application.database import db
from application.defs import cre_defs as defs
from application.prompt_client import prompt_client
from application.utils.external_project_parsers.parsers import owasp_top10_2025


class TestOwaspTop10_2025Parser(unittest.TestCase):
def tearDown(self) -> None:
sqla.session.remove()
sqla.drop_all()
self.app_context.pop()

def setUp(self) -> None:
self.app = create_app(mode="test")
self.app_context = self.app.app_context()
self.app_context.push()
sqla.create_all()
self.collection = db.Node_collection()

def test_parse(self) -> None:
self.collection.add_cre(
defs.CRE(id="177-260", name="Session management", description="")
)
self.collection.add_cre(
defs.CRE(
id="117-371",
name="Use a centralized access control mechanism",
description="",
)
)
self.collection.add_cre(
defs.CRE(
id="724-770",
name="Technical application access control",
description="",
)
)
self.collection.add_cre(
defs.CRE(
id="031-447", name="Whitelist all external (HTTP) input", description=""
)
)
self.collection.add_cre(
defs.CRE(
id="064-808", name="Encode output context-specifically", description=""
)
)
self.collection.add_cre(
defs.CRE(id="760-764", name="Injection protection", description="")
)
self.collection.add_cre(
defs.CRE(id="513-183", name="Error handling", description="")
)

result = owasp_top10_2025.OwaspTop10_2025().parse(
self.collection,
prompt_client.PromptHandler(database=self.collection),
)

entries = result.results["OWASP Top 10 2025"]
self.assertEqual(10, len(entries))
self.assertEqual("A01", entries[0].sectionID)
self.assertEqual("Broken Access Control", entries[0].section)
self.assertEqual(
"https://owasp.org/Top10/2025/A01_2025-Broken_Access_Control/",
entries[0].hyperlink,
)
self.assertEqual(
["117-371", "177-260", "724-770"],
[link.document.id for link in entries[0].links],
)
self.assertEqual(
["031-447", "064-808", "760-764"],
[link.document.id for link in entries[4].links],
)
self.assertEqual("A10", entries[-1].sectionID)
self.assertEqual(["513-183"], [link.document.id for link in entries[-1].links])
Loading
Loading