graphrag-codeproperty-graph 0.5.0__tar.gz → 0.5.2__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.
- graphrag_codeproperty_graph-0.5.2/CHANGELOG.md +82 -0
- {graphrag_codeproperty_graph-0.5.0 → graphrag_codeproperty_graph-0.5.2}/PKG-INFO +53 -13
- {graphrag_codeproperty_graph-0.5.0 → graphrag_codeproperty_graph-0.5.2}/README.md +52 -12
- {graphrag_codeproperty_graph-0.5.0 → graphrag_codeproperty_graph-0.5.2}/pyproject.toml +1 -1
- {graphrag_codeproperty_graph-0.5.0 → graphrag_codeproperty_graph-0.5.2}/src/codeproperty_graph/delta_ingestor.py +1 -0
- {graphrag_codeproperty_graph-0.5.0 → graphrag_codeproperty_graph-0.5.2}/src/codeproperty_graph/vector_loader.py +22 -4
- graphrag_codeproperty_graph-0.5.2/tests/test_delta_ingestor_embedding_property.py +129 -0
- graphrag_codeproperty_graph-0.5.0/CHANGELOG.md +0 -16
- {graphrag_codeproperty_graph-0.5.0 → graphrag_codeproperty_graph-0.5.2}/.github/workflows/publish.yml +0 -0
- {graphrag_codeproperty_graph-0.5.0 → graphrag_codeproperty_graph-0.5.2}/.gitignore +0 -0
- {graphrag_codeproperty_graph-0.5.0 → graphrag_codeproperty_graph-0.5.2}/CONTRIBUTING.md +0 -0
- {graphrag_codeproperty_graph-0.5.0 → graphrag_codeproperty_graph-0.5.2}/LICENSE +0 -0
- {graphrag_codeproperty_graph-0.5.0 → graphrag_codeproperty_graph-0.5.2}/NOTICE +0 -0
- {graphrag_codeproperty_graph-0.5.0 → graphrag_codeproperty_graph-0.5.2}/docs/ARCHITECTURE.md +0 -0
- {graphrag_codeproperty_graph-0.5.0 → graphrag_codeproperty_graph-0.5.2}/docs/Defining the Master Evidence Graph: A Formal Model for Stateful Software Verdicts.md +0 -0
- {graphrag_codeproperty_graph-0.5.0 → graphrag_codeproperty_graph-0.5.2}/docs/HYBRID-GRAPH.md +0 -0
- {graphrag_codeproperty_graph-0.5.0 → graphrag_codeproperty_graph-0.5.2}/docs/NOTICE.md +0 -0
- {graphrag_codeproperty_graph-0.5.0 → graphrag_codeproperty_graph-0.5.2}/docs/Toward a Master Evidence Graph for Software Verdicts.md +0 -0
- {graphrag_codeproperty_graph-0.5.0 → graphrag_codeproperty_graph-0.5.2}/docs/graphrag_com_redrawn_architecture.md +0 -0
- {graphrag_codeproperty_graph-0.5.0 → graphrag_codeproperty_graph-0.5.2}/docs/graphrag_phased_architecture.md +0 -0
- {graphrag_codeproperty_graph-0.5.0 → graphrag_codeproperty_graph-0.5.2}/docs/neptune_vs_neptune_analytics_cpg_rag_architecture copy.md +0 -0
- {graphrag_codeproperty_graph-0.5.0 → graphrag_codeproperty_graph-0.5.2}/docs/neptune_vs_neptune_analytics_cpg_rag_architecture.md +0 -0
- {graphrag_codeproperty_graph-0.5.0 → graphrag_codeproperty_graph-0.5.2}/examples/README.md +0 -0
- {graphrag_codeproperty_graph-0.5.0 → graphrag_codeproperty_graph-0.5.2}/examples/notebooks/01-CPG-Models-and-GraphDiff.ipynb +0 -0
- {graphrag_codeproperty_graph-0.5.0 → graphrag_codeproperty_graph-0.5.2}/examples/notebooks/02-Delta-Ingestion-Pipeline.ipynb +0 -0
- {graphrag_codeproperty_graph-0.5.0 → graphrag_codeproperty_graph-0.5.2}/examples/notebooks/data/sample_edges.json +0 -0
- {graphrag_codeproperty_graph-0.5.0 → graphrag_codeproperty_graph-0.5.2}/examples/notebooks/data/sample_nodes.json +0 -0
- {graphrag_codeproperty_graph-0.5.0 → graphrag_codeproperty_graph-0.5.2}/sbom/AWS-SERVICES.md +0 -0
- {graphrag_codeproperty_graph-0.5.0 → graphrag_codeproperty_graph-0.5.2}/sbom/SBOM.md +0 -0
- {graphrag_codeproperty_graph-0.5.0 → graphrag_codeproperty_graph-0.5.2}/sbom/codeproperty-graph.cdx.json +0 -0
- {graphrag_codeproperty_graph-0.5.0 → graphrag_codeproperty_graph-0.5.2}/src/codeproperty_graph/__init__.py +0 -0
- {graphrag_codeproperty_graph-0.5.0 → graphrag_codeproperty_graph-0.5.2}/src/codeproperty_graph/artifact_reader.py +0 -0
- {graphrag_codeproperty_graph-0.5.0 → graphrag_codeproperty_graph-0.5.2}/src/codeproperty_graph/artifact_validator.py +0 -0
- {graphrag_codeproperty_graph-0.5.0 → graphrag_codeproperty_graph-0.5.2}/src/codeproperty_graph/code_slice_store.py +0 -0
- {graphrag_codeproperty_graph-0.5.0 → graphrag_codeproperty_graph-0.5.2}/src/codeproperty_graph/cpg_service.py +0 -0
- {graphrag_codeproperty_graph-0.5.0 → graphrag_codeproperty_graph-0.5.2}/src/codeproperty_graph/graph_diff.py +0 -0
- {graphrag_codeproperty_graph-0.5.0 → graphrag_codeproperty_graph-0.5.2}/src/codeproperty_graph/graph_loader.py +0 -0
- {graphrag_codeproperty_graph-0.5.0 → graphrag_codeproperty_graph-0.5.2}/src/codeproperty_graph/graphson_converter.py +0 -0
- {graphrag_codeproperty_graph-0.5.0 → graphrag_codeproperty_graph-0.5.2}/src/codeproperty_graph/manifest_manager.py +0 -0
- {graphrag_codeproperty_graph-0.5.0 → graphrag_codeproperty_graph-0.5.2}/src/codeproperty_graph/models.py +0 -0
- {graphrag_codeproperty_graph-0.5.0 → graphrag_codeproperty_graph-0.5.2}/src/codeproperty_graph/schema.py +0 -0
- {graphrag_codeproperty_graph-0.5.0 → graphrag_codeproperty_graph-0.5.2}/src/codeproperty_graph/summary_overlay.py +0 -0
- {graphrag_codeproperty_graph-0.5.0 → graphrag_codeproperty_graph-0.5.2}/src/codeproperty_graph/tenant_ops.py +0 -0
- {graphrag_codeproperty_graph-0.5.0 → graphrag_codeproperty_graph-0.5.2}/tests/__init__.py +0 -0
- {graphrag_codeproperty_graph-0.5.0 → graphrag_codeproperty_graph-0.5.2}/tests/test_codeproperty_graph.py +0 -0
- {graphrag_codeproperty_graph-0.5.0 → graphrag_codeproperty_graph-0.5.2}/tests/test_cpg_service.py +0 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [Unreleased]
|
|
4
|
+
|
|
5
|
+
## [0.5.2] - 2026-09-16
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
- **`VectorLoader` no longer writes the raw embedding vector as a Neptune node
|
|
9
|
+
property.** The 0.5.1 on-node write (`SET n += {embedding: <array>, ...}`) was a
|
|
10
|
+
Neo4j-era pattern: Neo4j stores list-valued properties, but the graph backend is
|
|
11
|
+
now Neptune Database, whose openCypher rejects arrays ("Property value must be a
|
|
12
|
+
simple literal"). Every per-node write failed with `BadRequestException`, flooding
|
|
13
|
+
the ingest log with warnings. The embedding **vector** already lives in the vector
|
|
14
|
+
store (AOSS/OpenSearch), which is the sole surface used for kNN retrieval — nothing
|
|
15
|
+
reads the on-node vector. `VectorLoader.load` now writes only **scalar embedding
|
|
16
|
+
provenance** to the node (`hasEmbedding`, `embeddingModel`, `embeddingDimensions`,
|
|
17
|
+
`embeddingTarget`, `embeddedTime`), which Neptune accepts, preserving the
|
|
18
|
+
graph-side "this node has an embedding" signal without duplicating unqueryable data.
|
|
19
|
+
Covered by `tests/test_delta_ingestor_embedding_property.py`
|
|
20
|
+
(`test_vector_loader_writes_scalar_provenance_not_array`). (PSAPI-66782.)
|
|
21
|
+
|
|
22
|
+
## [0.5.1] - 2026-09-15
|
|
23
|
+
|
|
24
|
+
### Fixed
|
|
25
|
+
- **`DeltaIngestor.ingest_artifact` now passes `graph_store` to `VectorLoader`.**
|
|
26
|
+
Previously `VectorLoader` was constructed with only `vector_store`, so the
|
|
27
|
+
`graph_store`-guarded step in `VectorLoader.load` — writing each embedding as an
|
|
28
|
+
`embedding` property on the Neptune node (`update_node_properties`) — never
|
|
29
|
+
fired. This restores the client-schema behaviour where CPG nodes carry their
|
|
30
|
+
embedding on the graph node (matching the original cpg-embedding-agent's
|
|
31
|
+
`SET n.embedding`), in addition to the OpenSearch vector index. One-line wiring
|
|
32
|
+
fix; the `SummaryOverlay`/`CodeSliceStore`/`GraphLoader` in the same method
|
|
33
|
+
already received `graph_store`. Covered by
|
|
34
|
+
`tests/test_delta_ingestor_embedding_property.py`. (PSAPI-66782, alignment wave W2.2.)
|
|
35
|
+
|
|
36
|
+
## [0.5.0] - 2026-08-20
|
|
37
|
+
|
|
38
|
+
### Added
|
|
39
|
+
- **CPGService** — node-level delta filtering for Neptune ingestion
|
|
40
|
+
- Only writes changed/added METHOD subtrees (not all nodes)
|
|
41
|
+
- AST edge traversal identifies child node ownership
|
|
42
|
+
- Surgical removal of deleted methods via `remove_fn` callback
|
|
43
|
+
- First run (no manifest): full ingest; incremental: filtered by diff
|
|
44
|
+
- 60-90% reduction in Neptune write volume on incremental runs
|
|
45
|
+
- Full artifact pipeline modules (previously in private wheel):
|
|
46
|
+
- `ArtifactReader` — S3 artifact reading and parsing
|
|
47
|
+
- `ArtifactValidator` — schema compliance validation before ingest
|
|
48
|
+
- `GraphLoader` — Neptune batch write with retry cascade
|
|
49
|
+
- `VectorLoader` — OpenSearch Serverless vector ingestion
|
|
50
|
+
- `SummaryOverlay` — LLM summary → Neptune node properties
|
|
51
|
+
- `CodeSliceStore` — source evidence → Neptune node properties
|
|
52
|
+
- `GraphSONConverter` — GraphSON format conversion
|
|
53
|
+
- `Schema` — full Joern CPG schema (20 node types, 14+ edge types)
|
|
54
|
+
- Optimistic locking in ManifestManager (ETag-based)
|
|
55
|
+
- `ManifestConflictError` for concurrent write detection
|
|
56
|
+
- `delete_domain()` and `list_domains()` in tenant_ops
|
|
57
|
+
- Full CPG schema support in models (VectorRecord, SummaryRecord, CodeSliceRecord)
|
|
58
|
+
- 5 new tests for CPGService delta filtering (14 total)
|
|
59
|
+
|
|
60
|
+
### Changed
|
|
61
|
+
- DeltaIngestor extended with full artifact pipeline (`ingest_artifact`)
|
|
62
|
+
- ManifestManager now supports rollback and optimistic locking
|
|
63
|
+
- Models expanded with full Joern node/edge type documentation
|
|
64
|
+
|
|
65
|
+
### Dependencies
|
|
66
|
+
- Added `boto3>=1.28.0`
|
|
67
|
+
- `graphrag-document-graph>=3.1.1` (bumped from 3.0.8)
|
|
68
|
+
|
|
69
|
+
## [0.4.3] - 2026-08-03
|
|
70
|
+
|
|
71
|
+
### Added
|
|
72
|
+
- Initial public release
|
|
73
|
+
- Joern/Semgrep CPG extraction and ingestion
|
|
74
|
+
- Delta ingestion — skip-or-replace logic to minimize Neptune writes
|
|
75
|
+
- Graph diff comparison between CPG states
|
|
76
|
+
- S3-backed manifest management for repository state tracking
|
|
77
|
+
- AI vulnerability enrichment and risk scoring
|
|
78
|
+
- Tenant lifecycle management (create, purge, replace)
|
|
79
|
+
- CPGNode and CPGEdge Pydantic models (Joern-specific types)
|
|
80
|
+
|
|
81
|
+
### Dependencies
|
|
82
|
+
- graphrag-document-graph>=3.0.8
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: graphrag-codeproperty-graph
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.2
|
|
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>
|
|
@@ -40,9 +40,8 @@ pip install graphrag-codeproperty-graph
|
|
|
40
40
|
|
|
41
41
|
## Dependencies
|
|
42
42
|
|
|
43
|
-
- `graphrag-document-graph>=3.
|
|
44
|
-
|
|
45
|
-
This package does **not** depend on `bona`.
|
|
43
|
+
- `graphrag-document-graph>=3.1.1` — Document graph infrastructure (typed nodes, Cypher builders, multi-tenancy)
|
|
44
|
+
- `boto3>=1.28.0` — AWS SDK for S3 manifest storage and service integrations
|
|
46
45
|
|
|
47
46
|
## Dependency Chain
|
|
48
47
|
|
|
@@ -57,12 +56,38 @@ graphrag-codeproperty-graph
|
|
|
57
56
|
|
|
58
57
|
## Quick Start
|
|
59
58
|
|
|
60
|
-
###
|
|
59
|
+
### CPGService — Delta Node-Level Filtering (Recommended)
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
from codeproperty_graph import CPGService
|
|
63
|
+
|
|
64
|
+
# Only writes changed/added method subtrees to Neptune
|
|
65
|
+
service = CPGService(bucket="graphrag-artifacts-705909755305")
|
|
66
|
+
|
|
67
|
+
result = await service.ingest(
|
|
68
|
+
repo="my-service",
|
|
69
|
+
job_id="build-456",
|
|
70
|
+
tenant_id="tenant_abc123",
|
|
71
|
+
nodes_data=joern_nodes,
|
|
72
|
+
edges_data=joern_edges,
|
|
73
|
+
nodes_path="s3://bucket/cpg-exports/my-service/build-456/nodes.json",
|
|
74
|
+
edges_path="s3://bucket/cpg-exports/my-service/build-456/edges.json",
|
|
75
|
+
graph_store=neptune_store,
|
|
76
|
+
write_fn=batch_write_function,
|
|
77
|
+
remove_fn=remove_method_subgraph, # optional: surgical deletion
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
# result: {"status": "SKIPPED"} — no changes
|
|
81
|
+
# result: {"status": "INGESTED", "delta": "+5 -2 ~3 =150",
|
|
82
|
+
# "filtered_nodes": 47, "total_nodes": 5123}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### DeltaIngestor — Full Artifact Pipeline
|
|
61
86
|
|
|
62
87
|
```python
|
|
63
|
-
from codeproperty_graph import DeltaIngestor
|
|
88
|
+
from codeproperty_graph import DeltaIngestor
|
|
64
89
|
|
|
65
|
-
#
|
|
90
|
+
# Full pipeline: graph + vectors + summaries + code slices
|
|
66
91
|
ingestor = DeltaIngestor(bucket="graphrag-artifacts-705909755305")
|
|
67
92
|
|
|
68
93
|
result = await ingestor.ingest(
|
|
@@ -116,12 +141,21 @@ previous = await manager.load(repo="my-service")
|
|
|
116
141
|
|
|
117
142
|
```
|
|
118
143
|
src/codeproperty_graph/
|
|
119
|
-
├── __init__.py # Public API
|
|
120
|
-
├── models.py # CPGNode, CPGEdge, Manifest
|
|
144
|
+
├── __init__.py # Public API (30 exports)
|
|
145
|
+
├── models.py # CPGNode, CPGEdge, Manifest, VectorRecord, SummaryRecord, CodeSliceRecord
|
|
146
|
+
├── schema.py # Full Joern CPG schema (20 node types, 14 edge types)
|
|
121
147
|
├── graph_diff.py # Compare two CPG states by method signature
|
|
122
|
-
├── manifest_manager.py # S3-backed state tracking
|
|
123
|
-
├── delta_ingestor.py #
|
|
124
|
-
|
|
148
|
+
├── manifest_manager.py # S3-backed state tracking with optimistic locking
|
|
149
|
+
├── delta_ingestor.py # Full artifact pipeline orchestration
|
|
150
|
+
├── cpg_service.py # Node-level delta filtering (only write changed methods)
|
|
151
|
+
├── tenant_ops.py # Lifecycle management (delete_tenant, delete_domain)
|
|
152
|
+
├── artifact_reader.py # S3 artifact reading and parsing
|
|
153
|
+
├── artifact_validator.py # Schema compliance validation
|
|
154
|
+
├── graph_loader.py # Neptune batch write with retry cascade
|
|
155
|
+
├── vector_loader.py # OpenSearch Serverless vector ingestion
|
|
156
|
+
├── summary_overlay.py # LLM summaries → Neptune node properties
|
|
157
|
+
├── code_slice_store.py # Source evidence → Neptune node properties
|
|
158
|
+
└── graphson_converter.py # GraphSON format conversion
|
|
125
159
|
```
|
|
126
160
|
|
|
127
161
|
## Integration
|
|
@@ -149,7 +183,13 @@ src/codeproperty_graph/
|
|
|
149
183
|
2. Extract METHOD node signatures: `{full_name: hash}`
|
|
150
184
|
3. Compare against previous manifest in S3
|
|
151
185
|
4. If identical → **SKIP** (no Neptune writes, saves cost)
|
|
152
|
-
5. If changed → **
|
|
186
|
+
5. If changed → **CPGService filters to changed methods only**:
|
|
187
|
+
- Identify added/modified METHOD nodes via `GraphDiff.compare()`
|
|
188
|
+
- Walk AST edges to collect child nodes of changed methods
|
|
189
|
+
- Filter edges to changed subgraph
|
|
190
|
+
- Write only the delta (60-90% fewer Neptune writes)
|
|
191
|
+
- Surgically remove deleted method subgraphs
|
|
192
|
+
- Update manifest with full current state
|
|
153
193
|
|
|
154
194
|
### With Document Graph
|
|
155
195
|
|
|
@@ -15,9 +15,8 @@ pip install graphrag-codeproperty-graph
|
|
|
15
15
|
|
|
16
16
|
## Dependencies
|
|
17
17
|
|
|
18
|
-
- `graphrag-document-graph>=3.
|
|
19
|
-
|
|
20
|
-
This package does **not** depend on `bona`.
|
|
18
|
+
- `graphrag-document-graph>=3.1.1` — Document graph infrastructure (typed nodes, Cypher builders, multi-tenancy)
|
|
19
|
+
- `boto3>=1.28.0` — AWS SDK for S3 manifest storage and service integrations
|
|
21
20
|
|
|
22
21
|
## Dependency Chain
|
|
23
22
|
|
|
@@ -32,12 +31,38 @@ graphrag-codeproperty-graph
|
|
|
32
31
|
|
|
33
32
|
## Quick Start
|
|
34
33
|
|
|
35
|
-
###
|
|
34
|
+
### CPGService — Delta Node-Level Filtering (Recommended)
|
|
35
|
+
|
|
36
|
+
```python
|
|
37
|
+
from codeproperty_graph import CPGService
|
|
38
|
+
|
|
39
|
+
# Only writes changed/added method subtrees to Neptune
|
|
40
|
+
service = CPGService(bucket="graphrag-artifacts-705909755305")
|
|
41
|
+
|
|
42
|
+
result = await service.ingest(
|
|
43
|
+
repo="my-service",
|
|
44
|
+
job_id="build-456",
|
|
45
|
+
tenant_id="tenant_abc123",
|
|
46
|
+
nodes_data=joern_nodes,
|
|
47
|
+
edges_data=joern_edges,
|
|
48
|
+
nodes_path="s3://bucket/cpg-exports/my-service/build-456/nodes.json",
|
|
49
|
+
edges_path="s3://bucket/cpg-exports/my-service/build-456/edges.json",
|
|
50
|
+
graph_store=neptune_store,
|
|
51
|
+
write_fn=batch_write_function,
|
|
52
|
+
remove_fn=remove_method_subgraph, # optional: surgical deletion
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
# result: {"status": "SKIPPED"} — no changes
|
|
56
|
+
# result: {"status": "INGESTED", "delta": "+5 -2 ~3 =150",
|
|
57
|
+
# "filtered_nodes": 47, "total_nodes": 5123}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### DeltaIngestor — Full Artifact Pipeline
|
|
36
61
|
|
|
37
62
|
```python
|
|
38
|
-
from codeproperty_graph import DeltaIngestor
|
|
63
|
+
from codeproperty_graph import DeltaIngestor
|
|
39
64
|
|
|
40
|
-
#
|
|
65
|
+
# Full pipeline: graph + vectors + summaries + code slices
|
|
41
66
|
ingestor = DeltaIngestor(bucket="graphrag-artifacts-705909755305")
|
|
42
67
|
|
|
43
68
|
result = await ingestor.ingest(
|
|
@@ -91,12 +116,21 @@ previous = await manager.load(repo="my-service")
|
|
|
91
116
|
|
|
92
117
|
```
|
|
93
118
|
src/codeproperty_graph/
|
|
94
|
-
├── __init__.py # Public API
|
|
95
|
-
├── models.py # CPGNode, CPGEdge, Manifest
|
|
119
|
+
├── __init__.py # Public API (30 exports)
|
|
120
|
+
├── models.py # CPGNode, CPGEdge, Manifest, VectorRecord, SummaryRecord, CodeSliceRecord
|
|
121
|
+
├── schema.py # Full Joern CPG schema (20 node types, 14 edge types)
|
|
96
122
|
├── graph_diff.py # Compare two CPG states by method signature
|
|
97
|
-
├── manifest_manager.py # S3-backed state tracking
|
|
98
|
-
├── delta_ingestor.py #
|
|
99
|
-
|
|
123
|
+
├── manifest_manager.py # S3-backed state tracking with optimistic locking
|
|
124
|
+
├── delta_ingestor.py # Full artifact pipeline orchestration
|
|
125
|
+
├── cpg_service.py # Node-level delta filtering (only write changed methods)
|
|
126
|
+
├── tenant_ops.py # Lifecycle management (delete_tenant, delete_domain)
|
|
127
|
+
├── artifact_reader.py # S3 artifact reading and parsing
|
|
128
|
+
├── artifact_validator.py # Schema compliance validation
|
|
129
|
+
├── graph_loader.py # Neptune batch write with retry cascade
|
|
130
|
+
├── vector_loader.py # OpenSearch Serverless vector ingestion
|
|
131
|
+
├── summary_overlay.py # LLM summaries → Neptune node properties
|
|
132
|
+
├── code_slice_store.py # Source evidence → Neptune node properties
|
|
133
|
+
└── graphson_converter.py # GraphSON format conversion
|
|
100
134
|
```
|
|
101
135
|
|
|
102
136
|
## Integration
|
|
@@ -124,7 +158,13 @@ src/codeproperty_graph/
|
|
|
124
158
|
2. Extract METHOD node signatures: `{full_name: hash}`
|
|
125
159
|
3. Compare against previous manifest in S3
|
|
126
160
|
4. If identical → **SKIP** (no Neptune writes, saves cost)
|
|
127
|
-
5. If changed → **
|
|
161
|
+
5. If changed → **CPGService filters to changed methods only**:
|
|
162
|
+
- Identify added/modified METHOD nodes via `GraphDiff.compare()`
|
|
163
|
+
- Walk AST edges to collect child nodes of changed methods
|
|
164
|
+
- Filter edges to changed subgraph
|
|
165
|
+
- Write only the delta (60-90% fewer Neptune writes)
|
|
166
|
+
- Surgically remove deleted method subgraphs
|
|
167
|
+
- Update manifest with full current state
|
|
128
168
|
|
|
129
169
|
### With Document Graph
|
|
130
170
|
|
|
@@ -7,7 +7,7 @@ packages = ["src/codeproperty_graph"]
|
|
|
7
7
|
|
|
8
8
|
[project]
|
|
9
9
|
name = "graphrag-codeproperty-graph"
|
|
10
|
-
version = "0.5.
|
|
10
|
+
version = "0.5.2"
|
|
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"
|
|
@@ -166,6 +166,7 @@ class DeltaIngestor:
|
|
|
166
166
|
vector_loader = VectorLoader(
|
|
167
167
|
vector_store=vector_store,
|
|
168
168
|
expected_dimensions=manifest.get("embedding_dimensions", 0),
|
|
169
|
+
graph_store=graph_store,
|
|
169
170
|
tenant_id=tenant_id,
|
|
170
171
|
)
|
|
171
172
|
vector_result = await vector_loader.load(enriched_vectors)
|
|
@@ -163,7 +163,17 @@ class VectorLoader:
|
|
|
163
163
|
result.total_loaded += count
|
|
164
164
|
logger.info(f"Loaded {count} vectors for target '{target}'")
|
|
165
165
|
|
|
166
|
-
#
|
|
166
|
+
# Write embedding PROVENANCE (scalar metadata) onto the graph node.
|
|
167
|
+
#
|
|
168
|
+
# The embedding VECTOR itself lives in the vector store (AOSS/OpenSearch),
|
|
169
|
+
# which is the sole surface used for kNN retrieval. We deliberately do NOT
|
|
170
|
+
# write the raw vector as a node property: the original Neo4j schema stored
|
|
171
|
+
# `SET n.embedding = <array>` (Neo4j supports list-valued properties), but
|
|
172
|
+
# the graph backend here is Neptune Database, whose openCypher rejects
|
|
173
|
+
# array/list property values ("Property value must be a simple literal").
|
|
174
|
+
# Storing scalar provenance (model, dimensions, timestamp, presence flag)
|
|
175
|
+
# keeps the "this node has an embedding" graph-side signal — queryable and
|
|
176
|
+
# filterable — without duplicating the vector where nothing reads it.
|
|
167
177
|
if self._graph_store and records:
|
|
168
178
|
written = 0
|
|
169
179
|
for raw in records:
|
|
@@ -171,13 +181,21 @@ class VectorLoader:
|
|
|
171
181
|
try:
|
|
172
182
|
await self._graph_store.update_node_properties(
|
|
173
183
|
record.cpg_node_id,
|
|
174
|
-
{
|
|
184
|
+
{
|
|
185
|
+
"hasEmbedding": True,
|
|
186
|
+
"embeddingModel": record.embedding_model,
|
|
187
|
+
"embeddingDimensions": (
|
|
188
|
+
record.embedding_dimensions or len(record.vector)
|
|
189
|
+
),
|
|
190
|
+
"embeddingTarget": record.embedding_target,
|
|
191
|
+
"embeddedTime": record.metadata.get("embedded_time", ""),
|
|
192
|
+
},
|
|
175
193
|
)
|
|
176
194
|
written += 1
|
|
177
195
|
except Exception as e:
|
|
178
|
-
logger.debug(f"Failed to write embedding
|
|
196
|
+
logger.debug(f"Failed to write embedding provenance for {record.cpg_node_id}: {e}")
|
|
179
197
|
if written:
|
|
180
|
-
logger.info(f"Wrote embedding
|
|
198
|
+
logger.info(f"Wrote embedding provenance to {written} Neptune nodes")
|
|
181
199
|
|
|
182
200
|
if result.errors:
|
|
183
201
|
logger.warning(f"Encountered {len(result.errors)} validation errors during load")
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
"""Wave W2.2 — DeltaIngestor must pass graph_store to VectorLoader.
|
|
2
|
+
|
|
3
|
+
When graph_store is passed to VectorLoader, VectorLoader.load also writes the
|
|
4
|
+
embedding as a property on the Neptune node (update_node_properties), which is
|
|
5
|
+
the client-schema behaviour the Azure cpg-embedding-agent had (SET n.embedding).
|
|
6
|
+
Previously ingest_artifact constructed VectorLoader WITHOUT graph_store, so that
|
|
7
|
+
Neptune write silently never fired.
|
|
8
|
+
|
|
9
|
+
This test asserts the wiring: VectorLoader is constructed with the same
|
|
10
|
+
graph_store that GraphLoader / SummaryOverlay receive.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import pytest
|
|
14
|
+
from unittest.mock import AsyncMock, MagicMock, patch
|
|
15
|
+
|
|
16
|
+
from codeproperty_graph import DeltaIngestor
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _manifest():
|
|
20
|
+
return {"repo_id": "test-repo", "analysis_run_id": "job-1", "embedding_dimensions": 768}
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@pytest.mark.asyncio
|
|
24
|
+
async def test_vector_loader_receives_graph_store():
|
|
25
|
+
ingestor = DeltaIngestor.__new__(DeltaIngestor)
|
|
26
|
+
# Manifest manager: force "changed" so the pipeline proceeds to the loaders.
|
|
27
|
+
mm = MagicMock()
|
|
28
|
+
mm.has_changes.return_value = (True, None)
|
|
29
|
+
ingestor._manifest_mgr = mm
|
|
30
|
+
|
|
31
|
+
graph_store = MagicMock(name="neptune_store")
|
|
32
|
+
vector_store = MagicMock(name="opensearch_store")
|
|
33
|
+
|
|
34
|
+
nodes = [{"id": "m1", "node_type": "METHOD", "full_name": "com.app.A.m", "hash": "h1"}]
|
|
35
|
+
vectors = [{"cpg_node_id": "m1", "embedding_target": "code", "vector": [0.0] * 768, "text": "x"}]
|
|
36
|
+
|
|
37
|
+
dm = "codeproperty_graph.delta_ingestor"
|
|
38
|
+
with patch(f"{dm}.ArtifactValidator") as V, \
|
|
39
|
+
patch(f"{dm}.GraphLoader") as GL, \
|
|
40
|
+
patch(f"{dm}.VectorLoader") as VL, \
|
|
41
|
+
patch(f"{dm}.SummaryOverlay") as SO, \
|
|
42
|
+
patch(f"{dm}.CodeSliceStore") as CS:
|
|
43
|
+
|
|
44
|
+
V.return_value.validate.return_value = MagicMock(valid=True, warnings=[], errors=[])
|
|
45
|
+
GL.return_value.load = AsyncMock(return_value={"nodes_written": 1})
|
|
46
|
+
VL.return_value.load = AsyncMock(return_value=MagicMock(total_loaded=1))
|
|
47
|
+
SO.return_value.apply = AsyncMock(return_value=1)
|
|
48
|
+
CS.return_value.store = AsyncMock(return_value=0)
|
|
49
|
+
|
|
50
|
+
await ingestor.ingest_artifact(
|
|
51
|
+
manifest=_manifest(),
|
|
52
|
+
nodes_data=nodes,
|
|
53
|
+
edges_data=[],
|
|
54
|
+
vectors_data=vectors,
|
|
55
|
+
summaries_data=[],
|
|
56
|
+
code_slices_data=[],
|
|
57
|
+
graph_store=graph_store,
|
|
58
|
+
vector_store=vector_store,
|
|
59
|
+
validate=False,
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
# The crux of W2.2: VectorLoader must be constructed WITH graph_store,
|
|
63
|
+
# so the Neptune embedding-property write can fire.
|
|
64
|
+
assert VL.called, "VectorLoader was not constructed"
|
|
65
|
+
_, kwargs = VL.call_args
|
|
66
|
+
assert kwargs.get("graph_store") is graph_store, (
|
|
67
|
+
"VectorLoader must receive the graph_store (else the Neptune "
|
|
68
|
+
"embedding-property write never fires — the W2.2 regression)"
|
|
69
|
+
)
|
|
70
|
+
# And it should be the SAME store GraphLoader got.
|
|
71
|
+
assert GL.call_args.kwargs.get("graph_store") is graph_store
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
# ─── Wave (Neptune fix): on-node write must be SCALAR provenance, not the array ──
|
|
75
|
+
#
|
|
76
|
+
# Neptune Database openCypher rejects list/array property values ("Property value
|
|
77
|
+
# must be a simple literal"). The raw embedding vector lives in the vector store
|
|
78
|
+
# (AOSS); the graph node must carry only scalar provenance. This test drives
|
|
79
|
+
# VectorLoader.load directly and asserts what actually reaches update_node_properties.
|
|
80
|
+
|
|
81
|
+
from codeproperty_graph import VectorLoader
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
@pytest.mark.asyncio
|
|
85
|
+
async def test_vector_loader_writes_scalar_provenance_not_array():
|
|
86
|
+
graph_store = MagicMock(name="neptune_store")
|
|
87
|
+
graph_store.update_node_properties = AsyncMock(return_value=True)
|
|
88
|
+
|
|
89
|
+
vector_store = MagicMock(name="opensearch_store")
|
|
90
|
+
vector_store.put_vectors = AsyncMock(return_value=1)
|
|
91
|
+
|
|
92
|
+
loader = VectorLoader(vector_store=vector_store, graph_store=graph_store)
|
|
93
|
+
|
|
94
|
+
records = [{
|
|
95
|
+
"cpg_node_id": "n1",
|
|
96
|
+
"embedding_target": "class_summary",
|
|
97
|
+
"vector": [0.1] * 768,
|
|
98
|
+
"text": "summary text",
|
|
99
|
+
"embedding_model": "nomic-embed-text",
|
|
100
|
+
"embedding_dimensions": 768,
|
|
101
|
+
"metadata": {"embedded_time": "2026-09-16T07:50:43Z"},
|
|
102
|
+
}]
|
|
103
|
+
|
|
104
|
+
await loader.load(records)
|
|
105
|
+
|
|
106
|
+
# The on-node write must have happened...
|
|
107
|
+
assert graph_store.update_node_properties.await_count == 1
|
|
108
|
+
node_id, props = graph_store.update_node_properties.await_args.args
|
|
109
|
+
|
|
110
|
+
assert node_id == "n1"
|
|
111
|
+
# ...and it must NOT include the raw vector array (the Neptune-rejecting bug).
|
|
112
|
+
assert "embedding" not in props, (
|
|
113
|
+
"VectorLoader must not write the raw embedding array to the Neptune node "
|
|
114
|
+
"(Neptune Database rejects list-valued properties)"
|
|
115
|
+
)
|
|
116
|
+
# ...every value written must be a Neptune-safe scalar literal.
|
|
117
|
+
for key, value in props.items():
|
|
118
|
+
assert not isinstance(value, (list, dict, tuple, set)), (
|
|
119
|
+
f"Node property {key!r} must be a scalar literal, got {type(value).__name__}"
|
|
120
|
+
)
|
|
121
|
+
# ...and the useful provenance is present.
|
|
122
|
+
assert props["hasEmbedding"] is True
|
|
123
|
+
assert props["embeddingModel"] == "nomic-embed-text"
|
|
124
|
+
assert props["embeddingDimensions"] == 768
|
|
125
|
+
assert props["embeddingTarget"] == "class_summary"
|
|
126
|
+
assert props["embeddedTime"] == "2026-09-16T07:50:43Z"
|
|
127
|
+
|
|
128
|
+
# The VECTOR itself still goes to the vector store (AOSS).
|
|
129
|
+
assert vector_store.put_vectors.await_count >= 1
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
## [0.4.3] - 2026-08-03
|
|
4
|
-
|
|
5
|
-
### Added
|
|
6
|
-
- Initial public release
|
|
7
|
-
- Joern/Semgrep CPG extraction and ingestion
|
|
8
|
-
- Delta ingestion — skip-or-replace logic to minimize Neptune writes
|
|
9
|
-
- Graph diff comparison between CPG states
|
|
10
|
-
- S3-backed manifest management for repository state tracking
|
|
11
|
-
- AI vulnerability enrichment and risk scoring
|
|
12
|
-
- Tenant lifecycle management (create, purge, replace)
|
|
13
|
-
- CPGNode and CPGEdge Pydantic models (Joern-specific types)
|
|
14
|
-
|
|
15
|
-
### Dependencies
|
|
16
|
-
- graphrag-document-graph>=3.0.8
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{graphrag_codeproperty_graph-0.5.0 → graphrag_codeproperty_graph-0.5.2}/docs/ARCHITECTURE.md
RENAMED
|
File without changes
|
|
File without changes
|
{graphrag_codeproperty_graph-0.5.0 → graphrag_codeproperty_graph-0.5.2}/docs/HYBRID-GRAPH.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{graphrag_codeproperty_graph-0.5.0 → graphrag_codeproperty_graph-0.5.2}/sbom/AWS-SERVICES.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{graphrag_codeproperty_graph-0.5.0 → graphrag_codeproperty_graph-0.5.2}/tests/test_cpg_service.py
RENAMED
|
File without changes
|