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.
Files changed (109) hide show
  1. coding_client/__init__.py +1 -0
  2. coding_client/api/__init__.py +19 -0
  3. coding_client/api/exception_handlers.py +158 -0
  4. coding_client/api/logging_setup.py +44 -0
  5. coding_client/api/metrics.py +40 -0
  6. coding_client/api/openapi_config.py +124 -0
  7. coding_client/api/request_logging.py +60 -0
  8. coding_client/api/validation.py +150 -0
  9. coding_client/auth/__init__.py +78 -0
  10. coding_client/auth/_default_tenant.py +132 -0
  11. coding_client/auth/_header_trust.py +98 -0
  12. coding_client/auth/_onbehalf.py +315 -0
  13. coding_client/auth/_trusted_networks.py +94 -0
  14. coding_client/auth/dependencies.py +61 -0
  15. coding_client/auth/middleware.py +445 -0
  16. coding_client/auth/models.py +83 -0
  17. coding_client/auth/outbound.py +137 -0
  18. coding_client/auth/rbac.py +21 -0
  19. coding_client/auth/rbac_coding.py +5 -0
  20. coding_client/auth/tenant.py +650 -0
  21. coding_client/auth/websocket.py +148 -0
  22. coding_client/clients/__init__.py +24 -0
  23. coding_client/clients/base.py +131 -0
  24. coding_client/clients/coding_ai.py +33 -0
  25. coding_client/clients/coding_analysis.py +36 -0
  26. coding_client/clients/coding_containers.py +45 -0
  27. coding_client/clients/coding_github.py +127 -0
  28. coding_client/clients/coding_realtime.py +127 -0
  29. coding_client/clients/coding_security.py +51 -0
  30. coding_client/clients/coding_testing.py +31 -0
  31. coding_client/clients/coding_workspaces.py +265 -0
  32. coding_client/config/__init__.py +12 -0
  33. coding_client/config/base_settings.py +61 -0
  34. coding_client/config/yaml_config_loader.py +172 -0
  35. coding_client/db/__init__.py +42 -0
  36. coding_client/db/db_types.py +122 -0
  37. coding_client/db/exceptions.py +59 -0
  38. coding_client/db/postgres_connection.py +572 -0
  39. coding_client/db/tenant_query_helper.py +417 -0
  40. coding_client/db_init.py +49 -0
  41. coding_client/exceptions/__init__.py +67 -0
  42. coding_client/exceptions/api_exceptions.py +395 -0
  43. coding_client/exceptions/pydantic_ai_exceptions.py +533 -0
  44. coding_client/interfaces/__init__.py +22 -0
  45. coding_client/interfaces/cache_interface.py +179 -0
  46. coding_client/interfaces/container_interface.py +49 -0
  47. coding_client/interfaces/docker_interface.py +283 -0
  48. coding_client/interfaces/graph_interface.py +28 -0
  49. coding_client/interfaces/security_interface.py +72 -0
  50. coding_client/interfaces/webhook_interface.py +67 -0
  51. coding_client/llm/__init__.py +54 -0
  52. coding_client/llm/base_agent.py +195 -0
  53. coding_client/llm/context.py +121 -0
  54. coding_client/llm/responses.py +102 -0
  55. coding_client/llm/routing.py +82 -0
  56. coding_client/llm/settings.py +102 -0
  57. coding_client/models/__init__.py +62 -0
  58. coding_client/models/agent.py +38 -0
  59. coding_client/models/ai_test_failure.py +745 -0
  60. coding_client/models/analysis.py +330 -0
  61. coding_client/models/architecture.py +685 -0
  62. coding_client/models/bug.py +128 -0
  63. coding_client/models/code_graph.py +317 -0
  64. coding_client/models/container.py +241 -0
  65. coding_client/models/core.py +878 -0
  66. coding_client/models/docker_container.py +104 -0
  67. coding_client/models/github.py +293 -0
  68. coding_client/models/logging.py +29 -0
  69. coding_client/models/package_manager.py +257 -0
  70. coding_client/models/pr_validation.py +440 -0
  71. coding_client/models/pydantic_ai.py +395 -0
  72. coding_client/models/repo_scanner.py +249 -0
  73. coding_client/models/responses.py +431 -0
  74. coding_client/models/security.py +185 -0
  75. coding_client/models/static_analysis.py +508 -0
  76. coding_client/models/system.py +48 -0
  77. coding_client/models/test_executor.py +204 -0
  78. coding_client/models/testing.py +673 -0
  79. coding_client/models/testing_config.py +200 -0
  80. coding_client/models/validation.py +127 -0
  81. coding_client/models_init.py +272 -0
  82. coding_client/telemetry.py +195 -0
  83. coding_client/testing.py +180 -0
  84. coding_client/types/__init__.py +130 -0
  85. coding_client/types/constraint_types.py +276 -0
  86. coding_client/types/core_types.py +112 -0
  87. coding_client/types/state_machine.py +443 -0
  88. coding_client/utils/__init__.py +86 -0
  89. coding_client/utils/archive_utils.py +387 -0
  90. coding_client/utils/ast_debug.py +45 -0
  91. coding_client/utils/async_timeout.py +364 -0
  92. coding_client/utils/constants.py +518 -0
  93. coding_client/utils/content_processing.py +326 -0
  94. coding_client/utils/database.py +916 -0
  95. coding_client/utils/encoding_helper.py +222 -0
  96. coding_client/utils/enum_helpers.py +166 -0
  97. coding_client/utils/file_operations.py +177 -0
  98. coding_client/utils/filesystem_ops.py +528 -0
  99. coding_client/utils/http_client.py +562 -0
  100. coding_client/utils/path_utils.py +471 -0
  101. coding_client/utils/profiling.py +421 -0
  102. coding_client/utils/response_builder.py +240 -0
  103. coding_client/utils/retry_helper.py +712 -0
  104. coding_client/utils/security_validation.py +423 -0
  105. coding_client-1.21.2.dist-info/METADATA +234 -0
  106. coding_client-1.21.2.dist-info/RECORD +109 -0
  107. coding_client-1.21.2.dist-info/WHEEL +5 -0
  108. coding_client-1.21.2.dist-info/licenses/LICENSE +201 -0
  109. coding_client-1.21.2.dist-info/top_level.txt +1 -0
@@ -0,0 +1,200 @@
1
+ """Testing configuration models for background tasks and quality analysis."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from datetime import datetime
6
+ from typing import Any
7
+
8
+ from pydantic import BaseModel, Field
9
+
10
+
11
+ class TestingConfiguration(BaseModel):
12
+ """Configuration for testing and quality analysis."""
13
+
14
+ # Basic settings
15
+ default_timeout: int = Field(
16
+ default=30, ge=1, le=300, description="Default test timeout in seconds"
17
+ )
18
+ max_memory_mb: int = Field(
19
+ default=512,
20
+ ge=128,
21
+ le=2048,
22
+ description="Maximum memory per container in MB",
23
+ )
24
+ max_cpu_quota: int = Field(
25
+ default=50000,
26
+ ge=10000,
27
+ le=100000,
28
+ description="Maximum CPU quota (100000 = 1 CPU)",
29
+ )
30
+
31
+ # Security settings
32
+ network_isolation: bool = Field(
33
+ default=True, description="Enable network isolation for containers"
34
+ )
35
+ readonly_filesystem: bool = Field(
36
+ default=True, description="Use read-only filesystem for containers"
37
+ )
38
+ enable_security_scanning: bool = Field(
39
+ default=True, description="Enable security scanning of code"
40
+ )
41
+
42
+ # Language-specific settings
43
+ python_version: str = Field(default="3.11", description="Python version to use")
44
+ node_version: str = Field(default="18", description="Node.js version to use")
45
+
46
+ # Quality tool settings
47
+ enabled_python_tools: list[str] = Field(
48
+ default=["ruff", "ruff-format", "ty", "bandit"],
49
+ description="Enabled Python quality tools",
50
+ )
51
+ enabled_js_tools: list[str] = Field(
52
+ default=["eslint", "prettier"],
53
+ description="Enabled JavaScript quality tools",
54
+ )
55
+ enabled_ts_tools: list[str] = Field(
56
+ default=["eslint", "prettier", "tsc"],
57
+ description="Enabled TypeScript quality tools",
58
+ )
59
+
60
+ # Analysis settings
61
+ quality_score_threshold: float = Field(
62
+ default=7.0,
63
+ ge=0.0,
64
+ le=10.0,
65
+ description="Minimum quality score threshold",
66
+ )
67
+ auto_fix_enabled: bool = Field(
68
+ default=False, description="Enable automatic resolving of issues"
69
+ )
70
+ fail_on_security_issues: bool = Field(
71
+ default=True, description="Fail analysis on security issues"
72
+ )
73
+
74
+ # Caching settings
75
+ cache_test_results: bool = Field(default=True, description="Cache test execution results")
76
+ cache_quality_results: bool = Field(default=True, description="Cache quality analysis results")
77
+ cache_ttl_seconds: int = Field(
78
+ default=3600, ge=300, le=86400, description="Cache TTL in seconds"
79
+ )
80
+
81
+ # Container settings
82
+ cleanup_containers: bool = Field(
83
+ default=True,
84
+ description="Automatically cleanup containers after execution",
85
+ )
86
+ container_registry: str = Field(default="docker.io", description="Container registry to use")
87
+ base_images: dict[str, str] = Field(
88
+ default={
89
+ "python": "code_graph_helper-api:latest",
90
+ "javascript": "node:18-slim",
91
+ "typescript": "node:18-slim",
92
+ },
93
+ description="Base container images for each language",
94
+ )
95
+
96
+
97
+ class DependencyScanConfig(BaseModel):
98
+ """Configuration for dependency scanning tasks."""
99
+
100
+ enabled: bool = Field(default=True, description="Enable dependency scanning")
101
+ scan_dev_dependencies: bool = Field(
102
+ default=False, description="Include dev dependencies in scan"
103
+ )
104
+ security_advisory_check: bool = Field(default=True, description="Check for security advisories")
105
+ outdated_package_check: bool = Field(default=True, description="Check for outdated packages")
106
+ max_scan_time_seconds: int = Field(
107
+ default=300, ge=30, le=1800, description="Maximum scan time in seconds"
108
+ )
109
+ cache_scan_results: bool = Field(default=True, description="Cache dependency scan results")
110
+ cache_ttl_hours: int = Field(default=24, ge=1, le=168, description="Cache TTL in hours")
111
+
112
+
113
+ class QualityScanConfig(BaseModel):
114
+ """Configuration for quality scanning tasks."""
115
+
116
+ enabled: bool = Field(default=True, description="Enable quality scanning")
117
+ parallel_tool_execution: bool = Field(default=True, description="Run quality tools in parallel")
118
+ max_parallel_tools: int = Field(
119
+ default=4, ge=1, le=8, description="Maximum parallel tool executions"
120
+ )
121
+ fail_fast: bool = Field(default=False, description="Stop on first tool failure")
122
+ generate_reports: bool = Field(default=True, description="Generate quality reports")
123
+ include_suggestions: bool = Field(default=True, description="Include improvement suggestions")
124
+ max_scan_time_seconds: int = Field(
125
+ default=600, ge=60, le=3600, description="Maximum scan time in seconds"
126
+ )
127
+ cache_quality_results: bool = Field(default=True, description="Cache quality scan results")
128
+ cache_ttl_hours: int = Field(default=6, ge=1, le=72, description="Cache TTL in hours")
129
+
130
+
131
+ class BackgroundTaskConfig(BaseModel):
132
+ """Configuration for background task execution."""
133
+
134
+ max_concurrent_tasks: int = Field(
135
+ default=5, ge=1, le=20, description="Maximum concurrent background tasks"
136
+ )
137
+ task_timeout_seconds: int = Field(
138
+ default=1800, ge=300, le=7200, description="Task timeout in seconds"
139
+ )
140
+ retry_failed_tasks: bool = Field(default=True, description="Retry failed tasks")
141
+ max_retries: int = Field(default=3, ge=0, le=10, description="Maximum task retry attempts")
142
+ retry_delay_seconds: int = Field(
143
+ default=60, ge=10, le=300, description="Delay between retries in seconds"
144
+ )
145
+ cleanup_completed_tasks: bool = Field(default=True, description="Cleanup completed task data")
146
+ cleanup_delay_hours: int = Field(
147
+ default=24, ge=1, le=168, description="Delay before cleanup in hours"
148
+ )
149
+
150
+
151
+ class TaskExecutionResult(BaseModel):
152
+ """Result of a background task execution."""
153
+
154
+ task_id: str = Field(description="Unique task identifier")
155
+ task_type: str = Field(description="Type of task executed")
156
+ success: bool = Field(description="Whether task completed successfully")
157
+ start_time: datetime = Field(description="Task start timestamp")
158
+ end_time: datetime | None = Field(None, description="Task completion timestamp")
159
+ execution_time_seconds: float | None = Field(None, description="Task execution duration")
160
+ result_data: dict[str, Any] | None = Field(None, description="Task result data")
161
+ error_message: str | None = Field(None, description="Error message if failed")
162
+ retry_count: int = Field(default=0, description="Number of retry attempts")
163
+ metadata: dict[str, Any] | None = Field(None, description="Additional task metadata")
164
+
165
+
166
+ class TestingTaskQueueConfig(BaseModel):
167
+ """Configuration for task queue management."""
168
+
169
+ queue_name: str = Field(description="Name of the task queue")
170
+ max_queue_size: int = Field(default=1000, ge=10, le=10000, description="Maximum queue size")
171
+ worker_count: int = Field(default=3, ge=1, le=10, description="Number of worker processes")
172
+ batch_size: int = Field(default=5, ge=1, le=50, description="Tasks processed per batch")
173
+ poll_interval_seconds: int = Field(
174
+ default=10, ge=1, le=60, description="Queue polling interval"
175
+ )
176
+ priority_enabled: bool = Field(default=True, description="Enable task priority handling")
177
+ dead_letter_queue: bool = Field(
178
+ default=True, description="Enable dead letter queue for failed tasks"
179
+ )
180
+
181
+
182
+ # Factory function for creating default configurations
183
+ def get_default_testing_config() -> TestingConfiguration:
184
+ """Get default testing configuration."""
185
+ return TestingConfiguration()
186
+
187
+
188
+ def get_default_dependency_scan_config() -> DependencyScanConfig:
189
+ """Get default dependency scan configuration."""
190
+ return DependencyScanConfig()
191
+
192
+
193
+ def get_default_quality_scan_config() -> QualityScanConfig:
194
+ """Get default quality scan configuration."""
195
+ return QualityScanConfig()
196
+
197
+
198
+ def get_default_background_task_config() -> BackgroundTaskConfig:
199
+ """Get default background task configuration."""
200
+ return BackgroundTaskConfig()
@@ -0,0 +1,127 @@
1
+ """Validation models for multi-language code validation endpoints.
2
+
3
+ This module provides language-specific validation models that ensure consistent
4
+ request/response structures across different programming languages. The models
5
+ are designed with Pydantic v2/v3 compatibility and support specialized validation
6
+ options for each supported language.
7
+
8
+ The validation system handles:
9
+ - Language-specific validation requirements (class names, project types, etc.)
10
+ - Consistent error reporting across all languages
11
+ - Type-safe request/response validation
12
+ - Proper field aliasing for API compatibility
13
+
14
+ Supported Languages:
15
+ - Python: General-purpose validation with filename support
16
+ - JavaScript/TypeScript: ES6+ and TypeScript validation
17
+ - Java: Class-based validation with className parameter
18
+ - Rust: Crate-based validation with crate type specification
19
+ - C#: Project-based validation with framework targeting
20
+ - Go: Package-based validation with Go module support
21
+
22
+ Example:
23
+ ```python
24
+ from validation_models import JavaValidationRequest, ValidationResponse
25
+
26
+ # Create Java validation request
27
+ request = JavaValidationRequest(
28
+ code='public class Hello { public static void main(String[] args) { System.out.println("Hello"); } }',
29
+ className="Hello"
30
+ )
31
+
32
+ # Process validation response
33
+ response = ValidationResponse(
34
+ validationId="val-123",
35
+ valid=True,
36
+ errors=[],
37
+ output="Compilation successful"
38
+ )
39
+ ```
40
+ """
41
+
42
+ from __future__ import annotations
43
+
44
+ from typing import Literal
45
+
46
+ from pydantic import BaseModel, ConfigDict, Field, field_validator
47
+
48
+
49
+ class ValidationRequest(BaseModel):
50
+ """Base validation request model."""
51
+
52
+ model_config = ConfigDict(
53
+ extra="forbid", # Reject extra fields
54
+ str_strip_whitespace=True, # Strip whitespace from strings
55
+ )
56
+
57
+ code: str = Field(..., description="Code to validate")
58
+
59
+ @field_validator("code")
60
+ @classmethod
61
+ def validate_code_not_none(cls, v: str) -> str:
62
+ """Ensure code is provided and not None."""
63
+ if v is None:
64
+ raise ValueError("Code field is required")
65
+ return v
66
+
67
+
68
+ class JavaScriptValidationRequest(ValidationRequest):
69
+ """JavaScript/TypeScript validation request."""
70
+
71
+ filename: str | None = Field(default="test.js", description="Filename for validation")
72
+
73
+
74
+ class PythonValidationRequest(ValidationRequest):
75
+ """Python validation request."""
76
+
77
+ filename: str | None = Field(default="test.py", description="Filename for validation")
78
+
79
+
80
+ class JavaValidationRequest(ValidationRequest):
81
+ """Java validation request."""
82
+
83
+ className: str | None = Field(default="Test", description="Java class name")
84
+
85
+
86
+ class RustValidationRequest(ValidationRequest):
87
+ """Rust validation request."""
88
+
89
+ crateType: Literal["bin", "lib"] | None = Field(default="bin", description="Crate type")
90
+
91
+
92
+ class CSharpValidationRequest(ValidationRequest):
93
+ """C# validation request."""
94
+
95
+ projectType: Literal["console", "library"] | None = Field(
96
+ default="console", description="Project type"
97
+ )
98
+ targetFramework: str | None = Field(default="net8.0", description="Target framework")
99
+
100
+
101
+ class GoValidationRequest(ValidationRequest):
102
+ """Go validation request."""
103
+
104
+ filename: str | None = Field(default="main.go", description="Filename for validation")
105
+
106
+
107
+ class ValidationResponse(BaseModel):
108
+ """Validation response model."""
109
+
110
+ model_config = ConfigDict(extra="forbid")
111
+
112
+ validationId: str = Field(..., description="Unique validation ID")
113
+ valid: bool = Field(..., description="Whether the code is valid")
114
+ errors: list[str] = Field(default_factory=list, description="List of validation errors")
115
+ output: str = Field(default="", description="Validation output")
116
+ warnings: list[str] | None = Field(default=None, description="List of warnings")
117
+
118
+
119
+ class CodeValidationErrorResponse(BaseModel):
120
+ """Validation error response model."""
121
+
122
+ model_config = ConfigDict(extra="forbid")
123
+
124
+ validationId: str | None = Field(default=None, description="Validation ID if available")
125
+ valid: bool = Field(default=False, description="Always false for errors")
126
+ error: str = Field(..., description="Error message")
127
+ details: str | None = Field(default=None, description="Additional error details")
@@ -0,0 +1,272 @@
1
+ """
2
+ SQLAlchemy ORM models for code graph database.
3
+
4
+ Models include:
5
+ - Node: Code entities (functions, classes, modules) with multi-language support
6
+ - Edge: Relationships between entities (calls, imports, inheritance)
7
+ - Codebase: Repository/project tracking
8
+ - SchemaVersion: Migration tracking
9
+ - NodeAudit: Change audit logging
10
+ - Architecture analysis tables (components, metrics, patterns, packages)
11
+ - Quality analysis tables (results, sessions)
12
+ """
13
+
14
+ from sqlalchemy import (
15
+ Column,
16
+ DateTime,
17
+ Float,
18
+ ForeignKey,
19
+ Index,
20
+ Integer,
21
+ String,
22
+ Text,
23
+ UniqueConstraint,
24
+ func,
25
+ )
26
+ from sqlalchemy.dialects.postgresql import JSONB, TSVECTOR
27
+
28
+ from .db_init import Base
29
+
30
+
31
+ class Node(Base):
32
+ """Code entity node in the graph."""
33
+
34
+ __tablename__ = "nodes"
35
+
36
+ id = Column(String(500), primary_key=True)
37
+ type = Column(String(50), nullable=False, index=True)
38
+ properties = Column(JSONB, nullable=True, default=dict)
39
+ created_at = Column(DateTime(timezone=True), server_default=func.now())
40
+ updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
41
+ content_hash = Column(String(64), nullable=True, index=True)
42
+ file_size = Column(Integer, nullable=True)
43
+ tenant_id = Column(String(100), nullable=True, index=True)
44
+ tsv = Column(TSVECTOR, nullable=True)
45
+
46
+ __table_args__ = (
47
+ Index("ix_nodes_type_created", "type", "created_at"),
48
+ Index("ix_nodes_tenant_type", "tenant_id", "type"),
49
+ Index("ix_nodes_tsv", "tsv", postgresql_using="gin"),
50
+ Index("ix_nodes_properties", "properties", postgresql_using="gin"),
51
+ )
52
+
53
+
54
+ class Edge(Base):
55
+ """Relationship edge between code entities."""
56
+
57
+ __tablename__ = "edges"
58
+
59
+ id = Column(Integer, primary_key=True, autoincrement=True)
60
+ source = Column(String(500), ForeignKey("nodes.id", ondelete="CASCADE"), nullable=False)
61
+ target = Column(String(500), ForeignKey("nodes.id", ondelete="CASCADE"), nullable=False)
62
+ relationship = Column(String(50), nullable=False)
63
+ properties = Column(JSONB, nullable=True, default=dict)
64
+ weight = Column(Float, nullable=False, default=1.0)
65
+ created_at = Column(DateTime(timezone=True), server_default=func.now())
66
+ tenant_id = Column(String(100), nullable=True)
67
+
68
+ __table_args__ = (
69
+ UniqueConstraint("source", "target", "relationship", name="uq_edges_source_target_rel"),
70
+ Index("ix_edges_source", "source"),
71
+ Index("ix_edges_target", "target"),
72
+ Index("ix_edges_relationship", "relationship"),
73
+ Index("ix_edges_source_rel", "source", "relationship"),
74
+ Index("ix_edges_target_rel", "target", "relationship"),
75
+ Index("ix_edges_weight", "relationship", "weight"),
76
+ Index("ix_edges_tenant", "tenant_id"),
77
+ Index("ix_edges_tenant_source", "tenant_id", "source"),
78
+ )
79
+
80
+
81
+ class Codebase(Base):
82
+ """Repository/project being analyzed."""
83
+
84
+ __tablename__ = "codebases"
85
+
86
+ id = Column(String(100), primary_key=True)
87
+ name = Column(String(200), nullable=False)
88
+ description = Column(Text, nullable=True)
89
+ tenant_id = Column(String(100), nullable=True, index=True)
90
+ created_at = Column(DateTime(timezone=True), server_default=func.now())
91
+ updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
92
+
93
+
94
+ class SchemaVersion(Base):
95
+ """Tracks schema migration versions."""
96
+
97
+ __tablename__ = "schema_version"
98
+
99
+ version = Column(Integer, primary_key=True)
100
+ description = Column(Text, nullable=True)
101
+ applied_at = Column(DateTime(timezone=True), server_default=func.now())
102
+
103
+
104
+ class NodeAudit(Base):
105
+ """Audit log for node operations."""
106
+
107
+ __tablename__ = "nodes_audit"
108
+
109
+ id = Column(Integer, primary_key=True, autoincrement=True)
110
+ node_id = Column(String(500), nullable=True)
111
+ operation = Column(String(20), nullable=False)
112
+ timestamp = Column(DateTime(timezone=True), server_default=func.now())
113
+ tenant_id = Column(String(100), nullable=True)
114
+
115
+ __table_args__ = (
116
+ Index("ix_nodes_audit_node_id", "node_id"),
117
+ Index("ix_nodes_audit_tenant", "tenant_id"),
118
+ )
119
+
120
+
121
+ # Architecture Analysis Tables
122
+
123
+
124
+ class ArchitectureComponent(Base):
125
+ """Architecture component for dependency analysis."""
126
+
127
+ __tablename__ = "architecture_components"
128
+
129
+ id = Column(String(100), primary_key=True)
130
+ codebase_id = Column(
131
+ String(100), ForeignKey("codebases.id", ondelete="CASCADE"), nullable=False
132
+ )
133
+ name = Column(String(200), nullable=False)
134
+ files = Column(JSONB, nullable=False, default=list)
135
+ dependencies = Column(JSONB, nullable=False, default=list)
136
+ layer = Column(String(50), nullable=True)
137
+ tenant_id = Column(String(100), nullable=True)
138
+ created_at = Column(DateTime(timezone=True), server_default=func.now())
139
+ updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
140
+
141
+ __table_args__ = (
142
+ Index("ix_arch_components_codebase", "codebase_id"),
143
+ Index("ix_arch_components_layer", "layer"),
144
+ Index("ix_arch_components_tenant", "tenant_id"),
145
+ )
146
+
147
+
148
+ class ArchitectureMetric(Base):
149
+ """Architecture quality metrics (instability, abstractness, distance)."""
150
+
151
+ __tablename__ = "architecture_metrics"
152
+
153
+ codebase_id = Column(
154
+ String(100), ForeignKey("codebases.id", ondelete="CASCADE"), primary_key=True
155
+ )
156
+ instability = Column(Float, nullable=False)
157
+ abstractness = Column(Float, nullable=False)
158
+ distance = Column(Float, nullable=False)
159
+ tenant_id = Column(String(100), nullable=True, index=True)
160
+ created_at = Column(DateTime(timezone=True), server_default=func.now())
161
+ updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
162
+
163
+
164
+ class DetectedPattern(Base):
165
+ """Detected design patterns in codebase."""
166
+
167
+ __tablename__ = "detected_patterns"
168
+
169
+ id = Column(Integer, primary_key=True, autoincrement=True)
170
+ codebase_id = Column(
171
+ String(100), ForeignKey("codebases.id", ondelete="CASCADE"), nullable=False
172
+ )
173
+ name = Column(String(100), nullable=False)
174
+ location = Column(String(500), nullable=False)
175
+ confidence = Column(Float, nullable=False)
176
+ tenant_id = Column(String(100), nullable=True)
177
+ created_at = Column(DateTime(timezone=True), server_default=func.now())
178
+
179
+ __table_args__ = (
180
+ Index("ix_detected_patterns_codebase", "codebase_id"),
181
+ Index("ix_detected_patterns_name", "name"),
182
+ Index("ix_detected_patterns_tenant", "tenant_id"),
183
+ )
184
+
185
+
186
+ class ExternalPackage(Base):
187
+ """External package dependencies with vulnerability tracking."""
188
+
189
+ __tablename__ = "external_packages"
190
+
191
+ id = Column(Integer, primary_key=True, autoincrement=True)
192
+ codebase_id = Column(
193
+ String(100), ForeignKey("codebases.id", ondelete="CASCADE"), nullable=False
194
+ )
195
+ name = Column(String(200), nullable=False)
196
+ current_version = Column(String(50), nullable=False)
197
+ latest_version = Column(String(50), nullable=True)
198
+ license = Column(String(100), nullable=True)
199
+ severity = Column(String(20), nullable=True)
200
+ tenant_id = Column(String(100), nullable=True)
201
+ created_at = Column(DateTime(timezone=True), server_default=func.now())
202
+ updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
203
+
204
+ __table_args__ = (
205
+ UniqueConstraint("codebase_id", "name", name="uq_external_packages_codebase_name"),
206
+ Index("ix_external_packages_codebase", "codebase_id"),
207
+ Index("ix_external_packages_severity", "severity"),
208
+ )
209
+
210
+
211
+ class LayerAssignment(Base):
212
+ """Layer assignments for architecture analysis."""
213
+
214
+ __tablename__ = "layer_assignments"
215
+
216
+ id = Column(Integer, primary_key=True, autoincrement=True)
217
+ codebase_id = Column(
218
+ String(100), ForeignKey("codebases.id", ondelete="CASCADE"), nullable=False
219
+ )
220
+ layer_name = Column(String(50), nullable=False)
221
+ component_ids = Column(JSONB, nullable=False, default=list)
222
+ tenant_id = Column(String(100), nullable=True)
223
+ created_at = Column(DateTime(timezone=True), server_default=func.now())
224
+ updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
225
+
226
+ __table_args__ = (
227
+ UniqueConstraint("codebase_id", "layer_name", name="uq_layer_assignments_codebase_layer"),
228
+ Index("ix_layer_assignments_codebase", "codebase_id"),
229
+ )
230
+
231
+
232
+ class QualityResult(Base):
233
+ """Quality analysis results."""
234
+
235
+ __tablename__ = "quality_results"
236
+
237
+ id = Column(Integer, primary_key=True, autoincrement=True)
238
+ codebase_id = Column(
239
+ String(100), ForeignKey("codebases.id", ondelete="CASCADE"), nullable=False
240
+ )
241
+ overall_score = Column(Float, nullable=False)
242
+ issues_count = Column(Integer, nullable=False)
243
+ issues_data = Column(JSONB, nullable=True)
244
+ summary_data = Column(JSONB, nullable=True)
245
+ tenant_id = Column(String(100), nullable=True)
246
+ created_at = Column(DateTime(timezone=True), server_default=func.now())
247
+
248
+ __table_args__ = (Index("ix_quality_results_codebase", "codebase_id"),)
249
+
250
+
251
+ class AnalysisSession(Base):
252
+ """Analysis session tracking."""
253
+
254
+ __tablename__ = "analysis_sessions"
255
+
256
+ id = Column(String(100), primary_key=True)
257
+ codebase_id = Column(
258
+ String(100), ForeignKey("codebases.id", ondelete="CASCADE"), nullable=False
259
+ )
260
+ analysis_type = Column(String(50), nullable=False)
261
+ status = Column(String(20), nullable=False, default="running")
262
+ started_at = Column(DateTime(timezone=True), server_default=func.now())
263
+ completed_at = Column(DateTime(timezone=True), nullable=True)
264
+ error_message = Column(Text, nullable=True)
265
+ result_data = Column(JSONB, nullable=True)
266
+ tenant_id = Column(String(100), nullable=True)
267
+
268
+ __table_args__ = (
269
+ Index("ix_analysis_sessions_codebase", "codebase_id"),
270
+ Index("ix_analysis_sessions_type", "analysis_type"),
271
+ Index("ix_analysis_sessions_status", "status"),
272
+ )