graphrag-codeproperty-graph 0.5.2__tar.gz → 0.5.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. {graphrag_codeproperty_graph-0.5.2 → graphrag_codeproperty_graph-0.5.3}/CHANGELOG.md +16 -0
  2. {graphrag_codeproperty_graph-0.5.2 → graphrag_codeproperty_graph-0.5.3}/PKG-INFO +1 -1
  3. {graphrag_codeproperty_graph-0.5.2 → graphrag_codeproperty_graph-0.5.3}/pyproject.toml +1 -1
  4. {graphrag_codeproperty_graph-0.5.2 → graphrag_codeproperty_graph-0.5.3}/src/codeproperty_graph/graph_loader.py +36 -2
  5. graphrag_codeproperty_graph-0.5.3/tests/test_graph_loader_neptune_safe_props.py +75 -0
  6. {graphrag_codeproperty_graph-0.5.2 → graphrag_codeproperty_graph-0.5.3}/.github/workflows/publish.yml +0 -0
  7. {graphrag_codeproperty_graph-0.5.2 → graphrag_codeproperty_graph-0.5.3}/.gitignore +0 -0
  8. {graphrag_codeproperty_graph-0.5.2 → graphrag_codeproperty_graph-0.5.3}/CONTRIBUTING.md +0 -0
  9. {graphrag_codeproperty_graph-0.5.2 → graphrag_codeproperty_graph-0.5.3}/LICENSE +0 -0
  10. {graphrag_codeproperty_graph-0.5.2 → graphrag_codeproperty_graph-0.5.3}/NOTICE +0 -0
  11. {graphrag_codeproperty_graph-0.5.2 → graphrag_codeproperty_graph-0.5.3}/README.md +0 -0
  12. {graphrag_codeproperty_graph-0.5.2 → graphrag_codeproperty_graph-0.5.3}/docs/ARCHITECTURE.md +0 -0
  13. {graphrag_codeproperty_graph-0.5.2 → graphrag_codeproperty_graph-0.5.3}/docs/Defining the Master Evidence Graph: A Formal Model for Stateful Software Verdicts.md +0 -0
  14. {graphrag_codeproperty_graph-0.5.2 → graphrag_codeproperty_graph-0.5.3}/docs/HYBRID-GRAPH.md +0 -0
  15. {graphrag_codeproperty_graph-0.5.2 → graphrag_codeproperty_graph-0.5.3}/docs/NOTICE.md +0 -0
  16. {graphrag_codeproperty_graph-0.5.2 → graphrag_codeproperty_graph-0.5.3}/docs/Toward a Master Evidence Graph for Software Verdicts.md +0 -0
  17. {graphrag_codeproperty_graph-0.5.2 → graphrag_codeproperty_graph-0.5.3}/docs/graphrag_com_redrawn_architecture.md +0 -0
  18. {graphrag_codeproperty_graph-0.5.2 → graphrag_codeproperty_graph-0.5.3}/docs/graphrag_phased_architecture.md +0 -0
  19. {graphrag_codeproperty_graph-0.5.2 → graphrag_codeproperty_graph-0.5.3}/docs/neptune_vs_neptune_analytics_cpg_rag_architecture copy.md +0 -0
  20. {graphrag_codeproperty_graph-0.5.2 → graphrag_codeproperty_graph-0.5.3}/docs/neptune_vs_neptune_analytics_cpg_rag_architecture.md +0 -0
  21. {graphrag_codeproperty_graph-0.5.2 → graphrag_codeproperty_graph-0.5.3}/examples/README.md +0 -0
  22. {graphrag_codeproperty_graph-0.5.2 → graphrag_codeproperty_graph-0.5.3}/examples/notebooks/01-CPG-Models-and-GraphDiff.ipynb +0 -0
  23. {graphrag_codeproperty_graph-0.5.2 → graphrag_codeproperty_graph-0.5.3}/examples/notebooks/02-Delta-Ingestion-Pipeline.ipynb +0 -0
  24. {graphrag_codeproperty_graph-0.5.2 → graphrag_codeproperty_graph-0.5.3}/examples/notebooks/data/sample_edges.json +0 -0
  25. {graphrag_codeproperty_graph-0.5.2 → graphrag_codeproperty_graph-0.5.3}/examples/notebooks/data/sample_nodes.json +0 -0
  26. {graphrag_codeproperty_graph-0.5.2 → graphrag_codeproperty_graph-0.5.3}/sbom/AWS-SERVICES.md +0 -0
  27. {graphrag_codeproperty_graph-0.5.2 → graphrag_codeproperty_graph-0.5.3}/sbom/SBOM.md +0 -0
  28. {graphrag_codeproperty_graph-0.5.2 → graphrag_codeproperty_graph-0.5.3}/sbom/codeproperty-graph.cdx.json +0 -0
  29. {graphrag_codeproperty_graph-0.5.2 → graphrag_codeproperty_graph-0.5.3}/src/codeproperty_graph/__init__.py +0 -0
  30. {graphrag_codeproperty_graph-0.5.2 → graphrag_codeproperty_graph-0.5.3}/src/codeproperty_graph/artifact_reader.py +0 -0
  31. {graphrag_codeproperty_graph-0.5.2 → graphrag_codeproperty_graph-0.5.3}/src/codeproperty_graph/artifact_validator.py +0 -0
  32. {graphrag_codeproperty_graph-0.5.2 → graphrag_codeproperty_graph-0.5.3}/src/codeproperty_graph/code_slice_store.py +0 -0
  33. {graphrag_codeproperty_graph-0.5.2 → graphrag_codeproperty_graph-0.5.3}/src/codeproperty_graph/cpg_service.py +0 -0
  34. {graphrag_codeproperty_graph-0.5.2 → graphrag_codeproperty_graph-0.5.3}/src/codeproperty_graph/delta_ingestor.py +0 -0
  35. {graphrag_codeproperty_graph-0.5.2 → graphrag_codeproperty_graph-0.5.3}/src/codeproperty_graph/graph_diff.py +0 -0
  36. {graphrag_codeproperty_graph-0.5.2 → graphrag_codeproperty_graph-0.5.3}/src/codeproperty_graph/graphson_converter.py +0 -0
  37. {graphrag_codeproperty_graph-0.5.2 → graphrag_codeproperty_graph-0.5.3}/src/codeproperty_graph/manifest_manager.py +0 -0
  38. {graphrag_codeproperty_graph-0.5.2 → graphrag_codeproperty_graph-0.5.3}/src/codeproperty_graph/models.py +0 -0
  39. {graphrag_codeproperty_graph-0.5.2 → graphrag_codeproperty_graph-0.5.3}/src/codeproperty_graph/schema.py +0 -0
  40. {graphrag_codeproperty_graph-0.5.2 → graphrag_codeproperty_graph-0.5.3}/src/codeproperty_graph/summary_overlay.py +0 -0
  41. {graphrag_codeproperty_graph-0.5.2 → graphrag_codeproperty_graph-0.5.3}/src/codeproperty_graph/tenant_ops.py +0 -0
  42. {graphrag_codeproperty_graph-0.5.2 → graphrag_codeproperty_graph-0.5.3}/src/codeproperty_graph/vector_loader.py +0 -0
  43. {graphrag_codeproperty_graph-0.5.2 → graphrag_codeproperty_graph-0.5.3}/tests/__init__.py +0 -0
  44. {graphrag_codeproperty_graph-0.5.2 → graphrag_codeproperty_graph-0.5.3}/tests/test_codeproperty_graph.py +0 -0
  45. {graphrag_codeproperty_graph-0.5.2 → graphrag_codeproperty_graph-0.5.3}/tests/test_cpg_service.py +0 -0
  46. {graphrag_codeproperty_graph-0.5.2 → graphrag_codeproperty_graph-0.5.3}/tests/test_delta_ingestor_embedding_property.py +0 -0
@@ -2,6 +2,22 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [0.5.3] - 2026-09-16
6
+
7
+ ### Fixed
8
+ - **`GraphLoader` now coerces all node/edge properties to Neptune-safe scalar
9
+ literals before writing.** Neptune Database openCypher rejects list/dict/tuple/set
10
+ property values ("Property value must be a simple literal"). Joern's raw node/edge
11
+ `properties` (merged verbatim in `_node_to_write_dict` / `_edge_to_write_dict`) can
12
+ contain collection values — e.g. Java `modifiers`, `annotations`, `parameterTypes`,
13
+ edge `argIndexList` — which would fail the primary node/edge write the same way the
14
+ 0.5.2 embedding write did. A new `_neptune_safe_properties` helper JSON-serializes
15
+ collection values to compact strings (preserving the data as a queryable scalar,
16
+ since these Joern properties have no other store) and drops `None`. Applied at the
17
+ single write boundary so every node and edge is Neptune-safe regardless of what the
18
+ Joern export contains. Covered by `tests/test_graph_loader_neptune_safe_props.py`.
19
+ (PSAPI-66782.)
20
+
5
21
  ## [0.5.2] - 2026-09-16
6
22
 
7
23
  ### Fixed
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: graphrag-codeproperty-graph
3
- Version: 0.5.2
3
+ Version: 0.5.3
4
4
  Summary: Code Property Graphs — Joern/Semgrep extraction, AI vulnerability enrichment, risk scoring
5
5
  Project-URL: Repository, https://github.com/kanjani-ai-research/codeproperty-graph
6
6
  Author-email: Evan Erwee <evan@erwee.com>
@@ -7,7 +7,7 @@ packages = ["src/codeproperty_graph"]
7
7
 
8
8
  [project]
9
9
  name = "graphrag-codeproperty-graph"
10
- version = "0.5.2"
10
+ version = "0.5.3"
11
11
  description = "Code Property Graphs — Joern/Semgrep extraction, AI vulnerability enrichment, risk scoring"
12
12
  readme = "README.md"
13
13
  requires-python = ">=3.11"
@@ -7,6 +7,7 @@ Converts raw artifact dicts (from nodes.jsonl / edges.jsonl) into typed CPG
7
7
  models and writes them in batches to a graph store, applying tenant isolation.
8
8
  """
9
9
 
10
+ import json
10
11
  import logging
11
12
  from typing import Any, Protocol, runtime_checkable
12
13
 
@@ -15,6 +16,35 @@ from .models import CPGNode, CPGEdge
15
16
  logger = logging.getLogger(__name__)
16
17
 
17
18
 
19
+ def _neptune_safe_properties(properties: dict) -> dict:
20
+ """Coerce a property dict to Neptune-Database-safe SCALAR values.
21
+
22
+ Neptune Database openCypher only accepts simple-literal property values —
23
+ it rejects list/dict/tuple/set with "Property value must be a simple
24
+ literal". Joern's raw node/edge properties can contain collection values
25
+ (e.g. Java `modifiers`, `annotations`, `parameterTypes`), which would fail
26
+ the write. Unlike the embedding vector (which lives in the vector store),
27
+ these Joern properties have no other home, so we PRESERVE them as a compact
28
+ JSON string rather than dropping them — keeping the data queryable as a
29
+ scalar. `None` values are dropped (Neptune stores nothing for them).
30
+ """
31
+ safe = {}
32
+ for key, value in (properties or {}).items():
33
+ if value is None:
34
+ continue
35
+ if isinstance(value, (list, tuple, set, dict)):
36
+ try:
37
+ safe[key] = json.dumps(
38
+ list(value) if isinstance(value, (tuple, set)) else value,
39
+ ensure_ascii=False, default=str,
40
+ )
41
+ except (TypeError, ValueError):
42
+ safe[key] = str(value)
43
+ else:
44
+ safe[key] = value
45
+ return safe
46
+
47
+
18
48
  @runtime_checkable
19
49
  class GraphStoreProtocol(Protocol):
20
50
  """Protocol for graph store backends (e.g., Neptune)."""
@@ -220,7 +250,9 @@ class GraphLoader:
220
250
  return {
221
251
  "id": node.id,
222
252
  "label": f"{self._tenant_id}__{node.node_type}",
223
- "properties": properties,
253
+ # Neptune Database rejects non-scalar property values; coerce
254
+ # collection-valued Joern properties to JSON strings.
255
+ "properties": _neptune_safe_properties(properties),
224
256
  }
225
257
 
226
258
  def _edge_to_write_dict(self, edge: CPGEdge) -> dict:
@@ -244,5 +276,7 @@ class GraphLoader:
244
276
  "source_id": edge.source_id,
245
277
  "target_id": edge.target_id,
246
278
  "edge_type": edge.edge_type,
247
- "properties": properties,
279
+ # Neptune Database rejects non-scalar property values; coerce
280
+ # collection-valued Joern edge properties to JSON strings.
281
+ "properties": _neptune_safe_properties(properties),
248
282
  }
@@ -0,0 +1,75 @@
1
+ """GraphLoader must coerce node/edge properties to Neptune-safe scalars.
2
+
3
+ Neptune Database openCypher rejects list/dict/tuple/set property values
4
+ ("Property value must be a simple literal"). Joern's raw node/edge properties
5
+ can contain collection values (Java modifiers, annotations, parameterTypes, ...),
6
+ so GraphLoader serializes them to JSON strings at the write boundary — preserving
7
+ the data as a queryable scalar rather than failing the write.
8
+ """
9
+
10
+ import json
11
+ import pytest
12
+
13
+ from codeproperty_graph.graph_loader import _neptune_safe_properties, GraphLoader
14
+ from codeproperty_graph.models import CPGNode, CPGEdge
15
+
16
+
17
+ def test_sanitizer_json_encodes_collections_and_keeps_scalars():
18
+ props = {
19
+ "name": "ProductController", # str scalar → kept
20
+ "line_number": 42, # int scalar → kept
21
+ "is_external": False, # bool scalar → kept
22
+ "modifiers": ["public", "final"], # list → JSON string
23
+ "annotations": {"RestController": {}}, # dict → JSON string
24
+ "parameterTypes": ("int", "String"), # tuple → JSON string
25
+ "tags": {"a", "b"}, # set → JSON string
26
+ "nothing": None, # None → dropped
27
+ }
28
+ out = _neptune_safe_properties(props)
29
+
30
+ # scalars unchanged
31
+ assert out["name"] == "ProductController"
32
+ assert out["line_number"] == 42
33
+ assert out["is_external"] is False
34
+ # None dropped
35
+ assert "nothing" not in out
36
+ # collections became strings, round-trippable
37
+ assert isinstance(out["modifiers"], str)
38
+ assert json.loads(out["modifiers"]) == ["public", "final"]
39
+ assert isinstance(out["annotations"], str)
40
+ assert json.loads(out["annotations"]) == {"RestController": {}}
41
+ assert isinstance(out["parameterTypes"], str)
42
+ assert json.loads(out["parameterTypes"]) == ["int", "String"]
43
+ assert isinstance(out["tags"], str) # set serialized (order not asserted)
44
+ # EVERY value is now a Neptune-safe scalar literal
45
+ for k, v in out.items():
46
+ assert not isinstance(v, (list, dict, tuple, set)), k
47
+
48
+
49
+ def test_node_write_dict_has_only_scalar_properties():
50
+ loader = GraphLoader.__new__(GraphLoader)
51
+ loader._tenant_id = "apm1"
52
+ node = CPGNode.from_artifact({
53
+ "cpg_node_id": "n1",
54
+ "node_type": "METHOD",
55
+ "full_name": "com.app.A.m",
56
+ "properties": {"modifiers": ["public"], "annotations": ["@Override"]},
57
+ })
58
+ wd = loader._node_to_write_dict(node)
59
+ for k, v in wd["properties"].items():
60
+ assert not isinstance(v, (list, dict, tuple, set)), (k, type(v))
61
+
62
+
63
+ def test_edge_write_dict_has_only_scalar_properties():
64
+ loader = GraphLoader.__new__(GraphLoader)
65
+ loader._tenant_id = "apm1"
66
+ edge = CPGEdge.from_artifact({
67
+ "edge_id": "e1",
68
+ "source_cpg_node_id": "n1",
69
+ "target_cpg_node_id": "n2",
70
+ "edge_type": "CALL",
71
+ "properties": {"argIndexList": [0, 1, 2]},
72
+ })
73
+ wd = loader._edge_to_write_dict(edge)
74
+ for k, v in wd["properties"].items():
75
+ assert not isinstance(v, (list, dict, tuple, set)), (k, type(v))