coding-client 1.21.2__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.
- coding_client/__init__.py +1 -0
- coding_client/api/__init__.py +19 -0
- coding_client/api/exception_handlers.py +158 -0
- coding_client/api/logging_setup.py +44 -0
- coding_client/api/metrics.py +40 -0
- coding_client/api/openapi_config.py +124 -0
- coding_client/api/request_logging.py +60 -0
- coding_client/api/validation.py +150 -0
- coding_client/auth/__init__.py +78 -0
- coding_client/auth/_default_tenant.py +132 -0
- coding_client/auth/_header_trust.py +98 -0
- coding_client/auth/_onbehalf.py +315 -0
- coding_client/auth/_trusted_networks.py +94 -0
- coding_client/auth/dependencies.py +61 -0
- coding_client/auth/middleware.py +445 -0
- coding_client/auth/models.py +83 -0
- coding_client/auth/outbound.py +137 -0
- coding_client/auth/rbac.py +21 -0
- coding_client/auth/rbac_coding.py +5 -0
- coding_client/auth/tenant.py +650 -0
- coding_client/auth/websocket.py +148 -0
- coding_client/clients/__init__.py +24 -0
- coding_client/clients/base.py +131 -0
- coding_client/clients/coding_ai.py +33 -0
- coding_client/clients/coding_analysis.py +36 -0
- coding_client/clients/coding_containers.py +45 -0
- coding_client/clients/coding_github.py +127 -0
- coding_client/clients/coding_realtime.py +127 -0
- coding_client/clients/coding_security.py +51 -0
- coding_client/clients/coding_testing.py +31 -0
- coding_client/clients/coding_workspaces.py +265 -0
- coding_client/config/__init__.py +12 -0
- coding_client/config/base_settings.py +61 -0
- coding_client/config/yaml_config_loader.py +172 -0
- coding_client/db/__init__.py +42 -0
- coding_client/db/db_types.py +122 -0
- coding_client/db/exceptions.py +59 -0
- coding_client/db/postgres_connection.py +572 -0
- coding_client/db/tenant_query_helper.py +417 -0
- coding_client/db_init.py +49 -0
- coding_client/exceptions/__init__.py +67 -0
- coding_client/exceptions/api_exceptions.py +395 -0
- coding_client/exceptions/pydantic_ai_exceptions.py +533 -0
- coding_client/interfaces/__init__.py +22 -0
- coding_client/interfaces/cache_interface.py +179 -0
- coding_client/interfaces/container_interface.py +49 -0
- coding_client/interfaces/docker_interface.py +283 -0
- coding_client/interfaces/graph_interface.py +28 -0
- coding_client/interfaces/security_interface.py +72 -0
- coding_client/interfaces/webhook_interface.py +67 -0
- coding_client/llm/__init__.py +54 -0
- coding_client/llm/base_agent.py +195 -0
- coding_client/llm/context.py +121 -0
- coding_client/llm/responses.py +102 -0
- coding_client/llm/routing.py +82 -0
- coding_client/llm/settings.py +102 -0
- coding_client/models/__init__.py +62 -0
- coding_client/models/agent.py +38 -0
- coding_client/models/ai_test_failure.py +745 -0
- coding_client/models/analysis.py +330 -0
- coding_client/models/architecture.py +685 -0
- coding_client/models/bug.py +128 -0
- coding_client/models/code_graph.py +317 -0
- coding_client/models/container.py +241 -0
- coding_client/models/core.py +878 -0
- coding_client/models/docker_container.py +104 -0
- coding_client/models/github.py +293 -0
- coding_client/models/logging.py +29 -0
- coding_client/models/package_manager.py +257 -0
- coding_client/models/pr_validation.py +440 -0
- coding_client/models/pydantic_ai.py +395 -0
- coding_client/models/repo_scanner.py +249 -0
- coding_client/models/responses.py +431 -0
- coding_client/models/security.py +185 -0
- coding_client/models/static_analysis.py +508 -0
- coding_client/models/system.py +48 -0
- coding_client/models/test_executor.py +204 -0
- coding_client/models/testing.py +673 -0
- coding_client/models/testing_config.py +200 -0
- coding_client/models/validation.py +127 -0
- coding_client/models_init.py +272 -0
- coding_client/telemetry.py +195 -0
- coding_client/testing.py +180 -0
- coding_client/types/__init__.py +130 -0
- coding_client/types/constraint_types.py +276 -0
- coding_client/types/core_types.py +112 -0
- coding_client/types/state_machine.py +443 -0
- coding_client/utils/__init__.py +86 -0
- coding_client/utils/archive_utils.py +387 -0
- coding_client/utils/ast_debug.py +45 -0
- coding_client/utils/async_timeout.py +364 -0
- coding_client/utils/constants.py +518 -0
- coding_client/utils/content_processing.py +326 -0
- coding_client/utils/database.py +916 -0
- coding_client/utils/encoding_helper.py +222 -0
- coding_client/utils/enum_helpers.py +166 -0
- coding_client/utils/file_operations.py +177 -0
- coding_client/utils/filesystem_ops.py +528 -0
- coding_client/utils/http_client.py +562 -0
- coding_client/utils/path_utils.py +471 -0
- coding_client/utils/profiling.py +421 -0
- coding_client/utils/response_builder.py +240 -0
- coding_client/utils/retry_helper.py +712 -0
- coding_client/utils/security_validation.py +423 -0
- coding_client-1.21.2.dist-info/METADATA +234 -0
- coding_client-1.21.2.dist-info/RECORD +109 -0
- coding_client-1.21.2.dist-info/WHEEL +5 -0
- coding_client-1.21.2.dist-info/licenses/LICENSE +201 -0
- coding_client-1.21.2.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Cache interface for breaking circular dependencies.
|
|
3
|
+
|
|
4
|
+
This module provides abstract interfaces for cache operations to prevent
|
|
5
|
+
circular dependencies between analysis_cache and language processing modules.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from abc import ABC, abstractmethod
|
|
11
|
+
from collections.abc import Callable
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
from typing import TYPE_CHECKING, Any
|
|
14
|
+
|
|
15
|
+
if TYPE_CHECKING:
|
|
16
|
+
# TODO: service-specific import removed
|
|
17
|
+
# from ..processing.languages.base import ParseResult
|
|
18
|
+
pass
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class IAnalysisCache(ABC):
|
|
22
|
+
"""Abstract interface for analysis cache operations."""
|
|
23
|
+
|
|
24
|
+
@abstractmethod
|
|
25
|
+
async def get_cached_result(self, file_path: Path, content: str) -> Any | None:
|
|
26
|
+
"""Get cached analysis result if available and valid.
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
file_path: Path to the source file
|
|
30
|
+
content: Current file content
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
Cached ParseResult if available, None otherwise
|
|
34
|
+
"""
|
|
35
|
+
pass
|
|
36
|
+
|
|
37
|
+
@abstractmethod
|
|
38
|
+
async def cache_result(self, file_path: Path, content: str, parse_result: Any) -> None:
|
|
39
|
+
"""Cache an analysis result.
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
file_path: Path to the source file
|
|
43
|
+
content: File content that was analyzed
|
|
44
|
+
parse_result: Analysis result to cache
|
|
45
|
+
"""
|
|
46
|
+
pass
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class ICacheManager(ABC):
|
|
50
|
+
"""Abstract interface for Redis-based cache manager operations."""
|
|
51
|
+
|
|
52
|
+
@abstractmethod
|
|
53
|
+
async def get(self, key: str) -> Any | None:
|
|
54
|
+
"""Get a value from cache.
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
key: Cache key
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
Cached value or None if not found
|
|
61
|
+
"""
|
|
62
|
+
...
|
|
63
|
+
|
|
64
|
+
@abstractmethod
|
|
65
|
+
async def set(self, key: str, value: Any, ttl: int | None = None) -> bool:
|
|
66
|
+
"""Set a value in cache.
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
key: Cache key
|
|
70
|
+
value: Value to cache
|
|
71
|
+
ttl: Time-to-live in seconds
|
|
72
|
+
|
|
73
|
+
Returns:
|
|
74
|
+
True if successful, False otherwise
|
|
75
|
+
"""
|
|
76
|
+
...
|
|
77
|
+
|
|
78
|
+
@abstractmethod
|
|
79
|
+
async def delete(
|
|
80
|
+
self, key: str, record_eviction: bool = True, eviction_reason: str = "manual"
|
|
81
|
+
) -> bool:
|
|
82
|
+
"""Delete a value from cache.
|
|
83
|
+
|
|
84
|
+
Args:
|
|
85
|
+
key: Cache key
|
|
86
|
+
record_eviction: Whether to record this deletion as an eviction
|
|
87
|
+
eviction_reason: Reason for eviction
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
True if successful, False otherwise
|
|
91
|
+
"""
|
|
92
|
+
...
|
|
93
|
+
|
|
94
|
+
@abstractmethod
|
|
95
|
+
async def delete_pattern(self, pattern: str) -> int:
|
|
96
|
+
"""Delete keys matching a pattern.
|
|
97
|
+
|
|
98
|
+
Args:
|
|
99
|
+
pattern: Key pattern (e.g., "container:*")
|
|
100
|
+
|
|
101
|
+
Returns:
|
|
102
|
+
Number of keys deleted
|
|
103
|
+
"""
|
|
104
|
+
...
|
|
105
|
+
|
|
106
|
+
@abstractmethod
|
|
107
|
+
async def get_or_compute(
|
|
108
|
+
self, key: str, compute_func: Callable[[], Any], ttl: int | None = None
|
|
109
|
+
) -> Any:
|
|
110
|
+
"""Get from cache or compute and cache.
|
|
111
|
+
|
|
112
|
+
Args:
|
|
113
|
+
key: Cache key
|
|
114
|
+
compute_func: Function to compute value if not cached
|
|
115
|
+
ttl: Time-to-live in seconds
|
|
116
|
+
|
|
117
|
+
Returns:
|
|
118
|
+
Cached or computed value
|
|
119
|
+
"""
|
|
120
|
+
...
|
|
121
|
+
|
|
122
|
+
@abstractmethod
|
|
123
|
+
def get_stats(self) -> dict[str, int]:
|
|
124
|
+
"""Get cache statistics.
|
|
125
|
+
|
|
126
|
+
Returns:
|
|
127
|
+
Dictionary with hits, misses, errors counts
|
|
128
|
+
"""
|
|
129
|
+
...
|
|
130
|
+
|
|
131
|
+
@abstractmethod
|
|
132
|
+
async def clear_stats(self) -> None:
|
|
133
|
+
"""Reset cache statistics."""
|
|
134
|
+
...
|
|
135
|
+
|
|
136
|
+
@abstractmethod
|
|
137
|
+
async def get_container_stats(self, container_name: str) -> dict[str, Any]:
|
|
138
|
+
"""Get cache statistics for a specific container.
|
|
139
|
+
|
|
140
|
+
Args:
|
|
141
|
+
container_name: Name of the container to get stats for
|
|
142
|
+
|
|
143
|
+
Returns:
|
|
144
|
+
Dictionary with hit_count, miss_count, size, entry_count
|
|
145
|
+
"""
|
|
146
|
+
...
|
|
147
|
+
|
|
148
|
+
@abstractmethod
|
|
149
|
+
async def clear_container_cache(self, container_name: str) -> int:
|
|
150
|
+
"""Clear all cache entries for a specific container.
|
|
151
|
+
|
|
152
|
+
Args:
|
|
153
|
+
container_name: Name of the container whose cache should be cleared
|
|
154
|
+
|
|
155
|
+
Returns:
|
|
156
|
+
Number of cache entries deleted
|
|
157
|
+
"""
|
|
158
|
+
...
|
|
159
|
+
|
|
160
|
+
@abstractmethod
|
|
161
|
+
async def get_container_keys(
|
|
162
|
+
self, container_name: str, limit: int = 100, offset: int = 0
|
|
163
|
+
) -> list[str]:
|
|
164
|
+
"""Get paginated list of cache keys for a specific container.
|
|
165
|
+
|
|
166
|
+
Args:
|
|
167
|
+
container_name: Name of the container to get keys for
|
|
168
|
+
limit: Maximum number of keys to return
|
|
169
|
+
offset: Number of keys to skip
|
|
170
|
+
|
|
171
|
+
Returns:
|
|
172
|
+
List of cache key strings
|
|
173
|
+
"""
|
|
174
|
+
...
|
|
175
|
+
|
|
176
|
+
@abstractmethod
|
|
177
|
+
async def close(self) -> None:
|
|
178
|
+
"""Close the cache manager and clean up resources."""
|
|
179
|
+
...
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Container interface for breaking circular dependencies.
|
|
3
|
+
|
|
4
|
+
This module provides abstract interfaces for container operations to prevent
|
|
5
|
+
circular dependencies between container_manager and graph_service modules.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from abc import ABC, abstractmethod
|
|
11
|
+
from typing import Protocol
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class ContainerInfo(Protocol):
|
|
15
|
+
"""Protocol for container information objects."""
|
|
16
|
+
|
|
17
|
+
container_name: str
|
|
18
|
+
code_graph_id: str
|
|
19
|
+
status: str
|
|
20
|
+
api_endpoint: str | None
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class IContainerManager(ABC):
|
|
24
|
+
"""Abstract interface for container management operations."""
|
|
25
|
+
|
|
26
|
+
@abstractmethod
|
|
27
|
+
def get_container_for_graph(self, code_graph_id: str) -> ContainerInfo | None:
|
|
28
|
+
"""Get container information for a specific code graph ID.
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
code_graph_id: The code graph identifier
|
|
32
|
+
|
|
33
|
+
Returns:
|
|
34
|
+
ContainerInfo if found, None otherwise
|
|
35
|
+
"""
|
|
36
|
+
pass
|
|
37
|
+
|
|
38
|
+
@abstractmethod
|
|
39
|
+
def list_containers(self) -> list[ContainerInfo]:
|
|
40
|
+
"""List all containers.
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
List of ContainerInfo objects
|
|
44
|
+
"""
|
|
45
|
+
pass
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
# Type alias for container manager instances
|
|
49
|
+
ContainerManagerType = IContainerManager
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Docker Service interface for breaking circular dependencies.
|
|
3
|
+
|
|
4
|
+
This module provides abstract interfaces for Docker container operations to prevent
|
|
5
|
+
circular dependencies and enable dependency injection.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from abc import ABC, abstractmethod
|
|
11
|
+
from typing import TYPE_CHECKING, Any
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from models.container import ContainerInfo, GitHubRepoRequest
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class IDockerService(ABC):
|
|
18
|
+
"""Abstract interface for Docker container operations."""
|
|
19
|
+
|
|
20
|
+
@abstractmethod
|
|
21
|
+
def is_docker_available(self) -> bool:
|
|
22
|
+
"""Check if Docker is available and accessible.
|
|
23
|
+
|
|
24
|
+
Returns:
|
|
25
|
+
True if Docker is available, False otherwise
|
|
26
|
+
"""
|
|
27
|
+
...
|
|
28
|
+
|
|
29
|
+
@abstractmethod
|
|
30
|
+
def retry_docker_connection(self) -> bool:
|
|
31
|
+
"""Attempt to reconnect to Docker if it wasn't available initially.
|
|
32
|
+
|
|
33
|
+
Returns:
|
|
34
|
+
True if reconnection succeeded, False otherwise
|
|
35
|
+
"""
|
|
36
|
+
...
|
|
37
|
+
|
|
38
|
+
@abstractmethod
|
|
39
|
+
async def create_container(
|
|
40
|
+
self, request: GitHubRepoRequest, env_vars: dict[str, str] | None = None
|
|
41
|
+
) -> ContainerInfo:
|
|
42
|
+
"""Create and start a Docker container for GitHub repository.
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
request: GitHub repository provisioning request
|
|
46
|
+
env_vars: Optional environment variables from secret store
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
ContainerInfo with container details
|
|
50
|
+
"""
|
|
51
|
+
...
|
|
52
|
+
|
|
53
|
+
@abstractmethod
|
|
54
|
+
async def remove_container(self, container: ContainerInfo) -> bool:
|
|
55
|
+
"""Remove existing container and cleanup.
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
container: Container info to remove
|
|
59
|
+
|
|
60
|
+
Returns:
|
|
61
|
+
True if removal succeeded, False otherwise
|
|
62
|
+
"""
|
|
63
|
+
...
|
|
64
|
+
|
|
65
|
+
@abstractmethod
|
|
66
|
+
async def remove_container_by_name(self, container_name: str) -> bool:
|
|
67
|
+
"""Remove a container by its name and clean up resources.
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
container_name: Name of the container to remove
|
|
71
|
+
|
|
72
|
+
Returns:
|
|
73
|
+
True if removal succeeded, False otherwise
|
|
74
|
+
"""
|
|
75
|
+
...
|
|
76
|
+
|
|
77
|
+
@abstractmethod
|
|
78
|
+
async def remove_container_by_id(self, docker_id: str, force: bool = True) -> None:
|
|
79
|
+
"""Remove a container by ID.
|
|
80
|
+
|
|
81
|
+
Args:
|
|
82
|
+
docker_id: Docker container ID
|
|
83
|
+
force: Force removal even if running
|
|
84
|
+
"""
|
|
85
|
+
...
|
|
86
|
+
|
|
87
|
+
@abstractmethod
|
|
88
|
+
async def start_container(self, docker_id: str) -> None:
|
|
89
|
+
"""Start a container by ID.
|
|
90
|
+
|
|
91
|
+
Args:
|
|
92
|
+
docker_id: Docker container ID
|
|
93
|
+
"""
|
|
94
|
+
...
|
|
95
|
+
|
|
96
|
+
@abstractmethod
|
|
97
|
+
async def stop_container(self, docker_id: str, timeout: int = 10) -> None:
|
|
98
|
+
"""Stop a container by ID.
|
|
99
|
+
|
|
100
|
+
Args:
|
|
101
|
+
docker_id: Docker container ID
|
|
102
|
+
timeout: Timeout in seconds before force kill
|
|
103
|
+
"""
|
|
104
|
+
...
|
|
105
|
+
|
|
106
|
+
@abstractmethod
|
|
107
|
+
async def list_containers(self) -> list[ContainerInfo]:
|
|
108
|
+
"""List all managed containers with real-time status verification.
|
|
109
|
+
|
|
110
|
+
Returns:
|
|
111
|
+
List of ContainerInfo objects
|
|
112
|
+
"""
|
|
113
|
+
...
|
|
114
|
+
|
|
115
|
+
@abstractmethod
|
|
116
|
+
async def find_container_by_name(self, container_name: str) -> ContainerInfo | None:
|
|
117
|
+
"""Find container by container_name.
|
|
118
|
+
|
|
119
|
+
Args:
|
|
120
|
+
container_name: Name of the container to find
|
|
121
|
+
|
|
122
|
+
Returns:
|
|
123
|
+
ContainerInfo if found, None otherwise
|
|
124
|
+
"""
|
|
125
|
+
...
|
|
126
|
+
|
|
127
|
+
@abstractmethod
|
|
128
|
+
async def find_existing_container(self, repo_url: str) -> ContainerInfo | None:
|
|
129
|
+
"""Find existing container by repository URL.
|
|
130
|
+
|
|
131
|
+
Args:
|
|
132
|
+
repo_url: Repository URL to search for
|
|
133
|
+
|
|
134
|
+
Returns:
|
|
135
|
+
ContainerInfo if found, None otherwise
|
|
136
|
+
"""
|
|
137
|
+
...
|
|
138
|
+
|
|
139
|
+
@abstractmethod
|
|
140
|
+
async def initialize_code_graph(
|
|
141
|
+
self,
|
|
142
|
+
container: ContainerInfo,
|
|
143
|
+
analysis_settings: dict[str, Any] | None = None,
|
|
144
|
+
) -> ContainerInfo:
|
|
145
|
+
"""Manually initialize the code graph by calling the container's initialization endpoint.
|
|
146
|
+
|
|
147
|
+
Args:
|
|
148
|
+
container: Container info to initialize graph for
|
|
149
|
+
analysis_settings: Optional analysis configuration
|
|
150
|
+
|
|
151
|
+
Returns:
|
|
152
|
+
Updated ContainerInfo
|
|
153
|
+
"""
|
|
154
|
+
...
|
|
155
|
+
|
|
156
|
+
@abstractmethod
|
|
157
|
+
async def read_container_file(
|
|
158
|
+
self,
|
|
159
|
+
container_name: str,
|
|
160
|
+
file_path: str,
|
|
161
|
+
offset: int = 0,
|
|
162
|
+
length: int | None = None,
|
|
163
|
+
) -> dict[str, Any]:
|
|
164
|
+
"""Read file from container using docker exec.
|
|
165
|
+
|
|
166
|
+
Args:
|
|
167
|
+
container_name: Name of the container
|
|
168
|
+
file_path: Path to the file inside the container
|
|
169
|
+
offset: Starting offset for reading
|
|
170
|
+
length: Number of bytes to read
|
|
171
|
+
|
|
172
|
+
Returns:
|
|
173
|
+
Dictionary with file content and metadata
|
|
174
|
+
"""
|
|
175
|
+
...
|
|
176
|
+
|
|
177
|
+
@abstractmethod
|
|
178
|
+
async def list_container_directory(
|
|
179
|
+
self, container_name: str, path: str = "", recursive: bool = False
|
|
180
|
+
) -> list[dict[str, Any]]:
|
|
181
|
+
"""List directory contents in container.
|
|
182
|
+
|
|
183
|
+
Args:
|
|
184
|
+
container_name: Name of the container
|
|
185
|
+
path: Directory path to list
|
|
186
|
+
recursive: Whether to list recursively
|
|
187
|
+
|
|
188
|
+
Returns:
|
|
189
|
+
List of directory entries
|
|
190
|
+
"""
|
|
191
|
+
...
|
|
192
|
+
|
|
193
|
+
@abstractmethod
|
|
194
|
+
async def exec_in_container(
|
|
195
|
+
self,
|
|
196
|
+
docker_id: str,
|
|
197
|
+
command: list[str],
|
|
198
|
+
timeout: int = 30,
|
|
199
|
+
environment: dict[str, str] | None = None,
|
|
200
|
+
user: str | None = None,
|
|
201
|
+
) -> dict[str, Any]:
|
|
202
|
+
"""Execute command in container and return structured result.
|
|
203
|
+
|
|
204
|
+
Args:
|
|
205
|
+
docker_id: Docker container ID or name
|
|
206
|
+
command: Command to execute as list of strings
|
|
207
|
+
timeout: Execution timeout in seconds
|
|
208
|
+
environment: Optional environment variables
|
|
209
|
+
user: Optional user to run command as
|
|
210
|
+
|
|
211
|
+
Returns:
|
|
212
|
+
Dictionary with exit_code, stdout, stderr, execution_time, timeout
|
|
213
|
+
"""
|
|
214
|
+
...
|
|
215
|
+
|
|
216
|
+
@abstractmethod
|
|
217
|
+
async def create_file_in_container(
|
|
218
|
+
self, docker_id: str, file_path: str, content: str, mode: str = "w"
|
|
219
|
+
) -> bool:
|
|
220
|
+
"""Create file with content in container.
|
|
221
|
+
|
|
222
|
+
Args:
|
|
223
|
+
docker_id: Docker container ID or name
|
|
224
|
+
file_path: Path to create file at
|
|
225
|
+
content: Content to write
|
|
226
|
+
mode: Write mode ('w' for write, 'a' for append)
|
|
227
|
+
|
|
228
|
+
Returns:
|
|
229
|
+
True if successful, False otherwise
|
|
230
|
+
"""
|
|
231
|
+
...
|
|
232
|
+
|
|
233
|
+
@abstractmethod
|
|
234
|
+
async def get_container_stats(self, docker_id: str) -> dict[str, Any]:
|
|
235
|
+
"""Get resource usage statistics for container.
|
|
236
|
+
|
|
237
|
+
Args:
|
|
238
|
+
docker_id: Docker container ID or name
|
|
239
|
+
|
|
240
|
+
Returns:
|
|
241
|
+
Dictionary with resource statistics
|
|
242
|
+
"""
|
|
243
|
+
...
|
|
244
|
+
|
|
245
|
+
@abstractmethod
|
|
246
|
+
def get_language_container_image(self, language: str) -> str:
|
|
247
|
+
"""Get appropriate container image for language.
|
|
248
|
+
|
|
249
|
+
Args:
|
|
250
|
+
language: Programming language name
|
|
251
|
+
|
|
252
|
+
Returns:
|
|
253
|
+
Docker image name for the language
|
|
254
|
+
"""
|
|
255
|
+
...
|
|
256
|
+
|
|
257
|
+
@abstractmethod
|
|
258
|
+
async def create_test_container(self, config: dict[str, Any]) -> str:
|
|
259
|
+
"""Create container specifically for test execution.
|
|
260
|
+
|
|
261
|
+
Args:
|
|
262
|
+
config: Container configuration
|
|
263
|
+
|
|
264
|
+
Returns:
|
|
265
|
+
Container ID
|
|
266
|
+
"""
|
|
267
|
+
...
|
|
268
|
+
|
|
269
|
+
@abstractmethod
|
|
270
|
+
async def install_tools_in_container(
|
|
271
|
+
self, docker_id: str, tools: list[str], language: str = "python"
|
|
272
|
+
) -> bool:
|
|
273
|
+
"""Install testing/quality tools in container.
|
|
274
|
+
|
|
275
|
+
Args:
|
|
276
|
+
docker_id: Docker container ID or name
|
|
277
|
+
tools: List of tool names to install
|
|
278
|
+
language: Programming language for tool installation
|
|
279
|
+
|
|
280
|
+
Returns:
|
|
281
|
+
True if successful, False otherwise
|
|
282
|
+
"""
|
|
283
|
+
...
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Graph interface for breaking circular dependencies.
|
|
3
|
+
|
|
4
|
+
This module provides abstract interfaces for graph operations to prevent
|
|
5
|
+
circular dependencies between graph_service and container_manager modules.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from abc import ABC, abstractmethod
|
|
11
|
+
from typing import Any
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class IGraphService(ABC):
|
|
15
|
+
"""Abstract interface for graph service operations."""
|
|
16
|
+
|
|
17
|
+
@abstractmethod
|
|
18
|
+
async def delete_graph(self, graph_id: str, force: bool = False) -> dict[str, Any]:
|
|
19
|
+
"""Delete a graph and all associated data.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
graph_id: Unique identifier of the graph to delete
|
|
23
|
+
force: If True, force deletion even for containerized graphs
|
|
24
|
+
|
|
25
|
+
Returns:
|
|
26
|
+
Dict containing deletion results
|
|
27
|
+
"""
|
|
28
|
+
pass
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Security Service interface for breaking circular dependencies.
|
|
3
|
+
|
|
4
|
+
This module provides abstract interfaces for security validation operations to prevent
|
|
5
|
+
circular dependencies and enable dependency injection.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from abc import ABC, abstractmethod
|
|
11
|
+
from typing import TYPE_CHECKING, Any
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from models.security import (
|
|
15
|
+
SecurityValidationRequest,
|
|
16
|
+
SecurityValidationResult,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class ISecurityService(ABC):
|
|
21
|
+
"""Abstract interface for security validation operations."""
|
|
22
|
+
|
|
23
|
+
@abstractmethod
|
|
24
|
+
async def validate_code_security(
|
|
25
|
+
self, request: SecurityValidationRequest
|
|
26
|
+
) -> SecurityValidationResult:
|
|
27
|
+
"""Main security validation method with comprehensive analysis.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
request: Security validation request containing code and configuration
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
SecurityValidationResult with safety status, violations, and risk score
|
|
34
|
+
"""
|
|
35
|
+
...
|
|
36
|
+
|
|
37
|
+
@abstractmethod
|
|
38
|
+
async def generate_sandbox_config(self, language: str, security_level: str) -> dict[str, Any]:
|
|
39
|
+
"""Generate sandbox configuration based on language and security level.
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
language: Programming language for sandbox configuration
|
|
43
|
+
security_level: Security level (low, medium, high, critical)
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
Dictionary containing sandbox configuration
|
|
47
|
+
"""
|
|
48
|
+
...
|
|
49
|
+
|
|
50
|
+
@abstractmethod
|
|
51
|
+
def get_dangerous_patterns(self, language: str) -> list[dict[str, Any]]:
|
|
52
|
+
"""Get dangerous code patterns for a specific language.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
language: Programming language name
|
|
56
|
+
|
|
57
|
+
Returns:
|
|
58
|
+
List of pattern dictionaries with pattern, severity, description
|
|
59
|
+
"""
|
|
60
|
+
...
|
|
61
|
+
|
|
62
|
+
@abstractmethod
|
|
63
|
+
def get_sandbox_config(self, language: str) -> dict[str, Any] | None:
|
|
64
|
+
"""Get default sandbox configuration for a language.
|
|
65
|
+
|
|
66
|
+
Args:
|
|
67
|
+
language: Programming language name
|
|
68
|
+
|
|
69
|
+
Returns:
|
|
70
|
+
Sandbox configuration dictionary or None if not configured
|
|
71
|
+
"""
|
|
72
|
+
...
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Webhook interface for breaking circular dependencies.
|
|
3
|
+
|
|
4
|
+
This module provides abstract interfaces for webhook event handling to prevent
|
|
5
|
+
circular dependencies between webhook handler and endpoint modules.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from abc import ABC, abstractmethod
|
|
11
|
+
from typing import Any
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class IWebhookEventHandler(ABC):
|
|
15
|
+
"""Abstract interface for webhook event handlers."""
|
|
16
|
+
|
|
17
|
+
@abstractmethod
|
|
18
|
+
async def analyze_pull_request_changes(
|
|
19
|
+
self, repo_name: str, pr_number: int, trigger: str
|
|
20
|
+
) -> None:
|
|
21
|
+
"""Analyze changes in a pull request and provide feedback.
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
repo_name: Repository name (owner/repo)
|
|
25
|
+
pr_number: Pull request number
|
|
26
|
+
trigger: What triggered the analysis
|
|
27
|
+
"""
|
|
28
|
+
pass
|
|
29
|
+
|
|
30
|
+
@abstractmethod
|
|
31
|
+
async def analyze_repository_changes(
|
|
32
|
+
self, repo_name: str, branch: str, commits: list
|
|
33
|
+
) -> dict[str, Any]:
|
|
34
|
+
"""Analyze changes from push events.
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
repo_name: Repository name (owner/repo)
|
|
38
|
+
branch: Branch name
|
|
39
|
+
commits: List of commits
|
|
40
|
+
|
|
41
|
+
Returns:
|
|
42
|
+
Analysis results dictionary
|
|
43
|
+
"""
|
|
44
|
+
pass
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class WebhookEventHandlerRegistry:
|
|
48
|
+
"""Registry for webhook event handlers to enable dependency injection."""
|
|
49
|
+
|
|
50
|
+
_handlers: dict[str, IWebhookEventHandler] = {}
|
|
51
|
+
|
|
52
|
+
@classmethod
|
|
53
|
+
def register(cls, name: str, handler: IWebhookEventHandler) -> None:
|
|
54
|
+
"""Register a webhook event handler."""
|
|
55
|
+
cls._handlers[name] = handler
|
|
56
|
+
|
|
57
|
+
@classmethod
|
|
58
|
+
def get_handler(cls, name: str) -> IWebhookEventHandler | None:
|
|
59
|
+
"""Get a registered webhook event handler."""
|
|
60
|
+
return cls._handlers.get(name)
|
|
61
|
+
|
|
62
|
+
@classmethod
|
|
63
|
+
def get(cls, name: str) -> IWebhookEventHandler:
|
|
64
|
+
"""Get a registered webhook event handler (with error if not found)."""
|
|
65
|
+
if name not in cls._handlers:
|
|
66
|
+
raise ValueError(f"No handler registered with name: {name}")
|
|
67
|
+
return cls._handlers[name]
|