Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions graphify/manifest_ingest.py
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,11 @@ def _parse_gomod(text: str) -> dict | None:


def _parse_pom(text: str) -> dict | None:
# ElementTree does not cap entity expansion, so reject declarations before
# parsing rather than allowing a crafted POM to consume excessive memory.
lowered = text.lower()
if "<!doctype" in lowered or "<!entity" in lowered:
raise ValueError("refusing XML with DOCTYPE/ENTITY declaration")
# Drop the default namespace so findtext/findall don't need the {uri} prefix.
text = re.sub(r'\sxmlns="[^"]*"', '', text, count=1)
root = ET.fromstring(text)
Expand Down
11 changes: 10 additions & 1 deletion tests/test_manifest_ingest.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ def test_gomod_parses_module_and_requires(tmp_path):
assert "pkg_github_com_x_y" in deps and "pkg_github_com_a_b" in deps


def test_pom_parses_artifact_and_deps(tmp_path):
def test_namespaced_pom_parses_artifact_and_deps(tmp_path):
p = _write(tmp_path / "pom.xml",
'<project xmlns="http://maven.apache.org/POM/4.0.0">\n'
' <groupId>com.acme</groupId>\n <artifactId>widget</artifactId>\n <version>2.0</version>\n'
Expand All @@ -75,6 +75,15 @@ def test_pom_parses_artifact_and_deps(tmp_path):
assert any(e["target"] == "pkg_org_lib_core" for e in r["edges"])


def test_pom_with_internal_entity_is_rejected_before_parsing(tmp_path):
p = _write(tmp_path / "pom.xml",
'<!DOCTYPE project [<!ENTITY artifact "expanded-widget">]>\n'
'<project><artifactId>&artifact;</artifactId></project>\n')
r = extract_package_manifest(p)
assert r["nodes"] == [] and r["edges"] == []
assert r["error"] == "manifest parse error: refusing XML with DOCTYPE/ENTITY declaration"


# ── #1377: a package referenced by N manifests is ONE node ───────────────────

def test_apm_dependency_collapses_to_single_canonical_node(tmp_path):
Expand Down