truthound-dashboard 1.3.0__py3-none-any.whl → 1.4.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- truthound_dashboard/api/alerts.py +258 -0
- truthound_dashboard/api/anomaly.py +1302 -0
- truthound_dashboard/api/cross_alerts.py +352 -0
- truthound_dashboard/api/deps.py +143 -0
- truthound_dashboard/api/drift_monitor.py +540 -0
- truthound_dashboard/api/lineage.py +1151 -0
- truthound_dashboard/api/maintenance.py +363 -0
- truthound_dashboard/api/middleware.py +373 -1
- truthound_dashboard/api/model_monitoring.py +805 -0
- truthound_dashboard/api/notifications_advanced.py +2452 -0
- truthound_dashboard/api/plugins.py +2096 -0
- truthound_dashboard/api/profile.py +211 -14
- truthound_dashboard/api/reports.py +853 -0
- truthound_dashboard/api/router.py +147 -0
- truthound_dashboard/api/rule_suggestions.py +310 -0
- truthound_dashboard/api/schema_evolution.py +231 -0
- truthound_dashboard/api/sources.py +47 -3
- truthound_dashboard/api/triggers.py +190 -0
- truthound_dashboard/api/validations.py +13 -0
- truthound_dashboard/api/validators.py +333 -4
- truthound_dashboard/api/versioning.py +309 -0
- truthound_dashboard/api/websocket.py +301 -0
- truthound_dashboard/core/__init__.py +27 -0
- truthound_dashboard/core/anomaly.py +1395 -0
- truthound_dashboard/core/anomaly_explainer.py +633 -0
- truthound_dashboard/core/cache.py +206 -0
- truthound_dashboard/core/cached_services.py +422 -0
- truthound_dashboard/core/charts.py +352 -0
- truthound_dashboard/core/connections.py +1069 -42
- truthound_dashboard/core/cross_alerts.py +837 -0
- truthound_dashboard/core/drift_monitor.py +1477 -0
- truthound_dashboard/core/drift_sampling.py +669 -0
- truthound_dashboard/core/i18n/__init__.py +42 -0
- truthound_dashboard/core/i18n/detector.py +173 -0
- truthound_dashboard/core/i18n/messages.py +564 -0
- truthound_dashboard/core/lineage.py +971 -0
- truthound_dashboard/core/maintenance.py +443 -5
- truthound_dashboard/core/model_monitoring.py +1043 -0
- truthound_dashboard/core/notifications/channels.py +1020 -1
- truthound_dashboard/core/notifications/deduplication/__init__.py +143 -0
- truthound_dashboard/core/notifications/deduplication/policies.py +274 -0
- truthound_dashboard/core/notifications/deduplication/service.py +400 -0
- truthound_dashboard/core/notifications/deduplication/stores.py +2365 -0
- truthound_dashboard/core/notifications/deduplication/strategies.py +422 -0
- truthound_dashboard/core/notifications/dispatcher.py +43 -0
- truthound_dashboard/core/notifications/escalation/__init__.py +149 -0
- truthound_dashboard/core/notifications/escalation/backends.py +1384 -0
- truthound_dashboard/core/notifications/escalation/engine.py +429 -0
- truthound_dashboard/core/notifications/escalation/models.py +336 -0
- truthound_dashboard/core/notifications/escalation/scheduler.py +1187 -0
- truthound_dashboard/core/notifications/escalation/state_machine.py +330 -0
- truthound_dashboard/core/notifications/escalation/stores.py +2896 -0
- truthound_dashboard/core/notifications/events.py +49 -0
- truthound_dashboard/core/notifications/metrics/__init__.py +115 -0
- truthound_dashboard/core/notifications/metrics/base.py +528 -0
- truthound_dashboard/core/notifications/metrics/collectors.py +583 -0
- truthound_dashboard/core/notifications/routing/__init__.py +169 -0
- truthound_dashboard/core/notifications/routing/combinators.py +184 -0
- truthound_dashboard/core/notifications/routing/config.py +375 -0
- truthound_dashboard/core/notifications/routing/config_parser.py +867 -0
- truthound_dashboard/core/notifications/routing/engine.py +382 -0
- truthound_dashboard/core/notifications/routing/expression_engine.py +1269 -0
- truthound_dashboard/core/notifications/routing/jinja2_engine.py +774 -0
- truthound_dashboard/core/notifications/routing/rules.py +625 -0
- truthound_dashboard/core/notifications/routing/validator.py +678 -0
- truthound_dashboard/core/notifications/service.py +2 -0
- truthound_dashboard/core/notifications/stats_aggregator.py +850 -0
- truthound_dashboard/core/notifications/throttling/__init__.py +83 -0
- truthound_dashboard/core/notifications/throttling/builder.py +311 -0
- truthound_dashboard/core/notifications/throttling/stores.py +1859 -0
- truthound_dashboard/core/notifications/throttling/throttlers.py +633 -0
- truthound_dashboard/core/openlineage.py +1028 -0
- truthound_dashboard/core/plugins/__init__.py +39 -0
- truthound_dashboard/core/plugins/docs/__init__.py +39 -0
- truthound_dashboard/core/plugins/docs/extractor.py +703 -0
- truthound_dashboard/core/plugins/docs/renderers.py +804 -0
- truthound_dashboard/core/plugins/hooks/__init__.py +63 -0
- truthound_dashboard/core/plugins/hooks/decorators.py +367 -0
- truthound_dashboard/core/plugins/hooks/manager.py +403 -0
- truthound_dashboard/core/plugins/hooks/protocols.py +265 -0
- truthound_dashboard/core/plugins/lifecycle/__init__.py +41 -0
- truthound_dashboard/core/plugins/lifecycle/hot_reload.py +584 -0
- truthound_dashboard/core/plugins/lifecycle/machine.py +419 -0
- truthound_dashboard/core/plugins/lifecycle/states.py +266 -0
- truthound_dashboard/core/plugins/loader.py +504 -0
- truthound_dashboard/core/plugins/registry.py +810 -0
- truthound_dashboard/core/plugins/reporter_executor.py +588 -0
- truthound_dashboard/core/plugins/sandbox/__init__.py +59 -0
- truthound_dashboard/core/plugins/sandbox/code_validator.py +243 -0
- truthound_dashboard/core/plugins/sandbox/engines.py +770 -0
- truthound_dashboard/core/plugins/sandbox/protocols.py +194 -0
- truthound_dashboard/core/plugins/sandbox.py +617 -0
- truthound_dashboard/core/plugins/security/__init__.py +68 -0
- truthound_dashboard/core/plugins/security/analyzer.py +535 -0
- truthound_dashboard/core/plugins/security/policies.py +311 -0
- truthound_dashboard/core/plugins/security/protocols.py +296 -0
- truthound_dashboard/core/plugins/security/signing.py +842 -0
- truthound_dashboard/core/plugins/security.py +446 -0
- truthound_dashboard/core/plugins/validator_executor.py +401 -0
- truthound_dashboard/core/plugins/versioning/__init__.py +51 -0
- truthound_dashboard/core/plugins/versioning/constraints.py +377 -0
- truthound_dashboard/core/plugins/versioning/dependencies.py +541 -0
- truthound_dashboard/core/plugins/versioning/semver.py +266 -0
- truthound_dashboard/core/profile_comparison.py +601 -0
- truthound_dashboard/core/report_history.py +570 -0
- truthound_dashboard/core/reporters/__init__.py +57 -0
- truthound_dashboard/core/reporters/base.py +296 -0
- truthound_dashboard/core/reporters/csv_reporter.py +155 -0
- truthound_dashboard/core/reporters/html_reporter.py +598 -0
- truthound_dashboard/core/reporters/i18n/__init__.py +65 -0
- truthound_dashboard/core/reporters/i18n/base.py +494 -0
- truthound_dashboard/core/reporters/i18n/catalogs.py +930 -0
- truthound_dashboard/core/reporters/json_reporter.py +160 -0
- truthound_dashboard/core/reporters/junit_reporter.py +233 -0
- truthound_dashboard/core/reporters/markdown_reporter.py +207 -0
- truthound_dashboard/core/reporters/pdf_reporter.py +209 -0
- truthound_dashboard/core/reporters/registry.py +272 -0
- truthound_dashboard/core/rule_generator.py +2088 -0
- truthound_dashboard/core/scheduler.py +822 -12
- truthound_dashboard/core/schema_evolution.py +858 -0
- truthound_dashboard/core/services.py +152 -9
- truthound_dashboard/core/statistics.py +718 -0
- truthound_dashboard/core/streaming_anomaly.py +883 -0
- truthound_dashboard/core/triggers/__init__.py +45 -0
- truthound_dashboard/core/triggers/base.py +226 -0
- truthound_dashboard/core/triggers/evaluators.py +609 -0
- truthound_dashboard/core/triggers/factory.py +363 -0
- truthound_dashboard/core/unified_alerts.py +870 -0
- truthound_dashboard/core/validation_limits.py +509 -0
- truthound_dashboard/core/versioning.py +709 -0
- truthound_dashboard/core/websocket/__init__.py +59 -0
- truthound_dashboard/core/websocket/manager.py +512 -0
- truthound_dashboard/core/websocket/messages.py +130 -0
- truthound_dashboard/db/__init__.py +30 -0
- truthound_dashboard/db/models.py +3375 -3
- truthound_dashboard/main.py +22 -0
- truthound_dashboard/schemas/__init__.py +396 -1
- truthound_dashboard/schemas/anomaly.py +1258 -0
- truthound_dashboard/schemas/base.py +4 -0
- truthound_dashboard/schemas/cross_alerts.py +334 -0
- truthound_dashboard/schemas/drift_monitor.py +890 -0
- truthound_dashboard/schemas/lineage.py +428 -0
- truthound_dashboard/schemas/maintenance.py +154 -0
- truthound_dashboard/schemas/model_monitoring.py +374 -0
- truthound_dashboard/schemas/notifications_advanced.py +1363 -0
- truthound_dashboard/schemas/openlineage.py +704 -0
- truthound_dashboard/schemas/plugins.py +1293 -0
- truthound_dashboard/schemas/profile.py +420 -34
- truthound_dashboard/schemas/profile_comparison.py +242 -0
- truthound_dashboard/schemas/reports.py +285 -0
- truthound_dashboard/schemas/rule_suggestion.py +434 -0
- truthound_dashboard/schemas/schema_evolution.py +164 -0
- truthound_dashboard/schemas/source.py +117 -2
- truthound_dashboard/schemas/triggers.py +511 -0
- truthound_dashboard/schemas/unified_alerts.py +223 -0
- truthound_dashboard/schemas/validation.py +25 -1
- truthound_dashboard/schemas/validators/__init__.py +11 -0
- truthound_dashboard/schemas/validators/base.py +151 -0
- truthound_dashboard/schemas/versioning.py +152 -0
- truthound_dashboard/static/index.html +2 -2
- {truthound_dashboard-1.3.0.dist-info → truthound_dashboard-1.4.0.dist-info}/METADATA +142 -18
- truthound_dashboard-1.4.0.dist-info/RECORD +239 -0
- truthound_dashboard/static/assets/index-BCA8H1hO.js +0 -574
- truthound_dashboard/static/assets/index-BNsSQ2fN.css +0 -1
- truthound_dashboard/static/assets/unmerged_dictionaries-CsJWCRx9.js +0 -1
- truthound_dashboard-1.3.0.dist-info/RECORD +0 -110
- {truthound_dashboard-1.3.0.dist-info → truthound_dashboard-1.4.0.dist-info}/WHEEL +0 -0
- {truthound_dashboard-1.3.0.dist-info → truthound_dashboard-1.4.0.dist-info}/entry_points.txt +0 -0
- {truthound_dashboard-1.3.0.dist-info → truthound_dashboard-1.4.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,1293 @@
|
|
|
1
|
+
"""Pydantic schemas for Plugin System.
|
|
2
|
+
|
|
3
|
+
This module defines schemas for plugin management including:
|
|
4
|
+
- Plugin metadata and versioning
|
|
5
|
+
- Custom validators
|
|
6
|
+
- Custom reporters
|
|
7
|
+
- Plugin marketplace
|
|
8
|
+
- Security and sandboxing
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from datetime import datetime
|
|
12
|
+
from enum import Enum
|
|
13
|
+
from typing import Any, Literal
|
|
14
|
+
|
|
15
|
+
from pydantic import Field, field_validator
|
|
16
|
+
|
|
17
|
+
from .base import BaseSchema, IDMixin, ListResponseWrapper, TimestampMixin
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
# =============================================================================
|
|
21
|
+
# Enums
|
|
22
|
+
# =============================================================================
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class PluginType(str, Enum):
|
|
26
|
+
"""Type of plugin."""
|
|
27
|
+
|
|
28
|
+
VALIDATOR = "validator"
|
|
29
|
+
REPORTER = "reporter"
|
|
30
|
+
CONNECTOR = "connector"
|
|
31
|
+
TRANSFORMER = "transformer"
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class PluginStatus(str, Enum):
|
|
35
|
+
"""Installation status of a plugin."""
|
|
36
|
+
|
|
37
|
+
AVAILABLE = "available"
|
|
38
|
+
INSTALLED = "installed"
|
|
39
|
+
ENABLED = "enabled"
|
|
40
|
+
DISABLED = "disabled"
|
|
41
|
+
UPDATE_AVAILABLE = "update_available"
|
|
42
|
+
ERROR = "error"
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class PluginSource(str, Enum):
|
|
46
|
+
"""Source of the plugin."""
|
|
47
|
+
|
|
48
|
+
OFFICIAL = "official"
|
|
49
|
+
COMMUNITY = "community"
|
|
50
|
+
LOCAL = "local"
|
|
51
|
+
PRIVATE = "private"
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class SecurityLevel(str, Enum):
|
|
55
|
+
"""Security level of the plugin."""
|
|
56
|
+
|
|
57
|
+
TRUSTED = "trusted"
|
|
58
|
+
VERIFIED = "verified"
|
|
59
|
+
UNVERIFIED = "unverified"
|
|
60
|
+
SANDBOXED = "sandboxed"
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class ValidatorParamType(str, Enum):
|
|
64
|
+
"""Parameter types for custom validators."""
|
|
65
|
+
|
|
66
|
+
STRING = "string"
|
|
67
|
+
INTEGER = "integer"
|
|
68
|
+
FLOAT = "float"
|
|
69
|
+
BOOLEAN = "boolean"
|
|
70
|
+
COLUMN = "column"
|
|
71
|
+
COLUMN_LIST = "column_list"
|
|
72
|
+
SELECT = "select"
|
|
73
|
+
MULTI_SELECT = "multi_select"
|
|
74
|
+
REGEX = "regex"
|
|
75
|
+
JSON = "json"
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
class ReporterOutputFormat(str, Enum):
|
|
79
|
+
"""Output format for custom reporters."""
|
|
80
|
+
|
|
81
|
+
PDF = "pdf"
|
|
82
|
+
HTML = "html"
|
|
83
|
+
JSON = "json"
|
|
84
|
+
CSV = "csv"
|
|
85
|
+
EXCEL = "excel"
|
|
86
|
+
MARKDOWN = "markdown"
|
|
87
|
+
CUSTOM = "custom"
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
# =============================================================================
|
|
91
|
+
# Plugin Version Management
|
|
92
|
+
# =============================================================================
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
class SemverVersion(BaseSchema):
|
|
96
|
+
"""Semantic version representation."""
|
|
97
|
+
|
|
98
|
+
major: int = Field(ge=0, description="Major version (breaking changes)")
|
|
99
|
+
minor: int = Field(ge=0, description="Minor version (new features)")
|
|
100
|
+
patch: int = Field(ge=0, description="Patch version (bug fixes)")
|
|
101
|
+
prerelease: str | None = Field(
|
|
102
|
+
default=None, description="Pre-release identifier (e.g., 'beta.1')"
|
|
103
|
+
)
|
|
104
|
+
build: str | None = Field(default=None, description="Build metadata")
|
|
105
|
+
|
|
106
|
+
def __str__(self) -> str:
|
|
107
|
+
version = f"{self.major}.{self.minor}.{self.patch}"
|
|
108
|
+
if self.prerelease:
|
|
109
|
+
version += f"-{self.prerelease}"
|
|
110
|
+
if self.build:
|
|
111
|
+
version += f"+{self.build}"
|
|
112
|
+
return version
|
|
113
|
+
|
|
114
|
+
@classmethod
|
|
115
|
+
def parse(cls, version_str: str) -> "SemverVersion":
|
|
116
|
+
"""Parse a version string into SemverVersion."""
|
|
117
|
+
import re
|
|
118
|
+
|
|
119
|
+
pattern = r"^(\d+)\.(\d+)\.(\d+)(?:-([a-zA-Z0-9.]+))?(?:\+([a-zA-Z0-9.]+))?$"
|
|
120
|
+
match = re.match(pattern, version_str)
|
|
121
|
+
if not match:
|
|
122
|
+
raise ValueError(f"Invalid version string: {version_str}")
|
|
123
|
+
return cls(
|
|
124
|
+
major=int(match.group(1)),
|
|
125
|
+
minor=int(match.group(2)),
|
|
126
|
+
patch=int(match.group(3)),
|
|
127
|
+
prerelease=match.group(4),
|
|
128
|
+
build=match.group(5),
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
class PluginDependency(BaseSchema):
|
|
133
|
+
"""Plugin dependency specification."""
|
|
134
|
+
|
|
135
|
+
plugin_id: str = Field(description="ID of the dependent plugin")
|
|
136
|
+
version_constraint: str = Field(
|
|
137
|
+
description="Version constraint (e.g., '>=1.0.0', '^2.0.0')"
|
|
138
|
+
)
|
|
139
|
+
optional: bool = Field(default=False, description="Whether dependency is optional")
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
# =============================================================================
|
|
143
|
+
# Plugin Security
|
|
144
|
+
# =============================================================================
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
class PluginPermission(str, Enum):
|
|
148
|
+
"""Permissions that a plugin can request."""
|
|
149
|
+
|
|
150
|
+
READ_DATA = "read_data"
|
|
151
|
+
WRITE_DATA = "write_data"
|
|
152
|
+
NETWORK_ACCESS = "network_access"
|
|
153
|
+
FILE_SYSTEM = "file_system"
|
|
154
|
+
EXECUTE_CODE = "execute_code"
|
|
155
|
+
SEND_NOTIFICATIONS = "send_notifications"
|
|
156
|
+
ACCESS_SECRETS = "access_secrets"
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
class PluginSignature(BaseSchema):
|
|
160
|
+
"""Plugin signature information for verification."""
|
|
161
|
+
|
|
162
|
+
algorithm: str = Field(default="ed25519", description="Signature algorithm")
|
|
163
|
+
public_key: str = Field(description="Public key for verification")
|
|
164
|
+
signature: str = Field(description="Signature of the plugin package")
|
|
165
|
+
signed_at: datetime = Field(description="Timestamp of signing")
|
|
166
|
+
signer_id: str | None = Field(default=None, description="ID of the signer")
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
class SandboxConfig(BaseSchema):
|
|
170
|
+
"""Sandbox configuration for plugin execution."""
|
|
171
|
+
|
|
172
|
+
enabled: bool = Field(default=True, description="Whether sandbox is enabled")
|
|
173
|
+
memory_limit_mb: int = Field(
|
|
174
|
+
default=256, ge=64, le=2048, description="Memory limit in MB"
|
|
175
|
+
)
|
|
176
|
+
cpu_time_limit_seconds: int = Field(
|
|
177
|
+
default=30, ge=1, le=300, description="CPU time limit in seconds"
|
|
178
|
+
)
|
|
179
|
+
network_enabled: bool = Field(
|
|
180
|
+
default=False, description="Whether network access is allowed"
|
|
181
|
+
)
|
|
182
|
+
allowed_modules: list[str] = Field(
|
|
183
|
+
default_factory=list, description="List of allowed Python modules"
|
|
184
|
+
)
|
|
185
|
+
blocked_modules: list[str] = Field(
|
|
186
|
+
default_factory=lambda: ["os", "subprocess", "sys", "shutil"],
|
|
187
|
+
description="List of blocked Python modules",
|
|
188
|
+
)
|
|
189
|
+
max_file_size_mb: int = Field(
|
|
190
|
+
default=10, ge=1, le=100, description="Max file size in MB"
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
class SecurityReport(BaseSchema):
|
|
195
|
+
"""Security analysis report for a plugin."""
|
|
196
|
+
|
|
197
|
+
plugin_id: str
|
|
198
|
+
analyzed_at: datetime
|
|
199
|
+
risk_level: SecurityLevel
|
|
200
|
+
issues: list[str] = Field(default_factory=list)
|
|
201
|
+
warnings: list[str] = Field(default_factory=list)
|
|
202
|
+
permissions_required: list[PluginPermission] = Field(default_factory=list)
|
|
203
|
+
signature_valid: bool = Field(default=False)
|
|
204
|
+
sandbox_compatible: bool = Field(default=True)
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
# =============================================================================
|
|
208
|
+
# Custom Validator Plugin
|
|
209
|
+
# =============================================================================
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
class ValidatorParamDefinition(BaseSchema):
|
|
213
|
+
"""Definition of a validator parameter."""
|
|
214
|
+
|
|
215
|
+
name: str = Field(description="Parameter name")
|
|
216
|
+
type: ValidatorParamType = Field(description="Parameter type")
|
|
217
|
+
description: str = Field(description="Parameter description")
|
|
218
|
+
required: bool = Field(default=False, description="Whether parameter is required")
|
|
219
|
+
default: Any = Field(default=None, description="Default value")
|
|
220
|
+
options: list[str] | None = Field(
|
|
221
|
+
default=None, description="Options for select/multi_select types"
|
|
222
|
+
)
|
|
223
|
+
min_value: float | None = Field(
|
|
224
|
+
default=None, description="Minimum value for numeric types"
|
|
225
|
+
)
|
|
226
|
+
max_value: float | None = Field(
|
|
227
|
+
default=None, description="Maximum value for numeric types"
|
|
228
|
+
)
|
|
229
|
+
pattern: str | None = Field(
|
|
230
|
+
default=None, description="Regex pattern for string validation"
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
class CustomValidatorBase(BaseSchema):
|
|
235
|
+
"""Base schema for custom validator."""
|
|
236
|
+
|
|
237
|
+
name: str = Field(max_length=100, description="Validator name")
|
|
238
|
+
display_name: str = Field(max_length=200, description="Display name for UI")
|
|
239
|
+
description: str = Field(description="Validator description")
|
|
240
|
+
category: str = Field(max_length=50, description="Validator category")
|
|
241
|
+
severity: Literal["error", "warning", "info"] = Field(
|
|
242
|
+
default="error", description="Default severity"
|
|
243
|
+
)
|
|
244
|
+
tags: list[str] = Field(default_factory=list, description="Tags for search/filter")
|
|
245
|
+
parameters: list[ValidatorParamDefinition] = Field(
|
|
246
|
+
default_factory=list, description="Validator parameters"
|
|
247
|
+
)
|
|
248
|
+
code: str = Field(description="Python code implementing the validator")
|
|
249
|
+
test_cases: list[dict[str, Any]] = Field(
|
|
250
|
+
default_factory=list, description="Test cases for validation"
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
class CustomValidatorCreate(CustomValidatorBase):
|
|
255
|
+
"""Schema for creating a custom validator."""
|
|
256
|
+
|
|
257
|
+
plugin_id: str | None = Field(
|
|
258
|
+
default=None, description="Associated plugin ID if part of a plugin"
|
|
259
|
+
)
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
class CustomValidatorUpdate(BaseSchema):
|
|
263
|
+
"""Schema for updating a custom validator."""
|
|
264
|
+
|
|
265
|
+
display_name: str | None = None
|
|
266
|
+
description: str | None = None
|
|
267
|
+
category: str | None = None
|
|
268
|
+
severity: Literal["error", "warning", "info"] | None = None
|
|
269
|
+
tags: list[str] | None = None
|
|
270
|
+
parameters: list[ValidatorParamDefinition] | None = None
|
|
271
|
+
code: str | None = None
|
|
272
|
+
test_cases: list[dict[str, Any]] | None = None
|
|
273
|
+
is_enabled: bool | None = None
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
class CustomValidatorResponse(CustomValidatorBase, IDMixin, TimestampMixin):
|
|
277
|
+
"""Response schema for custom validator."""
|
|
278
|
+
|
|
279
|
+
plugin_id: str | None = None
|
|
280
|
+
is_enabled: bool = True
|
|
281
|
+
is_verified: bool = False
|
|
282
|
+
usage_count: int = 0
|
|
283
|
+
last_used_at: datetime | None = None
|
|
284
|
+
|
|
285
|
+
@classmethod
|
|
286
|
+
def from_model(cls, model: Any) -> "CustomValidatorResponse":
|
|
287
|
+
return cls(
|
|
288
|
+
id=str(model.id),
|
|
289
|
+
name=model.name,
|
|
290
|
+
display_name=model.display_name,
|
|
291
|
+
description=model.description,
|
|
292
|
+
category=model.category,
|
|
293
|
+
severity=model.severity,
|
|
294
|
+
tags=model.tags or [],
|
|
295
|
+
parameters=model.parameters or [],
|
|
296
|
+
code=model.code,
|
|
297
|
+
test_cases=model.test_cases or [],
|
|
298
|
+
plugin_id=str(model.plugin_id) if model.plugin_id else None,
|
|
299
|
+
is_enabled=model.is_enabled,
|
|
300
|
+
is_verified=model.is_verified,
|
|
301
|
+
usage_count=model.usage_count,
|
|
302
|
+
last_used_at=model.last_used_at,
|
|
303
|
+
created_at=model.created_at,
|
|
304
|
+
updated_at=model.updated_at,
|
|
305
|
+
)
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
class CustomValidatorListResponse(ListResponseWrapper[CustomValidatorResponse]):
|
|
309
|
+
"""List response for custom validators."""
|
|
310
|
+
|
|
311
|
+
pass
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
class ValidatorTestRequest(BaseSchema):
|
|
315
|
+
"""Request to test a custom validator."""
|
|
316
|
+
|
|
317
|
+
code: str = Field(description="Validator code to test")
|
|
318
|
+
parameters: list[ValidatorParamDefinition] = Field(
|
|
319
|
+
default_factory=list, description="Parameter definitions"
|
|
320
|
+
)
|
|
321
|
+
test_data: dict[str, Any] = Field(description="Test data (column values)")
|
|
322
|
+
param_values: dict[str, Any] = Field(
|
|
323
|
+
default_factory=dict, description="Parameter values for test"
|
|
324
|
+
)
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
class ValidatorTestResponse(BaseSchema):
|
|
328
|
+
"""Response from testing a custom validator."""
|
|
329
|
+
|
|
330
|
+
success: bool
|
|
331
|
+
passed: bool | None = None
|
|
332
|
+
execution_time_ms: float
|
|
333
|
+
result: dict[str, Any] | None = None
|
|
334
|
+
error: str | None = None
|
|
335
|
+
warnings: list[str] = Field(default_factory=list)
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
# =============================================================================
|
|
339
|
+
# Custom Reporter Plugin
|
|
340
|
+
# =============================================================================
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
class ReporterFieldDefinition(BaseSchema):
|
|
344
|
+
"""Definition of a reporter configuration field."""
|
|
345
|
+
|
|
346
|
+
name: str = Field(description="Field name")
|
|
347
|
+
type: str = Field(description="Field type (string, boolean, select, etc.)")
|
|
348
|
+
label: str = Field(description="Display label")
|
|
349
|
+
description: str | None = Field(default=None, description="Field description")
|
|
350
|
+
required: bool = Field(default=False)
|
|
351
|
+
default: Any = Field(default=None)
|
|
352
|
+
options: list[dict[str, str]] | None = Field(
|
|
353
|
+
default=None, description="Options for select fields"
|
|
354
|
+
)
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
class CustomReporterBase(BaseSchema):
|
|
358
|
+
"""Base schema for custom reporter."""
|
|
359
|
+
|
|
360
|
+
name: str = Field(max_length=100, description="Reporter name")
|
|
361
|
+
display_name: str = Field(max_length=200, description="Display name for UI")
|
|
362
|
+
description: str = Field(description="Reporter description")
|
|
363
|
+
output_formats: list[ReporterOutputFormat] = Field(
|
|
364
|
+
default_factory=lambda: [ReporterOutputFormat.HTML],
|
|
365
|
+
description="Supported output formats",
|
|
366
|
+
)
|
|
367
|
+
config_fields: list[ReporterFieldDefinition] = Field(
|
|
368
|
+
default_factory=list, description="Configuration fields"
|
|
369
|
+
)
|
|
370
|
+
template: str | None = Field(
|
|
371
|
+
default=None, description="Jinja2 template for report generation"
|
|
372
|
+
)
|
|
373
|
+
code: str | None = Field(
|
|
374
|
+
default=None, description="Python code for custom report generation"
|
|
375
|
+
)
|
|
376
|
+
preview_image_url: str | None = Field(
|
|
377
|
+
default=None, description="Preview image URL"
|
|
378
|
+
)
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
class CustomReporterCreate(CustomReporterBase):
|
|
382
|
+
"""Schema for creating a custom reporter."""
|
|
383
|
+
|
|
384
|
+
plugin_id: str | None = Field(default=None, description="Associated plugin ID")
|
|
385
|
+
|
|
386
|
+
|
|
387
|
+
class CustomReporterUpdate(BaseSchema):
|
|
388
|
+
"""Schema for updating a custom reporter."""
|
|
389
|
+
|
|
390
|
+
display_name: str | None = None
|
|
391
|
+
description: str | None = None
|
|
392
|
+
output_formats: list[ReporterOutputFormat] | None = None
|
|
393
|
+
config_fields: list[ReporterFieldDefinition] | None = None
|
|
394
|
+
template: str | None = None
|
|
395
|
+
code: str | None = None
|
|
396
|
+
preview_image_url: str | None = None
|
|
397
|
+
is_enabled: bool | None = None
|
|
398
|
+
|
|
399
|
+
|
|
400
|
+
class CustomReporterResponse(CustomReporterBase, IDMixin, TimestampMixin):
|
|
401
|
+
"""Response schema for custom reporter."""
|
|
402
|
+
|
|
403
|
+
plugin_id: str | None = None
|
|
404
|
+
is_enabled: bool = True
|
|
405
|
+
is_verified: bool = False
|
|
406
|
+
usage_count: int = 0
|
|
407
|
+
|
|
408
|
+
@classmethod
|
|
409
|
+
def from_model(cls, model: Any) -> "CustomReporterResponse":
|
|
410
|
+
return cls(
|
|
411
|
+
id=str(model.id),
|
|
412
|
+
name=model.name,
|
|
413
|
+
display_name=model.display_name,
|
|
414
|
+
description=model.description,
|
|
415
|
+
output_formats=model.output_formats or [ReporterOutputFormat.HTML],
|
|
416
|
+
config_fields=model.config_fields or [],
|
|
417
|
+
template=model.template,
|
|
418
|
+
code=model.code,
|
|
419
|
+
preview_image_url=model.preview_image_url,
|
|
420
|
+
plugin_id=str(model.plugin_id) if model.plugin_id else None,
|
|
421
|
+
is_enabled=model.is_enabled,
|
|
422
|
+
is_verified=model.is_verified,
|
|
423
|
+
usage_count=model.usage_count,
|
|
424
|
+
created_at=model.created_at,
|
|
425
|
+
updated_at=model.updated_at,
|
|
426
|
+
)
|
|
427
|
+
|
|
428
|
+
|
|
429
|
+
class CustomReporterListResponse(ListResponseWrapper[CustomReporterResponse]):
|
|
430
|
+
"""List response for custom reporters."""
|
|
431
|
+
|
|
432
|
+
pass
|
|
433
|
+
|
|
434
|
+
|
|
435
|
+
class ReporterGenerateRequest(BaseSchema):
|
|
436
|
+
"""Request to generate a report using a custom reporter."""
|
|
437
|
+
|
|
438
|
+
output_format: ReporterOutputFormat = Field(description="Desired output format")
|
|
439
|
+
config: dict[str, Any] = Field(
|
|
440
|
+
default_factory=dict, description="Reporter configuration"
|
|
441
|
+
)
|
|
442
|
+
# Either validation_id or data must be provided
|
|
443
|
+
validation_id: str | None = Field(
|
|
444
|
+
default=None,
|
|
445
|
+
description="Validation ID to generate report from (auto-fetches data)",
|
|
446
|
+
)
|
|
447
|
+
data: dict[str, Any] | None = Field(
|
|
448
|
+
default=None,
|
|
449
|
+
description="Data to include in report (use if not providing validation_id)",
|
|
450
|
+
)
|
|
451
|
+
source_ids: list[str] | None = Field(
|
|
452
|
+
default=None, description="Source IDs to include"
|
|
453
|
+
)
|
|
454
|
+
|
|
455
|
+
|
|
456
|
+
class ReporterGenerateResponse(BaseSchema):
|
|
457
|
+
"""Response from generating a report."""
|
|
458
|
+
|
|
459
|
+
success: bool
|
|
460
|
+
report_id: str | None = None
|
|
461
|
+
download_url: str | None = None
|
|
462
|
+
preview_html: str | None = None
|
|
463
|
+
error: str | None = None
|
|
464
|
+
generation_time_ms: float = 0
|
|
465
|
+
|
|
466
|
+
|
|
467
|
+
# =============================================================================
|
|
468
|
+
# Plugin Metadata
|
|
469
|
+
# =============================================================================
|
|
470
|
+
|
|
471
|
+
|
|
472
|
+
class PluginAuthor(BaseSchema):
|
|
473
|
+
"""Plugin author information."""
|
|
474
|
+
|
|
475
|
+
name: str = Field(description="Author name")
|
|
476
|
+
email: str | None = Field(default=None, description="Author email")
|
|
477
|
+
url: str | None = Field(default=None, description="Author website")
|
|
478
|
+
|
|
479
|
+
|
|
480
|
+
class PluginMetadata(BaseSchema):
|
|
481
|
+
"""Metadata for a plugin."""
|
|
482
|
+
|
|
483
|
+
name: str = Field(max_length=100, description="Plugin name")
|
|
484
|
+
display_name: str = Field(max_length=200, description="Display name for UI")
|
|
485
|
+
description: str = Field(description="Plugin description")
|
|
486
|
+
version: str = Field(description="Plugin version (semver)")
|
|
487
|
+
type: PluginType = Field(description="Plugin type")
|
|
488
|
+
source: PluginSource = Field(default=PluginSource.COMMUNITY)
|
|
489
|
+
author: PluginAuthor | None = None
|
|
490
|
+
license: str | None = Field(default=None, description="License identifier")
|
|
491
|
+
homepage: str | None = Field(default=None, description="Plugin homepage URL")
|
|
492
|
+
repository: str | None = Field(default=None, description="Repository URL")
|
|
493
|
+
keywords: list[str] = Field(default_factory=list, description="Search keywords")
|
|
494
|
+
categories: list[str] = Field(default_factory=list, description="Plugin categories")
|
|
495
|
+
dependencies: list[PluginDependency] = Field(
|
|
496
|
+
default_factory=list, description="Plugin dependencies"
|
|
497
|
+
)
|
|
498
|
+
python_version: str | None = Field(
|
|
499
|
+
default=None, description="Required Python version"
|
|
500
|
+
)
|
|
501
|
+
dashboard_version: str | None = Field(
|
|
502
|
+
default=None, description="Required dashboard version"
|
|
503
|
+
)
|
|
504
|
+
permissions: list[PluginPermission] = Field(
|
|
505
|
+
default_factory=list, description="Required permissions"
|
|
506
|
+
)
|
|
507
|
+
|
|
508
|
+
@field_validator("version")
|
|
509
|
+
@classmethod
|
|
510
|
+
def validate_version(cls, v: str) -> str:
|
|
511
|
+
SemverVersion.parse(v) # Validate semver format
|
|
512
|
+
return v
|
|
513
|
+
|
|
514
|
+
|
|
515
|
+
class PluginBase(PluginMetadata):
|
|
516
|
+
"""Base schema for plugin."""
|
|
517
|
+
|
|
518
|
+
icon_url: str | None = Field(default=None, description="Plugin icon URL")
|
|
519
|
+
banner_url: str | None = Field(default=None, description="Plugin banner URL")
|
|
520
|
+
documentation_url: str | None = Field(
|
|
521
|
+
default=None, description="Documentation URL"
|
|
522
|
+
)
|
|
523
|
+
changelog: str | None = Field(default=None, description="Changelog markdown")
|
|
524
|
+
readme: str | None = Field(default=None, description="README markdown")
|
|
525
|
+
|
|
526
|
+
|
|
527
|
+
class PluginCreate(PluginBase):
|
|
528
|
+
"""Schema for creating/registering a plugin."""
|
|
529
|
+
|
|
530
|
+
package_url: str | None = Field(
|
|
531
|
+
default=None, description="URL to download plugin package"
|
|
532
|
+
)
|
|
533
|
+
signature: PluginSignature | None = Field(
|
|
534
|
+
default=None, description="Plugin signature"
|
|
535
|
+
)
|
|
536
|
+
sandbox_config: SandboxConfig | None = Field(
|
|
537
|
+
default=None, description="Sandbox configuration"
|
|
538
|
+
)
|
|
539
|
+
|
|
540
|
+
|
|
541
|
+
class PluginUpdate(BaseSchema):
|
|
542
|
+
"""Schema for updating a plugin."""
|
|
543
|
+
|
|
544
|
+
display_name: str | None = None
|
|
545
|
+
description: str | None = None
|
|
546
|
+
icon_url: str | None = None
|
|
547
|
+
banner_url: str | None = None
|
|
548
|
+
documentation_url: str | None = None
|
|
549
|
+
changelog: str | None = None
|
|
550
|
+
readme: str | None = None
|
|
551
|
+
is_enabled: bool | None = None
|
|
552
|
+
sandbox_config: SandboxConfig | None = None
|
|
553
|
+
|
|
554
|
+
|
|
555
|
+
class PluginResponse(PluginBase, IDMixin, TimestampMixin):
|
|
556
|
+
"""Response schema for a plugin."""
|
|
557
|
+
|
|
558
|
+
status: PluginStatus = Field(default=PluginStatus.AVAILABLE)
|
|
559
|
+
security_level: SecurityLevel = Field(default=SecurityLevel.UNVERIFIED)
|
|
560
|
+
installed_version: str | None = Field(
|
|
561
|
+
default=None, description="Currently installed version"
|
|
562
|
+
)
|
|
563
|
+
latest_version: str | None = Field(
|
|
564
|
+
default=None, description="Latest available version"
|
|
565
|
+
)
|
|
566
|
+
is_enabled: bool = Field(default=False)
|
|
567
|
+
install_count: int = Field(default=0, description="Total install count")
|
|
568
|
+
rating: float | None = Field(
|
|
569
|
+
default=None, ge=0, le=5, description="Average rating"
|
|
570
|
+
)
|
|
571
|
+
rating_count: int = Field(default=0, description="Number of ratings")
|
|
572
|
+
validators_count: int = Field(default=0, description="Number of validators")
|
|
573
|
+
reporters_count: int = Field(default=0, description="Number of reporters")
|
|
574
|
+
last_updated: datetime | None = None
|
|
575
|
+
installed_at: datetime | None = None
|
|
576
|
+
|
|
577
|
+
@classmethod
|
|
578
|
+
def from_model(cls, model: Any) -> "PluginResponse":
|
|
579
|
+
return cls(
|
|
580
|
+
id=str(model.id),
|
|
581
|
+
name=model.name,
|
|
582
|
+
display_name=model.display_name,
|
|
583
|
+
description=model.description,
|
|
584
|
+
version=model.version,
|
|
585
|
+
type=model.type,
|
|
586
|
+
source=model.source,
|
|
587
|
+
author=model.author,
|
|
588
|
+
license=model.license,
|
|
589
|
+
homepage=model.homepage,
|
|
590
|
+
repository=model.repository,
|
|
591
|
+
keywords=model.keywords or [],
|
|
592
|
+
categories=model.categories or [],
|
|
593
|
+
dependencies=model.dependencies or [],
|
|
594
|
+
python_version=model.python_version,
|
|
595
|
+
dashboard_version=model.dashboard_version,
|
|
596
|
+
permissions=model.permissions or [],
|
|
597
|
+
icon_url=model.icon_url,
|
|
598
|
+
banner_url=model.banner_url,
|
|
599
|
+
documentation_url=model.documentation_url,
|
|
600
|
+
changelog=model.changelog,
|
|
601
|
+
readme=model.readme,
|
|
602
|
+
status=model.status,
|
|
603
|
+
security_level=model.security_level,
|
|
604
|
+
installed_version=model.installed_version,
|
|
605
|
+
latest_version=model.latest_version,
|
|
606
|
+
is_enabled=model.is_enabled,
|
|
607
|
+
install_count=model.install_count,
|
|
608
|
+
rating=model.rating,
|
|
609
|
+
rating_count=model.rating_count,
|
|
610
|
+
validators_count=model.validators_count,
|
|
611
|
+
reporters_count=model.reporters_count,
|
|
612
|
+
last_updated=model.last_updated,
|
|
613
|
+
installed_at=model.installed_at,
|
|
614
|
+
created_at=model.created_at,
|
|
615
|
+
updated_at=model.updated_at,
|
|
616
|
+
)
|
|
617
|
+
|
|
618
|
+
|
|
619
|
+
class PluginListResponse(ListResponseWrapper[PluginResponse]):
|
|
620
|
+
"""List response for plugins."""
|
|
621
|
+
|
|
622
|
+
pass
|
|
623
|
+
|
|
624
|
+
|
|
625
|
+
class PluginSummary(BaseSchema):
|
|
626
|
+
"""Summary of a plugin for list views."""
|
|
627
|
+
|
|
628
|
+
id: str
|
|
629
|
+
name: str
|
|
630
|
+
display_name: str
|
|
631
|
+
description: str
|
|
632
|
+
version: str
|
|
633
|
+
type: PluginType
|
|
634
|
+
source: PluginSource
|
|
635
|
+
status: PluginStatus
|
|
636
|
+
security_level: SecurityLevel
|
|
637
|
+
icon_url: str | None = None
|
|
638
|
+
rating: float | None = None
|
|
639
|
+
rating_count: int = 0
|
|
640
|
+
install_count: int = 0
|
|
641
|
+
|
|
642
|
+
|
|
643
|
+
# =============================================================================
|
|
644
|
+
# Plugin Marketplace
|
|
645
|
+
# =============================================================================
|
|
646
|
+
|
|
647
|
+
|
|
648
|
+
class MarketplaceSearchRequest(BaseSchema):
|
|
649
|
+
"""Request to search plugins in marketplace."""
|
|
650
|
+
|
|
651
|
+
query: str | None = Field(default=None, description="Search query")
|
|
652
|
+
types: list[PluginType] | None = Field(
|
|
653
|
+
default=None, description="Filter by plugin types"
|
|
654
|
+
)
|
|
655
|
+
sources: list[PluginSource] | None = Field(
|
|
656
|
+
default=None, description="Filter by sources"
|
|
657
|
+
)
|
|
658
|
+
categories: list[str] | None = Field(
|
|
659
|
+
default=None, description="Filter by categories"
|
|
660
|
+
)
|
|
661
|
+
keywords: list[str] | None = Field(default=None, description="Filter by keywords")
|
|
662
|
+
min_rating: float | None = Field(
|
|
663
|
+
default=None, ge=0, le=5, description="Minimum rating"
|
|
664
|
+
)
|
|
665
|
+
verified_only: bool = Field(default=False, description="Only show verified plugins")
|
|
666
|
+
sort_by: Literal["relevance", "rating", "installs", "updated", "name"] = Field(
|
|
667
|
+
default="relevance"
|
|
668
|
+
)
|
|
669
|
+
sort_order: Literal["asc", "desc"] = Field(default="desc")
|
|
670
|
+
offset: int = Field(default=0, ge=0)
|
|
671
|
+
limit: int = Field(default=20, ge=1, le=100)
|
|
672
|
+
|
|
673
|
+
|
|
674
|
+
class MarketplaceCategory(BaseSchema):
|
|
675
|
+
"""Category in the marketplace."""
|
|
676
|
+
|
|
677
|
+
name: str
|
|
678
|
+
display_name: str
|
|
679
|
+
description: str
|
|
680
|
+
icon: str | None = None
|
|
681
|
+
plugin_count: int = 0
|
|
682
|
+
|
|
683
|
+
|
|
684
|
+
class MarketplaceStats(BaseSchema):
|
|
685
|
+
"""Statistics about the marketplace."""
|
|
686
|
+
|
|
687
|
+
total_plugins: int = 0
|
|
688
|
+
total_validators: int = 0
|
|
689
|
+
total_reporters: int = 0
|
|
690
|
+
total_installs: int = 0
|
|
691
|
+
categories: list[MarketplaceCategory] = Field(default_factory=list)
|
|
692
|
+
featured_plugins: list[PluginSummary] = Field(default_factory=list)
|
|
693
|
+
popular_plugins: list[PluginSummary] = Field(default_factory=list)
|
|
694
|
+
recent_plugins: list[PluginSummary] = Field(default_factory=list)
|
|
695
|
+
|
|
696
|
+
|
|
697
|
+
class PluginInstallRequest(BaseSchema):
|
|
698
|
+
"""Request to install a plugin."""
|
|
699
|
+
|
|
700
|
+
plugin_id: str = Field(description="Plugin ID to install")
|
|
701
|
+
version: str | None = Field(
|
|
702
|
+
default=None, description="Specific version to install"
|
|
703
|
+
)
|
|
704
|
+
force: bool = Field(default=False, description="Force reinstall if exists")
|
|
705
|
+
enable_after_install: bool = Field(
|
|
706
|
+
default=True, description="Enable plugin after installation"
|
|
707
|
+
)
|
|
708
|
+
skip_verification: bool = Field(
|
|
709
|
+
default=False,
|
|
710
|
+
description="Skip security verification (use with caution)",
|
|
711
|
+
)
|
|
712
|
+
|
|
713
|
+
|
|
714
|
+
class PluginInstallResponse(BaseSchema):
|
|
715
|
+
"""Response from plugin installation."""
|
|
716
|
+
|
|
717
|
+
success: bool
|
|
718
|
+
plugin_id: str
|
|
719
|
+
installed_version: str | None = None
|
|
720
|
+
message: str | None = None
|
|
721
|
+
warnings: list[str] = Field(default_factory=list)
|
|
722
|
+
security_report: SecurityReport | None = None
|
|
723
|
+
|
|
724
|
+
|
|
725
|
+
class PluginUninstallRequest(BaseSchema):
|
|
726
|
+
"""Request to uninstall a plugin."""
|
|
727
|
+
|
|
728
|
+
plugin_id: str = Field(description="Plugin ID to uninstall")
|
|
729
|
+
remove_data: bool = Field(
|
|
730
|
+
default=False, description="Remove all plugin data and configuration"
|
|
731
|
+
)
|
|
732
|
+
|
|
733
|
+
|
|
734
|
+
class PluginUninstallResponse(BaseSchema):
|
|
735
|
+
"""Response from plugin uninstallation."""
|
|
736
|
+
|
|
737
|
+
success: bool
|
|
738
|
+
plugin_id: str
|
|
739
|
+
message: str | None = None
|
|
740
|
+
|
|
741
|
+
|
|
742
|
+
class PluginUpdateCheckResponse(BaseSchema):
|
|
743
|
+
"""Response from checking for plugin updates."""
|
|
744
|
+
|
|
745
|
+
plugin_id: str
|
|
746
|
+
current_version: str
|
|
747
|
+
latest_version: str
|
|
748
|
+
update_available: bool
|
|
749
|
+
changelog: str | None = None
|
|
750
|
+
breaking_changes: bool = False
|
|
751
|
+
release_notes: str | None = None
|
|
752
|
+
|
|
753
|
+
|
|
754
|
+
class PluginRatingRequest(BaseSchema):
|
|
755
|
+
"""Request to rate a plugin."""
|
|
756
|
+
|
|
757
|
+
plugin_id: str
|
|
758
|
+
rating: int = Field(ge=1, le=5, description="Rating from 1 to 5")
|
|
759
|
+
review: str | None = Field(
|
|
760
|
+
default=None, max_length=2000, description="Optional review text"
|
|
761
|
+
)
|
|
762
|
+
|
|
763
|
+
|
|
764
|
+
class PluginRatingResponse(BaseSchema):
|
|
765
|
+
"""Response from rating a plugin."""
|
|
766
|
+
|
|
767
|
+
success: bool
|
|
768
|
+
plugin_id: str
|
|
769
|
+
new_average_rating: float
|
|
770
|
+
total_ratings: int
|
|
771
|
+
|
|
772
|
+
|
|
773
|
+
# =============================================================================
|
|
774
|
+
# Plugin Execution
|
|
775
|
+
# =============================================================================
|
|
776
|
+
|
|
777
|
+
|
|
778
|
+
class PluginExecutionContext(BaseSchema):
|
|
779
|
+
"""Context for plugin execution."""
|
|
780
|
+
|
|
781
|
+
plugin_id: str
|
|
782
|
+
execution_id: str
|
|
783
|
+
source_id: str | None = None
|
|
784
|
+
validation_id: str | None = None
|
|
785
|
+
parameters: dict[str, Any] = Field(default_factory=dict)
|
|
786
|
+
sandbox_enabled: bool = True
|
|
787
|
+
timeout_seconds: int = 30
|
|
788
|
+
memory_limit_mb: int = 256
|
|
789
|
+
|
|
790
|
+
|
|
791
|
+
class PluginExecutionResult(BaseSchema):
|
|
792
|
+
"""Result of plugin execution."""
|
|
793
|
+
|
|
794
|
+
execution_id: str
|
|
795
|
+
plugin_id: str
|
|
796
|
+
success: bool
|
|
797
|
+
result: Any = None
|
|
798
|
+
error: str | None = None
|
|
799
|
+
execution_time_ms: float = 0
|
|
800
|
+
memory_used_mb: float | None = None
|
|
801
|
+
warnings: list[str] = Field(default_factory=list)
|
|
802
|
+
logs: list[str] = Field(default_factory=list)
|
|
803
|
+
|
|
804
|
+
|
|
805
|
+
# =============================================================================
|
|
806
|
+
# Plugin Lifecycle & State Management
|
|
807
|
+
# =============================================================================
|
|
808
|
+
|
|
809
|
+
|
|
810
|
+
class PluginState(str, Enum):
|
|
811
|
+
"""Plugin lifecycle states."""
|
|
812
|
+
|
|
813
|
+
DISCOVERED = "discovered"
|
|
814
|
+
LOADING = "loading"
|
|
815
|
+
LOADED = "loaded"
|
|
816
|
+
ACTIVATING = "activating"
|
|
817
|
+
ACTIVE = "active"
|
|
818
|
+
DEACTIVATING = "deactivating"
|
|
819
|
+
UNLOADING = "unloading"
|
|
820
|
+
UNLOADED = "unloaded"
|
|
821
|
+
FAILED = "failed"
|
|
822
|
+
RELOADING = "reloading"
|
|
823
|
+
UPGRADING = "upgrading"
|
|
824
|
+
|
|
825
|
+
|
|
826
|
+
class PluginLifecycleEvent(BaseSchema):
|
|
827
|
+
"""A plugin lifecycle event."""
|
|
828
|
+
|
|
829
|
+
plugin_id: str
|
|
830
|
+
from_state: PluginState
|
|
831
|
+
to_state: PluginState
|
|
832
|
+
trigger: str
|
|
833
|
+
timestamp: datetime
|
|
834
|
+
metadata: dict[str, Any] = Field(default_factory=dict)
|
|
835
|
+
|
|
836
|
+
|
|
837
|
+
class PluginLifecycleResponse(BaseSchema):
|
|
838
|
+
"""Plugin lifecycle status response."""
|
|
839
|
+
|
|
840
|
+
plugin_id: str
|
|
841
|
+
current_state: PluginState
|
|
842
|
+
can_activate: bool = False
|
|
843
|
+
can_deactivate: bool = False
|
|
844
|
+
can_reload: bool = False
|
|
845
|
+
can_upgrade: bool = False
|
|
846
|
+
recent_events: list[PluginLifecycleEvent] = Field(default_factory=list)
|
|
847
|
+
|
|
848
|
+
|
|
849
|
+
class PluginTransitionRequest(BaseSchema):
|
|
850
|
+
"""Request to transition plugin state."""
|
|
851
|
+
|
|
852
|
+
target_state: PluginState
|
|
853
|
+
force: bool = Field(default=False, description="Force transition even if not allowed")
|
|
854
|
+
metadata: dict[str, Any] = Field(default_factory=dict)
|
|
855
|
+
|
|
856
|
+
|
|
857
|
+
class PluginTransitionResponse(BaseSchema):
|
|
858
|
+
"""Response from plugin state transition."""
|
|
859
|
+
|
|
860
|
+
success: bool
|
|
861
|
+
plugin_id: str
|
|
862
|
+
from_state: PluginState
|
|
863
|
+
to_state: PluginState
|
|
864
|
+
message: str | None = None
|
|
865
|
+
error: str | None = None
|
|
866
|
+
|
|
867
|
+
|
|
868
|
+
# =============================================================================
|
|
869
|
+
# Plugin Hot Reload
|
|
870
|
+
# =============================================================================
|
|
871
|
+
|
|
872
|
+
|
|
873
|
+
class ReloadStrategy(str, Enum):
|
|
874
|
+
"""Strategy for handling hot reloads."""
|
|
875
|
+
|
|
876
|
+
IMMEDIATE = "immediate"
|
|
877
|
+
DEBOUNCED = "debounced"
|
|
878
|
+
MANUAL = "manual"
|
|
879
|
+
SCHEDULED = "scheduled"
|
|
880
|
+
|
|
881
|
+
|
|
882
|
+
class HotReloadConfigRequest(BaseSchema):
|
|
883
|
+
"""Request to configure hot reload for a plugin."""
|
|
884
|
+
|
|
885
|
+
strategy: ReloadStrategy = Field(default=ReloadStrategy.DEBOUNCED)
|
|
886
|
+
debounce_delay_ms: int = Field(default=500, ge=0, le=5000)
|
|
887
|
+
watch_paths: list[str] = Field(default_factory=list)
|
|
888
|
+
enabled: bool = True
|
|
889
|
+
|
|
890
|
+
|
|
891
|
+
class HotReloadStatus(BaseSchema):
|
|
892
|
+
"""Hot reload status for a plugin."""
|
|
893
|
+
|
|
894
|
+
plugin_id: str
|
|
895
|
+
enabled: bool = False
|
|
896
|
+
watching: bool = False
|
|
897
|
+
strategy: ReloadStrategy = ReloadStrategy.MANUAL
|
|
898
|
+
has_pending_reload: bool = False
|
|
899
|
+
last_reload_at: datetime | None = None
|
|
900
|
+
last_reload_duration_ms: float | None = None
|
|
901
|
+
|
|
902
|
+
|
|
903
|
+
class HotReloadResult(BaseSchema):
|
|
904
|
+
"""Result of a hot reload operation."""
|
|
905
|
+
|
|
906
|
+
success: bool
|
|
907
|
+
plugin_id: str
|
|
908
|
+
old_version: str = ""
|
|
909
|
+
new_version: str = ""
|
|
910
|
+
duration_ms: float = 0
|
|
911
|
+
error: str | None = None
|
|
912
|
+
rolled_back: bool = False
|
|
913
|
+
changes: list[str] = Field(default_factory=list)
|
|
914
|
+
|
|
915
|
+
|
|
916
|
+
# =============================================================================
|
|
917
|
+
# Plugin Dependencies
|
|
918
|
+
# =============================================================================
|
|
919
|
+
|
|
920
|
+
|
|
921
|
+
class DependencyType(str, Enum):
|
|
922
|
+
"""Type of dependency relationship."""
|
|
923
|
+
|
|
924
|
+
REQUIRED = "required"
|
|
925
|
+
OPTIONAL = "optional"
|
|
926
|
+
DEV = "dev"
|
|
927
|
+
PEER = "peer"
|
|
928
|
+
CONFLICT = "conflict"
|
|
929
|
+
|
|
930
|
+
|
|
931
|
+
class DependencyInfo(BaseSchema):
|
|
932
|
+
"""Detailed dependency information."""
|
|
933
|
+
|
|
934
|
+
plugin_id: str
|
|
935
|
+
version_constraint: str
|
|
936
|
+
dependency_type: DependencyType = DependencyType.REQUIRED
|
|
937
|
+
resolved_version: str | None = None
|
|
938
|
+
is_installed: bool = False
|
|
939
|
+
is_satisfied: bool = False
|
|
940
|
+
|
|
941
|
+
|
|
942
|
+
class DependencyGraphNode(BaseSchema):
|
|
943
|
+
"""A node in the dependency graph."""
|
|
944
|
+
|
|
945
|
+
plugin_id: str
|
|
946
|
+
version: str
|
|
947
|
+
dependencies: list[DependencyInfo] = Field(default_factory=list)
|
|
948
|
+
dependents: list[str] = Field(default_factory=list)
|
|
949
|
+
depth: int = 0
|
|
950
|
+
|
|
951
|
+
|
|
952
|
+
class DependencyGraphResponse(BaseSchema):
|
|
953
|
+
"""Full dependency graph for visualization."""
|
|
954
|
+
|
|
955
|
+
root_plugin_id: str
|
|
956
|
+
nodes: list[DependencyGraphNode] = Field(default_factory=list)
|
|
957
|
+
has_cycles: bool = False
|
|
958
|
+
cycle_path: list[str] | None = None
|
|
959
|
+
install_order: list[str] = Field(default_factory=list)
|
|
960
|
+
total_dependencies: int = 0
|
|
961
|
+
|
|
962
|
+
|
|
963
|
+
class DependencyResolutionRequest(BaseSchema):
|
|
964
|
+
"""Request to resolve dependencies for installation."""
|
|
965
|
+
|
|
966
|
+
plugin_ids: list[str] = Field(description="Plugin IDs to resolve")
|
|
967
|
+
include_optional: bool = Field(default=False)
|
|
968
|
+
include_dev: bool = Field(default=False)
|
|
969
|
+
|
|
970
|
+
|
|
971
|
+
class DependencyResolutionResponse(BaseSchema):
|
|
972
|
+
"""Result of dependency resolution."""
|
|
973
|
+
|
|
974
|
+
success: bool
|
|
975
|
+
resolved: list[DependencyInfo] = Field(default_factory=list)
|
|
976
|
+
unresolved: list[DependencyInfo] = Field(default_factory=list)
|
|
977
|
+
conflicts: list[str] = Field(default_factory=list)
|
|
978
|
+
install_order: list[str] = Field(default_factory=list)
|
|
979
|
+
error: str | None = None
|
|
980
|
+
|
|
981
|
+
|
|
982
|
+
# =============================================================================
|
|
983
|
+
# Plugin Security - Extended
|
|
984
|
+
# =============================================================================
|
|
985
|
+
|
|
986
|
+
|
|
987
|
+
class IsolationLevel(str, Enum):
|
|
988
|
+
"""Sandbox isolation levels."""
|
|
989
|
+
|
|
990
|
+
NONE = "none"
|
|
991
|
+
PROCESS = "process"
|
|
992
|
+
CONTAINER = "container"
|
|
993
|
+
|
|
994
|
+
|
|
995
|
+
class SignatureAlgorithm(str, Enum):
|
|
996
|
+
"""Supported signature algorithms."""
|
|
997
|
+
|
|
998
|
+
SHA256 = "sha256"
|
|
999
|
+
SHA512 = "sha512"
|
|
1000
|
+
HMAC_SHA256 = "hmac_sha256"
|
|
1001
|
+
HMAC_SHA512 = "hmac_sha512"
|
|
1002
|
+
RSA_SHA256 = "rsa_sha256"
|
|
1003
|
+
ED25519 = "ed25519"
|
|
1004
|
+
|
|
1005
|
+
|
|
1006
|
+
class TrustedSigner(BaseSchema):
|
|
1007
|
+
"""A trusted signer in the trust store."""
|
|
1008
|
+
|
|
1009
|
+
signer_id: str
|
|
1010
|
+
name: str
|
|
1011
|
+
public_key: str
|
|
1012
|
+
algorithm: SignatureAlgorithm
|
|
1013
|
+
added_at: datetime
|
|
1014
|
+
expires_at: datetime | None = None
|
|
1015
|
+
is_active: bool = True
|
|
1016
|
+
trust_level: SecurityLevel = SecurityLevel.VERIFIED
|
|
1017
|
+
|
|
1018
|
+
|
|
1019
|
+
class TrustStoreResponse(BaseSchema):
|
|
1020
|
+
"""Response containing trust store information."""
|
|
1021
|
+
|
|
1022
|
+
signers: list[TrustedSigner] = Field(default_factory=list)
|
|
1023
|
+
total_signers: int = 0
|
|
1024
|
+
last_updated: datetime | None = None
|
|
1025
|
+
|
|
1026
|
+
|
|
1027
|
+
class AddSignerRequest(BaseSchema):
|
|
1028
|
+
"""Request to add a signer to the trust store."""
|
|
1029
|
+
|
|
1030
|
+
signer_id: str
|
|
1031
|
+
name: str
|
|
1032
|
+
public_key: str
|
|
1033
|
+
algorithm: SignatureAlgorithm = SignatureAlgorithm.ED25519
|
|
1034
|
+
expires_at: datetime | None = None
|
|
1035
|
+
trust_level: SecurityLevel = SecurityLevel.VERIFIED
|
|
1036
|
+
|
|
1037
|
+
|
|
1038
|
+
class SecurityPolicyPreset(str, Enum):
|
|
1039
|
+
"""Pre-defined security policy presets."""
|
|
1040
|
+
|
|
1041
|
+
DEVELOPMENT = "development"
|
|
1042
|
+
TESTING = "testing"
|
|
1043
|
+
STANDARD = "standard"
|
|
1044
|
+
ENTERPRISE = "enterprise"
|
|
1045
|
+
STRICT = "strict"
|
|
1046
|
+
AIRGAPPED = "airgapped"
|
|
1047
|
+
|
|
1048
|
+
|
|
1049
|
+
class SecurityPolicyConfig(BaseSchema):
|
|
1050
|
+
"""Full security policy configuration."""
|
|
1051
|
+
|
|
1052
|
+
preset: SecurityPolicyPreset = SecurityPolicyPreset.STANDARD
|
|
1053
|
+
isolation_level: IsolationLevel = IsolationLevel.PROCESS
|
|
1054
|
+
require_signature: bool = True
|
|
1055
|
+
min_signatures: int = Field(default=1, ge=0, le=10)
|
|
1056
|
+
allowed_signers: list[str] = Field(default_factory=list)
|
|
1057
|
+
blocked_modules: list[str] = Field(default_factory=list)
|
|
1058
|
+
memory_limit_mb: int = Field(default=256, ge=64, le=4096)
|
|
1059
|
+
cpu_time_limit_sec: int = Field(default=30, ge=1, le=600)
|
|
1060
|
+
network_enabled: bool = False
|
|
1061
|
+
filesystem_read: bool = False
|
|
1062
|
+
filesystem_write: bool = False
|
|
1063
|
+
|
|
1064
|
+
|
|
1065
|
+
class SecurityAnalysisRequest(BaseSchema):
|
|
1066
|
+
"""Request to analyze plugin security."""
|
|
1067
|
+
|
|
1068
|
+
plugin_id: str
|
|
1069
|
+
code: str | None = None
|
|
1070
|
+
deep_analysis: bool = Field(default=False, description="Perform deep AST analysis")
|
|
1071
|
+
|
|
1072
|
+
|
|
1073
|
+
class CodeAnalysisResult(BaseSchema):
|
|
1074
|
+
"""Result of code security analysis."""
|
|
1075
|
+
|
|
1076
|
+
is_safe: bool
|
|
1077
|
+
issues: list[str] = Field(default_factory=list)
|
|
1078
|
+
warnings: list[str] = Field(default_factory=list)
|
|
1079
|
+
blocked_constructs: list[str] = Field(default_factory=list)
|
|
1080
|
+
detected_imports: list[str] = Field(default_factory=list)
|
|
1081
|
+
detected_permissions: list[str] = Field(default_factory=list)
|
|
1082
|
+
complexity_score: int = Field(default=0, ge=0, le=100)
|
|
1083
|
+
|
|
1084
|
+
|
|
1085
|
+
class ExtendedSecurityReport(SecurityReport):
|
|
1086
|
+
"""Extended security report with detailed analysis."""
|
|
1087
|
+
|
|
1088
|
+
code_analysis: CodeAnalysisResult | None = None
|
|
1089
|
+
signature_count: int = 0
|
|
1090
|
+
trust_level: SecurityLevel = SecurityLevel.UNVERIFIED
|
|
1091
|
+
can_run_in_sandbox: bool = True
|
|
1092
|
+
code_hash: str = ""
|
|
1093
|
+
recommendations: list[str] = Field(default_factory=list)
|
|
1094
|
+
|
|
1095
|
+
|
|
1096
|
+
class VerifySignatureRequest(BaseSchema):
|
|
1097
|
+
"""Request to verify plugin signature."""
|
|
1098
|
+
|
|
1099
|
+
plugin_id: str
|
|
1100
|
+
signature: str
|
|
1101
|
+
content_hash: str
|
|
1102
|
+
algorithm: SignatureAlgorithm = SignatureAlgorithm.ED25519
|
|
1103
|
+
|
|
1104
|
+
|
|
1105
|
+
class VerifySignatureResponse(BaseSchema):
|
|
1106
|
+
"""Response from signature verification."""
|
|
1107
|
+
|
|
1108
|
+
is_valid: bool
|
|
1109
|
+
signer_id: str | None = None
|
|
1110
|
+
signer_name: str | None = None
|
|
1111
|
+
signed_at: datetime | None = None
|
|
1112
|
+
error: str | None = None
|
|
1113
|
+
|
|
1114
|
+
|
|
1115
|
+
# =============================================================================
|
|
1116
|
+
# Plugin Hooks
|
|
1117
|
+
# =============================================================================
|
|
1118
|
+
|
|
1119
|
+
|
|
1120
|
+
class HookType(str, Enum):
|
|
1121
|
+
"""Types of hooks in the plugin system."""
|
|
1122
|
+
|
|
1123
|
+
BEFORE_VALIDATION = "before_validation"
|
|
1124
|
+
AFTER_VALIDATION = "after_validation"
|
|
1125
|
+
ON_ISSUE_FOUND = "on_issue_found"
|
|
1126
|
+
BEFORE_PROFILE = "before_profile"
|
|
1127
|
+
AFTER_PROFILE = "after_profile"
|
|
1128
|
+
BEFORE_COMPARE = "before_compare"
|
|
1129
|
+
AFTER_COMPARE = "after_compare"
|
|
1130
|
+
ON_PLUGIN_LOAD = "on_plugin_load"
|
|
1131
|
+
ON_PLUGIN_UNLOAD = "on_plugin_unload"
|
|
1132
|
+
ON_PLUGIN_ERROR = "on_plugin_error"
|
|
1133
|
+
BEFORE_NOTIFICATION = "before_notification"
|
|
1134
|
+
AFTER_NOTIFICATION = "after_notification"
|
|
1135
|
+
ON_SCHEDULE_RUN = "on_schedule_run"
|
|
1136
|
+
ON_DATA_SOURCE_CONNECT = "on_data_source_connect"
|
|
1137
|
+
ON_SCHEMA_CHANGE = "on_schema_change"
|
|
1138
|
+
CUSTOM = "custom"
|
|
1139
|
+
|
|
1140
|
+
|
|
1141
|
+
class HookPriority(str, Enum):
|
|
1142
|
+
"""Priority levels for hook execution."""
|
|
1143
|
+
|
|
1144
|
+
HIGHEST = "highest"
|
|
1145
|
+
HIGH = "high"
|
|
1146
|
+
NORMAL = "normal"
|
|
1147
|
+
LOW = "low"
|
|
1148
|
+
LOWEST = "lowest"
|
|
1149
|
+
|
|
1150
|
+
|
|
1151
|
+
class HookRegistration(BaseSchema):
|
|
1152
|
+
"""A registered hook."""
|
|
1153
|
+
|
|
1154
|
+
id: str
|
|
1155
|
+
hook_type: HookType
|
|
1156
|
+
plugin_id: str
|
|
1157
|
+
function_name: str
|
|
1158
|
+
priority: HookPriority = HookPriority.NORMAL
|
|
1159
|
+
is_async: bool = False
|
|
1160
|
+
is_enabled: bool = True
|
|
1161
|
+
description: str | None = None
|
|
1162
|
+
|
|
1163
|
+
|
|
1164
|
+
class HookListResponse(BaseSchema):
|
|
1165
|
+
"""Response listing registered hooks."""
|
|
1166
|
+
|
|
1167
|
+
hooks: list[HookRegistration] = Field(default_factory=list)
|
|
1168
|
+
total: int = 0
|
|
1169
|
+
by_type: dict[str, int] = Field(default_factory=dict)
|
|
1170
|
+
|
|
1171
|
+
|
|
1172
|
+
class RegisterHookRequest(BaseSchema):
|
|
1173
|
+
"""Request to register a new hook."""
|
|
1174
|
+
|
|
1175
|
+
hook_type: HookType
|
|
1176
|
+
plugin_id: str
|
|
1177
|
+
function_name: str
|
|
1178
|
+
priority: HookPriority = HookPriority.NORMAL
|
|
1179
|
+
description: str | None = None
|
|
1180
|
+
|
|
1181
|
+
|
|
1182
|
+
class UnregisterHookRequest(BaseSchema):
|
|
1183
|
+
"""Request to unregister a hook."""
|
|
1184
|
+
|
|
1185
|
+
hook_id: str
|
|
1186
|
+
|
|
1187
|
+
|
|
1188
|
+
class HookExecutionResult(BaseSchema):
|
|
1189
|
+
"""Result of hook execution."""
|
|
1190
|
+
|
|
1191
|
+
hook_id: str
|
|
1192
|
+
plugin_id: str
|
|
1193
|
+
success: bool
|
|
1194
|
+
result: Any = None
|
|
1195
|
+
error: str | None = None
|
|
1196
|
+
execution_time_ms: float = 0
|
|
1197
|
+
modified_data: bool = False
|
|
1198
|
+
|
|
1199
|
+
|
|
1200
|
+
class HookExecutionSummary(BaseSchema):
|
|
1201
|
+
"""Summary of all hook executions for an event."""
|
|
1202
|
+
|
|
1203
|
+
hook_type: HookType
|
|
1204
|
+
total_hooks: int
|
|
1205
|
+
successful: int
|
|
1206
|
+
failed: int
|
|
1207
|
+
total_time_ms: float
|
|
1208
|
+
results: list[HookExecutionResult] = Field(default_factory=list)
|
|
1209
|
+
|
|
1210
|
+
|
|
1211
|
+
# =============================================================================
|
|
1212
|
+
# Plugin Documentation
|
|
1213
|
+
# =============================================================================
|
|
1214
|
+
|
|
1215
|
+
|
|
1216
|
+
class ParameterDoc(BaseSchema):
|
|
1217
|
+
"""Documentation for a function parameter."""
|
|
1218
|
+
|
|
1219
|
+
name: str
|
|
1220
|
+
type: str | None = None
|
|
1221
|
+
description: str | None = None
|
|
1222
|
+
default: str | None = None
|
|
1223
|
+
required: bool = True
|
|
1224
|
+
|
|
1225
|
+
|
|
1226
|
+
class FunctionDoc(BaseSchema):
|
|
1227
|
+
"""Documentation for a function."""
|
|
1228
|
+
|
|
1229
|
+
name: str
|
|
1230
|
+
description: str | None = None
|
|
1231
|
+
parameters: list[ParameterDoc] = Field(default_factory=list)
|
|
1232
|
+
return_type: str | None = None
|
|
1233
|
+
return_description: str | None = None
|
|
1234
|
+
raises: dict[str, str] = Field(default_factory=dict)
|
|
1235
|
+
is_async: bool = False
|
|
1236
|
+
deprecated: bool = False
|
|
1237
|
+
examples: list[str] = Field(default_factory=list)
|
|
1238
|
+
|
|
1239
|
+
|
|
1240
|
+
class ClassDoc(BaseSchema):
|
|
1241
|
+
"""Documentation for a class."""
|
|
1242
|
+
|
|
1243
|
+
name: str
|
|
1244
|
+
description: str | None = None
|
|
1245
|
+
bases: list[str] = Field(default_factory=list)
|
|
1246
|
+
init_params: list[ParameterDoc] = Field(default_factory=list)
|
|
1247
|
+
attributes: dict[str, dict[str, Any]] = Field(default_factory=dict)
|
|
1248
|
+
methods: list[FunctionDoc] = Field(default_factory=list)
|
|
1249
|
+
deprecated: bool = False
|
|
1250
|
+
examples: list[str] = Field(default_factory=list)
|
|
1251
|
+
|
|
1252
|
+
|
|
1253
|
+
class ModuleDoc(BaseSchema):
|
|
1254
|
+
"""Documentation for a module."""
|
|
1255
|
+
|
|
1256
|
+
name: str
|
|
1257
|
+
description: str | None = None
|
|
1258
|
+
file_path: str | None = None
|
|
1259
|
+
classes: list[ClassDoc] = Field(default_factory=list)
|
|
1260
|
+
functions: list[FunctionDoc] = Field(default_factory=list)
|
|
1261
|
+
constants: dict[str, Any] = Field(default_factory=dict)
|
|
1262
|
+
|
|
1263
|
+
|
|
1264
|
+
class PluginDocumentation(BaseSchema):
|
|
1265
|
+
"""Complete documentation for a plugin."""
|
|
1266
|
+
|
|
1267
|
+
plugin_id: str
|
|
1268
|
+
plugin_name: str
|
|
1269
|
+
version: str
|
|
1270
|
+
modules: list[ModuleDoc] = Field(default_factory=list)
|
|
1271
|
+
readme: str | None = None
|
|
1272
|
+
changelog: str | None = None
|
|
1273
|
+
examples: list[dict[str, str]] = Field(default_factory=list)
|
|
1274
|
+
generated_at: datetime | None = None
|
|
1275
|
+
|
|
1276
|
+
|
|
1277
|
+
class DocumentationRenderRequest(BaseSchema):
|
|
1278
|
+
"""Request to render plugin documentation."""
|
|
1279
|
+
|
|
1280
|
+
plugin_id: str
|
|
1281
|
+
format: Literal["markdown", "html", "json"] = "markdown"
|
|
1282
|
+
include_private: bool = False
|
|
1283
|
+
include_source: bool = False
|
|
1284
|
+
include_examples: bool = True
|
|
1285
|
+
|
|
1286
|
+
|
|
1287
|
+
class DocumentationRenderResponse(BaseSchema):
|
|
1288
|
+
"""Response with rendered documentation."""
|
|
1289
|
+
|
|
1290
|
+
plugin_id: str
|
|
1291
|
+
format: str
|
|
1292
|
+
content: str
|
|
1293
|
+
generation_time_ms: float = 0
|