diff --git a/graphify/manifest_ingest.py b/graphify/manifest_ingest.py
index ae3aa61fc..18f39fffd 100644
--- a/graphify/manifest_ingest.py
+++ b/graphify/manifest_ingest.py
@@ -226,17 +226,20 @@ def _parse_pom(text: str) -> dict | None:
text = re.sub(r'\sxmlns="[^"]*"', '', text, count=1)
root = ET.fromstring(text)
aid = root.findtext("artifactId")
- gid = root.findtext("groupId")
+ gid = root.findtext("groupId") or root.findtext("parent/groupId")
+ version = root.findtext("version") or root.findtext("parent/version")
if not aid:
return None
name = f"{gid}:{aid}" if gid else aid
deps: list[str] = []
- for dep in root.findall(".//dependencies/dependency"):
+ project_deps = root.findall("dependencies/dependency")
+ profile_deps = root.findall("profiles/profile/dependencies/dependency")
+ for dep in project_deps + profile_deps:
da = dep.findtext("artifactId")
dg = dep.findtext("groupId")
if da:
deps.append(f"{dg}:{da}" if dg else da)
- return {"name": name, "version": root.findtext("version"), "deps": deps}
+ return {"name": name, "version": version, "deps": deps}
_PARSERS = {
diff --git a/tests/test_manifest_ingest.py b/tests/test_manifest_ingest.py
index 2b97f5fb9..74181b595 100644
--- a/tests/test_manifest_ingest.py
+++ b/tests/test_manifest_ingest.py
@@ -75,6 +75,55 @@ 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_includes_only_top_level_dependencies(tmp_path):
+ p = _write(tmp_path / "pom.xml",
+ 'com.acmeapp'
+ 'org.lib'
+ 'runtime')
+ r = extract_package_manifest(p)
+ deps = {e["target"] for e in r["edges"] if e["relation"] == "depends_on"}
+ assert deps == {"pkg_org_lib_runtime"}
+
+
+def test_pom_excludes_dependency_management_and_plugin_dependencies(tmp_path):
+ p = _write(tmp_path / "pom.xml",
+ 'com.acmeapp'
+ 'org.managed'
+ 'bom-entry'
+ 'org.plugin'
+ 'helper'
+ '')
+ r = extract_package_manifest(p)
+ deps = {e["target"] for e in r["edges"] if e["relation"] == "depends_on"}
+ assert deps == set()
+
+
+def test_pom_uses_parent_group_id_when_project_group_id_is_missing(tmp_path):
+ p = _write(tmp_path / "pom.xml",
+ 'com.parentparent'
+ '1.0child')
+ r = extract_package_manifest(p)
+ assert _pkg_nodes(r)[0]["label"] == "com.parent:child"
+
+
+def test_pom_uses_parent_version_when_project_version_is_missing(tmp_path):
+ p = _write(tmp_path / "pom.xml",
+ 'com.parentparent'
+ '1.2.3child')
+ r = extract_package_manifest(p)
+ assert _pkg_nodes(r)[0]["version"] == "1.2.3"
+
+
+def test_pom_includes_profile_dependencies(tmp_path):
+ p = _write(tmp_path / "pom.xml",
+ 'com.acmeapp'
+ 'optional-featureorg.profile'
+ 'feature')
+ r = extract_package_manifest(p)
+ deps = {e["target"] for e in r["edges"] if e["relation"] == "depends_on"}
+ assert deps == {"pkg_org_profile_feature"}
+
+
# ── #1377: a package referenced by N manifests is ONE node ───────────────────
def test_apm_dependency_collapses_to_single_canonical_node(tmp_path):