graphrag-codeproperty-graph 0.1.0__py3-none-any.whl

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.
@@ -0,0 +1,20 @@
1
+ """Code Property Graph — domain layer for Joern CPG delta ingestion.
2
+
3
+ Built on document-graph for typed property graph primitives.
4
+ Adds CPG-specific models, delta comparison, manifest management,
5
+ and tenant lifecycle for incremental code analysis.
6
+ """
7
+
8
+ __version__ = "0.1.0"
9
+
10
+ from .models import CPGNode, CPGEdge, Manifest
11
+ from .graph_diff import GraphDiff
12
+ from .manifest_manager import ManifestManager
13
+ from .delta_ingestor import DeltaIngestor
14
+ from .tenant_ops import delete_tenant
15
+
16
+ __all__ = [
17
+ "CPGNode", "CPGEdge", "Manifest",
18
+ "GraphDiff", "ManifestManager", "DeltaIngestor",
19
+ "delete_tenant",
20
+ ]
@@ -0,0 +1,117 @@
1
+ """Delta Ingestor — orchestrates skip-or-replace CPG ingestion."""
2
+
3
+ import logging
4
+ from datetime import datetime, timezone
5
+ from typing import Any
6
+
7
+ from .graph_diff import GraphDiff
8
+ from .manifest_manager import ManifestManager
9
+ from .models import Manifest
10
+ from .tenant_ops import delete_tenant
11
+
12
+ logger = logging.getLogger(__name__)
13
+
14
+
15
+ class DeltaIngestor:
16
+ """Orchestrates CPG delta ingestion: compare → skip/ingest → purge → update manifest.
17
+
18
+ Usage:
19
+ ingestor = DeltaIngestor(bucket="graphrag-artifacts-705909755305")
20
+ result = await ingestor.ingest(
21
+ repo="amigo-core",
22
+ job_id="uuid",
23
+ nodes_data=[...],
24
+ edges_data=[...],
25
+ graph_store=neptune_store,
26
+ write_fn=my_write_function,
27
+ )
28
+ """
29
+
30
+ def __init__(self, bucket: str, prefix: str = "cpg-exports", region: str = "us-east-1"):
31
+ self._manifest_mgr = ManifestManager(bucket, prefix, region)
32
+
33
+ async def ingest(
34
+ self,
35
+ repo: str,
36
+ job_id: str,
37
+ tenant_id: str,
38
+ nodes_data: list[dict],
39
+ edges_data: list[dict],
40
+ nodes_path: str,
41
+ edges_path: str,
42
+ graph_store: Any,
43
+ write_fn=None,
44
+ ) -> dict:
45
+ """Execute delta-aware ingestion.
46
+
47
+ Args:
48
+ repo: Repository name
49
+ job_id: Current job UUID
50
+ tenant_id: Derived tenant for this job
51
+ nodes_data: Parsed node records from Joern export
52
+ edges_data: Parsed edge records from Joern export
53
+ nodes_path: S3 URI to nodes.json
54
+ edges_path: S3 URI to edges.json
55
+ graph_store: Neptune graph store instance
56
+ write_fn: async callable(nodes_data, edges_data, tenant_id, graph_store) → dict
57
+
58
+ Returns:
59
+ Dict with status, nodes_written, etc.
60
+ """
61
+ # Extract method signatures from nodes
62
+ method_sigs = {
63
+ n["full_name"]: n.get("hash", "")
64
+ for n in nodes_data
65
+ if n.get("node_type") == "METHOD" and n.get("full_name")
66
+ }
67
+
68
+ # Check manifest
69
+ changed, previous = self._manifest_mgr.has_changes(repo, method_sigs)
70
+
71
+ if not changed:
72
+ logger.info(f"Delta check: no changes for {repo}, skipping ingest")
73
+ return {
74
+ "status": "SKIPPED",
75
+ "reason": "no_changes",
76
+ "tenant_id": previous.tenant_id,
77
+ "previous_job_id": previous.job_id,
78
+ }
79
+
80
+ # Log diff if previous exists
81
+ if previous:
82
+ diff = GraphDiff.compare(previous.method_signatures, method_sigs)
83
+ logger.info(f"Delta: {diff.summary} for {repo}")
84
+
85
+ # Perform full ingest
86
+ if write_fn:
87
+ result = await write_fn(nodes_data, edges_data, tenant_id, graph_store)
88
+ else:
89
+ result = {"nodes_written": len(nodes_data), "edges_written": len(edges_data)}
90
+
91
+ # Purge old tenant
92
+ if previous and previous.tenant_id != tenant_id:
93
+ try:
94
+ await delete_tenant(previous.tenant_id, graph_store)
95
+ except Exception:
96
+ pass # logged inside delete_tenant
97
+
98
+ # Update manifest
99
+ new_manifest = Manifest(
100
+ repo=repo,
101
+ signature=self._manifest_mgr.compute_signature(method_sigs),
102
+ job_id=job_id,
103
+ tenant_id=tenant_id,
104
+ exported_at=datetime.now(timezone.utc).isoformat(),
105
+ nodes_path=nodes_path,
106
+ edges_path=edges_path,
107
+ method_signatures=method_sigs,
108
+ )
109
+ self._manifest_mgr.put(new_manifest)
110
+
111
+ result["status"] = "INGESTED"
112
+ result["tenant_id"] = tenant_id
113
+ result["delta"] = GraphDiff.compare(
114
+ previous.method_signatures if previous else {}, method_sigs
115
+ ).summary
116
+
117
+ return result
@@ -0,0 +1,61 @@
1
+ """Graph Diff — compare two CPG states and compute delta."""
2
+
3
+ from dataclasses import dataclass, field
4
+ from typing import Dict
5
+
6
+
7
+ @dataclass
8
+ class DiffResult:
9
+ """Result of comparing two method signature sets."""
10
+
11
+ added: Dict[str, str] = field(default_factory=dict) # full_name → hash (new methods)
12
+ removed: Dict[str, str] = field(default_factory=dict) # full_name → hash (deleted methods)
13
+ modified: Dict[str, str] = field(default_factory=dict) # full_name → new_hash (body changed)
14
+ unchanged: int = 0
15
+
16
+ @property
17
+ def has_changes(self) -> bool:
18
+ return bool(self.added or self.removed or self.modified)
19
+
20
+ @property
21
+ def summary(self) -> str:
22
+ return f"+{len(self.added)} -{len(self.removed)} ~{len(self.modified)} ={self.unchanged}"
23
+
24
+
25
+ class GraphDiff:
26
+ """Compare method signatures between two CPG exports."""
27
+
28
+ @staticmethod
29
+ def compare(
30
+ previous: Dict[str, str],
31
+ current: Dict[str, str],
32
+ ) -> DiffResult:
33
+ """Compare previous vs current method_signatures dicts.
34
+
35
+ Args:
36
+ previous: {full_name: hash} from manifest
37
+ current: {full_name: hash} from new export
38
+
39
+ Returns:
40
+ DiffResult with added/removed/modified/unchanged counts
41
+ """
42
+ prev_keys = set(previous.keys())
43
+ curr_keys = set(current.keys())
44
+
45
+ added = {k: current[k] for k in curr_keys - prev_keys}
46
+ removed = {k: previous[k] for k in prev_keys - curr_keys}
47
+
48
+ modified = {}
49
+ unchanged = 0
50
+ for k in prev_keys & curr_keys:
51
+ if previous[k] != current[k]:
52
+ modified[k] = current[k]
53
+ else:
54
+ unchanged += 1
55
+
56
+ return DiffResult(
57
+ added=added,
58
+ removed=removed,
59
+ modified=modified,
60
+ unchanged=unchanged,
61
+ )
@@ -0,0 +1,64 @@
1
+ """Manifest Manager — S3-backed CPG state tracking."""
2
+
3
+ import hashlib
4
+ import json
5
+ import logging
6
+ from typing import Optional
7
+
8
+ import boto3
9
+
10
+ from .models import Manifest
11
+
12
+ logger = logging.getLogger(__name__)
13
+
14
+
15
+ class ManifestManager:
16
+ """Read/write/compare CPG manifests on S3."""
17
+
18
+ def __init__(self, bucket: str, prefix: str = "cpg-exports", region: str = "us-east-1"):
19
+ self._bucket = bucket
20
+ self._prefix = prefix
21
+ self._s3 = boto3.client("s3", region_name=region)
22
+
23
+ def compute_signature(self, method_signatures: dict[str, str]) -> str:
24
+ """Compute sha256 signature from method full_name:hash pairs."""
25
+ payload = json.dumps(method_signatures, sort_keys=True)
26
+ return "sha256:" + hashlib.sha256(payload.encode()).hexdigest()
27
+
28
+ def get(self, repo: str) -> Optional[Manifest]:
29
+ """Read manifest for a repo from S3. Returns None if not found."""
30
+ key = f"{self._prefix}/{repo}/manifest.json"
31
+ try:
32
+ resp = self._s3.get_object(Bucket=self._bucket, Key=key)
33
+ data = json.loads(resp["Body"].read())
34
+ return Manifest(**data)
35
+ except Exception:
36
+ return None
37
+
38
+ def put(self, manifest: Manifest) -> None:
39
+ """Write manifest to S3."""
40
+ key = f"{self._prefix}/{manifest.repo}/manifest.json"
41
+ body = json.dumps({
42
+ "repo": manifest.repo,
43
+ "signature": manifest.signature,
44
+ "job_id": manifest.job_id,
45
+ "tenant_id": manifest.tenant_id,
46
+ "exported_at": manifest.exported_at,
47
+ "nodes_path": manifest.nodes_path,
48
+ "edges_path": manifest.edges_path,
49
+ "method_signatures": manifest.method_signatures,
50
+ })
51
+ self._s3.put_object(Bucket=self._bucket, Key=key, Body=body.encode(), ContentType="application/json")
52
+ logger.info(f"Manifest written: s3://{self._bucket}/{key}")
53
+
54
+ def has_changes(self, repo: str, current_signatures: dict[str, str]) -> tuple[bool, Optional[Manifest]]:
55
+ """Check if current export differs from stored manifest.
56
+
57
+ Returns:
58
+ (has_changes: bool, previous_manifest: Optional[Manifest])
59
+ """
60
+ previous = self.get(repo)
61
+ if not previous:
62
+ return True, None
63
+ new_sig = self.compute_signature(current_signatures)
64
+ return new_sig != previous.signature, previous
@@ -0,0 +1,62 @@
1
+ """CPG domain models — typed representations of Joern output."""
2
+
3
+ from dataclasses import dataclass, field
4
+ from typing import Dict, Any, Optional
5
+
6
+
7
+ @dataclass
8
+ class CPGNode:
9
+ """A code property graph node with Joern metadata.
10
+
11
+ Identity: full_name (stable across line shifts)
12
+ Change detection: hash (content fingerprint from Joern)
13
+ """
14
+
15
+ id: str
16
+ node_type: str # METHOD, CALL, IDENTIFIER, LITERAL, etc.
17
+ full_name: str = ""
18
+ hash: str = ""
19
+ filename: str = ""
20
+ name: str = ""
21
+ code: str = ""
22
+ signature: str = ""
23
+ line_number: Optional[int] = None
24
+ is_external: bool = False
25
+ properties: Dict[str, Any] = field(default_factory=dict)
26
+
27
+ @property
28
+ def stable_id(self) -> str:
29
+ """Content-addressed identity for delta comparison."""
30
+ return self.full_name or self.id
31
+
32
+
33
+ @dataclass
34
+ class CPGEdge:
35
+ """A code property graph edge with semantic metadata.
36
+
37
+ Joern edge types: AST, CFG, CDG, REACHING_DEF, CALL, ARGUMENT, DOMINATE, etc.
38
+ """
39
+
40
+ source_id: str
41
+ target_id: str
42
+ edge_type: str # AST, CFG, CDG, REACHING_DEF, CALL, ARGUMENT
43
+ properties: Dict[str, Any] = field(default_factory=dict)
44
+
45
+ @property
46
+ def key(self) -> str:
47
+ """Unique edge identity for diff."""
48
+ return f"{self.source_id}->{self.edge_type}->{self.target_id}"
49
+
50
+
51
+ @dataclass
52
+ class Manifest:
53
+ """CPG extraction manifest — tracks the current graph state for a repo."""
54
+
55
+ repo: str
56
+ signature: str # sha256 of sorted method full_name:hash pairs
57
+ job_id: str
58
+ tenant_id: str
59
+ exported_at: str
60
+ nodes_path: str
61
+ edges_path: str
62
+ method_signatures: Dict[str, str] = field(default_factory=dict) # full_name → hash
@@ -0,0 +1,26 @@
1
+ """Tenant Operations — lifecycle management for CPG tenants in Neptune."""
2
+
3
+ import asyncio
4
+ import logging
5
+
6
+ logger = logging.getLogger(__name__)
7
+
8
+
9
+ async def delete_tenant(tenant_id: str, graph_store) -> int:
10
+ """Purge all nodes and edges for a tenant from Neptune.
11
+
12
+ Args:
13
+ tenant_id: The tenant scope to delete
14
+ graph_store: Neptune graph store with execute_query method
15
+
16
+ Returns:
17
+ Number of nodes deleted (approximate)
18
+ """
19
+ cypher = f"MATCH (n) WHERE n.tenant_id = '{tenant_id}' DETACH DELETE n"
20
+ try:
21
+ await asyncio.to_thread(graph_store.execute_query, cypher, {})
22
+ logger.info(f"Tenant purged: {tenant_id}")
23
+ return -1 # Neptune doesn't return count on DELETE
24
+ except Exception as e:
25
+ logger.warning(f"Tenant purge failed for {tenant_id}: {e}")
26
+ raise
@@ -0,0 +1,168 @@
1
+ Metadata-Version: 2.4
2
+ Name: graphrag-codeproperty-graph
3
+ Version: 0.1.0
4
+ Summary: Code Property Graphs — Joern/Semgrep extraction, AI vulnerability enrichment, risk scoring
5
+ Project-URL: Repository, https://github.com/RW-Lab/codeproperty-graph
6
+ Author-email: Evan Erwee <evan@erwee.com>
7
+ License-Expression: MIT
8
+ License-File: LICENSE
9
+ License-File: NOTICE
10
+ Keywords: code-analysis,cpg,graph,joern,neptune,semgrep,vulnerability
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Topic :: Security
14
+ Classifier: Topic :: Software Development :: Quality Assurance
15
+ Requires-Python: >=3.11
16
+ Requires-Dist: boto3>=1.26.0
17
+ Requires-Dist: document-graph>=0.1.0
18
+ Provides-Extra: dev
19
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
20
+ Requires-Dist: pytest-cov>=4.0; extra == 'dev'
21
+ Requires-Dist: pytest>=7.0; extra == 'dev'
22
+ Provides-Extra: graphrag
23
+ Requires-Dist: graphrag-toolkit-lexical-graph>=3.18.0; extra == 'graphrag'
24
+ Description-Content-Type: text/markdown
25
+
26
+ # Code Property Graph
27
+
28
+ Code Property Graphs — Joern/Semgrep extraction, AI vulnerability enrichment, risk scoring.
29
+
30
+ > **This package depends on AWS GraphRAG Toolkit (graphrag-toolkit-lexical-graph) for graph storage, vector indexing, and retrieval.**
31
+
32
+ ## Quick Start
33
+
34
+ ### Install
35
+
36
+ ```bash
37
+ pip install codeproperty-graph
38
+ ```
39
+
40
+ ### Python API Example
41
+
42
+ ```python
43
+ from codeproperty_graph import DeltaIngestor, CPGNode, CPGEdge, GraphDiff
44
+
45
+ # Delta ingestion — only writes to Neptune when code actually changed
46
+ ingestor = DeltaIngestor(bucket="graphrag-artifacts-705909755305")
47
+
48
+ result = await ingestor.ingest(
49
+ repo="my-service",
50
+ job_id="build-456",
51
+ tenant_id="tenant_abc123",
52
+ nodes_data=joern_nodes, # Joern CPG export
53
+ edges_data=joern_edges, # Joern CPG export
54
+ nodes_path="s3://bucket/cpg-exports/my-service/build-456/nodes.json",
55
+ edges_path="s3://bucket/cpg-exports/my-service/build-456/edges.json",
56
+ graph_store=neptune_store,
57
+ write_fn=batch_write_function,
58
+ )
59
+
60
+ # result: {"status": "SKIPPED"} or {"status": "INGESTED", "delta": "+5 -2 ~3 =150"}
61
+ ```
62
+
63
+ ### Graph Diff — Compare CPG States
64
+
65
+ ```python
66
+ from codeproperty_graph import GraphDiff, CPGNode
67
+
68
+ # Compare current vs previous code analysis
69
+ diff = GraphDiff.compare(
70
+ current_nodes=current_cpg_nodes,
71
+ previous_nodes=previous_cpg_nodes,
72
+ )
73
+
74
+ print(f"Added: {len(diff.added)}")
75
+ print(f"Removed: {len(diff.removed)}")
76
+ print(f"Modified: {len(diff.modified)}")
77
+ print(f"Unchanged: {len(diff.unchanged)}")
78
+ ```
79
+
80
+ ### Manifest Management
81
+
82
+ ```python
83
+ from codeproperty_graph import ManifestManager
84
+
85
+ # Track CPG state per repository in S3
86
+ manager = ManifestManager(bucket="graphrag-artifacts-705909755305")
87
+
88
+ # Save manifest after successful ingestion
89
+ await manager.save(repo="my-service", job_id="build-456", signatures=method_signatures)
90
+
91
+ # Load previous manifest for diff comparison
92
+ previous = await manager.load(repo="my-service")
93
+ ```
94
+
95
+ ## Package Structure
96
+
97
+ ```
98
+ src/codeproperty_graph/
99
+ ├── __init__.py # Public API: CPGNode, CPGEdge, DeltaIngestor, etc.
100
+ ├── models.py # CPGNode, CPGEdge, Manifest — Joern-specific types
101
+ ├── graph_diff.py # Compare two CPG states by method signature
102
+ ├── manifest_manager.py # S3-backed state tracking per repository
103
+ ├── delta_ingestor.py # Skip-or-replace orchestration with tenant purge
104
+ └── tenant_ops.py # Clean lifecycle management (delete_tenant)
105
+ ```
106
+
107
+ ## Integration
108
+
109
+ ### Architecture Stack
110
+
111
+ ```
112
+ ┌─────────────────────────────────────────────────────┐
113
+ │ codeproperty-graph (this package) │
114
+ │ Joern/Semgrep CPG, delta ingestion, risk scoring │
115
+ ├─────────────────────────────────────────────────────┤
116
+ │ document-graph (infra) │
117
+ │ Node, Edge, CypherBuilder, PipelineExecutor │
118
+ │ Multi-tenancy, batch operations │
119
+ ├─────────────────────────────────────────────────────┤
120
+ │ graphrag-toolkit-lexical-graph (foundation) │
121
+ │ GraphStore, Neptune writer, AOSS writer │
122
+ │ Lexical indexing, entity resolution, retrieval │
123
+ └─────────────────────────────────────────────────────┘
124
+ ```
125
+
126
+ ### Delta Logic
127
+
128
+ 1. Joern exports CPG → `nodes.json` + `edges.json`
129
+ 2. Extract METHOD node signatures: `{full_name: hash}`
130
+ 3. Compare against previous manifest in S3
131
+ 4. If identical → **SKIP** (no Neptune writes, saves cost)
132
+ 5. If changed → **INGEST** full graph under new tenant, purge old tenant, update manifest
133
+
134
+ ### With Document Graph
135
+
136
+ Code Property Graph uses document-graph for typed property graph primitives:
137
+
138
+ ```python
139
+ # document-graph provides the graph write infrastructure
140
+ from graphrag_toolkit.document_graph.graph_build.cypher_builder import CypherBuilder
141
+ from graphrag_toolkit.document_graph import Node, Edge
142
+
143
+ # codeproperty-graph adds CPG-specific semantics on top
144
+ from codeproperty_graph import CPGNode, CPGEdge
145
+ ```
146
+
147
+ ### AI Vulnerability Enrichment
148
+
149
+ After CPG ingestion, enrich with AI-powered vulnerability analysis:
150
+
151
+ ```python
152
+ # Query Neptune for high-risk patterns
153
+ # Score methods by complexity, dependency depth, and known CVE proximity
154
+ # Annotate graph with risk scores for downstream consumption
155
+ ```
156
+
157
+ ## Requirements
158
+
159
+ - Python >= 3.11
160
+ - `document-graph >= 0.1.0`
161
+ - `boto3 >= 1.26.0`
162
+ - Optional: `graphrag-toolkit-lexical-graph >= 3.18.0`
163
+
164
+ ## License
165
+
166
+ MIT — see [LICENSE](LICENSE) for details.
167
+
168
+ See [NOTICE](NOTICE) for third-party acknowledgments.
@@ -0,0 +1,11 @@
1
+ codeproperty_graph/__init__.py,sha256=Kbf6nqUzsvTDHcukATDRVIt2zmDaw6JQr527_YhiwU0,612
2
+ codeproperty_graph/delta_ingestor.py,sha256=J-TD7Z7qxKzdhdBOa3sCHTZhJQMmCruXoNRuBK9d6o8,3885
3
+ codeproperty_graph/graph_diff.py,sha256=e6blXSv1JhtsHShuJG_U_c5oRHBGV7yMiC4mBhRKKeM,1870
4
+ codeproperty_graph/manifest_manager.py,sha256=G4R9WqUwN9RzPg3soNEJS-54ryqi82xVI7utxM6s7oU,2394
5
+ codeproperty_graph/models.py,sha256=vsGb5nL8efuyqreqytezmvF4tZK1adn8PbXlb6giQpQ,1713
6
+ codeproperty_graph/tenant_ops.py,sha256=v4zzQuwjbzpePRDlCoMdPMliVF10L4s8pArmAec__C8,837
7
+ graphrag_codeproperty_graph-0.1.0.dist-info/METADATA,sha256=n9NeKdRbxERtJA1l-tNCO1wHUZYCVLQRD99IFJ6NKQw,5941
8
+ graphrag_codeproperty_graph-0.1.0.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
9
+ graphrag_codeproperty_graph-0.1.0.dist-info/licenses/LICENSE,sha256=uwE9MC3_X48nBQ0WlXxXYbTknQYFB2qBeiKk6CCVxc8,1067
10
+ graphrag_codeproperty_graph-0.1.0.dist-info/licenses/NOTICE,sha256=r_j1bkjjV4lqE3M64cDNd_-JluPv216nqr4qicJdGfI,773
11
+ graphrag_codeproperty_graph-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.31.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Evan Erwee
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,27 @@
1
+ NOTICE
2
+
3
+ Code Property Graph
4
+ Copyright (c) 2026 Evan Erwee
5
+
6
+ This project is licensed under the MIT License.
7
+
8
+ ---
9
+
10
+ Third-Party Components
11
+ ======================
12
+
13
+ This project builds upon and integrates with the AWS GraphRAG Toolkit
14
+ (lexical-graph), which is licensed under the Apache License, Version 2.0.
15
+
16
+ AWS GraphRAG Toolkit (graphrag-toolkit-lexical-graph)
17
+ Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
18
+ Licensed under the Apache License, Version 2.0
19
+ https://github.com/awslabs/graphrag-toolkit
20
+
21
+ You may obtain a copy of the Apache License at:
22
+ http://www.apache.org/licenses/LICENSE-2.0
23
+
24
+ ---
25
+
26
+ Our original additions and modifications in this repository are released
27
+ under the MIT License. See the LICENSE file for the full MIT License text.