codegraph-engine 3.0.0__1-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.
Files changed (130) hide show
  1. codegraph/__init__.py +37 -0
  2. codegraph/agent.py +26 -0
  3. codegraph/agent_brain.py +2212 -0
  4. codegraph/agent_capabilities.py +4058 -0
  5. codegraph/agent_rules.py +531 -0
  6. codegraph/api_drift.py +455 -0
  7. codegraph/architecture.py +371 -0
  8. codegraph/async_queue/__init__.py +50 -0
  9. codegraph/async_queue/detectors/__init__.py +48 -0
  10. codegraph/async_queue/detectors/celery.py +160 -0
  11. codegraph/async_queue/detectors/kafka.py +168 -0
  12. codegraph/async_queue/detectors/rabbitmq.py +116 -0
  13. codegraph/async_queue/detectors/redis.py +130 -0
  14. codegraph/async_queue/detectors/sqs.py +135 -0
  15. codegraph/async_queue/models.py +161 -0
  16. codegraph/async_queue/otel_models.py +74 -0
  17. codegraph/async_queue/otel_parser.py +337 -0
  18. codegraph/async_queue/reconciler.py +427 -0
  19. codegraph/async_queue/scanner.py +291 -0
  20. codegraph/async_queue/traversal.py +447 -0
  21. codegraph/audit.py +106 -0
  22. codegraph/binding_resolver.py +616 -0
  23. codegraph/branch_comparison.py +197 -0
  24. codegraph/cache.py +95 -0
  25. codegraph/change_impact.py +547 -0
  26. codegraph/cli.py +2436 -0
  27. codegraph/cli_output.py +205 -0
  28. codegraph/config.py +45 -0
  29. codegraph/constraints.py +238 -0
  30. codegraph/context.py +2182 -0
  31. codegraph/context_freshness.py +351 -0
  32. codegraph/database/__init__.py +72 -0
  33. codegraph/database/extractor.py +3651 -0
  34. codegraph/database/interrogation.py +1494 -0
  35. codegraph/database/models.py +310 -0
  36. codegraph/database/schema_drift.py +862 -0
  37. codegraph/epistemic.py +200 -0
  38. codegraph/errors.py +282 -0
  39. codegraph/evidence/__init__.py +15 -0
  40. codegraph/evidence/citations.py +418 -0
  41. codegraph/evidence_contract.py +486 -0
  42. codegraph/frameworks.py +960 -0
  43. codegraph/frameworks_nestjs.py +502 -0
  44. codegraph/frameworks_nextjs.py +337 -0
  45. codegraph/frameworks_react.py +457 -0
  46. codegraph/freshness.py +335 -0
  47. codegraph/frontend_html.py +109 -0
  48. codegraph/git.py +362 -0
  49. codegraph/git_state.py +545 -0
  50. codegraph/graph/__init__.py +46 -0
  51. codegraph/graph/models.py +56 -0
  52. codegraph/graph/traversal.py +1993 -0
  53. codegraph/indexing/__init__.py +24 -0
  54. codegraph/indexing/classifier.py +564 -0
  55. codegraph/indexing/indexer.py +2578 -0
  56. codegraph/indexing/models.py +427 -0
  57. codegraph/indexing/parser.py +3404 -0
  58. codegraph/indexing/pool.py +136 -0
  59. codegraph/indexing/scanner.py +211 -0
  60. codegraph/indexing/telemetry.py +326 -0
  61. codegraph/indexing/templates.py +418 -0
  62. codegraph/indexing/test_framework.py +116 -0
  63. codegraph/installer.py +1702 -0
  64. codegraph/interrogation.py +2355 -0
  65. codegraph/llm/__init__.py +3 -0
  66. codegraph/llm/base.py +15 -0
  67. codegraph/llm/context.py +20 -0
  68. codegraph/mcp/__init__.py +3 -0
  69. codegraph/mcp/server.py +1476 -0
  70. codegraph/mcp_diagnostics.py +882 -0
  71. codegraph/memory/__init__.py +3 -0
  72. codegraph/memory/store.py +46 -0
  73. codegraph/models.py +310 -0
  74. codegraph/monorepo.py +925 -0
  75. codegraph/observability.py +262 -0
  76. codegraph/optimizer.py +1014 -0
  77. codegraph/planner.py +417 -0
  78. codegraph/process_lifecycle.py +1153 -0
  79. codegraph/py.typed +1 -0
  80. codegraph/query_expansion.py +199 -0
  81. codegraph/ranking.py +408 -0
  82. codegraph/refactor/__init__.py +36 -0
  83. codegraph/refactor/models.py +114 -0
  84. codegraph/refactor/renamer.py +844 -0
  85. codegraph/refactor/transactions.py +414 -0
  86. codegraph/resolver.py +3968 -0
  87. codegraph/resources/__init__.py +46 -0
  88. codegraph/resources/cache.py +117 -0
  89. codegraph/resources/coalescer.py +83 -0
  90. codegraph/resources/debouncer.py +98 -0
  91. codegraph/resources/governor.py +219 -0
  92. codegraph/resources/monitor.py +102 -0
  93. codegraph/resources/policy.py +123 -0
  94. codegraph/retrieval_policy.py +320 -0
  95. codegraph/roblox.py +2174 -0
  96. codegraph/route_composer.py +363 -0
  97. codegraph/route_topology.py +172 -0
  98. codegraph/runtime/__init__.py +51 -0
  99. codegraph/runtime/collector.py +155 -0
  100. codegraph/runtime/db_watcher.py +191 -0
  101. codegraph/runtime/ingestor.py +692 -0
  102. codegraph/runtime/models.py +130 -0
  103. codegraph/runtime/port_inspector.py +304 -0
  104. codegraph/runtime/reconciliation.py +492 -0
  105. codegraph/runtime/runner.py +353 -0
  106. codegraph/runtime/trace_linker.py +175 -0
  107. codegraph/search/__init__.py +25 -0
  108. codegraph/search/hybrid.py +846 -0
  109. codegraph/search/semantic.py +28 -0
  110. codegraph/security/__init__.py +51 -0
  111. codegraph/security/paths.py +189 -0
  112. codegraph/security/redaction.py +633 -0
  113. codegraph/semantic_conflicts.py +270 -0
  114. codegraph/semantic_decorators.py +372 -0
  115. codegraph/structural_diff.py +542 -0
  116. codegraph/styles.py +144 -0
  117. codegraph/symbol_history.py +277 -0
  118. codegraph/target_resolver.py +348 -0
  119. codegraph/task.py +637 -0
  120. codegraph/tool_selection_eval.py +1158 -0
  121. codegraph/tsconfig.py +236 -0
  122. codegraph/ui/__init__.py +6 -0
  123. codegraph/ui/server.py +755 -0
  124. codegraph/watcher.py +323 -0
  125. codegraph_engine-3.0.0.dist-info/METADATA +859 -0
  126. codegraph_engine-3.0.0.dist-info/RECORD +130 -0
  127. codegraph_engine-3.0.0.dist-info/WHEEL +6 -0
  128. codegraph_engine-3.0.0.dist-info/entry_points.txt +2 -0
  129. codegraph_engine-3.0.0.dist-info/licenses/LICENSE +21 -0
  130. codegraph_engine-3.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,28 @@
1
+ from __future__ import annotations
2
+
3
+ from abc import ABC, abstractmethod
4
+ from dataclasses import dataclass
5
+
6
+
7
+ class SemanticSearchUnavailable(RuntimeError):
8
+ """No embedding provider has been configured for semantic retrieval."""
9
+
10
+
11
+ class EmbeddingProvider(ABC):
12
+ """Provider-neutral embeddings interface; implementations must be deterministic in tests."""
13
+
14
+ @abstractmethod
15
+ def embed(self, texts: list[str]) -> list[list[float]]:
16
+ raise NotImplementedError
17
+
18
+
19
+ @dataclass(frozen=True)
20
+ class SemanticStatus:
21
+ available: bool
22
+ detail: str
23
+
24
+
25
+ def status(provider: EmbeddingProvider | None) -> SemanticStatus:
26
+ if provider is None:
27
+ return SemanticStatus(False, "No embedding provider configured; lexical and symbol retrieval remain active.")
28
+ return SemanticStatus(True, "Embedding provider configured.")
@@ -0,0 +1,51 @@
1
+ from .paths import (
2
+ DEFAULT_MAX_READ_BYTES,
3
+ DEFAULT_SENSITIVE_PATTERNS,
4
+ is_sensitive,
5
+ is_sensitive_path,
6
+ safe_path,
7
+ safe_read_text,
8
+ )
9
+ from .redaction import (
10
+ REDACTED_DB_CREDENTIALS,
11
+ REDACTED_PRIVATE_KEY,
12
+ REDACTED_SECRET,
13
+ REDACTED_TOKEN,
14
+ SECRET_ENV_EXACT_NAMES,
15
+ SENSITIVE_RUNTIME_KEYS,
16
+ audit_sqlite_for_secrets,
17
+ contains_private_key,
18
+ detect_env_variable_reads,
19
+ is_probable_secret_value,
20
+ is_secret_variable_name,
21
+ normalize_and_redact_sql,
22
+ parse_safe_connection_metadata,
23
+ redact_connection_string,
24
+ redact_payload,
25
+ redact_secrets,
26
+ )
27
+
28
+ __all__ = [
29
+ "DEFAULT_MAX_READ_BYTES",
30
+ "DEFAULT_SENSITIVE_PATTERNS",
31
+ "REDACTED_DB_CREDENTIALS",
32
+ "REDACTED_PRIVATE_KEY",
33
+ "REDACTED_SECRET",
34
+ "REDACTED_TOKEN",
35
+ "SECRET_ENV_EXACT_NAMES",
36
+ "SENSITIVE_RUNTIME_KEYS",
37
+ "audit_sqlite_for_secrets",
38
+ "contains_private_key",
39
+ "detect_env_variable_reads",
40
+ "is_probable_secret_value",
41
+ "is_secret_variable_name",
42
+ "is_sensitive",
43
+ "is_sensitive_path",
44
+ "normalize_and_redact_sql",
45
+ "parse_safe_connection_metadata",
46
+ "redact_connection_string",
47
+ "redact_payload",
48
+ "redact_secrets",
49
+ "safe_path",
50
+ "safe_read_text",
51
+ ]
@@ -0,0 +1,189 @@
1
+ from __future__ import annotations
2
+
3
+ import fnmatch
4
+ import re
5
+ from pathlib import Path
6
+ from urllib.parse import unquote
7
+
8
+ from codegraph.errors import ErrorCode, SecurityError
9
+
10
+ DEFAULT_MAX_READ_BYTES = 256_000
11
+
12
+ DEFAULT_SENSITIVE_PATTERNS: tuple[str, ...] = (
13
+ ".env",
14
+ ".env.*",
15
+ "*.pem",
16
+ "*.key",
17
+ "*.crt",
18
+ "*.p12",
19
+ "*.pfx",
20
+ "id_rsa",
21
+ "id_rsa.*",
22
+ "id_ed25519",
23
+ "id_ed25519.*",
24
+ "id_ecdsa",
25
+ "id_ecdsa.*",
26
+ "id_dsa",
27
+ "id_dsa.*",
28
+ "kubeconfig",
29
+ "*kubeconfig*",
30
+ ".npmrc",
31
+ ".pypirc",
32
+ ".netrc",
33
+ ".git/config",
34
+ "*/.git/config",
35
+ ".git/credentials",
36
+ "*/.git/credentials",
37
+ ".git-credentials",
38
+ "credentials",
39
+ "credentials*",
40
+ "*.credentials",
41
+ "secrets.*",
42
+ "*secret*.json",
43
+ "*secret*.yaml",
44
+ "*secret*.yml",
45
+ "service-account*",
46
+ "service_account*",
47
+ ".aws/*",
48
+ "*/.aws/*",
49
+ ".ssh/*",
50
+ "*/.ssh/*",
51
+ ".gnupg/*",
52
+ "*/.gnupg/*",
53
+ ".kube/*",
54
+ "*/.kube/*",
55
+ ".docker/config.json",
56
+ "*/.docker/config.json",
57
+ "*docker*credential*",
58
+ "docker-credentials*",
59
+ "*.sqlite",
60
+ "*.sqlite3",
61
+ "*.db",
62
+ )
63
+
64
+ _SENSITIVE_DIRS: frozenset[str] = frozenset({
65
+ ".aws",
66
+ ".ssh",
67
+ ".gnupg",
68
+ ".kube",
69
+ })
70
+
71
+ _DEFAULT_SENSITIVE_REGEX = re.compile(
72
+ "|".join(f"(?:{fnmatch.translate(p.lower())})" for p in DEFAULT_SENSITIVE_PATTERNS)
73
+ )
74
+
75
+
76
+ def is_sensitive_path(
77
+ relative_path: str | Path,
78
+ patterns: tuple[str, ...] = DEFAULT_SENSITIVE_PATTERNS,
79
+ ) -> bool:
80
+ """Authoritative check for sensitive credentials, private keys, and secret configs."""
81
+ raw = str(relative_path).replace("\\", "/").strip()
82
+ while raw.startswith("./"):
83
+ raw = raw[2:]
84
+ p_obj = Path(raw)
85
+ value = p_obj.as_posix()
86
+ value_lower = value.lower()
87
+ name = p_obj.name
88
+ name_lower = name.lower()
89
+
90
+ parts_lower = {part.lower() for part in p_obj.parts}
91
+ if parts_lower & _SENSITIVE_DIRS:
92
+ return True
93
+
94
+ if value_lower in (".git/config", ".git/credentials") or value_lower.endswith(("/.git/config", "/.git/credentials")):
95
+ return True
96
+ if value_lower == ".docker/config.json" or value_lower.endswith("/.docker/config.json"):
97
+ return True
98
+
99
+ if patterns is DEFAULT_SENSITIVE_PATTERNS or patterns == DEFAULT_SENSITIVE_PATTERNS:
100
+ return bool(
101
+ _DEFAULT_SENSITIVE_REGEX.match(value_lower)
102
+ or _DEFAULT_SENSITIVE_REGEX.match(name_lower)
103
+ )
104
+
105
+ return any(
106
+ fnmatch.fnmatch(value, p)
107
+ or fnmatch.fnmatch(value_lower, p.lower())
108
+ or fnmatch.fnmatch(name, p)
109
+ or fnmatch.fnmatch(name_lower, p.lower())
110
+ for p in patterns
111
+ )
112
+
113
+
114
+ def is_sensitive(
115
+ relative_path: str | Path,
116
+ patterns: tuple[str, ...] = DEFAULT_SENSITIVE_PATTERNS,
117
+ ) -> bool:
118
+ """Alias for `is_sensitive_path` maintained for backward compatibility."""
119
+ return is_sensitive_path(relative_path, patterns=patterns)
120
+
121
+
122
+ def safe_path(repository: Path, requested: str | Path) -> Path:
123
+ """Resolve a repo-relative path and reject traversal and symlink escapes."""
124
+ root = repository.resolve(strict=True)
125
+ raw_value = unquote(str(requested))
126
+ if "\x00" in raw_value:
127
+ raise SecurityError("null bytes are not allowed in paths")
128
+ raw = Path(raw_value)
129
+ if raw.is_absolute():
130
+ raise SecurityError("absolute paths are not allowed")
131
+ candidate = (root / raw).resolve(strict=False)
132
+ try:
133
+ candidate.relative_to(root)
134
+ except ValueError as exc:
135
+ raise SecurityError("path escapes the configured repository") from exc
136
+ return candidate
137
+
138
+
139
+ def safe_read_text(
140
+ repository: Path,
141
+ requested: str | Path,
142
+ max_read_bytes: int = DEFAULT_MAX_READ_BYTES,
143
+ ) -> tuple[Path, str, str]:
144
+ """Safely validate and read a repository file with path-traversal, sensitive-path,
145
+ binary-file, and size-cap enforcement BEFORE reading full contents into memory.
146
+
147
+ Returns:
148
+ (resolved_path, relative_posix_path, text_content)
149
+ """
150
+ resolved = safe_path(repository, requested)
151
+ root = repository.resolve(strict=True)
152
+ relative = resolved.relative_to(root)
153
+ rel_posix = relative.as_posix()
154
+
155
+ if is_sensitive_path(relative) or is_sensitive_path( str(requested) ):
156
+ raise SecurityError(
157
+ f"sensitive files cannot be read: '{rel_posix}'",
158
+ code=ErrorCode.SENSITIVE_FILE_ACCESS_DENIED,
159
+ )
160
+
161
+ if not resolved.exists() or not resolved.is_file():
162
+ raise FileNotFoundError(f"File does not exist: '{rel_posix}'")
163
+
164
+ file_size = resolved.stat().st_size
165
+ if file_size > max_read_bytes:
166
+ raise SecurityError(
167
+ f"File '{rel_posix}' size ({file_size} bytes) exceeds max_read_bytes limit ({max_read_bytes} bytes).",
168
+ code=ErrorCode.FILE_TOO_LARGE,
169
+ )
170
+
171
+ with resolved.open("rb") as fh:
172
+ raw_bytes = fh.read(max_read_bytes + 1)
173
+
174
+ if len(raw_bytes) > max_read_bytes:
175
+ raise SecurityError(
176
+ f"File '{rel_posix}' exceeds max_read_bytes limit ({max_read_bytes} bytes).",
177
+ code=ErrorCode.FILE_TOO_LARGE,
178
+ )
179
+
180
+ if b"\x00" in raw_bytes[:8192]:
181
+ raise SecurityError(
182
+ f"Binary file '{rel_posix}' cannot be read as text.",
183
+ code=ErrorCode.BINARY_FILE_NOT_READABLE,
184
+ )
185
+
186
+ from .redaction import redact_secrets
187
+
188
+ decoded = raw_bytes.decode("utf-8", errors="replace")
189
+ return resolved, rel_posix, redact_secrets(decoded)