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,431 @@
|
|
|
1
|
+
"""Common response models for consistent API endpoint responses.
|
|
2
|
+
|
|
3
|
+
This module provides standardized response models that ensure consistency across all
|
|
4
|
+
API endpoints in the code graph helper system. These models support proper OpenAPI
|
|
5
|
+
documentation generation and provide a unified error handling experience.
|
|
6
|
+
|
|
7
|
+
The response models follow REST API best practices with:
|
|
8
|
+
- Consistent status codes and error formats
|
|
9
|
+
- Standardized field naming and structure
|
|
10
|
+
- Comprehensive OpenAPI documentation examples
|
|
11
|
+
- Type-safe response validation
|
|
12
|
+
|
|
13
|
+
Key Components:
|
|
14
|
+
Base Models: BaseResponse, LegacyStandardErrorResponse for consistent structure
|
|
15
|
+
Error Models: Specialized models for different HTTP error types (400, 401, 403, etc.)
|
|
16
|
+
Utility Functions: Helper functions for generating response schemas
|
|
17
|
+
Response Schemas: Pre-configured OpenAPI documentation examples
|
|
18
|
+
|
|
19
|
+
Example:
|
|
20
|
+
```python
|
|
21
|
+
from common_responses_models import LegacyBaseResponse, LegacyResponseStatus, get_common_responses
|
|
22
|
+
|
|
23
|
+
# Create a successful response
|
|
24
|
+
response = LegacyBaseResponse(
|
|
25
|
+
status=LegacyResponseStatus.SUCCESS,
|
|
26
|
+
message="Operation completed successfully",
|
|
27
|
+
data={"result": "value"}
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
# Get OpenAPI response schemas
|
|
31
|
+
responses = get_common_responses(400, 404, 500)
|
|
32
|
+
```
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
from __future__ import annotations
|
|
36
|
+
|
|
37
|
+
from enum import StrEnum
|
|
38
|
+
from typing import Any
|
|
39
|
+
|
|
40
|
+
from fastapi import HTTPException, status
|
|
41
|
+
from pydantic import BaseModel, Field
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class LegacyResponseStatus(StrEnum):
|
|
45
|
+
"""Legacy response status enum (deprecated - use V2 API ResponseStatus)."""
|
|
46
|
+
|
|
47
|
+
SUCCESS = "success"
|
|
48
|
+
ERROR = "error"
|
|
49
|
+
WARNING = "warning"
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class LegacyBaseResponse(BaseModel):
|
|
53
|
+
"""Legacy base response model (deprecated - use V2 API BaseResponse)."""
|
|
54
|
+
|
|
55
|
+
status: LegacyResponseStatus = Field(
|
|
56
|
+
default=LegacyResponseStatus.SUCCESS, description="Response status"
|
|
57
|
+
)
|
|
58
|
+
message: str | None = Field(default=None, description="Response message")
|
|
59
|
+
data: dict[str, Any] | None = Field(default=None, description="Response data")
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class ValidationErrorDetail(BaseModel):
|
|
63
|
+
"""Individual validation error detail."""
|
|
64
|
+
|
|
65
|
+
loc: list[str] = Field(..., description="Location of the validation error")
|
|
66
|
+
msg: str = Field(..., description="Error message")
|
|
67
|
+
type: str = Field(..., description="Error type")
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class LegacyStandardErrorResponse(BaseModel):
|
|
71
|
+
"""Legacy standard error response format (deprecated - use V2 API error models)."""
|
|
72
|
+
|
|
73
|
+
detail: str = Field(..., description="Error message")
|
|
74
|
+
status_code: int | None = Field(None, description="HTTP status code")
|
|
75
|
+
type: str | None = Field(None, description="Error type")
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
class SimpleValidationErrorResponse(BaseModel):
|
|
79
|
+
"""Response model for validation errors (422)."""
|
|
80
|
+
|
|
81
|
+
detail: list[ValidationErrorDetail] = Field(..., description="List of validation errors")
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class NotFoundResponse(BaseModel):
|
|
85
|
+
"""Response model for resource not found errors (404)."""
|
|
86
|
+
|
|
87
|
+
detail: str = Field(..., description="Resource not found message")
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class UnauthorizedResponse(BaseModel):
|
|
91
|
+
"""Response model for authentication errors (401)."""
|
|
92
|
+
|
|
93
|
+
detail: str = Field(..., description="Authentication error message")
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
class ForbiddenResponse(BaseModel):
|
|
97
|
+
"""Response model for authorization errors (403)."""
|
|
98
|
+
|
|
99
|
+
detail: str = Field(..., description="Authorization error message")
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class InternalServerErrorResponse(BaseModel):
|
|
103
|
+
"""Response model for server errors (500)."""
|
|
104
|
+
|
|
105
|
+
detail: str = Field(..., description="Internal server error message")
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
class BadRequestResponse(BaseModel):
|
|
109
|
+
"""Response model for bad request errors (400)."""
|
|
110
|
+
|
|
111
|
+
detail: str = Field(..., description="Bad request error message")
|
|
112
|
+
status_code: int | None = Field(400, description="HTTP status code")
|
|
113
|
+
type: str | None = Field("input_validation_error", description="Error type")
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
class ServiceUnavailableResponse(BaseModel):
|
|
117
|
+
"""Response model for service unavailable errors (503)."""
|
|
118
|
+
|
|
119
|
+
detail: str = Field(..., description="Service unavailable error message")
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
class GoneResponse(BaseModel):
|
|
123
|
+
"""Response model for gone/deprecated resource errors (410)."""
|
|
124
|
+
|
|
125
|
+
detail: str = Field(..., description="Resource is gone or deprecated message")
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
class NotImplementedResponse(BaseModel):
|
|
129
|
+
"""Response model for not implemented errors (501)."""
|
|
130
|
+
|
|
131
|
+
detail: str = Field(..., description="Feature not implemented error message")
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
class TimeoutResponse(BaseModel):
|
|
135
|
+
"""Response model for timeout errors (408)."""
|
|
136
|
+
|
|
137
|
+
detail: str = Field(..., description="Request timeout error message")
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
# Common response schemas for OpenAPI documentation
|
|
141
|
+
COMMON_RESPONSES = {
|
|
142
|
+
400: {
|
|
143
|
+
"description": "Bad Request - Invalid input or malformed request",
|
|
144
|
+
"model": BadRequestResponse,
|
|
145
|
+
"content": {
|
|
146
|
+
"application/json": {
|
|
147
|
+
"examples": {
|
|
148
|
+
"validation_error": {
|
|
149
|
+
"summary": "Input validation error",
|
|
150
|
+
"value": {
|
|
151
|
+
"detail": "Invalid request body: Unsafe string contains illegal characters",
|
|
152
|
+
"status_code": 400,
|
|
153
|
+
"type": "input_validation_error",
|
|
154
|
+
},
|
|
155
|
+
},
|
|
156
|
+
"path_error": {
|
|
157
|
+
"summary": "Path validation error",
|
|
158
|
+
"value": {
|
|
159
|
+
"detail": "Invalid request path contains illegal characters",
|
|
160
|
+
"status_code": 400,
|
|
161
|
+
"type": "input_validation_error",
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
401: {
|
|
169
|
+
"description": "Unauthorized - Authentication required or invalid credentials",
|
|
170
|
+
"model": UnauthorizedResponse,
|
|
171
|
+
"content": {
|
|
172
|
+
"application/json": {"example": {"detail": "Invalid authentication credentials"}}
|
|
173
|
+
},
|
|
174
|
+
},
|
|
175
|
+
403: {
|
|
176
|
+
"description": "Forbidden - Insufficient permissions",
|
|
177
|
+
"model": ForbiddenResponse,
|
|
178
|
+
"content": {
|
|
179
|
+
"application/json": {
|
|
180
|
+
"example": {"detail": "Insufficient permissions to access this resource"}
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
},
|
|
184
|
+
404: {
|
|
185
|
+
"description": "Not Found - Resource does not exist",
|
|
186
|
+
"model": NotFoundResponse,
|
|
187
|
+
"content": {"application/json": {"example": {"detail": "Resource not found"}}},
|
|
188
|
+
},
|
|
189
|
+
408: {
|
|
190
|
+
"description": "Request Timeout - Request took too long to process",
|
|
191
|
+
"model": TimeoutResponse,
|
|
192
|
+
"content": {
|
|
193
|
+
"application/json": {
|
|
194
|
+
"example": {"detail": "Request timeout - processing took too long"}
|
|
195
|
+
}
|
|
196
|
+
},
|
|
197
|
+
},
|
|
198
|
+
410: {
|
|
199
|
+
"description": "Gone - Resource is deprecated or no longer available",
|
|
200
|
+
"model": GoneResponse,
|
|
201
|
+
"content": {
|
|
202
|
+
"application/json": {
|
|
203
|
+
"example": {
|
|
204
|
+
"detail": "This endpoint has been deprecated. Use containerized alternatives."
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
},
|
|
208
|
+
},
|
|
209
|
+
422: {
|
|
210
|
+
"description": "Unprocessable Entity - Validation errors",
|
|
211
|
+
"model": SimpleValidationErrorResponse,
|
|
212
|
+
"content": {
|
|
213
|
+
"application/json": {
|
|
214
|
+
"example": {
|
|
215
|
+
"detail": [
|
|
216
|
+
{
|
|
217
|
+
"loc": ["body", "field_name"],
|
|
218
|
+
"msg": "field required",
|
|
219
|
+
"type": "value_error.missing",
|
|
220
|
+
}
|
|
221
|
+
]
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
},
|
|
225
|
+
},
|
|
226
|
+
500: {
|
|
227
|
+
"description": "Internal Server Error - Unexpected server error",
|
|
228
|
+
"model": InternalServerErrorResponse,
|
|
229
|
+
"content": {"application/json": {"example": {"detail": "Internal server error occurred"}}},
|
|
230
|
+
},
|
|
231
|
+
501: {
|
|
232
|
+
"description": "Not Implemented - Feature not yet implemented",
|
|
233
|
+
"model": NotImplementedResponse,
|
|
234
|
+
"content": {
|
|
235
|
+
"application/json": {
|
|
236
|
+
"example": {
|
|
237
|
+
"detail": "This feature is not yet implemented. Planned for future release."
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
},
|
|
241
|
+
},
|
|
242
|
+
503: {
|
|
243
|
+
"description": "Service Unavailable - External service is unavailable",
|
|
244
|
+
"model": ServiceUnavailableResponse,
|
|
245
|
+
"content": {
|
|
246
|
+
"application/json": {"example": {"detail": "External service is currently unavailable"}}
|
|
247
|
+
},
|
|
248
|
+
},
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
def get_common_responses(*status_codes: int) -> dict[int, dict[str, Any]]:
|
|
253
|
+
"""Get common response schemas for specified status codes.
|
|
254
|
+
|
|
255
|
+
Args:
|
|
256
|
+
*status_codes: HTTP status codes to include
|
|
257
|
+
|
|
258
|
+
Returns:
|
|
259
|
+
Dict mapping status codes to response schemas
|
|
260
|
+
"""
|
|
261
|
+
return {code: COMMON_RESPONSES[code] for code in status_codes if code in COMMON_RESPONSES}
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
def get_standard_responses() -> dict[int, dict[str, Any]]:
|
|
265
|
+
"""Get standard responses that most endpoints should include.
|
|
266
|
+
|
|
267
|
+
Returns:
|
|
268
|
+
Dict with common 400, 404, 422, and 500 responses
|
|
269
|
+
"""
|
|
270
|
+
return get_common_responses(400, 404, 422, 500)
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
def get_auth_responses() -> dict[int, dict[str, Any]]:
|
|
274
|
+
"""Get authentication-related responses.
|
|
275
|
+
|
|
276
|
+
Returns:
|
|
277
|
+
Dict with 401 and 403 responses
|
|
278
|
+
"""
|
|
279
|
+
return get_common_responses(401, 403)
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
def get_all_responses() -> dict[int, dict[str, Any]]:
|
|
283
|
+
"""Get all common response schemas.
|
|
284
|
+
|
|
285
|
+
Returns:
|
|
286
|
+
Dict with all defined response schemas
|
|
287
|
+
"""
|
|
288
|
+
return COMMON_RESPONSES.copy()
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
# ============================================================================
|
|
292
|
+
# Response helper functions
|
|
293
|
+
# ============================================================================
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
def success_response(data: Any, message: str = "Success") -> dict:
|
|
297
|
+
"""Create a standardized success response.
|
|
298
|
+
|
|
299
|
+
Args:
|
|
300
|
+
data: The response data payload
|
|
301
|
+
message: Optional success message
|
|
302
|
+
|
|
303
|
+
Returns:
|
|
304
|
+
Dict with standardized success format
|
|
305
|
+
"""
|
|
306
|
+
return {
|
|
307
|
+
"status": "success",
|
|
308
|
+
"message": message,
|
|
309
|
+
"data": data,
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
def error_response(
|
|
314
|
+
status_code: int,
|
|
315
|
+
message: str,
|
|
316
|
+
error_code: str = "INTERNAL_ERROR",
|
|
317
|
+
details: dict | None = None,
|
|
318
|
+
) -> HTTPException:
|
|
319
|
+
"""Create a standardized error HTTPException.
|
|
320
|
+
|
|
321
|
+
Args:
|
|
322
|
+
status_code: HTTP status code
|
|
323
|
+
message: Human-readable error message
|
|
324
|
+
error_code: Machine-readable error code
|
|
325
|
+
details: Additional error details
|
|
326
|
+
|
|
327
|
+
Returns:
|
|
328
|
+
HTTPException with standardized error format
|
|
329
|
+
"""
|
|
330
|
+
return HTTPException(
|
|
331
|
+
status_code=status_code,
|
|
332
|
+
detail={
|
|
333
|
+
"status": "error",
|
|
334
|
+
"message": message,
|
|
335
|
+
"error_code": error_code,
|
|
336
|
+
"details": details or {},
|
|
337
|
+
},
|
|
338
|
+
)
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
def not_found(resource: str, identifier: str) -> HTTPException:
|
|
342
|
+
"""Create a 404 Not Found error."""
|
|
343
|
+
return error_response(
|
|
344
|
+
status_code=status.HTTP_404_NOT_FOUND,
|
|
345
|
+
message=f"{resource} '{identifier}' not found",
|
|
346
|
+
error_code=f"{resource.upper().replace(' ', '_')}_NOT_FOUND",
|
|
347
|
+
)
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
def bad_request(message: str, details: dict | None = None) -> HTTPException:
|
|
351
|
+
"""Create a 400 Bad Request error."""
|
|
352
|
+
return error_response(
|
|
353
|
+
status_code=status.HTTP_400_BAD_REQUEST,
|
|
354
|
+
message=message,
|
|
355
|
+
error_code="BAD_REQUEST",
|
|
356
|
+
details=details,
|
|
357
|
+
)
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
def validation_error(message: str, field: str, details: dict | None = None) -> HTTPException:
|
|
361
|
+
"""Create a 422 Validation Error."""
|
|
362
|
+
return error_response(
|
|
363
|
+
status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
|
|
364
|
+
message=message,
|
|
365
|
+
error_code="VALIDATION_ERROR",
|
|
366
|
+
details={"field": field, **(details or {})},
|
|
367
|
+
)
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
def internal_error(message: str, details: dict | None = None) -> HTTPException:
|
|
371
|
+
"""Create a 500 Internal Server Error."""
|
|
372
|
+
return error_response(
|
|
373
|
+
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
374
|
+
message=message,
|
|
375
|
+
error_code="INTERNAL_ERROR",
|
|
376
|
+
details=details,
|
|
377
|
+
)
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
def unauthorized(message: str = "Authentication required") -> HTTPException:
|
|
381
|
+
"""Create a 401 Unauthorized error."""
|
|
382
|
+
return error_response(
|
|
383
|
+
status_code=status.HTTP_401_UNAUTHORIZED,
|
|
384
|
+
message=message,
|
|
385
|
+
error_code="UNAUTHORIZED",
|
|
386
|
+
)
|
|
387
|
+
|
|
388
|
+
|
|
389
|
+
def forbidden(message: str = "Access denied") -> HTTPException:
|
|
390
|
+
"""Create a 403 Forbidden error."""
|
|
391
|
+
return error_response(
|
|
392
|
+
status_code=status.HTTP_403_FORBIDDEN,
|
|
393
|
+
message=message,
|
|
394
|
+
error_code="FORBIDDEN",
|
|
395
|
+
)
|
|
396
|
+
|
|
397
|
+
|
|
398
|
+
def conflict(resource: str, message: str) -> HTTPException:
|
|
399
|
+
"""Create a 409 Conflict error."""
|
|
400
|
+
return error_response(
|
|
401
|
+
status_code=status.HTTP_409_CONFLICT,
|
|
402
|
+
message=message,
|
|
403
|
+
error_code=f"{resource.upper().replace(' ', '_')}_CONFLICT",
|
|
404
|
+
)
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
def service_unavailable(message: str = "Service temporarily unavailable") -> HTTPException:
|
|
408
|
+
"""Create a 503 Service Unavailable error."""
|
|
409
|
+
return error_response(
|
|
410
|
+
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
|
|
411
|
+
message=message,
|
|
412
|
+
error_code="SERVICE_UNAVAILABLE",
|
|
413
|
+
)
|
|
414
|
+
|
|
415
|
+
|
|
416
|
+
def timeout_error(message: str = "Request timed out") -> HTTPException:
|
|
417
|
+
"""Create a 504 Gateway Timeout error."""
|
|
418
|
+
return error_response(
|
|
419
|
+
status_code=status.HTTP_504_GATEWAY_TIMEOUT,
|
|
420
|
+
message=message,
|
|
421
|
+
error_code="TIMEOUT",
|
|
422
|
+
)
|
|
423
|
+
|
|
424
|
+
|
|
425
|
+
def rate_limited(message: str = "Rate limit exceeded") -> HTTPException:
|
|
426
|
+
"""Create a 429 Too Many Requests error."""
|
|
427
|
+
return error_response(
|
|
428
|
+
status_code=status.HTTP_429_TOO_MANY_REQUESTS,
|
|
429
|
+
message=message,
|
|
430
|
+
error_code="RATE_LIMITED",
|
|
431
|
+
)
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
"""Security-specific Pydantic models for code security analysis and validation.
|
|
2
|
+
|
|
3
|
+
This module provides comprehensive data models for security analysis operations,
|
|
4
|
+
including code vulnerability detection, security violation reporting, and
|
|
5
|
+
security-aware code validation. The models support multi-level security
|
|
6
|
+
assessment and provide structured security analysis results.
|
|
7
|
+
|
|
8
|
+
The security analysis system enables:
|
|
9
|
+
- Code vulnerability detection with severity assessment
|
|
10
|
+
- Security violation reporting with remediation suggestions
|
|
11
|
+
- Multi-level security validation (LOW, MEDIUM, HIGH, CRITICAL)
|
|
12
|
+
- Context-aware security analysis with configurable rules
|
|
13
|
+
- Integration with security scanning tools and methodologies
|
|
14
|
+
|
|
15
|
+
Key Model Categories:
|
|
16
|
+
Enumeration Models: SecurityLevel for security level classification
|
|
17
|
+
Violation Models: SecurityViolation for detected security issues
|
|
18
|
+
Request Models: SecurityValidationRequest, SecurityScanRequest, SecurityReportRequest
|
|
19
|
+
Response Models: SecurityValidationResult, VulnerabilityScanResult
|
|
20
|
+
|
|
21
|
+
Security Features:
|
|
22
|
+
- Pattern-based vulnerability detection
|
|
23
|
+
- Severity-based issue classification
|
|
24
|
+
- Remediation suggestion generation
|
|
25
|
+
- Context-aware security analysis
|
|
26
|
+
- Configurable security validation levels
|
|
27
|
+
|
|
28
|
+
Example:
|
|
29
|
+
```python
|
|
30
|
+
from security_models import (
|
|
31
|
+
SecurityLevel, SecurityViolation,
|
|
32
|
+
SecurityValidationRequest, SecurityValidationResult
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
# Create security validation request
|
|
36
|
+
request = SecurityValidationRequest(
|
|
37
|
+
code='import os\\nos.system("rm -rf /")',
|
|
38
|
+
language="python",
|
|
39
|
+
security_level=SecurityLevel.HIGH,
|
|
40
|
+
context={"environment": "production"}
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
# Security violation detection
|
|
44
|
+
violation = SecurityViolation(
|
|
45
|
+
type="command_injection",
|
|
46
|
+
severity=SecurityLevel.CRITICAL,
|
|
47
|
+
line_number=2,
|
|
48
|
+
pattern_matched="os.system",
|
|
49
|
+
description="Dangerous system command execution detected",
|
|
50
|
+
suggested_fix="Use subprocess.run with shell=False instead"
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
# Security validation result
|
|
54
|
+
result = SecurityValidationResult(
|
|
55
|
+
is_safe=False,
|
|
56
|
+
violations=[violation],
|
|
57
|
+
risk_score=95.0,
|
|
58
|
+
sandbox_config={"network_access": False, "file_system": "read_only"}
|
|
59
|
+
)
|
|
60
|
+
```
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
from __future__ import annotations
|
|
64
|
+
|
|
65
|
+
from datetime import datetime
|
|
66
|
+
from enum import StrEnum
|
|
67
|
+
from typing import Any
|
|
68
|
+
|
|
69
|
+
from pydantic import BaseModel, Field
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class SecurityLevel(StrEnum):
|
|
73
|
+
"""Enumeration of security levels for code validation and risk assessment.
|
|
74
|
+
|
|
75
|
+
Defines the security validation levels that determine the depth and strictness
|
|
76
|
+
of security analysis performed on code. Each level applies different security
|
|
77
|
+
rules and has different performance characteristics.
|
|
78
|
+
|
|
79
|
+
Attributes:
|
|
80
|
+
LOW: Basic security checks with minimal performance impact.
|
|
81
|
+
Suitable for development environments and low-risk code.
|
|
82
|
+
MEDIUM: Standard security validation with balanced performance.
|
|
83
|
+
Appropriate for most production code and regular workflows.
|
|
84
|
+
HIGH: Comprehensive security analysis with thorough validation.
|
|
85
|
+
Recommended for security-sensitive applications and critical systems.
|
|
86
|
+
CRITICAL: Maximum security scrutiny with intensive analysis.
|
|
87
|
+
Required for high-security environments and critical infrastructure.
|
|
88
|
+
"""
|
|
89
|
+
|
|
90
|
+
LOW = "low"
|
|
91
|
+
MEDIUM = "medium"
|
|
92
|
+
HIGH = "high"
|
|
93
|
+
CRITICAL = "critical"
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
class SecurityViolation(BaseModel):
|
|
97
|
+
"""Model representing a security violation detected in code analysis."""
|
|
98
|
+
|
|
99
|
+
type: str = Field(..., description="Type of security violation")
|
|
100
|
+
severity: SecurityLevel = Field(..., description="Severity level")
|
|
101
|
+
line_number: int | None = Field(None, description="Line number where violation occurs")
|
|
102
|
+
pattern_matched: str = Field(..., description="Pattern that triggered the violation")
|
|
103
|
+
description: str = Field(..., description="Human-readable description")
|
|
104
|
+
suggested_fix: str | None = Field(None, description="Suggested remediation")
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class SecurityValidationRequest(BaseModel):
|
|
108
|
+
"""Request model for security validation of code snippets."""
|
|
109
|
+
|
|
110
|
+
code: str = Field(..., description="Code to validate")
|
|
111
|
+
language: str = Field(..., description="Programming language")
|
|
112
|
+
security_level: SecurityLevel = Field(
|
|
113
|
+
SecurityLevel.MEDIUM, description="Required security level"
|
|
114
|
+
)
|
|
115
|
+
context: dict[str, Any] | None = Field(None, description="Additional context for validation")
|
|
116
|
+
container_name: str | None = Field(
|
|
117
|
+
None, description="Optional container name (accepted but not used)"
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
class SecurityValidationResult(BaseModel):
|
|
122
|
+
"""Result model for security validation outcomes."""
|
|
123
|
+
|
|
124
|
+
is_safe: bool = Field(..., description="Whether code passes security validation")
|
|
125
|
+
violations: list[SecurityViolation] = Field(default_factory=list)
|
|
126
|
+
risk_score: float = Field(..., ge=0, le=100, description="Overall risk score")
|
|
127
|
+
sandbox_config: dict[str, Any] | None = Field(
|
|
128
|
+
None, description="Recommended sandbox configuration"
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
class SecurityScanRequest(BaseModel):
|
|
133
|
+
"""Request model for initiating a security scan on a container."""
|
|
134
|
+
|
|
135
|
+
container_name: str = Field(..., description="Name of the container to scan")
|
|
136
|
+
scan_type: str | None = Field("full", description="Type of security scan to perform")
|
|
137
|
+
include_dependencies: bool = Field(True, description="Whether to include dependency scanning")
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
class SecurityReportRequest(BaseModel):
|
|
141
|
+
"""Request model for generating a security report for a container."""
|
|
142
|
+
|
|
143
|
+
container_name: str = Field(..., description="Name of the container for security report")
|
|
144
|
+
format: str = Field("json", description="Output format for the report")
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
class VulnerabilityScanResult(BaseModel):
|
|
148
|
+
"""Result model for vulnerability scanning operations."""
|
|
149
|
+
|
|
150
|
+
container_name: str = Field(..., description="Name of the scanned container")
|
|
151
|
+
vulnerabilities: list[dict] = Field(
|
|
152
|
+
default_factory=list, description="List of detected vulnerabilities"
|
|
153
|
+
)
|
|
154
|
+
scan_timestamp: datetime = Field(..., description="Timestamp when the scan was completed")
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
class OSVPackageInfo(BaseModel):
|
|
158
|
+
"""Model representing package information for OSV.dev queries."""
|
|
159
|
+
|
|
160
|
+
name: str = Field(..., description="Package name")
|
|
161
|
+
ecosystem: str = Field(..., description="Package ecosystem")
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
class OSVVulnerability(BaseModel):
|
|
165
|
+
"""Model representing an OSV.dev vulnerability."""
|
|
166
|
+
|
|
167
|
+
id: str = Field(..., description="Vulnerability identifier (e.g., GHSA-xxxx)")
|
|
168
|
+
summary: str = Field(..., description="Vulnerability summary")
|
|
169
|
+
details: str | None = Field(None, description="Detailed description")
|
|
170
|
+
severity: str | None = Field(None, description="Severity level")
|
|
171
|
+
affected_versions: list[str] = Field(default_factory=list, description="Affected versions")
|
|
172
|
+
fixed_versions: list[str] | None = Field(None, description="Versions where issue is fixed")
|
|
173
|
+
cve_ids: list[str] = Field(default_factory=list, description="Associated CVE IDs")
|
|
174
|
+
references: list[str] = Field(default_factory=list, description="Reference URLs")
|
|
175
|
+
published_date: str | None = Field(None, description="Publication date")
|
|
176
|
+
package_name: str = Field(..., description="Affected package name")
|
|
177
|
+
ecosystem: str = Field(..., description="Package ecosystem")
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
class PackageInfo(BaseModel):
|
|
181
|
+
"""Model representing package information for batch queries."""
|
|
182
|
+
|
|
183
|
+
name: str = Field(..., description="Package name")
|
|
184
|
+
version: str = Field(..., description="Package version")
|
|
185
|
+
ecosystem: str = Field(..., description="Package ecosystem")
|